Skip to content
Snippets Groups Projects
index.js 7.57 MiB
Newer Older
  • Learn to ignore specific revisions
  • Hugo NOUTS's avatar
    Hugo NOUTS committed
    16001 16002 16003 16004 16005 16006 16007 16008 16009 16010 16011 16012 16013 16014 16015 16016 16017 16018 16019 16020 16021 16022 16023 16024 16025 16026 16027 16028 16029 16030 16031 16032 16033 16034 16035 16036 16037 16038 16039 16040 16041 16042 16043 16044 16045 16046 16047 16048 16049 16050 16051 16052 16053 16054 16055 16056 16057 16058 16059 16060 16061 16062 16063 16064 16065 16066 16067 16068 16069 16070 16071 16072 16073 16074 16075 16076 16077 16078 16079 16080 16081 16082 16083 16084 16085 16086 16087 16088 16089 16090 16091 16092 16093 16094 16095 16096 16097 16098 16099 16100 16101 16102 16103 16104 16105 16106 16107 16108 16109 16110 16111 16112 16113 16114 16115 16116 16117 16118 16119 16120 16121 16122 16123 16124 16125 16126 16127 16128 16129 16130 16131 16132 16133 16134 16135 16136 16137 16138 16139 16140 16141 16142 16143 16144 16145 16146 16147 16148 16149 16150 16151 16152 16153 16154 16155 16156 16157 16158 16159 16160 16161 16162 16163 16164 16165 16166 16167 16168 16169 16170 16171 16172 16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191 16192 16193 16194 16195 16196 16197 16198 16199 16200 16201 16202 16203 16204 16205 16206 16207 16208 16209 16210 16211 16212 16213 16214 16215 16216 16217 16218 16219 16220 16221 16222 16223 16224 16225 16226 16227 16228 16229 16230 16231 16232 16233 16234 16235 16236 16237 16238 16239 16240 16241 16242 16243 16244 16245 16246 16247 16248 16249 16250 16251 16252 16253 16254 16255 16256 16257 16258 16259 16260 16261 16262 16263 16264 16265 16266 16267 16268 16269 16270 16271 16272 16273 16274 16275 16276 16277 16278 16279 16280 16281 16282 16283 16284 16285 16286 16287 16288 16289 16290 16291 16292 16293 16294 16295 16296 16297 16298 16299 16300 16301 16302 16303 16304 16305 16306 16307 16308 16309 16310 16311 16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 16324 16325 16326 16327 16328 16329 16330 16331 16332 16333 16334 16335 16336 16337 16338 16339 16340 16341 16342 16343 16344 16345 16346 16347 16348 16349 16350 16351 16352 16353 16354 16355 16356 16357 16358 16359 16360 16361 16362 16363 16364 16365 16366 16367 16368 16369 16370 16371 16372 16373 16374 16375 16376 16377 16378 16379 16380 16381 16382 16383 16384 16385 16386 16387 16388 16389 16390 16391 16392 16393 16394 16395 16396 16397 16398 16399 16400 16401 16402 16403 16404 16405 16406 16407 16408 16409 16410 16411 16412 16413 16414 16415 16416 16417 16418 16419 16420 16421 16422 16423 16424 16425 16426 16427 16428 16429 16430 16431 16432 16433 16434 16435 16436 16437 16438 16439 16440 16441 16442 16443 16444 16445 16446 16447 16448 16449 16450 16451 16452 16453 16454 16455 16456 16457 16458 16459 16460 16461 16462 16463 16464 16465 16466 16467 16468 16469 16470 16471 16472 16473 16474 16475 16476 16477 16478 16479 16480 16481 16482 16483 16484 16485 16486 16487 16488 16489 16490 16491 16492 16493 16494 16495 16496 16497 16498 16499 16500 16501 16502 16503 16504 16505 16506 16507 16508 16509 16510 16511 16512 16513 16514 16515 16516 16517 16518 16519 16520 16521 16522 16523 16524 16525 16526 16527 16528 16529 16530 16531 16532 16533 16534 16535 16536 16537 16538 16539 16540 16541 16542 16543 16544 16545 16546 16547 16548 16549 16550 16551 16552 16553 16554 16555 16556 16557 16558 16559 16560 16561 16562 16563 16564 16565 16566 16567 16568 16569 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 16580 16581 16582 16583 16584 16585 16586 16587 16588 16589 16590 16591 16592 16593 16594 16595 16596 16597 16598 16599 16600 16601 16602 16603 16604 16605 16606 16607 16608 16609 16610 16611 16612 16613 16614 16615 16616 16617 16618 16619 16620 16621 16622 16623 16624 16625 16626 16627 16628 16629 16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643 16644 16645 16646 16647 16648 16649 16650 16651 16652 16653 16654 16655 16656 16657 16658 16659 16660 16661 16662 16663 16664 16665 16666 16667 16668 16669 16670 16671 16672 16673 16674 16675 16676 16677 16678 16679 16680 16681 16682 16683 16684 16685 16686 16687 16688 16689 16690 16691 16692 16693 16694 16695 16696 16697 16698 16699 16700 16701 16702 16703 16704 16705 16706 16707 16708 16709 16710 16711 16712 16713 16714 16715 16716 16717 16718 16719 16720 16721 16722 16723 16724 16725 16726 16727 16728 16729 16730 16731 16732 16733 16734 16735 16736 16737 16738 16739 16740 16741 16742 16743 16744 16745 16746 16747 16748 16749 16750 16751 16752 16753 16754 16755 16756 16757 16758 16759 16760 16761 16762 16763 16764 16765 16766 16767 16768 16769 16770 16771 16772 16773 16774 16775 16776 16777 16778 16779 16780 16781 16782 16783 16784 16785 16786 16787 16788 16789 16790 16791 16792 16793 16794 16795 16796 16797 16798 16799 16800 16801 16802 16803 16804 16805 16806 16807 16808 16809 16810 16811 16812 16813 16814 16815 16816 16817 16818 16819 16820 16821 16822 16823 16824 16825 16826 16827 16828 16829 16830 16831 16832 16833 16834 16835 16836 16837 16838 16839 16840 16841 16842 16843 16844 16845 16846 16847 16848 16849 16850 16851 16852 16853 16854 16855 16856 16857 16858 16859 16860 16861 16862 16863 16864 16865 16866 16867 16868 16869 16870 16871 16872 16873 16874 16875 16876 16877 16878 16879 16880 16881 16882 16883 16884 16885 16886 16887 16888 16889 16890 16891 16892 16893 16894 16895 16896 16897 16898 16899 16900 16901 16902 16903 16904 16905 16906 16907 16908 16909 16910 16911 16912 16913 16914 16915 16916 16917 16918 16919 16920 16921 16922 16923 16924 16925 16926 16927 16928 16929 16930 16931 16932 16933 16934 16935 16936 16937 16938 16939 16940 16941 16942 16943 16944 16945 16946 16947 16948 16949 16950 16951 16952 16953 16954 16955 16956 16957 16958 16959 16960 16961 16962 16963 16964 16965 16966 16967 16968 16969 16970 16971 16972 16973 16974 16975 16976 16977 16978 16979 16980 16981 16982 16983 16984 16985 16986 16987 16988 16989 16990 16991 16992 16993 16994 16995 16996 16997 16998 16999 17000
    // Requires jsbn.js and jsbn2.js
    var BigInteger = (__webpack_require__(109).BigInteger)
    var Barrett = BigInteger.prototype.Barrett
    
    // ----------------
    // ECFieldElementFp
    
    // constructor
    function ECFieldElementFp(q,x) {
        this.x = x;
        // TODO if(x.compareTo(q) >= 0) error
        this.q = q;
    }
    
    function feFpEquals(other) {
        if(other == this) return true;
        return (this.q.equals(other.q) && this.x.equals(other.x));
    }
    
    function feFpToBigInteger() {
        return this.x;
    }
    
    function feFpNegate() {
        return new ECFieldElementFp(this.q, this.x.negate().mod(this.q));
    }
    
    function feFpAdd(b) {
        return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));
    }
    
    function feFpSubtract(b) {
        return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));
    }
    
    function feFpMultiply(b) {
        return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));
    }
    
    function feFpSquare() {
        return new ECFieldElementFp(this.q, this.x.square().mod(this.q));
    }
    
    function feFpDivide(b) {
        return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));
    }
    
    ECFieldElementFp.prototype.equals = feFpEquals;
    ECFieldElementFp.prototype.toBigInteger = feFpToBigInteger;
    ECFieldElementFp.prototype.negate = feFpNegate;
    ECFieldElementFp.prototype.add = feFpAdd;
    ECFieldElementFp.prototype.subtract = feFpSubtract;
    ECFieldElementFp.prototype.multiply = feFpMultiply;
    ECFieldElementFp.prototype.square = feFpSquare;
    ECFieldElementFp.prototype.divide = feFpDivide;
    
    // ----------------
    // ECPointFp
    
    // constructor
    function ECPointFp(curve,x,y,z) {
        this.curve = curve;
        this.x = x;
        this.y = y;
        // Projective coordinates: either zinv == null or z * zinv == 1
        // z and zinv are just BigIntegers, not fieldElements
        if(z == null) {
          this.z = BigInteger.ONE;
        }
        else {
          this.z = z;
        }
        this.zinv = null;
        //TODO: compression flag
    }
    
    function pointFpGetX() {
        if(this.zinv == null) {
          this.zinv = this.z.modInverse(this.curve.q);
        }
        var r = this.x.toBigInteger().multiply(this.zinv);
        this.curve.reduce(r);
        return this.curve.fromBigInteger(r);
    }
    
    function pointFpGetY() {
        if(this.zinv == null) {
          this.zinv = this.z.modInverse(this.curve.q);
        }
        var r = this.y.toBigInteger().multiply(this.zinv);
        this.curve.reduce(r);
        return this.curve.fromBigInteger(r);
    }
    
    function pointFpEquals(other) {
        if(other == this) return true;
        if(this.isInfinity()) return other.isInfinity();
        if(other.isInfinity()) return this.isInfinity();
        var u, v;
        // u = Y2 * Z1 - Y1 * Z2
        u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
        if(!u.equals(BigInteger.ZERO)) return false;
        // v = X2 * Z1 - X1 * Z2
        v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
        return v.equals(BigInteger.ZERO);
    }
    
    function pointFpIsInfinity() {
        if((this.x == null) && (this.y == null)) return true;
        return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
    }
    
    function pointFpNegate() {
        return new ECPointFp(this.curve, this.x, this.y.negate(), this.z);
    }
    
    function pointFpAdd(b) {
        if(this.isInfinity()) return b;
        if(b.isInfinity()) return this;
    
        // u = Y2 * Z1 - Y1 * Z2
        var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
        // v = X2 * Z1 - X1 * Z2
        var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
    
        if(BigInteger.ZERO.equals(v)) {
            if(BigInteger.ZERO.equals(u)) {
                return this.twice(); // this == b, so double
            }
    	return this.curve.getInfinity(); // this = -b, so infinity
        }
    
        var THREE = new BigInteger("3");
        var x1 = this.x.toBigInteger();
        var y1 = this.y.toBigInteger();
        var x2 = b.x.toBigInteger();
        var y2 = b.y.toBigInteger();
    
        var v2 = v.square();
        var v3 = v2.multiply(v);
        var x1v2 = x1.multiply(v2);
        var zu2 = u.square().multiply(this.z);
    
        // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
        var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
        // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
        var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);
        // z3 = v^3 * z1 * z2
        var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
    
        return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
    }
    
    function pointFpTwice() {
        if(this.isInfinity()) return this;
        if(this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();
    
        // TODO: optimized handling of constants
        var THREE = new BigInteger("3");
        var x1 = this.x.toBigInteger();
        var y1 = this.y.toBigInteger();
    
        var y1z1 = y1.multiply(this.z);
        var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);
        var a = this.curve.a.toBigInteger();
    
        // w = 3 * x1^2 + a * z1^2
        var w = x1.square().multiply(THREE);
        if(!BigInteger.ZERO.equals(a)) {
          w = w.add(this.z.square().multiply(a));
        }
        w = w.mod(this.curve.q);
        //this.curve.reduce(w);
        // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
        var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
        // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
        var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
        // z3 = 8 * (y1 * z1)^3
        var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
    
        return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
    }
    
    // Simple NAF (Non-Adjacent Form) multiplication algorithm
    // TODO: modularize the multiplication algorithm
    function pointFpMultiply(k) {
        if(this.isInfinity()) return this;
        if(k.signum() == 0) return this.curve.getInfinity();
    
        var e = k;
        var h = e.multiply(new BigInteger("3"));
    
        var neg = this.negate();
        var R = this;
    
        var i;
        for(i = h.bitLength() - 2; i > 0; --i) {
    	R = R.twice();
    
    	var hBit = h.testBit(i);
    	var eBit = e.testBit(i);
    
    	if (hBit != eBit) {
    	    R = R.add(hBit ? this : neg);
    	}
        }
    
        return R;
    }
    
    // Compute this*j + x*k (simultaneous multiplication)
    function pointFpMultiplyTwo(j,x,k) {
      var i;
      if(j.bitLength() > k.bitLength())
        i = j.bitLength() - 1;
      else
        i = k.bitLength() - 1;
    
      var R = this.curve.getInfinity();
      var both = this.add(x);
      while(i >= 0) {
        R = R.twice();
        if(j.testBit(i)) {
          if(k.testBit(i)) {
            R = R.add(both);
          }
          else {
            R = R.add(this);
          }
        }
        else {
          if(k.testBit(i)) {
            R = R.add(x);
          }
        }
        --i;
      }
    
      return R;
    }
    
    ECPointFp.prototype.getX = pointFpGetX;
    ECPointFp.prototype.getY = pointFpGetY;
    ECPointFp.prototype.equals = pointFpEquals;
    ECPointFp.prototype.isInfinity = pointFpIsInfinity;
    ECPointFp.prototype.negate = pointFpNegate;
    ECPointFp.prototype.add = pointFpAdd;
    ECPointFp.prototype.twice = pointFpTwice;
    ECPointFp.prototype.multiply = pointFpMultiply;
    ECPointFp.prototype.multiplyTwo = pointFpMultiplyTwo;
    
    // ----------------
    // ECCurveFp
    
    // constructor
    function ECCurveFp(q,a,b) {
        this.q = q;
        this.a = this.fromBigInteger(a);
        this.b = this.fromBigInteger(b);
        this.infinity = new ECPointFp(this, null, null);
        this.reducer = new Barrett(this.q);
    }
    
    function curveFpGetQ() {
        return this.q;
    }
    
    function curveFpGetA() {
        return this.a;
    }
    
    function curveFpGetB() {
        return this.b;
    }
    
    function curveFpEquals(other) {
        if(other == this) return true;
        return(this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));
    }
    
    function curveFpGetInfinity() {
        return this.infinity;
    }
    
    function curveFpFromBigInteger(x) {
        return new ECFieldElementFp(this.q, x);
    }
    
    function curveReduce(x) {
        this.reducer.reduce(x);
    }
    
    // for now, work with hex strings because they're easier in JS
    function curveFpDecodePointHex(s) {
        switch(parseInt(s.substr(0,2), 16)) { // first byte
        case 0:
    	return this.infinity;
        case 2:
        case 3:
    	// point compression not supported yet
    	return null;
        case 4:
        case 6:
        case 7:
    	var len = (s.length - 2) / 2;
    	var xHex = s.substr(2, len);
    	var yHex = s.substr(len+2, len);
    
    	return new ECPointFp(this,
    			     this.fromBigInteger(new BigInteger(xHex, 16)),
    			     this.fromBigInteger(new BigInteger(yHex, 16)));
    
        default: // unsupported
    	return null;
        }
    }
    
    function curveFpEncodePointHex(p) {
    	if (p.isInfinity()) return "00";
    	var xHex = p.getX().toBigInteger().toString(16);
    	var yHex = p.getY().toBigInteger().toString(16);
    	var oLen = this.getQ().toString(16).length;
    	if ((oLen % 2) != 0) oLen++;
    	while (xHex.length < oLen) {
    		xHex = "0" + xHex;
    	}
    	while (yHex.length < oLen) {
    		yHex = "0" + yHex;
    	}
    	return "04" + xHex + yHex;
    }
    
    ECCurveFp.prototype.getQ = curveFpGetQ;
    ECCurveFp.prototype.getA = curveFpGetA;
    ECCurveFp.prototype.getB = curveFpGetB;
    ECCurveFp.prototype.equals = curveFpEquals;
    ECCurveFp.prototype.getInfinity = curveFpGetInfinity;
    ECCurveFp.prototype.fromBigInteger = curveFpFromBigInteger;
    ECCurveFp.prototype.reduce = curveReduce;
    //ECCurveFp.prototype.decodePointHex = curveFpDecodePointHex;
    ECCurveFp.prototype.encodePointHex = curveFpEncodePointHex;
    
    // from: https://github.com/kaielvin/jsbn-ec-point-compression
    ECCurveFp.prototype.decodePointHex = function(s)
    {
    	var yIsEven;
        switch(parseInt(s.substr(0,2), 16)) { // first byte
        case 0:
    	return this.infinity;
        case 2:
    	yIsEven = false;
        case 3:
    	if(yIsEven == undefined) yIsEven = true;
    	var len = s.length - 2;
    	var xHex = s.substr(2, len);
    	var x = this.fromBigInteger(new BigInteger(xHex,16));
    	var alpha = x.multiply(x.square().add(this.getA())).add(this.getB());
    	var beta = alpha.sqrt();
    
        if (beta == null) throw "Invalid point compression";
    
        var betaValue = beta.toBigInteger();
        if (betaValue.testBit(0) != yIsEven)
        {
            // Use the other root
            beta = this.fromBigInteger(this.getQ().subtract(betaValue));
        }
        return new ECPointFp(this,x,beta);
        case 4:
        case 6:
        case 7:
    	var len = (s.length - 2) / 2;
    	var xHex = s.substr(2, len);
    	var yHex = s.substr(len+2, len);
    
    	return new ECPointFp(this,
    			     this.fromBigInteger(new BigInteger(xHex, 16)),
    			     this.fromBigInteger(new BigInteger(yHex, 16)));
    
        default: // unsupported
    	return null;
        }
    }
    ECCurveFp.prototype.encodeCompressedPointHex = function(p)
    {
    	if (p.isInfinity()) return "00";
    	var xHex = p.getX().toBigInteger().toString(16);
    	var oLen = this.getQ().toString(16).length;
    	if ((oLen % 2) != 0) oLen++;
    	while (xHex.length < oLen)
    		xHex = "0" + xHex;
    	var yPrefix;
    	if(p.getY().toBigInteger().isEven()) yPrefix = "02";
    	else                                 yPrefix = "03";
    
    	return yPrefix + xHex;
    }
    
    
    ECFieldElementFp.prototype.getR = function()
    {
    	if(this.r != undefined) return this.r;
    
        this.r = null;
        var bitLength = this.q.bitLength();
        if (bitLength > 128)
        {
            var firstWord = this.q.shiftRight(bitLength - 64);
            if (firstWord.intValue() == -1)
            {
                this.r = BigInteger.ONE.shiftLeft(bitLength).subtract(this.q);
            }
        }
        return this.r;
    }
    ECFieldElementFp.prototype.modMult = function(x1,x2)
    {
        return this.modReduce(x1.multiply(x2));
    }
    ECFieldElementFp.prototype.modReduce = function(x)
    {
        if (this.getR() != null)
        {
            var qLen = q.bitLength();
            while (x.bitLength() > (qLen + 1))
            {
                var u = x.shiftRight(qLen);
                var v = x.subtract(u.shiftLeft(qLen));
                if (!this.getR().equals(BigInteger.ONE))
                {
                    u = u.multiply(this.getR());
                }
                x = u.add(v); 
            }
            while (x.compareTo(q) >= 0)
            {
                x = x.subtract(q);
            }
        }
        else
        {
            x = x.mod(q);
        }
        return x;
    }
    ECFieldElementFp.prototype.sqrt = function()
    {
        if (!this.q.testBit(0)) throw "unsupported";
    
        // p mod 4 == 3
        if (this.q.testBit(1))
        {
        	var z = new ECFieldElementFp(this.q,this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE),this.q));
        	return z.square().equals(this) ? z : null;
        }
    
        // p mod 4 == 1
        var qMinusOne = this.q.subtract(BigInteger.ONE);
    
        var legendreExponent = qMinusOne.shiftRight(1);
        if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE)))
        {
            return null;
        }
    
        var u = qMinusOne.shiftRight(2);
        var k = u.shiftLeft(1).add(BigInteger.ONE);
    
        var Q = this.x;
        var fourQ = modDouble(modDouble(Q));
    
        var U, V;
        do
        {
            var P;
            do
            {
                P = new BigInteger(this.q.bitLength(), new SecureRandom());
            }
            while (P.compareTo(this.q) >= 0
                || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));
    
            var result = this.lucasSequence(P, Q, k);
            U = result[0];
            V = result[1];
    
            if (this.modMult(V, V).equals(fourQ))
            {
                // Integer division by 2, mod q
                if (V.testBit(0))
                {
                    V = V.add(q);
                }
    
                V = V.shiftRight(1);
    
                return new ECFieldElementFp(q,V);
            }
        }
        while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));
    
        return null;
    }
    ECFieldElementFp.prototype.lucasSequence = function(P,Q,k)
    {
        var n = k.bitLength();
        var s = k.getLowestSetBit();
    
        var Uh = BigInteger.ONE;
        var Vl = BigInteger.TWO;
        var Vh = P;
        var Ql = BigInteger.ONE;
        var Qh = BigInteger.ONE;
    
        for (var j = n - 1; j >= s + 1; --j)
        {
            Ql = this.modMult(Ql, Qh);
    
            if (k.testBit(j))
            {
                Qh = this.modMult(Ql, Q);
                Uh = this.modMult(Uh, Vh);
                Vl = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
                Vh = this.modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1)));
            }
            else
            {
                Qh = Ql;
                Uh = this.modReduce(Uh.multiply(Vl).subtract(Ql));
                Vh = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
                Vl = this.modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
            }
        }
    
        Ql = this.modMult(Ql, Qh);
        Qh = this.modMult(Ql, Q);
        Uh = this.modReduce(Uh.multiply(Vl).subtract(Ql));
        Vl = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
        Ql = this.modMult(Ql, Qh);
    
        for (var j = 1; j <= s; ++j)
        {
            Uh = this.modMult(Uh, Vl);
            Vl = this.modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
            Ql = this.modMult(Ql, Ql);
        }
    
        return [ Uh, Vl ];
    }
    
    var exports = {
      ECCurveFp: ECCurveFp,
      ECPointFp: ECPointFp,
      ECFieldElementFp: ECFieldElementFp
    }
    
    module.exports = exports
    
    
    /***/ }),
    /* 109 */
    /***/ (function(module, exports) {
    
    (function(){
    
        // Copyright (c) 2005  Tom Wu
        // All Rights Reserved.
        // See "LICENSE" for details.
    
        // Basic JavaScript BN library - subset useful for RSA encryption.
    
        // Bits per digit
        var dbits;
    
        // JavaScript engine analysis
        var canary = 0xdeadbeefcafe;
        var j_lm = ((canary&0xffffff)==0xefcafe);
    
        // (public) Constructor
        function BigInteger(a,b,c) {
          if(a != null)
            if("number" == typeof a) this.fromNumber(a,b,c);
            else if(b == null && "string" != typeof a) this.fromString(a,256);
            else this.fromString(a,b);
        }
    
        // return new, unset BigInteger
        function nbi() { return new BigInteger(null); }
    
        // am: Compute w_j += (x*this_i), propagate carries,
        // c is initial carry, returns final carry.
        // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
        // We need to select the fastest one that works in this environment.
    
        // am1: use a single mult and divide to get the high bits,
        // max digit bits should be 26 because
        // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
        function am1(i,x,w,j,c,n) {
          while(--n >= 0) {
            var v = x*this[i++]+w[j]+c;
            c = Math.floor(v/0x4000000);
            w[j++] = v&0x3ffffff;
          }
          return c;
        }
        // am2 avoids a big mult-and-extract completely.
        // Max digit bits should be <= 30 because we do bitwise ops
        // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
        function am2(i,x,w,j,c,n) {
          var xl = x&0x7fff, xh = x>>15;
          while(--n >= 0) {
            var l = this[i]&0x7fff;
            var h = this[i++]>>15;
            var m = xh*l+h*xl;
            l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
            c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
            w[j++] = l&0x3fffffff;
          }
          return c;
        }
        // Alternately, set max digit bits to 28 since some
        // browsers slow down when dealing with 32-bit numbers.
        function am3(i,x,w,j,c,n) {
          var xl = x&0x3fff, xh = x>>14;
          while(--n >= 0) {
            var l = this[i]&0x3fff;
            var h = this[i++]>>14;
            var m = xh*l+h*xl;
            l = xl*l+((m&0x3fff)<<14)+w[j]+c;
            c = (l>>28)+(m>>14)+xh*h;
            w[j++] = l&0xfffffff;
          }
          return c;
        }
        var inBrowser = typeof navigator !== "undefined";
        if(inBrowser && j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
          BigInteger.prototype.am = am2;
          dbits = 30;
        }
        else if(inBrowser && j_lm && (navigator.appName != "Netscape")) {
          BigInteger.prototype.am = am1;
          dbits = 26;
        }
        else { // Mozilla/Netscape seems to prefer am3
          BigInteger.prototype.am = am3;
          dbits = 28;
        }
    
        BigInteger.prototype.DB = dbits;
        BigInteger.prototype.DM = ((1<<dbits)-1);
        BigInteger.prototype.DV = (1<<dbits);
    
        var BI_FP = 52;
        BigInteger.prototype.FV = Math.pow(2,BI_FP);
        BigInteger.prototype.F1 = BI_FP-dbits;
        BigInteger.prototype.F2 = 2*dbits-BI_FP;
    
        // Digit conversions
        var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
        var BI_RC = new Array();
        var rr,vv;
        rr = "0".charCodeAt(0);
        for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
        rr = "a".charCodeAt(0);
        for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
        rr = "A".charCodeAt(0);
        for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
    
        function int2char(n) { return BI_RM.charAt(n); }
        function intAt(s,i) {
          var c = BI_RC[s.charCodeAt(i)];
          return (c==null)?-1:c;
        }
    
        // (protected) copy this to r
        function bnpCopyTo(r) {
          for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
          r.t = this.t;
          r.s = this.s;
        }
    
        // (protected) set from integer value x, -DV <= x < DV
        function bnpFromInt(x) {
          this.t = 1;
          this.s = (x<0)?-1:0;
          if(x > 0) this[0] = x;
          else if(x < -1) this[0] = x+this.DV;
          else this.t = 0;
        }
    
        // return bigint initialized to value
        function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
    
        // (protected) set from string and radix
        function bnpFromString(s,b) {
          var k;
          if(b == 16) k = 4;
          else if(b == 8) k = 3;
          else if(b == 256) k = 8; // byte array
          else if(b == 2) k = 1;
          else if(b == 32) k = 5;
          else if(b == 4) k = 2;
          else { this.fromRadix(s,b); return; }
          this.t = 0;
          this.s = 0;
          var i = s.length, mi = false, sh = 0;
          while(--i >= 0) {
            var x = (k==8)?s[i]&0xff:intAt(s,i);
            if(x < 0) {
              if(s.charAt(i) == "-") mi = true;
              continue;
            }
            mi = false;
            if(sh == 0)
              this[this.t++] = x;
            else if(sh+k > this.DB) {
              this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
              this[this.t++] = (x>>(this.DB-sh));
            }
            else
              this[this.t-1] |= x<<sh;
            sh += k;
            if(sh >= this.DB) sh -= this.DB;
          }
          if(k == 8 && (s[0]&0x80) != 0) {
            this.s = -1;
            if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
          }
          this.clamp();
          if(mi) BigInteger.ZERO.subTo(this,this);
        }
    
        // (protected) clamp off excess high words
        function bnpClamp() {
          var c = this.s&this.DM;
          while(this.t > 0 && this[this.t-1] == c) --this.t;
        }
    
        // (public) return string representation in given radix
        function bnToString(b) {
          if(this.s < 0) return "-"+this.negate().toString(b);
          var k;
          if(b == 16) k = 4;
          else if(b == 8) k = 3;
          else if(b == 2) k = 1;
          else if(b == 32) k = 5;
          else if(b == 4) k = 2;
          else return this.toRadix(b);
          var km = (1<<k)-1, d, m = false, r = "", i = this.t;
          var p = this.DB-(i*this.DB)%k;
          if(i-- > 0) {
            if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
            while(i >= 0) {
              if(p < k) {
                d = (this[i]&((1<<p)-1))<<(k-p);
                d |= this[--i]>>(p+=this.DB-k);
              }
              else {
                d = (this[i]>>(p-=k))&km;
                if(p <= 0) { p += this.DB; --i; }
              }
              if(d > 0) m = true;
              if(m) r += int2char(d);
            }
          }
          return m?r:"0";
        }
    
        // (public) -this
        function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
    
        // (public) |this|
        function bnAbs() { return (this.s<0)?this.negate():this; }
    
        // (public) return + if this > a, - if this < a, 0 if equal
        function bnCompareTo(a) {
          var r = this.s-a.s;
          if(r != 0) return r;
          var i = this.t;
          r = i-a.t;
          if(r != 0) return (this.s<0)?-r:r;
          while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
          return 0;
        }
    
        // returns bit length of the integer x
        function nbits(x) {
          var r = 1, t;
          if((t=x>>>16) != 0) { x = t; r += 16; }
          if((t=x>>8) != 0) { x = t; r += 8; }
          if((t=x>>4) != 0) { x = t; r += 4; }
          if((t=x>>2) != 0) { x = t; r += 2; }
          if((t=x>>1) != 0) { x = t; r += 1; }
          return r;
        }
    
        // (public) return the number of bits in "this"
        function bnBitLength() {
          if(this.t <= 0) return 0;
          return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
        }
    
        // (protected) r = this << n*DB
        function bnpDLShiftTo(n,r) {
          var i;
          for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
          for(i = n-1; i >= 0; --i) r[i] = 0;
          r.t = this.t+n;
          r.s = this.s;
        }
    
        // (protected) r = this >> n*DB
        function bnpDRShiftTo(n,r) {
          for(var i = n; i < this.t; ++i) r[i-n] = this[i];
          r.t = Math.max(this.t-n,0);
          r.s = this.s;
        }
    
        // (protected) r = this << n
        function bnpLShiftTo(n,r) {
          var bs = n%this.DB;
          var cbs = this.DB-bs;
          var bm = (1<<cbs)-1;
          var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
          for(i = this.t-1; i >= 0; --i) {
            r[i+ds+1] = (this[i]>>cbs)|c;
            c = (this[i]&bm)<<bs;
          }
          for(i = ds-1; i >= 0; --i) r[i] = 0;
          r[ds] = c;
          r.t = this.t+ds+1;
          r.s = this.s;
          r.clamp();
        }
    
        // (protected) r = this >> n
        function bnpRShiftTo(n,r) {
          r.s = this.s;
          var ds = Math.floor(n/this.DB);
          if(ds >= this.t) { r.t = 0; return; }
          var bs = n%this.DB;
          var cbs = this.DB-bs;
          var bm = (1<<bs)-1;
          r[0] = this[ds]>>bs;
          for(var i = ds+1; i < this.t; ++i) {
            r[i-ds-1] |= (this[i]&bm)<<cbs;
            r[i-ds] = this[i]>>bs;
          }
          if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
          r.t = this.t-ds;
          r.clamp();
        }
    
        // (protected) r = this - a
        function bnpSubTo(a,r) {
          var i = 0, c = 0, m = Math.min(a.t,this.t);
          while(i < m) {
            c += this[i]-a[i];
            r[i++] = c&this.DM;
            c >>= this.DB;
          }
          if(a.t < this.t) {
            c -= a.s;
            while(i < this.t) {
              c += this[i];
              r[i++] = c&this.DM;
              c >>= this.DB;
            }
            c += this.s;
          }
          else {
            c += this.s;
            while(i < a.t) {
              c -= a[i];
              r[i++] = c&this.DM;
              c >>= this.DB;
            }
            c -= a.s;
          }
          r.s = (c<0)?-1:0;
          if(c < -1) r[i++] = this.DV+c;
          else if(c > 0) r[i++] = c;
          r.t = i;
          r.clamp();
        }
    
        // (protected) r = this * a, r != this,a (HAC 14.12)
        // "this" should be the larger one if appropriate.
        function bnpMultiplyTo(a,r) {
          var x = this.abs(), y = a.abs();
          var i = x.t;
          r.t = i+y.t;
          while(--i >= 0) r[i] = 0;
          for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
          r.s = 0;
          r.clamp();
          if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
        }
    
        // (protected) r = this^2, r != this (HAC 14.16)
        function bnpSquareTo(r) {
          var x = this.abs();
          var i = r.t = 2*x.t;
          while(--i >= 0) r[i] = 0;
          for(i = 0; i < x.t-1; ++i) {
            var c = x.am(i,x[i],r,2*i,0,1);
            if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
              r[i+x.t] -= x.DV;
              r[i+x.t+1] = 1;
            }
          }
          if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
          r.s = 0;
          r.clamp();
        }
    
        // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
        // r != q, this != m.  q or r may be null.
        function bnpDivRemTo(m,q,r) {
          var pm = m.abs();
          if(pm.t <= 0) return;
          var pt = this.abs();
          if(pt.t < pm.t) {
            if(q != null) q.fromInt(0);
            if(r != null) this.copyTo(r);
            return;
          }
          if(r == null) r = nbi();
          var y = nbi(), ts = this.s, ms = m.s;
          var nsh = this.DB-nbits(pm[pm.t-1]);   // normalize modulus
          if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
          else { pm.copyTo(y); pt.copyTo(r); }
          var ys = y.t;
          var y0 = y[ys-1];
          if(y0 == 0) return;
          var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
          var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
          var i = r.t, j = i-ys, t = (q==null)?nbi():q;
          y.dlShiftTo(j,t);
          if(r.compareTo(t) >= 0) {
            r[r.t++] = 1;
            r.subTo(t,r);
          }
          BigInteger.ONE.dlShiftTo(ys,t);
          t.subTo(y,y);  // "negative" y so we can replace sub with am later
          while(y.t < ys) y[y.t++] = 0;
          while(--j >= 0) {
            // Estimate quotient digit
            var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
            if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) {   // Try it out
              y.dlShiftTo(j,t);
              r.subTo(t,r);
              while(r[i] < --qd) r.subTo(t,r);
            }
          }
          if(q != null) {
            r.drShiftTo(ys,q);
            if(ts != ms) BigInteger.ZERO.subTo(q,q);
          }
          r.t = ys;
          r.clamp();
          if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
          if(ts < 0) BigInteger.ZERO.subTo(r,r);
        }
    
        // (public) this mod a
        function bnMod(a) {
          var r = nbi();
          this.abs().divRemTo(a,null,r);
          if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
          return r;
        }
    
        // Modular reduction using "classic" algorithm
        function Classic(m) { this.m = m; }
        function cConvert(x) {
          if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
          else return x;
        }
        function cRevert(x) { return x; }
        function cReduce(x) { x.divRemTo(this.m,null,x); }
        function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
        function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
    
        Classic.prototype.convert = cConvert;
        Classic.prototype.revert = cRevert;
        Classic.prototype.reduce = cReduce;
        Classic.prototype.mulTo = cMulTo;
        Classic.prototype.sqrTo = cSqrTo;
    
        // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
        // justification:
        //         xy == 1 (mod m)
        //         xy =  1+km
        //   xy(2-xy) = (1+km)(1-km)
        // x[y(2-xy)] = 1-k^2m^2
        // x[y(2-xy)] == 1 (mod m^2)
        // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
        // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
        // JS multiply "overflows" differently from C/C++, so care is needed here.