2014-02-27 15:02:11 -08:00
|
|
|
if ('undefined' === typeof window) window = this;
|
2014-02-20 13:59:41 -08:00
|
|
|
/*!
|
|
|
|
* Crypto-JS v2.0.0
|
|
|
|
* http://code.google.com/p/crypto-js/
|
|
|
|
* Copyright (c) 2009, Jeff Mott. All rights reserved.
|
|
|
|
* http://code.google.com/p/crypto-js/wiki/License
|
|
|
|
*/
|
|
|
|
|
|
|
|
var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
|
|
|
// Global Crypto object
|
|
|
|
var Crypto = window.Crypto = {};
|
|
|
|
|
|
|
|
// Crypto utilities
|
|
|
|
var util = Crypto.util = {
|
|
|
|
|
|
|
|
// Bit-wise rotate left
|
|
|
|
rotl: function (n, b) {
|
|
|
|
return (n << b) | (n >>> (32 - b));
|
|
|
|
},
|
|
|
|
|
|
|
|
// Bit-wise rotate right
|
|
|
|
rotr: function (n, b) {
|
|
|
|
return (n << (32 - b)) | (n >>> b);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Swap big-endian to little-endian and vice versa
|
|
|
|
endian: function (n) {
|
|
|
|
|
|
|
|
// If number given, swap endian
|
|
|
|
if (n.constructor == Number) {
|
|
|
|
return util.rotl(n, 8) & 0x00FF00FF |
|
|
|
|
util.rotl(n, 24) & 0xFF00FF00;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Else, assume array and swap all items
|
|
|
|
for (var i = 0; i < n.length; i++)
|
|
|
|
n[i] = util.endian(n[i]);
|
|
|
|
return n;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// Generate an array of any length of random bytes
|
|
|
|
randomBytes: function (n) {
|
|
|
|
for (var bytes = []; n > 0; n--)
|
|
|
|
bytes.push(Math.floor(Math.random() * 256));
|
|
|
|
return bytes;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a byte array to big-endian 32-bit words
|
|
|
|
bytesToWords: function (bytes) {
|
|
|
|
for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
|
|
|
|
words[b >>> 5] |= bytes[i] << (24 - b % 32);
|
|
|
|
return words;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert big-endian 32-bit words to a byte array
|
|
|
|
wordsToBytes: function (words) {
|
|
|
|
for (var bytes = [], b = 0; b < words.length * 32; b += 8)
|
|
|
|
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
|
|
|
|
return bytes;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a byte array to a hex string
|
|
|
|
bytesToHex: function (bytes) {
|
|
|
|
for (var hex = [], i = 0; i < bytes.length; i++) {
|
|
|
|
hex.push((bytes[i] >>> 4).toString(16));
|
|
|
|
hex.push((bytes[i] & 0xF).toString(16));
|
|
|
|
}
|
|
|
|
return hex.join("");
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a hex string to a byte array
|
|
|
|
hexToBytes: function (hex) {
|
|
|
|
for (var bytes = [], c = 0; c < hex.length; c += 2)
|
|
|
|
bytes.push(parseInt(hex.substr(c, 2), 16));
|
|
|
|
return bytes;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a byte array to a base-64 string
|
|
|
|
bytesToBase64: function (bytes) {
|
|
|
|
|
|
|
|
// Use browser-native function if it exists
|
|
|
|
if (typeof btoa == "function") return btoa(Binary.bytesToString(bytes));
|
|
|
|
|
|
|
|
for(var base64 = [], i = 0; i < bytes.length; i += 3) {
|
|
|
|
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
|
|
|
for (var j = 0; j < 4; j++) {
|
|
|
|
if (i * 8 + j * 6 <= bytes.length * 8)
|
|
|
|
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
|
|
|
|
else base64.push("=");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return base64.join("");
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a base-64 string to a byte array
|
|
|
|
base64ToBytes: function (base64) {
|
|
|
|
|
|
|
|
// Use browser-native function if it exists
|
|
|
|
if (typeof atob == "function") return Binary.stringToBytes(atob(base64));
|
|
|
|
|
|
|
|
// Remove non-base-64 characters
|
|
|
|
base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");
|
|
|
|
|
|
|
|
for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {
|
|
|
|
if (imod4 == 0) continue;
|
|
|
|
bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |
|
|
|
|
(base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// Crypto mode namespace
|
|
|
|
Crypto.mode = {};
|
|
|
|
|
|
|
|
// Crypto character encodings
|
|
|
|
var charenc = Crypto.charenc = {};
|
|
|
|
|
|
|
|
// UTF-8 encoding
|
|
|
|
var UTF8 = charenc.UTF8 = {
|
|
|
|
|
|
|
|
// Convert a string to a byte array
|
|
|
|
stringToBytes: function (str) {
|
|
|
|
return Binary.stringToBytes(unescape(encodeURIComponent(str)));
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a byte array to a string
|
|
|
|
bytesToString: function (bytes) {
|
|
|
|
return decodeURIComponent(escape(Binary.bytesToString(bytes)));
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// Binary encoding
|
|
|
|
var Binary = charenc.Binary = {
|
|
|
|
|
|
|
|
// Convert a string to a byte array
|
|
|
|
stringToBytes: function (str) {
|
|
|
|
for (var bytes = [], i = 0; i < str.length; i++)
|
|
|
|
bytes.push(str.charCodeAt(i));
|
|
|
|
return bytes;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Convert a byte array to a string
|
|
|
|
bytesToString: function (bytes) {
|
|
|
|
for (var str = [], i = 0; i < bytes.length; i++)
|
|
|
|
str.push(String.fromCharCode(bytes[i]));
|
|
|
|
return str.join("");
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2014-02-27 15:02:11 -08:00
|
|
|
/*
|
|
|
|
CryptoJS v3.1.2
|
|
|
|
code.google.com/p/crypto-js
|
|
|
|
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
|
|
|
code.google.com/p/crypto-js/wiki/License
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
|
|
|
|
(c) 2012 by C?dric Mesnil. All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
|
|
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
var CryptoJS=CryptoJS||function(j,k){var e={},l=e.lib={},z=function(){},t=l.Base={extend:function(a){z.prototype=this;var c=new z;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
|
|
|
u=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=k?c:4*a.length},toString:function(a){return(a||D).stringify(this)},concat:function(a){var c=this.words,h=a.words,d=this.sigBytes;a=a.sigBytes;this.clamp();if(d%4)for(var b=0;b<a;b++)c[d+b>>>2]|=(h[b>>>2]>>>24-8*(b%4)&255)<<24-8*((d+b)%4);else if(65535<h.length)for(b=0;b<a;b+=4)c[d+b>>>2]=h[b>>>2];else c.push.apply(c,h);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
|
|
|
|
32-8*(c%4);a.length=j.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b<a;b+=4)c.push(4294967296*j.random()|0);return new u.init(c,a)}}),w=e.enc={},D=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],d=0;d<a;d++){var g=c[d>>>2]>>>24-8*(d%4)&255;b.push((g>>>4).toString(16));b.push((g&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],d=0;d<c;d+=2)b[d>>>3]|=parseInt(a.substr(d,
|
|
|
|
2),16)<<24-4*(d%8);return new u.init(b,c/2)}},A=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],d=0;d<a;d++)b.push(String.fromCharCode(c[d>>>2]>>>24-8*(d%4)&255));return b.join("")},parse:function(a){for(var b=a.length,h=[],d=0;d<b;d++)h[d>>>2]|=(a.charCodeAt(d)&255)<<24-8*(d%4);return new u.init(h,b)}},g=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(A.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return A.parse(unescape(encodeURIComponent(a)))}},
|
|
|
|
v=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new u.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=g.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,h=b.words,d=b.sigBytes,g=this.blockSize,v=d/(4*g),v=a?j.ceil(v):j.max((v|0)-this._minBufferSize,0);a=v*g;d=j.min(4*a,d);if(a){for(var e=0;e<a;e+=g)this._doProcessBlock(h,e);e=h.splice(0,a);b.sigBytes-=d}return new u.init(e,d)},clone:function(){var a=t.clone.call(this);
|
|
|
|
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=v.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){v.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,g){return(new a.init(g)).finalize(b)}},_createHmacHelper:function(a){return function(c,g){return(new b.HMAC.init(a,
|
|
|
|
g)).finalize(c)}}});var b=e.algo={};return e}(Math);
|
|
|
|
(function(){var j=CryptoJS,k=j.lib,e=k.WordArray,l=k.Hasher,k=j.algo,z=e.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),t=e.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),u=e.create([11,14,15,12,
|
|
|
|
5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),w=e.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),D=e.create([0,1518500249,1859775393,2400959708,2840853838]),A=e.create([1352829926,1548603684,1836072691,
|
|
|
|
2053994217,0]),k=k.RIPEMD160=l.extend({_doReset:function(){this._hash=e.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(g,e){for(var b=0;16>b;b++){var a=e+b,c=g[a];g[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360}var a=this._hash.words,c=D.words,h=A.words,d=z.words,j=t.words,k=u.words,l=w.words,B,m,n,p,x,C,q,r,s,y;C=B=a[0];q=m=a[1];r=n=a[2];s=p=a[3];y=x=a[4];for(var f,b=0;80>b;b+=1)f=B+g[e+d[b]]|0,f=16>b?f+((m^n^p)+c[0]):32>b?f+((m&n|~m&p)+c[1]):48>b?
|
|
|
|
f+(((m|~n)^p)+c[2]):64>b?f+((m&p|n&~p)+c[3]):f+((m^(n|~p))+c[4]),f|=0,f=f<<k[b]|f>>>32-k[b],f=f+x|0,B=x,x=p,p=n<<10|n>>>22,n=m,m=f,f=C+g[e+j[b]]|0,f=16>b?f+((q^(r|~s))+h[0]):32>b?f+((q&s|r&~s)+h[1]):48>b?f+(((q|~r)^s)+h[2]):64>b?f+((q&r|~q&s)+h[3]):f+((q^r^s)+h[4]),f|=0,f=f<<l[b]|f>>>32-l[b],f=f+y|0,C=y,y=s,s=r<<10|r>>>22,r=q,q=f;f=a[1]+n+s|0;a[1]=a[2]+p+y|0;a[2]=a[3]+x+C|0;a[3]=a[4]+B+q|0;a[4]=a[0]+m+r|0;a[0]=f},_doFinalize:function(){var g=this._data,e=g.words,b=8*this._nDataBytes,a=8*g.sigBytes;
|
|
|
|
e[a>>>5]|=128<<24-a%32;e[(a+64>>>9<<4)+14]=(b<<8|b>>>24)&16711935|(b<<24|b>>>8)&4278255360;g.sigBytes=4*(e.length+1);this._process();g=this._hash;e=g.words;for(b=0;5>b;b++)a=e[b],e[b]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;return g},clone:function(){var e=l.clone.call(this);e._hash=this._hash.clone();return e}});j.RIPEMD160=l._createHelper(k);j.HmacRIPEMD160=l._createHmacHelper(k)})(Math);
|
|
|
|
|
|
|
|
|
|
|
|
module.exports.RIPEMD160 = CryptoJS.RIPEMD160;
|
2014-02-20 13:59:41 -08:00
|
|
|
Bitcoin = {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof navigator === 'undefined') {
|
|
|
|
var navigator = {};
|
|
|
|
navigator.appName = 'NodeJS';
|
|
|
|
|
|
|
|
}
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
|
|
|
|
BigInteger.prototype.am = am2;
|
|
|
|
dbits = 30;
|
|
|
|
}
|
|
|
|
else if(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+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.
|
|
|
|
function bnpInvDigit() {
|
|
|
|
if(this.t < 1) return 0;
|
|
|
|
var x = this[0];
|
|
|
|
if((x&1) == 0) return 0;
|
|
|
|
var y = x&3; // y == 1/x mod 2^2
|
|
|
|
y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
|
|
|
|
y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
|
|
|
|
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
|
|
|
|
// last step - calculate inverse mod DV directly;
|
|
|
|
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
|
|
|
|
y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
|
|
|
|
// we really want the negative inverse, and -DV < y < DV
|
|
|
|
return (y>0)?this.DV-y:-y;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Montgomery reduction
|
|
|
|
function Montgomery(m) {
|
|
|
|
this.m = m;
|
|
|
|
this.mp = m.invDigit();
|
|
|
|
this.mpl = this.mp&0x7fff;
|
|
|
|
this.mph = this.mp>>15;
|
|
|
|
this.um = (1<<(m.DB-15))-1;
|
|
|
|
this.mt2 = 2*m.t;
|
|
|
|
}
|
|
|
|
|
|
|
|
// xR mod m
|
|
|
|
function montConvert(x) {
|
|
|
|
var r = nbi();
|
|
|
|
x.abs().dlShiftTo(this.m.t,r);
|
|
|
|
r.divRemTo(this.m,null,r);
|
|
|
|
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// x/R mod m
|
|
|
|
function montRevert(x) {
|
|
|
|
var r = nbi();
|
|
|
|
x.copyTo(r);
|
|
|
|
this.reduce(r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// x = x/R mod m (HAC 14.32)
|
|
|
|
function montReduce(x) {
|
|
|
|
while(x.t <= this.mt2) // pad x so am has enough room later
|
|
|
|
x[x.t++] = 0;
|
|
|
|
for(var i = 0; i < this.m.t; ++i) {
|
|
|
|
// faster way of calculating u0 = x[i]*mp mod DV
|
|
|
|
var j = x[i]&0x7fff;
|
|
|
|
var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
|
|
|
|
// use am to combine the multiply-shift-add into one call
|
|
|
|
j = i+this.m.t;
|
|
|
|
x[j] += this.m.am(0,u0,x,i,0,this.m.t);
|
|
|
|
// propagate carry
|
|
|
|
while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
|
|
|
|
}
|
|
|
|
x.clamp();
|
|
|
|
x.drShiftTo(this.m.t,x);
|
|
|
|
if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// r = "x^2/R mod m"; x != r
|
|
|
|
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
|
|
|
|
|
|
// r = "xy/R mod m"; x,y != r
|
|
|
|
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
|
|
|
|
|
|
Montgomery.prototype.convert = montConvert;
|
|
|
|
Montgomery.prototype.revert = montRevert;
|
|
|
|
Montgomery.prototype.reduce = montReduce;
|
|
|
|
Montgomery.prototype.mulTo = montMulTo;
|
|
|
|
Montgomery.prototype.sqrTo = montSqrTo;
|
|
|
|
|
|
|
|
// (protected) true iff this is even
|
|
|
|
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
|
|
|
|
|
|
|
|
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
|
|
|
|
function bnpExp(e,z) {
|
|
|
|
if(e > 0xffffffff || e < 1) return BigInteger.ONE;
|
|
|
|
var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
|
|
|
|
g.copyTo(r);
|
|
|
|
while(--i >= 0) {
|
|
|
|
z.sqrTo(r,r2);
|
|
|
|
if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
|
|
|
|
else { var t = r; r = r2; r2 = t; }
|
|
|
|
}
|
|
|
|
return z.revert(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) this^e % m, 0 <= e < 2^32
|
|
|
|
function bnModPowInt(e,m) {
|
|
|
|
var z;
|
|
|
|
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
|
|
|
|
return this.exp(e,z);
|
|
|
|
}
|
|
|
|
|
|
|
|
// protected
|
|
|
|
BigInteger.prototype.copyTo = bnpCopyTo;
|
|
|
|
BigInteger.prototype.fromInt = bnpFromInt;
|
|
|
|
BigInteger.prototype.fromString = bnpFromString;
|
|
|
|
BigInteger.prototype.clamp = bnpClamp;
|
|
|
|
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
|
|
|
|
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
|
|
|
|
BigInteger.prototype.lShiftTo = bnpLShiftTo;
|
|
|
|
BigInteger.prototype.rShiftTo = bnpRShiftTo;
|
|
|
|
BigInteger.prototype.subTo = bnpSubTo;
|
|
|
|
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
|
|
|
|
BigInteger.prototype.squareTo = bnpSquareTo;
|
|
|
|
BigInteger.prototype.divRemTo = bnpDivRemTo;
|
|
|
|
BigInteger.prototype.invDigit = bnpInvDigit;
|
|
|
|
BigInteger.prototype.isEven = bnpIsEven;
|
|
|
|
BigInteger.prototype.exp = bnpExp;
|
|
|
|
|
|
|
|
// public
|
|
|
|
BigInteger.prototype.toString = bnToString;
|
|
|
|
BigInteger.prototype.negate = bnNegate;
|
|
|
|
BigInteger.prototype.abs = bnAbs;
|
|
|
|
BigInteger.prototype.compareTo = bnCompareTo;
|
|
|
|
BigInteger.prototype.bitLength = bnBitLength;
|
|
|
|
BigInteger.prototype.mod = bnMod;
|
|
|
|
BigInteger.prototype.modPowInt = bnModPowInt;
|
|
|
|
|
|
|
|
// "constants"
|
|
|
|
BigInteger.ZERO = nbv(0);
|
|
|
|
BigInteger.ONE = nbv(1);
|
|
|
|
// Copyright (c) 2005-2009 Tom Wu
|
|
|
|
// All Rights Reserved.
|
|
|
|
// See "LICENSE" for details.
|
|
|
|
|
|
|
|
// Extended JavaScript BN functions, required for RSA private ops.
|
|
|
|
|
|
|
|
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
|
|
|
|
// Version 1.2: square() API, isProbablePrime fix
|
|
|
|
|
|
|
|
// (public)
|
|
|
|
function bnClone() { var r = nbi(); this.copyTo(r); return r; }
|
|
|
|
|
|
|
|
// (public) return value as integer
|
|
|
|
function bnIntValue() {
|
|
|
|
if(this.s < 0) {
|
|
|
|
if(this.t == 1) return this[0]-this.DV;
|
|
|
|
else if(this.t == 0) return -1;
|
|
|
|
}
|
|
|
|
else if(this.t == 1) return this[0];
|
|
|
|
else if(this.t == 0) return 0;
|
|
|
|
// assumes 16 < DB < 32
|
|
|
|
return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) return value as byte
|
|
|
|
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
|
|
|
|
|
|
|
|
// (public) return value as short (assumes DB>=16)
|
|
|
|
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
|
|
|
|
|
|
|
|
// (protected) return x s.t. r^x < DV
|
|
|
|
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
|
|
|
|
|
|
|
|
// (public) 0 if this == 0, 1 if this > 0
|
|
|
|
function bnSigNum() {
|
|
|
|
if(this.s < 0) return -1;
|
|
|
|
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
|
|
|
|
else return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) convert to radix string
|
|
|
|
function bnpToRadix(b) {
|
|
|
|
if(b == null) b = 10;
|
|
|
|
if(this.signum() == 0 || b < 2 || b > 36) return "0";
|
|
|
|
var cs = this.chunkSize(b);
|
|
|
|
var a = Math.pow(b,cs);
|
|
|
|
var d = nbv(a), y = nbi(), z = nbi(), r = "";
|
|
|
|
this.divRemTo(d,y,z);
|
|
|
|
while(y.signum() > 0) {
|
|
|
|
r = (a+z.intValue()).toString(b).substr(1) + r;
|
|
|
|
y.divRemTo(d,y,z);
|
|
|
|
}
|
|
|
|
return z.intValue().toString(b) + r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) convert from radix string
|
|
|
|
function bnpFromRadix(s,b) {
|
|
|
|
this.fromInt(0);
|
|
|
|
if(b == null) b = 10;
|
|
|
|
var cs = this.chunkSize(b);
|
|
|
|
var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
|
|
|
|
for(var i = 0; i < s.length; ++i) {
|
|
|
|
var x = intAt(s,i);
|
|
|
|
if(x < 0) {
|
|
|
|
if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
w = b*w+x;
|
|
|
|
if(++j >= cs) {
|
|
|
|
this.dMultiply(d);
|
|
|
|
this.dAddOffset(w,0);
|
|
|
|
j = 0;
|
|
|
|
w = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(j > 0) {
|
|
|
|
this.dMultiply(Math.pow(b,j));
|
|
|
|
this.dAddOffset(w,0);
|
|
|
|
}
|
|
|
|
if(mi) BigInteger.ZERO.subTo(this,this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) alternate constructor
|
|
|
|
function bnpFromNumber(a,b,c) {
|
|
|
|
if("number" == typeof b) {
|
|
|
|
// new BigInteger(int,int,RNG)
|
|
|
|
if(a < 2) this.fromInt(1);
|
|
|
|
else {
|
|
|
|
this.fromNumber(a,c);
|
|
|
|
if(!this.testBit(a-1)) // force MSB set
|
|
|
|
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
|
|
|
|
if(this.isEven()) this.dAddOffset(1,0); // force odd
|
|
|
|
while(!this.isProbablePrime(b)) {
|
|
|
|
this.dAddOffset(2,0);
|
|
|
|
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// new BigInteger(int,RNG)
|
|
|
|
var x = new Array(), t = a&7;
|
|
|
|
x.length = (a>>3)+1;
|
|
|
|
b.nextBytes(x);
|
|
|
|
if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
|
|
|
|
this.fromString(x,256);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) convert to bigendian byte array
|
|
|
|
function bnToByteArray() {
|
|
|
|
var i = this.t, r = new Array();
|
|
|
|
r[0] = this.s;
|
|
|
|
var p = this.DB-(i*this.DB)%8, d, k = 0;
|
|
|
|
if(i-- > 0) {
|
|
|
|
if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
|
|
|
|
r[k++] = d|(this.s<<(this.DB-p));
|
|
|
|
while(i >= 0) {
|
|
|
|
if(p < 8) {
|
|
|
|
d = (this[i]&((1<<p)-1))<<(8-p);
|
|
|
|
d |= this[--i]>>(p+=this.DB-8);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
d = (this[i]>>(p-=8))&0xff;
|
|
|
|
if(p <= 0) { p += this.DB; --i; }
|
|
|
|
}
|
|
|
|
if((d&0x80) != 0) d |= -256;
|
|
|
|
if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
|
|
|
|
if(k > 0 || d != this.s) r[k++] = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
function bnEquals(a) { return(this.compareTo(a)==0); }
|
|
|
|
function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
|
|
|
|
function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
|
|
|
|
|
|
|
|
// (protected) r = this op a (bitwise)
|
|
|
|
function bnpBitwiseTo(a,op,r) {
|
|
|
|
var i, f, m = Math.min(a.t,this.t);
|
|
|
|
for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
|
|
|
|
if(a.t < this.t) {
|
|
|
|
f = a.s&this.DM;
|
|
|
|
for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
|
|
|
|
r.t = this.t;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
f = this.s&this.DM;
|
|
|
|
for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
|
|
|
|
r.t = a.t;
|
|
|
|
}
|
|
|
|
r.s = op(this.s,a.s);
|
|
|
|
r.clamp();
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) this & a
|
|
|
|
function op_and(x,y) { return x&y; }
|
|
|
|
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
|
|
|
|
|
|
|
|
// (public) this | a
|
|
|
|
function op_or(x,y) { return x|y; }
|
|
|
|
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
|
|
|
|
|
|
|
|
// (public) this ^ a
|
|
|
|
function op_xor(x,y) { return x^y; }
|
|
|
|
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
|
|
|
|
|
|
|
|
// (public) this & ~a
|
|
|
|
function op_andnot(x,y) { return x&~y; }
|
|
|
|
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
|
|
|
|
|
|
|
|
// (public) ~this
|
|
|
|
function bnNot() {
|
|
|
|
var r = nbi();
|
|
|
|
for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
|
|
|
|
r.t = this.t;
|
|
|
|
r.s = ~this.s;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) this << n
|
|
|
|
function bnShiftLeft(n) {
|
|
|
|
var r = nbi();
|
|
|
|
if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) this >> n
|
|
|
|
function bnShiftRight(n) {
|
|
|
|
var r = nbi();
|
|
|
|
if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return index of lowest 1-bit in x, x < 2^31
|
|
|
|
function lbit(x) {
|
|
|
|
if(x == 0) return -1;
|
|
|
|
var r = 0;
|
|
|
|
if((x&0xffff) == 0) { x >>= 16; r += 16; }
|
|
|
|
if((x&0xff) == 0) { x >>= 8; r += 8; }
|
|
|
|
if((x&0xf) == 0) { x >>= 4; r += 4; }
|
|
|
|
if((x&3) == 0) { x >>= 2; r += 2; }
|
|
|
|
if((x&1) == 0) ++r;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) returns index of lowest 1-bit (or -1 if none)
|
|
|
|
function bnGetLowestSetBit() {
|
|
|
|
for(var i = 0; i < this.t; ++i)
|
|
|
|
if(this[i] != 0) return i*this.DB+lbit(this[i]);
|
|
|
|
if(this.s < 0) return this.t*this.DB;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return number of 1 bits in x
|
|
|
|
function cbit(x) {
|
|
|
|
var r = 0;
|
|
|
|
while(x != 0) { x &= x-1; ++r; }
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) return number of set bits
|
|
|
|
function bnBitCount() {
|
|
|
|
var r = 0, x = this.s&this.DM;
|
|
|
|
for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) true iff nth bit is set
|
|
|
|
function bnTestBit(n) {
|
|
|
|
var j = Math.floor(n/this.DB);
|
|
|
|
if(j >= this.t) return(this.s!=0);
|
|
|
|
return((this[j]&(1<<(n%this.DB)))!=0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) this op (1<<n)
|
|
|
|
function bnpChangeBit(n,op) {
|
|
|
|
var r = BigInteger.ONE.shiftLeft(n);
|
|
|
|
this.bitwiseTo(r,op,r);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) this | (1<<n)
|
|
|
|
function bnSetBit(n) { return this.changeBit(n,op_or); }
|
|
|
|
|
|
|
|
// (public) this & ~(1<<n)
|
|
|
|
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
|
|
|
|
|
|
|
|
// (public) this ^ (1<<n)
|
|
|
|
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
|
|
|
|
|
|
|
|
// (protected) r = this + a
|
|
|
|
function bnpAddTo(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 > 0) r[i++] = c;
|
|
|
|
else if(c < -1) r[i++] = this.DV+c;
|
|
|
|
r.t = i;
|
|
|
|
r.clamp();
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) this + a
|
|
|
|
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
|
|
|
|
|
|
|
|
// (public) this - a
|
|
|
|
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
|
|
|
|
|
|
|
|
// (public) this * a
|
|
|
|
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
|
|
|
|
|
|
|
|
// (public) this^2
|
|
|
|
function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
|
|
|
|
|
|
|
|
// (public) this / a
|
|
|
|
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
|
|
|
|
|
|
|
|
// (public) this % a
|
|
|
|
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
|
|
|
|
|
|
|
|
// (public) [this/a,this%a]
|
|
|
|
function bnDivideAndRemainder(a) {
|
|
|
|
var q = nbi(), r = nbi();
|
|
|
|
this.divRemTo(a,q,r);
|
|
|
|
return new Array(q,r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) this *= n, this >= 0, 1 < n < DV
|
|
|
|
function bnpDMultiply(n) {
|
|
|
|
this[this.t] = this.am(0,n-1,this,0,0,this.t);
|
|
|
|
++this.t;
|
|
|
|
this.clamp();
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) this += n << w words, this >= 0
|
|
|
|
function bnpDAddOffset(n,w) {
|
|
|
|
if(n == 0) return;
|
|
|
|
while(this.t <= w) this[this.t++] = 0;
|
|
|
|
this[w] += n;
|
|
|
|
while(this[w] >= this.DV) {
|
|
|
|
this[w] -= this.DV;
|
|
|
|
if(++w >= this.t) this[this.t++] = 0;
|
|
|
|
++this[w];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A "null" reducer
|
|
|
|
function NullExp() {}
|
|
|
|
function nNop(x) { return x; }
|
|
|
|
function nMulTo(x,y,r) { x.multiplyTo(y,r); }
|
|
|
|
function nSqrTo(x,r) { x.squareTo(r); }
|
|
|
|
|
|
|
|
NullExp.prototype.convert = nNop;
|
|
|
|
NullExp.prototype.revert = nNop;
|
|
|
|
NullExp.prototype.mulTo = nMulTo;
|
|
|
|
NullExp.prototype.sqrTo = nSqrTo;
|
|
|
|
|
|
|
|
// (public) this^e
|
|
|
|
function bnPow(e) { return this.exp(e,new NullExp()); }
|
|
|
|
|
|
|
|
// (protected) r = lower n words of "this * a", a.t <= n
|
|
|
|
// "this" should be the larger one if appropriate.
|
|
|
|
function bnpMultiplyLowerTo(a,n,r) {
|
|
|
|
var i = Math.min(this.t+a.t,n);
|
|
|
|
r.s = 0; // assumes a,this >= 0
|
|
|
|
r.t = i;
|
|
|
|
while(i > 0) r[--i] = 0;
|
|
|
|
var j;
|
|
|
|
for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
|
|
|
|
for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
|
|
|
|
r.clamp();
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) r = "this * a" without lower n words, n > 0
|
|
|
|
// "this" should be the larger one if appropriate.
|
|
|
|
function bnpMultiplyUpperTo(a,n,r) {
|
|
|
|
--n;
|
|
|
|
var i = r.t = this.t+a.t-n;
|
|
|
|
r.s = 0; // assumes a,this >= 0
|
|
|
|
while(--i >= 0) r[i] = 0;
|
|
|
|
for(i = Math.max(n-this.t,0); i < a.t; ++i)
|
|
|
|
r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
|
|
|
|
r.clamp();
|
|
|
|
r.drShiftTo(1,r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Barrett modular reduction
|
|
|
|
function Barrett(m) {
|
|
|
|
// setup Barrett
|
|
|
|
this.r2 = nbi();
|
|
|
|
this.q3 = nbi();
|
|
|
|
BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
|
|
|
|
this.mu = this.r2.divide(m);
|
|
|
|
this.m = m;
|
|
|
|
}
|
|
|
|
|
|
|
|
function barrettConvert(x) {
|
|
|
|
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
|
|
|
|
else if(x.compareTo(this.m) < 0) return x;
|
|
|
|
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
|
|
|
|
}
|
|
|
|
|
|
|
|
function barrettRevert(x) { return x; }
|
|
|
|
|
|
|
|
// x = x mod m (HAC 14.42)
|
|
|
|
function barrettReduce(x) {
|
|
|
|
x.drShiftTo(this.m.t-1,this.r2);
|
|
|
|
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
|
|
|
|
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
|
|
|
|
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
|
|
|
|
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
|
|
|
|
x.subTo(this.r2,x);
|
|
|
|
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// r = x^2 mod m; x != r
|
|
|
|
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
|
|
|
|
|
|
// r = x*y mod m; x,y != r
|
|
|
|
function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
|
|
|
|
|
|
Barrett.prototype.convert = barrettConvert;
|
|
|
|
Barrett.prototype.revert = barrettRevert;
|
|
|
|
Barrett.prototype.reduce = barrettReduce;
|
|
|
|
Barrett.prototype.mulTo = barrettMulTo;
|
|
|
|
Barrett.prototype.sqrTo = barrettSqrTo;
|
|
|
|
|
|
|
|
// (public) this^e % m (HAC 14.85)
|
|
|
|
function bnModPow(e,m) {
|
|
|
|
var i = e.bitLength(), k, r = nbv(1), z;
|
|
|
|
if(i <= 0) return r;
|
|
|
|
else if(i < 18) k = 1;
|
|
|
|
else if(i < 48) k = 3;
|
|
|
|
else if(i < 144) k = 4;
|
|
|
|
else if(i < 768) k = 5;
|
|
|
|
else k = 6;
|
|
|
|
if(i < 8)
|
|
|
|
z = new Classic(m);
|
|
|
|
else if(m.isEven())
|
|
|
|
z = new Barrett(m);
|
|
|
|
else
|
|
|
|
z = new Montgomery(m);
|
|
|
|
|
|
|
|
// precomputation
|
|
|
|
var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
|
|
|
|
g[1] = z.convert(this);
|
|
|
|
if(k > 1) {
|
|
|
|
var g2 = nbi();
|
|
|
|
z.sqrTo(g[1],g2);
|
|
|
|
while(n <= km) {
|
|
|
|
g[n] = nbi();
|
|
|
|
z.mulTo(g2,g[n-2],g[n]);
|
|
|
|
n += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var j = e.t-1, w, is1 = true, r2 = nbi(), t;
|
|
|
|
i = nbits(e[j])-1;
|
|
|
|
while(j >= 0) {
|
|
|
|
if(i >= k1) w = (e[j]>>(i-k1))&km;
|
|
|
|
else {
|
|
|
|
w = (e[j]&((1<<(i+1))-1))<<(k1-i);
|
|
|
|
if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
|
|
|
|
}
|
|
|
|
|
|
|
|
n = k;
|
|
|
|
while((w&1) == 0) { w >>= 1; --n; }
|
|
|
|
if((i -= n) < 0) { i += this.DB; --j; }
|
|
|
|
if(is1) { // ret == 1, don't bother squaring or multiplying it
|
|
|
|
g[w].copyTo(r);
|
|
|
|
is1 = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
|
|
|
|
if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
|
|
|
|
z.mulTo(r2,g[w],r);
|
|
|
|
}
|
|
|
|
|
|
|
|
while(j >= 0 && (e[j]&(1<<i)) == 0) {
|
|
|
|
z.sqrTo(r,r2); t = r; r = r2; r2 = t;
|
|
|
|
if(--i < 0) { i = this.DB-1; --j; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return z.revert(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) gcd(this,a) (HAC 14.54)
|
|
|
|
function bnGCD(a) {
|
|
|
|
var x = (this.s<0)?this.negate():this.clone();
|
|
|
|
var y = (a.s<0)?a.negate():a.clone();
|
|
|
|
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
|
|
|
|
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
|
|
|
|
if(g < 0) return x;
|
|
|
|
if(i < g) g = i;
|
|
|
|
if(g > 0) {
|
|
|
|
x.rShiftTo(g,x);
|
|
|
|
y.rShiftTo(g,y);
|
|
|
|
}
|
|
|
|
while(x.signum() > 0) {
|
|
|
|
if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
|
|
|
|
if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
|
|
|
|
if(x.compareTo(y) >= 0) {
|
|
|
|
x.subTo(y,x);
|
|
|
|
x.rShiftTo(1,x);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
y.subTo(x,y);
|
|
|
|
y.rShiftTo(1,y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(g > 0) y.lShiftTo(g,y);
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) this % n, n < 2^26
|
|
|
|
function bnpModInt(n) {
|
|
|
|
if(n <= 0) return 0;
|
|
|
|
var d = this.DV%n, r = (this.s<0)?n-1:0;
|
|
|
|
if(this.t > 0)
|
|
|
|
if(d == 0) r = this[0]%n;
|
|
|
|
else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (public) 1/this % m (HAC 14.61)
|
|
|
|
function bnModInverse(m) {
|
|
|
|
var ac = m.isEven();
|
|
|
|
if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
|
|
|
|
var u = m.clone(), v = this.clone();
|
|
|
|
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
|
|
|
|
while(u.signum() != 0) {
|
|
|
|
while(u.isEven()) {
|
|
|
|
u.rShiftTo(1,u);
|
|
|
|
if(ac) {
|
|
|
|
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
|
|
|
|
a.rShiftTo(1,a);
|
|
|
|
}
|
|
|
|
else if(!b.isEven()) b.subTo(m,b);
|
|
|
|
b.rShiftTo(1,b);
|
|
|
|
}
|
|
|
|
while(v.isEven()) {
|
|
|
|
v.rShiftTo(1,v);
|
|
|
|
if(ac) {
|
|
|
|
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
|
|
|
|
c.rShiftTo(1,c);
|
|
|
|
}
|
|
|
|
else if(!d.isEven()) d.subTo(m,d);
|
|
|
|
d.rShiftTo(1,d);
|
|
|
|
}
|
|
|
|
if(u.compareTo(v) >= 0) {
|
|
|
|
u.subTo(v,u);
|
|
|
|
if(ac) a.subTo(c,a);
|
|
|
|
b.subTo(d,b);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
v.subTo(u,v);
|
|
|
|
if(ac) c.subTo(a,c);
|
|
|
|
d.subTo(b,d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
|
|
|
|
if(d.compareTo(m) >= 0) return d.subtract(m);
|
|
|
|
if(d.signum() < 0) d.addTo(m,d); else return d;
|
|
|
|
if(d.signum() < 0) return d.add(m); else return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
|
|
|
|
var lplim = (1<<26)/lowprimes[lowprimes.length-1];
|
|
|
|
|
|
|
|
// (public) test primality with certainty >= 1-.5^t
|
|
|
|
function bnIsProbablePrime(t) {
|
|
|
|
var i, x = this.abs();
|
|
|
|
if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
|
|
|
|
for(i = 0; i < lowprimes.length; ++i)
|
|
|
|
if(x[0] == lowprimes[i]) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(x.isEven()) return false;
|
|
|
|
i = 1;
|
|
|
|
while(i < lowprimes.length) {
|
|
|
|
var m = lowprimes[i], j = i+1;
|
|
|
|
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
|
|
|
|
m = x.modInt(m);
|
|
|
|
while(i < j) if(m%lowprimes[i++] == 0) return false;
|
|
|
|
}
|
|
|
|
return x.millerRabin(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
|
|
|
|
function bnpMillerRabin(t) {
|
|
|
|
var n1 = this.subtract(BigInteger.ONE);
|
|
|
|
var k = n1.getLowestSetBit();
|
|
|
|
if(k <= 0) return false;
|
|
|
|
var r = n1.shiftRight(k);
|
|
|
|
t = (t+1)>>1;
|
|
|
|
if(t > lowprimes.length) t = lowprimes.length;
|
|
|
|
var a = nbi();
|
|
|
|
for(var i = 0; i < t; ++i) {
|
|
|
|
//Pick bases at random, instead of starting at 2
|
|
|
|
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
|
|
|
|
var y = a.modPow(r,this);
|
|
|
|
if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
|
|
|
|
var j = 1;
|
|
|
|
while(j++ < k && y.compareTo(n1) != 0) {
|
|
|
|
y = y.modPowInt(2,this);
|
|
|
|
if(y.compareTo(BigInteger.ONE) == 0) return false;
|
|
|
|
}
|
|
|
|
if(y.compareTo(n1) != 0) return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// protected
|
|
|
|
BigInteger.prototype.chunkSize = bnpChunkSize;
|
|
|
|
BigInteger.prototype.toRadix = bnpToRadix;
|
|
|
|
BigInteger.prototype.fromRadix = bnpFromRadix;
|
|
|
|
BigInteger.prototype.fromNumber = bnpFromNumber;
|
|
|
|
BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
|
|
|
|
BigInteger.prototype.changeBit = bnpChangeBit;
|
|
|
|
BigInteger.prototype.addTo = bnpAddTo;
|
|
|
|
BigInteger.prototype.dMultiply = bnpDMultiply;
|
|
|
|
BigInteger.prototype.dAddOffset = bnpDAddOffset;
|
|
|
|
BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
|
|
|
|
BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
|
|
|
|
BigInteger.prototype.modInt = bnpModInt;
|
|
|
|
BigInteger.prototype.millerRabin = bnpMillerRabin;
|
|
|
|
|
|
|
|
// public
|
|
|
|
BigInteger.prototype.clone = bnClone;
|
|
|
|
BigInteger.prototype.intValue = bnIntValue;
|
|
|
|
BigInteger.prototype.byteValue = bnByteValue;
|
|
|
|
BigInteger.prototype.shortValue = bnShortValue;
|
|
|
|
BigInteger.prototype.signum = bnSigNum;
|
|
|
|
BigInteger.prototype.toByteArray = bnToByteArray;
|
|
|
|
BigInteger.prototype.equals = bnEquals;
|
|
|
|
BigInteger.prototype.min = bnMin;
|
|
|
|
BigInteger.prototype.max = bnMax;
|
|
|
|
BigInteger.prototype.and = bnAnd;
|
|
|
|
BigInteger.prototype.or = bnOr;
|
|
|
|
BigInteger.prototype.xor = bnXor;
|
|
|
|
BigInteger.prototype.andNot = bnAndNot;
|
|
|
|
BigInteger.prototype.not = bnNot;
|
|
|
|
BigInteger.prototype.shiftLeft = bnShiftLeft;
|
|
|
|
BigInteger.prototype.shiftRight = bnShiftRight;
|
|
|
|
BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
|
|
|
|
BigInteger.prototype.bitCount = bnBitCount;
|
|
|
|
BigInteger.prototype.testBit = bnTestBit;
|
|
|
|
BigInteger.prototype.setBit = bnSetBit;
|
|
|
|
BigInteger.prototype.clearBit = bnClearBit;
|
|
|
|
BigInteger.prototype.flipBit = bnFlipBit;
|
|
|
|
BigInteger.prototype.add = bnAdd;
|
|
|
|
BigInteger.prototype.subtract = bnSubtract;
|
|
|
|
BigInteger.prototype.multiply = bnMultiply;
|
|
|
|
BigInteger.prototype.divide = bnDivide;
|
|
|
|
BigInteger.prototype.remainder = bnRemainder;
|
|
|
|
BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
|
|
|
|
BigInteger.prototype.modPow = bnModPow;
|
|
|
|
BigInteger.prototype.modInverse = bnModInverse;
|
|
|
|
BigInteger.prototype.pow = bnPow;
|
|
|
|
BigInteger.prototype.gcd = bnGCD;
|
|
|
|
BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
|
|
|
|
|
|
|
|
// JSBN-specific extension
|
|
|
|
BigInteger.prototype.square = bnSquare;
|
|
|
|
|
|
|
|
// BigInteger interfaces not implemented in jsbn:
|
|
|
|
|
|
|
|
// BigInteger(int signum, byte[] magnitude)
|
|
|
|
// double doubleValue()
|
|
|
|
// float floatValue()
|
|
|
|
// int hashCode()
|
|
|
|
// long longValue()
|
|
|
|
// static BigInteger valueOf(long val)
|
|
|
|
// prng4.js - uses Arcfour as a PRNG
|
|
|
|
|
|
|
|
function Arcfour() {
|
|
|
|
this.i = 0;
|
|
|
|
this.j = 0;
|
|
|
|
this.S = new Array();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize arcfour context from key, an array of ints, each from [0..255]
|
|
|
|
function ARC4init(key) {
|
|
|
|
var i, j, t;
|
|
|
|
for(i = 0; i < 256; ++i)
|
|
|
|
this.S[i] = i;
|
|
|
|
j = 0;
|
|
|
|
for(i = 0; i < 256; ++i) {
|
|
|
|
j = (j + this.S[i] + key[i % key.length]) & 255;
|
|
|
|
t = this.S[i];
|
|
|
|
this.S[i] = this.S[j];
|
|
|
|
this.S[j] = t;
|
|
|
|
}
|
|
|
|
this.i = 0;
|
|
|
|
this.j = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ARC4next() {
|
|
|
|
var t;
|
|
|
|
this.i = (this.i + 1) & 255;
|
|
|
|
this.j = (this.j + this.S[this.i]) & 255;
|
|
|
|
t = this.S[this.i];
|
|
|
|
this.S[this.i] = this.S[this.j];
|
|
|
|
this.S[this.j] = t;
|
|
|
|
return this.S[(t + this.S[this.i]) & 255];
|
|
|
|
}
|
|
|
|
|
|
|
|
Arcfour.prototype.init = ARC4init;
|
|
|
|
Arcfour.prototype.next = ARC4next;
|
|
|
|
|
|
|
|
// Plug in your RNG constructor here
|
|
|
|
function prng_newstate() {
|
|
|
|
return new Arcfour();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pool size must be a multiple of 4 and greater than 32.
|
|
|
|
// An array of bytes the size of the pool will be passed to init()
|
|
|
|
var rng_psize = 256;
|
|
|
|
// BigInteger monkey patching
|
|
|
|
BigInteger.valueOf = nbv;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a byte array representation of the big integer.
|
|
|
|
*
|
|
|
|
* This returns the absolute of the contained value in big endian
|
|
|
|
* form. A value of zero results in an empty array.
|
|
|
|
*/
|
|
|
|
BigInteger.prototype.toByteArrayUnsigned = function () {
|
|
|
|
var ba = this.abs().toByteArray();
|
|
|
|
if (ba.length) {
|
|
|
|
if (ba[0] == 0) {
|
|
|
|
ba = ba.slice(1);
|
|
|
|
}
|
|
|
|
return ba.map(function (v) {
|
|
|
|
return (v < 0) ? v + 256 : v;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// Empty array, nothing to do
|
|
|
|
return ba;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Turns a byte array into a big integer.
|
|
|
|
*
|
|
|
|
* This function will interpret a byte array as a big integer in big
|
|
|
|
* endian notation and ignore leading zeros.
|
|
|
|
*/
|
|
|
|
BigInteger.fromByteArrayUnsigned = function (ba) {
|
|
|
|
if (!ba.length) {
|
|
|
|
return ba.valueOf(0);
|
|
|
|
} else if (ba[0] & 0x80) {
|
|
|
|
// Prepend a zero so the BigInteger class doesn't mistake this
|
|
|
|
// for a negative integer.
|
|
|
|
return new BigInteger([0].concat(ba));
|
|
|
|
} else {
|
|
|
|
return new BigInteger(ba);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts big integer to signed byte representation.
|
|
|
|
*
|
|
|
|
* The format for this value uses a the most significant bit as a sign
|
|
|
|
* bit. If the most significant bit is already occupied by the
|
|
|
|
* absolute value, an extra byte is prepended and the sign bit is set
|
|
|
|
* there.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 0 => 0x00
|
|
|
|
* 1 => 0x01
|
|
|
|
* -1 => 0x81
|
|
|
|
* 127 => 0x7f
|
|
|
|
* -127 => 0xff
|
|
|
|
* 128 => 0x0080
|
|
|
|
* -128 => 0x8080
|
|
|
|
* 255 => 0x00ff
|
|
|
|
* -255 => 0x80ff
|
|
|
|
* 16300 => 0x3fac
|
|
|
|
* -16300 => 0xbfac
|
|
|
|
* 62300 => 0x00f35c
|
|
|
|
* -62300 => 0x80f35c
|
|
|
|
*/
|
|
|
|
BigInteger.prototype.toByteArraySigned = function () {
|
|
|
|
var val = this.abs().toByteArrayUnsigned();
|
|
|
|
var neg = this.compareTo(BigInteger.ZERO) < 0;
|
|
|
|
|
|
|
|
if (neg) {
|
|
|
|
if (val[0] & 0x80) {
|
|
|
|
val.unshift(0x80);
|
|
|
|
} else {
|
|
|
|
val[0] |= 0x80;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (val[0] & 0x80) {
|
|
|
|
val.unshift(0x00);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a signed big integer byte representation.
|
|
|
|
*
|
|
|
|
* For details on the format please see BigInteger.toByteArraySigned.
|
|
|
|
*/
|
|
|
|
BigInteger.fromByteArraySigned = function (ba) {
|
|
|
|
// Check for negative value
|
|
|
|
if (ba[0] & 0x80) {
|
|
|
|
// Remove sign bit
|
|
|
|
ba[0] &= 0x7f;
|
|
|
|
|
|
|
|
return BigInteger.fromByteArrayUnsigned(ba).negate();
|
|
|
|
} else {
|
|
|
|
return BigInteger.fromByteArrayUnsigned(ba);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Console ignore
|
|
|
|
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
|
|
|
|
"dirxml", "group", "groupEnd", "time", "timeEnd", "count",
|
|
|
|
"trace", "profile", "profileEnd"];
|
|
|
|
|
|
|
|
if ("undefined" == typeof window.console) window.console = {};
|
|
|
|
for (var i = 0; i < names.length; ++i)
|
|
|
|
if ("undefined" == typeof window.console[names[i]])
|
|
|
|
window.console[names[i]] = function() {};
|
|
|
|
|
|
|
|
// Bitcoin utility functions
|
|
|
|
Bitcoin.Util = {
|
|
|
|
/**
|
|
|
|
* Cross-browser compatibility version of Array.isArray.
|
|
|
|
*/
|
|
|
|
isArray: Array.isArray || function(o)
|
|
|
|
{
|
|
|
|
return Object.prototype.toString.call(o) === '[object Array]';
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an array of a certain length filled with a specific value.
|
|
|
|
*/
|
|
|
|
makeFilledArray: function (len, val)
|
|
|
|
{
|
|
|
|
var array = [];
|
|
|
|
var i = 0;
|
|
|
|
while (i < len) {
|
|
|
|
array[i++] = val;
|
|
|
|
}
|
|
|
|
return array;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Turn an integer into a "var_int".
|
|
|
|
*
|
|
|
|
* "var_int" is a variable length integer used by Bitcoin's binary format.
|
|
|
|
*
|
|
|
|
* Returns a byte array.
|
|
|
|
*/
|
|
|
|
numToVarInt: function (i)
|
|
|
|
{
|
|
|
|
if (i < 0xfd) {
|
|
|
|
// unsigned char
|
|
|
|
return [i];
|
|
|
|
} else if (i <= 1<<16) {
|
|
|
|
// unsigned short (LE)
|
|
|
|
return [0xfd, i >>> 8, i & 255];
|
|
|
|
} else if (i <= 1<<32) {
|
|
|
|
// unsigned int (LE)
|
|
|
|
return [0xfe].concat(Crypto.util.wordsToBytes([i]));
|
|
|
|
} else {
|
|
|
|
// unsigned long long (LE)
|
|
|
|
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a Bitcoin value byte array, returning a BigInteger.
|
|
|
|
*/
|
|
|
|
valueToBigInt: function (valueBuffer)
|
|
|
|
{
|
|
|
|
if (valueBuffer instanceof BigInteger) return valueBuffer;
|
|
|
|
|
|
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
|
|
|
return BigInteger.fromByteArrayUnsigned(valueBuffer);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Format a Bitcoin value as a string.
|
|
|
|
*
|
|
|
|
* Takes a BigInteger or byte-array and returns that amount of Bitcoins in a
|
|
|
|
* nice standard formatting.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
* 12.3555
|
|
|
|
* 0.1234
|
|
|
|
* 900.99998888
|
|
|
|
* 34.00
|
|
|
|
*/
|
|
|
|
formatValue: function (valueBuffer) {
|
|
|
|
var value = this.valueToBigInt(valueBuffer).toString();
|
|
|
|
var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0';
|
|
|
|
var decimalPart = value.length > 8 ? value.substr(value.length-8) : value;
|
|
|
|
while (decimalPart.length < 8) decimalPart = "0"+decimalPart;
|
|
|
|
decimalPart = decimalPart.replace(/0*$/, '');
|
|
|
|
while (decimalPart.length < 2) decimalPart += "0";
|
|
|
|
return integerPart+"."+decimalPart;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a floating point string as a Bitcoin value.
|
|
|
|
*
|
|
|
|
* Keep in mind that parsing user input is messy. You should always display
|
|
|
|
* the parsed value back to the user to make sure we understood his input
|
|
|
|
* correctly.
|
|
|
|
*/
|
|
|
|
parseValue: function (valueString) {
|
|
|
|
// TODO: Detect other number formats (e.g. comma as decimal separator)
|
|
|
|
var valueComp = valueString.split('.');
|
|
|
|
var integralPart = valueComp[0];
|
|
|
|
var fractionalPart = valueComp[1] || "0";
|
|
|
|
while (fractionalPart.length < 8) fractionalPart += "0";
|
|
|
|
fractionalPart = fractionalPart.replace(/^0+/g, '');
|
|
|
|
var value = BigInteger.valueOf(parseInt(integralPart));
|
|
|
|
value = value.multiply(BigInteger.valueOf(100000000));
|
|
|
|
value = value.add(BigInteger.valueOf(parseInt(fractionalPart)));
|
|
|
|
return value;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate RIPEMD160(SHA256(data)).
|
|
|
|
*
|
|
|
|
* Takes an arbitrary byte array as inputs and returns the hash as a byte
|
|
|
|
* array.
|
|
|
|
*/
|
|
|
|
sha256ripe160: function (data) {
|
|
|
|
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for (var i in Crypto.util) {
|
|
|
|
if (Crypto.util.hasOwnProperty(i)) {
|
|
|
|
Bitcoin.Util[i] = Crypto.util[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Random number generator - requires a PRNG backend, e.g. prng4.js
|
|
|
|
|
|
|
|
// For best results, put code like
|
|
|
|
// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>
|
|
|
|
// in your main HTML document.
|
|
|
|
|
|
|
|
var rng_state;
|
|
|
|
var rng_pool;
|
|
|
|
var rng_pptr;
|
|
|
|
|
|
|
|
// Mix in a 32-bit integer into the pool
|
|
|
|
function rng_seed_int(x) {
|
|
|
|
rng_pool[rng_pptr++] ^= x & 255;
|
|
|
|
rng_pool[rng_pptr++] ^= (x >> 8) & 255;
|
|
|
|
rng_pool[rng_pptr++] ^= (x >> 16) & 255;
|
|
|
|
rng_pool[rng_pptr++] ^= (x >> 24) & 255;
|
|
|
|
if(rng_pptr >= rng_psize) rng_pptr -= rng_psize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mix in the current time (w/milliseconds) into the pool
|
|
|
|
function rng_seed_time() {
|
|
|
|
rng_seed_int(new Date().getTime());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the pool with junk if needed.
|
|
|
|
if(rng_pool == null) {
|
|
|
|
rng_pool = new Array();
|
|
|
|
rng_pptr = 0;
|
|
|
|
var t;
|
|
|
|
if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) {
|
|
|
|
// Extract entropy (256 bits) from NS4 RNG if available
|
|
|
|
var z = window.crypto.random(32);
|
|
|
|
for(t = 0; t < z.length; ++t)
|
|
|
|
rng_pool[rng_pptr++] = z.charCodeAt(t) & 255;
|
|
|
|
}
|
|
|
|
while(rng_pptr < rng_psize) { // extract some randomness from Math.random()
|
|
|
|
t = Math.floor(65536 * Math.random());
|
|
|
|
rng_pool[rng_pptr++] = t >>> 8;
|
|
|
|
rng_pool[rng_pptr++] = t & 255;
|
|
|
|
}
|
|
|
|
rng_pptr = 0;
|
|
|
|
rng_seed_time();
|
|
|
|
//rng_seed_int(window.screenX);
|
|
|
|
//rng_seed_int(window.screenY);
|
|
|
|
}
|
|
|
|
|
|
|
|
function rng_get_byte() {
|
|
|
|
if(rng_state == null) {
|
|
|
|
rng_seed_time();
|
|
|
|
rng_state = prng_newstate();
|
|
|
|
rng_state.init(rng_pool);
|
|
|
|
for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)
|
|
|
|
rng_pool[rng_pptr] = 0;
|
|
|
|
rng_pptr = 0;
|
|
|
|
//rng_pool = null;
|
|
|
|
}
|
|
|
|
// TODO: allow reseeding after first request
|
|
|
|
return rng_state.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
function rng_get_bytes(ba) {
|
|
|
|
var i;
|
|
|
|
for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();
|
|
|
|
}
|
|
|
|
|
|
|
|
function SecureRandom() {}
|
|
|
|
|
|
|
|
SecureRandom.prototype.nextBytes = rng_get_bytes;
|
|
|
|
// Basic Javascript Elliptic Curve implementation
|
|
|
|
// Ported loosely from BouncyCastle's Java EC code
|
|
|
|
// Only Fp curves implemented for now
|
|
|
|
|
|
|
|
// Requires jsbn.js and jsbn2.js
|
|
|
|
|
|
|
|
// ----------------
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
return this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q));
|
|
|
|
}
|
|
|
|
|
|
|
|
function pointFpGetY() {
|
|
|
|
if(this.zinv == null) {
|
|
|
|
this.zinv = this.z.modInverse(this.curve.q);
|
|
|
|
}
|
|
|
|
return this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q));
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.decodePointHex = curveFpDecodePointHex;
|
|
|
|
// Named EC curves
|
|
|
|
|
|
|
|
// Requires ec.js, jsbn.js, and jsbn2.js
|
|
|
|
|
|
|
|
// ----------------
|
|
|
|
// X9ECParameters
|
|
|
|
|
|
|
|
// constructor
|
|
|
|
function X9ECParameters(curve,g,n,h) {
|
|
|
|
this.curve = curve;
|
|
|
|
this.g = g;
|
|
|
|
this.n = n;
|
|
|
|
this.h = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
function x9getCurve() {
|
|
|
|
return this.curve;
|
|
|
|
}
|
|
|
|
|
|
|
|
function x9getG() {
|
|
|
|
return this.g;
|
|
|
|
}
|
|
|
|
|
|
|
|
function x9getN() {
|
|
|
|
return this.n;
|
|
|
|
}
|
|
|
|
|
|
|
|
function x9getH() {
|
|
|
|
return this.h;
|
|
|
|
}
|
|
|
|
|
|
|
|
X9ECParameters.prototype.getCurve = x9getCurve;
|
|
|
|
X9ECParameters.prototype.getG = x9getG;
|
|
|
|
X9ECParameters.prototype.getN = x9getN;
|
|
|
|
X9ECParameters.prototype.getH = x9getH;
|
|
|
|
|
|
|
|
// ----------------
|
|
|
|
// SECNamedCurves
|
|
|
|
|
|
|
|
function fromHex(s) { return new BigInteger(s, 16); }
|
|
|
|
|
|
|
|
function secp128r1() {
|
|
|
|
// p = 2^128 - 2^97 - 1
|
|
|
|
var p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
|
|
|
|
var a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
|
|
|
|
var b = fromHex("E87579C11079F43DD824993C2CEE5ED3");
|
|
|
|
//byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679");
|
|
|
|
var n = fromHex("FFFFFFFE0000000075A30D1B9038A115");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "161FF7528B899B2D0C28607CA52C5B86"
|
|
|
|
+ "CF5AC8395BAFEB13C02DA292DDED7A83");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
function secp160k1() {
|
|
|
|
// p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
|
|
|
|
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
|
|
|
|
var a = BigInteger.ZERO;
|
|
|
|
var b = fromHex("7");
|
|
|
|
//byte[] S = null;
|
|
|
|
var n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
|
|
|
|
+ "938CF935318FDCED6BC28286531733C3F03C4FEE");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
function secp160r1() {
|
|
|
|
// p = 2^160 - 2^31 - 1
|
|
|
|
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
|
|
|
|
var a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
|
|
|
|
var b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
|
|
|
|
//byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345");
|
|
|
|
var n = fromHex("0100000000000000000001F4C8F927AED3CA752257");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "4A96B5688EF573284664698968C38BB913CBFC82"
|
|
|
|
+ "23A628553168947D59DCC912042351377AC5FB32");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
function secp192k1() {
|
|
|
|
// p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
|
|
|
|
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
|
|
|
|
var a = BigInteger.ZERO;
|
|
|
|
var b = fromHex("3");
|
|
|
|
//byte[] S = null;
|
|
|
|
var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
|
|
|
|
+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
function secp192r1() {
|
|
|
|
// p = 2^192 - 2^64 - 1
|
|
|
|
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
|
|
|
|
var a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
|
|
|
|
var b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
|
|
|
|
//byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
|
|
|
|
var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
|
|
|
|
+ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
function secp224r1() {
|
|
|
|
// p = 2^224 - 2^96 + 1
|
|
|
|
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
|
|
|
|
var a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
|
|
|
|
var b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
|
|
|
|
//byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
|
|
|
|
var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
|
|
|
|
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
function secp256r1() {
|
|
|
|
// p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
|
|
|
|
var p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
|
|
|
|
var a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
|
|
|
|
var b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
|
|
|
|
//byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
|
|
|
|
var n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
|
|
|
|
var h = BigInteger.ONE;
|
|
|
|
var curve = new ECCurveFp(p, a, b);
|
|
|
|
var G = curve.decodePointHex("04"
|
|
|
|
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
|
|
|
|
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
|
|
|
|
return new X9ECParameters(curve, G, n, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: make this into a proper hashtable
|
|
|
|
function getSECCurveByName(name) {
|
|
|
|
if(name == "secp128r1") return secp128r1();
|
|
|
|
if(name == "secp160k1") return secp160k1();
|
|
|
|
if(name == "secp160r1") return secp160r1();
|
|
|
|
if(name == "secp192k1") return secp192k1();
|
|
|
|
if(name == "secp192r1") return secp192r1();
|
|
|
|
if(name == "secp224r1") return secp224r1();
|
|
|
|
if(name == "secp256k1") return secp256k1();
|
|
|
|
if(name == "secp256r1") return secp256r1();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
function integerToBytes(i, len) {
|
|
|
|
var bytes = i.toByteArrayUnsigned();
|
|
|
|
|
|
|
|
if (len < bytes.length) {
|
|
|
|
bytes = bytes.slice(bytes.length-len);
|
|
|
|
} else while (len > bytes.length) {
|
|
|
|
bytes.unshift(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes;
|
|
|
|
};
|
|
|
|
|
|
|
|
ECFieldElementFp.prototype.getByteLength = function () {
|
|
|
|
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECPointFp.prototype.getEncoded = function (compressed) {
|
|
|
|
var x = this.getX().toBigInteger();
|
|
|
|
var y = this.getY().toBigInteger();
|
|
|
|
|
|
|
|
// Get value as a 32-byte Buffer
|
|
|
|
// Fixed length based on a patch by bitaddress.org and Casascius
|
|
|
|
var enc = integerToBytes(x, 32);
|
|
|
|
|
|
|
|
if (compressed) {
|
|
|
|
if (y.isEven()) {
|
|
|
|
// Compressed even pubkey
|
|
|
|
// M = 02 || X
|
|
|
|
enc.unshift(0x02);
|
|
|
|
} else {
|
|
|
|
// Compressed uneven pubkey
|
|
|
|
// M = 03 || X
|
|
|
|
enc.unshift(0x03);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Uncompressed pubkey
|
|
|
|
// M = 04 || X || Y
|
|
|
|
enc.unshift(0x04);
|
|
|
|
enc = enc.concat(integerToBytes(y, 32));
|
|
|
|
}
|
|
|
|
return enc;
|
|
|
|
};
|
|
|
|
|
2014-03-03 21:52:17 -08:00
|
|
|
ECPointFp.decodeFrom = function (ecparams, enc) {
|
2014-02-20 13:59:41 -08:00
|
|
|
var type = enc[0];
|
|
|
|
var dataLen = enc.length-1;
|
|
|
|
|
|
|
|
// Extract x and y as byte arrays
|
2014-03-03 21:52:17 -08:00
|
|
|
if (type == 4) {
|
|
|
|
var xBa = enc.slice(1, 1 + dataLen/2),
|
|
|
|
yBa = enc.slice(1 + dataLen/2, 1 + dataLen),
|
|
|
|
x = BigInteger.fromByteArrayUnsigned(xBa),
|
|
|
|
y = BigInteger.fromByteArrayUnsigned(yBa);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var xBa = enc.slice(1),
|
|
|
|
x = BigInteger.fromByteArrayUnsigned(xBa),
|
|
|
|
p = ecparams.getQ(),
|
|
|
|
xCubedPlus7 = x.multiply(x).multiply(x).add(new BigInteger('7')).mod(p),
|
|
|
|
pPlus1Over4 = p.add(new BigInteger('1'))
|
|
|
|
.divide(new BigInteger('4')),
|
|
|
|
y = xCubedPlus7.modPow(pPlus1Over4,p);
|
|
|
|
if (y.mod(new BigInteger('2')).toString() != ''+(type % 2)) {
|
|
|
|
y = p.subtract(y)
|
|
|
|
}
|
|
|
|
}
|
2014-02-20 13:59:41 -08:00
|
|
|
|
|
|
|
// Return point
|
2014-03-03 21:52:17 -08:00
|
|
|
return new ECPointFp(ecparams,
|
|
|
|
ecparams.fromBigInteger(x),
|
|
|
|
ecparams.fromBigInteger(y));
|
2014-02-20 13:59:41 -08:00
|
|
|
};
|
|
|
|
|
2014-03-03 21:52:17 -08:00
|
|
|
|
2014-02-20 13:59:41 -08:00
|
|
|
ECPointFp.prototype.add2D = function (b) {
|
|
|
|
if(this.isInfinity()) return b;
|
|
|
|
if(b.isInfinity()) return this;
|
|
|
|
|
|
|
|
if (this.x.equals(b.x)) {
|
|
|
|
if (this.y.equals(b.y)) {
|
|
|
|
// this = b, i.e. this must be doubled
|
|
|
|
return this.twice();
|
|
|
|
}
|
|
|
|
// this = -b, i.e. the result is the point at infinity
|
|
|
|
return this.curve.getInfinity();
|
|
|
|
}
|
|
|
|
|
|
|
|
var x_x = b.x.subtract(this.x);
|
|
|
|
var y_y = b.y.subtract(this.y);
|
|
|
|
var gamma = y_y.divide(x_x);
|
|
|
|
|
|
|
|
var x3 = gamma.square().subtract(this.x).subtract(b.x);
|
|
|
|
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
|
|
|
|
|
|
|
return new ECPointFp(this.curve, x3, y3);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECPointFp.prototype.twice2D = function () {
|
|
|
|
if (this.isInfinity()) return this;
|
|
|
|
if (this.y.toBigInteger().signum() == 0) {
|
|
|
|
// if y1 == 0, then (x1, y1) == (x1, -y1)
|
|
|
|
// and hence this = -this and thus 2(x1, y1) == infinity
|
|
|
|
return this.curve.getInfinity();
|
|
|
|
}
|
|
|
|
|
|
|
|
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
|
|
|
|
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
|
|
|
|
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
|
|
|
|
|
|
|
|
var x3 = gamma.square().subtract(this.x.multiply(TWO));
|
|
|
|
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
|
|
|
|
|
|
|
return new ECPointFp(this.curve, x3, y3);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECPointFp.prototype.multiply2D = function (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.add2D(hBit ? this : neg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return R;
|
|
|
|
};
|
|
|
|
|
|
|
|
ECPointFp.prototype.isOnCurve = function () {
|
|
|
|
var x = this.getX().toBigInteger();
|
|
|
|
var y = this.getY().toBigInteger();
|
|
|
|
var a = this.curve.getA().toBigInteger();
|
|
|
|
var b = this.curve.getB().toBigInteger();
|
|
|
|
var n = this.curve.getQ();
|
|
|
|
var lhs = y.multiply(y).mod(n);
|
|
|
|
var rhs = x.multiply(x).multiply(x)
|
|
|
|
.add(a.multiply(x)).add(b).mod(n);
|
|
|
|
return lhs.equals(rhs);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECPointFp.prototype.toString = function () {
|
|
|
|
return '('+this.getX().toBigInteger().toString()+','+
|
|
|
|
this.getY().toBigInteger().toString()+')';
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validate an elliptic curve point.
|
|
|
|
*
|
|
|
|
* See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
|
|
|
|
*/
|
|
|
|
ECPointFp.prototype.validate = function () {
|
|
|
|
var n = this.curve.getQ();
|
|
|
|
|
|
|
|
// Check Q != O
|
|
|
|
if (this.isInfinity()) {
|
|
|
|
throw new Error("Point is at infinity.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check coordinate bounds
|
|
|
|
var x = this.getX().toBigInteger();
|
|
|
|
var y = this.getY().toBigInteger();
|
|
|
|
if (x.compareTo(BigInteger.ONE) < 0 ||
|
|
|
|
x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
|
|
|
|
throw new Error('x coordinate out of bounds');
|
|
|
|
}
|
|
|
|
if (y.compareTo(BigInteger.ONE) < 0 ||
|
|
|
|
y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
|
|
|
|
throw new Error('y coordinate out of bounds');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check y^2 = x^3 + ax + b (mod n)
|
|
|
|
if (!this.isOnCurve()) {
|
|
|
|
throw new Error("Point is not on the curve.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check nQ = 0 (Q is a scalar multiple of G)
|
|
|
|
if (this.multiply(n).isInfinity()) {
|
|
|
|
// TODO: This check doesn't work - fix.
|
|
|
|
throw new Error("Point is not a scalar multiple of G.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
function dmp(v) {
|
|
|
|
if (!(v instanceof BigInteger)) v = v.toBigInteger();
|
|
|
|
return Crypto.util.bytesToHex(v.toByteArrayUnsigned());
|
|
|
|
};
|
|
|
|
|
|
|
|
Bitcoin.ECDSA = (function () {
|
|
|
|
var ecparams = getSECCurveByName("secp256k1");
|
|
|
|
var rng = new SecureRandom();
|
|
|
|
|
|
|
|
var P_OVER_FOUR = null;
|
|
|
|
|
|
|
|
function implShamirsTrick(P, k, Q, l)
|
|
|
|
{
|
|
|
|
var m = Math.max(k.bitLength(), l.bitLength());
|
|
|
|
var Z = P.add2D(Q);
|
|
|
|
var R = P.curve.getInfinity();
|
|
|
|
|
|
|
|
for (var i = m - 1; i >= 0; --i) {
|
|
|
|
R = R.twice2D();
|
|
|
|
|
|
|
|
R.z = BigInteger.ONE;
|
|
|
|
|
|
|
|
if (k.testBit(i)) {
|
|
|
|
if (l.testBit(i)) {
|
|
|
|
R = R.add2D(Z);
|
|
|
|
} else {
|
|
|
|
R = R.add2D(P);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (l.testBit(i)) {
|
|
|
|
R = R.add2D(Q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return R;
|
|
|
|
};
|
|
|
|
|
|
|
|
var ECDSA = {
|
|
|
|
getBigRandom: function (limit) {
|
|
|
|
return new BigInteger(limit.bitLength(), rng)
|
|
|
|
.mod(limit.subtract(BigInteger.ONE))
|
|
|
|
.add(BigInteger.ONE)
|
|
|
|
;
|
|
|
|
},
|
|
|
|
sign: function (hash, priv) {
|
|
|
|
var d = priv;
|
|
|
|
var n = ecparams.getN();
|
|
|
|
var e = BigInteger.fromByteArrayUnsigned(hash);
|
|
|
|
|
|
|
|
do {
|
|
|
|
var k = ECDSA.getBigRandom(n);
|
|
|
|
var G = ecparams.getG();
|
|
|
|
var Q = G.multiply(k);
|
|
|
|
var r = Q.getX().toBigInteger().mod(n);
|
|
|
|
} while (r.compareTo(BigInteger.ZERO) <= 0);
|
|
|
|
|
|
|
|
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
|
|
|
|
|
|
|
|
return ECDSA.serializeSig(r, s);
|
|
|
|
},
|
|
|
|
|
|
|
|
verify: function (hash, sig, pubkey) {
|
|
|
|
var r,s;
|
|
|
|
if (Bitcoin.Util.isArray(sig)) {
|
|
|
|
var obj = ECDSA.parseSig(sig);
|
|
|
|
r = obj.r;
|
|
|
|
s = obj.s;
|
|
|
|
} else if ("object" === typeof sig && sig.r && sig.s) {
|
|
|
|
r = sig.r;
|
|
|
|
s = sig.s;
|
|
|
|
} else {
|
|
|
|
throw "Invalid value for signature";
|
|
|
|
}
|
|
|
|
|
|
|
|
var Q;
|
|
|
|
if (pubkey instanceof ECPointFp) {
|
|
|
|
Q = pubkey;
|
|
|
|
} else if (Bitcoin.Util.isArray(pubkey)) {
|
|
|
|
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
|
|
|
|
} else {
|
|
|
|
throw "Invalid format for pubkey value, must be byte array or ECPointFp";
|
|
|
|
}
|
|
|
|
var e = BigInteger.fromByteArrayUnsigned(hash);
|
|
|
|
|
|
|
|
return ECDSA.verifyRaw(e, r, s, Q);
|
|
|
|
},
|
|
|
|
|
|
|
|
verifyRaw: function (e, r, s, Q) {
|
|
|
|
var n = ecparams.getN();
|
|
|
|
var G = ecparams.getG();
|
|
|
|
|
|
|
|
if (r.compareTo(BigInteger.ONE) < 0 ||
|
|
|
|
r.compareTo(n) >= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (s.compareTo(BigInteger.ONE) < 0 ||
|
|
|
|
s.compareTo(n) >= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
var c = s.modInverse(n);
|
|
|
|
|
|
|
|
var u1 = e.multiply(c).mod(n);
|
|
|
|
var u2 = r.multiply(c).mod(n);
|
|
|
|
|
|
|
|
// TODO(!!!): For some reason Shamir's trick isn't working with
|
|
|
|
// signed message verification!? Probably an implementation
|
|
|
|
// error!
|
|
|
|
//var point = implShamirsTrick(G, u1, Q, u2);
|
|
|
|
var point = G.multiply(u1).add(Q.multiply(u2));
|
|
|
|
|
|
|
|
var v = point.getX().toBigInteger().mod(n);
|
|
|
|
|
|
|
|
return v.equals(r);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serialize a signature into DER format.
|
|
|
|
*
|
|
|
|
* Takes two BigIntegers representing r and s and returns a byte array.
|
|
|
|
*/
|
|
|
|
serializeSig: function (r, s) {
|
|
|
|
var rBa = r.toByteArraySigned();
|
|
|
|
var sBa = s.toByteArraySigned();
|
|
|
|
|
|
|
|
var sequence = [];
|
|
|
|
sequence.push(0x02); // INTEGER
|
|
|
|
sequence.push(rBa.length);
|
|
|
|
sequence = sequence.concat(rBa);
|
|
|
|
|
|
|
|
sequence.push(0x02); // INTEGER
|
|
|
|
sequence.push(sBa.length);
|
|
|
|
sequence = sequence.concat(sBa);
|
|
|
|
|
|
|
|
sequence.unshift(sequence.length);
|
|
|
|
sequence.unshift(0x30); // SEQUENCE
|
|
|
|
|
|
|
|
return sequence;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses a byte array containing a DER-encoded signature.
|
|
|
|
*
|
|
|
|
* This function will return an object of the form:
|
|
|
|
*
|
|
|
|
* {
|
|
|
|
* r: BigInteger,
|
|
|
|
* s: BigInteger
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
parseSig: function (sig) {
|
|
|
|
var cursor;
|
|
|
|
if (sig[0] != 0x30)
|
|
|
|
throw new Error("Signature not a valid DERSequence");
|
|
|
|
|
|
|
|
cursor = 2;
|
|
|
|
if (sig[cursor] != 0x02)
|
|
|
|
throw new Error("First element in signature must be a DERInteger");;
|
|
|
|
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
|
|
|
|
|
|
|
|
cursor += 2+sig[cursor+1];
|
|
|
|
if (sig[cursor] != 0x02)
|
|
|
|
throw new Error("Second element in signature must be a DERInteger");
|
|
|
|
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
|
|
|
|
|
|
|
|
cursor += 2+sig[cursor+1];
|
|
|
|
|
|
|
|
//if (cursor != sig.length)
|
|
|
|
// throw new Error("Extra bytes in signature");
|
|
|
|
|
|
|
|
var r = BigInteger.fromByteArrayUnsigned(rBa);
|
|
|
|
var s = BigInteger.fromByteArrayUnsigned(sBa);
|
|
|
|
|
|
|
|
return {r: r, s: s};
|
|
|
|
},
|
|
|
|
|
|
|
|
parseSigCompact: function (sig) {
|
|
|
|
if (sig.length !== 65) {
|
|
|
|
throw "Signature has the wrong length";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signature is prefixed with a type byte storing three bits of
|
|
|
|
// information.
|
|
|
|
var i = sig[0] - 27;
|
|
|
|
if (i < 0 || i > 7) {
|
|
|
|
throw "Invalid signature type";
|
|
|
|
}
|
|
|
|
|
|
|
|
var n = ecparams.getN();
|
|
|
|
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
|
|
|
|
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
|
|
|
|
|
|
|
|
return {r: r, s: s, i: i};
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recover a public key from a signature.
|
|
|
|
*
|
|
|
|
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
|
|
|
|
* Key Recovery Operation".
|
|
|
|
*
|
|
|
|
* http://www.secg.org/download/aid-780/sec1-v2.pdf
|
|
|
|
*/
|
|
|
|
recoverPubKey: function (r, s, hash, i) {
|
|
|
|
// The recovery parameter i has two bits.
|
|
|
|
i = i & 3;
|
|
|
|
|
|
|
|
// The less significant bit specifies whether the y coordinate
|
|
|
|
// of the compressed point is even or not.
|
|
|
|
var isYEven = i & 1;
|
|
|
|
|
|
|
|
// The more significant bit specifies whether we should use the
|
|
|
|
// first or second candidate key.
|
|
|
|
var isSecondKey = i >> 1;
|
|
|
|
|
|
|
|
var n = ecparams.getN();
|
|
|
|
var G = ecparams.getG();
|
|
|
|
var curve = ecparams.getCurve();
|
|
|
|
var p = curve.getQ();
|
|
|
|
var a = curve.getA().toBigInteger();
|
|
|
|
var b = curve.getB().toBigInteger();
|
|
|
|
|
|
|
|
// We precalculate (p + 1) / 4 where p is if the field order
|
|
|
|
if (!P_OVER_FOUR) {
|
|
|
|
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 1.1 Compute x
|
|
|
|
var x = isSecondKey ? r.add(n) : r;
|
|
|
|
|
|
|
|
// 1.3 Convert x to point
|
|
|
|
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
|
|
|
|
var beta = alpha.modPow(P_OVER_FOUR, p);
|
|
|
|
|
|
|
|
var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2);
|
|
|
|
// If beta is even, but y isn't or vice versa, then convert it,
|
|
|
|
// otherwise we're done and y == beta.
|
|
|
|
var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
|
|
|
|
|
|
|
|
// 1.4 Check that nR is at infinity
|
|
|
|
var R = new ECPointFp(curve,
|
|
|
|
curve.fromBigInteger(x),
|
|
|
|
curve.fromBigInteger(y));
|
|
|
|
R.validate();
|
|
|
|
|
|
|
|
// 1.5 Compute e from M
|
|
|
|
var e = BigInteger.fromByteArrayUnsigned(hash);
|
|
|
|
var eNeg = BigInteger.ZERO.subtract(e).mod(n);
|
|
|
|
|
|
|
|
// 1.6 Compute Q = r^-1 (sR - eG)
|
|
|
|
var rInv = r.modInverse(n);
|
|
|
|
var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
|
|
|
|
|
|
|
|
Q.validate();
|
|
|
|
if (!ECDSA.verifyRaw(e, r, s, Q)) {
|
|
|
|
throw "Pubkey recovery unsuccessful";
|
|
|
|
}
|
|
|
|
|
|
|
|
var pubKey = new Bitcoin.ECKey();
|
|
|
|
pubKey.pub = Q;
|
|
|
|
return pubKey;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate pubkey extraction parameter.
|
|
|
|
*
|
|
|
|
* When extracting a pubkey from a signature, we have to
|
|
|
|
* distinguish four different cases. Rather than putting this
|
|
|
|
* burden on the verifier, Bitcoin includes a 2-bit value with the
|
|
|
|
* signature.
|
|
|
|
*
|
|
|
|
* This function simply tries all four cases and returns the value
|
|
|
|
* that resulted in a successful pubkey recovery.
|
|
|
|
*/
|
|
|
|
calcPubkeyRecoveryParam: function (address, r, s, hash)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < 4; i++) {
|
|
|
|
try {
|
|
|
|
var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
|
|
|
|
if (pubkey.getBitcoinAddress().toString() == address) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
throw "Unable to find valid recovery factor";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return ECDSA;
|
|
|
|
})();
|
|
|
|
Bitcoin.ECKey = (function () {
|
|
|
|
var ECDSA = Bitcoin.ECDSA;
|
|
|
|
var ecparams = getSECCurveByName("secp256k1");
|
|
|
|
var rng = new SecureRandom();
|
|
|
|
|
|
|
|
var ECKey = function (input) {
|
|
|
|
if (!input) {
|
|
|
|
// Generate new key
|
|
|
|
var n = ecparams.getN();
|
|
|
|
this.priv = ECDSA.getBigRandom(n);
|
|
|
|
} else if (input instanceof BigInteger) {
|
|
|
|
// Input is a private key value
|
|
|
|
this.priv = input;
|
|
|
|
} else if (Bitcoin.Util.isArray(input)) {
|
|
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(input);
|
|
|
|
} else if ("string" == typeof input) {
|
|
|
|
if (input.length == 51 && input[0] == '5') {
|
|
|
|
// Base58 encoded private key
|
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(ECKey.decodeString(input));
|
|
|
|
} else {
|
|
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
2014-02-21 10:19:38 -08:00
|
|
|
this.priv = BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(input));
|
2014-02-20 13:59:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.compressed = !!ECKey.compressByDefault;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether public keys should be returned compressed by default.
|
|
|
|
*/
|
|
|
|
ECKey.compressByDefault = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set whether the public key should be returned compressed or not.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.setCompressed = function (v) {
|
|
|
|
this.compressed = !!v;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return public key in DER encoding.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.getPub = function () {
|
|
|
|
return this.getPubPoint().getEncoded(this.compressed);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return public point as ECPoint object.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.getPubPoint = function () {
|
|
|
|
if (!this.pub) this.pub = ecparams.getG().multiply(this.priv);
|
|
|
|
|
|
|
|
return this.pub;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the pubKeyHash for this key.
|
|
|
|
*
|
|
|
|
* This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
|
|
|
|
* a byte array.
|
|
|
|
*/
|
|
|
|
ECKey.prototype.getPubKeyHash = function () {
|
|
|
|
if (this.pubKeyHash) return this.pubKeyHash;
|
|
|
|
|
|
|
|
return this.pubKeyHash = Bitcoin.Util.sha256ripe160(this.getPub());
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.getBitcoinAddress = function () {
|
|
|
|
var hash = this.getPubKeyHash();
|
|
|
|
var addr = new Bitcoin.Address(hash);
|
|
|
|
return addr;
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.getExportedPrivateKey = function () {
|
|
|
|
var hash = this.priv.toByteArrayUnsigned();
|
|
|
|
while (hash.length < 32) hash.unshift(0);
|
|
|
|
hash.unshift(0x80);
|
|
|
|
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
|
|
|
|
var bytes = hash.concat(checksum.slice(0,4));
|
|
|
|
return Bitcoin.Base58.encode(bytes);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.setPub = function (pub) {
|
|
|
|
this.pub = ECPointFp.decodeFrom(ecparams.getCurve(), pub);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.toString = function (format) {
|
|
|
|
if (format === "base64") {
|
|
|
|
return Crypto.util.bytesToBase64(this.priv.toByteArrayUnsigned());
|
|
|
|
} else {
|
|
|
|
return Crypto.util.bytesToHex(this.priv.toByteArrayUnsigned());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.sign = function (hash) {
|
|
|
|
return ECDSA.sign(hash, this.priv);
|
|
|
|
};
|
|
|
|
|
|
|
|
ECKey.prototype.verify = function (hash, sig) {
|
|
|
|
return ECDSA.verify(hash, sig, this.getPub());
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse an exported private key contained in a string.
|
|
|
|
*/
|
|
|
|
ECKey.decodeString = function (string) {
|
|
|
|
var bytes = Bitcoin.Base58.decode(string);
|
|
|
|
|
|
|
|
var hash = bytes.slice(0, 33);
|
|
|
|
|
|
|
|
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
|
|
|
|
|
|
|
|
if (checksum[0] != bytes[33] ||
|
|
|
|
checksum[1] != bytes[34] ||
|
|
|
|
checksum[2] != bytes[35] ||
|
|
|
|
checksum[3] != bytes[36]) {
|
|
|
|
throw "Checksum validation failed!";
|
|
|
|
}
|
|
|
|
|
|
|
|
var version = hash.shift();
|
|
|
|
|
|
|
|
if (version != 0x80) {
|
|
|
|
throw "Version "+version+" not supported!";
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
};
|
|
|
|
|
|
|
|
return ECKey;
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
module.exports.ECKey = Bitcoin.ECKey;
|