8097 lines
495 KiB
HTML
8097 lines
495 KiB
HTML
<!doctype html>
|
||
<html>
|
||
<head>
|
||
<!--
|
||
Donation Address: 1NiNja1bUmhSoTXozBRBEtR8LeF9TGbZBN
|
||
|
||
Notice of Copyrights and Licenses:
|
||
***********************************
|
||
The bitaddress.org project, software and embedded resources are copyright bitaddress.org.
|
||
The bitaddress.org name and logo are not part of the open source license.
|
||
|
||
Portions of the all-in-one HTML document contain JavaScript codes that are the copyrights of others.
|
||
The individual copyrights are included throughout the document along with their licenses.
|
||
Included JavaScript libraries are separated with HTML script tags.
|
||
|
||
Summary of JavaScript functions with a redistributable license:
|
||
JavaScript function License
|
||
******************* ***************
|
||
Array.prototype.map Public Domain
|
||
window.Crypto BSD License
|
||
window.SecureRandom BSD License
|
||
window.EllipticCurve BSD License
|
||
window.BigInteger BSD License
|
||
window.QRCode MIT License
|
||
window.Bitcoin MIT License
|
||
window.Crypto_scrypt MIT License
|
||
|
||
The bitaddress.org software is available under The MIT License (MIT)
|
||
Copyright (c) 2011-2013 bitaddress.org
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||
sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject
|
||
to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||
portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
GitHub Repository: https://github.com/pointbiz/bitaddress.org
|
||
-->
|
||
|
||
<title>bitaddress.org</title>
|
||
<meta charset="utf-8">
|
||
|
||
<script type="text/javascript">
|
||
// Array.prototype.map function is in the public domain.
|
||
// 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.5.4 Crypto.js
|
||
* http://code.google.com/p/crypto-js/
|
||
* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
|
||
* http://code.google.com/p/crypto-js/wiki/License
|
||
*/
|
||
if (typeof Crypto == "undefined" || !Crypto.util) {
|
||
(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] & 0xFF) << (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) {
|
||
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) {
|
||
// 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 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) & 0xFF);
|
||
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("");
|
||
}
|
||
|
||
};
|
||
|
||
})();
|
||
}
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*!
|
||
* Crypto-JS v2.5.4 SHA256.js
|
||
* http://code.google.com/p/crypto-js/
|
||
* Copyright (c) 2009-2013, 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) >>> 0;
|
||
d = c;
|
||
c = b;
|
||
b = a;
|
||
a = (t1 + t2) >>> 0;
|
||
|
||
}
|
||
|
||
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;
|
||
|
||
SHA256._digestsize = 32;
|
||
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*!
|
||
* Crypto-JS v2.5.4 PBKDF2.js
|
||
* http://code.google.com/p/crypto-js/
|
||
* Copyright (c) 2009-2013, 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;
|
||
|
||
C.PBKDF2 = function (password, salt, keylen, options) {
|
||
|
||
// Convert to byte arrays
|
||
if (password.constructor == String) password = UTF8.stringToBytes(password);
|
||
if (salt.constructor == String) salt = UTF8.stringToBytes(salt);
|
||
/* else, assume byte arrays already */
|
||
|
||
// Defaults
|
||
var hasher = options && options.hasher || C.SHA1,
|
||
iterations = options && options.iterations || 1;
|
||
|
||
// Pseudo-random function
|
||
function PRF(password, salt) {
|
||
return C.HMAC(hasher, salt, password, { asBytes: true });
|
||
}
|
||
|
||
// Generate key
|
||
var derivedKeyBytes = [],
|
||
blockindex = 1;
|
||
while (derivedKeyBytes.length < keylen) {
|
||
var block = PRF(password, salt.concat(util.wordsToBytes([blockindex])));
|
||
for (var u = block, i = 1; i < iterations; i++) {
|
||
u = PRF(password, u);
|
||
for (var j = 0; j < block.length; j++) block[j] ^= u[j];
|
||
}
|
||
derivedKeyBytes = derivedKeyBytes.concat(block);
|
||
blockindex++;
|
||
}
|
||
|
||
// Truncate excess bytes
|
||
derivedKeyBytes.length = keylen;
|
||
|
||
return options && options.asBytes ? derivedKeyBytes :
|
||
options && options.asString ? Binary.bytesToString(derivedKeyBytes) :
|
||
util.bytesToHex(derivedKeyBytes);
|
||
|
||
};
|
||
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*!
|
||
* Crypto-JS v2.5.4 HMAC.js
|
||
* http://code.google.com/p/crypto-js/
|
||
* Copyright (c) 2009-2013, 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;
|
||
|
||
C.HMAC = function (hasher, message, key, options) {
|
||
|
||
// Convert to byte arrays
|
||
if (message.constructor == String) message = UTF8.stringToBytes(message);
|
||
if (key.constructor == String) key = UTF8.stringToBytes(key);
|
||
/* else, assume byte arrays already */
|
||
|
||
// Allow arbitrary length keys
|
||
if (key.length > hasher._blocksize * 4)
|
||
key = hasher(key, { asBytes: true });
|
||
|
||
// XOR keys with pad constants
|
||
var okey = key.slice(0),
|
||
ikey = key.slice(0);
|
||
for (var i = 0; i < hasher._blocksize * 4; i++) {
|
||
okey[i] ^= 0x5C;
|
||
ikey[i] ^= 0x36;
|
||
}
|
||
|
||
var hmacbytes = hasher(okey.concat(hasher(ikey.concat(message), { asBytes: true })), { asBytes: true });
|
||
|
||
return options && options.asBytes ? hmacbytes :
|
||
options && options.asString ? Binary.bytesToString(hmacbytes) :
|
||
util.bytesToHex(hmacbytes);
|
||
|
||
};
|
||
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*!
|
||
* Crypto-JS v2.5.4 AES.js
|
||
* http://code.google.com/p/crypto-js/
|
||
* Copyright (c) 2009-2013, 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;
|
||
|
||
// Precomputed SBOX
|
||
var SBOX = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
|
||
|
||
// Compute inverse SBOX lookup table
|
||
for (var INVSBOX = [], i = 0; i < 256; i++) INVSBOX[SBOX[i]] = i;
|
||
|
||
// Compute multiplication in GF(2^8) lookup tables
|
||
var MULT2 = [],
|
||
MULT3 = [],
|
||
MULT9 = [],
|
||
MULTB = [],
|
||
MULTD = [],
|
||
MULTE = [];
|
||
|
||
function xtime(a, b) {
|
||
for (var result = 0, i = 0; i < 8; i++) {
|
||
if (b & 1) result ^= a;
|
||
var hiBitSet = a & 0x80;
|
||
a = (a << 1) & 0xFF;
|
||
if (hiBitSet) a ^= 0x1b;
|
||
b >>>= 1;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
for (var i = 0; i < 256; i++) {
|
||
MULT2[i] = xtime(i, 2);
|
||
MULT3[i] = xtime(i, 3);
|
||
MULT9[i] = xtime(i, 9);
|
||
MULTB[i] = xtime(i, 0xB);
|
||
MULTD[i] = xtime(i, 0xD);
|
||
MULTE[i] = xtime(i, 0xE);
|
||
}
|
||
|
||
// Precomputed RCon lookup
|
||
var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
|
||
|
||
// Inner state
|
||
var state = [[], [], [], []],
|
||
keylength,
|
||
nrounds,
|
||
keyschedule;
|
||
|
||
var AES = C.AES = {
|
||
|
||
/**
|
||
* Public API
|
||
*/
|
||
|
||
encrypt: function (message, password, options) {
|
||
|
||
options = options || {};
|
||
|
||
// Determine mode
|
||
var mode = options.mode || new C.mode.OFB;
|
||
|
||
// Allow mode to override options
|
||
if (mode.fixOptions) mode.fixOptions(options);
|
||
|
||
var
|
||
|
||
// Convert to bytes if message is a string
|
||
m = (
|
||
message.constructor == String ?
|
||
UTF8.stringToBytes(message) :
|
||
message
|
||
),
|
||
|
||
// Generate random IV
|
||
iv = options.iv || util.randomBytes(AES._blocksize * 4),
|
||
|
||
// Generate key
|
||
k = (
|
||
password.constructor == String ?
|
||
// Derive key from pass-phrase
|
||
C.PBKDF2(password, iv, 32, { asBytes: true }) :
|
||
// else, assume byte array representing cryptographic key
|
||
password
|
||
);
|
||
|
||
// Encrypt
|
||
AES._init(k);
|
||
mode.encrypt(AES, m, iv);
|
||
|
||
// Return ciphertext
|
||
m = options.iv ? m : iv.concat(m);
|
||
return (options && options.asBytes) ? m : util.bytesToBase64(m);
|
||
|
||
},
|
||
|
||
decrypt: function (ciphertext, password, options) {
|
||
|
||
options = options || {};
|
||
|
||
// Determine mode
|
||
var mode = options.mode || new C.mode.OFB;
|
||
|
||
// Allow mode to override options
|
||
if (mode.fixOptions) mode.fixOptions(options);
|
||
|
||
var
|
||
|
||
// Convert to bytes if ciphertext is a string
|
||
c = (
|
||
ciphertext.constructor == String ?
|
||
util.base64ToBytes(ciphertext) :
|
||
ciphertext
|
||
),
|
||
|
||
// Separate IV and message
|
||
iv = options.iv || c.splice(0, AES._blocksize * 4),
|
||
|
||
// Generate key
|
||
k = (
|
||
password.constructor == String ?
|
||
// Derive key from pass-phrase
|
||
C.PBKDF2(password, iv, 32, { asBytes: true }) :
|
||
// else, assume byte array representing cryptographic key
|
||
password
|
||
);
|
||
|
||
// Decrypt
|
||
AES._init(k);
|
||
mode.decrypt(AES, c, iv);
|
||
|
||
// Return plaintext
|
||
return (options && options.asBytes) ? c : UTF8.bytesToString(c);
|
||
|
||
},
|
||
|
||
|
||
/**
|
||
* Package private methods and properties
|
||
*/
|
||
|
||
_blocksize: 4,
|
||
|
||
_encryptblock: function (m, offset) {
|
||
|
||
// Set input
|
||
for (var row = 0; row < AES._blocksize; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] = m[offset + col * 4 + row];
|
||
}
|
||
|
||
// Add round key
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] ^= keyschedule[col][row];
|
||
}
|
||
|
||
for (var round = 1; round < nrounds; round++) {
|
||
|
||
// Sub bytes
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] = SBOX[state[row][col]];
|
||
}
|
||
|
||
// Shift rows
|
||
state[1].push(state[1].shift());
|
||
state[2].push(state[2].shift());
|
||
state[2].push(state[2].shift());
|
||
state[3].unshift(state[3].pop());
|
||
|
||
// Mix columns
|
||
for (var col = 0; col < 4; col++) {
|
||
|
||
var s0 = state[0][col],
|
||
s1 = state[1][col],
|
||
s2 = state[2][col],
|
||
s3 = state[3][col];
|
||
|
||
state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3;
|
||
state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3;
|
||
state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3];
|
||
state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3];
|
||
|
||
}
|
||
|
||
// Add round key
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] ^= keyschedule[round * 4 + col][row];
|
||
}
|
||
|
||
}
|
||
|
||
// Sub bytes
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] = SBOX[state[row][col]];
|
||
}
|
||
|
||
// Shift rows
|
||
state[1].push(state[1].shift());
|
||
state[2].push(state[2].shift());
|
||
state[2].push(state[2].shift());
|
||
state[3].unshift(state[3].pop());
|
||
|
||
// Add round key
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] ^= keyschedule[nrounds * 4 + col][row];
|
||
}
|
||
|
||
// Set output
|
||
for (var row = 0; row < AES._blocksize; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
m[offset + col * 4 + row] = state[row][col];
|
||
}
|
||
|
||
},
|
||
|
||
_decryptblock: function (c, offset) {
|
||
|
||
// Set input
|
||
for (var row = 0; row < AES._blocksize; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] = c[offset + col * 4 + row];
|
||
}
|
||
|
||
// Add round key
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] ^= keyschedule[nrounds * 4 + col][row];
|
||
}
|
||
|
||
for (var round = 1; round < nrounds; round++) {
|
||
|
||
// Inv shift rows
|
||
state[1].unshift(state[1].pop());
|
||
state[2].push(state[2].shift());
|
||
state[2].push(state[2].shift());
|
||
state[3].push(state[3].shift());
|
||
|
||
// Inv sub bytes
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] = INVSBOX[state[row][col]];
|
||
}
|
||
|
||
// Add round key
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row];
|
||
}
|
||
|
||
// Inv mix columns
|
||
for (var col = 0; col < 4; col++) {
|
||
|
||
var s0 = state[0][col],
|
||
s1 = state[1][col],
|
||
s2 = state[2][col],
|
||
s3 = state[3][col];
|
||
|
||
state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3];
|
||
state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3];
|
||
state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3];
|
||
state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3];
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// Inv shift rows
|
||
state[1].unshift(state[1].pop());
|
||
state[2].push(state[2].shift());
|
||
state[2].push(state[2].shift());
|
||
state[3].push(state[3].shift());
|
||
|
||
// Inv sub bytes
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] = INVSBOX[state[row][col]];
|
||
}
|
||
|
||
// Add round key
|
||
for (var row = 0; row < 4; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
state[row][col] ^= keyschedule[col][row];
|
||
}
|
||
|
||
// Set output
|
||
for (var row = 0; row < AES._blocksize; row++) {
|
||
for (var col = 0; col < 4; col++)
|
||
c[offset + col * 4 + row] = state[row][col];
|
||
}
|
||
|
||
},
|
||
|
||
|
||
/**
|
||
* Private methods
|
||
*/
|
||
|
||
_init: function (k) {
|
||
keylength = k.length / 4;
|
||
nrounds = keylength + 6;
|
||
AES._keyexpansion(k);
|
||
},
|
||
|
||
// Generate a key schedule
|
||
_keyexpansion: function (k) {
|
||
|
||
keyschedule = [];
|
||
|
||
for (var row = 0; row < keylength; row++) {
|
||
keyschedule[row] = [
|
||
k[row * 4],
|
||
k[row * 4 + 1],
|
||
k[row * 4 + 2],
|
||
k[row * 4 + 3]
|
||
];
|
||
}
|
||
|
||
for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) {
|
||
|
||
var temp = [
|
||
keyschedule[row - 1][0],
|
||
keyschedule[row - 1][1],
|
||
keyschedule[row - 1][2],
|
||
keyschedule[row - 1][3]
|
||
];
|
||
|
||
if (row % keylength == 0) {
|
||
|
||
// Rot word
|
||
temp.push(temp.shift());
|
||
|
||
// Sub word
|
||
temp[0] = SBOX[temp[0]];
|
||
temp[1] = SBOX[temp[1]];
|
||
temp[2] = SBOX[temp[2]];
|
||
temp[3] = SBOX[temp[3]];
|
||
|
||
temp[0] ^= RCON[row / keylength];
|
||
|
||
} else if (keylength > 6 && row % keylength == 4) {
|
||
|
||
// Sub word
|
||
temp[0] = SBOX[temp[0]];
|
||
temp[1] = SBOX[temp[1]];
|
||
temp[2] = SBOX[temp[2]];
|
||
temp[3] = SBOX[temp[3]];
|
||
|
||
}
|
||
|
||
keyschedule[row] = [
|
||
keyschedule[row - keylength][0] ^ temp[0],
|
||
keyschedule[row - keylength][1] ^ temp[1],
|
||
keyschedule[row - keylength][2] ^ temp[2],
|
||
keyschedule[row - keylength][3] ^ temp[3]
|
||
];
|
||
|
||
}
|
||
|
||
}
|
||
|
||
};
|
||
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*!
|
||
* Crypto-JS 2.5.4 BlockModes.js
|
||
* contribution from Simon Greatrix
|
||
*/
|
||
|
||
(function (C) {
|
||
|
||
// Create pad namespace
|
||
var C_pad = C.pad = {};
|
||
|
||
// Calculate the number of padding bytes required.
|
||
function _requiredPadding(cipher, message) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
var reqd = blockSizeInBytes - message.length % blockSizeInBytes;
|
||
return reqd;
|
||
}
|
||
|
||
// Remove padding when the final byte gives the number of padding bytes.
|
||
var _unpadLength = function (cipher, message, alg, padding) {
|
||
var pad = message.pop();
|
||
if (pad == 0) {
|
||
throw new Error("Invalid zero-length padding specified for " + alg
|
||
+ ". Wrong cipher specification or key used?");
|
||
}
|
||
var maxPad = cipher._blocksize * 4;
|
||
if (pad > maxPad) {
|
||
throw new Error("Invalid padding length of " + pad
|
||
+ " specified for " + alg
|
||
+ ". Wrong cipher specification or key used?");
|
||
}
|
||
for (var i = 1; i < pad; i++) {
|
||
var b = message.pop();
|
||
if (padding != undefined && padding != b) {
|
||
throw new Error("Invalid padding byte of 0x" + b.toString(16)
|
||
+ " specified for " + alg
|
||
+ ". Wrong cipher specification or key used?");
|
||
}
|
||
}
|
||
};
|
||
|
||
// No-operation padding, used for stream ciphers
|
||
C_pad.NoPadding = {
|
||
pad: function (cipher, message) { },
|
||
unpad: function (cipher, message) { }
|
||
};
|
||
|
||
// Zero Padding.
|
||
//
|
||
// If the message is not an exact number of blocks, the final block is
|
||
// completed with 0x00 bytes. There is no unpadding.
|
||
C_pad.ZeroPadding = {
|
||
pad: function (cipher, message) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
var reqd = message.length % blockSizeInBytes;
|
||
if (reqd != 0) {
|
||
for (reqd = blockSizeInBytes - reqd; reqd > 0; reqd--) {
|
||
message.push(0x00);
|
||
}
|
||
}
|
||
},
|
||
|
||
unpad: function (cipher, message) {
|
||
while (message[message.length - 1] == 0) {
|
||
message.pop();
|
||
}
|
||
}
|
||
};
|
||
|
||
// ISO/IEC 7816-4 padding.
|
||
//
|
||
// Pads the plain text with an 0x80 byte followed by as many 0x00
|
||
// bytes are required to complete the block.
|
||
C_pad.iso7816 = {
|
||
pad: function (cipher, message) {
|
||
var reqd = _requiredPadding(cipher, message);
|
||
message.push(0x80);
|
||
for (; reqd > 1; reqd--) {
|
||
message.push(0x00);
|
||
}
|
||
},
|
||
|
||
unpad: function (cipher, message) {
|
||
var padLength;
|
||
for (padLength = cipher._blocksize * 4; padLength > 0; padLength--) {
|
||
var b = message.pop();
|
||
if (b == 0x80) return;
|
||
if (b != 0x00) {
|
||
throw new Error("ISO-7816 padding byte must be 0, not 0x" + b.toString(16) + ". Wrong cipher specification or key used?");
|
||
}
|
||
}
|
||
throw new Error("ISO-7816 padded beyond cipher block size. Wrong cipher specification or key used?");
|
||
}
|
||
};
|
||
|
||
// ANSI X.923 padding
|
||
//
|
||
// The final block is padded with zeros except for the last byte of the
|
||
// last block which contains the number of padding bytes.
|
||
C_pad.ansix923 = {
|
||
pad: function (cipher, message) {
|
||
var reqd = _requiredPadding(cipher, message);
|
||
for (var i = 1; i < reqd; i++) {
|
||
message.push(0x00);
|
||
}
|
||
message.push(reqd);
|
||
},
|
||
|
||
unpad: function (cipher, message) {
|
||
_unpadLength(cipher, message, "ANSI X.923", 0);
|
||
}
|
||
};
|
||
|
||
// ISO 10126
|
||
//
|
||
// The final block is padded with random bytes except for the last
|
||
// byte of the last block which contains the number of padding bytes.
|
||
C_pad.iso10126 = {
|
||
pad: function (cipher, message) {
|
||
var reqd = _requiredPadding(cipher, message);
|
||
for (var i = 1; i < reqd; i++) {
|
||
message.push(Math.floor(Math.random() * 256));
|
||
}
|
||
message.push(reqd);
|
||
},
|
||
|
||
unpad: function (cipher, message) {
|
||
_unpadLength(cipher, message, "ISO 10126", undefined);
|
||
}
|
||
};
|
||
|
||
// PKCS7 padding
|
||
//
|
||
// PKCS7 is described in RFC 5652. Padding is in whole bytes. The
|
||
// value of each added byte is the number of bytes that are added,
|
||
// i.e. N bytes, each of value N are added.
|
||
C_pad.pkcs7 = {
|
||
pad: function (cipher, message) {
|
||
var reqd = _requiredPadding(cipher, message);
|
||
for (var i = 0; i < reqd; i++) {
|
||
message.push(reqd);
|
||
}
|
||
},
|
||
|
||
unpad: function (cipher, message) {
|
||
_unpadLength(cipher, message, "PKCS 7", message[message.length - 1]);
|
||
}
|
||
};
|
||
|
||
// Create mode namespace
|
||
var C_mode = C.mode = {};
|
||
|
||
/**
|
||
* Mode base "class".
|
||
*/
|
||
var Mode = C_mode.Mode = function (padding) {
|
||
if (padding) {
|
||
this._padding = padding;
|
||
}
|
||
};
|
||
|
||
Mode.prototype = {
|
||
encrypt: function (cipher, m, iv) {
|
||
this._padding.pad(cipher, m);
|
||
this._doEncrypt(cipher, m, iv);
|
||
},
|
||
|
||
decrypt: function (cipher, m, iv) {
|
||
this._doDecrypt(cipher, m, iv);
|
||
this._padding.unpad(cipher, m);
|
||
},
|
||
|
||
// Default padding
|
||
_padding: C_pad.iso7816
|
||
};
|
||
|
||
|
||
/**
|
||
* Electronic Code Book mode.
|
||
*
|
||
* ECB applies the cipher directly against each block of the input.
|
||
*
|
||
* ECB does not require an initialization vector.
|
||
*/
|
||
var ECB = C_mode.ECB = function () {
|
||
// Call parent constructor
|
||
Mode.apply(this, arguments);
|
||
};
|
||
|
||
// Inherit from Mode
|
||
var ECB_prototype = ECB.prototype = new Mode;
|
||
|
||
// Concrete steps for Mode template
|
||
ECB_prototype._doEncrypt = function (cipher, m, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
// Encrypt each block
|
||
for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
|
||
cipher._encryptblock(m, offset);
|
||
}
|
||
};
|
||
ECB_prototype._doDecrypt = function (cipher, c, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
// Decrypt each block
|
||
for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
|
||
cipher._decryptblock(c, offset);
|
||
}
|
||
};
|
||
|
||
// ECB never uses an IV
|
||
ECB_prototype.fixOptions = function (options) {
|
||
options.iv = [];
|
||
};
|
||
|
||
|
||
/**
|
||
* Cipher block chaining
|
||
*
|
||
* The first block is XORed with the IV. Subsequent blocks are XOR with the
|
||
* previous cipher output.
|
||
*/
|
||
var CBC = C_mode.CBC = function () {
|
||
// Call parent constructor
|
||
Mode.apply(this, arguments);
|
||
};
|
||
|
||
// Inherit from Mode
|
||
var CBC_prototype = CBC.prototype = new Mode;
|
||
|
||
// Concrete steps for Mode template
|
||
CBC_prototype._doEncrypt = function (cipher, m, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
|
||
// Encrypt each block
|
||
for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
|
||
if (offset == 0) {
|
||
// XOR first block using IV
|
||
for (var i = 0; i < blockSizeInBytes; i++)
|
||
m[i] ^= iv[i];
|
||
} else {
|
||
// XOR this block using previous crypted block
|
||
for (var i = 0; i < blockSizeInBytes; i++)
|
||
m[offset + i] ^= m[offset + i - blockSizeInBytes];
|
||
}
|
||
// Encrypt block
|
||
cipher._encryptblock(m, offset);
|
||
}
|
||
};
|
||
CBC_prototype._doDecrypt = function (cipher, c, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
|
||
// At the start, the previously crypted block is the IV
|
||
var prevCryptedBlock = iv;
|
||
|
||
// Decrypt each block
|
||
for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
|
||
// Save this crypted block
|
||
var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
|
||
// Decrypt block
|
||
cipher._decryptblock(c, offset);
|
||
// XOR decrypted block using previous crypted block
|
||
for (var i = 0; i < blockSizeInBytes; i++) {
|
||
c[offset + i] ^= prevCryptedBlock[i];
|
||
}
|
||
prevCryptedBlock = thisCryptedBlock;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* Cipher feed back
|
||
*
|
||
* The cipher output is XORed with the plain text to produce the cipher output,
|
||
* which is then fed back into the cipher to produce a bit pattern to XOR the
|
||
* next block with.
|
||
*
|
||
* This is a stream cipher mode and does not require padding.
|
||
*/
|
||
var CFB = C_mode.CFB = function () {
|
||
// Call parent constructor
|
||
Mode.apply(this, arguments);
|
||
};
|
||
|
||
// Inherit from Mode
|
||
var CFB_prototype = CFB.prototype = new Mode;
|
||
|
||
// Override padding
|
||
CFB_prototype._padding = C_pad.NoPadding;
|
||
|
||
// Concrete steps for Mode template
|
||
CFB_prototype._doEncrypt = function (cipher, m, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4,
|
||
keystream = iv.slice(0);
|
||
|
||
// Encrypt each byte
|
||
for (var i = 0; i < m.length; i++) {
|
||
|
||
var j = i % blockSizeInBytes;
|
||
if (j == 0) cipher._encryptblock(keystream, 0);
|
||
|
||
m[i] ^= keystream[j];
|
||
keystream[j] = m[i];
|
||
}
|
||
};
|
||
CFB_prototype._doDecrypt = function (cipher, c, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4,
|
||
keystream = iv.slice(0);
|
||
|
||
// Encrypt each byte
|
||
for (var i = 0; i < c.length; i++) {
|
||
|
||
var j = i % blockSizeInBytes;
|
||
if (j == 0) cipher._encryptblock(keystream, 0);
|
||
|
||
var b = c[i];
|
||
c[i] ^= keystream[j];
|
||
keystream[j] = b;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* Output feed back
|
||
*
|
||
* The cipher repeatedly encrypts its own output. The output is XORed with the
|
||
* plain text to produce the cipher text.
|
||
*
|
||
* This is a stream cipher mode and does not require padding.
|
||
*/
|
||
var OFB = C_mode.OFB = function () {
|
||
// Call parent constructor
|
||
Mode.apply(this, arguments);
|
||
};
|
||
|
||
// Inherit from Mode
|
||
var OFB_prototype = OFB.prototype = new Mode;
|
||
|
||
// Override padding
|
||
OFB_prototype._padding = C_pad.NoPadding;
|
||
|
||
// Concrete steps for Mode template
|
||
OFB_prototype._doEncrypt = function (cipher, m, iv) {
|
||
|
||
var blockSizeInBytes = cipher._blocksize * 4,
|
||
keystream = iv.slice(0);
|
||
|
||
// Encrypt each byte
|
||
for (var i = 0; i < m.length; i++) {
|
||
|
||
// Generate keystream
|
||
if (i % blockSizeInBytes == 0)
|
||
cipher._encryptblock(keystream, 0);
|
||
|
||
// Encrypt byte
|
||
m[i] ^= keystream[i % blockSizeInBytes];
|
||
|
||
}
|
||
};
|
||
OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
|
||
|
||
/**
|
||
* Counter
|
||
* @author Gergely Risko
|
||
*
|
||
* After every block the last 4 bytes of the IV is increased by one
|
||
* with carry and that IV is used for the next block.
|
||
*
|
||
* This is a stream cipher mode and does not require padding.
|
||
*/
|
||
var CTR = C_mode.CTR = function () {
|
||
// Call parent constructor
|
||
Mode.apply(this, arguments);
|
||
};
|
||
|
||
// Inherit from Mode
|
||
var CTR_prototype = CTR.prototype = new Mode;
|
||
|
||
// Override padding
|
||
CTR_prototype._padding = C_pad.NoPadding;
|
||
|
||
CTR_prototype._doEncrypt = function (cipher, m, iv) {
|
||
var blockSizeInBytes = cipher._blocksize * 4;
|
||
var counter = iv.slice(0);
|
||
|
||
for (var i = 0; i < m.length; ) {
|
||
// do not lose iv
|
||
var keystream = counter.slice(0);
|
||
|
||
// Generate keystream for next block
|
||
cipher._encryptblock(keystream, 0);
|
||
|
||
// XOR keystream with block
|
||
for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
|
||
m[i] ^= keystream[j];
|
||
}
|
||
|
||
// Increase counter
|
||
if (++(counter[blockSizeInBytes - 1]) == 256) {
|
||
counter[blockSizeInBytes - 1] = 0;
|
||
if (++(counter[blockSizeInBytes - 2]) == 256) {
|
||
counter[blockSizeInBytes - 2] = 0;
|
||
if (++(counter[blockSizeInBytes - 3]) == 256) {
|
||
counter[blockSizeInBytes - 3] = 0;
|
||
++(counter[blockSizeInBytes - 4]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
|
||
|
||
})(Crypto);
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*!
|
||
* Crypto-JS v2.0.0 RIPEMD-160
|
||
* 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, bitaddress.org BSD License.
|
||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
||
*/
|
||
(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();
|
||
// entropy
|
||
sr.seedInt(window.screenX);
|
||
sr.seedInt(window.screenY);
|
||
}
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/faa10f0f6a1fff0b9a99fffb9bc30cee33b17212/src/ecdsa.js
|
||
/*!
|
||
* Basic Javascript Elliptic Curve implementation
|
||
* Ported loosely from BouncyCastle's Java EC code
|
||
* Only Fp curves implemented for now
|
||
*
|
||
* Copyright Tom Wu, bitaddress.org BSD License.
|
||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
||
*/
|
||
(function () {
|
||
|
||
// Constructor function of Global EllipticCurve object
|
||
var ec = window.EllipticCurve = function () { };
|
||
|
||
|
||
// ----------------
|
||
// ECFieldElementFp constructor
|
||
// q instanceof BigInteger
|
||
// x instanceof BigInteger
|
||
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);
|
||
};
|
||
|
||
// D.1.4 91
|
||
/**
|
||
* return a sqrt root - the routine verifies that the calculation
|
||
* returns the right value - if none exists it returns null.
|
||
*
|
||
* Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||
* Ported to JavaScript by bitaddress.org
|
||
*/
|
||
ec.FieldElementFp.prototype.sqrt = function () {
|
||
if (!this.q.testBit(0)) throw new Error("even value of q");
|
||
|
||
// p mod 4 == 3
|
||
if (this.q.testBit(1)) {
|
||
// z = g^(u+1) + p, p = 4u + 3
|
||
var z = new ec.FieldElementFp(this.q, this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE), this.q));
|
||
return z.square().equals(this) ? z : null;
|
||
}
|
||
|
||
// p mod 4 == 1
|
||
var qMinusOne = this.q.subtract(BigInteger.ONE);
|
||
var legendreExponent = qMinusOne.shiftRight(1);
|
||
if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE))) return null;
|
||
var u = qMinusOne.shiftRight(2);
|
||
var k = u.shiftLeft(1).add(BigInteger.ONE);
|
||
var Q = this.x;
|
||
var fourQ = Q.shiftLeft(2).mod(this.q);
|
||
var U, V;
|
||
|
||
do {
|
||
var rand = new SecureRandom();
|
||
var P;
|
||
do {
|
||
P = new BigInteger(this.q.bitLength(), rand);
|
||
}
|
||
while (P.compareTo(this.q) >= 0 || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));
|
||
|
||
var result = ec.FieldElementFp.fastLucasSequence(this.q, P, Q, k);
|
||
|
||
U = result[0];
|
||
V = result[1];
|
||
if (V.multiply(V).mod(this.q).equals(fourQ)) {
|
||
// Integer division by 2, mod q
|
||
if (V.testBit(0)) {
|
||
V = V.add(this.q);
|
||
}
|
||
V = V.shiftRight(1);
|
||
return new ec.FieldElementFp(this.q, V);
|
||
}
|
||
}
|
||
while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));
|
||
|
||
return null;
|
||
};
|
||
|
||
/*
|
||
* Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||
* Ported to JavaScript by bitaddress.org
|
||
*/
|
||
ec.FieldElementFp.fastLucasSequence = function (p, P, Q, k) {
|
||
// TODO Research and apply "common-multiplicand multiplication here"
|
||
|
||
var n = k.bitLength();
|
||
var s = k.getLowestSetBit();
|
||
var Uh = BigInteger.ONE;
|
||
var Vl = BigInteger.TWO;
|
||
var Vh = P;
|
||
var Ql = BigInteger.ONE;
|
||
var Qh = BigInteger.ONE;
|
||
|
||
for (var j = n - 1; j >= s + 1; --j) {
|
||
Ql = Ql.multiply(Qh).mod(p);
|
||
if (k.testBit(j)) {
|
||
Qh = Ql.multiply(Q).mod(p);
|
||
Uh = Uh.multiply(Vh).mod(p);
|
||
Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
|
||
Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
|
||
}
|
||
else {
|
||
Qh = Ql;
|
||
Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
|
||
Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
|
||
Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
|
||
}
|
||
}
|
||
|
||
Ql = Ql.multiply(Qh).mod(p);
|
||
Qh = Ql.multiply(Q).mod(p);
|
||
Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
|
||
Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
|
||
Ql = Ql.multiply(Qh).mod(p);
|
||
|
||
for (var j = 1; j <= s; ++j) {
|
||
Uh = Uh.multiply(Vl).mod(p);
|
||
Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
|
||
Ql = Ql.multiply(Ql).mod(p);
|
||
}
|
||
|
||
return [Uh, Vl];
|
||
};
|
||
|
||
// ----------------
|
||
// ECPointFp constructor
|
||
ec.PointFp = function (curve, x, y, z, compressed) {
|
||
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;
|
||
// compression flag
|
||
this.compressed = !!compressed;
|
||
};
|
||
|
||
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
|
||
// patched by coretechs to support compressed public keys
|
||
ec.PointFp.prototype.getEncoded = function (compressed) {
|
||
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);
|
||
|
||
// when compressed prepend byte depending if y point is even or odd
|
||
if (compressed) {
|
||
if (y.isEven()) {
|
||
enc.unshift(0x02);
|
||
}
|
||
else {
|
||
enc.unshift(0x03);
|
||
}
|
||
}
|
||
else {
|
||
enc.unshift(0x04);
|
||
enc = enc.concat(ec.integerToBytes(y, len)); // uncompressed public key appends the bytes of the y point
|
||
}
|
||
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.toString = function () {
|
||
return '(' + this.getX().toBigInteger().toString() + ',' + this.getY().toBigInteger().toString() + ')';
|
||
};
|
||
|
||
/**
|
||
* Validate an elliptic curve point.
|
||
*
|
||
* See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
|
||
*/
|
||
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
|
||
// compressed support added by bitaddress.org
|
||
ec.CurveFp.prototype.decodePointHex = function (s) {
|
||
var firstByte = parseInt(s.substr(0, 2), 16);
|
||
switch (firstByte) { // first byte
|
||
case 0:
|
||
return this.infinity;
|
||
case 2: // compressed
|
||
case 3: // compressed
|
||
var yTilde = firstByte & 1;
|
||
var xHex = s.substr(2, s.length - 2);
|
||
var X1 = new BigInteger(xHex, 16);
|
||
return this.decompressPoint(yTilde, X1);
|
||
case 4: // uncompressed
|
||
case 6: // hybrid
|
||
case 7: // hybrid
|
||
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;
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||
* Ported to JavaScript by bitaddress.org
|
||
*
|
||
* Number yTilde
|
||
* BigInteger X1
|
||
*/
|
||
ec.CurveFp.prototype.decompressPoint = function (yTilde, X1) {
|
||
var x = this.fromBigInteger(X1);
|
||
var alpha = x.multiply(x.square().add(this.getA())).add(this.getB());
|
||
var beta = alpha.sqrt();
|
||
// if we can't find a sqrt we haven't got a point on the curve - run!
|
||
if (beta == null) throw new Error("Invalid point compression");
|
||
var betaValue = beta.toBigInteger();
|
||
var bit0 = betaValue.testBit(0) ? 1 : 0;
|
||
if (bit0 != yTilde) {
|
||
// Use the other root
|
||
beta = this.fromBigInteger(this.getQ().subtract(betaValue));
|
||
}
|
||
return new ec.PointFp(this, x, beta, null, true);
|
||
};
|
||
|
||
|
||
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. v1.3
|
||
*
|
||
* Copyright (c) 2005 Tom Wu
|
||
* All Rights Reserved.
|
||
* BSD License
|
||
* 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 (this.s < 0) ? -r : 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) --- //
|
||
// https://raw.github.com/bitcoinjs/bitcoinjs-lib/07f9d55ccb6abd962efb6befdd37671f85ea4ff9/src/util.js
|
||
// BigInteger monkey patching
|
||
BigInteger.valueOf = nbv;
|
||
|
||
/**
|
||
* Returns a byte array representation of the big integer.
|
||
*
|
||
* This returns the absolute of the contained value in big endian
|
||
* form. A value of zero results in an empty array.
|
||
*/
|
||
BigInteger.prototype.toByteArrayUnsigned = function () {
|
||
var ba = this.abs().toByteArray();
|
||
if (ba.length) {
|
||
if (ba[0] == 0) {
|
||
ba = ba.slice(1);
|
||
}
|
||
return ba.map(function (v) {
|
||
return (v < 0) ? v + 256 : v;
|
||
});
|
||
} else {
|
||
// Empty array, nothing to do
|
||
return ba;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Turns a byte array into a big integer.
|
||
*
|
||
* This function will interpret a byte array as a big integer in big
|
||
* endian notation and ignore leading zeros.
|
||
*/
|
||
BigInteger.fromByteArrayUnsigned = function (ba) {
|
||
if (!ba.length) {
|
||
return ba.valueOf(0);
|
||
} else if (ba[0] & 0x80) {
|
||
// Prepend a zero so the BigInteger class doesn't mistake this
|
||
// for a negative integer.
|
||
return new BigInteger([0].concat(ba));
|
||
} else {
|
||
return new BigInteger(ba);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Converts big integer to signed byte representation.
|
||
*
|
||
* The format for this value uses a the most significant bit as a sign
|
||
* bit. If the most significant bit is already occupied by the
|
||
* absolute value, an extra byte is prepended and the sign bit is set
|
||
* there.
|
||
*
|
||
* Examples:
|
||
*
|
||
* 0 => 0x00
|
||
* 1 => 0x01
|
||
* -1 => 0x81
|
||
* 127 => 0x7f
|
||
* -127 => 0xff
|
||
* 128 => 0x0080
|
||
* -128 => 0x8080
|
||
* 255 => 0x00ff
|
||
* -255 => 0x80ff
|
||
* 16300 => 0x3fac
|
||
* -16300 => 0xbfac
|
||
* 62300 => 0x00f35c
|
||
* -62300 => 0x80f35c
|
||
*/
|
||
BigInteger.prototype.toByteArraySigned = function () {
|
||
var val = this.abs().toByteArrayUnsigned();
|
||
var neg = this.compareTo(BigInteger.ZERO) < 0;
|
||
|
||
if (neg) {
|
||
if (val[0] & 0x80) {
|
||
val.unshift(0x80);
|
||
} else {
|
||
val[0] |= 0x80;
|
||
}
|
||
} else {
|
||
if (val[0] & 0x80) {
|
||
val.unshift(0x00);
|
||
}
|
||
}
|
||
|
||
return val;
|
||
};
|
||
|
||
/**
|
||
* Parse a signed big integer byte representation.
|
||
*
|
||
* For details on the format please see BigInteger.toByteArraySigned.
|
||
*/
|
||
BigInteger.fromByteArraySigned = function (ba) {
|
||
// Check for negative value
|
||
if (ba[0] & 0x80) {
|
||
// Remove sign bit
|
||
ba[0] &= 0x7f;
|
||
|
||
return BigInteger.fromByteArrayUnsigned(ba).negate();
|
||
} else {
|
||
return BigInteger.fromByteArrayUnsigned(ba);
|
||
}
|
||
};
|
||
// 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 () {
|
||
//---------------------------------------------------------------------
|
||
// 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 QRCode.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 = QRCode.Util.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 = QRCode.Util.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 = QRCode.Util.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 = QRCode.Util.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 = QRCode.Util.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 = QRCode.RSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
|
||
|
||
var buffer = new QRCode.BitBuffer();
|
||
|
||
for (var i = 0; i < dataList.length; i++) {
|
||
var data = dataList[i];
|
||
buffer.put(data.mode, 4);
|
||
buffer.put(data.getLength(), QRCode.Util.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 = QRCode.Util.getErrorCorrectPolynomial(ecCount);
|
||
var rawPoly = new QRCode.Polynomial(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;
|
||
|
||
};
|
||
|
||
//---------------------------------------------------------------------
|
||
// QR8bitByte
|
||
//---------------------------------------------------------------------
|
||
QRCode.QR8bitByte = function (data) {
|
||
this.mode = QRCode.Mode.MODE_8BIT_BYTE;
|
||
this.data = data;
|
||
}
|
||
|
||
QRCode.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);
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
//---------------------------------------------------------------------
|
||
// 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
|
||
//---------------------------------------------------------------------
|
||
|
||
QRCode.Util = {
|
||
|
||
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 (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15) >= 0) {
|
||
d ^= (QRCode.Util.G15 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15)));
|
||
}
|
||
return ((data << 10) | d) ^ QRCode.Util.G15_MASK;
|
||
},
|
||
|
||
getBCHTypeNumber: function (data) {
|
||
var d = data << 12;
|
||
while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18) >= 0) {
|
||
d ^= (QRCode.Util.G18 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18)));
|
||
}
|
||
return (data << 12) | d;
|
||
},
|
||
|
||
getBCHDigit: function (data) {
|
||
|
||
var digit = 0;
|
||
|
||
while (data != 0) {
|
||
digit++;
|
||
data >>>= 1;
|
||
}
|
||
|
||
return digit;
|
||
},
|
||
|
||
getPatternPosition: function (typeNumber) {
|
||
return QRCode.Util.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 QRCode.Polynomial([1], 0);
|
||
|
||
for (var i = 0; i < errorCorrectLength; i++) {
|
||
a = a.multiply(new QRCode.Polynomial([1, QRCode.Math.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
|
||
//---------------------------------------------------------------------
|
||
|
||
QRCode.Math = {
|
||
|
||
glog: function (n) {
|
||
|
||
if (n < 1) {
|
||
throw new Error("glog(" + n + ")");
|
||
}
|
||
|
||
return QRCode.Math.LOG_TABLE[n];
|
||
},
|
||
|
||
gexp: function (n) {
|
||
|
||
while (n < 0) {
|
||
n += 255;
|
||
}
|
||
|
||
while (n >= 256) {
|
||
n -= 255;
|
||
}
|
||
|
||
return QRCode.Math.EXP_TABLE[n];
|
||
},
|
||
|
||
EXP_TABLE: new Array(256),
|
||
|
||
LOG_TABLE: new Array(256)
|
||
|
||
};
|
||
|
||
for (var i = 0; i < 8; i++) {
|
||
QRCode.Math.EXP_TABLE[i] = 1 << i;
|
||
}
|
||
for (var i = 8; i < 256; i++) {
|
||
QRCode.Math.EXP_TABLE[i] = QRCode.Math.EXP_TABLE[i - 4]
|
||
^ QRCode.Math.EXP_TABLE[i - 5]
|
||
^ QRCode.Math.EXP_TABLE[i - 6]
|
||
^ QRCode.Math.EXP_TABLE[i - 8];
|
||
}
|
||
for (var i = 0; i < 255; i++) {
|
||
QRCode.Math.LOG_TABLE[QRCode.Math.EXP_TABLE[i]] = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------
|
||
// QRPolynomial
|
||
//---------------------------------------------------------------------
|
||
|
||
QRCode.Polynomial = function (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];
|
||
}
|
||
}
|
||
|
||
QRCode.Polynomial.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] ^= QRCode.Math.gexp(QRCode.Math.glog(this.get(i)) + QRCode.Math.glog(e.get(j)));
|
||
}
|
||
}
|
||
|
||
return new QRCode.Polynomial(num, 0);
|
||
},
|
||
|
||
mod: function (e) {
|
||
|
||
if (this.getLength() - e.getLength() < 0) {
|
||
return this;
|
||
}
|
||
|
||
var ratio = QRCode.Math.glog(this.get(0)) - QRCode.Math.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] ^= QRCode.Math.gexp(QRCode.Math.glog(e.get(i)) + ratio);
|
||
}
|
||
|
||
// recursive call
|
||
return new QRCode.Polynomial(num, 0).mod(e);
|
||
}
|
||
};
|
||
|
||
//---------------------------------------------------------------------
|
||
// QRRSBlock
|
||
//---------------------------------------------------------------------
|
||
|
||
QRCode.RSBlock = function (totalCount, dataCount) {
|
||
this.totalCount = totalCount;
|
||
this.dataCount = dataCount;
|
||
}
|
||
|
||
QRCode.RSBlock.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]
|
||
|
||
];
|
||
|
||
QRCode.RSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
|
||
|
||
var rsBlock = QRCode.RSBlock.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 QRCode.RSBlock(totalCount, dataCount));
|
||
}
|
||
}
|
||
|
||
return list;
|
||
};
|
||
|
||
QRCode.RSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
|
||
|
||
switch (errorCorrectLevel) {
|
||
case QRCode.ErrorCorrectLevel.L:
|
||
return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
|
||
case QRCode.ErrorCorrectLevel.M:
|
||
return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
|
||
case QRCode.ErrorCorrectLevel.Q:
|
||
return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
|
||
case QRCode.ErrorCorrectLevel.H:
|
||
return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
|
||
default:
|
||
return undefined;
|
||
}
|
||
};
|
||
|
||
//---------------------------------------------------------------------
|
||
// QRBitBuffer
|
||
//---------------------------------------------------------------------
|
||
|
||
QRCode.BitBuffer = function () {
|
||
this.buffer = new Array();
|
||
this.length = 0;
|
||
}
|
||
|
||
QRCode.BitBuffer.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">
|
||
/*
|
||
Copyright (c) 2011 Stefan Thomas
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
*/
|
||
|
||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/1a7fc9d063f864058809d06ef4542af40be3558f/src/bitcoin.js
|
||
(function (exports) {
|
||
var Bitcoin = exports;
|
||
})(
|
||
'object' === typeof module ? module.exports : (window.Bitcoin = {})
|
||
);
|
||
</script>
|
||
<script type="text/javascript">
|
||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/c952aaeb3ee472e3776655b8ea07299ebed702c7/src/base58.js
|
||
(function (Bitcoin) {
|
||
Bitcoin.Base58 = {
|
||
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
||
validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/,
|
||
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;
|
||
}
|
||
|
||
return chars.join('');
|
||
},
|
||
|
||
/**
|
||
* 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) {
|
||
var bi = BigInteger.valueOf(0);
|
||
var leadingZerosNum = 0;
|
||
for (var i = input.length - 1; i >= 0; i--) {
|
||
var alphaIndex = B58.alphabet.indexOf(input[i]);
|
||
if (alphaIndex < 0) {
|
||
throw "Invalid character";
|
||
}
|
||
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;
|
||
}
|
||
};
|
||
|
||
var B58 = Bitcoin.Base58;
|
||
})(
|
||
'undefined' != typeof Bitcoin ? Bitcoin : module.exports
|
||
);
|
||
</script>
|
||
<script type="text/javascript">
|
||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/address.js
|
||
Bitcoin.Address = function (bytes) {
|
||
if ("string" == typeof bytes) {
|
||
bytes = Bitcoin.Address.decodeString(bytes);
|
||
}
|
||
this.hash = bytes;
|
||
this.version = Bitcoin.Address.networkVersion;
|
||
};
|
||
|
||
Bitcoin.Address.networkVersion = 0x00; // mainnet
|
||
|
||
/**
|
||
* Serialize this object as a standard Bitcoin address.
|
||
*
|
||
* Returns the address as a base58-encoded string in the standardized format.
|
||
*/
|
||
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);
|
||
};
|
||
|
||
/**
|
||
* Parse a Bitcoin address contained in a string.
|
||
*/
|
||
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;
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/e90780d3d3b8fc0d027d2bcb38b80479902f223e/src/ecdsa.js
|
||
Bitcoin.ECDSA = (function () {
|
||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||
var rng = new SecureRandom();
|
||
|
||
var P_OVER_FOUR = null;
|
||
|
||
function implShamirsTrick(P, k, Q, l) {
|
||
var m = Math.max(k.bitLength(), l.bitLength());
|
||
var Z = P.add2D(Q);
|
||
var R = P.curve.getInfinity();
|
||
|
||
for (var i = m - 1; i >= 0; --i) {
|
||
R = R.twice2D();
|
||
|
||
R.z = BigInteger.ONE;
|
||
|
||
if (k.testBit(i)) {
|
||
if (l.testBit(i)) {
|
||
R = R.add2D(Z);
|
||
} else {
|
||
R = R.add2D(P);
|
||
}
|
||
} else {
|
||
if (l.testBit(i)) {
|
||
R = R.add2D(Q);
|
||
}
|
||
}
|
||
}
|
||
|
||
return R;
|
||
};
|
||
|
||
var ECDSA = {
|
||
getBigRandom: function (limit) {
|
||
return new BigInteger(limit.bitLength(), rng)
|
||
.mod(limit.subtract(BigInteger.ONE))
|
||
.add(BigInteger.ONE);
|
||
},
|
||
sign: function (hash, priv) {
|
||
var d = priv;
|
||
var n = ecparams.getN();
|
||
var e = BigInteger.fromByteArrayUnsigned(hash);
|
||
|
||
do {
|
||
var k = ECDSA.getBigRandom(n);
|
||
var G = ecparams.getG();
|
||
var Q = G.multiply(k);
|
||
var r = Q.getX().toBigInteger().mod(n);
|
||
} while (r.compareTo(BigInteger.ZERO) <= 0);
|
||
|
||
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
|
||
|
||
return ECDSA.serializeSig(r, s);
|
||
},
|
||
|
||
verify: function (hash, sig, pubkey) {
|
||
var r, s;
|
||
if (Bitcoin.Util.isArray(sig)) {
|
||
var obj = ECDSA.parseSig(sig);
|
||
r = obj.r;
|
||
s = obj.s;
|
||
} else if ("object" === typeof sig && sig.r && sig.s) {
|
||
r = sig.r;
|
||
s = sig.s;
|
||
} else {
|
||
throw "Invalid value for signature";
|
||
}
|
||
|
||
var Q;
|
||
if (pubkey instanceof ec.PointFp) {
|
||
Q = pubkey;
|
||
} else if (Bitcoin.Util.isArray(pubkey)) {
|
||
Q = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), pubkey);
|
||
} else {
|
||
throw "Invalid format for pubkey value, must be byte array or ec.PointFp";
|
||
}
|
||
var e = BigInteger.fromByteArrayUnsigned(hash);
|
||
|
||
return ECDSA.verifyRaw(e, r, s, Q);
|
||
},
|
||
|
||
verifyRaw: function (e, r, s, Q) {
|
||
var n = ecparams.getN();
|
||
var G = ecparams.getG();
|
||
|
||
if (r.compareTo(BigInteger.ONE) < 0 ||
|
||
r.compareTo(n) >= 0)
|
||
return false;
|
||
|
||
if (s.compareTo(BigInteger.ONE) < 0 ||
|
||
s.compareTo(n) >= 0)
|
||
return false;
|
||
|
||
var c = s.modInverse(n);
|
||
|
||
var u1 = e.multiply(c).mod(n);
|
||
var u2 = r.multiply(c).mod(n);
|
||
|
||
// TODO(!!!): For some reason Shamir's trick isn't working with
|
||
// signed message verification!? Probably an implementation
|
||
// error!
|
||
//var point = implShamirsTrick(G, u1, Q, u2);
|
||
var point = G.multiply(u1).add(Q.multiply(u2));
|
||
|
||
var v = point.getX().toBigInteger().mod(n);
|
||
|
||
return v.equals(r);
|
||
},
|
||
|
||
/**
|
||
* Serialize a signature into DER format.
|
||
*
|
||
* Takes two BigIntegers representing r and s and returns a byte array.
|
||
*/
|
||
serializeSig: function (r, s) {
|
||
var rBa = r.toByteArraySigned();
|
||
var sBa = s.toByteArraySigned();
|
||
|
||
var sequence = [];
|
||
sequence.push(0x02); // INTEGER
|
||
sequence.push(rBa.length);
|
||
sequence = sequence.concat(rBa);
|
||
|
||
sequence.push(0x02); // INTEGER
|
||
sequence.push(sBa.length);
|
||
sequence = sequence.concat(sBa);
|
||
|
||
sequence.unshift(sequence.length);
|
||
sequence.unshift(0x30); // SEQUENCE
|
||
|
||
return sequence;
|
||
},
|
||
|
||
/**
|
||
* Parses a byte array containing a DER-encoded signature.
|
||
*
|
||
* This function will return an object of the form:
|
||
*
|
||
* {
|
||
* r: BigInteger,
|
||
* s: BigInteger
|
||
* }
|
||
*/
|
||
parseSig: function (sig) {
|
||
var cursor;
|
||
if (sig[0] != 0x30)
|
||
throw new Error("Signature not a valid DERSequence");
|
||
|
||
cursor = 2;
|
||
if (sig[cursor] != 0x02)
|
||
throw new Error("First element in signature must be a DERInteger"); ;
|
||
var rBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
|
||
|
||
cursor += 2 + sig[cursor + 1];
|
||
if (sig[cursor] != 0x02)
|
||
throw new Error("Second element in signature must be a DERInteger");
|
||
var sBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
|
||
|
||
cursor += 2 + sig[cursor + 1];
|
||
|
||
//if (cursor != sig.length)
|
||
// throw new Error("Extra bytes in signature");
|
||
|
||
var r = BigInteger.fromByteArrayUnsigned(rBa);
|
||
var s = BigInteger.fromByteArrayUnsigned(sBa);
|
||
|
||
return { r: r, s: s };
|
||
},
|
||
|
||
parseSigCompact: function (sig) {
|
||
if (sig.length !== 65) {
|
||
throw "Signature has the wrong length";
|
||
}
|
||
|
||
// Signature is prefixed with a type byte storing three bits of
|
||
// information.
|
||
var i = sig[0] - 27;
|
||
if (i < 0 || i > 7) {
|
||
throw "Invalid signature type";
|
||
}
|
||
|
||
var n = ecparams.getN();
|
||
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
|
||
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
|
||
|
||
return { r: r, s: s, i: i };
|
||
},
|
||
|
||
/**
|
||
* Recover a public key from a signature.
|
||
*
|
||
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
|
||
* Key Recovery Operation".
|
||
*
|
||
* http://www.secg.org/download/aid-780/sec1-v2.pdf
|
||
*/
|
||
recoverPubKey: function (r, s, hash, i) {
|
||
// The recovery parameter i has two bits.
|
||
i = i & 3;
|
||
|
||
// The less significant bit specifies whether the y coordinate
|
||
// of the compressed point is even or not.
|
||
var isYEven = i & 1;
|
||
|
||
// The more significant bit specifies whether we should use the
|
||
// first or second candidate key.
|
||
var isSecondKey = i >> 1;
|
||
|
||
var n = ecparams.getN();
|
||
var G = ecparams.getG();
|
||
var curve = ecparams.getCurve();
|
||
var p = curve.getQ();
|
||
var a = curve.getA().toBigInteger();
|
||
var b = curve.getB().toBigInteger();
|
||
|
||
// We precalculate (p + 1) / 4 where p is if the field order
|
||
if (!P_OVER_FOUR) {
|
||
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
|
||
}
|
||
|
||
// 1.1 Compute x
|
||
var x = isSecondKey ? r.add(n) : r;
|
||
|
||
// 1.3 Convert x to point
|
||
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
|
||
var beta = alpha.modPow(P_OVER_FOUR, p);
|
||
|
||
var xorOdd = beta.isEven() ? (i % 2) : ((i + 1) % 2);
|
||
// If beta is even, but y isn't or vice versa, then convert it,
|
||
// otherwise we're done and y == beta.
|
||
var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
|
||
|
||
// 1.4 Check that nR is at infinity
|
||
var R = new EllipticCurve.PointFp(curve,
|
||
curve.fromBigInteger(x),
|
||
curve.fromBigInteger(y));
|
||
R.validate();
|
||
|
||
// 1.5 Compute e from M
|
||
var e = BigInteger.fromByteArrayUnsigned(hash);
|
||
var eNeg = BigInteger.ZERO.subtract(e).mod(n);
|
||
|
||
// 1.6 Compute Q = r^-1 (sR - eG)
|
||
var rInv = r.modInverse(n);
|
||
var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
|
||
|
||
Q.validate();
|
||
if (!ECDSA.verifyRaw(e, r, s, Q)) {
|
||
throw "Pubkey recovery unsuccessful";
|
||
}
|
||
|
||
var pubKey = new Bitcoin.ECKey();
|
||
pubKey.pub = Q;
|
||
return pubKey;
|
||
},
|
||
|
||
/**
|
||
* Calculate pubkey extraction parameter.
|
||
*
|
||
* When extracting a pubkey from a signature, we have to
|
||
* distinguish four different cases. Rather than putting this
|
||
* burden on the verifier, Bitcoin includes a 2-bit value with the
|
||
* signature.
|
||
*
|
||
* This function simply tries all four cases and returns the value
|
||
* that resulted in a successful pubkey recovery.
|
||
*/
|
||
calcPubkeyRecoveryParam: function (address, r, s, hash) {
|
||
for (var i = 0; i < 4; i++) {
|
||
try {
|
||
var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
|
||
if (pubkey.getBitcoinAddress().toString() == address) {
|
||
return i;
|
||
}
|
||
} catch (e) { }
|
||
}
|
||
throw "Unable to find valid recovery factor";
|
||
}
|
||
};
|
||
|
||
return ECDSA;
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
//https://raw.github.com/pointbiz/bitcoinjs-lib/9b2f94a028a7bc9bed94e0722563e9ff1d8e8db8/src/eckey.js
|
||
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) {
|
||
var bytes = null;
|
||
if (ECKey.isWalletImportFormat(input)) {
|
||
bytes = ECKey.decodeWalletImportFormat(input);
|
||
} else if (ECKey.isCompressedWalletImportFormat(input)) {
|
||
bytes = ECKey.decodeCompressedWalletImportFormat(input);
|
||
this.compressed = true;
|
||
} else if (ECKey.isMiniFormat(input)) {
|
||
bytes = Crypto.SHA256(input, { asBytes: true });
|
||
} else if (ECKey.isHexFormat(input)) {
|
||
bytes = Crypto.util.hexToBytes(input);
|
||
} else if (ECKey.isBase64Format(input)) {
|
||
bytes = Crypto.util.base64ToBytes(input);
|
||
}
|
||
|
||
if (bytes == null || bytes.length != 32) {
|
||
this.priv = null;
|
||
} else {
|
||
// Prepend zero byte to prevent interpretation as negative integer
|
||
this.priv = BigInteger.fromByteArrayUnsigned(bytes);
|
||
}
|
||
}
|
||
|
||
this.compressed = (this.compressed == undefined) ? !!ECKey.compressByDefault : this.compressed;
|
||
};
|
||
|
||
ECKey.privateKeyPrefix = 0x80; // mainnet 0x80 testnet 0xEF
|
||
|
||
/**
|
||
* Whether public keys should be returned compressed by default.
|
||
*/
|
||
ECKey.compressByDefault = false;
|
||
|
||
/**
|
||
* Set whether the public key should be returned compressed or not.
|
||
*/
|
||
ECKey.prototype.setCompressed = function (v) {
|
||
this.compressed = !!v;
|
||
if (this.pubPoint) this.pubPoint.compressed = this.compressed;
|
||
return this;
|
||
};
|
||
|
||
/*
|
||
* Return public key as a byte array in DER encoding
|
||
*/
|
||
ECKey.prototype.getPub = function () {
|
||
if (this.compressed) {
|
||
if (this.pubComp) return this.pubComp;
|
||
return this.pubComp = this.getPubPoint().getEncoded(1);
|
||
} else {
|
||
if (this.pubUncomp) return this.pubUncomp;
|
||
return this.pubUncomp = this.getPubPoint().getEncoded(0);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Return public point as ECPoint object.
|
||
*/
|
||
ECKey.prototype.getPubPoint = function () {
|
||
if (!this.pubPoint) {
|
||
this.pubPoint = ecparams.getG().multiply(this.priv);
|
||
this.pubPoint.compressed = this.compressed;
|
||
}
|
||
return this.pubPoint;
|
||
};
|
||
|
||
ECKey.prototype.getPubKeyHex = function () {
|
||
if (this.compressed) {
|
||
if (this.pubKeyHexComp) return this.pubKeyHexComp;
|
||
return this.pubKeyHexComp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
|
||
} else {
|
||
if (this.pubKeyHexUncomp) return this.pubKeyHexUncomp;
|
||
return this.pubKeyHexUncomp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Get the pubKeyHash for this key.
|
||
*
|
||
* This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
|
||
* a byte array.
|
||
*/
|
||
ECKey.prototype.getPubKeyHash = function () {
|
||
if (this.compressed) {
|
||
if (this.pubKeyHashComp) return this.pubKeyHashComp;
|
||
return this.pubKeyHashComp = Bitcoin.Util.sha256ripe160(this.getPub());
|
||
} else {
|
||
if (this.pubKeyHashUncomp) return this.pubKeyHashUncomp;
|
||
return this.pubKeyHashUncomp = Bitcoin.Util.sha256ripe160(this.getPub());
|
||
}
|
||
};
|
||
|
||
ECKey.prototype.getBitcoinAddress = function () {
|
||
var hash = this.getPubKeyHash();
|
||
var addr = new Bitcoin.Address(hash);
|
||
return addr.toString();
|
||
};
|
||
|
||
/*
|
||
* Takes a public point as a hex string or byte array
|
||
*/
|
||
ECKey.prototype.setPub = function (pub) {
|
||
// byte array
|
||
if (Bitcoin.Util.isArray(pub)) {
|
||
pub = Crypto.util.bytesToHex(pub).toString().toUpperCase();
|
||
}
|
||
var ecPoint = ecparams.getCurve().decodePointHex(pub);
|
||
this.setCompressed(ecPoint.compressed);
|
||
this.pubPoint = ecPoint;
|
||
return this;
|
||
};
|
||
|
||
// Sipa Private Key Wallet Import Format
|
||
ECKey.prototype.getBitcoinWalletImportFormat = function () {
|
||
var bytes = this.getBitcoinPrivateKeyByteArray();
|
||
bytes.unshift(ECKey.privateKeyPrefix); // prepend 0x80 byte
|
||
if (this.compressed) bytes.push(0x01); // append 0x01 byte for compressed format
|
||
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;
|
||
};
|
||
|
||
// Private Key Hex Format
|
||
ECKey.prototype.getBitcoinHexFormat = function () {
|
||
return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase();
|
||
};
|
||
|
||
// Private Key Base64 Format
|
||
ECKey.prototype.getBitcoinBase64Format = function () {
|
||
return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray());
|
||
};
|
||
|
||
ECKey.prototype.getBitcoinPrivateKeyByteArray = 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
|
||
while (bytes.length < 32) bytes.unshift(0x00);
|
||
return bytes;
|
||
};
|
||
|
||
ECKey.prototype.toString = function (format) {
|
||
format = format || "";
|
||
if (format.toString().toLowerCase() == "base64" || format.toString().toLowerCase() == "b64") {
|
||
return this.getBitcoinBase64Format();
|
||
}
|
||
// Wallet Import Format
|
||
else if (format.toString().toLowerCase() == "wif") {
|
||
return this.getBitcoinWalletImportFormat();
|
||
}
|
||
else {
|
||
return this.getBitcoinHexFormat();
|
||
}
|
||
};
|
||
|
||
ECKey.prototype.sign = function (hash) {
|
||
return ECDSA.sign(hash, this.priv);
|
||
};
|
||
|
||
ECKey.prototype.verify = function (hash, sig) {
|
||
return ECDSA.verify(hash, sig, this.getPub());
|
||
};
|
||
|
||
/**
|
||
* Parse a wallet import format private key contained in a string.
|
||
*/
|
||
ECKey.decodeWalletImportFormat = function (privStr) {
|
||
var bytes = Bitcoin.Base58.decode(privStr);
|
||
var hash = bytes.slice(0, 33);
|
||
var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
|
||
if (checksum[0] != bytes[33] ||
|
||
checksum[1] != bytes[34] ||
|
||
checksum[2] != bytes[35] ||
|
||
checksum[3] != bytes[36]) {
|
||
throw "Checksum validation failed!";
|
||
}
|
||
var version = hash.shift();
|
||
if (version != ECKey.privateKeyPrefix) {
|
||
throw "Version " + version + " not supported!";
|
||
}
|
||
return hash;
|
||
};
|
||
|
||
/**
|
||
* Parse a compressed wallet import format private key contained in a string.
|
||
*/
|
||
ECKey.decodeCompressedWalletImportFormat = function (privStr) {
|
||
var bytes = Bitcoin.Base58.decode(privStr);
|
||
var hash = bytes.slice(0, 34);
|
||
var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
|
||
if (checksum[0] != bytes[34] ||
|
||
checksum[1] != bytes[35] ||
|
||
checksum[2] != bytes[36] ||
|
||
checksum[3] != bytes[37]) {
|
||
throw "Checksum validation failed!";
|
||
}
|
||
var version = hash.shift();
|
||
if (version != ECKey.privateKeyPrefix) {
|
||
throw "Version " + version + " not supported!";
|
||
}
|
||
hash.pop();
|
||
return hash;
|
||
};
|
||
|
||
// 64 characters [0-9A-F]
|
||
ECKey.isHexFormat = function (key) {
|
||
key = key.toString();
|
||
return /^[A-Fa-f0-9]{64}$/.test(key);
|
||
};
|
||
|
||
// 51 characters base58, always starts with a '5'
|
||
ECKey.isWalletImportFormat = function (key) {
|
||
key = key.toString();
|
||
return (ECKey.privateKeyPrefix == 0x80) ?
|
||
(/^5[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key)) :
|
||
(/^9[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key));
|
||
};
|
||
|
||
// 52 characters base58
|
||
ECKey.isCompressedWalletImportFormat = function (key) {
|
||
key = key.toString();
|
||
return (ECKey.privateKeyPrefix == 0x80) ?
|
||
(/^[LK][123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key)) :
|
||
(/^c[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key));
|
||
};
|
||
|
||
// 44 characters
|
||
ECKey.isBase64Format = function (key) {
|
||
key = key.toString();
|
||
return (/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key));
|
||
};
|
||
|
||
// 22, 26 or 30 characters, always starts with an 'S'
|
||
ECKey.isMiniFormat = function (key) {
|
||
key = key.toString();
|
||
var validChars22 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key);
|
||
var validChars26 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key);
|
||
var validChars30 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key);
|
||
var testBytes = Crypto.SHA256(key + "?", { asBytes: true });
|
||
|
||
return ((testBytes[0] === 0x00 || testBytes[0] === 0x01) && (validChars22 || validChars26 || validChars30));
|
||
};
|
||
|
||
return ECKey;
|
||
})();
|
||
</script>
|
||
<script type="text/javascript">
|
||
//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/util.js
|
||
// Bitcoin utility functions
|
||
Bitcoin.Util = {
|
||
/**
|
||
* Cross-browser compatibility version of Array.isArray.
|
||
*/
|
||
isArray: Array.isArray || function (o) {
|
||
return Object.prototype.toString.call(o) === '[object Array]';
|
||
},
|
||
/**
|
||
* Create an array of a certain length filled with a specific value.
|
||
*/
|
||
makeFilledArray: function (len, val) {
|
||
var array = [];
|
||
var i = 0;
|
||
while (i < len) {
|
||
array[i++] = val;
|
||
}
|
||
return array;
|
||
},
|
||
/**
|
||
* Turn an integer into a "var_int".
|
||
*
|
||
* "var_int" is a variable length integer used by Bitcoin's binary format.
|
||
*
|
||
* Returns a byte array.
|
||
*/
|
||
numToVarInt: function (i) {
|
||
if (i < 0xfd) {
|
||
// unsigned char
|
||
return [i];
|
||
} else if (i <= 1 << 16) {
|
||
// unsigned short (LE)
|
||
return [0xfd, i >>> 8, i & 255];
|
||
} else if (i <= 1 << 32) {
|
||
// unsigned int (LE)
|
||
return [0xfe].concat(Crypto.util.wordsToBytes([i]));
|
||
} else {
|
||
// unsigned long long (LE)
|
||
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
|
||
}
|
||
},
|
||
/**
|
||
* Parse a Bitcoin value byte array, returning a BigInteger.
|
||
*/
|
||
valueToBigInt: function (valueBuffer) {
|
||
if (valueBuffer instanceof BigInteger) return valueBuffer;
|
||
|
||
// Prepend zero byte to prevent interpretation as negative integer
|
||
return BigInteger.fromByteArrayUnsigned(valueBuffer);
|
||
},
|
||
/**
|
||
* Format a Bitcoin value as a string.
|
||
*
|
||
* Takes a BigInteger or byte-array and returns that amount of Bitcoins in a
|
||
* nice standard formatting.
|
||
*
|
||
* Examples:
|
||
* 12.3555
|
||
* 0.1234
|
||
* 900.99998888
|
||
* 34.00
|
||
*/
|
||
formatValue: function (valueBuffer) {
|
||
var value = this.valueToBigInt(valueBuffer).toString();
|
||
var integerPart = value.length > 8 ? value.substr(0, value.length - 8) : '0';
|
||
var decimalPart = value.length > 8 ? value.substr(value.length - 8) : value;
|
||
while (decimalPart.length < 8) decimalPart = "0" + decimalPart;
|
||
decimalPart = decimalPart.replace(/0*$/, '');
|
||
while (decimalPart.length < 2) decimalPart += "0";
|
||
return integerPart + "." + decimalPart;
|
||
},
|
||
/**
|
||
* Parse a floating point string as a Bitcoin value.
|
||
*
|
||
* Keep in mind that parsing user input is messy. You should always display
|
||
* the parsed value back to the user to make sure we understood his input
|
||
* correctly.
|
||
*/
|
||
parseValue: function (valueString) {
|
||
// TODO: Detect other number formats (e.g. comma as decimal separator)
|
||
var valueComp = valueString.split('.');
|
||
var integralPart = valueComp[0];
|
||
var fractionalPart = valueComp[1] || "0";
|
||
while (fractionalPart.length < 8) fractionalPart += "0";
|
||
fractionalPart = fractionalPart.replace(/^0+/g, '');
|
||
var value = BigInteger.valueOf(parseInt(integralPart));
|
||
value = value.multiply(BigInteger.valueOf(100000000));
|
||
value = value.add(BigInteger.valueOf(parseInt(fractionalPart)));
|
||
return value;
|
||
},
|
||
/**
|
||
* Calculate RIPEMD160(SHA256(data)).
|
||
*
|
||
* Takes an arbitrary byte array as inputs and returns the hash as a byte
|
||
* array.
|
||
*/
|
||
sha256ripe160: function (data) {
|
||
return Crypto.RIPEMD160(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
|
||
},
|
||
// double sha256
|
||
dsha256: function (data) {
|
||
return Crypto.SHA256(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
/*
|
||
* Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
* of this software and associated documentation files (the "Software"), to deal
|
||
* in the Software without restriction, including without limitation the rights
|
||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
* copies of the Software, and to permit persons to whom the Software is
|
||
* furnished to do so, subject to the following conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be included in
|
||
* all copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
* THE SOFTWARE.
|
||
*/
|
||
// https://github.com/cheongwy/node-scrypt-js
|
||
(function () {
|
||
|
||
var MAX_VALUE = 2147483647;
|
||
var workerUrl = null;
|
||
|
||
//function scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen)
|
||
/*
|
||
* N = Cpu cost
|
||
* r = Memory cost
|
||
* p = parallelization cost
|
||
*
|
||
*/
|
||
window.Crypto_scrypt = function (passwd, salt, N, r, p, dkLen, callback) {
|
||
if (N == 0 || (N & (N - 1)) != 0) throw Error("N must be > 0 and a power of 2");
|
||
|
||
if (N > MAX_VALUE / 128 / r) throw Error("Parameter N is too large");
|
||
if (r > MAX_VALUE / 128 / p) throw Error("Parameter r is too large");
|
||
|
||
var PBKDF2_opts = { iterations: 1, hasher: Crypto.SHA256, asBytes: true };
|
||
|
||
var B = Crypto.PBKDF2(passwd, salt, p * 128 * r, PBKDF2_opts);
|
||
|
||
try {
|
||
var i = 0;
|
||
var worksDone = 0;
|
||
var makeWorker = function () {
|
||
if (!workerUrl) {
|
||
var code = '(' + scryptCore.toString() + ')()';
|
||
var blob;
|
||
try {
|
||
blob = new Blob([code], { type: "text/javascript" });
|
||
} catch (e) {
|
||
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
||
blob = new BlobBuilder();
|
||
blob.append(code);
|
||
blob = blob.getBlob("text/javascript");
|
||
}
|
||
workerUrl = URL.createObjectURL(blob);
|
||
}
|
||
var worker = new Worker(workerUrl);
|
||
worker.onmessage = function (event) {
|
||
var Bi = event.data[0], Bslice = event.data[1];
|
||
worksDone++;
|
||
|
||
if (i < p) {
|
||
worker.postMessage([N, r, p, B, i++]);
|
||
}
|
||
|
||
var length = Bslice.length, destPos = Bi * 128 * r, srcPos = 0;
|
||
while (length--) {
|
||
B[destPos++] = Bslice[srcPos++];
|
||
}
|
||
|
||
if (worksDone == p) {
|
||
callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
|
||
}
|
||
};
|
||
return worker;
|
||
};
|
||
var workers = [makeWorker(), makeWorker()];
|
||
workers[0].postMessage([N, r, p, B, i++]);
|
||
if (p > 1) {
|
||
workers[1].postMessage([N, r, p, B, i++]);
|
||
}
|
||
} catch (e) {
|
||
window.setTimeout(function () {
|
||
scryptCore();
|
||
callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
|
||
}, 0);
|
||
}
|
||
|
||
// using this function to enclose everything needed to create a worker (but also invokable directly for synchronous use)
|
||
function scryptCore() {
|
||
var XY = [], V = [];
|
||
|
||
if (typeof B === 'undefined') {
|
||
onmessage = function (event) {
|
||
var data = event.data;
|
||
var N = data[0], r = data[1], p = data[2], B = data[3], i = data[4];
|
||
|
||
var Bslice = [];
|
||
arraycopy32(B, i * 128 * r, Bslice, 0, 128 * r);
|
||
smix(Bslice, 0, r, N, V, XY);
|
||
|
||
postMessage([i, Bslice]);
|
||
};
|
||
} else {
|
||
for (var i = 0; i < p; i++) {
|
||
smix(B, i * 128 * r, r, N, V, XY);
|
||
}
|
||
}
|
||
|
||
function smix(B, Bi, r, N, V, XY) {
|
||
var Xi = 0;
|
||
var Yi = 128 * r;
|
||
var i;
|
||
|
||
arraycopy32(B, Bi, XY, Xi, Yi);
|
||
|
||
for (i = 0; i < N; i++) {
|
||
arraycopy32(XY, Xi, V, i * Yi, Yi);
|
||
blockmix_salsa8(XY, Xi, Yi, r);
|
||
}
|
||
|
||
for (i = 0; i < N; i++) {
|
||
var j = integerify(XY, Xi, r) & (N - 1);
|
||
blockxor(V, j * Yi, XY, Xi, Yi);
|
||
blockmix_salsa8(XY, Xi, Yi, r);
|
||
}
|
||
|
||
arraycopy32(XY, Xi, B, Bi, Yi);
|
||
}
|
||
|
||
function blockmix_salsa8(BY, Bi, Yi, r) {
|
||
var X = [];
|
||
var i;
|
||
|
||
arraycopy32(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
|
||
|
||
for (i = 0; i < 2 * r; i++) {
|
||
blockxor(BY, i * 64, X, 0, 64);
|
||
salsa20_8(X);
|
||
arraycopy32(X, 0, BY, Yi + (i * 64), 64);
|
||
}
|
||
|
||
for (i = 0; i < r; i++) {
|
||
arraycopy32(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
|
||
}
|
||
|
||
for (i = 0; i < r; i++) {
|
||
arraycopy32(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
|
||
}
|
||
}
|
||
|
||
function R(a, b) {
|
||
return (a << b) | (a >>> (32 - b));
|
||
}
|
||
|
||
function salsa20_8(B) {
|
||
var B32 = new Array(32);
|
||
var x = new Array(32);
|
||
var i;
|
||
|
||
for (i = 0; i < 16; i++) {
|
||
B32[i] = (B[i * 4 + 0] & 0xff) << 0;
|
||
B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
|
||
B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
|
||
B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
|
||
}
|
||
|
||
arraycopy(B32, 0, x, 0, 16);
|
||
|
||
for (i = 8; i > 0; i -= 2) {
|
||
x[4] ^= R(x[0] + x[12], 7); x[8] ^= R(x[4] + x[0], 9);
|
||
x[12] ^= R(x[8] + x[4], 13); x[0] ^= R(x[12] + x[8], 18);
|
||
x[9] ^= R(x[5] + x[1], 7); x[13] ^= R(x[9] + x[5], 9);
|
||
x[1] ^= R(x[13] + x[9], 13); x[5] ^= R(x[1] + x[13], 18);
|
||
x[14] ^= R(x[10] + x[6], 7); x[2] ^= R(x[14] + x[10], 9);
|
||
x[6] ^= R(x[2] + x[14], 13); x[10] ^= R(x[6] + x[2], 18);
|
||
x[3] ^= R(x[15] + x[11], 7); x[7] ^= R(x[3] + x[15], 9);
|
||
x[11] ^= R(x[7] + x[3], 13); x[15] ^= R(x[11] + x[7], 18);
|
||
x[1] ^= R(x[0] + x[3], 7); x[2] ^= R(x[1] + x[0], 9);
|
||
x[3] ^= R(x[2] + x[1], 13); x[0] ^= R(x[3] + x[2], 18);
|
||
x[6] ^= R(x[5] + x[4], 7); x[7] ^= R(x[6] + x[5], 9);
|
||
x[4] ^= R(x[7] + x[6], 13); x[5] ^= R(x[4] + x[7], 18);
|
||
x[11] ^= R(x[10] + x[9], 7); x[8] ^= R(x[11] + x[10], 9);
|
||
x[9] ^= R(x[8] + x[11], 13); x[10] ^= R(x[9] + x[8], 18);
|
||
x[12] ^= R(x[15] + x[14], 7); x[13] ^= R(x[12] + x[15], 9);
|
||
x[14] ^= R(x[13] + x[12], 13); x[15] ^= R(x[14] + x[13], 18);
|
||
}
|
||
|
||
for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
|
||
|
||
for (i = 0; i < 16; i++) {
|
||
var bi = i * 4;
|
||
B[bi + 0] = (B32[i] >> 0 & 0xff);
|
||
B[bi + 1] = (B32[i] >> 8 & 0xff);
|
||
B[bi + 2] = (B32[i] >> 16 & 0xff);
|
||
B[bi + 3] = (B32[i] >> 24 & 0xff);
|
||
}
|
||
}
|
||
|
||
function blockxor(S, Si, D, Di, len) {
|
||
var i = len >> 6;
|
||
while (i--) {
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
||
}
|
||
}
|
||
|
||
function integerify(B, bi, r) {
|
||
var n;
|
||
|
||
bi += (2 * r - 1) * 64;
|
||
|
||
n = (B[bi + 0] & 0xff) << 0;
|
||
n |= (B[bi + 1] & 0xff) << 8;
|
||
n |= (B[bi + 2] & 0xff) << 16;
|
||
n |= (B[bi + 3] & 0xff) << 24;
|
||
|
||
return n;
|
||
}
|
||
|
||
function arraycopy(src, srcPos, dest, destPos, length) {
|
||
while (length--) {
|
||
dest[destPos++] = src[srcPos++];
|
||
}
|
||
}
|
||
|
||
function arraycopy32(src, srcPos, dest, destPos, length) {
|
||
var i = length >> 5;
|
||
while (i--) {
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
||
}
|
||
}
|
||
} // scryptCore
|
||
}; // window.Crypto_scrypt
|
||
})();
|
||
</script>
|
||
<style type="text/css">
|
||
.more { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAWdEVYdENyZWF0aW9uIFRpbWUAMDEvMDIvMTLltnQyAAAB1UlEQVQ4jYWTS04bQRCGv3q0x8gMYJCwknCGLDgLVwiH4grhLFaUXdhkQ0A8pBg/FOLpnmbhMYzxRKlNS1Vdf/31V5XknGnb+eXJCBjzbzu9OLu+azu845Opysej4wHmshF4uJ2TUrb3CV0gIBAKRboC5C2vdkDE9fdty6/xDegvXz+NgDbFUejZ+PjDgExmtpxS9vYwMe5u5iyX8RRoa5Ic+C4qx9KUN1MGu4E618yqJ5axAp44KA7ZL3eYzp/HKdVIw7WK8d6BuDvcod9TQlBEIOXEdPlElSoUJabIIs4Z7h9yNDwgqOMayLXw7epHVIBggrsgspZPUBQyiCgugRQji7TAVDF1XB2TlQoOYCqovkmpopS9fcoiM3ue0rOCYf8IU8NklWxiiOQ3EPXtWagIqo6KYWYEc4IGvMViA6RrnCJKVS9B8ypRHG1YKNa0Ur+C+MPt/I2BKWVZUO4FgvQ47PcptEDF+T2Z8TiZUMWIyGtpd+Bze5VTSqP57O/4YG+AN/RXbSiPkwmL5z/be/L+mM4vT2JKeUW7EXD1erMz/Lo4u77f0K9DDhdA1XG11jh9vWBb99Z9gAg5QZ2hzpmUa0RSW4f/gqSY0s3Vz+tufEjvHS8Tg6BXC7qVbQAAAABJRU5ErkJggg==)
|
||
no-repeat left center; width: 17px; height: 17px; display: inline-block; float: right; }
|
||
.less { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAWdEVYdENyZWF0aW9uIFRpbWUAMDEvMDIvMTLltnQyAAABuklEQVQ4ja2US25TQRBFT336OSEY5ESyBfEakNiLt0AW5S2QvQQxAiZIYBwSz/yByH7dxcB2bPMME+hJS/W5fetWVUtE8K/HfzdcXfdfqsr4onuGuRz4Jrdzcg6Gg9HfQYAxAqmlSMMlQJO5/oliE4AtQLcR++btZQ+wPVsvVXbTfXFGEMyWU9rVM0yMu/Gc5bJ+DdztxWcH3otKVzbPmyq5LnwfzSgEBMxlhqJEBFWVKKUgG66rur53oH7aOeWkUlJSRCBHZracssorlLXttHpCpzonaYukjmsiivDu08daAZIJ7oLIVg9BUQgQUVwSua5Z5AWmiqnj6pisVXAAU0F1J6WK0q6e024Fs4cplbXonFxgapisk00MkdiBqDd7oSKoOiqGmZHMSZrwPRYHIMfaKaKsyhI01oni6IaFYptSyiOIT27nOwaq5FyQrUAIC/nBhK+UErRSos55z4878CrneJyTnHOvquymf3mOb+hvy/jw+QuLh5/NORkORvsGrq77dc6xpr0RcH07y3oF8G04GN0f6HdEDhdA1XG1vXb6dsAa+3Z8AREiQwkoEeQoiBzocHDkf/wnvwC5IpRVsUDNUgAAAABJRU5ErkJggg==)
|
||
no-repeat left center; width: 17px; height: 17px; display: inline-block; float: right; }
|
||
.right { text-align: right; }
|
||
.walletarea { display: none; border: 2px solid green; }
|
||
.keyarea { font-family: Courier New; height: 110px; text-align: left; position: relative; padding: 5px; }
|
||
.keyarea .public { float: left; }
|
||
.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 20px 0 0; position: relative; }
|
||
.keyarea .label { text-decoration: underline; }
|
||
.keyarea .output { display: block; }
|
||
.keyarea .qrcode_public { display: inline-block; float: left; }
|
||
.keyarea .qrcode_private { display: inline-block; position: relative; top: 28px; float: right; }
|
||
.pubkeyhex { word-wrap: break-word; }
|
||
.faqs ol { padding: 0 0 0 25px; }
|
||
.faqs li { padding: 3px 0; }
|
||
body { font-family: Arial; }
|
||
#main { position: relative; text-align: center; margin: 0px auto; width: 1005px; }
|
||
#logo { width: 578px; height: 80px; }
|
||
#generate { font-family: Courier New; height: 158px; text-align: left; position: relative; padding: 5px; border: 2px solid green; }
|
||
#generate span { padding: 5px 5px 0 5px; }
|
||
#menu { visibility: hidden; font-size: 90%; }
|
||
#culturemenu { text-align: right; padding: 0 20px; }
|
||
#culturemenu span { padding: 3px; }
|
||
#culturemenu .selected { text-decoration: none; color: #000000; }
|
||
|
||
#paperarea { min-height: 120px; display: none; }
|
||
#paperarea .keyarea { border: 2px solid green; border-top: 0; }
|
||
#paperarea .keyarea.art { display: block; height: auto; border: 0; font-family: Ubuntu, Arial; padding: 0; margin: 0; }
|
||
#paperarea .artwallet .papersvg { width: 486px; height: 261px; border: 0; margin: 0; padding: 0; left: 0; }
|
||
#paperarea .artwallet .qrcode_public { top: 52px; left: 17px; z-index: 100; margin: 0; float: none; display: block; position: absolute; background-color: #FFFFFF;
|
||
padding: 5px 5px 2px 5px; }
|
||
#paperarea .artwallet .qrcode_private { top: 104px; left: 360px; z-index: 100; margin: 0; float: none; display: block; position: absolute; background-color: #FFFFFF;
|
||
padding: 5px 5px 2px 5px; }
|
||
#paperarea .artwallet .btcaddress
|
||
{
|
||
position: absolute; top: 240px; left: 139px; z-index: 100; font-size: 10px; background-color: transparent;
|
||
font-weight:bold; color: #000000; margin: 0;
|
||
-webkit-transform-origin:top left; -webkit-transform:rotate(-90deg);
|
||
-moz-transform-origin:top left; -moz-transform:rotate(-90deg);
|
||
-ms-transform-origin:top left; -ms-transform:rotate(-90deg);
|
||
-o-transform-origin:top left; -o-transform:rotate(-90deg);
|
||
transform-origin:top left; transform:rotate(-90deg);
|
||
}
|
||
#paperarea .artwallet .btcprivwif
|
||
{
|
||
position: absolute; top: 236px; left: 346px; z-index: 100; font-size: 7px; background-color: transparent;
|
||
font-weight:bold; color: #000000; margin: 0;
|
||
-webkit-transform-origin:top left; -webkit-transform:rotate(-90deg);
|
||
-moz-transform-origin:top left; -moz-transform:rotate(-90deg);
|
||
-ms-transform-origin:top left; -ms-transform:rotate(-90deg);
|
||
-o-transform-origin:top left; -o-transform:rotate(-90deg);
|
||
transform-origin:top left; transform:rotate(-90deg);
|
||
}
|
||
#bulkarea .body { padding: 5px 0 0 0; }
|
||
#bulkarea .format { font-style: italic; font-size: 90%; }
|
||
#bulktextarea { font-size: 90%; width: 98%; margin: 4px 0 0 0; }
|
||
.bulkquestion { padding: 10px 15px; text-align: left; cursor: pointer; }
|
||
.bulkquestion:hover, .expandable:hover { color: #77777A; }
|
||
.bulkanswer { padding: 0 15px 10px 25px; text-align: left; display: none; font-size: 80%; }
|
||
.bulkfaq { border: 0; border-top: 2px solid green; }
|
||
#brainarea .keyarea { visibility: hidden; min-height: 110px; }
|
||
#detailkeyarea { padding: 10px; }
|
||
#detailarea { margin: 0; text-align: left; }
|
||
#detailarea .notes { text-align: left; font-size: 80%; padding: 0 0 20px 0; }
|
||
#detailarea .pubqr .item .label { text-decoration: none; }
|
||
#detailarea .pubqr .item { float: left; margin: 10px 0; position: relative; }
|
||
#detailarea .pubqr .item.right { float: right; position: relative; top: 0; }
|
||
#detailarea .privqr .item .label { text-decoration: none; }
|
||
#detailarea .privqr .item { float: left; margin: 0; position: relative; }
|
||
#detailarea .privqr .item.right { float: right; position: relative; }
|
||
#detailarea .item { margin: 10px 0; position: relative; font-size: 90%; }
|
||
#detailarea .item.clear { clear: both; padding-top: 10px; }
|
||
#detailarea .label { display: block; text-decoration: underline; }
|
||
#detailarea .output { display: block; min-height: 20px; }
|
||
#detailarea #detailqrcodepublic { position: relative; float: left; margin: 0 10px 0 0; }
|
||
#detailarea #detailqrcodepubliccomp { position: relative; float: right; margin: 0 0 0 10px; }
|
||
#detailarea #detailqrcodeprivate { position: relative; float: left; margin: 0 10px 0 0; }
|
||
#detailarea #detailqrcodeprivatecomp { position: relative; float: right; margin: 0 0 0 10px; }
|
||
#detailpubkey { width: 566px; }
|
||
#detailbip38commands { display: none; padding-top: 5px; }
|
||
#vanityarea { text-align: left; }
|
||
#vanityarea .label { text-decoration: underline; }
|
||
#vanityarea .output { display: block; }
|
||
#vanityarea .notes { text-align: left; font-size: 80%; padding: 0 0 20px 0; }
|
||
#vanitystep1area { display: none; text-align: left; position: relative; padding: 15px; border-bottom: 2px solid green; }
|
||
#vanitystep1label { padding-left: 5px; }
|
||
#vanitystep2area { border-top: 2px solid green; display: block; padding: 15px; }
|
||
#vanitystep2inputs { padding: 0 15px 10px 15px; }
|
||
#vanitycalc { margin-top: 5px; }
|
||
|
||
.englishjson { text-align: center; padding: 40px 0 20px 0; }
|
||
.unittests { text-align: center; }
|
||
.unittests div { width: 894px; font-family: monospace; text-align: left; margin: auto; padding: 5px; border: 1px solid black; }
|
||
#testnet { font-family: Tahoma; display: none; background-color: Orange; color: #000000; border-radius: 5px; font-weight: bold; padding: 10px 0; margin: 0 auto 20px auto; }
|
||
#busyblock { position: fixed; display: none; background: url("data:image/gif;base64,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") #ccc no-repeat center; opacity: 0.4; width: 100%; height: 100%; top: 0; left: 0; z-index: 5000; }
|
||
#busyblock.busy { display: block; }
|
||
|
||
/* IE8 */
|
||
.qrcodetable { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; }
|
||
.qrcodetddark { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #000000; }
|
||
.qrcodetdlight { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #ffffff; }
|
||
|
||
@media screen
|
||
{
|
||
#tagline { margin: 0 0 15px 0; font-style: italic; }
|
||
.menu { text-align: left; }
|
||
.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; cursor: pointer; }
|
||
.menu .tab:hover { color: #FFF; }
|
||
.menu .tab.selected { background-color: #FFF; border-bottom: 2px solid #FFF; cursor: default; }
|
||
.menu .tab.selected:hover { color: #000; }
|
||
.pagebreak { height: 50px; }
|
||
.commands { border-bottom: 2px solid green; padding: 10px 0; margin-bottom: 0; }
|
||
.commands span { padding: 0 10px; }
|
||
.commands span.print { float: right; }
|
||
.commands span.right { float: right; }
|
||
.expandable { padding: 10px 15px; text-align: left; cursor: pointer; }
|
||
|
||
#papercommands { padding: 10px 0; border: 2px solid green; }
|
||
#braincommands .row { text-align: left; }
|
||
#braincommands .row .label { width: 200px; display: inline-block; }
|
||
#braincommands .row.extra { padding: 6px 0 0 0; }
|
||
#braincommands .notes { font-size: 80%; display: block; padding: 5px 10px; }
|
||
#brainpassphrase { width: 280px; }
|
||
#brainpassphraseconfirm { width: 280px; }
|
||
#detailcommands { padding: 10px 0; }
|
||
#detailcommands span { padding: 0 10px; }
|
||
#detailprivkey { width: 250px; }
|
||
#detailprivkeypassphrase { width: 250px; }
|
||
.paper #commands { border-bottom: 2px solid green; padding: 0; margin-bottom: 0; }
|
||
#bulkstartindex, #paperlimit, #paperlimitperpage { width: 35px; }
|
||
#bulklimit { width: 45px; }
|
||
|
||
.footer { font-family: Arial; font-size: 90%; clear: both; width: 750px; padding: 10px 0 10px 0; margin: 50px auto auto auto; }
|
||
.footer div span.item { padding: 10px; }
|
||
.footer .authorbtc { float: left; width: 470px; }
|
||
.footer .authorbtc span.item { text-align: left; display: block; padding: 0 20px; }
|
||
.footer .authorbtc div { position: relative; z-index: 100; }
|
||
.footer .authorpgp { position: relative; }
|
||
.footer .authorpgp span.item { 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
|
||
{
|
||
#main { width: auto; }
|
||
#culturemenu { display: none; }
|
||
#paperarea .keyarea:first-child { border-top: 2px solid green; }
|
||
#paperarea .keyarea.art:first-child { border: 0; }
|
||
.pagebreak { height: 1px; }
|
||
.paper #logo { display: none; }
|
||
.menu { display: none; }
|
||
.footer { display: none; }
|
||
.commands { display: none; }
|
||
#tagline { display: none; }
|
||
#faqs { display: none; }
|
||
#detailprivwif { width: 285px; word-wrap: break-word; }
|
||
#detailprivwifcomp { width: 285px; word-wrap: break-word; text-align: right; }
|
||
#detailarea .privqr .item { width: 285px; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body onclick="SecureRandom.seedTime();" onkeypress="SecureRandom.seedTime();" onmousemove="ninja.seeder.seed(event);">
|
||
<div id="busyblock"></div>
|
||
<div id="main">
|
||
<div id="culturemenu">
|
||
<span><a href="?culture=en" id="cultureen" class="selected">English</a></span> |
|
||
<span><a href="?culture=es" id="culturees">Español</a></span> |
|
||
<span><a href="?culture=fr" id="culturefr">Français</a></span> |
|
||
<span><a href="?culture=el" id="cultureel">ελληνικά</a></span>
|
||
</div>
|
||
<img alt="bitaddress.org" title="bitaddress.org" id="logo" src="data:image/png;base64,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" />
|
||
<div id="tagline">Open Source JavaScript Client-Side Bitcoin Wallet Generator</div>
|
||
<div id="testnet"></div>
|
||
<div class="menu" id="menu">
|
||
<div class="tab selected" id="singlewallet" onclick="ninja.tabSwitch(this);">Single Wallet</div>
|
||
<div class="tab" id="paperwallet" onclick="ninja.tabSwitch(this);">Paper Wallet</div>
|
||
<div class="tab" id="bulkwallet" onclick="ninja.tabSwitch(this);">Bulk Wallet</div>
|
||
<div class="tab" id="brainwallet" onclick="ninja.tabSwitch(this);">Brain Wallet</div>
|
||
<div class="tab" id="vanitywallet" onclick="ninja.tabSwitch(this);">Vanity Wallet</div>
|
||
<div class="tab" id="detailwallet" onclick="ninja.tabSwitch(this);">Wallet Details</div>
|
||
</div>
|
||
|
||
<div id="generate">
|
||
<span id="generatelabelbitcoinaddress">Generating Bitcoin Address...</span><br />
|
||
<span id="generatelabelmovemouse">MOVE your mouse around to add some extra randomness...</span><br />
|
||
</div>
|
||
|
||
<div id="wallets">
|
||
<div id="singlearea" class="walletarea">
|
||
<div class="commands">
|
||
<div id="singlecommands">
|
||
<span><input type="button" id="newaddress" value="Generate New Address" onclick="ninja.wallets.singlewallet.generateNewAddressAndKey();" /></span>
|
||
<span class="print"><input type="button" name="print" value="Print" id="singleprint" onclick="window.print();" /></span>
|
||
</div>
|
||
</div>
|
||
<div id="keyarea" class="keyarea">
|
||
<div class="public">
|
||
<div id="qrcode_public" class="qrcode_public"></div>
|
||
<div class="pubaddress">
|
||
<span class="label" id="singlelabelbitcoinaddress">Bitcoin Address:</span>
|
||
<span class="output" id="btcaddress"></span>
|
||
</div>
|
||
</div>
|
||
<div class="private">
|
||
<div id="qrcode_private" class="qrcode_private"></div>
|
||
<div class="privwif">
|
||
<span class="label" id="singlelabelprivatekey">Private Key (Wallet Import Format):</span>
|
||
<span class="output" id="btcprivwif"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="paperarea">
|
||
<div id="papercommands" class="commands">
|
||
<span><label id="paperlabelhideart">Hide Art?</label> <input type="checkbox" id="paperart" onchange="ninja.wallets.paperwallet.toggleArt(this);" /></span>
|
||
<span><label id="paperlabeladdressesperpage">Addresses per page:</label> <input type="text" id="paperlimitperpage" /></span>
|
||
<span><label id="paperlabeladdressestogenerate">Addresses to generate:</label> <input type="text" id="paperlimit" /></span>
|
||
<span><input type="button" id="papergenerate" value="Generate" onclick="ninja.wallets.paperwallet.build(document.getElementById('paperlimit').value * 1, document.getElementById('paperlimitperpage').value * 1, !document.getElementById('paperart').checked);" /></span>
|
||
<span class="print"><input type="button" name="print" value="Print" id="paperprint" onclick="window.print();" /></span>
|
||
</div>
|
||
<div id="paperkeyarea"></div>
|
||
</div>
|
||
|
||
<div id="bulkarea" class="walletarea">
|
||
<div id="bulkcommands" class="commands">
|
||
<span><label id="bulklabelstartindex">Start index:</label> <input type="text" id="bulkstartindex" value="1" /></span>
|
||
<span><label id="bulklabelrowstogenerate">Rows to generate:</label> <input type="text" id="bulklimit" value="3" /></span>
|
||
<span><label id="bulklabelcompressed">Compressed addresses?</label> <input type="checkbox" id="bulkcompressed" /></span>
|
||
<span><input type="button" id="bulkgenerate" value="Generate" onclick="ninja.wallets.bulkwallet.buildCSV(document.getElementById('bulklimit').value * 1, document.getElementById('bulkstartindex').value * 1, document.getElementById('bulkcompressed').checked);" /> </span>
|
||
<span class="print"><input type="button" name="print" id="bulkprint" value="Print" onclick="window.print();" /></span>
|
||
</div>
|
||
<div class="body">
|
||
<span class="label" id="bulklabelcsv">Comma Separated Values:</span> <span class="format" id="bulklabelformat">Index,Address,Private Key (WIF)</span>
|
||
<textarea rows="20" cols="88" id="bulktextarea"></textarea>
|
||
</div>
|
||
<div class="faqs">
|
||
<div id="bulkfaq1" class="bulkfaq">
|
||
<div id="bulkq1" class="bulkquestion" onclick="ninja.wallets.bulkwallet.openCloseFaq(1);">
|
||
<span id="bulklabelq1">Why should I use a Bulk Wallet to accept Bitcoins on my website?</span>
|
||
<div id="bulke1" class="more"></div>
|
||
</div>
|
||
<div id="bulka1" class="bulkanswer">The traditional approach to accepting bitcoins on your website requires that you install the official bitcoin client daemon ("bitcoind"). Many website hosting packages don't support installing the bitcoin daemon. Also, running the bitcoin daemon on your web server means your private keys are hosted on the server and could get stolen if your web server is hacked. When using a Bulk Wallet you can upload only the bitcoin addresses and not the private keys to your web server. Then you don't have to worry about your bitcoin wallet being stolen if your web server is hacked. </div>
|
||
</div>
|
||
<div id="bulkfaq2" class="bulkfaq">
|
||
<div id="bulkq2" class="bulkquestion" onclick="ninja.wallets.bulkwallet.openCloseFaq(2);">
|
||
<span id="bulklabelq2">How do I use a Bulk Wallet to accept Bitcoins on my website?</span>
|
||
<div id="bulke2" class="more"></div>
|
||
</div>
|
||
<div id="bulka2" class="bulkanswer">
|
||
<ol>
|
||
<li id="bulklabela2li1">Use the Bulk Wallet tab to pre-generate a large number of bitcoin addresses (10,000+). Copy and paste the generated comma separated values (CSV) list to a secure text file on your computer. Backup the file you just created to a secure location.</li>
|
||
<li id="bulklabela2li2">Import the bitcoin addresses into a database table on your web server. (Don't put the wallet/private keys on your web server, otherwise you risk hackers stealing your coins. Just the bitcoin addresses as they will be shown to customers.)</li>
|
||
<li id="bulklabela2li3">Provide an option on your website's shopping cart for your customer to pay in Bitcoin. When the customer chooses to pay in Bitcoin you will then display one of the addresses from your database to the customer as his "payment address" and save it with his shopping cart order.</li>
|
||
<li id="bulklabela2li4">You now need to be notified when the payment arrives. Google "bitcoin payment notification" and subscribe to at least one bitcoin payment notification service. There are various services that will notify you via Web Services, API, SMS, Email, etc. Once you receive this notification, which could be programmatically automated, you can process the customer's order. To manually check if a payment has arrived you can use Block Explorer. Replace THEADDRESSGOESHERE with the bitcoin address you are checking. It could take between 10 minutes to one hour for the transaction to be confirmed.<br />http://www.blockexplorer.com/address/THEADDRESSGOESHERE<br /><br />Unconfirmed transactions can be viewed at: http://blockchain.info/ <br />You should see the transaction there within 30 seconds.</li>
|
||
<li id="bulklabela2li5">Bitcoins will safely pile up on the block chain. Use the original wallet file you generated in step 1 to spend them.</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="brainarea" class="walletarea">
|
||
<div id="braincommands" class="commands">
|
||
<div class="row">
|
||
<span id="brainlabelenterpassphrase" class="label">Enter Passphrase: </span>
|
||
<input tabindex="1" type="password" id="brainpassphrase" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.brainwallet.view();" />
|
||
<span><label id="brainlabelshow">Show?</label> <input type="checkbox" id="brainpassphraseshow" onchange="ninja.wallets.brainwallet.showToggle(this);" /></span>
|
||
<span class="print"><input type="button" name="print" id="brainprint" value="Print" onclick="window.print();" /></span>
|
||
</div>
|
||
<div class="row extra">
|
||
<span class="label" id="brainlabelconfirm">Confirm Passphrase: </span>
|
||
<input tabindex="2" type="password" id="brainpassphraseconfirm" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.brainwallet.view();" />
|
||
<span><input tabindex="3" type="button" id="brainview" value="View" onclick="ninja.wallets.brainwallet.view();" /></span>
|
||
<span id="brainalgorithm" class="notes right">Algorithm: SHA256(passphrase)</span>
|
||
</div>
|
||
</div>
|
||
<div id="brainkeyarea" class="keyarea">
|
||
<div class="public">
|
||
<div id="brainqrcodepublic" class="qrcode_public"></div>
|
||
<div class="pubaddress">
|
||
<span class="label" id="brainlabelbitcoinaddress">Bitcoin Address:</span>
|
||
<span class="output" id="brainbtcaddress"></span>
|
||
</div>
|
||
</div>
|
||
<div class="private">
|
||
<div id="brainqrcodeprivate" class="qrcode_private"></div>
|
||
<div class="privwif">
|
||
<span class="label" id="brainlabelprivatekey">Private Key (Wallet Import Format):</span>
|
||
<span class="output" id="brainbtcprivwif"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="vanityarea" class="walletarea">
|
||
<div id="vanitystep1label" class="commands expandable" onclick="ninja.wallets.vanitywallet.openCloseStep(1);">
|
||
<span><label id="vanitylabelstep1">Step 1 - Generate your "Step1 Key Pair"</label> <input type="button" id="vanitynewkeypair"
|
||
value="Generate" onclick="ninja.wallets.vanitywallet.generateKeyPair();" /></span>
|
||
<div id="vanitystep1icon" class="more"></div>
|
||
</div>
|
||
<div id="vanitystep1area">
|
||
<div>
|
||
<span class="label" id="vanitylabelstep1publickey">Step 1 Public Key:</span>
|
||
<div class="output pubkeyhex" id="vanitypubkey"></div>
|
||
<br /><div class="notes" id="vanitylabelstep1pubnotes">Copy and paste the above into the Your-Part-Public-Key field in the Vanity Pool Website.</div>
|
||
</div>
|
||
<div>
|
||
<span class="label" id="vanitylabelstep1privatekey">Step 1 Private Key:</span>
|
||
<span class="output" id="vanityprivatekey"></span>
|
||
<br /><div class="notes" id="vanitylabelstep1privnotes">Copy and paste the above Private Key field into a text file. Ideally save to an encrypted drive. You will need this to retrieve the Bitcoin Private Key once the Pool has found your prefix.</div>
|
||
</div>
|
||
</div>
|
||
<div id="vanitystep2label" class="expandable" onclick="ninja.wallets.vanitywallet.openCloseStep(2);">
|
||
<span id="vanitylabelstep2calculateyourvanitywallet">Step 2 - Calculate your Vanity Wallet</span>
|
||
<div id="vanitystep2icon" class="more"></div>
|
||
</div>
|
||
<div id="vanitystep2inputs">
|
||
<div>
|
||
<span id="vanitylabelenteryourpart">Enter Your Part Private Key (generated in Step 1 above and previously saved):</span>
|
||
<br /><span class="notes" id="vanitylabelnote1">[NOTE: this input box can accept a public key or private key]</span>
|
||
</div>
|
||
<div><textarea id="vanityinput1" rows="2" cols="90" onfocus="this.select();"></textarea></div>
|
||
<div>
|
||
<span id="vanitylabelenteryourpoolpart">Enter Pool Part Private Key (from Vanity Pool):</span>
|
||
<br /><span class="notes" id="vanitylabelnote2">[NOTE: this input box can accept a public key or private key]</span>
|
||
</div>
|
||
<div><textarea id="vanityinput2" rows="2" cols="90" onfocus="this.select();"></textarea></div>
|
||
<div>
|
||
<label for="vanityradioadd" id="vanitylabelradioadd">Add</label> <input type="radio" id="vanityradioadd" name="vanityradio" value="add" checked />
|
||
<label for="vanityradiomultiply" id="vanitylabelradiomultiply">Multiply</label> <input type="radio" id="vanityradiomultiply" name="vanityradio" value="multiply" />
|
||
</div>
|
||
<div><input type="button" id="vanitycalc" value="Calculate Vanity Wallet" onclick="ninja.wallets.vanitywallet.addKeys();" /></div>
|
||
</div>
|
||
<div id="vanitystep2area">
|
||
<div>
|
||
<span class="label" id="vanitylabelbitcoinaddress">Vanity Bitcoin Address:</span>
|
||
<span class="output" id="vanityaddress"></span>
|
||
<br /><div class="notes" id="vanitylabelnotesbitcoinaddress">The above is your new address that should include your required prefix.</div>
|
||
</div>
|
||
|
||
<div>
|
||
<span class="label" id="vanitylabelpublickeyhex">Vanity Public Key (HEX):</span>
|
||
<span class="output pubkeyhex" id="vanitypublickeyhex"></span>
|
||
<br /><div class="notes" id="vanitylabelnotespublickeyhex">The above is the Public Key in hexadecimal format. </div>
|
||
</div>
|
||
|
||
<div>
|
||
<span class="label" id="vanitylabelprivatekey">Vanity Private Key (WIF):</span>
|
||
<span class="output" id="vanityprivatekeywif"></span>
|
||
<br /><div class="notes" id="vanitylabelnotesprivatekey">The above is the Private Key to load into your wallet. </div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="detailarea" class="walletarea">
|
||
<div id="detailcommands" class="commands">
|
||
<span><label id="detaillabelenterprivatekey">Enter Private Key (any format)</label> <input type="text" id="detailprivkey" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.detailwallet.viewDetails();" /></span>
|
||
<span><input type="button" id="detailview" value="View Details" onclick="ninja.wallets.detailwallet.viewDetails();" /></span>
|
||
<span class="print"><input type="button" name="print" id="detailprint" value="Print" onclick="window.print();" /></span>
|
||
<div id="detailbip38commands">
|
||
<span><label id="detaillabelpassphrase">Enter BIP38 Passphrase</label> <input type="text" id="detailprivkeypassphrase" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.detailwallet.viewDetails();" /></span>
|
||
<span><input type="button" id="detaildecrypt" value="Decrypt BIP38" onclick="ninja.wallets.detailwallet.viewDetails();" /></span>
|
||
</div>
|
||
</div>
|
||
<div id="detailkeyarea">
|
||
<div class="notes">
|
||
<span id="detaillabelnote1">Your Bitcoin Private Key is a unique secret number that only you know. It can be encoded in a number of different formats. Below we show the Bitcoin Address and Public Key that corresponds to your Private Key as well as your Private Key in the most popular encoding formats (WIF, HEX, B64, MINI).</span>
|
||
<br /><br />
|
||
<span id="detaillabelnote2">Bitcoin v0.6+ stores public keys in compressed format. The client now also supports import and export of private keys with importprivkey/dumpprivkey. The format of the exported private key is determined by whether the address was generated in an old or new wallet.</span>
|
||
</div>
|
||
<div class="pubqr">
|
||
<div class="item">
|
||
<span class="label" id="detaillabelbitcoinaddress">Bitcoin Address</span>
|
||
<div id="detailqrcodepublic" class="qrcode_public"></div>
|
||
<span class="output" id="detailaddress"></span>
|
||
</div>
|
||
<div class="item right">
|
||
<span class="label" id="detaillabelbitcoinaddresscomp">Bitcoin Address Compressed</span>
|
||
<div id="detailqrcodepubliccomp" class="qrcode_public"></div>
|
||
<span class="output" id="detailaddresscomp"></span>
|
||
</div>
|
||
</div>
|
||
<br /><br />
|
||
<div class="item clear">
|
||
<span class="label" id="detaillabelpublickey">Public Key (130 characters [0-9A-F]):</span>
|
||
<span class="output pubkeyhex" id="detailpubkey"></span>
|
||
</div>
|
||
<div class="item">
|
||
<span class="label" id="detaillabelpublickeycomp">Public Key (compressed, 66 characters [0-9A-F]):</span>
|
||
<span class="output" id="detailpubkeycomp"></span>
|
||
</div>
|
||
<hr />
|
||
<div class="privqr">
|
||
<div class="item">
|
||
<span class="label"><span id="detaillabelprivwif">Private Key WIF<br />51 characters base58, starts with a</span> <span id="detailwifprefix">'5'</span></span>
|
||
<div id="detailqrcodeprivate" class="qrcode_private"></div>
|
||
<span class="output" id="detailprivwif"></span>
|
||
</div>
|
||
<div class="item right">
|
||
<span class="label"><span id="detaillabelprivwifcomp">Private Key WIF Compressed<br />52 characters base58, starts with a</span> <span id="detailcompwifprefix">'K' or 'L'</span></span>
|
||
<div id="detailqrcodeprivatecomp" class="qrcode_private"></div>
|
||
<span class="output" id="detailprivwifcomp"></span>
|
||
</div>
|
||
</div>
|
||
<br /><br />
|
||
<div class="item clear">
|
||
<span class="label" id="detaillabelprivhex">Private Key Hexadecimal Format (64 characters [0-9A-F]):</span>
|
||
<span class="output" id="detailprivhex"></span>
|
||
</div>
|
||
<div class="item">
|
||
<span class="label" id="detaillabelprivb64">Private Key Base64 (44 characters):</span>
|
||
<span class="output" id="detailprivb64"></span>
|
||
</div>
|
||
<div class="item" style="display: none;" id="detailmini">
|
||
<span class="label" id="detaillabelprivmini">Private Key Mini Format (22, 26 or 30 characters, starts with an 'S'):</span>
|
||
<span class="output" id="detailprivmini"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="footer" class="footer">
|
||
<div class="authorbtc">
|
||
<div>
|
||
<span class="item"><span id="footerlabeldonations">Donations:</span> <b>1NiNja</b>1bUmhSoTXozBRBEtR8LeF9TGbZBN</span>
|
||
<span class="item"><a href="http://firstbits.net/1ninja" target="_blank">firstbits.net/1ninja</a></span>
|
||
<span class="item" id="footerlabeltranslatedby"></span>
|
||
</div>
|
||
</div>
|
||
<div class="authorpgp">
|
||
<span class="item"><a href="ninja_bitaddress.org.txt" target="_blank" id="footerlabelpgp">PGP Public Key</a></span>
|
||
<span class="item"><a href="pgpsignedmsg.txt" target="_blank"><span id="footerlabelversion">Signed Version History</span> (v2.5)</a></span>
|
||
<span class="item"><a href="https://github.com/pointbiz/bitaddress.org" target="_blank" id="footerlabelgithub">GitHub Repository</a></span>
|
||
</div>
|
||
<div class="copyright">
|
||
<span id="footerlabelcopyright1">Copyright bitaddress.org.</span>
|
||
<span id="footerlabelcopyright2">JavaScript copyrights are included in the source.</span>
|
||
<span id="footerlabelnowarranty">No warranty.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
var ninja = { wallets: {} };
|
||
|
||
ninja.privateKey = {
|
||
isPrivateKey: function (key) {
|
||
return (
|
||
Bitcoin.ECKey.isWalletImportFormat(key) ||
|
||
Bitcoin.ECKey.isCompressedWalletImportFormat(key) ||
|
||
Bitcoin.ECKey.isHexFormat(key) ||
|
||
Bitcoin.ECKey.isBase64Format(key) ||
|
||
Bitcoin.ECKey.isMiniFormat(key)
|
||
);
|
||
},
|
||
getECKeyFromAdding: function (privKey1, privKey2) {
|
||
var n = EllipticCurve.getSECCurveByName("secp256k1").getN();
|
||
var ecKey1 = new Bitcoin.ECKey(privKey1);
|
||
var ecKey2 = new Bitcoin.ECKey(privKey2);
|
||
// if both keys are the same return null
|
||
if (ecKey1.getBitcoinHexFormat() == ecKey2.getBitcoinHexFormat()) return null;
|
||
if (ecKey1 == null || ecKey2 == null) return null;
|
||
var combinedPrivateKey = new Bitcoin.ECKey(ecKey1.priv.add(ecKey2.priv).mod(n));
|
||
// compressed when both keys are compressed
|
||
if (ecKey1.compressed && ecKey2.compressed) combinedPrivateKey.setCompressed(true);
|
||
return combinedPrivateKey;
|
||
},
|
||
getECKeyFromMultiplying: function (privKey1, privKey2) {
|
||
var n = EllipticCurve.getSECCurveByName("secp256k1").getN();
|
||
var ecKey1 = new Bitcoin.ECKey(privKey1);
|
||
var ecKey2 = new Bitcoin.ECKey(privKey2);
|
||
// if both keys are the same return null
|
||
if (ecKey1.getBitcoinHexFormat() == ecKey2.getBitcoinHexFormat()) return null;
|
||
if (ecKey1 == null || ecKey2 == null) return null;
|
||
var combinedPrivateKey = new Bitcoin.ECKey(ecKey1.priv.multiply(ecKey2.priv).mod(n));
|
||
// compressed when both keys are compressed
|
||
if (ecKey1.compressed && ecKey2.compressed) combinedPrivateKey.setCompressed(true);
|
||
return combinedPrivateKey;
|
||
},
|
||
// 58 base58 characters starting with 6P
|
||
isBIP38Format: function (key) {
|
||
return (/^6P[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{56}$/.test(key));
|
||
},
|
||
BIP38EncryptedKeyToByteArrayAsync: function (base58Encrypted, passphrase, callback) {
|
||
var hex;
|
||
try {
|
||
hex = Bitcoin.Base58.decode(base58Encrypted);
|
||
} catch (e) {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
|
||
// 43 bytes: 2 bytes prefix, 37 bytes payload, 4 bytes checksum
|
||
if (hex.length != 43) {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
// first byte is always 0x01
|
||
else if (hex[0] != 0x01) {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
|
||
var expChecksum = hex.slice(-4);
|
||
hex = hex.slice(0, -4);
|
||
var checksum = Bitcoin.Util.dsha256(hex);
|
||
if (checksum[0] != expChecksum[0] || checksum[1] != expChecksum[1] || checksum[2] != expChecksum[2] || checksum[3] != expChecksum[3]) {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
|
||
var isCompPoint = false;
|
||
var isECMult = false;
|
||
var hasLotSeq = false;
|
||
// second byte for non-EC-multiplied key
|
||
if (hex[1] == 0x42) {
|
||
// key should use compression
|
||
if (hex[2] == 0xe0) {
|
||
isCompPoint = true;
|
||
}
|
||
// key should NOT use compression
|
||
else if (hex[2] != 0xc0) {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
}
|
||
// second byte for EC-multiplied key
|
||
else if (hex[1] == 0x43) {
|
||
isECMult = true;
|
||
isCompPoint = (hex[2] & 0x20) != 0;
|
||
hasLotSeq = (hex[2] & 0x04) != 0;
|
||
if ((hex[2] & 0x24) != hex[2]) {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
}
|
||
else {
|
||
callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
|
||
return;
|
||
}
|
||
|
||
var decrypted;
|
||
var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
|
||
|
||
var verifyHashAndReturn = function () {
|
||
var tmpkey = new Bitcoin.ECKey(decrypted); // decrypted using closure
|
||
var base58AddrText = tmpkey.setCompressed(isCompPoint).getBitcoinAddress(); // isCompPoint using closure
|
||
checksum = Bitcoin.Util.dsha256(base58AddrText); // checksum using closure
|
||
|
||
if (checksum[0] != hex[3] || checksum[1] != hex[4] || checksum[2] != hex[5] || checksum[3] != hex[6]) {
|
||
callback(new Error(ninja.translator.get("bip38alertincorrectpassphrase"))); // callback using closure
|
||
return;
|
||
}
|
||
callback(tmpkey.getBitcoinPrivateKeyByteArray()); // callback using closure
|
||
};
|
||
|
||
if (!isECMult) {
|
||
var addresshash = hex.slice(3, 7);
|
||
Crypto_scrypt(passphrase, addresshash, 16384, 8, 8, 64, function (derivedBytes) {
|
||
var k = derivedBytes.slice(32, 32 + 32);
|
||
decrypted = Crypto.AES.decrypt(hex.slice(7, 7 + 32), k, AES_opts);
|
||
for (var x = 0; x < 32; x++) decrypted[x] ^= derivedBytes[x];
|
||
verifyHashAndReturn(); //TODO: pass in 'decrypted' as a param
|
||
});
|
||
}
|
||
else {
|
||
var ownerentropy = hex.slice(7, 7 + 8);
|
||
var ownersalt = !hasLotSeq ? ownerentropy : ownerentropy.slice(0, 4);
|
||
Crypto_scrypt(passphrase, ownersalt, 16384, 8, 8, 32, function (prefactorA) {
|
||
var passfactor;
|
||
if (!hasLotSeq) { // hasLotSeq using closure
|
||
passfactor = prefactorA;
|
||
} else {
|
||
var prefactorB = prefactorA.concat(ownerentropy); // ownerentropy using closure
|
||
passfactor = Bitcoin.Util.dsha256(prefactorB);
|
||
}
|
||
var kp = new Bitcoin.ECKey(passfactor);
|
||
var passpoint = kp.setCompressed(true).getPub();
|
||
|
||
var encryptedpart2 = hex.slice(23, 23 + 16);
|
||
|
||
var addresshashplusownerentropy = hex.slice(3, 3 + 12);
|
||
Crypto_scrypt(passpoint, addresshashplusownerentropy, 1024, 1, 1, 64, function (derived) {
|
||
var k = derived.slice(32);
|
||
|
||
var unencryptedpart2 = Crypto.AES.decrypt(encryptedpart2, k, AES_opts);
|
||
for (var i = 0; i < 16; i++) { unencryptedpart2[i] ^= derived[i + 16]; }
|
||
|
||
var encryptedpart1 = hex.slice(15, 15 + 8).concat(unencryptedpart2.slice(0, 0 + 8));
|
||
var unencryptedpart1 = Crypto.AES.decrypt(encryptedpart1, k, AES_opts);
|
||
for (var i = 0; i < 16; i++) { unencryptedpart1[i] ^= derived[i]; }
|
||
|
||
var seedb = unencryptedpart1.slice(0, 0 + 16).concat(unencryptedpart2.slice(8, 8 + 8));
|
||
|
||
var factorb = Bitcoin.Util.dsha256(seedb);
|
||
|
||
var ps = EllipticCurve.getSECCurveByName("secp256k1");
|
||
var privateKey = BigInteger.fromByteArrayUnsigned(passfactor).multiply(BigInteger.fromByteArrayUnsigned(factorb)).remainder(ps.getN());
|
||
|
||
decrypted = privateKey.toByteArrayUnsigned();
|
||
verifyHashAndReturn();
|
||
});
|
||
});
|
||
}
|
||
}
|
||
};
|
||
|
||
ninja.publicKey = {
|
||
isPublicKeyHexFormat: function (key) {
|
||
key = key.toString();
|
||
return ninja.publicKey.isUncompressedPublicKeyHexFormat(key) || ninja.publicKey.isCompressedPublicKeyHexFormat(key);
|
||
},
|
||
// 130 characters [0-9A-F] starts with 04
|
||
isUncompressedPublicKeyHexFormat: function (key) {
|
||
key = key.toString();
|
||
return /^04[A-Fa-f0-9]{128}$/.test(key);
|
||
},
|
||
// 66 characters [0-9A-F] starts with 02 or 03
|
||
isCompressedPublicKeyHexFormat: function (key) {
|
||
key = key.toString();
|
||
return /^0[2-3][A-Fa-f0-9]{64}$/.test(key);
|
||
},
|
||
getBitcoinAddressFromByteArray: function (pubKeyByteArray) {
|
||
var pubKeyHash = Bitcoin.Util.sha256ripe160(pubKeyByteArray);
|
||
var addr = new Bitcoin.Address(pubKeyHash);
|
||
return addr.toString();
|
||
},
|
||
getHexFromByteArray: function (pubKeyByteArray) {
|
||
return Crypto.util.bytesToHex(pubKeyByteArray).toString().toUpperCase();
|
||
},
|
||
getByteArrayFromAdding: function (pubKeyHex1, pubKeyHex2) {
|
||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||
var curve = ecparams.getCurve();
|
||
var ecPoint1 = curve.decodePointHex(pubKeyHex1);
|
||
var ecPoint2 = curve.decodePointHex(pubKeyHex2);
|
||
// if both points are the same return null
|
||
if (ecPoint1.equals(ecPoint2)) return null;
|
||
var compressed = (ecPoint1.compressed && ecPoint2.compressed);
|
||
var pubKey = ecPoint1.add(ecPoint2).getEncoded(compressed);
|
||
return pubKey;
|
||
},
|
||
getByteArrayFromMultiplying: function (pubKeyHex, ecKey) {
|
||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||
var ecPoint = ecparams.getCurve().decodePointHex(pubKeyHex);
|
||
var compressed = (ecPoint.compressed && ecKey.compressed);
|
||
// if both points are the same return null
|
||
ecKey.setCompressed(false);
|
||
if (ecPoint.equals(ecKey.getPubPoint())) {
|
||
return null;
|
||
}
|
||
var bigInt = ecKey.priv;
|
||
var pubKey = ecPoint.multiply(bigInt).getEncoded(compressed);
|
||
return pubKey;
|
||
},
|
||
// used by unit test
|
||
getDecompressedPubKeyHex: function (pubKeyHexComp) {
|
||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||
var ecPoint = ecparams.getCurve().decodePointHex(pubKeyHexComp);
|
||
var pubByteArray = ecPoint.getEncoded(0);
|
||
var pubHexUncompressed = ninja.publicKey.getHexFromByteArray(pubByteArray);
|
||
return pubHexUncompressed;
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.seeder = {
|
||
// number of mouse movements to wait for
|
||
seedLimit: (function () {
|
||
var num = Crypto.util.randomBytes(12)[11];
|
||
return 50 + Math.floor(num);
|
||
})(),
|
||
|
||
seedCount: 0, // counter
|
||
|
||
// seed function exists to wait for mouse movement to add more entropy before generating an address
|
||
seed: function (evt) {
|
||
if (!evt) var evt = window.event;
|
||
|
||
// seed a bunch (minimum seedLimit) of times based on mouse moves
|
||
SecureRandom.seedTime();
|
||
// seed mouse position X and Y
|
||
if (evt) SecureRandom.seedInt((evt.clientX * evt.clientY));
|
||
|
||
ninja.seeder.seedCount++;
|
||
// seeding is over now we generate and display the address
|
||
if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
|
||
ninja.wallets.singlewallet.open();
|
||
// UI
|
||
document.getElementById("generate").style.display = "none";
|
||
document.getElementById("menu").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.seeder.seedCount < ninja.seeder.seedLimit) {
|
||
SecureRandom.seedTime();
|
||
ninja.seeder.seedCount = ninja.seeder.seedLimit - 1;
|
||
ninja.seeder.seed();
|
||
}
|
||
}
|
||
};
|
||
|
||
ninja.qrCode = {
|
||
// determine which type number is big enough for the input text length
|
||
getTypeNumber: 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;
|
||
},
|
||
|
||
createCanvas: function (text, sizeMultiplier) {
|
||
sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
|
||
// create the qrcode itself
|
||
var typeNumber = ninja.qrCode.getTypeNumber(text);
|
||
var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
|
||
qrcode.addData(text);
|
||
qrcode.make();
|
||
var width = qrcode.getModuleCount() * sizeMultiplier;
|
||
var height = qrcode.getModuleCount() * sizeMultiplier;
|
||
// create canvas element
|
||
var canvas = document.createElement('canvas');
|
||
var scale = 10.0;
|
||
canvas.width = width * scale;
|
||
canvas.height = height * scale;
|
||
canvas.style.width = width + 'px';
|
||
canvas.style.height = height + 'px';
|
||
var ctx = canvas.getContext('2d');
|
||
ctx.scale(scale, scale);
|
||
// 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
|
||
createTableHtml: function (text) {
|
||
var typeNumber = ninja.qrCode.getTypeNumber(text);
|
||
var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
|
||
qr.addData(text);
|
||
qr.make();
|
||
var tableHtml = "<table class='qrcodetable'>";
|
||
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='qrcodetddark'/>";
|
||
} else {
|
||
tableHtml += "<td class='qrcodetdlight'/>";
|
||
}
|
||
}
|
||
tableHtml += "</tr>";
|
||
}
|
||
tableHtml += "</table>";
|
||
return tableHtml;
|
||
},
|
||
|
||
// show QRCodes with canvas OR table (IE8)
|
||
// parameter: keyValuePair
|
||
// example: { "id1": "string1", "id2": "string2"}
|
||
// "id1" is the id of a div element where you want a QRCode inserted.
|
||
// "string1" is the string you want encoded into the QRCode.
|
||
showQrCode: function (keyValuePair, sizeMultiplier) {
|
||
for (var key in keyValuePair) {
|
||
var value = keyValuePair[key];
|
||
try {
|
||
if (document.getElementById(key)) {
|
||
document.getElementById(key).innerHTML = "";
|
||
document.getElementById(key).appendChild(ninja.qrCode.createCanvas(value, sizeMultiplier));
|
||
}
|
||
}
|
||
catch (e) {
|
||
// for browsers that do not support canvas (IE8)
|
||
document.getElementById(key).innerHTML = ninja.qrCode.createTableHtml(value);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
ninja.tabSwitch = function (walletTab) {
|
||
if (walletTab.className.indexOf("selected") == -1) {
|
||
// unselect all tabs
|
||
for (var wType in ninja.wallets) {
|
||
document.getElementById(wType).className = "tab";
|
||
ninja.wallets[wType].close();
|
||
}
|
||
walletTab.className += " selected";
|
||
ninja.wallets[walletTab.getAttribute("id")].open();
|
||
}
|
||
};
|
||
|
||
ninja.getQueryString = function () {
|
||
var result = {}, queryString = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;
|
||
while (m = re.exec(queryString)) {
|
||
result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
|
||
}
|
||
return result;
|
||
};
|
||
|
||
// use when passing an Array of Functions
|
||
ninja.runSerialized = function (functions, onComplete) {
|
||
onComplete = onComplete || function () { };
|
||
|
||
if (functions.length === 0) onComplete();
|
||
else {
|
||
// run the first function, and make it call this
|
||
// function when finished with the rest of the list
|
||
var f = functions.shift();
|
||
f(function () { ninja.runSerialized(functions, onComplete); });
|
||
}
|
||
};
|
||
|
||
ninja.forSerialized = function (initial, max, whatToDo, onComplete) {
|
||
onComplete = onComplete || function () { };
|
||
|
||
if (initial === max) { onComplete(); }
|
||
else {
|
||
// same idea as runSerialized
|
||
whatToDo(initial, function () { ninja.forSerialized(++initial, max, whatToDo, onComplete); });
|
||
}
|
||
};
|
||
|
||
// use when passing an Object (dictionary) of Functions
|
||
ninja.foreachSerialized = function (collection, whatToDo, onComplete) {
|
||
var keys = [];
|
||
for (var name in collection) {
|
||
keys.push(name);
|
||
}
|
||
ninja.forSerialized(0, keys.length, function (i, callback) {
|
||
whatToDo(keys[i], callback);
|
||
}, onComplete);
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.translator = {
|
||
currentCulture: "en",
|
||
|
||
translate: function (culture) {
|
||
var dict = ninja.translator.translations[culture];
|
||
if (dict) {
|
||
// set current culture
|
||
ninja.translator.currentCulture = culture;
|
||
// update menu UI
|
||
for (var cult in ninja.translator.translations) {
|
||
document.getElementById("culture" + cult).setAttribute("class", "");
|
||
}
|
||
document.getElementById("culture" + culture).setAttribute("class", "selected");
|
||
// apply translations
|
||
for (var id in dict) {
|
||
if (document.getElementById(id) && document.getElementById(id).value) {
|
||
document.getElementById(id).value = dict[id];
|
||
}
|
||
else if (document.getElementById(id)) {
|
||
document.getElementById(id).innerHTML = dict[id];
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
get: function (id) {
|
||
var translation = ninja.translator.translations[ninja.translator.currentCulture][id];
|
||
return translation;
|
||
},
|
||
|
||
translations: {
|
||
"en": {
|
||
// javascript alerts or messages
|
||
"testneteditionactivated": "TESTNET EDITION ACTIVATED",
|
||
"paperlabelbitcoinaddress": "Bitcoin Address:",
|
||
"paperlabelprivatekey": "Private Key (Wallet Import Format):",
|
||
"bulkgeneratingaddresses": "Generating addresses... ",
|
||
"brainalertpassphrasetooshort": "The passphrase you entered is too short.\n\nWarning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your bitcoins.",
|
||
"brainalertpassphrasedoesnotmatch": "The passphrase does not match the confirm passphrase.",
|
||
"detailalertnotvalidprivatekey": "The text you entered is not a valid Private Key",
|
||
"detailconfirmsha256": "The text you entered is not a valid Private Key!\n\nWould you like to use the entered text as a passphrase and create a Private Key using a SHA256 hash of the passphrase?\n\nWarning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your bitcoins.",
|
||
"bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.",
|
||
"bip38alertpassphraserequired": "Passphrase required for BIP38 key",
|
||
"vanityinvalidinputcouldnotcombinekeys": "Invalid input. Could not combine keys.",
|
||
"vanityalertinvalidinputpublickeysmatch": "Invalid input. The Public Key of both entries match. You must input two different keys.",
|
||
"vanityalertinvalidinputcannotmultiple": "Invalid input. Cannot multiply two public keys. Select 'Add' to add two public keys to get a bitcoin address.",
|
||
"vanityprivatekeyonlyavailable": "Only available when combining two private keys",
|
||
"vanityalertinvalidinputprivatekeysmatch": "Invalid input. The Private Key of both entries match. You must input two different keys."
|
||
},
|
||
|
||
"es": {
|
||
// javascript alerts or messages
|
||
"testneteditionactivated": "Testnet se activa",
|
||
"paperlabelbitcoinaddress": "Dirección Bitcoin:",
|
||
"paperlabelprivatekey": "Clave privada (formato para importar):",
|
||
"bulkgeneratingaddresses": "Generación de direcciones... ",
|
||
"brainalertpassphrasetooshort": "La contraseña introducida es demasiado corta.\n\nAviso: Es importante escoger una contraseña fuerte para evitar ataques de fuerza bruta a fin de adivinarla y robar tus bitcoins.",
|
||
"brainalertpassphrasedoesnotmatch": "Las contraseñas no coinciden.",
|
||
"detailalertnotvalidprivatekey": "El texto que has introducido no es una clave privada válida",
|
||
"detailconfirmsha256": "El texto que has introducido no es una clave privada válida\n\n¿Quieres usar ese texto como si fuera una contraseña y generar una clave privada usando un hash SHA256 de tal contraseña?\n\nAviso: Es importante escoger una contraseña fuerte para evitar ataques de fuerza bruta a fin de adivinarla y robar tus bitcoins.",
|
||
"bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.", //TODO: please translate
|
||
"bip38alertpassphraserequired": "Passphrase required for BIP38 key", //TODO: please translate
|
||
"vanityinvalidinputcouldnotcombinekeys": "Entrada no válida. No se puede combinar llaves.",
|
||
"vanityalertinvalidinputpublickeysmatch": "Entrada no válida. La clave pública de ambos coincidan entradas. Debe introducir dos claves diferentes.",
|
||
"vanityalertinvalidinputcannotmultiple": "Entrada no válida. No se puede multiplicar dos claves públicas. Seleccione 'Añadir' para agregar dos claves públicas para obtener una dirección bitcoin.",
|
||
"vanityprivatekeyonlyavailable": "Sólo está disponible cuando se combinan dos claves privadas",
|
||
"vanityalertinvalidinputprivatekeysmatch": "Entrada no válida. La clave privada de ambos coincidan entradas. Debe introducir dos claves diferentes.",
|
||
|
||
// header and menu html
|
||
"tagline": "Generador de carteras Bitcoin de código abierto en lado de cliente con Javascript",
|
||
"generatelabelbitcoinaddress": "Generando dirección Bitcoin...",
|
||
"generatelabelmovemouse": "Mueve un poco el ratón para crear entropía...",
|
||
"singlewallet": "Una sola cartera",
|
||
"paperwallet": "Cartera en papel",
|
||
"bulkwallet": "Direcciones en masa",
|
||
"brainwallet": "Cartera mental",
|
||
"vanitywallet": "Cartera personalizada",
|
||
"detailwallet": "Detalles de la cartera",
|
||
|
||
// footer html
|
||
"footerlabeldonations": "Donaciones:",
|
||
"footerlabeltranslatedby": "Traducción: <b>12345</b>Vypv2QSmuRXcciT5oEB27mPbWGeva",
|
||
"footerlabelpgp": "Clave pública PGP",
|
||
"footerlabelversion": "Histórico de versiones",
|
||
"footerlabelgithub": "Repositorio GitHub",
|
||
"footerlabelcopyright1": "Copyright bitaddress.org.",
|
||
"footerlabelcopyright2": "Copyright del código JavaScript: en el fuente.",
|
||
"footerlabelnowarranty": "Sin garantía.",
|
||
|
||
// single wallet html
|
||
"newaddress": "Generar dirección",
|
||
"singleprint": "Imprimir",
|
||
"singlelabelbitcoinaddress": "Dirección Bitcoin",
|
||
"singlelabelprivatekey": "Clave privada (formato para importar):",
|
||
|
||
// paper wallet html
|
||
"paperlabelhideart": "Ocultar diseño",
|
||
"paperlabeladdressesperpage": "Direcciones por página:",
|
||
"paperlabeladdressestogenerate": "Direcciones en total:",
|
||
"papergenerate": "Generar",
|
||
"paperprint": "Imprimir",
|
||
|
||
// bulk wallet html
|
||
"bulklabelstartindex": "Empezar en:",
|
||
"bulklabelrowstogenerate": "Filas a generar:",
|
||
"bulklabelcompressed": "Compressed addresses?", //TODO: please translate
|
||
"bulkgenerate": "Generar",
|
||
"bulkprint": "Imprimir",
|
||
"bulklabelcsv": "Valores separados por coma:",
|
||
"bulklabelformat": "Índice,Dirección,Clave privada (formato para importar)",
|
||
"bulklabelq1": "¿Por qué debo usar \"Direcciones en masa\" para aceptar Bitcoins en mi web?",
|
||
"bulka1": "La forma tradicional de aceptar bitcoins en tu web requiere tener instalado el cliente oficial de bitcoin (\"bitcoind\"). Sin embargo muchos servicios de hosting no permiten instalar dicho cliente. Además, ejecutar el cliente en tu servidor supone que las claves privadas están también en el servidor y podrían ser comprometidas en caso de intrusión. Al usar este mecanismo, puedes subir al servidor sólo las dirección de bitcoin y no las claves privadas. De esta forma no te tienes que preocupar de que alguien robe la cartera si se cuelan en el servidor.",
|
||
"bulklabelq2": "¿Cómo uso \"Direcciones en masa\" para aceptar bitcoins en mi web?",
|
||
"bulklabela2li1": "Usa el tab \"Direcciones en masa\" para generar por anticipado muchas direcciones (más de 10000). Copia y pega la lista de valores separados por comas (CSV) a un archivo de texto seguro (cifrado) en tu ordenador. Guarda una copia de seguridad en algún lugar seguro.",
|
||
"bulklabela2li2": "Importa las direcciones en la base de datos de tu servidor. No subas la cartera ni las claves públicas, o de lo contrario te lo pueden robar. Sube sólo las direcciones, ya que es lo que se va a mostrar a los clientes.",
|
||
"bulklabela2li3": "Ofrece una alternativa en el carro de la compra de tu web para que los clientes paguen con Bitcoin. Cuando el cliente elija pagar con Bitcoin, les muestras una de las direcciones de la base de datos como su \"dirección de pago\" y guardas esto junto con el pedido.",
|
||
"bulklabela2li4": "Ahora te hace falta recibir una notificación del pago. Busca en google \"notificación de pagos bitcoin\" (o \"bitcoin payment notification\" en inglés) y suscríbete a alguno de los servicios que aparezcan. Hay varios de ellos, que te pueden notificar vía Web services, API, SMS, email, etc. Una vez te llegue la notificación, lo cual puede ser automatizado, entonces ya puedes procesar el pedido. Para comprobar a mano si has recibido un pago, puedes usar Block Explorer: reemplaza DIRECCION a continuación por la dirección que estés comprobando. La transacción puede tardar entre 10 minutos y una hora en ser confirmada. <br />http://www.blockexplorer.com/address/DIRECCION<br /><br />Puedes ver las transacciones sin confirmar en: http://blockchain.info/ <br />Las transacciones sin confirmar suelen aparecer ahí en unos 30 segundos.",
|
||
"bulklabela2li5": "Las bitcoins que recibas se almacenarán de forma segura en la cadena de bloques. Usa la cartera original que generaste en el paso 1 para usarlas.",
|
||
|
||
// brain wallet html
|
||
"brainlabelenterpassphrase": "Contraseña:",
|
||
"brainlabelshow": "Mostrar",
|
||
"brainprint": "Imprimir",
|
||
"brainlabelconfirm": "Confirmar contraseña:",
|
||
"brainview": "Ver",
|
||
"brainalgorithm": "Algoritmo: SHA256(contraseña)",
|
||
"brainlabelbitcoinaddress": "Dirección Bitcoin:",
|
||
"brainlabelprivatekey": "Clave privada (formato para importar):",
|
||
|
||
// vanity wallet html
|
||
"vanitylabelstep1": "Paso 1 - Genera tu par de claves",
|
||
"vanitynewkeypair": "Generar",
|
||
"vanitylabelstep1publickey": "Clave pública:",
|
||
"vanitylabelstep1pubnotes": "Copia y pega la línea de arriba en el campo \"Your-Part-Public-Key\" de la web de Vanity Pool.",
|
||
"vanitylabelstep1privatekey": "Clave privada:",
|
||
"vanitylabelstep1privnotes": "Copia y pega la clave pública de arriba en un archivo de texto. Es mejor que lo almacenes en un volumen cifrado. Lo necesitarás para recuperar la clave privada una vez Vanity Pool haya encontrado tu prefijo.",
|
||
"vanitylabelstep2calculateyourvanitywallet": "Paso 2 - Calcula tu cartera personalizada",
|
||
"vanitylabelenteryourpart": "Introduce la clave privada generada en el paso 1, y que has guardado:",
|
||
"vanitylabelenteryourpoolpart": "Introduce la clave privada obtenida de la Vanity Pool:",
|
||
"vanitylabelnote1": "[NOTA: esta casilla de entrada puede aceptar una clave pública o clave privada]",
|
||
"vanitylabelnote2": "[NOTA: esta casilla de entrada puede aceptar una clave pública o clave privada]",
|
||
"vanitylabelradioadd": "Añadir",
|
||
"vanitylabelradiomultiply": "Multiplicar",
|
||
"vanitycalc": "Calcular cartera personalizada",
|
||
"vanitylabelbitcoinaddress": "Dirección Bitcoin personalizada:",
|
||
"vanitylabelnotesbitcoinaddress": "Esta es tu nueva dirección, que debería tener el prefijo deseado.",
|
||
"vanitylabelpublickeyhex": "Clave pública personalizada (HEX):",
|
||
"vanitylabelnotespublickeyhex": "Lo anterior es la clave pública en formato hexadecimal.",
|
||
"vanitylabelprivatekey": "Clave privada personalizada (formato para importar):",
|
||
"vanitylabelnotesprivatekey": "Esto es la clave privada para introducir en tu cartera.",
|
||
|
||
// detail wallet html
|
||
"detaillabelenterprivatekey": "Introduce la clave privada (en cualquier formato)",
|
||
"detailview": "Ver detalles",
|
||
"detailprint": "Imprimir",
|
||
"detaillabelnote1": "Tu clave privada es un número secreto, único, que sólo tú conoces. Se puede expresar en varios formatos. Aquí abajo mostramos la dirección y la clave pública que se corresponden con tu clave privada, así como la clave privada en los formatos más conocidos (para importar, hex, base64 y mini).",
|
||
"detaillabelnote2": "Bitcoin v0.6+ almacena las claves públicas comprimidas. El cliente también soporta importar/exportar claves privadas usando importprivkey/dumpprivkey. El formato de las claves privadas exportadas depende de si la dirección se generó en una cartera antigua o nueva.",
|
||
"detaillabelbitcoinaddress": "Dirección Bitcoin:",
|
||
"detaillabelbitcoinaddresscomp": "Dirección Bitcoin (comprimida):",
|
||
"detaillabelpublickey": "Clave pública (130 caracteres [0-9A-F]):",
|
||
"detaillabelpublickeycomp": "Clave pública (comprimida, 66 caracteres [0-9A-F]):",
|
||
"detaillabelprivwif": "Clave privada para importar (51 caracteres en base58, empieza con un",
|
||
"detaillabelprivwifcomp": "Clave privada para importar (comprimida, 52 caracteres en base58, empieza con",
|
||
"detailcompwifprefix": "'K' o 'L'",
|
||
"detaillabelprivhex": "Clave privada en formato hexadecimal (64 caracteres [0-9A-F]):",
|
||
"detaillabelprivb64": "Clave privada en base64 (44 caracteres):",
|
||
"detaillabelprivmini": "Clave privada en formato mini (22, 26 o 30 caracteres, empieza por 'S'):",
|
||
"detaillabelpassphrase": "BIP38 Passphrase", //TODO: please translate
|
||
"detaildecrypt": "Decrypt BIP38" //TODO: please translate
|
||
},
|
||
|
||
"fr": {
|
||
"testneteditionactivated": "ÉDITION TESTNET ACTIVÉE",
|
||
"paperlabelbitcoinaddress": "Adresse Bitcoin:",
|
||
"paperlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
|
||
"bulkgeneratingaddresses": "Création de l'adresse... ",
|
||
"brainalertpassphrasetooshort": "Le mot de passe que vous avez entré est trop court.\n\nAttention: Choisir un mot de passe solide est important pour vous protéger des attaques bruteforce visant à trouver votre mot de passe et voler vos Bitcoins.",
|
||
"brainalertpassphrasedoesnotmatch": "Le mot de passe ne correspond pas au mot de passe de vérification.",
|
||
"detailalertnotvalidprivatekey": "Le texte que vous avez entré n'est pas une Clé Privée valide",
|
||
"detailconfirmsha256": "Le texte que vous avez entré n'est pas une Clé Privée valide!\n\nVoulez-vous utiliser le texte comme un mot de passe et créer une Clé Privée à partir d'un hash SHA256 de ce mot de passe?\n\nAttention: Choisir un mot de passe solide est important pour vous protéger des attaques bruteforce visant à trouver votre mot de passe et voler vos Bitcoins.",
|
||
"bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.", //TODO: please translate
|
||
"bip38alertpassphraserequired": "Passphrase required for BIP38 key", //TODO: please translate
|
||
"vanityinvalidinputcouldnotcombinekeys": "Entrée non valide. Impossible de combiner les clés.",
|
||
"vanityalertinvalidinputpublickeysmatch": "Entrée non valide. La clé publique des deux entrées est identique. Vous devez entrer deux clés différentes.",
|
||
"vanityalertinvalidinputcannotmultiple": "Entrée non valide. Il n'est pas possible de multiplier deux clés publiques. Sélectionner 'Ajouter' pour ajouter deux clés publiques pour obtenir une adresse Bitcoin.",
|
||
"vanityprivatekeyonlyavailable": "Seulement disponible si vos combinez deux clés privées",
|
||
"vanityalertinvalidinputprivatekeysmatch": "Entrée non valide. La clé Privée des deux entrées est identique. Vous devez entrer deux clés différentes.",
|
||
"tagline": "Générateur De Porte-Monnaie Bitcoin Javascript Hors-Ligne",
|
||
"generatelabelbitcoinaddress": "Création de l'adresse Bitcoin...",
|
||
"generatelabelmovemouse": "BOUGEZ votre souris pour ajouter de l'entropie...",
|
||
"singlewallet": "Porte-Monnaie Simple",
|
||
"paperwallet": "Porte-Monnaie Papier",
|
||
"bulkwallet": "Porte-Monnaie En Vrac",
|
||
"brainwallet": "Porte-Monnaie Cerveau",
|
||
"vanitywallet": "Porte-Monnaie Vanité",
|
||
"detailwallet": "Détails du Porte-Monnaie",
|
||
"footerlabeldonations": "Dons:",
|
||
"footerlabeltranslatedby": "Traduction: 1Gy7NYSJNUYqUdXTBow5d7bCUEJkUFDFSq",
|
||
"footerlabelpgp": "Clé Publique PGP",
|
||
"footerlabelversion": "Historique De Version Signé",
|
||
"footerlabelgithub": "Dépôt GitHub",
|
||
"footerlabelcopyright1": "Copyright bitaddress.org.",
|
||
"footerlabelcopyright2": "Les droits d'auteurs JavaScript sont inclus dans le code source.",
|
||
"footerlabelnowarranty": "Aucune garantie.",
|
||
"newaddress": "Générer Une Nouvelle Adresse",
|
||
"singleprint": "Imprimer",
|
||
"singlelabelbitcoinaddress": "Adresse Bitcoin:",
|
||
"singlelabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
|
||
"paperlabelhideart": "Retirer Le Style?",
|
||
"paperlabeladdressesperpage": "Adresses par page:",
|
||
"paperlabeladdressestogenerate": "Nombre d'adresses à créer:",
|
||
"papergenerate": "Générer",
|
||
"paperprint": "Imprimer",
|
||
"bulklabelstartindex": "Commencer à l'index:",
|
||
"bulklabelrowstogenerate": "Colonnes à générer:",
|
||
"bulklabelcompressed": "Compressed addresses?", //TODO: please translate
|
||
"bulkgenerate": "Générer",
|
||
"bulkprint": "Imprimer",
|
||
"bulklabelcsv": "Valeurs Séparées Par Des Virgules (CSV):",
|
||
"bulklabelformat": "Index,Adresse,Clé Privée (WIF)",
|
||
"bulklabelq1": "Pourquoi utiliserais-je un Porte-monnaie en vrac pour accepter les Bitcoins sur mon site web?",
|
||
"bulka1": "L'approche traditionnelle pour accepter des Bitcoins sur votre site web requière l'installation du logiciel Bitcoin officiel (\"bitcoind\"). Plusieurs hébergeurs ne supportent pas l'installation du logiciel Bitcoin. De plus, faire fonctionner le logiciel Bitcoin sur votre serveur web signifie que vos clés privées sont hébergées sur le serveur et pourraient donc être volées si votre serveur web était compromis. En utilisant un Porte-monnaie en vrac, vous pouvez publiquer seulement les adresses Bitcoin sur votre serveur et non les clés privées. Vous n'avez alors pas à vous inquiéter du risque de vous faire voler votre porte-monnaie si votre serveur était compromis.",
|
||
"bulklabelq2": "Comment utiliser le Porte-monnaie en vrac pour utiliser le Bitcoin sur mon site web?",
|
||
"bulklabela2li1": "Utilisez le Porte-monnaie en vrac pour pré-générer une large quantité d'adresses Bitcoin (10,000+). Copiez collez les données séparées par des virgules (CSV) dans un fichier texte sécurisé dans votre ordinateur. Sauvegardez ce fichier dans un endroit sécurisé.",
|
||
"bulklabela2li2": "Importez les adresses Bitcoin dans une base de donnée sur votre serveur web. (N'ajoutez pas le porte-monnaie ou les clés privées sur votre serveur web, sinon vous courrez le risque de vous faire voler si votre serveur est compromis. Ajoutez seulement les adresses Bitcoin qui seront visibles à vos visiteurs.)",
|
||
"bulklabela2li3": "Ajoutez une option dans votre panier en ligne pour que vos clients puissent vous payer en Bitcoin. Quand un client choisi de vous payer en Bitcoin, vous pouvez afficher une des adresses de votre base de donnée comme \"adresse de paiment\" pour votre client et sauvegarder cette adresse avec sa commande.",
|
||
"bulklabela2li4": "Vous avez maintenant besoin d'être avisé quand le paiement est reçu. Cherchez \"bitcoin payment notification\" sur Google et inscrivez-vous à un service de notification de paiement Bitcoin. Il y a plusieurs services qui vous avertiront via des services Web, API, SMS, Email, etc. Une fois que vous avez reçu la notification, qui devrait être programmée automatiquement, vous pouvez traiter la commande de votre client. Pour vérifier manuellement si un paiement est arrivé, vous pouvez utiliser Block Explorer. Remplacez ADRESSE par l'adresse Bitcoin que vous souhaitez vérifier. La confirmation de la transaction pourrait prendre de 10 à 60 minutes pour être confirmée.<br />http://www.blockexplorer.com/address/ADRESSE<br /><br />Les transactions non confirmées peuvent être visualisées ici: http://blockchain.info/ <br />Vous devriez voir la transaction à l'intérieur de 30 secondes.",
|
||
"bulklabela2li5": "Les Bitcoins vos s'accumuler de façon sécuritaire dans la chaîne de blocs. Utilisez le porte-monnaie original que vous avez généré à l'étape 1 pour les dépenser.",
|
||
"brainlabelenterpassphrase": "Entrez votre mot de passe: ",
|
||
"brainlabelshow": "Afficher?",
|
||
"brainprint": "Imprimer",
|
||
"brainlabelconfirm": "Confirmer le mot de passe: ",
|
||
"brainview": "Visualiser",
|
||
"brainalgorithm": "Algorithme: SHA256(mot de passe)",
|
||
"brainlabelbitcoinaddress": "Adresse Bitcoin:",
|
||
"brainlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
|
||
"vanitylabelstep1": "Étape 1 - Générer votre \"Étape 1 Paire De Clés\"",
|
||
"vanitynewkeypair": "Générer",
|
||
"vanitylabelstep1publickey": "Étape 1 Clé Publique:",
|
||
"vanitylabelstep1pubnotes": "Copiez celle-ci dans la case Votre-Clé-Publique du site de Vanity Pool.",
|
||
"vanitylabelstep1privatekey": "Step 1 Clé Privée:",
|
||
"vanitylabelstep1privnotes": "Copiez la cette Clé Privée dans un fichier texte. Idéalement, sauvegardez la dans un fichier encrypté. Vous en aurez besoin pour récupérer la Clé Privée lors que Vanity Pool aura trouvé votre préfixe.",
|
||
"vanitylabelstep2calculateyourvanitywallet": "Étape 2 - Calculer votre Porte-monnaie Vanité",
|
||
"vanitylabelenteryourpart": "Entrez votre Clé Privée (générée à l'étape 1 plus haut et précédemment sauvegardée):",
|
||
"vanitylabelenteryourpoolpart": "Entrez la Clé Privée (provenant de Vanity Pool):",
|
||
"vanitylabelnote1": "[NOTE: cette case peut accepter une clé publique ou un clé privée]",
|
||
"vanitylabelnote2": "[NOTE: cette case peut accepter une clé publique ou un clé privée]",
|
||
"vanitylabelradioadd": "Ajouter",
|
||
"vanitylabelradiomultiply": "Multiplier",
|
||
"vanitycalc": "Calculer Le Porte-monnaie Vanité",
|
||
"vanitylabelbitcoinaddress": "Adresse Bitcoin Vanité:",
|
||
"vanitylabelnotesbitcoinaddress": "Ci-haut est votre nouvelle adresse qui devrait inclure le préfix requis.",
|
||
"vanitylabelpublickeyhex": "Clé Public Vanité (HEX):",
|
||
"vanitylabelnotespublickeyhex": "Celle-ci est la Clé Publique dans le format hexadécimal. ",
|
||
"vanitylabelprivatekey": "Clé Privée Vanité (WIF):",
|
||
"vanitylabelnotesprivatekey": "Celle-ci est la Clé Privée pour accéder à votre porte-monnaie. ",
|
||
"detaillabelenterprivatekey": "Entrez la Clé Privée (quel que soit son format)",
|
||
"detailview": "Voir les détails",
|
||
"detailprint": "Imprimer",
|
||
"detaillabelnote1": "Votre Clé Privée Bitcoin est un nombre secret que vous êtes le seul à connaître. Il peut être encodé sous la forme d'un nombre sous différents formats. Ci-bas, nous affichons l'adresse Bitcoin et la Clé Publique qui corresponds à la Clé Privée ainsi que la Clé Privée dans les formats d'encodage les plus populaires (WIF, HEX, B64, MINI).",
|
||
"detaillabelnote2": "Bitcoin v0.6+ conserve les clés publiques dans un format compressé. Le logiciel supporte maintenant aussi l'importation et l'exportation de clés privées avec importprivkey/dumpprivkey. Le format de la clé privée exportée est déterminé selon la version du porte-monnaie Bitcoin.",
|
||
"detaillabelbitcoinaddress": "Adresse Bitcoin:",
|
||
"detaillabelbitcoinaddresscomp": "Adresse Bitcoin (compressée):",
|
||
"detaillabelpublickey": "Clé Publique (130 caractères [0-9A-F]):",
|
||
"detaillabelpublickeycomp": "Clé Publique (compressée, 66 caractères [0-9A-F]):",
|
||
"detaillabelprivwif": "Clé Privée WIF (51 caractères base58, débute avec un a",
|
||
"detaillabelprivwifcomp": "Clé Privée WIF (compressée, 52 caractères base58, débute avec un a",
|
||
"detailcompwifprefix": "'K' ou 'L'",
|
||
"detaillabelprivhex": "Clé Privée Format Hexadecimal (64 caractères [0-9A-F]):",
|
||
"detaillabelprivb64": "Clé Privée Base64 (44 caractères):",
|
||
"detaillabelprivmini": "Clé Privée Format Mini (22, 26 ou 30 caractères, débute avec un 'S'):",
|
||
"detaillabelpassphrase": "BIP38 Passphrase", //TODO: please translate
|
||
"detaildecrypt": "Decrypt BIP38" //TODO: please translate
|
||
},
|
||
|
||
"el": {
|
||
// javascript alerts or messages
|
||
"testneteditionactivated": "ΕΝΕΡΓΗ ΕΚΔΟΣΗ TESTNET",
|
||
"paperlabelbitcoinaddress": "Διεύθυνση Bitcoin:",
|
||
"paperlabelprivatekey": "Προσωπικό Κλειδί (Μορφή εισαγωγής σε πορτοφόλι):",
|
||
"bulkgeneratingaddresses": "Δημιουργία διευθύνσεων... ",
|
||
"brainalertpassphrasetooshort": "Η φράση κωδικός που δώσατε είναι πολύ αδύναμη.\n\nΠροσοχή: Είναι σημαντικό να επιλέξετε μια ισχυρή φράση κωδικό που θα σας προφυλάξει από απόπειρες παραβίασής της τύπου brute force και κλοπή των bitcoins σας.",
|
||
"brainalertpassphrasedoesnotmatch": "Η φράση κωδικός και η επιβεβαίωση της δε συμφωνούν.",
|
||
"detailalertnotvalidprivatekey": "Το κείμενο που εισάγατε δεν αντιστοιχεί σε έγκυρο Προσωπικό Κλειδί",
|
||
"detailconfirmsha256": "Το κείμενο που εισάγατε δεν αντιστοιχεί σε έγκυρο Προσωπικό Κλειδί!\n\nΘα θέλατε να χρησιμοποιηθεί το κείμενο ως κωδικός για τη δημιουργία ενός Προσωπικού Κλειδιού που θα δημιουργηθεί από το SHA265 hash της φράσης κωδικού;\n\nΠροσοχή: Είναι σημαντικό να επιλέξετε έναν ισχυρό κωδικό ώστε να είναι δύσκολο να τον μαντέψει κάποιος και να κλέψει τα bitcoins σας.",
|
||
"bip38alertincorrectpassphrase": "Λάθος φράση κωδικός αποκρυπτογράφησης Προσωπικού Κλειδιού.",
|
||
"bip38alertpassphraserequired": "Απαιτείται η φράση κωδικός για το Κλειδί BIP38",
|
||
"vanityinvalidinputcouldnotcombinekeys": "Μη έγκυρη εισαγωγή. Ο συνδυασμός των κλειδιών είναι αδύνατος.",
|
||
"vanityalertinvalidinputpublickeysmatch": "Μη έγκυρη εισαγωγή. Τα Δημόσια Κλειδιά των δύο εγγραφών είναι όμοια. Πρέπει να εισάγετε δύο διαφορετικά Κλειδιά.",
|
||
"vanityalertinvalidinputcannotmultiple": "Μη έγκυρη εισαγωγή. Δεν είναι δυνατός ο πολλαπλασιασμός δύο Δημόσιων Κλειδιών. Επιλέξτε 'Πρόσθεση' για να προσθέσετε δύο Δημόσια Κλειδιά για δημιουργία μίας Διεύθυνσης Bitcoin.",
|
||
"vanityprivatekeyonlyavailable": "Διαθέσιμο μόνο κατά το συνδυασμό δύο Προσωπικών Κλειδιών",
|
||
"vanityalertinvalidinputprivatekeysmatch": "Μη έγκυρη εισαγωγή. Τα Προσωπικά Κλειδιά των δύο εγγραφών είναι όμοια. Πρέπει να εισάγετε δύο διαφορετικά Κλειδιά.",
|
||
|
||
// header and menu html
|
||
"tagline": "Δημιουργός Διευθύνσεων Bitcoin, ανοικτού κώδικα Javascript",
|
||
"generatelabelbitcoinaddress": "Δημιουργία Διεύθυνσης Bitcoin...",
|
||
"generatelabelmovemouse": "ΚΟΥΝΗΣΤΕ το ποντίκι τριγύρω για να προσθέσετε επιπλέον τυχαιότητα...",
|
||
"singlewallet": "Απλό Πορτοφόλι",
|
||
"paperwallet": "Χάρτινο Πορτοφόλι",
|
||
"bulkwallet": "Πολλαπλά Πορτοφόλια",
|
||
"brainwallet": "Μνημονικό Πορτοφόλι",
|
||
"vanitywallet": "Πορτοφόλι Vanity",
|
||
"detailwallet": "Λεπτομέρειες Πορτοφολιού",
|
||
|
||
// footer html
|
||
"footerlabeldonations": "Δωρεές:",
|
||
"footerlabeltranslatedby": "Μετάφραση: <a href='http://BitcoinX.gr/'><b>BitcoinX.gr</b></a> 1BitcoiNxkUPcTFxwMqxhRiPEiQRzYskf6",
|
||
"footerlabelpgp": "Δημόσιο Κλειδί PGP",
|
||
"footerlabelversion": "Υπογεγραμένο ιστορικό εκδόσεων",
|
||
"footerlabelgithub": "Αποθετήριο GitHub",
|
||
"footerlabelcopyright1": "Copyright bitaddress.org.",
|
||
"footerlabelcopyright2": "Τα πνευματικά δικαιώματα της JavaScript περιλαμβάνονται στον κώδικα.",
|
||
"footerlabelnowarranty": "Καμία εγγύηση.",
|
||
|
||
// single wallet html
|
||
"newaddress": "Δημιουργία μιας νέας Διεύθυνσης",
|
||
"singleprint": "Εκτύπωση",
|
||
"singlelabelbitcoinaddress": "Διεύθυνση Bitcoin:",
|
||
"singlelabelprivatekey": "Προσωπικό Κλειδί (Μορφή εισαγωγής σε πορτοφόλι):",
|
||
|
||
// paper wallet html
|
||
"paperlabelhideart": "Απόκρυψη γραφικού;",
|
||
"paperlabeladdressesperpage": "Διευθύνσεις ανά σελίδα:",
|
||
"paperlabeladdressestogenerate": "Πλήθος διευθύνσεων:",
|
||
"papergenerate": "Δημιουργία",
|
||
"paperprint": "Εκτύπωση",
|
||
|
||
// bulk wallet html
|
||
"bulklabelstartindex": "Ξεκίνημα δείκτη:",
|
||
"bulklabelrowstogenerate": "Πλήθος σειρών:",
|
||
"bulklabelcompressed": "Συμπιεσμένες διευθύνσεις;",
|
||
"bulkgenerate": "Δημιουργία",
|
||
"bulkprint": "Εκτύπωση",
|
||
"bulklabelcsv": "Τιμές που χωρίζονται με κόμμα (CSV):",
|
||
"bulklabelformat": "Δείκτης,Διεύθυνση,Προσωπικό Κλειδί (WIF)",
|
||
"bulklabelq1": "Γιατί να χρησιμοποιήσω Πολλαπλά Πορτοφόλια στην ιστοσελίδα μου;",
|
||
"bulka1": "Ο παραδοσιακός τρόπος για να δέχεστε bitcoins στην ιστοσελίδα σας, απαιτεί την εγκατάσταση και λειτουργία του επίσημου δαίμονα πελάτη bitcoin (\"bitcoind\"). Αρκετά πακέτα φιλοξενίας δεν υποστηρίζουν την εγκατάστασή του. Επιπλέον, η εκτέλεση του πελάτη bitcoin στον web server σας συνεπάγεται και τη φιλοξενία των προσωπικών σας κλειδιών στον ίδιο server, τα οποία μπορεί να υποκλαπούν αν ο server πέσει θύμα επίθεσης. Χρησιμοποιώντας τα Πολλαπλά Πορτοφόλια, ανεβάζετε στον server σας μόνο τις διευθύνσεις Bitcoin κι όχι τα προσωπικά κλειδιά. Με αυτό τον τρόπο δεν χρειάζεται να ανησυχείτε μήπως υποκλαπεί το πορτοφόλι σας.",
|
||
"bulklabelq2": "Πως χρησιμοποιώ τα Πολλαπλά Πορτοφόλια για να δέχομαι bitcoins στην ιστοσελίδα μου;",
|
||
"bulklabela2li1": "Χρησιμοποιήστε την καρτέλα Πολλαπλά Πορτοφόλια για να δημιουργήσετε έναν μεγάλο αριθμό διευθύνσεων Bitcoin (10.000+). Αντιγράψτε κι επικολλήστε τη λίστα των χωρισμένων με κόμμα τιμών (CSV) που δημιουργήθηκαν, σε ένα ασφαλές αρχείο στον υπολογιστή σας. Αντιγράψτε το αρχείο που δημιουργήσατε σε μια ασφαλή τοποθεσία.",
|
||
"bulklabela2li2": "Εισάγετε τις διευθύνσεις Bitcoin σε έναν πίνακα βάσης δεδομένων στον web server σας. (Μην αντιγράψετε τα προσωπικά κλειδιά ή το πορτοφόλι στον web server γιατί διακινδυνεύετε να σας τα κλέψουν. Μόνο τις διευθύνσεις Bitcoin που θα εμφανίζονται στους πελάτες.)",
|
||
"bulklabela2li3": "Παρέχετε στο καλάθι αγορών σας μια επιλογή για πληρωμή σε Bitcoin. Όταν ο πελάτης επιλέγει να πληρώσει με Bitcoin, θα εμφανίσετε σε αυτόν μια από τις διευθύνσεις από τη βάση δεδομένων, ως την «προσωπική του διεύθυνση πληρωμής» την οποία θα αποθηκεύσετε μαζί με την εντολή αγοράς.",
|
||
"bulklabela2li4": "Τώρα χρειάζεται να ειδοποιηθείτε μόλις γίνει η πληρωμή. Ψάξτε στο Google για «bitcoin payment notification» κι εγγραφείτε σε τουλάχιστο μία υπηρεσία ειδοποίησης πληρωμής. Υπάρχουν διάφορες υπηρεσίες που θα σας ειδοποιήσουν με Web υπηρεσίες, API, SMS, Email, κλπ. Όταν λάβετε την ειδοποίηση, η οποία μπορεί να αυτοματοποιηθεί προγραμματιστικά, εκτελείτε την εντολή του πελάτη. Για να ελέγξετε χειροκίνητα την πληρωμή μπορείτε να χρησιμοποιήσετε τον Block Explorer. Αντικαταστήστε το THEADDRESSGOESHERE με τη Bitcoin διεύθυνσή σας. Η επιβεβαίωση της πληρωμής ενδέχεται να διαρκέσει από δέκα λεπτά έως μία ώρα.<br />http://www.blockexplorer.com/address/THEADDRESSGOESHERE<br /><br />Μπορείτε να δείτε τις συναλλαγές που δεν έχουν επιβεβαιωθεί στο: http://blockchain.info/ <br />Θα πρέπει να δείτε τη συναλλαγή εκεί εντός 30 δευτερολέπτων.",
|
||
"bulklabela2li5": "Τα Bitcoins θα συσσωρεύονται με ασφάλεια στην αλυσίδα των μπλοκ. Χρησιμοποιήστε το αρχικό πορτοφόλι που δημιουργήσατε στο βήμα 1 για να τα ξοδέψετε.",
|
||
|
||
// brain wallet html
|
||
"brainlabelenterpassphrase": "Εισάγετε κωδικό: ",
|
||
"brainlabelshow": "Εμφάνιση;",
|
||
"brainprint": "Εκτύπωση",
|
||
"brainlabelconfirm": "Επιβεβαιώστε τον κωδικό: ",
|
||
"brainview": "Δημιουργία",
|
||
"brainalgorithm": "Αλγόριθμος: SHA256(κωδικός)",
|
||
"brainlabelbitcoinaddress": "Διεύθυνση Bitcoin:",
|
||
"brainlabelprivatekey": "Προσωπικό Κλειδί (Μορφή εισαγωγής σε πορτοφόλι):",
|
||
|
||
// vanity wallet html
|
||
"vanitylabelstep1": "Βήμα 1 - Δημιουργήστε το «Ζεύγος κλειδιών του Βήματος 1»",
|
||
"vanitynewkeypair": "Δημιουργία",
|
||
"vanitylabelstep1publickey": "Βήμα 1 Δημόσιο Κλειδί:",
|
||
"vanitylabelstep1pubnotes": "Αντιγράψτε κι επικολλήστε το παραπάνω στο πεδίο Your-Part-Public-Key στην ιστοσελίδα του Vanity Pool.",
|
||
"vanitylabelstep1privatekey": "Step 1 Προσωπικό Κλειδί:",
|
||
"vanitylabelstep1privnotes": "Αντιγράψτε κι επικολλήστε το παραπάνω Προσωπικό Κλειδί σε ένα αρχείο κειμένου. Ιδανικά, αποθηκεύστε το σε έναν κρυπτογραφημένο δίσκο. Θα το χρειαστείτε για να ανακτήσετε το Bitcoin Προσωπικό Κλειδί όταν βρεθεί το πρόθεμά σας από το Vanity Pool.",
|
||
"vanitylabelstep2calculateyourvanitywallet": "Βήμα 2 - Υπολογίστε το Vanity Πορτοφόλι σας.",
|
||
"vanitylabelenteryourpart": "Εισάγετε το Προσωπικό Κλειδί που δημιουργήσατε στο Βήμα 1 κι αποθηκεύσατε:",
|
||
"vanitylabelenteryourpoolpart": "Εισάγετε το Προσωπικό Κλειδί από το Vanity Pool:",
|
||
"vanitylabelnote1": "[ΣΗΜΕΙΩΣΗ: Το πεδίο αυτό μπορεί να δεχθεί είτε ένα Δημόσιο είτε ένα Προσωπικό Κλειδί.]",
|
||
"vanitylabelnote2": "[ΣΗΜΕΙΩΣΗ: Το πεδίο αυτό μπορεί να δεχθεί είτε ένα Δημόσιο είτε ένα Προσωπικό Κλειδί.]",
|
||
"vanitylabelradioadd": "Πρόσθεσε",
|
||
"vanitylabelradiomultiply": "Πολλαπλασίασε",
|
||
"vanitycalc": "Υπολογισμός του Πορτοφολιού Vanity",
|
||
"vanitylabelbitcoinaddress": "Vanity Διεύθυνση Bitcoin:",
|
||
"vanitylabelnotesbitcoinaddress": "Παραπάνω είναι η διεύθυνσή σας που θα πρέπει να περιλαμβάνει το επιθυμητό πρόθεμα.",
|
||
"vanitylabelpublickeyhex": "Vanity Δημόσιο Κλειδί (HEX):",
|
||
"vanitylabelnotespublickeyhex": "Παραπάνω είναι το Δημόσιο Κλειδί σε δεκαεξαδική μορφή. ",
|
||
"vanitylabelprivatekey": "Vanity Προσωπικό Κλειδί (WIF):",
|
||
"vanitylabelnotesprivatekey": "Παραπάνω είναι το Προσωπικό Κλειδί που θα φορτώσετε στο Πορτοφόλι σας. ",
|
||
|
||
// detail wallet html
|
||
"detaillabelenterprivatekey": "Εισάγετε το Προσωπικό Κλειδί (οποιαδήποτε μορφή)",
|
||
"detailview": "Προβολή λεπτομερειών",
|
||
"detailprint": "Εκτύπωση",
|
||
"detaillabelnote1": "Το Bitcoin Προσωπικό Κλειδί είναι ένας μοναδικός και μυστικός αριθμός που μόνο εσείς πρέπει να γνωρίζετε, ο οποίος μπορεί να κωδικοποιηθεί σε πολλές διαφορετικές μορφές. Εμφανίζουμε παρακάτω τη διεύθυνση Bitcoin και το Δημόσιο Κλειδί, μαζί με το Προσωπικό Κλειδί, στις πιο δημοφιλείς μορφές (WIF, HEX, B64, MINI).",
|
||
"detaillabelnote2": "Το Bitcoin v0.6+ αποθηκεύει τα Προσωπικά Κλειδιά σε συμπιεσμένη μορφή. Το πρόγραμμα υποστηρίζει επίσης εισαγωγή κι εξαγωγή των Προσωπικών Κλειδιών με τις εντολές importprivkey/dumpprivkey. Η μορφή του εξαγόμενου Προσωπικού Κλειδιού προσδιορίζεται από το αν η διεύθυνση δημιουργήθηκε σε ένα παλιό ή νέο πορτοφόλι.",
|
||
"detaillabelbitcoinaddress": "Διεύθυνση Bitcoin:",
|
||
"detaillabelbitcoinaddresscomp": "Συμπιεσμένη Διεύθυνση Bitcoin:",
|
||
"detaillabelpublickey": "Δημόσιο Κλειδί (130 χαρακτήρες [0-9A-F]):",
|
||
"detaillabelpublickeycomp": "Δημόσιο Κλειδί (Συμπιεσμένο, 66 χαρακτήρες [0-9A-F]):",
|
||
"detaillabelprivwif": "Προσωπικό Κλειδί WIF (51 χαρακτήρες base58, ξεκινάει με",
|
||
"detaillabelprivwifcomp": "Προσωπικό Κλειδί WIF (Συμπιεσμένο, 52 χαρακτήρες base58, ξεκινάει με",
|
||
"detailcompwifprefix": "'K' ή 'L'",
|
||
"detaillabelprivhex": "Προσωπικό Κλειδί Δεκαεξαδική Μορφή (64 χαρακτήρες [0-9A-F]):",
|
||
"detaillabelprivb64": "Προσωπικό Κλειδί Base64 (44 χαρακτήρες):",
|
||
"detaillabelprivmini": "Προσωπικό Κλειδί Μορφή Mini (22, 26 ή 30 χαρακτήρες, ξεκινάει με 'S'):",
|
||
"detaillabelpassphrase": "BIP38 Κωδικός",
|
||
"detaildecrypt": "Αποκωδικοποίηση BIP38"
|
||
}
|
||
|
||
}
|
||
};
|
||
|
||
ninja.translator.showEnglishJson = function () {
|
||
var english = ninja.translator.translations["en"];
|
||
var spanish = ninja.translator.translations["es"];
|
||
var spanishClone = {};
|
||
for (var key in spanish) {
|
||
spanishClone[key] = spanish[key];
|
||
}
|
||
var newLang = {};
|
||
for (var key in english) {
|
||
newLang[key] = english[key];
|
||
delete spanishClone[key];
|
||
}
|
||
for (var key in spanishClone) {
|
||
if (document.getElementById(key)) {
|
||
if (document.getElementById(key).value) {
|
||
newLang[key] = document.getElementById(key).value;
|
||
}
|
||
else {
|
||
newLang[key] = document.getElementById(key).innerHTML;
|
||
}
|
||
}
|
||
}
|
||
var div = document.createElement("div");
|
||
div.setAttribute("class", "englishjson");
|
||
div.innerHTML = "<h3>English Json</h3>";
|
||
var elem = document.createElement("textarea");
|
||
elem.setAttribute("rows", "35");
|
||
elem.setAttribute("cols", "110");
|
||
elem.setAttribute("wrap", "off");
|
||
var langJson = "{\n";
|
||
for (var key in newLang) {
|
||
langJson += "\t\"" + key + "\"" + ": " + "\"" + newLang[key].replace(/\"/g, "\\\"").replace(/\n/g, "\\n") + "\",\n";
|
||
}
|
||
langJson = langJson.substr(0, langJson.length - 2);
|
||
langJson += "\n}\n";
|
||
elem.innerHTML = langJson;
|
||
div.appendChild(elem);
|
||
document.body.appendChild(div);
|
||
};
|
||
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.wallets.singlewallet = {
|
||
open: function () {
|
||
if (document.getElementById("btcaddress").innerHTML == "") {
|
||
ninja.wallets.singlewallet.generateNewAddressAndKey();
|
||
}
|
||
document.getElementById("singlearea").style.display = "block";
|
||
},
|
||
|
||
close: function () {
|
||
document.getElementById("singlearea").style.display = "none";
|
||
},
|
||
|
||
// 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();
|
||
var privateKeyWif = key.getBitcoinWalletImportFormat();
|
||
document.getElementById("btcaddress").innerHTML = bitcoinAddress;
|
||
document.getElementById("btcprivwif").innerHTML = privateKeyWif;
|
||
var keyValuePair = {
|
||
"qrcode_public": bitcoinAddress,
|
||
"qrcode_private": privateKeyWif
|
||
};
|
||
ninja.qrCode.showQrCode(keyValuePair);
|
||
}
|
||
catch (e) {
|
||
// browser does not have sufficient JavaScript support to generate a bitcoin address
|
||
alert(e);
|
||
document.getElementById("btcaddress").innerHTML = "error";
|
||
document.getElementById("btcprivwif").innerHTML = "error";
|
||
document.getElementById("qrcode_public").innerHTML = "";
|
||
document.getElementById("qrcode_private").innerHTML = "";
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.wallets.paperwallet = {
|
||
open: function () {
|
||
document.getElementById("main").setAttribute("class", "paper"); // add 'paper' class to main div
|
||
var paperArea = document.getElementById("paperarea");
|
||
paperArea.style.display = "block";
|
||
var perPageLimitElement = document.getElementById("paperlimitperpage");
|
||
var limitElement = document.getElementById("paperlimit");
|
||
var pageBreakAt = (ninja.wallets.paperwallet.useArtisticWallet) ? ninja.wallets.paperwallet.pageBreakAtArtisticDefault : ninja.wallets.paperwallet.pageBreakAtDefault;
|
||
if (perPageLimitElement && perPageLimitElement.value < 1) {
|
||
perPageLimitElement.value = pageBreakAt;
|
||
}
|
||
if (limitElement && limitElement.value < 1) {
|
||
limitElement.value = pageBreakAt;
|
||
}
|
||
if (document.getElementById("paperkeyarea").innerHTML == "") {
|
||
ninja.wallets.paperwallet.build(pageBreakAt, pageBreakAt, !document.getElementById('paperart').checked);
|
||
}
|
||
},
|
||
|
||
close: function () {
|
||
document.getElementById("paperarea").style.display = "none";
|
||
document.getElementById("main").setAttribute("class", ""); // remove 'paper' class from main div
|
||
},
|
||
|
||
remaining: null, // use to keep track of how many addresses are left to process when building the paper wallet
|
||
count: 0,
|
||
pageBreakAtDefault: 7,
|
||
pageBreakAtArtisticDefault: 3,
|
||
useArtisticWallet: true,
|
||
pageBreakAt: null,
|
||
|
||
build: function (numWallets, pageBreakAt, useArtisticWallet) {
|
||
if (numWallets < 1) numWallets = 1;
|
||
if (pageBreakAt < 1) pageBreakAt = 1;
|
||
ninja.wallets.paperwallet.remaining = numWallets;
|
||
ninja.wallets.paperwallet.count = 0;
|
||
ninja.wallets.paperwallet.useArtisticWallet = useArtisticWallet;
|
||
ninja.wallets.paperwallet.pageBreakAt = pageBreakAt;
|
||
document.getElementById("paperkeyarea").innerHTML = "";
|
||
setTimeout(ninja.wallets.paperwallet.batch, 0);
|
||
},
|
||
|
||
batch: function () {
|
||
if (ninja.wallets.paperwallet.remaining > 0) {
|
||
var paperArea = document.getElementById("paperkeyarea");
|
||
ninja.wallets.paperwallet.count++;
|
||
var i = ninja.wallets.paperwallet.count;
|
||
var pageBreakAt = ninja.wallets.paperwallet.pageBreakAt;
|
||
var div = document.createElement("div");
|
||
div.setAttribute("id", "keyarea" + i);
|
||
if (ninja.wallets.paperwallet.useArtisticWallet) {
|
||
div.innerHTML = ninja.wallets.paperwallet.templateArtisticHtml(i);
|
||
div.setAttribute("class", "keyarea art");
|
||
}
|
||
else {
|
||
div.innerHTML = ninja.wallets.paperwallet.templateHtml(i);
|
||
div.setAttribute("class", "keyarea");
|
||
}
|
||
if (paperArea.innerHTML != "") {
|
||
// page break
|
||
if ((i - 1) % pageBreakAt == 0 && i >= pageBreakAt) {
|
||
var pBreak = document.createElement("div");
|
||
pBreak.setAttribute("class", "pagebreak");
|
||
document.getElementById("paperkeyarea").appendChild(pBreak);
|
||
div.style.pageBreakBefore = "always";
|
||
if (!ninja.wallets.paperwallet.useArtisticWallet) {
|
||
div.style.borderTop = "2px solid green";
|
||
}
|
||
}
|
||
}
|
||
document.getElementById("paperkeyarea").appendChild(div);
|
||
ninja.wallets.paperwallet.generateNewWallet(i);
|
||
ninja.wallets.paperwallet.remaining--;
|
||
setTimeout(ninja.wallets.paperwallet.batch, 0);
|
||
}
|
||
},
|
||
|
||
// generate bitcoin address, private key, QR Code and update information in the HTML
|
||
// idPostFix: 1, 2, 3, etc.
|
||
generateNewWallet: function (idPostFix) {
|
||
var key = new Bitcoin.ECKey(false);
|
||
var bitcoinAddress = key.getBitcoinAddress();
|
||
var privateKeyWif = key.getBitcoinWalletImportFormat();
|
||
if (ninja.wallets.paperwallet.useArtisticWallet) {
|
||
ninja.wallets.paperwallet.showArtisticWallet(idPostFix, bitcoinAddress, privateKeyWif);
|
||
}
|
||
else {
|
||
ninja.wallets.paperwallet.showWallet(idPostFix, bitcoinAddress, privateKeyWif);
|
||
}
|
||
},
|
||
|
||
templateHtml: function (i) {
|
||
var walletHtml =
|
||
"<div class='public'>" +
|
||
"<div id='qrcode_public" + i + "' class='qrcode_public'></div>" +
|
||
"<div class='pubaddress'>" +
|
||
"<span class='label'>" + ninja.translator.get("paperlabelbitcoinaddress") + "</span>" +
|
||
"<span class='output' id='btcaddress" + i + "'></span>" +
|
||
"</div>" +
|
||
"</div>" +
|
||
"<div class='private'>" +
|
||
"<div id='qrcode_private" + i + "' class='qrcode_private'></div>" +
|
||
"<div class='privwif'>" +
|
||
"<span class='label'>" + ninja.translator.get("paperlabelprivatekey") + "</span>" +
|
||
"<span class='output' id='btcprivwif" + i + "'></span>" +
|
||
"</div>" +
|
||
"</div>";
|
||
return walletHtml;
|
||
},
|
||
|
||
showWallet: function (idPostFix, bitcoinAddress, privateKeyWif) {
|
||
document.getElementById("btcaddress" + idPostFix).innerHTML = bitcoinAddress;
|
||
document.getElementById("btcprivwif" + idPostFix).innerHTML = privateKeyWif;
|
||
var keyValuePair = {};
|
||
keyValuePair["qrcode_public" + idPostFix] = bitcoinAddress;
|
||
keyValuePair["qrcode_private" + idPostFix] = privateKeyWif;
|
||
ninja.qrCode.showQrCode(keyValuePair);
|
||
document.getElementById("keyarea" + idPostFix).style.display = "block";
|
||
},
|
||
|
||
templateArtisticHtml: function (i) {
|
||
var walletHtml =
|
||
"<div class='artwallet' id='artwallet" + i + "'>" +
|
||
//"<iframe src='bitcoin-wallet-01.svg' id='papersvg" + i + "' class='papersvg' ></iframe>" +
|
||
"<img id='papersvg" + i + "' class='papersvg' src='data:image/png;base64,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' />" +
|
||
"<div id='qrcode_public" + i + "' class='qrcode_public'></div>" +
|
||
"<div id='qrcode_private" + i + "' class='qrcode_private'></div>" +
|
||
"<div class='btcaddress' id='btcaddress" + i + "'></div>" +
|
||
"<div class='btcprivwif' id='btcprivwif" + i + "'></div>" +
|
||
"</div>";
|
||
return walletHtml;
|
||
},
|
||
|
||
showArtisticWallet: function (idPostFix, bitcoinAddress, privateKeyWif) {
|
||
var keyValuePair = {};
|
||
keyValuePair["qrcode_public" + idPostFix] = bitcoinAddress;
|
||
keyValuePair["qrcode_private" + idPostFix] = privateKeyWif;
|
||
ninja.qrCode.showQrCode(keyValuePair, 2.5);
|
||
document.getElementById("btcaddress" + idPostFix).innerHTML = bitcoinAddress;
|
||
document.getElementById("btcprivwif" + idPostFix).innerHTML = privateKeyWif;
|
||
|
||
// CODE to modify SVG DOM elements
|
||
//var paperSvg = document.getElementById("papersvg" + idPostFix);
|
||
//if (paperSvg) {
|
||
// svgDoc = paperSvg.contentDocument;
|
||
// if (svgDoc) {
|
||
// var bitcoinAddressElement = svgDoc.getElementById("bitcoinaddress");
|
||
// var privateKeyElement = svgDoc.getElementById("privatekey");
|
||
// if (bitcoinAddressElement && privateKeyElement) {
|
||
// bitcoinAddressElement.textContent = bitcoinAddress;
|
||
// privateKeyElement.textContent = privateKeyWif;
|
||
// }
|
||
// }
|
||
//}
|
||
},
|
||
|
||
toggleArt: function (element) {
|
||
if (!element.checked) {
|
||
// show Art
|
||
document.getElementById("paperlimitperpage").value = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
|
||
document.getElementById("paperlimit").value = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
|
||
}
|
||
else {
|
||
// hide Art
|
||
document.getElementById("paperlimitperpage").value = ninja.wallets.paperwallet.pageBreakAtDefault;
|
||
document.getElementById("paperlimit").value = ninja.wallets.paperwallet.pageBreakAtDefault;
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.wallets.bulkwallet = {
|
||
open: function () {
|
||
document.getElementById("bulkarea").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.wallets.bulkwallet.buildCSV(3, 1, document.getElementById("bulkcompressed").checked); }, 200);
|
||
}
|
||
},
|
||
|
||
close: function () {
|
||
document.getElementById("bulkarea").style.display = "none";
|
||
},
|
||
|
||
// 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, compressedAddrs) {
|
||
var bulkWallet = ninja.wallets.bulkwallet;
|
||
document.getElementById("bulktextarea").value = ninja.translator.get("bulkgeneratingaddresses") + rowLimit;
|
||
bulkWallet.csv = [];
|
||
bulkWallet.csvRowLimit = rowLimit;
|
||
bulkWallet.csvRowsRemaining = rowLimit;
|
||
bulkWallet.csvStartIndex = --startIndex;
|
||
bulkWallet.compressedAddrs = !!compressedAddrs;
|
||
setTimeout(bulkWallet.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 () {
|
||
var bulkWallet = ninja.wallets.bulkwallet;
|
||
if (bulkWallet.csvRowsRemaining > 0) {
|
||
bulkWallet.csvRowsRemaining--;
|
||
var key = new Bitcoin.ECKey(false);
|
||
key.setCompressed(bulkWallet.compressedAddrs);
|
||
|
||
bulkWallet.csv.push((bulkWallet.csvRowLimit - bulkWallet.csvRowsRemaining + bulkWallet.csvStartIndex)
|
||
+ ",\"" + key.getBitcoinAddress() + "\",\"" + key.toString("wif")
|
||
//+ "\",\"" + key.toString("wifcomp") // uncomment these lines to add different private key formats to the CSV
|
||
//+ "\",\"" + key.getBitcoinHexFormat()
|
||
//+ "\",\"" + key.toString("base64")
|
||
+ "\"");
|
||
|
||
document.getElementById("bulktextarea").value = ninja.translator.get("bulkgeneratingaddresses") + bulkWallet.csvRowsRemaining;
|
||
|
||
// release thread to browser to render UI
|
||
setTimeout(bulkWallet.batchCSV, 0);
|
||
}
|
||
// processing is finished so put CSV in text area
|
||
else if (bulkWallet.csvRowsRemaining === 0) {
|
||
document.getElementById("bulktextarea").value = bulkWallet.csv.join("\n");
|
||
}
|
||
},
|
||
|
||
openCloseFaq: function (faqNum) {
|
||
// do close
|
||
if (document.getElementById("bulka" + faqNum).style.display == "block") {
|
||
document.getElementById("bulka" + faqNum).style.display = "none";
|
||
document.getElementById("bulke" + faqNum).setAttribute("class", "more");
|
||
}
|
||
// do open
|
||
else {
|
||
document.getElementById("bulka" + faqNum).style.display = "block";
|
||
document.getElementById("bulke" + faqNum).setAttribute("class", "less");
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.wallets.brainwallet = {
|
||
open: function () {
|
||
document.getElementById("brainarea").style.display = "block";
|
||
document.getElementById("brainpassphrase").focus();
|
||
},
|
||
|
||
close: function () {
|
||
document.getElementById("brainarea").style.display = "none";
|
||
},
|
||
|
||
minPassphraseLength: 15,
|
||
|
||
view: function () {
|
||
var key = document.getElementById("brainpassphrase").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
|
||
document.getElementById("brainpassphrase").value = key;
|
||
var keyConfirm = document.getElementById("brainpassphraseconfirm").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
|
||
document.getElementById("brainpassphraseconfirm").value = keyConfirm;
|
||
|
||
if (key == keyConfirm || document.getElementById("brainpassphraseshow").checked) {
|
||
// enforce a minimum passphrase length
|
||
if (key.length >= ninja.wallets.brainwallet.minPassphraseLength) {
|
||
var bytes = Crypto.SHA256(key, { asBytes: true });
|
||
var btcKey = new Bitcoin.ECKey(bytes);
|
||
var bitcoinAddress = btcKey.getBitcoinAddress();
|
||
var privWif = btcKey.getBitcoinWalletImportFormat();
|
||
document.getElementById("brainbtcaddress").innerHTML = bitcoinAddress;
|
||
document.getElementById("brainbtcprivwif").innerHTML = privWif;
|
||
ninja.qrCode.showQrCode({
|
||
"brainqrcodepublic": bitcoinAddress,
|
||
"brainqrcodeprivate": privWif
|
||
});
|
||
document.getElementById("brainkeyarea").style.visibility = "visible";
|
||
}
|
||
else {
|
||
alert(ninja.translator.get("brainalertpassphrasetooshort"));
|
||
ninja.wallets.brainwallet.clear();
|
||
}
|
||
}
|
||
else {
|
||
alert(ninja.translator.get("brainalertpassphrasedoesnotmatch"));
|
||
ninja.wallets.brainwallet.clear();
|
||
}
|
||
},
|
||
|
||
clear: function () {
|
||
document.getElementById("brainkeyarea").style.visibility = "hidden";
|
||
},
|
||
|
||
showToggle: function (element) {
|
||
if (element.checked) {
|
||
document.getElementById("brainpassphrase").setAttribute("type", "text");
|
||
document.getElementById("brainpassphraseconfirm").style.visibility = "hidden";
|
||
document.getElementById("brainlabelconfirm").style.visibility = "hidden";
|
||
}
|
||
else {
|
||
document.getElementById("brainpassphrase").setAttribute("type", "password");
|
||
document.getElementById("brainpassphraseconfirm").style.visibility = "visible";
|
||
document.getElementById("brainlabelconfirm").style.visibility = "visible";
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.wallets.vanitywallet = {
|
||
open: function () {
|
||
document.getElementById("vanityarea").style.display = "block";
|
||
},
|
||
|
||
close: function () {
|
||
document.getElementById("vanityarea").style.display = "none";
|
||
document.getElementById("vanitystep1area").style.display = "none";
|
||
document.getElementById("vanitystep2area").style.display = "none";
|
||
document.getElementById("vanitystep1icon").setAttribute("class", "more");
|
||
document.getElementById("vanitystep2icon").setAttribute("class", "more");
|
||
},
|
||
|
||
generateKeyPair: function () {
|
||
var key = new Bitcoin.ECKey(false);
|
||
var publicKey = key.getPubKeyHex();
|
||
var privateKey = key.getBitcoinHexFormat();
|
||
document.getElementById("vanitypubkey").innerHTML = publicKey;
|
||
document.getElementById("vanityprivatekey").innerHTML = privateKey;
|
||
document.getElementById("vanityarea").style.display = "block";
|
||
document.getElementById("vanitystep1area").style.display = "none";
|
||
},
|
||
|
||
addKeys: function () {
|
||
var privateKeyWif = ninja.translator.get("vanityinvalidinputcouldnotcombinekeys");
|
||
var bitcoinAddress = ninja.translator.get("vanityinvalidinputcouldnotcombinekeys");
|
||
var publicKeyHex = ninja.translator.get("vanityinvalidinputcouldnotcombinekeys");
|
||
try {
|
||
var input1KeyString = document.getElementById("vanityinput1").value;
|
||
var input2KeyString = document.getElementById("vanityinput2").value;
|
||
|
||
// both inputs are public keys
|
||
if (ninja.publicKey.isPublicKeyHexFormat(input1KeyString) && ninja.publicKey.isPublicKeyHexFormat(input2KeyString)) {
|
||
// add both public keys together
|
||
if (document.getElementById("vanityradioadd").checked) {
|
||
var pubKeyByteArray = ninja.publicKey.getByteArrayFromAdding(input1KeyString, input2KeyString);
|
||
if (pubKeyByteArray == null) {
|
||
alert(ninja.translator.get("vanityalertinvalidinputpublickeysmatch"));
|
||
}
|
||
else {
|
||
privateKeyWif = ninja.translator.get("vanityprivatekeyonlyavailable");
|
||
bitcoinAddress = ninja.publicKey.getBitcoinAddressFromByteArray(pubKeyByteArray);
|
||
publicKeyHex = ninja.publicKey.getHexFromByteArray(pubKeyByteArray);
|
||
}
|
||
}
|
||
else {
|
||
alert(ninja.translator.get("vanityalertinvalidinputcannotmultiple"));
|
||
}
|
||
}
|
||
// one public key and one private key
|
||
else if ((ninja.publicKey.isPublicKeyHexFormat(input1KeyString) && ninja.privateKey.isPrivateKey(input2KeyString))
|
||
|| (ninja.publicKey.isPublicKeyHexFormat(input2KeyString) && ninja.privateKey.isPrivateKey(input1KeyString))
|
||
) {
|
||
privateKeyWif = ninja.translator.get("vanityprivatekeyonlyavailable");
|
||
var pubKeyHex = (ninja.publicKey.isPublicKeyHexFormat(input1KeyString)) ? input1KeyString : input2KeyString;
|
||
var ecKey = (ninja.privateKey.isPrivateKey(input1KeyString)) ? new Bitcoin.ECKey(input1KeyString) : new Bitcoin.ECKey(input2KeyString);
|
||
// add
|
||
if (document.getElementById("vanityradioadd").checked) {
|
||
var pubKeyCombined = ninja.publicKey.getByteArrayFromAdding(pubKeyHex, ecKey.getPubKeyHex());
|
||
}
|
||
// multiply
|
||
else {
|
||
var pubKeyCombined = ninja.publicKey.getByteArrayFromMultiplying(pubKeyHex, ecKey);
|
||
}
|
||
if (pubKeyCombined == null) {
|
||
alert(ninja.translator.get("vanityalertinvalidinputpublickeysmatch"));
|
||
} else {
|
||
bitcoinAddress = ninja.publicKey.getBitcoinAddressFromByteArray(pubKeyCombined);
|
||
publicKeyHex = ninja.publicKey.getHexFromByteArray(pubKeyCombined);
|
||
}
|
||
}
|
||
// both inputs are private keys
|
||
else if (ninja.privateKey.isPrivateKey(input1KeyString) && ninja.privateKey.isPrivateKey(input2KeyString)) {
|
||
var combinedPrivateKey;
|
||
// add both private keys together
|
||
if (document.getElementById("vanityradioadd").checked) {
|
||
combinedPrivateKey = ninja.privateKey.getECKeyFromAdding(input1KeyString, input2KeyString);
|
||
}
|
||
// multiply both private keys together
|
||
else {
|
||
combinedPrivateKey = ninja.privateKey.getECKeyFromMultiplying(input1KeyString, input2KeyString);
|
||
}
|
||
if (combinedPrivateKey == null) {
|
||
alert(ninja.translator.get("vanityalertinvalidinputprivatekeysmatch"));
|
||
}
|
||
else {
|
||
bitcoinAddress = combinedPrivateKey.getBitcoinAddress();
|
||
privateKeyWif = combinedPrivateKey.getBitcoinWalletImportFormat();
|
||
publicKeyHex = combinedPrivateKey.getPubKeyHex();
|
||
}
|
||
}
|
||
} catch (e) {
|
||
alert(e);
|
||
}
|
||
document.getElementById("vanityprivatekeywif").innerHTML = privateKeyWif;
|
||
document.getElementById("vanityaddress").innerHTML = bitcoinAddress;
|
||
document.getElementById("vanitypublickeyhex").innerHTML = publicKeyHex;
|
||
document.getElementById("vanitystep2area").style.display = "block";
|
||
document.getElementById("vanitystep2icon").setAttribute("class", "less");
|
||
},
|
||
|
||
openCloseStep: function (num) {
|
||
// do close
|
||
if (document.getElementById("vanitystep" + num + "area").style.display == "block") {
|
||
document.getElementById("vanitystep" + num + "area").style.display = "none";
|
||
document.getElementById("vanitystep" + num + "icon").setAttribute("class", "more");
|
||
}
|
||
// do open
|
||
else {
|
||
document.getElementById("vanitystep" + num + "area").style.display = "block";
|
||
document.getElementById("vanitystep" + num + "icon").setAttribute("class", "less");
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
ninja.wallets.detailwallet = {
|
||
open: function () {
|
||
document.getElementById("detailarea").style.display = "block";
|
||
document.getElementById("detailprivkey").focus();
|
||
},
|
||
|
||
close: function () {
|
||
document.getElementById("detailarea").style.display = "none";
|
||
},
|
||
|
||
viewDetails: function () {
|
||
var bip38 = false;
|
||
var key = document.getElementById("detailprivkey").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
|
||
if (key == "") {
|
||
ninja.wallets.detailwallet.clear();
|
||
return;
|
||
}
|
||
document.getElementById("detailprivkey").value = key;
|
||
if (Bitcoin.ECKey.isMiniFormat(key)) {
|
||
// show Private Key Mini Format
|
||
document.getElementById("detailprivmini").innerHTML = key;
|
||
document.getElementById("detailmini").style.display = "block";
|
||
document.getElementById("detailbip38commands").style.display = "none";
|
||
}
|
||
else if (ninja.privateKey.isBIP38Format(key)) {
|
||
if (document.getElementById("detailbip38commands").style.display != "block") {
|
||
document.getElementById("detailbip38commands").style.display = "block";
|
||
document.getElementById("detailprivkeypassphrase").focus();
|
||
return;
|
||
}
|
||
else {
|
||
bip38 = true;
|
||
}
|
||
}
|
||
else {
|
||
// hide Private Key Mini Format
|
||
document.getElementById("detailmini").style.display = "none";
|
||
document.getElementById("detailbip38commands").style.display = "none";
|
||
}
|
||
|
||
if (bip38) {
|
||
var passphrase = document.getElementById("detailprivkeypassphrase").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
|
||
if (passphrase == "") {
|
||
alert(ninja.translator.get("bip38alertpassphraserequired"));
|
||
return;
|
||
}
|
||
ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(key, passphrase, function (btcKeyOrError) {
|
||
document.getElementById("busyblock").className = "";
|
||
if (btcKeyOrError.message) {
|
||
alert(btcKeyOrError.message);
|
||
ninja.wallets.detailwallet.clear();
|
||
} else {
|
||
ninja.wallets.detailwallet.populateKeyDetails(new Bitcoin.ECKey(btcKeyOrError));
|
||
}
|
||
});
|
||
document.getElementById("busyblock").className = "busy";
|
||
}
|
||
else {
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.priv == null) {
|
||
// enforce a minimum passphrase length
|
||
if (key.length >= ninja.wallets.brainwallet.minPassphraseLength) {
|
||
// Deterministic Wallet confirm box to ask if user wants to SHA256 the input to get a private key
|
||
var usePassphrase = confirm(ninja.translator.get("detailconfirmsha256"));
|
||
if (usePassphrase) {
|
||
var bytes = Crypto.SHA256(key, { asBytes: true });
|
||
var btcKey = new Bitcoin.ECKey(bytes);
|
||
}
|
||
else {
|
||
ninja.wallets.detailwallet.clear();
|
||
}
|
||
}
|
||
else {
|
||
alert(ninja.translator.get("detailalertnotvalidprivatekey"));
|
||
ninja.wallets.detailwallet.clear();
|
||
}
|
||
}
|
||
ninja.wallets.detailwallet.populateKeyDetails(btcKey);
|
||
}
|
||
},
|
||
|
||
populateKeyDetails: function (btcKey) {
|
||
if (btcKey.priv != null) {
|
||
btcKey.setCompressed(false);
|
||
document.getElementById("detailprivhex").innerHTML = btcKey.toString().toUpperCase();
|
||
document.getElementById("detailprivb64").innerHTML = btcKey.toString("base64");
|
||
var bitcoinAddress = btcKey.getBitcoinAddress();
|
||
var wif = btcKey.getBitcoinWalletImportFormat();
|
||
document.getElementById("detailpubkey").innerHTML = btcKey.getPubKeyHex();
|
||
document.getElementById("detailaddress").innerHTML = bitcoinAddress;
|
||
document.getElementById("detailprivwif").innerHTML = wif;
|
||
btcKey.setCompressed(true);
|
||
var bitcoinAddressComp = btcKey.getBitcoinAddress();
|
||
var wifComp = btcKey.getBitcoinWalletImportFormat();
|
||
document.getElementById("detailpubkeycomp").innerHTML = btcKey.getPubKeyHex();
|
||
document.getElementById("detailaddresscomp").innerHTML = bitcoinAddressComp;
|
||
document.getElementById("detailprivwifcomp").innerHTML = wifComp;
|
||
|
||
ninja.qrCode.showQrCode({
|
||
"detailqrcodepublic": bitcoinAddress,
|
||
"detailqrcodepubliccomp": bitcoinAddressComp,
|
||
"detailqrcodeprivate": wif,
|
||
"detailqrcodeprivatecomp": wifComp
|
||
}, 4);
|
||
}
|
||
},
|
||
|
||
clear: function () {
|
||
document.getElementById("detailpubkey").innerHTML = "";
|
||
document.getElementById("detailpubkeycomp").innerHTML = "";
|
||
document.getElementById("detailaddress").innerHTML = "";
|
||
document.getElementById("detailaddresscomp").innerHTML = "";
|
||
document.getElementById("detailprivwif").innerHTML = "";
|
||
document.getElementById("detailprivwifcomp").innerHTML = "";
|
||
document.getElementById("detailprivhex").innerHTML = "";
|
||
document.getElementById("detailprivb64").innerHTML = "";
|
||
document.getElementById("detailprivmini").innerHTML = "";
|
||
document.getElementById("detailqrcodepublic").innerHTML = "";
|
||
document.getElementById("detailqrcodepubliccomp").innerHTML = "";
|
||
document.getElementById("detailqrcodeprivate").innerHTML = "";
|
||
document.getElementById("detailqrcodeprivatecomp").innerHTML = "";
|
||
document.getElementById("detailbip38commands").style.display = "none";
|
||
}
|
||
};
|
||
</script>
|
||
<script type="text/javascript">
|
||
(function (ninja) {
|
||
var ut = ninja.unitTests = {
|
||
runSynchronousTests: function () {
|
||
document.getElementById("busyblock").className = "busy";
|
||
var div = document.createElement("div");
|
||
div.setAttribute("class", "unittests");
|
||
div.setAttribute("id", "unittests");
|
||
var testResults = "";
|
||
var passCount = 0;
|
||
var testCount = 0;
|
||
for (var test in ut.synchronousTests) {
|
||
var exceptionMsg = "";
|
||
var resultBool = false;
|
||
try {
|
||
resultBool = ut.synchronousTests[test]();
|
||
} catch (ex) {
|
||
exceptionMsg = ex.toString();
|
||
resultBool = false;
|
||
}
|
||
if (resultBool == true) {
|
||
var passFailStr = "pass";
|
||
passCount++;
|
||
}
|
||
else {
|
||
var passFailStr = "<b>FAIL " + exceptionMsg + "</b>";
|
||
}
|
||
testCount++;
|
||
testResults += test + ": " + passFailStr + "<br/>";
|
||
}
|
||
testResults += passCount + " of " + testCount + " synchronous tests passed";
|
||
if (passCount < testCount) {
|
||
testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
|
||
}
|
||
div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
|
||
document.body.appendChild(div);
|
||
document.getElementById("busyblock").className = "";
|
||
|
||
},
|
||
|
||
runAsynchronousTests: function () {
|
||
document.getElementById("busyblock").className = "busy";
|
||
// run the asynchronous tests one after another so we don't crash the browser
|
||
ninja.foreachSerialized(ninja.unitTests.asynchronousTests, function (name, cb) {
|
||
ninja.unitTests.asynchronousTests[name](cb);
|
||
}, function () {
|
||
document.getElementById("unittestresults").innerHTML += "running of asynchronous unit tests complete!<br/>";
|
||
document.getElementById("busyblock").className = "";
|
||
});
|
||
},
|
||
|
||
synchronousTests: {
|
||
//ninja.publicKey tests
|
||
testIsPublicKeyHexFormat: function () {
|
||
var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var bool = ninja.publicKey.isPublicKeyHexFormat(key);
|
||
if (bool != true) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetHexFromByteArray: function () {
|
||
var bytes = [4, 120, 152, 47, 64, 250, 12, 11, 122, 85, 113, 117, 131, 175, 201, 154, 78, 223, 211, 1, 162, 114, 157, 197, 155, 11, 142, 185, 225, 134, 146, 188, 181, 33, 240, 84, 250, 217, 130, 175, 76, 193, 147, 58, 253, 31, 27, 86, 62, 167, 121, 166, 170, 108, 206, 54, 163, 11, 148, 125, 214, 83, 230, 62, 68];
|
||
var key = ninja.publicKey.getHexFromByteArray(bytes);
|
||
if (key != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testHexToBytes: function () {
|
||
var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var bytes = Crypto.util.hexToBytes(key);
|
||
if (bytes.toString() != "4,120,152,47,64,250,12,11,122,85,113,117,131,175,201,154,78,223,211,1,162,114,157,197,155,11,142,185,225,134,146,188,181,33,240,84,250,217,130,175,76,193,147,58,253,31,27,86,62,167,121,166,170,108,206,54,163,11,148,125,214,83,230,62,68") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetBitcoinAddressFromByteArray: function () {
|
||
var bytes = [4, 120, 152, 47, 64, 250, 12, 11, 122, 85, 113, 117, 131, 175, 201, 154, 78, 223, 211, 1, 162, 114, 157, 197, 155, 11, 142, 185, 225, 134, 146, 188, 181, 33, 240, 84, 250, 217, 130, 175, 76, 193, 147, 58, 253, 31, 27, 86, 62, 167, 121, 166, 170, 108, 206, 54, 163, 11, 148, 125, 214, 83, 230, 62, 68];
|
||
var address = ninja.publicKey.getBitcoinAddressFromByteArray(bytes);
|
||
if (address != "1Cnz9ULjzBPYhDw1J8bpczDWCEXnC9HuU1") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromAdding: function () {
|
||
var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var key2 = "0419153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C0159DC0099AD54F733812892EB9A11A8C816A201B3BAF0D97117EBA2033C9AB2";
|
||
var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
|
||
if (bytes.toString() != "4,151,19,227,152,54,37,184,255,4,83,115,216,102,189,76,82,170,57,4,196,253,2,41,74,6,226,33,167,199,250,74,235,223,128,233,99,150,147,92,57,39,208,84,196,71,68,248,166,106,138,95,172,253,224,70,187,65,62,92,81,38,253,79,0") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromAddingCompressed: function () {
|
||
var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
|
||
var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
|
||
var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
|
||
var hex = ninja.publicKey.getHexFromByteArray(bytes);
|
||
if (hex != "029713E3983625B8FF045373D866BD4C52AA3904C4FD02294A06E221A7C7FA4AEB") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromAddingUncompressedAndCompressed: function () {
|
||
var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
|
||
var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
|
||
if (bytes.toString() != "4,151,19,227,152,54,37,184,255,4,83,115,216,102,189,76,82,170,57,4,196,253,2,41,74,6,226,33,167,199,250,74,235,223,128,233,99,150,147,92,57,39,208,84,196,71,68,248,166,106,138,95,172,253,224,70,187,65,62,92,81,38,253,79,0") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromAddingShouldReturnNullWhenSameKey1: function () {
|
||
var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var key2 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
|
||
if (bytes != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromAddingShouldReturnNullWhenSameKey2: function () {
|
||
var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var key2 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
|
||
var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
|
||
if (bytes != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromMultiplying: function () {
|
||
var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
|
||
if (bytes.toString() != "4,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57,115,35,54,105,7,180,5,106,217,57,229,127,174,145,215,79,121,163,191,211,143,215,50,48,156,211,178,72,226,68,150,52") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromMultiplyingCompressedOutputsUncompressed: function () {
|
||
var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
|
||
var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
|
||
if (bytes.toString() != "4,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57,115,35,54,105,7,180,5,106,217,57,229,127,174,145,215,79,121,163,191,211,143,215,50,48,156,211,178,72,226,68,150,52") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromMultiplyingCompressedOutputsCompressed: function () {
|
||
var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
|
||
var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
|
||
var ecKey = new Bitcoin.ECKey(key2);
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, ecKey);
|
||
if (bytes.toString() != "2,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey1: function () {
|
||
var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
|
||
var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
|
||
if (bytes != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey2: function () {
|
||
var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
|
||
var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
|
||
if (bytes != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
// confirms multiplication is working and BigInteger was created correctly (Pub Key B vs Priv Key A)
|
||
testGetPubHexFromMultiplyingPrivAPubB: function () {
|
||
var keyPub = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
|
||
var keyPriv = "B1202A137E917536B3B4C5010C3FF5DDD4784917B3EEF21D3A3BF21B2E03310C";
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
|
||
var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
|
||
if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
// confirms multiplication is working and BigInteger was created correctly (Pub Key A vs Priv Key B)
|
||
testGetPubHexFromMultiplyingPrivBPubA: function () {
|
||
var keyPub = "0429BF26C0AF7D31D608474CEBD49DA6E7C541B8FAD95404B897643476CE621CFD05E24F7AE8DE8033AADE5857DB837E0B704A31FDDFE574F6ECA879643A0D3709";
|
||
var keyPriv = "7DE52819F1553C2BFEDE6A2628B6FDDF03C2A07EB21CF77ACA6C2C3D252E1FD9";
|
||
var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
|
||
var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
|
||
if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
|
||
// Private Key tests
|
||
testBadKeyIsNotWif: function () {
|
||
return !(Bitcoin.ECKey.isWalletImportFormat("bad key"));
|
||
},
|
||
testBadKeyIsNotWifCompressed: function () {
|
||
return !(Bitcoin.ECKey.isCompressedWalletImportFormat("bad key"));
|
||
},
|
||
testBadKeyIsNotHex: function () {
|
||
return !(Bitcoin.ECKey.isHexFormat("bad key"));
|
||
},
|
||
testBadKeyIsNotBase64: function () {
|
||
return !(Bitcoin.ECKey.isBase64Format("bad key"));
|
||
},
|
||
testBadKeyIsNotMini: function () {
|
||
return !(Bitcoin.ECKey.isMiniFormat("bad key"));
|
||
},
|
||
testBadKeyReturnsNullPrivFromECKey: function () {
|
||
var key = "bad key";
|
||
var ecKey = new Bitcoin.ECKey(key);
|
||
if (ecKey.priv != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetBitcoinPrivateKeyByteArray: function () {
|
||
var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var bytes = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinPrivateKeyByteArray().toString() != bytes.toString()) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testECKeyDecodeWalletImportFormat: function () {
|
||
var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var bytes1 = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
|
||
var bytes2 = Bitcoin.ECKey.decodeWalletImportFormat(key);
|
||
if (bytes1.toString() != bytes2.toString()) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testECKeyDecodeCompressedWalletImportFormat: function () {
|
||
var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var bytes1 = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
|
||
var bytes2 = Bitcoin.ECKey.decodeCompressedWalletImportFormat(key);
|
||
if (bytes1.toString() != bytes2.toString()) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testWifToPubKeyHex: function () {
|
||
var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getPubKeyHex() != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44"
|
||
|| btcKey.getPubPoint().compressed != false) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testWifToPubKeyHexCompressed: function () {
|
||
var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
btcKey.setCompressed(true);
|
||
if (btcKey.getPubKeyHex() != "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5"
|
||
|| btcKey.getPubPoint().compressed != true) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testBase64ToECKey: function () {
|
||
var key = "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinBase64Format() != "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testHexToECKey: function () {
|
||
var key = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinHexFormat() != "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testCompressedWifToECKey: function () {
|
||
var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinWalletImportFormat() != "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S"
|
||
|| btcKey.getPubPoint().compressed != true) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testWifToECKey: function () {
|
||
var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testBrainToECKey: function () {
|
||
var key = "bitaddress.org unit test";
|
||
var bytes = Crypto.SHA256(key, { asBytes: true });
|
||
var btcKey = new Bitcoin.ECKey(bytes);
|
||
if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testMini30CharsToECKey: function () {
|
||
var key = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinWalletImportFormat() != "5JrBLQseeZdYw4jWEAHmNxGMr5fxh9NJU3fUwnv4khfKcg2rJVh") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromAdding: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
|
||
var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
|
||
if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromAddingCompressed: function () {
|
||
var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
|
||
var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
|
||
if (ecKey.getBitcoinWalletImportFormat() != "L3A43j2pc2J8F2SjBNbYprPrcDpDCh8Aju8dUH65BEM2r7RFSLv4") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromAddingUncompressedAndCompressed: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
|
||
var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
|
||
if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromAddingShouldReturnNullWhenSameKey1: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
|
||
if (ecKey != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromAddingShouldReturnNullWhenSameKey2: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
|
||
if (ecKey != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromMultiplying: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
|
||
var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
|
||
if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromMultiplyingCompressed: function () {
|
||
var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
|
||
var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
|
||
if (ecKey.getBitcoinWalletImportFormat() != "L5LFitc24jme2PfVChJS3bKuQAPBp54euuqLWciQdF2CxnaU3M8t") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromMultiplyingUncompressedAndCompressed: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
|
||
var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
|
||
if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey1: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
|
||
if (ecKey != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey2: function () {
|
||
var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
|
||
var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
|
||
var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
|
||
if (ecKey != null) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testGetECKeyFromBase6Key: function () {
|
||
var base = 6;
|
||
var baseKey = "100531114202410255230521444145414341221420541210522412225005202300434134213212540304311321323051431";
|
||
var hexKey = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
|
||
var bigInt = new BigInteger(baseKey, base);
|
||
var ecKey = new Bitcoin.ECKey(bigInt);
|
||
if (ecKey.getBitcoinHexFormat() != hexKey) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
|
||
// EllipticCurve tests
|
||
testDecodePointEqualsDecodeFrom: function () {
|
||
var key = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
|
||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||
var ecPoint1 = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), Crypto.util.hexToBytes(key));
|
||
var ecPoint2 = ecparams.getCurve().decodePointHex(key);
|
||
if (!ecPoint1.equals(ecPoint2)) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testDecodePointHexForCompressedPublicKey: function () {
|
||
var key = "03F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F989380";
|
||
var pubHexUncompressed = ninja.publicKey.getDecompressedPubKeyHex(key);
|
||
if (pubHexUncompressed != "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
// old bugs
|
||
testBugWithLeadingZeroBytePublicKey: function () {
|
||
var key = "5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinAddress() != "1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E") {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
testBugWithLeadingZeroBytePrivateKey: function () {
|
||
var key = "0004d30da67214fa65a41a6493576944c7ea86713b14db437446c7a8df8e13da";
|
||
var btcKey = new Bitcoin.ECKey(key);
|
||
if (btcKey.getBitcoinAddress() != "1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn") {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
},
|
||
|
||
asynchronousTests: {
|
||
testBip38: function (done) {
|
||
var tests = [["6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg", "TestingOneTwoThree", "5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR"],
|
||
["6PRNFFkZc2NZ6dJqFfhRoFNMR9Lnyj7dYGrzdgXXVMXcxoKTePPX1dWByq", "Satoshi", "5HtasZ6ofTHP6HCwTqTkLDuLQisYPah7aUnSKfC7h4hMUVw2gi5"],
|
||
["6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo", "TestingOneTwoThree", "L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP"],
|
||
["6PYLtMnXvfG3oJde97zRyLYFZCYizPU5T3LwgdYJz1fRhh16bU7u6PPmY7", "Satoshi", "KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7"],
|
||
["6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX", "TestingOneTwoThree", "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2"],
|
||
["6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd", "Satoshi", "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH"],
|
||
["6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j", "MOLON LABE", "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8"],
|
||
["6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH", Crypto.charenc.UTF8.bytesToString([206, 156, 206, 159, 206, 155, 206, 169, 206, 157, 32, 206, 155, 206, 145, 206, 146, 206, 149])/*UTF-8 characters, encoded in source so they don't get corrupted*/, "5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D"]];
|
||
// running each test uses a lot of memory, which isn't freed
|
||
// immediately, so give the VM a little time to reclaim memory
|
||
function waitThenCall(callback) {
|
||
return function () { setTimeout(callback, 6000); }
|
||
}
|
||
|
||
var decryptTest = function (test, i, onComplete) {
|
||
ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(test[0], test[1], function (privBytes) {
|
||
if (privBytes.constructor == Error) {
|
||
document.getElementById("unittestresults").innerHTML += "fail testDecryptBip38 #" + i + ", error: " + privBytes.message + "<br/>";
|
||
} else {
|
||
var btcKey = new Bitcoin.ECKey(privBytes);
|
||
var wif = !test[2].substr(0, 1).match(/[LK]/) ? btcKey.setCompressed(false).getBitcoinWalletImportFormat() : btcKey.setCompressed(true).getBitcoinWalletImportFormat();
|
||
if (wif != test[2]) {
|
||
document.getElementById("unittestresults").innerHTML += "fail testDecryptBip38 #" + i + "<br/>";
|
||
} else {
|
||
document.getElementById("unittestresults").innerHTML += "pass testDecryptBip38 #" + i + "<br/>";
|
||
}
|
||
}
|
||
onComplete();
|
||
});
|
||
}
|
||
|
||
document.getElementById("unittestresults").innerHTML += "running " + tests.length + " tests named testDecryptBip38<br/>";
|
||
ninja.runSerialized([function (cb) {
|
||
ninja.forSerialized(0, tests.length, function (i, callback) {
|
||
decryptTest(tests[i], i, waitThenCall(callback));
|
||
}, waitThenCall(cb));
|
||
} ], done);
|
||
}
|
||
}
|
||
};
|
||
})(ninja);
|
||
</script>
|
||
<script type="text/javascript">
|
||
// run unit tests
|
||
if (ninja.getQueryString()["unittests"] == "true" || ninja.getQueryString()["unittests"] == "1") {
|
||
ninja.unitTests.runSynchronousTests();
|
||
ninja.translator.showEnglishJson();
|
||
}
|
||
// run async unit tests
|
||
if (ninja.getQueryString()["asyncunittests"] == "true" || ninja.getQueryString()["asyncunittests"] == "1") {
|
||
ninja.unitTests.runAsynchronousTests();
|
||
}
|
||
|
||
// change language
|
||
if (ninja.getQueryString()["culture"] != undefined) {
|
||
ninja.translator.translate(ninja.getQueryString()["culture"]);
|
||
}
|
||
|
||
// testnet, check if testnet edition should be activated
|
||
if (ninja.getQueryString()["testnet"] == "true" || ninja.getQueryString()["testnet"] == "1") {
|
||
document.getElementById("testnet").innerHTML = ninja.translator.get("testneteditionactivated");
|
||
document.getElementById("testnet").style.display = "block";
|
||
document.getElementById("detailwifprefix").innerHTML = "'9'";
|
||
document.getElementById("detailcompwifprefix").innerHTML = "'c'";
|
||
Bitcoin.Address.networkVersion = 0x6F; // testnet
|
||
Bitcoin.ECKey.privateKeyPrefix = 0xEF; // testnet
|
||
ninja.testnetMode = true;
|
||
}
|
||
|
||
// if users does not move mouse after random amount of time then generate the key anyway.
|
||
setTimeout(ninja.seeder.forceGenerate, ninja.seeder.seedLimit * 20);
|
||
</script>
|
||
</body>
|
||
</html>
|