JSBN vs SJCL ECC

JavaScript performance comparison

Revision 3 of this test case created by justmoon

Info

Comparison of ECC performance between JSBN and SJCL

Preparation code

<script src="http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js"></script>
<script src="http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js"></script>
<script src="http://www-cs-students.stanford.edu/~tjw/jsbn/prng4.js"></script>
<script src="http://www-cs-students.stanford.edu/~tjw/jsbn/rng.js"></script>
<script src="http://www-cs-students.stanford.edu/~tjw/jsbn/ec.js"></script>
<script src="http://www-cs-students.stanford.edu/~tjw/jsbn/sec.js"></script>
<script src="https://raw.github.com/bitwiseshiftleft/sjcl/master/sjcl.js"></script>
<script src="https://raw.github.com/bitwiseshiftleft/sjcl/master/core/bn.js"></script>
<script src="https://raw.github.com/bitwiseshiftleft/sjcl/master/core/ecc.js"></script>
<script>
Benchmark.prototype.setup = function() {
    function secp256k1() {
        // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
        var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
        var a = BigInteger.ZERO;
        var b = fromHex("7");
        //byte[] S = null;
        var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
        var h = BigInteger.ONE;
        var curve = new ECCurveFp(p, a, b);
        var G = curve.decodePointHex("04"
                    + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
                    + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");
        return new X9ECParameters(curve, G, n, h);
    }
   
    var ecparams = secp256k1()
    var rng = new SecureRandom();
    var n = ecparams.getN();
    var n1 = n.subtract(BigInteger.ONE);
    var G = ecparams.getG();
   
    // Overwrite NIST-P256 with secp256k1 so we're on even footing
    sjcl.ecc.curves.c256 = new sjcl.ecc.curve(
        sjcl.bn.pseudoMersennePrime(256, [[0,-1],[4,-1],[6,-1],[7,-1],[8,-1],[9,-1],[32,-1]]),
        "0x14551231950b75fc4402da1722fc9baee",
        0,
        7,
        "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
        "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
    );
   
    // Replace point addition and doubling algorithms
    // NIST-P256 is a=-3, we need algorithms for a=0
    sjcl.ecc.pointJac.prototype.add = function(T) {
      var S = this;
      if (S.curve !== T.curve) {
        throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
      }
   
      if (S.isIdentity) {
        return T.toJac();
      } else if (T.isIdentity) {
        return S;
      }
   
      var z1z1 = S.z.square();
      var h = T.x.mul(z1z1).sub(S.x);
      var s2 = T.y.mul(S.z).mul(z1z1);
   
      if (h.equals(0)) {
        if (S.y.equals(T.y.mul(z1z1.mul(S.z)))) {
          // same point
          return S.doubl();
        } else {
          // inverses
          return new sjcl.ecc.pointJac(S.curve);
        }
      }
   
      var hh = h.square();
      var i = hh.mul(4);
      var j = h.mul(i);
      var r = s2.sub(S.y).mul(2);
      var v = S.x.mul(i);
     
      var x = r.square().sub(j).sub(v.mul(2));
      var y = r.mul(v.sub(x)).sub(S.y.mul(j).mul(2));
      var z = S.z.add(h).square().sub(z1z1).sub(hh);
   
      return new sjcl.ecc.pointJac(this.curve,x,y,z);
    };
   
    sjcl.ecc.pointJac.prototype.doubl = function () {
      if (this.isIdentity) { return this; }
   
      var a = this.x.square();
      var b = this.y.square();
      var c = b.square();
      var d = this.x.add(b).square().sub(a).sub(c).mul(2);
      var e = a.mul(3);
      var f = e.square();
      var x = f.sub(d.mul(2));
      var y = e.mul(d.sub(x)).sub(c.mul(8));
      var z = this.y.mul(this.z).mul(2);
      return new sjcl.ecc.pointJac(this.curve, x, y, z);
    };
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
JSBN
var r = new BigInteger(n.bitLength(), rng);

var privateKey = r.mod(n1).add(BigInteger.ONE);

// Generate public key
var publicPoint = G.multiply(privateKey);
pending…
SJCL
var keys = sjcl.ecc.ecdsa.generateKeys(256,0);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment