4203 lines
No EOL
169 KiB
HTML
4203 lines
No EOL
169 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>bitaddress.org</title>
|
|
<script type="text/javascript">
|
|
// Production steps of ECMA-262, Edition 5, 15.4.4.19
|
|
// Reference: http://es5.github.com/#x15.4.4.19
|
|
if (!Array.prototype.map) {
|
|
Array.prototype.map = function (callback, thisArg) {
|
|
var T, A, k;
|
|
if (this == null) {
|
|
throw new TypeError(" this is null or not defined");
|
|
}
|
|
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
|
|
var O = Object(this);
|
|
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
|
|
// 3. Let len be ToUint32(lenValue).
|
|
var len = O.length >>> 0;
|
|
// 4. If IsCallable(callback) is false, throw a TypeError exception.
|
|
// See: http://es5.github.com/#x9.11
|
|
if ({}.toString.call(callback) != "[object Function]") {
|
|
throw new TypeError(callback + " is not a function");
|
|
}
|
|
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
|
if (thisArg) {
|
|
T = thisArg;
|
|
}
|
|
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
|
|
// the standard built-in constructor with that name and len is the value of len.
|
|
A = new Array(len);
|
|
// 7. Let k be 0
|
|
k = 0;
|
|
// 8. Repeat, while k < len
|
|
while (k < len) {
|
|
var kValue, mappedValue;
|
|
// a. Let Pk be ToString(k).
|
|
// This is implicit for LHS operands of the in operator
|
|
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
|
|
// This step can be combined with c
|
|
// c. If kPresent is true, then
|
|
if (k in O) {
|
|
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
|
|
kValue = O[k];
|
|
// ii. Let mappedValue be the result of calling the Call internal method of callback
|
|
// with T as the this value and argument list containing kValue, k, and O.
|
|
mappedValue = callback.call(T, kValue, k, O);
|
|
// iii. Call the DefineOwnProperty internal method of A with arguments
|
|
// Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true},
|
|
// and false.
|
|
// In browsers that support Object.defineProperty, use the following:
|
|
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
|
|
// For best browser support, use the following:
|
|
A[k] = mappedValue;
|
|
}
|
|
// d. Increase k by 1.
|
|
k++;
|
|
}
|
|
// 9. return A
|
|
return A;
|
|
};
|
|
}
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
/*!
|
|
* 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
|
|
*/
|
|
(function () {
|
|
|
|
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("");
|
|
}
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
|
|
/*!
|
|
* 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
|
|
*/
|
|
(function () {
|
|
|
|
// Shortcuts
|
|
var C = Crypto,
|
|
util = C.util,
|
|
charenc = C.charenc,
|
|
UTF8 = charenc.UTF8,
|
|
Binary = charenc.Binary;
|
|
|
|
// Constants
|
|
var K = [0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
|
|
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
|
|
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
|
|
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
|
|
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
|
|
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
|
|
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
|
|
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
|
|
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
|
|
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
|
|
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
|
|
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
|
|
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
|
|
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
|
|
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
|
|
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2];
|
|
|
|
// Public API
|
|
var SHA256 = C.SHA256 = function (message, options) {
|
|
var digestbytes = util.wordsToBytes(SHA256._sha256(message));
|
|
return options && options.asBytes ? digestbytes :
|
|
options && options.asString ? Binary.bytesToString(digestbytes) :
|
|
util.bytesToHex(digestbytes);
|
|
};
|
|
|
|
// The core
|
|
SHA256._sha256 = function (message) {
|
|
|
|
// Convert to byte array
|
|
if (message.constructor == String) message = UTF8.stringToBytes(message);
|
|
/* else, assume byte array already */
|
|
|
|
var m = util.bytesToWords(message),
|
|
l = message.length * 8,
|
|
H = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
|
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19],
|
|
w = [],
|
|
a, b, c, d, e, f, g, h, i, j,
|
|
t1, t2;
|
|
|
|
// Padding
|
|
m[l >> 5] |= 0x80 << (24 - l % 32);
|
|
m[((l + 64 >> 9) << 4) + 15] = l;
|
|
|
|
for (var i = 0; i < m.length; i += 16) {
|
|
|
|
a = H[0];
|
|
b = H[1];
|
|
c = H[2];
|
|
d = H[3];
|
|
e = H[4];
|
|
f = H[5];
|
|
g = H[6];
|
|
h = H[7];
|
|
|
|
for (var j = 0; j < 64; j++) {
|
|
|
|
if (j < 16) w[j] = m[j + i];
|
|
else {
|
|
|
|
var gamma0x = w[j - 15],
|
|
gamma1x = w[j - 2],
|
|
gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
|
|
((gamma0x << 14) | (gamma0x >>> 18)) ^
|
|
(gamma0x >>> 3),
|
|
gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
|
|
((gamma1x << 13) | (gamma1x >>> 19)) ^
|
|
(gamma1x >>> 10);
|
|
|
|
w[j] = gamma0 + (w[j - 7] >>> 0) +
|
|
gamma1 + (w[j - 16] >>> 0);
|
|
|
|
}
|
|
|
|
var ch = e & f ^ ~e & g,
|
|
maj = a & b ^ a & c ^ b & c,
|
|
sigma0 = ((a << 30) | (a >>> 2)) ^
|
|
((a << 19) | (a >>> 13)) ^
|
|
((a << 10) | (a >>> 22)),
|
|
sigma1 = ((e << 26) | (e >>> 6)) ^
|
|
((e << 21) | (e >>> 11)) ^
|
|
((e << 7) | (e >>> 25));
|
|
|
|
|
|
t1 = (h >>> 0) + sigma1 + ch + (K[j]) + (w[j] >>> 0);
|
|
t2 = sigma0 + maj;
|
|
|
|
h = g;
|
|
g = f;
|
|
f = e;
|
|
e = d + t1;
|
|
d = c;
|
|
c = b;
|
|
b = a;
|
|
a = t1 + t2;
|
|
|
|
}
|
|
|
|
H[0] += a;
|
|
H[1] += b;
|
|
H[2] += c;
|
|
H[3] += d;
|
|
H[4] += e;
|
|
H[5] += f;
|
|
H[6] += g;
|
|
H[7] += h;
|
|
|
|
}
|
|
|
|
return H;
|
|
|
|
};
|
|
|
|
// Package private blocksize
|
|
SHA256._blocksize = 16;
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
* 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
|
|
*
|
|
* A JavaScript implementation of the RIPEMD-160 Algorithm
|
|
* Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
* Distributed under the BSD License
|
|
* See http://pajhome.org.uk/crypt/md5 for details.
|
|
* Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
|
|
* Ported to Crypto-JS by Stefan Thomas.
|
|
*/
|
|
|
|
(function () {
|
|
// Shortcuts
|
|
var C = Crypto,
|
|
util = C.util,
|
|
charenc = C.charenc,
|
|
UTF8 = charenc.UTF8,
|
|
Binary = charenc.Binary;
|
|
|
|
// Convert a byte array to little-endian 32-bit words
|
|
util.bytesToLWords = function (bytes) {
|
|
|
|
var output = Array(bytes.length >> 2);
|
|
for (var i = 0; i < output.length; i++)
|
|
output[i] = 0;
|
|
for (var i = 0; i < bytes.length * 8; i += 8)
|
|
output[i >> 5] |= (bytes[i / 8] & 0xFF) << (i % 32);
|
|
return output;
|
|
};
|
|
|
|
// Convert little-endian 32-bit words to a byte array
|
|
util.lWordsToBytes = function (words) {
|
|
var output = [];
|
|
for (var i = 0; i < words.length * 32; i += 8)
|
|
output.push((words[i >> 5] >>> (i % 32)) & 0xff);
|
|
return output;
|
|
};
|
|
|
|
// Public API
|
|
var RIPEMD160 = C.RIPEMD160 = function (message, options) {
|
|
var digestbytes = util.lWordsToBytes(RIPEMD160._rmd160(message));
|
|
return options && options.asBytes ? digestbytes :
|
|
options && options.asString ? Binary.bytesToString(digestbytes) :
|
|
util.bytesToHex(digestbytes);
|
|
};
|
|
|
|
// The core
|
|
RIPEMD160._rmd160 = function (message) {
|
|
// Convert to byte array
|
|
if (message.constructor == String) message = UTF8.stringToBytes(message);
|
|
|
|
var x = util.bytesToLWords(message),
|
|
len = message.length * 8;
|
|
|
|
/* append padding */
|
|
x[len >> 5] |= 0x80 << (len % 32);
|
|
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
|
|
|
var h0 = 0x67452301;
|
|
var h1 = 0xefcdab89;
|
|
var h2 = 0x98badcfe;
|
|
var h3 = 0x10325476;
|
|
var h4 = 0xc3d2e1f0;
|
|
|
|
for (var i = 0; i < x.length; i += 16) {
|
|
var T;
|
|
var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
|
|
var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
|
|
for (var j = 0; j <= 79; ++j) {
|
|
T = safe_add(A1, rmd160_f(j, B1, C1, D1));
|
|
T = safe_add(T, x[i + rmd160_r1[j]]);
|
|
T = safe_add(T, rmd160_K1(j));
|
|
T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
|
|
A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
|
|
T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
|
|
T = safe_add(T, x[i + rmd160_r2[j]]);
|
|
T = safe_add(T, rmd160_K2(j));
|
|
T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
|
|
A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
|
|
}
|
|
T = safe_add(h1, safe_add(C1, D2));
|
|
h1 = safe_add(h2, safe_add(D1, E2));
|
|
h2 = safe_add(h3, safe_add(E1, A2));
|
|
h3 = safe_add(h4, safe_add(A1, B2));
|
|
h4 = safe_add(h0, safe_add(B1, C2));
|
|
h0 = T;
|
|
}
|
|
return [h0, h1, h2, h3, h4];
|
|
}
|
|
|
|
function rmd160_f(j, x, y, z) {
|
|
return (0 <= j && j <= 15) ? (x ^ y ^ z) :
|
|
(16 <= j && j <= 31) ? (x & y) | (~x & z) :
|
|
(32 <= j && j <= 47) ? (x | ~y) ^ z :
|
|
(48 <= j && j <= 63) ? (x & z) | (y & ~z) :
|
|
(64 <= j && j <= 79) ? x ^ (y | ~z) :
|
|
"rmd160_f: j out of range";
|
|
}
|
|
function rmd160_K1(j) {
|
|
return (0 <= j && j <= 15) ? 0x00000000 :
|
|
(16 <= j && j <= 31) ? 0x5a827999 :
|
|
(32 <= j && j <= 47) ? 0x6ed9eba1 :
|
|
(48 <= j && j <= 63) ? 0x8f1bbcdc :
|
|
(64 <= j && j <= 79) ? 0xa953fd4e :
|
|
"rmd160_K1: j out of range";
|
|
}
|
|
function rmd160_K2(j) {
|
|
return (0 <= j && j <= 15) ? 0x50a28be6 :
|
|
(16 <= j && j <= 31) ? 0x5c4dd124 :
|
|
(32 <= j && j <= 47) ? 0x6d703ef3 :
|
|
(48 <= j && j <= 63) ? 0x7a6d76e9 :
|
|
(64 <= j && j <= 79) ? 0x00000000 :
|
|
"rmd160_K2: j out of range";
|
|
}
|
|
var rmd160_r1 = [
|
|
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
|
|
];
|
|
var rmd160_r2 = [
|
|
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
|
|
];
|
|
var rmd160_s1 = [
|
|
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
|
|
];
|
|
var rmd160_s2 = [
|
|
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
|
|
];
|
|
|
|
/*
|
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
|
* to work around bugs in some JS interpreters.
|
|
*/
|
|
function safe_add(x, y) {
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
}
|
|
|
|
/*
|
|
* Bitwise rotate a 32-bit number to the left.
|
|
*/
|
|
function bit_rol(num, cnt) {
|
|
return (num << cnt) | (num >>> (32 - cnt));
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
/*!
|
|
* Random number generator with ArcFour PRNG
|
|
*
|
|
* NOTE: For best results, put code like
|
|
* <body onclick='SecureRandom.seedTime();' onkeypress='SecureRandom.seedTime();'>
|
|
* in your main HTML document.
|
|
*
|
|
* Copyright Tom Wu. BSD License.
|
|
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
|
*
|
|
* Copyright bitaddress.org
|
|
*/
|
|
(function () {
|
|
|
|
// Constructor function of Global SecureRandom object
|
|
var sr = window.SecureRandom = function () { };
|
|
|
|
// Properties
|
|
sr.state;
|
|
sr.pool;
|
|
sr.pptr;
|
|
|
|
// 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()
|
|
sr.poolSize = 256;
|
|
|
|
|
|
// --- object methods ---
|
|
|
|
// public method
|
|
// ba: byte array
|
|
sr.prototype.nextBytes = function (ba) {
|
|
var i;
|
|
for (i = 0; i < ba.length; ++i) ba[i] = sr.getByte();
|
|
};
|
|
|
|
|
|
// --- static methods ---
|
|
|
|
// Mix in the current time (w/milliseconds) into the pool
|
|
// NOTE: this method should be called from body click/keypress event handlers to increase entropy
|
|
sr.seedTime = function () {
|
|
sr.seedInt(new Date().getTime());
|
|
}
|
|
|
|
sr.getByte = function () {
|
|
if (sr.state == null) {
|
|
sr.seedTime();
|
|
sr.state = sr.ArcFour(); // Plug in your RNG constructor here
|
|
sr.state.init(sr.pool);
|
|
for (sr.pptr = 0; sr.pptr < sr.pool.length; ++sr.pptr)
|
|
sr.pool[sr.pptr] = 0;
|
|
sr.pptr = 0;
|
|
}
|
|
// TODO: allow reseeding after first request
|
|
return sr.state.next();
|
|
}
|
|
|
|
// Mix in a 32-bit integer into the pool
|
|
sr.seedInt = function (x) {
|
|
sr.pool[sr.pptr++] ^= x & 255;
|
|
sr.pool[sr.pptr++] ^= (x >> 8) & 255;
|
|
sr.pool[sr.pptr++] ^= (x >> 16) & 255;
|
|
sr.pool[sr.pptr++] ^= (x >> 24) & 255;
|
|
if (sr.pptr >= sr.poolSize) sr.pptr -= sr.poolSize;
|
|
}
|
|
|
|
|
|
// Arcfour is a PRNG
|
|
sr.ArcFour = function () {
|
|
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;
|
|
|
|
return new Arcfour();
|
|
};
|
|
|
|
|
|
// Initialize the pool with junk if needed.
|
|
if (sr.pool == null) {
|
|
sr.pool = new Array();
|
|
sr.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)
|
|
sr.pool[sr.pptr++] = z.charCodeAt(t) & 255;
|
|
}
|
|
while (sr.pptr < sr.poolSize) { // extract some randomness from Math.random()
|
|
t = Math.floor(65536 * Math.random());
|
|
sr.pool[sr.pptr++] = t >>> 8;
|
|
sr.pool[sr.pptr++] = t & 255;
|
|
}
|
|
sr.pptr = 0;
|
|
sr.seedTime();
|
|
}
|
|
|
|
})();
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
/*!
|
|
* Basic Javascript Elliptic Curve implementation
|
|
* Ported loosely from BouncyCastle's Java EC code
|
|
* Only Fp curves implemented for now
|
|
*
|
|
* Copyright Tom Wu. BSD License.
|
|
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
|
*
|
|
* Copyright bitaddress.org
|
|
*/
|
|
(function () {
|
|
|
|
// Constructor function of Global EllipticCurve object
|
|
var ec = window.EllipticCurve = function () { };
|
|
|
|
|
|
// ----------------
|
|
// ECFieldElementFp constructor
|
|
ec.FieldElementFp = function (q, x) {
|
|
this.x = x;
|
|
// TODO if(x.compareTo(q) >= 0) error
|
|
this.q = q;
|
|
}
|
|
|
|
ec.FieldElementFp.prototype.equals = function (other) {
|
|
if (other == this) return true;
|
|
return (this.q.equals(other.q) && this.x.equals(other.x));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.toBigInteger = function () {
|
|
return this.x;
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.negate = function () {
|
|
return new ec.FieldElementFp(this.q, this.x.negate().mod(this.q));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.add = function (b) {
|
|
return new ec.FieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.subtract = function (b) {
|
|
return new ec.FieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.multiply = function (b) {
|
|
return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.square = function () {
|
|
return new ec.FieldElementFp(this.q, this.x.square().mod(this.q));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.divide = function (b) {
|
|
return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));
|
|
};
|
|
|
|
ec.FieldElementFp.prototype.getByteLength = function () {
|
|
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
|
|
};
|
|
|
|
// ----------------
|
|
// ECPointFp constructor
|
|
ec.PointFp = function (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
|
|
};
|
|
|
|
ec.PointFp.prototype.getX = function () {
|
|
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));
|
|
};
|
|
|
|
ec.PointFp.prototype.getY = function () {
|
|
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));
|
|
};
|
|
|
|
ec.PointFp.prototype.equals = function (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);
|
|
};
|
|
|
|
ec.PointFp.prototype.isInfinity = function () {
|
|
if ((this.x == null) && (this.y == null)) return true;
|
|
return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
|
|
};
|
|
|
|
ec.PointFp.prototype.negate = function () {
|
|
return new ec.PointFp(this.curve, this.x, this.y.negate(), this.z);
|
|
};
|
|
|
|
ec.PointFp.prototype.add = function (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 ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
|
|
};
|
|
|
|
ec.PointFp.prototype.twice = function () {
|
|
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 ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
|
|
};
|
|
|
|
// Simple NAF (Non-Adjacent Form) multiplication algorithm
|
|
// TODO: modularize the multiplication algorithm
|
|
ec.PointFp.prototype.multiply = 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.add(hBit ? this : neg);
|
|
}
|
|
}
|
|
|
|
return R;
|
|
};
|
|
|
|
// Compute this*j + x*k (simultaneous multiplication)
|
|
ec.PointFp.prototype.multiplyTwo = function (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;
|
|
};
|
|
|
|
// patched by bitaddress.org and Casascius for use with Bitcoin.ECKey
|
|
ec.PointFp.prototype.getEncoded = function () {
|
|
var x = this.getX().toBigInteger();
|
|
var y = this.getY().toBigInteger();
|
|
var len = 32; // integerToBytes will zero pad if integer is less than 32 bytes. 32 bytes length is required by the Bitcoin protocol.
|
|
var enc = ec.integerToBytes(x, len);
|
|
enc.unshift(0x04);
|
|
enc = enc.concat(ec.integerToBytes(y, len));
|
|
return enc;
|
|
};
|
|
|
|
ec.PointFp.decodeFrom = function (curve, enc) {
|
|
var type = enc[0];
|
|
var dataLen = enc.length - 1;
|
|
|
|
// Extract x and y as byte arrays
|
|
var xBa = enc.slice(1, 1 + dataLen / 2);
|
|
var yBa = enc.slice(1 + dataLen / 2, 1 + dataLen);
|
|
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
|
xBa.unshift(0);
|
|
yBa.unshift(0);
|
|
|
|
// Convert to BigIntegers
|
|
var x = new BigInteger(xBa);
|
|
var y = new BigInteger(yBa);
|
|
|
|
// Return point
|
|
return new ec.PointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
|
|
};
|
|
|
|
ec.PointFp.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 ec.PointFp(this.curve, x3, y3);
|
|
};
|
|
|
|
ec.PointFp.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 ec.PointFp(this.curve, x3, y3);
|
|
};
|
|
|
|
ec.PointFp.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;
|
|
};
|
|
|
|
ec.PointFp.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);
|
|
};
|
|
|
|
ec.PointFp.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;
|
|
};
|
|
|
|
|
|
|
|
|
|
// ----------------
|
|
// ECCurveFp constructor
|
|
ec.CurveFp = function (q, a, b) {
|
|
this.q = q;
|
|
this.a = this.fromBigInteger(a);
|
|
this.b = this.fromBigInteger(b);
|
|
this.infinity = new ec.PointFp(this, null, null);
|
|
}
|
|
|
|
ec.CurveFp.prototype.getQ = function () {
|
|
return this.q;
|
|
};
|
|
|
|
ec.CurveFp.prototype.getA = function () {
|
|
return this.a;
|
|
};
|
|
|
|
ec.CurveFp.prototype.getB = function () {
|
|
return this.b;
|
|
};
|
|
|
|
ec.CurveFp.prototype.equals = function (other) {
|
|
if (other == this) return true;
|
|
return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));
|
|
};
|
|
|
|
ec.CurveFp.prototype.getInfinity = function () {
|
|
return this.infinity;
|
|
};
|
|
|
|
ec.CurveFp.prototype.fromBigInteger = function (x) {
|
|
return new ec.FieldElementFp(this.q, x);
|
|
};
|
|
|
|
// for now, work with hex strings because they're easier in JS
|
|
ec.CurveFp.prototype.decodePointHex = function (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 ec.PointFp(this,
|
|
this.fromBigInteger(new BigInteger(xHex, 16)),
|
|
this.fromBigInteger(new BigInteger(yHex, 16)));
|
|
|
|
default: // unsupported
|
|
return null;
|
|
}
|
|
};
|
|
|
|
|
|
ec.fromHex = function (s) { return new BigInteger(s, 16); };
|
|
|
|
ec.integerToBytes = function (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;
|
|
};
|
|
|
|
|
|
// Named EC curves
|
|
// ----------------
|
|
// X9ECParameters constructor
|
|
ec.X9Parameters = function (curve, g, n, h) {
|
|
this.curve = curve;
|
|
this.g = g;
|
|
this.n = n;
|
|
this.h = h;
|
|
}
|
|
ec.X9Parameters.prototype.getCurve = function () { return this.curve; };
|
|
ec.X9Parameters.prototype.getG = function () { return this.g; };
|
|
ec.X9Parameters.prototype.getN = function () { return this.n; };
|
|
ec.X9Parameters.prototype.getH = function () { return this.h; };
|
|
|
|
// secp256k1 is the Curve used by Bitcoin
|
|
ec.secNamedCurves = {
|
|
// used by Bitcoin
|
|
"secp256k1": function () {
|
|
// p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
|
|
var p = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
|
|
var a = BigInteger.ZERO;
|
|
var b = ec.fromHex("7");
|
|
var n = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
|
|
var h = BigInteger.ONE;
|
|
var curve = new ec.CurveFp(p, a, b);
|
|
var G = curve.decodePointHex("04"
|
|
+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
|
|
+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");
|
|
return new ec.X9Parameters(curve, G, n, h);
|
|
}
|
|
};
|
|
|
|
// secp256k1 called by Bitcoin's ECKEY
|
|
ec.getSECCurveByName = function (name) {
|
|
if (ec.secNamedCurves[name] == undefined) return null;
|
|
return ec.secNamedCurves[name]();
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
/*!
|
|
* Basic JavaScript BN library - subset useful for RSA encryption.
|
|
*
|
|
* Copyright (c) 2005 Tom Wu
|
|
* All Rights Reserved.
|
|
* See "LICENSE" for details.
|
|
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
|
*
|
|
* Copyright Stephan Thomas
|
|
* Copyright bitaddress.org
|
|
*/
|
|
|
|
(function () {
|
|
|
|
// (public) Constructor function of Global BigInteger object
|
|
var BigInteger = window.BigInteger = 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);
|
|
};
|
|
|
|
// Bits per digit
|
|
var dbits;
|
|
|
|
// JavaScript engine analysis
|
|
var canary = 0xdeadbeefcafe;
|
|
var j_lm = ((canary & 0xffffff) == 0xefcafe);
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
|
|
// return bigint initialized to value
|
|
function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// (protected) copy this to r
|
|
BigInteger.prototype.copyTo = function (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
|
|
BigInteger.prototype.fromInt = function (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;
|
|
};
|
|
|
|
// (protected) set from string and radix
|
|
BigInteger.prototype.fromString = function (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
|
|
BigInteger.prototype.clamp = function () {
|
|
var c = this.s & this.DM;
|
|
while (this.t > 0 && this[this.t - 1] == c) --this.t;
|
|
};
|
|
|
|
// (protected) r = this << n*DB
|
|
BigInteger.prototype.dlShiftTo = function (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
|
|
BigInteger.prototype.drShiftTo = function (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
|
|
BigInteger.prototype.lShiftTo = function (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
|
|
BigInteger.prototype.rShiftTo = function (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
|
|
BigInteger.prototype.subTo = function (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.
|
|
BigInteger.prototype.multiplyTo = function (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)
|
|
BigInteger.prototype.squareTo = function (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.
|
|
BigInteger.prototype.divRemTo = function (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);
|
|
};
|
|
|
|
|
|
// (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.
|
|
BigInteger.prototype.invDigit = function () {
|
|
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;
|
|
};
|
|
|
|
|
|
// (protected) true iff this is even
|
|
BigInteger.prototype.isEven = function () { 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)
|
|
BigInteger.prototype.exp = function (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) return string representation in given radix
|
|
BigInteger.prototype.toString = function (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
|
|
BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; };
|
|
|
|
// (public) |this|
|
|
BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this; };
|
|
|
|
// (public) return + if this > a, - if this < a, 0 if equal
|
|
BigInteger.prototype.compareTo = function (a) {
|
|
var r = this.s - a.s;
|
|
if (r != 0) return r;
|
|
var i = this.t;
|
|
r = i - a.t;
|
|
if (r != 0) return r;
|
|
while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
|
|
return 0;
|
|
}
|
|
|
|
// (public) return the number of bits in "this"
|
|
BigInteger.prototype.bitLength = function () {
|
|
if (this.t <= 0) return 0;
|
|
return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
|
|
};
|
|
|
|
// (public) this mod a
|
|
BigInteger.prototype.mod = function (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;
|
|
}
|
|
|
|
// (public) this^e % m, 0 <= e < 2^32
|
|
BigInteger.prototype.modPowInt = function (e, m) {
|
|
var z;
|
|
if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
|
|
return this.exp(e, z);
|
|
};
|
|
|
|
// "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
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
// return number of 1 bits in x
|
|
function cbit(x) {
|
|
var r = 0;
|
|
while (x != 0) { x &= x - 1; ++r; }
|
|
return r;
|
|
}
|
|
|
|
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];
|
|
|
|
|
|
|
|
// (protected) return x s.t. r^x < DV
|
|
BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); };
|
|
|
|
// (protected) convert to radix string
|
|
BigInteger.prototype.toRadix = function (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
|
|
BigInteger.prototype.fromRadix = function (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
|
|
BigInteger.prototype.fromNumber = function (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);
|
|
}
|
|
};
|
|
|
|
// (protected) r = this op a (bitwise)
|
|
BigInteger.prototype.bitwiseTo = function (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();
|
|
};
|
|
|
|
// (protected) this op (1<<n)
|
|
BigInteger.prototype.changeBit = function (n, op) {
|
|
var r = BigInteger.ONE.shiftLeft(n);
|
|
this.bitwiseTo(r, op, r);
|
|
return r;
|
|
};
|
|
|
|
// (protected) r = this + a
|
|
BigInteger.prototype.addTo = function (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();
|
|
};
|
|
|
|
// (protected) this *= n, this >= 0, 1 < n < DV
|
|
BigInteger.prototype.dMultiply = function (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
|
|
BigInteger.prototype.dAddOffset = function (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];
|
|
}
|
|
};
|
|
|
|
// (protected) r = lower n words of "this * a", a.t <= n
|
|
// "this" should be the larger one if appropriate.
|
|
BigInteger.prototype.multiplyLowerTo = function (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.
|
|
BigInteger.prototype.multiplyUpperTo = function (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);
|
|
};
|
|
|
|
// (protected) this % n, n < 2^26
|
|
BigInteger.prototype.modInt = function (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;
|
|
};
|
|
|
|
|
|
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
|
|
BigInteger.prototype.millerRabin = function (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;
|
|
};
|
|
|
|
|
|
|
|
// (public)
|
|
BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r; };
|
|
|
|
// (public) return value as integer
|
|
BigInteger.prototype.intValue = function () {
|
|
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
|
|
BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; };
|
|
|
|
// (public) return value as short (assumes DB>=16)
|
|
BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; };
|
|
|
|
// (public) 0 if this == 0, 1 if this > 0
|
|
BigInteger.prototype.signum = function () {
|
|
if (this.s < 0) return -1;
|
|
else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
|
|
else return 1;
|
|
};
|
|
|
|
|
|
// (public) convert to bigendian byte array
|
|
BigInteger.prototype.toByteArray = function () {
|
|
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;
|
|
};
|
|
|
|
BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0); };
|
|
BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a; };
|
|
BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a; };
|
|
|
|
// (public) this & a
|
|
function op_and(x, y) { return x & y; }
|
|
BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; };
|
|
|
|
// (public) this | a
|
|
function op_or(x, y) { return x | y; }
|
|
BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; };
|
|
|
|
// (public) this ^ a
|
|
function op_xor(x, y) { return x ^ y; }
|
|
BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; };
|
|
|
|
// (public) this & ~a
|
|
function op_andnot(x, y) { return x & ~y; }
|
|
BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; };
|
|
|
|
// (public) ~this
|
|
BigInteger.prototype.not = function () {
|
|
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
|
|
BigInteger.prototype.shiftLeft = function (n) {
|
|
var r = nbi();
|
|
if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r);
|
|
return r;
|
|
};
|
|
|
|
// (public) this >> n
|
|
BigInteger.prototype.shiftRight = function (n) {
|
|
var r = nbi();
|
|
if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r);
|
|
return r;
|
|
};
|
|
|
|
// (public) returns index of lowest 1-bit (or -1 if none)
|
|
BigInteger.prototype.getLowestSetBit = function () {
|
|
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;
|
|
};
|
|
|
|
// (public) return number of set bits
|
|
BigInteger.prototype.bitCount = function () {
|
|
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
|
|
BigInteger.prototype.testBit = function (n) {
|
|
var j = Math.floor(n / this.DB);
|
|
if (j >= this.t) return (this.s != 0);
|
|
return ((this[j] & (1 << (n % this.DB))) != 0);
|
|
};
|
|
|
|
// (public) this | (1<<n)
|
|
BigInteger.prototype.setBit = function (n) { return this.changeBit(n, op_or); };
|
|
// (public) this & ~(1<<n)
|
|
BigInteger.prototype.clearBit = function (n) { return this.changeBit(n, op_andnot); };
|
|
// (public) this ^ (1<<n)
|
|
BigInteger.prototype.flipBit = function (n) { return this.changeBit(n, op_xor); };
|
|
// (public) this + a
|
|
BigInteger.prototype.add = function (a) { var r = nbi(); this.addTo(a, r); return r; };
|
|
// (public) this - a
|
|
BigInteger.prototype.subtract = function (a) { var r = nbi(); this.subTo(a, r); return r; };
|
|
// (public) this * a
|
|
BigInteger.prototype.multiply = function (a) { var r = nbi(); this.multiplyTo(a, r); return r; };
|
|
// (public) this / a
|
|
BigInteger.prototype.divide = function (a) { var r = nbi(); this.divRemTo(a, r, null); return r; };
|
|
// (public) this % a
|
|
BigInteger.prototype.remainder = function (a) { var r = nbi(); this.divRemTo(a, null, r); return r; };
|
|
// (public) [this/a,this%a]
|
|
BigInteger.prototype.divideAndRemainder = function (a) {
|
|
var q = nbi(), r = nbi();
|
|
this.divRemTo(a, q, r);
|
|
return new Array(q, r);
|
|
};
|
|
|
|
// (public) this^e % m (HAC 14.85)
|
|
BigInteger.prototype.modPow = function (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) 1/this % m (HAC 14.61)
|
|
BigInteger.prototype.modInverse = function (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;
|
|
};
|
|
|
|
|
|
// (public) this^e
|
|
BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()); };
|
|
|
|
// (public) gcd(this,a) (HAC 14.54)
|
|
BigInteger.prototype.gcd = function (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;
|
|
};
|
|
|
|
// (public) test primality with certainty >= 1-.5^t
|
|
BigInteger.prototype.isProbablePrime = function (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);
|
|
};
|
|
|
|
|
|
// JSBN-specific extension
|
|
|
|
// (public) this^2
|
|
BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r; };
|
|
|
|
|
|
// NOTE: BigInteger interfaces not implemented in jsbn:
|
|
// BigInteger(int signum, byte[] magnitude)
|
|
// double doubleValue()
|
|
// float floatValue()
|
|
// int hashCode()
|
|
// long longValue()
|
|
// static BigInteger valueOf(long val)
|
|
|
|
|
|
|
|
// Copyright Stephan Thomas (start) --- //
|
|
// BigInteger monkey patching
|
|
BigInteger.valueOf = nbv;
|
|
BigInteger.prototype.toByteArrayUnsigned = function () {
|
|
var ba = this.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;
|
|
}
|
|
};
|
|
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);
|
|
}
|
|
};
|
|
// Copyright Stephan Thomas (end) --- //
|
|
|
|
|
|
|
|
|
|
// ****** REDUCTION ******* //
|
|
|
|
// Modular reduction using "classic" algorithm
|
|
function Classic(m) { this.m = m; }
|
|
Classic.prototype.convert = function (x) {
|
|
if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
|
|
else return x;
|
|
};
|
|
Classic.prototype.revert = function (x) { return x; };
|
|
Classic.prototype.reduce = function (x) { x.divRemTo(this.m, null, x); };
|
|
Classic.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
|
|
Classic.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
Montgomery.prototype.convert = function (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
|
|
Montgomery.prototype.revert = function (x) {
|
|
var r = nbi();
|
|
x.copyTo(r);
|
|
this.reduce(r);
|
|
return r;
|
|
};
|
|
// x = x/R mod m (HAC 14.32)
|
|
Montgomery.prototype.reduce = function (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 = "xy/R mod m"; x,y != r
|
|
Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
|
|
// r = "x^2/R mod m"; x != r
|
|
Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
|
|
|
|
|
|
|
|
|
|
|
|
// A "null" reducer
|
|
function NullExp() { }
|
|
NullExp.prototype.convert = function (x) { return x; };
|
|
NullExp.prototype.revert = function (x) { return x; };
|
|
NullExp.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); };
|
|
NullExp.prototype.sqrTo = function (x, r) { x.squareTo(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;
|
|
}
|
|
Barrett.prototype.convert = function (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; }
|
|
};
|
|
Barrett.prototype.revert = function (x) { return x; };
|
|
// x = x mod m (HAC 14.42)
|
|
Barrett.prototype.reduce = function (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*y mod m; x,y != r
|
|
Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
|
|
// r = x^2 mod m; x != r
|
|
Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
|
|
|
|
})();
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
//---------------------------------------------------------------------
|
|
// QRCode for JavaScript
|
|
//
|
|
// Copyright (c) 2009 Kazuhiko Arase
|
|
//
|
|
// URL: http://www.d-project.com/
|
|
//
|
|
// Licensed under the MIT license:
|
|
// http://www.opensource.org/licenses/mit-license.php
|
|
//
|
|
// The word "QR Code" is registered trademark of
|
|
// DENSO WAVE INCORPORATED
|
|
// http://www.denso-wave.com/qrcode/faqpatent-e.html
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
(function () {
|
|
//---------------------------------------------------------------------
|
|
// QR8bitByte
|
|
//---------------------------------------------------------------------
|
|
|
|
function QR8bitByte(data) {
|
|
this.mode = QRCode.Mode.MODE_8BIT_BYTE;
|
|
this.data = data;
|
|
}
|
|
|
|
QR8bitByte.prototype = {
|
|
|
|
getLength: function (buffer) {
|
|
return this.data.length;
|
|
},
|
|
|
|
write: function (buffer) {
|
|
for (var i = 0; i < this.data.length; i++) {
|
|
// not JIS ...
|
|
buffer.put(this.data.charCodeAt(i), 8);
|
|
}
|
|
}
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRCode
|
|
//---------------------------------------------------------------------
|
|
|
|
var QRCode = window.QRCode = function (typeNumber, errorCorrectLevel) {
|
|
this.typeNumber = typeNumber;
|
|
this.errorCorrectLevel = errorCorrectLevel;
|
|
this.modules = null;
|
|
this.moduleCount = 0;
|
|
this.dataCache = null;
|
|
this.dataList = new Array();
|
|
}
|
|
|
|
QRCode.prototype = {
|
|
|
|
addData: function (data) {
|
|
var newData = new QR8bitByte(data);
|
|
this.dataList.push(newData);
|
|
this.dataCache = null;
|
|
},
|
|
|
|
isDark: function (row, col) {
|
|
if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
|
|
throw new Error(row + "," + col);
|
|
}
|
|
return this.modules[row][col];
|
|
},
|
|
|
|
getModuleCount: function () {
|
|
return this.moduleCount;
|
|
},
|
|
|
|
make: function () {
|
|
this.makeImpl(false, this.getBestMaskPattern());
|
|
},
|
|
|
|
makeImpl: function (test, maskPattern) {
|
|
|
|
this.moduleCount = this.typeNumber * 4 + 17;
|
|
this.modules = new Array(this.moduleCount);
|
|
|
|
for (var row = 0; row < this.moduleCount; row++) {
|
|
|
|
this.modules[row] = new Array(this.moduleCount);
|
|
|
|
for (var col = 0; col < this.moduleCount; col++) {
|
|
this.modules[row][col] = null; //(col + row) % 3;
|
|
}
|
|
}
|
|
|
|
this.setupPositionProbePattern(0, 0);
|
|
this.setupPositionProbePattern(this.moduleCount - 7, 0);
|
|
this.setupPositionProbePattern(0, this.moduleCount - 7);
|
|
this.setupPositionAdjustPattern();
|
|
this.setupTimingPattern();
|
|
this.setupTypeInfo(test, maskPattern);
|
|
|
|
if (this.typeNumber >= 7) {
|
|
this.setupTypeNumber(test);
|
|
}
|
|
|
|
if (this.dataCache == null) {
|
|
this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
|
|
}
|
|
|
|
this.mapData(this.dataCache, maskPattern);
|
|
},
|
|
|
|
setupPositionProbePattern: function (row, col) {
|
|
|
|
for (var r = -1; r <= 7; r++) {
|
|
|
|
if (row + r <= -1 || this.moduleCount <= row + r) continue;
|
|
|
|
for (var c = -1; c <= 7; c++) {
|
|
|
|
if (col + c <= -1 || this.moduleCount <= col + c) continue;
|
|
|
|
if ((0 <= r && r <= 6 && (c == 0 || c == 6))
|
|
|| (0 <= c && c <= 6 && (r == 0 || r == 6))
|
|
|| (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
|
|
this.modules[row + r][col + c] = true;
|
|
} else {
|
|
this.modules[row + r][col + c] = false;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
getBestMaskPattern: function () {
|
|
|
|
var minLostPoint = 0;
|
|
var pattern = 0;
|
|
|
|
for (var i = 0; i < 8; i++) {
|
|
|
|
this.makeImpl(true, i);
|
|
|
|
var lostPoint = QRUtil.getLostPoint(this);
|
|
|
|
if (i == 0 || minLostPoint > lostPoint) {
|
|
minLostPoint = lostPoint;
|
|
pattern = i;
|
|
}
|
|
}
|
|
|
|
return pattern;
|
|
},
|
|
|
|
createMovieClip: function (target_mc, instance_name, depth) {
|
|
|
|
var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
|
|
var cs = 1;
|
|
|
|
this.make();
|
|
|
|
for (var row = 0; row < this.modules.length; row++) {
|
|
|
|
var y = row * cs;
|
|
|
|
for (var col = 0; col < this.modules[row].length; col++) {
|
|
|
|
var x = col * cs;
|
|
var dark = this.modules[row][col];
|
|
|
|
if (dark) {
|
|
qr_mc.beginFill(0, 100);
|
|
qr_mc.moveTo(x, y);
|
|
qr_mc.lineTo(x + cs, y);
|
|
qr_mc.lineTo(x + cs, y + cs);
|
|
qr_mc.lineTo(x, y + cs);
|
|
qr_mc.endFill();
|
|
}
|
|
}
|
|
}
|
|
|
|
return qr_mc;
|
|
},
|
|
|
|
setupTimingPattern: function () {
|
|
|
|
for (var r = 8; r < this.moduleCount - 8; r++) {
|
|
if (this.modules[r][6] != null) {
|
|
continue;
|
|
}
|
|
this.modules[r][6] = (r % 2 == 0);
|
|
}
|
|
|
|
for (var c = 8; c < this.moduleCount - 8; c++) {
|
|
if (this.modules[6][c] != null) {
|
|
continue;
|
|
}
|
|
this.modules[6][c] = (c % 2 == 0);
|
|
}
|
|
},
|
|
|
|
setupPositionAdjustPattern: function () {
|
|
|
|
var pos = QRUtil.getPatternPosition(this.typeNumber);
|
|
|
|
for (var i = 0; i < pos.length; i++) {
|
|
|
|
for (var j = 0; j < pos.length; j++) {
|
|
|
|
var row = pos[i];
|
|
var col = pos[j];
|
|
|
|
if (this.modules[row][col] != null) {
|
|
continue;
|
|
}
|
|
|
|
for (var r = -2; r <= 2; r++) {
|
|
|
|
for (var c = -2; c <= 2; c++) {
|
|
|
|
if (r == -2 || r == 2 || c == -2 || c == 2
|
|
|| (r == 0 && c == 0)) {
|
|
this.modules[row + r][col + c] = true;
|
|
} else {
|
|
this.modules[row + r][col + c] = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
setupTypeNumber: function (test) {
|
|
|
|
var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
|
|
|
|
for (var i = 0; i < 18; i++) {
|
|
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
|
|
}
|
|
|
|
for (var i = 0; i < 18; i++) {
|
|
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
|
|
}
|
|
},
|
|
|
|
setupTypeInfo: function (test, maskPattern) {
|
|
|
|
var data = (this.errorCorrectLevel << 3) | maskPattern;
|
|
var bits = QRUtil.getBCHTypeInfo(data);
|
|
|
|
// vertical
|
|
for (var i = 0; i < 15; i++) {
|
|
|
|
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
|
|
if (i < 6) {
|
|
this.modules[i][8] = mod;
|
|
} else if (i < 8) {
|
|
this.modules[i + 1][8] = mod;
|
|
} else {
|
|
this.modules[this.moduleCount - 15 + i][8] = mod;
|
|
}
|
|
}
|
|
|
|
// horizontal
|
|
for (var i = 0; i < 15; i++) {
|
|
|
|
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
|
|
if (i < 8) {
|
|
this.modules[8][this.moduleCount - i - 1] = mod;
|
|
} else if (i < 9) {
|
|
this.modules[8][15 - i - 1 + 1] = mod;
|
|
} else {
|
|
this.modules[8][15 - i - 1] = mod;
|
|
}
|
|
}
|
|
|
|
// fixed module
|
|
this.modules[this.moduleCount - 8][8] = (!test);
|
|
|
|
},
|
|
|
|
mapData: function (data, maskPattern) {
|
|
|
|
var inc = -1;
|
|
var row = this.moduleCount - 1;
|
|
var bitIndex = 7;
|
|
var byteIndex = 0;
|
|
|
|
for (var col = this.moduleCount - 1; col > 0; col -= 2) {
|
|
|
|
if (col == 6) col--;
|
|
|
|
while (true) {
|
|
|
|
for (var c = 0; c < 2; c++) {
|
|
|
|
if (this.modules[row][col - c] == null) {
|
|
|
|
var dark = false;
|
|
|
|
if (byteIndex < data.length) {
|
|
dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
|
|
}
|
|
|
|
var mask = QRUtil.getMask(maskPattern, row, col - c);
|
|
|
|
if (mask) {
|
|
dark = !dark;
|
|
}
|
|
|
|
this.modules[row][col - c] = dark;
|
|
bitIndex--;
|
|
|
|
if (bitIndex == -1) {
|
|
byteIndex++;
|
|
bitIndex = 7;
|
|
}
|
|
}
|
|
}
|
|
|
|
row += inc;
|
|
|
|
if (row < 0 || this.moduleCount <= row) {
|
|
row -= inc;
|
|
inc = -inc;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
QRCode.PAD0 = 0xEC;
|
|
QRCode.PAD1 = 0x11;
|
|
|
|
QRCode.createData = function (typeNumber, errorCorrectLevel, dataList) {
|
|
|
|
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
|
|
|
|
var buffer = new QRBitBuffer();
|
|
|
|
for (var i = 0; i < dataList.length; i++) {
|
|
var data = dataList[i];
|
|
buffer.put(data.mode, 4);
|
|
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
|
|
data.write(buffer);
|
|
}
|
|
|
|
// calc num max data.
|
|
var totalDataCount = 0;
|
|
for (var i = 0; i < rsBlocks.length; i++) {
|
|
totalDataCount += rsBlocks[i].dataCount;
|
|
}
|
|
|
|
if (buffer.getLengthInBits() > totalDataCount * 8) {
|
|
throw new Error("code length overflow. ("
|
|
+ buffer.getLengthInBits()
|
|
+ ">"
|
|
+ totalDataCount * 8
|
|
+ ")");
|
|
}
|
|
|
|
// end code
|
|
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
|
|
buffer.put(0, 4);
|
|
}
|
|
|
|
// padding
|
|
while (buffer.getLengthInBits() % 8 != 0) {
|
|
buffer.putBit(false);
|
|
}
|
|
|
|
// padding
|
|
while (true) {
|
|
|
|
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
break;
|
|
}
|
|
buffer.put(QRCode.PAD0, 8);
|
|
|
|
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
break;
|
|
}
|
|
buffer.put(QRCode.PAD1, 8);
|
|
}
|
|
|
|
return QRCode.createBytes(buffer, rsBlocks);
|
|
};
|
|
|
|
QRCode.createBytes = function (buffer, rsBlocks) {
|
|
|
|
var offset = 0;
|
|
|
|
var maxDcCount = 0;
|
|
var maxEcCount = 0;
|
|
|
|
var dcdata = new Array(rsBlocks.length);
|
|
var ecdata = new Array(rsBlocks.length);
|
|
|
|
for (var r = 0; r < rsBlocks.length; r++) {
|
|
|
|
var dcCount = rsBlocks[r].dataCount;
|
|
var ecCount = rsBlocks[r].totalCount - dcCount;
|
|
|
|
maxDcCount = Math.max(maxDcCount, dcCount);
|
|
maxEcCount = Math.max(maxEcCount, ecCount);
|
|
|
|
dcdata[r] = new Array(dcCount);
|
|
|
|
for (var i = 0; i < dcdata[r].length; i++) {
|
|
dcdata[r][i] = 0xff & buffer.buffer[i + offset];
|
|
}
|
|
offset += dcCount;
|
|
|
|
var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
|
|
var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
|
|
|
|
var modPoly = rawPoly.mod(rsPoly);
|
|
ecdata[r] = new Array(rsPoly.getLength() - 1);
|
|
for (var i = 0; i < ecdata[r].length; i++) {
|
|
var modIndex = i + modPoly.getLength() - ecdata[r].length;
|
|
ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
|
|
}
|
|
|
|
}
|
|
|
|
var totalCodeCount = 0;
|
|
for (var i = 0; i < rsBlocks.length; i++) {
|
|
totalCodeCount += rsBlocks[i].totalCount;
|
|
}
|
|
|
|
var data = new Array(totalCodeCount);
|
|
var index = 0;
|
|
|
|
for (var i = 0; i < maxDcCount; i++) {
|
|
for (var r = 0; r < rsBlocks.length; r++) {
|
|
if (i < dcdata[r].length) {
|
|
data[index++] = dcdata[r][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < maxEcCount; i++) {
|
|
for (var r = 0; r < rsBlocks.length; r++) {
|
|
if (i < ecdata[r].length) {
|
|
data[index++] = ecdata[r][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return data;
|
|
|
|
};
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRMode
|
|
//---------------------------------------------------------------------
|
|
QRCode.Mode = {
|
|
MODE_NUMBER: 1 << 0,
|
|
MODE_ALPHA_NUM: 1 << 1,
|
|
MODE_8BIT_BYTE: 1 << 2,
|
|
MODE_KANJI: 1 << 3
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRErrorCorrectLevel
|
|
//---------------------------------------------------------------------
|
|
QRCode.ErrorCorrectLevel = {
|
|
L: 1,
|
|
M: 0,
|
|
Q: 3,
|
|
H: 2
|
|
};
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRMaskPattern
|
|
//---------------------------------------------------------------------
|
|
QRCode.MaskPattern = {
|
|
PATTERN000: 0,
|
|
PATTERN001: 1,
|
|
PATTERN010: 2,
|
|
PATTERN011: 3,
|
|
PATTERN100: 4,
|
|
PATTERN101: 5,
|
|
PATTERN110: 6,
|
|
PATTERN111: 7
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRUtil
|
|
//---------------------------------------------------------------------
|
|
|
|
var QRUtil = {
|
|
|
|
PATTERN_POSITION_TABLE: [
|
|
[],
|
|
[6, 18],
|
|
[6, 22],
|
|
[6, 26],
|
|
[6, 30],
|
|
[6, 34],
|
|
[6, 22, 38],
|
|
[6, 24, 42],
|
|
[6, 26, 46],
|
|
[6, 28, 50],
|
|
[6, 30, 54],
|
|
[6, 32, 58],
|
|
[6, 34, 62],
|
|
[6, 26, 46, 66],
|
|
[6, 26, 48, 70],
|
|
[6, 26, 50, 74],
|
|
[6, 30, 54, 78],
|
|
[6, 30, 56, 82],
|
|
[6, 30, 58, 86],
|
|
[6, 34, 62, 90],
|
|
[6, 28, 50, 72, 94],
|
|
[6, 26, 50, 74, 98],
|
|
[6, 30, 54, 78, 102],
|
|
[6, 28, 54, 80, 106],
|
|
[6, 32, 58, 84, 110],
|
|
[6, 30, 58, 86, 114],
|
|
[6, 34, 62, 90, 118],
|
|
[6, 26, 50, 74, 98, 122],
|
|
[6, 30, 54, 78, 102, 126],
|
|
[6, 26, 52, 78, 104, 130],
|
|
[6, 30, 56, 82, 108, 134],
|
|
[6, 34, 60, 86, 112, 138],
|
|
[6, 30, 58, 86, 114, 142],
|
|
[6, 34, 62, 90, 118, 146],
|
|
[6, 30, 54, 78, 102, 126, 150],
|
|
[6, 24, 50, 76, 102, 128, 154],
|
|
[6, 28, 54, 80, 106, 132, 158],
|
|
[6, 32, 58, 84, 110, 136, 162],
|
|
[6, 26, 54, 82, 110, 138, 166],
|
|
[6, 30, 58, 86, 114, 142, 170]
|
|
],
|
|
|
|
G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
|
|
G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
|
|
G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
|
|
|
|
getBCHTypeInfo: function (data) {
|
|
var d = data << 10;
|
|
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
|
|
d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
|
|
}
|
|
return ((data << 10) | d) ^ QRUtil.G15_MASK;
|
|
},
|
|
|
|
getBCHTypeNumber: function (data) {
|
|
var d = data << 12;
|
|
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
|
|
d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
|
|
}
|
|
return (data << 12) | d;
|
|
},
|
|
|
|
getBCHDigit: function (data) {
|
|
|
|
var digit = 0;
|
|
|
|
while (data != 0) {
|
|
digit++;
|
|
data >>>= 1;
|
|
}
|
|
|
|
return digit;
|
|
},
|
|
|
|
getPatternPosition: function (typeNumber) {
|
|
return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
|
|
},
|
|
|
|
getMask: function (maskPattern, i, j) {
|
|
|
|
switch (maskPattern) {
|
|
|
|
case QRCode.MaskPattern.PATTERN000: return (i + j) % 2 == 0;
|
|
case QRCode.MaskPattern.PATTERN001: return i % 2 == 0;
|
|
case QRCode.MaskPattern.PATTERN010: return j % 3 == 0;
|
|
case QRCode.MaskPattern.PATTERN011: return (i + j) % 3 == 0;
|
|
case QRCode.MaskPattern.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
|
|
case QRCode.MaskPattern.PATTERN101: return (i * j) % 2 + (i * j) % 3 == 0;
|
|
case QRCode.MaskPattern.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
|
|
case QRCode.MaskPattern.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
|
|
|
|
default:
|
|
throw new Error("bad maskPattern:" + maskPattern);
|
|
}
|
|
},
|
|
|
|
getErrorCorrectPolynomial: function (errorCorrectLength) {
|
|
|
|
var a = new QRPolynomial([1], 0);
|
|
|
|
for (var i = 0; i < errorCorrectLength; i++) {
|
|
a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
|
|
}
|
|
|
|
return a;
|
|
},
|
|
|
|
getLengthInBits: function (mode, type) {
|
|
|
|
if (1 <= type && type < 10) {
|
|
|
|
// 1 - 9
|
|
|
|
switch (mode) {
|
|
case QRCode.Mode.MODE_NUMBER: return 10;
|
|
case QRCode.Mode.MODE_ALPHA_NUM: return 9;
|
|
case QRCode.Mode.MODE_8BIT_BYTE: return 8;
|
|
case QRCode.Mode.MODE_KANJI: return 8;
|
|
default:
|
|
throw new Error("mode:" + mode);
|
|
}
|
|
|
|
} else if (type < 27) {
|
|
|
|
// 10 - 26
|
|
|
|
switch (mode) {
|
|
case QRCode.Mode.MODE_NUMBER: return 12;
|
|
case QRCode.Mode.MODE_ALPHA_NUM: return 11;
|
|
case QRCode.Mode.MODE_8BIT_BYTE: return 16;
|
|
case QRCode.Mode.MODE_KANJI: return 10;
|
|
default:
|
|
throw new Error("mode:" + mode);
|
|
}
|
|
|
|
} else if (type < 41) {
|
|
|
|
// 27 - 40
|
|
|
|
switch (mode) {
|
|
case QRCode.Mode.MODE_NUMBER: return 14;
|
|
case QRCode.Mode.MODE_ALPHA_NUM: return 13;
|
|
case QRCode.Mode.MODE_8BIT_BYTE: return 16;
|
|
case QRCode.Mode.MODE_KANJI: return 12;
|
|
default:
|
|
throw new Error("mode:" + mode);
|
|
}
|
|
|
|
} else {
|
|
throw new Error("type:" + type);
|
|
}
|
|
},
|
|
|
|
getLostPoint: function (qrCode) {
|
|
|
|
var moduleCount = qrCode.getModuleCount();
|
|
|
|
var lostPoint = 0;
|
|
|
|
// LEVEL1
|
|
|
|
for (var row = 0; row < moduleCount; row++) {
|
|
|
|
for (var col = 0; col < moduleCount; col++) {
|
|
|
|
var sameCount = 0;
|
|
var dark = qrCode.isDark(row, col);
|
|
|
|
for (var r = -1; r <= 1; r++) {
|
|
|
|
if (row + r < 0 || moduleCount <= row + r) {
|
|
continue;
|
|
}
|
|
|
|
for (var c = -1; c <= 1; c++) {
|
|
|
|
if (col + c < 0 || moduleCount <= col + c) {
|
|
continue;
|
|
}
|
|
|
|
if (r == 0 && c == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (dark == qrCode.isDark(row + r, col + c)) {
|
|
sameCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sameCount > 5) {
|
|
lostPoint += (3 + sameCount - 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
// LEVEL2
|
|
|
|
for (var row = 0; row < moduleCount - 1; row++) {
|
|
for (var col = 0; col < moduleCount - 1; col++) {
|
|
var count = 0;
|
|
if (qrCode.isDark(row, col)) count++;
|
|
if (qrCode.isDark(row + 1, col)) count++;
|
|
if (qrCode.isDark(row, col + 1)) count++;
|
|
if (qrCode.isDark(row + 1, col + 1)) count++;
|
|
if (count == 0 || count == 4) {
|
|
lostPoint += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
// LEVEL3
|
|
|
|
for (var row = 0; row < moduleCount; row++) {
|
|
for (var col = 0; col < moduleCount - 6; col++) {
|
|
if (qrCode.isDark(row, col)
|
|
&& !qrCode.isDark(row, col + 1)
|
|
&& qrCode.isDark(row, col + 2)
|
|
&& qrCode.isDark(row, col + 3)
|
|
&& qrCode.isDark(row, col + 4)
|
|
&& !qrCode.isDark(row, col + 5)
|
|
&& qrCode.isDark(row, col + 6)) {
|
|
lostPoint += 40;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var col = 0; col < moduleCount; col++) {
|
|
for (var row = 0; row < moduleCount - 6; row++) {
|
|
if (qrCode.isDark(row, col)
|
|
&& !qrCode.isDark(row + 1, col)
|
|
&& qrCode.isDark(row + 2, col)
|
|
&& qrCode.isDark(row + 3, col)
|
|
&& qrCode.isDark(row + 4, col)
|
|
&& !qrCode.isDark(row + 5, col)
|
|
&& qrCode.isDark(row + 6, col)) {
|
|
lostPoint += 40;
|
|
}
|
|
}
|
|
}
|
|
|
|
// LEVEL4
|
|
|
|
var darkCount = 0;
|
|
|
|
for (var col = 0; col < moduleCount; col++) {
|
|
for (var row = 0; row < moduleCount; row++) {
|
|
if (qrCode.isDark(row, col)) {
|
|
darkCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
|
|
lostPoint += ratio * 10;
|
|
|
|
return lostPoint;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRMath
|
|
//---------------------------------------------------------------------
|
|
|
|
var QRMath = {
|
|
|
|
glog: function (n) {
|
|
|
|
if (n < 1) {
|
|
throw new Error("glog(" + n + ")");
|
|
}
|
|
|
|
return QRMath.LOG_TABLE[n];
|
|
},
|
|
|
|
gexp: function (n) {
|
|
|
|
while (n < 0) {
|
|
n += 255;
|
|
}
|
|
|
|
while (n >= 256) {
|
|
n -= 255;
|
|
}
|
|
|
|
return QRMath.EXP_TABLE[n];
|
|
},
|
|
|
|
EXP_TABLE: new Array(256),
|
|
|
|
LOG_TABLE: new Array(256)
|
|
|
|
};
|
|
|
|
for (var i = 0; i < 8; i++) {
|
|
QRMath.EXP_TABLE[i] = 1 << i;
|
|
}
|
|
for (var i = 8; i < 256; i++) {
|
|
QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4]
|
|
^ QRMath.EXP_TABLE[i - 5]
|
|
^ QRMath.EXP_TABLE[i - 6]
|
|
^ QRMath.EXP_TABLE[i - 8];
|
|
}
|
|
for (var i = 0; i < 255; i++) {
|
|
QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRPolynomial
|
|
//---------------------------------------------------------------------
|
|
|
|
function QRPolynomial(num, shift) {
|
|
|
|
if (num.length == undefined) {
|
|
throw new Error(num.length + "/" + shift);
|
|
}
|
|
|
|
var offset = 0;
|
|
|
|
while (offset < num.length && num[offset] == 0) {
|
|
offset++;
|
|
}
|
|
|
|
this.num = new Array(num.length - offset + shift);
|
|
for (var i = 0; i < num.length - offset; i++) {
|
|
this.num[i] = num[i + offset];
|
|
}
|
|
}
|
|
|
|
QRPolynomial.prototype = {
|
|
|
|
get: function (index) {
|
|
return this.num[index];
|
|
},
|
|
|
|
getLength: function () {
|
|
return this.num.length;
|
|
},
|
|
|
|
multiply: function (e) {
|
|
|
|
var num = new Array(this.getLength() + e.getLength() - 1);
|
|
|
|
for (var i = 0; i < this.getLength(); i++) {
|
|
for (var j = 0; j < e.getLength(); j++) {
|
|
num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
|
|
}
|
|
}
|
|
|
|
return new QRPolynomial(num, 0);
|
|
},
|
|
|
|
mod: function (e) {
|
|
|
|
if (this.getLength() - e.getLength() < 0) {
|
|
return this;
|
|
}
|
|
|
|
var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
|
|
|
|
var num = new Array(this.getLength());
|
|
|
|
for (var i = 0; i < this.getLength(); i++) {
|
|
num[i] = this.get(i);
|
|
}
|
|
|
|
for (var i = 0; i < e.getLength(); i++) {
|
|
num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
|
|
}
|
|
|
|
// recursive call
|
|
return new QRPolynomial(num, 0).mod(e);
|
|
}
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRRSBlock
|
|
//---------------------------------------------------------------------
|
|
|
|
function QRRSBlock(totalCount, dataCount) {
|
|
this.totalCount = totalCount;
|
|
this.dataCount = dataCount;
|
|
}
|
|
|
|
QRRSBlock.RS_BLOCK_TABLE = [
|
|
|
|
// L
|
|
// M
|
|
// Q
|
|
// H
|
|
|
|
// 1
|
|
[1, 26, 19],
|
|
[1, 26, 16],
|
|
[1, 26, 13],
|
|
[1, 26, 9],
|
|
|
|
// 2
|
|
[1, 44, 34],
|
|
[1, 44, 28],
|
|
[1, 44, 22],
|
|
[1, 44, 16],
|
|
|
|
// 3
|
|
[1, 70, 55],
|
|
[1, 70, 44],
|
|
[2, 35, 17],
|
|
[2, 35, 13],
|
|
|
|
// 4
|
|
[1, 100, 80],
|
|
[2, 50, 32],
|
|
[2, 50, 24],
|
|
[4, 25, 9],
|
|
|
|
// 5
|
|
[1, 134, 108],
|
|
[2, 67, 43],
|
|
[2, 33, 15, 2, 34, 16],
|
|
[2, 33, 11, 2, 34, 12],
|
|
|
|
// 6
|
|
[2, 86, 68],
|
|
[4, 43, 27],
|
|
[4, 43, 19],
|
|
[4, 43, 15],
|
|
|
|
// 7
|
|
[2, 98, 78],
|
|
[4, 49, 31],
|
|
[2, 32, 14, 4, 33, 15],
|
|
[4, 39, 13, 1, 40, 14],
|
|
|
|
// 8
|
|
[2, 121, 97],
|
|
[2, 60, 38, 2, 61, 39],
|
|
[4, 40, 18, 2, 41, 19],
|
|
[4, 40, 14, 2, 41, 15],
|
|
|
|
// 9
|
|
[2, 146, 116],
|
|
[3, 58, 36, 2, 59, 37],
|
|
[4, 36, 16, 4, 37, 17],
|
|
[4, 36, 12, 4, 37, 13],
|
|
|
|
// 10
|
|
[2, 86, 68, 2, 87, 69],
|
|
[4, 69, 43, 1, 70, 44],
|
|
[6, 43, 19, 2, 44, 20],
|
|
[6, 43, 15, 2, 44, 16]
|
|
|
|
];
|
|
|
|
QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
|
|
|
|
var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
|
|
|
|
if (rsBlock == undefined) {
|
|
throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
|
|
}
|
|
|
|
var length = rsBlock.length / 3;
|
|
|
|
var list = new Array();
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
|
var count = rsBlock[i * 3 + 0];
|
|
var totalCount = rsBlock[i * 3 + 1];
|
|
var dataCount = rsBlock[i * 3 + 2];
|
|
|
|
for (var j = 0; j < count; j++) {
|
|
list.push(new QRRSBlock(totalCount, dataCount));
|
|
}
|
|
}
|
|
|
|
return list;
|
|
};
|
|
|
|
QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
|
|
|
|
switch (errorCorrectLevel) {
|
|
case QRCode.ErrorCorrectLevel.L:
|
|
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
|
|
case QRCode.ErrorCorrectLevel.M:
|
|
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
|
|
case QRCode.ErrorCorrectLevel.Q:
|
|
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
|
|
case QRCode.ErrorCorrectLevel.H:
|
|
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
|
|
default:
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
// QRBitBuffer
|
|
//---------------------------------------------------------------------
|
|
|
|
function QRBitBuffer() {
|
|
this.buffer = new Array();
|
|
this.length = 0;
|
|
}
|
|
|
|
QRBitBuffer.prototype = {
|
|
|
|
get: function (index) {
|
|
var bufIndex = Math.floor(index / 8);
|
|
return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
|
|
},
|
|
|
|
put: function (num, length) {
|
|
for (var i = 0; i < length; i++) {
|
|
this.putBit(((num >>> (length - i - 1)) & 1) == 1);
|
|
}
|
|
},
|
|
|
|
getLengthInBits: function () {
|
|
return this.length;
|
|
},
|
|
|
|
putBit: function (bit) {
|
|
|
|
var bufIndex = Math.floor(this.length / 8);
|
|
if (this.buffer.length <= bufIndex) {
|
|
this.buffer.push(0);
|
|
}
|
|
|
|
if (bit) {
|
|
this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
|
|
}
|
|
|
|
this.length++;
|
|
}
|
|
};
|
|
})();
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
var Bitcoin = {};
|
|
|
|
(function () {
|
|
var B58 = Bitcoin.Base58 = {
|
|
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
|
base: BigInteger.valueOf(58),
|
|
|
|
/**
|
|
* Convert a byte array to a base58-encoded string.
|
|
*
|
|
* Written by Mike Hearn for BitcoinJ.
|
|
* Copyright (c) 2011 Google Inc.
|
|
*
|
|
* Ported to JavaScript by Stefan Thomas.
|
|
*/
|
|
encode: function (input) {
|
|
var bi = BigInteger.fromByteArrayUnsigned(input);
|
|
var chars = [];
|
|
|
|
while (bi.compareTo(B58.base) >= 0) {
|
|
var mod = bi.mod(B58.base);
|
|
chars.unshift(B58.alphabet[mod.intValue()]);
|
|
bi = bi.subtract(mod).divide(B58.base);
|
|
}
|
|
chars.unshift(B58.alphabet[bi.intValue()]);
|
|
|
|
// Convert leading zeros too.
|
|
for (var i = 0; i < input.length; i++) {
|
|
if (input[i] == 0x00) {
|
|
chars.unshift(B58.alphabet[0]);
|
|
} else break;
|
|
}
|
|
|
|
s = chars.join('');
|
|
return s;
|
|
},
|
|
|
|
/**
|
|
* Convert a base58-encoded string to a byte array.
|
|
*
|
|
* Written by Mike Hearn for BitcoinJ.
|
|
* Copyright (c) 2011 Google Inc.
|
|
*
|
|
* Ported to JavaScript by Stefan Thomas.
|
|
*/
|
|
decode: function (input) {
|
|
bi = BigInteger.valueOf(0);
|
|
var leadingZerosNum = 0;
|
|
for (var i = input.length - 1; i >= 0; i--) {
|
|
var alphaIndex = B58.alphabet.indexOf(input[i]);
|
|
bi = bi.add(BigInteger.valueOf(alphaIndex)
|
|
.multiply(B58.base.pow(input.length - 1 - i)));
|
|
|
|
// This counts leading zero bytes
|
|
if (input[i] == "1") leadingZerosNum++;
|
|
else leadingZerosNum = 0;
|
|
}
|
|
var bytes = bi.toByteArrayUnsigned();
|
|
|
|
// Add leading zeros
|
|
while (leadingZerosNum-- > 0) bytes.unshift(0);
|
|
|
|
return bytes;
|
|
}
|
|
};
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
Bitcoin.Address = function (bytes) {
|
|
if ("string" == typeof bytes) {
|
|
bytes = Bitcoin.Address.decodeString(bytes);
|
|
}
|
|
this.hash = bytes;
|
|
this.version = 0x00;
|
|
};
|
|
|
|
Bitcoin.Address.prototype.toString = function () {
|
|
// Get a copy of the hash
|
|
var hash = this.hash.slice(0);
|
|
|
|
// Version
|
|
hash.unshift(this.version);
|
|
var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
|
|
var bytes = hash.concat(checksum.slice(0, 4));
|
|
return Bitcoin.Base58.encode(bytes);
|
|
};
|
|
|
|
Bitcoin.Address.prototype.getHashBase64 = function () {
|
|
return Crypto.util.bytesToBase64(this.hash);
|
|
};
|
|
|
|
Bitcoin.Address.decodeString = function (string) {
|
|
var bytes = Bitcoin.Base58.decode(string);
|
|
var hash = bytes.slice(0, 21);
|
|
var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
|
|
|
|
if (checksum[0] != bytes[21] ||
|
|
checksum[1] != bytes[22] ||
|
|
checksum[2] != bytes[23] ||
|
|
checksum[3] != bytes[24]) {
|
|
throw "Checksum validation failed!";
|
|
}
|
|
|
|
var version = hash.shift();
|
|
|
|
if (version != 0) {
|
|
throw "Version " + version + " not supported!";
|
|
}
|
|
|
|
return hash;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitcoin.ECDSA = (function () {
|
|
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
|
var rng = new SecureRandom();
|
|
|
|
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);
|
|
},
|
|
|
|
serializeSig: function (r, s) {
|
|
var rBa = r.toByteArrayUnsigned();
|
|
var sBa = s.toByteArrayUnsigned();
|
|
|
|
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;
|
|
},
|
|
|
|
verify: function (hash, sig, pubkey) {
|
|
var obj = ECDSA.parseSig(sig);
|
|
var r = obj.r;
|
|
var s = obj.s;
|
|
|
|
var n = ecparams.getN();
|
|
var e = BigInteger.fromByteArrayUnsigned(hash);
|
|
|
|
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);
|
|
|
|
var G = ecparams.getG();
|
|
var Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
|
|
|
|
var point = implShamirsTrick(G, u1, Q, u2);
|
|
|
|
var v = point.x.toBigInteger().mod(n);
|
|
|
|
return v.equals(r);
|
|
},
|
|
|
|
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 };
|
|
}
|
|
};
|
|
|
|
return ECDSA;
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitcoin.ECKey = (function () {
|
|
var ECDSA = Bitcoin.ECDSA;
|
|
var ecparams = EllipticCurve.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) {
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
|
this.priv = BigInteger.fromByteArrayUnsigned(Crypto.util.base64ToBytes(input));
|
|
}
|
|
};
|
|
|
|
ECKey.prototype.getPub = function () {
|
|
if (this.pub) return this.pub;
|
|
this.pub = ecparams.getG().multiply(this.priv).getEncoded();
|
|
return this.pub;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
// Sipa Private Key Wallet Import Format (added by bitaddress.org)
|
|
ECKey.prototype.getBitcoinWalletImportFormat = function () {
|
|
// Get a copy of private key as a byte array
|
|
var bytes = this.priv.toByteArrayUnsigned();
|
|
|
|
// zero pad if private key is less than 32 bytes (thanks Casascius)
|
|
while (bytes.length < 32) bytes.unshift(0x00);
|
|
|
|
bytes.unshift(0x80); // prepend 0x80 byte
|
|
var checksum = Crypto.SHA256(Crypto.SHA256(bytes, { asBytes: true }), { asBytes: true });
|
|
bytes = bytes.concat(checksum.slice(0, 4));
|
|
|
|
var privWif = Bitcoin.Base58.encode(bytes);
|
|
return privWif;
|
|
};
|
|
|
|
ECKey.prototype.setPub = function (pub) {
|
|
this.pub = pub;
|
|
};
|
|
|
|
ECKey.prototype.toString = function (format) {
|
|
if (format === "base64") {
|
|
return Crypto.util.bytesToBase64(this.priv.toByteArrayUnsigned());
|
|
}
|
|
// Wallet Import Format
|
|
else if (format === "wif" || format === "WIF") {
|
|
return this.getBitcoinWalletImportFormat();
|
|
}
|
|
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());
|
|
};
|
|
|
|
return ECKey;
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Bitcoin utility functions
|
|
Bitcoin.Util = {
|
|
isArray: Array.isArray || function (o) {
|
|
return Object.prototype.toString.call(o) === '[object Array]';
|
|
},
|
|
makeFilledArray: function (len, val) {
|
|
var array = [];
|
|
var i = 0;
|
|
while (i < len) {
|
|
array[i++] = val;
|
|
}
|
|
return array;
|
|
},
|
|
numToVarInt: function (i) {
|
|
// TODO: THIS IS TOTALLY UNTESTED!
|
|
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]));
|
|
}
|
|
},
|
|
valueToBigInt: function (valueBuffer) {
|
|
if (valueBuffer instanceof BigInteger) return valueBuffer;
|
|
|
|
// Prepend zero byte to prevent interpretation as negative integer
|
|
return BigInteger.fromByteArrayUnsigned(valueBuffer);
|
|
},
|
|
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;
|
|
},
|
|
parseValue: function (valueString) {
|
|
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;
|
|
},
|
|
sha256ripe160: function (data) {
|
|
return Crypto.RIPEMD160(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
|
|
}
|
|
};
|
|
</script>
|
|
|
|
|
|
|
|
<style type="text/css">
|
|
.main { font-family: Arial; position: relative; text-align: center; }
|
|
.section { position: relative; width: 700px; margin: auto; border: 2px solid green; }
|
|
#generate { font-family: Courier New; height: 110px; text-align: left; position: relative; padding: 5px; }
|
|
#generate span { padding: 5px 5px 0 5px; }
|
|
.keyarea { font-family: Courier New; height: 110px; text-align: left; position: relative; padding: 5px; display: none; }
|
|
.keyarea .public { float: left; }
|
|
.keyarea .private {}
|
|
.keyarea .pubaddress { display: inline-block; height: 40px; padding: 0 0 0 10px; float: left; }
|
|
.keyarea .privwif { margin: 0; float: right; text-align: right; padding: 0 10px 0 0; position: relative; }
|
|
#qrcode_public { display: inline-block; float: left; }
|
|
#qrcode_private { display: inline-block; position: relative; top: 28px; float: right; }
|
|
|
|
.label { text-decoration: underline; }
|
|
.output { display: block; }
|
|
|
|
.qrcode_table { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; }
|
|
.qrcode_tddark { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #000000; }
|
|
.qrcode_tdlight { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #ffffff; }
|
|
|
|
#bulkarea { display: none; padding: 4px 0 0 0; }
|
|
#bulkarea .label { text-decoration: none; }
|
|
#bulkarea .format { font-style: italic; font-size: 90%; }
|
|
#bulktextarea { font-size: 90%; width: 98%; margin: 4px 0 0 0; }
|
|
#bulkstartindex { width: 35px; }
|
|
#bulklimit { width: 35px; }
|
|
|
|
@media screen
|
|
{
|
|
.menu { text-align: left; margin: auto; width: 700px; position: relative; left: -2px; }
|
|
.menu .tab { border-top-left-radius: 5px; border-top-right-radius: 5px; display: inline-block; background-color: #6C8C6C;
|
|
border: 2px solid green; padding: 5px; margin: 0 2px 0 0;
|
|
position: relative; top: 2px; z-index: 110;
|
|
}
|
|
.menu .tab.selected { background-color: White; border-bottom: 2px solid white; }
|
|
|
|
.commands { width: 700px; margin: auto; padding: 10px; }
|
|
.commands span { padding: 0 20px; }
|
|
#singlecommands { visibility: hidden; }
|
|
#bulkcommands { display: none; }
|
|
|
|
.footer { font-family: Arial; font-size: 90%; clear: both; width: 680px; margin: auto; padding: 50px 0 10px 0; }
|
|
.footer div span { padding: 10px; }
|
|
.footer .authorbtc { float: left; width: 470px; }
|
|
.footer .authorbtc span { text-align: left; display: block; padding: 0 20px; }
|
|
.footer .authorbtc div { position: relative; z-index: 100; }
|
|
.footer .authorpgp { position: relative; }
|
|
.footer .authorpgp span { text-align: right; display: block; padding: 0 20px; }
|
|
.footer .copyright { font-size: 80%; clear: both; padding: 5px 0; }
|
|
.footer .copyright span { padding: 10px 2px; }
|
|
}
|
|
|
|
@media print
|
|
{
|
|
.menu { display: none; }
|
|
.footer { display: none; }
|
|
.commands { display: none; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body onclick='SecureRandom.seedTime();' onkeypress='SecureRandom.seedTime();' onmousemove="ninja.seed();">
|
|
<div class="main">
|
|
<img alt="bitaddress.org" title="bitaddress.org" width="578px" height="80px" src="data:image/png;base64,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" />
|
|
|
|
<div class="menu">
|
|
<div class="tab selected" id="singlewallet" onclick="ninja.tabSwitch(this);">Single Wallet</div>
|
|
<div class="tab" id="bulkwallet" onclick="ninja.tabSwitch(this);">Bulk Wallet</div>
|
|
</div>
|
|
<div class="section" onmouseover="SecureRandom.seedTime();">
|
|
<div id="singlearea">
|
|
<div id="generate">
|
|
<span>Generating Bitcoin Address...<br /></span>
|
|
<span>MOVE your mouse around to add some extra randomness...<br /></span>
|
|
</div>
|
|
<div id="keyarea" class="keyarea">
|
|
<div class="public">
|
|
<div id="qrcode_public" class="qrcode"></div>
|
|
<div class="pubaddress">
|
|
<span class="label">Bitcoin Address:</span>
|
|
<span class="output" id="btcaddress"></span>
|
|
</div>
|
|
</div>
|
|
<div class="private">
|
|
<div id="qrcode_private" class="qrcode"></div>
|
|
<div class="privwif">
|
|
<span class="label">Private Key (Wallet Import Format):</span>
|
|
<span class="output" id="btcprivwif"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="bulkarea">
|
|
<span class="label">Comma Separated Values:</span> <span class="format">Index,Bitcoin Address,Private Key</span>
|
|
<textarea rows="20" cols="88" id="bulktextarea"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="commands" class="commands">
|
|
<div id="singlecommands">
|
|
<span><input type="button" id="newaddress" value="New Address" onclick="ninja.generateNewAddressAndKey();" /> </span>
|
|
<span><input type="button" name="print" value="Print" onclick="window.print();" /> </span>
|
|
</div>
|
|
|
|
<div id="bulkcommands">
|
|
<span>Start index:<input type="text" id="bulkstartindex" value="1" /> </span>
|
|
<span>Rows to generate:<input type="text" id="bulklimit" value="3" /> </span>
|
|
<span><input type="button" id="bulkgenerate" value="Generate" onclick="ninja.buildCSV((document.getElementById('bulklimit').value * 1), (document.getElementById('bulkstartindex').value) * 1);" /> </span>
|
|
<span><input type="button" name="print" value="Print" onclick="window.print();" /> </span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<div class="authorbtc">
|
|
<div>
|
|
<span>Donations: <b>1NiNja</b>1bUmhSoTXozBRBEtR8LeF9TGbZBN</span>
|
|
<span><a href="http://firstbits.com/1ninja" target="_blank">firstbits.com/1ninja</a></span>
|
|
</div>
|
|
</div>
|
|
<div class="authorpgp">
|
|
<span><a href="ninja_bitaddress.org.txt" target="_blank">PGP Public Key</a></span>
|
|
<span><a href="pgpsignedmsg.txt" target="_blank">Signed Version History</a></span>
|
|
</div>
|
|
<div class="copyright">
|
|
<span>Copyright bitaddress.org.</span>
|
|
<span>JavaScript copyrights are included in the source.</span>
|
|
<span>No warranty.</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
var ninja = {
|
|
// generate bitcoin address and private key and update information in the HTML
|
|
generateNewAddressAndKey: function () {
|
|
try {
|
|
var key = new Bitcoin.ECKey(false);
|
|
var bitcoinAddress = key.getBitcoinAddress().toString();
|
|
//var privateKeyHex = key.toString().toUpperCase(); // The Hex Private Key
|
|
var privateKeyWif = key.getBitcoinWalletImportFormat();
|
|
}
|
|
catch (e) {
|
|
alert(e);
|
|
bitcoinAddress = false;
|
|
}
|
|
|
|
if (bitcoinAddress) {
|
|
document.getElementById("btcaddress").innerHTML = bitcoinAddress;
|
|
document.getElementById("btcprivwif").innerHTML = privateKeyWif;
|
|
document.getElementById("qrcode_public").innerHTML = "";
|
|
document.getElementById("qrcode_private").innerHTML = "";
|
|
try {
|
|
document.getElementById("qrcode_public").appendChild(ninja.createQRCodeCanvas(bitcoinAddress));
|
|
document.getElementById("qrcode_private").appendChild(ninja.createQRCodeCanvas(privateKeyWif));
|
|
}
|
|
catch (e) {
|
|
// for browsers that do not support canvas (IE8)
|
|
document.getElementById("qrcode_public").innerHTML = ninja.createQRCodeTableHtml(bitcoinAddress);
|
|
document.getElementById("qrcode_private").innerHTML = ninja.createQRCodeTableHtml(privateKeyWif);
|
|
}
|
|
}
|
|
// browsers that failed to generate keys
|
|
else {
|
|
document.getElementById("btcaddress").innerHTML = "error";
|
|
document.getElementById("btcprivwif").innerHTML = "error";
|
|
document.getElementById("qrcode_public").innerHTML = "";
|
|
document.getElementById("qrcode_private").innerHTML = "";
|
|
}
|
|
},
|
|
|
|
// determine which type number is big enough for the input text length
|
|
getQRCodeTypeNumber: function (text) {
|
|
var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
|
|
|
|
if (lengthCalculation < 72) {
|
|
return 1;
|
|
}
|
|
else if (lengthCalculation < 128) {
|
|
return 2;
|
|
}
|
|
else if (lengthCalculation < 208) {
|
|
return 3;
|
|
}
|
|
else if (lengthCalculation < 288) {
|
|
return 4;
|
|
}
|
|
else if (lengthCalculation < 368) {
|
|
return 5;
|
|
}
|
|
else if (lengthCalculation < 480) {
|
|
return 6;
|
|
}
|
|
else if (lengthCalculation < 528) {
|
|
return 7;
|
|
}
|
|
else if (lengthCalculation < 688) {
|
|
return 8;
|
|
}
|
|
else if (lengthCalculation < 800) {
|
|
return 9;
|
|
}
|
|
else if (lengthCalculation < 976) {
|
|
return 10;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
createQRCodeCanvas: function (text) {
|
|
// create the qrcode itself
|
|
var typeNumber = ninja.getQRCodeTypeNumber(text);
|
|
var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
|
|
qrcode.addData(text);
|
|
qrcode.make();
|
|
|
|
var width = qrcode.getModuleCount() * 2;
|
|
var height = qrcode.getModuleCount() * 2;
|
|
|
|
// create canvas element
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
var ctx = canvas.getContext('2d');
|
|
// compute tileW/tileH based on width/height
|
|
var tileW = width / qrcode.getModuleCount();
|
|
var tileH = height / qrcode.getModuleCount();
|
|
|
|
// draw in the canvas
|
|
for (var row = 0; row < qrcode.getModuleCount(); row++) {
|
|
for (var col = 0; col < qrcode.getModuleCount(); col++) {
|
|
ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
|
|
ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
|
|
}
|
|
}
|
|
|
|
// return just built canvas
|
|
return canvas;
|
|
},
|
|
|
|
// generate a QRCode and return it's representation as an Html table
|
|
createQRCodeTableHtml: function (text) {
|
|
var typeNumber = ninja.getQRCodeTypeNumber(text);
|
|
var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
|
|
qr.addData(text);
|
|
qr.make();
|
|
|
|
var tableHtml = "";
|
|
tableHtml = "<table class='qrcode_table'>";
|
|
for (var r = 0; r < qr.getModuleCount(); r++) {
|
|
tableHtml += "<tr>";
|
|
for (var c = 0; c < qr.getModuleCount(); c++) {
|
|
if (qr.isDark(r, c)) {
|
|
tableHtml += "<td class='qrcode_tddark'/>";
|
|
} else {
|
|
tableHtml += "<td class='qrcode_tdlight'/>";
|
|
}
|
|
}
|
|
tableHtml += "</tr>";
|
|
}
|
|
tableHtml += "</table>";
|
|
|
|
return tableHtml;
|
|
},
|
|
|
|
// number of mouse movements to wait for
|
|
seedLimit: (function () {
|
|
var num = Crypto.util.randomBytes(2)[1];
|
|
return 10 + Math.floor(num / 5);
|
|
})(),
|
|
|
|
seedCount: 0, // counter
|
|
|
|
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
|
seed: function () {
|
|
ninja.seedCount++;
|
|
// seed a bunch (seedLimit) of times based on mouse moves
|
|
if (ninja.seedCount < ninja.seedLimit) {
|
|
SecureRandom.seedTime();
|
|
}
|
|
// seeding is over now we generate and display the address
|
|
else if (ninja.seedCount == ninja.seedLimit) {
|
|
ninja.generateNewAddressAndKey();
|
|
|
|
// show UI
|
|
document.getElementById("generate").style.display = "none";
|
|
document.getElementById("keyarea").style.display = "block";
|
|
document.getElementById("singlecommands").style.visibility = "visible";
|
|
}
|
|
},
|
|
|
|
// If user has not moved the mouse or if they are on a mobile device
|
|
// we will force the generation after a random period of time.
|
|
forceGenerate: function () {
|
|
// if the mouse has not moved enough
|
|
if (ninja.seedCount < ninja.seedLimit) {
|
|
SecureRandom.seedTime();
|
|
ninja.seedCount = ninja.seedLimit - 1;
|
|
ninja.seed();
|
|
}
|
|
},
|
|
|
|
|
|
tabSwitch: function (walletTab) {
|
|
if (walletTab.className.indexOf("selected") == -1) {
|
|
// unselect all tabs
|
|
for (var wType in ninja.walletType) {
|
|
document.getElementById(wType).className = "tab";
|
|
}
|
|
walletTab.className += " selected";
|
|
ninja.wallets[walletTab.getAttribute("id")].open();
|
|
}
|
|
},
|
|
|
|
wallets: {
|
|
"singlewallet": {
|
|
open: function () {
|
|
document.getElementById("singlearea").style.display = "block";
|
|
document.getElementById("singlecommands").style.display = "block";
|
|
document.getElementById("bulkarea").style.display = "none";
|
|
document.getElementById("bulkcommands").style.display = "none";
|
|
}
|
|
},
|
|
|
|
"bulkwallet": {
|
|
open: function () {
|
|
document.getElementById("singlearea").style.display = "none";
|
|
document.getElementById("singlecommands").style.display = "none";
|
|
document.getElementById("bulkarea").style.display = "block";
|
|
document.getElementById("bulkcommands").style.display = "block";
|
|
|
|
// show a default CSV list if the text area is empty
|
|
if (document.getElementById("bulktextarea").value == "") {
|
|
// return control of the thread to the browser to render the tab switch UI then build a default CSV list
|
|
setTimeout(function () { ninja.buildCSV(3, 1); }, 200);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
walletType: { "singlewallet": "singlewallet", "bulkwallet": "bulkwallet" },
|
|
|
|
// use this function to bulk generate addresses
|
|
// rowLimit: number of Bitcoin Addresses to generate
|
|
// startIndex: add this number to the row index for output purposes
|
|
// returns:
|
|
// index,bitcoinAddress,privateKeyWif
|
|
buildCSV: function (rowLimit, startIndex) {
|
|
document.getElementById("bulktextarea").value = "Generating addresses... " + rowLimit;
|
|
ninja.csv = [];
|
|
ninja.csvRowLimit = rowLimit;
|
|
ninja.csvRowsRemaining = rowLimit;
|
|
ninja.csvStartIndex = --startIndex;
|
|
setTimeout(ninja.batchCSV, 0);
|
|
},
|
|
|
|
csv: [],
|
|
csvRowsRemaining: null, // use to keep track of how many rows are left to process when building a large CSV array
|
|
csvRowLimit: 0,
|
|
csvStartIndex: 0,
|
|
|
|
batchCSV: function () {
|
|
if (ninja.csvRowsRemaining > 0) {
|
|
ninja.csvRowsRemaining--;
|
|
var key = new Bitcoin.ECKey(false);
|
|
var bitcoinAddress = key.getBitcoinAddress().toString();
|
|
var privateKeyWif = key.getBitcoinWalletImportFormat();
|
|
ninja.csv.push((ninja.csvRowLimit - ninja.csvRowsRemaining + ninja.csvStartIndex) + "," + key.getBitcoinAddress().toString() + "," + key.getBitcoinWalletImportFormat());
|
|
|
|
document.getElementById("bulktextarea").value = "Generating addresses... " + ninja.csvRowsRemaining;
|
|
|
|
// release thread to browser to render UI
|
|
setTimeout(ninja.batchCSV, 0);
|
|
}
|
|
// processing is finished so put CSV in text area
|
|
else if (ninja.csvRowsRemaining === 0) {
|
|
document.getElementById("bulktextarea").value = ninja.csv.join("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// if users does not move mouse after random amount of time then generate the key anyway.
|
|
setTimeout(ninja.forceGenerate, ninja.seedLimit * 100);
|
|
</script>
|
|
</body>
|
|
</html> |