· 8 years ago · Dec 16, 2017, 05:14 PM
1Phishing wallet generator at walletgenerator.org
2
3Read more here:
4
5https://rootvideochannel.blogspot.com/2017/12/example-of-phishing-bitcoin-wallet.html
6
7...
8
9<!doctype html>
10<html>
11<head>
12 <meta charset="utf-8">
13 <meta name="description" content="Universal Open Source Client-Side Paper Wallet Generator for BitCoins and other cryptocurrencies. Create your own paper wallet in a few easy steps : Generate, Print and Fold !">
14 <meta name="keywords" content="universal, paper, wallet, generator, cryptocurrencies, bitcoin, litecoin, dogecoin" />
15
16 <!--
17
18Notice of Copyrights and Licenses:
19---------------------------------------
20The WalletGenerator.net project, software and embedded resources are copyright WalletGenerator.net.
21The WalletGenerator.net name and logo are not part of the open source license.
22
23Portions of the all-in-one HTML document contain JavaScript codes that are the copyrights of others.
24The individual copyrights are included throughout the document along with their licenses. Included
25JavaScript libraries are separated with HTML script tags.
26
27Summary of JavaScript functions with a redistributable license:
28JavaScript function License
29------------------- --------------
30Array.prototype.map Public Domain
31window.Crypto BSD License
32window.SecureRandom BSD License
33window.EllipticCurve BSD License
34window.BigInteger BSD License
35window.QRCode MIT License
36window.Bitcoin MIT License
37jsqrcode Apache License, 2.0
38
39
40The WalletGenerator.net software is available under The MIT License (MIT)
41Copyright (c) 2014 WalletGenerator.net
42
43Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
44associated documentation files (the "Software"), to deal in the Software without restriction,
45including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
46and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
47subject to the following conditions:
48
49The above copyright notice and this permission notice shall be included in all copies or substantial
50portions of the Software.
51
52THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
53NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
54IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
55WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
56SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
57
58
59 GitHub Repository: https://github.com/MichaelMure/WalletGenerator.net
60 -->
61
62 <title>WalletGenerator.org - Universal Paper wallet generator for Bitcoin and other cryptocurrencies</title>
63
64 <script type="text/javascript">
65// Array.prototype.map function is in the public domain.
66// Production steps of ECMA-262, Edition 5, 15.4.4.19
67// Reference: http://es5.github.com/#x15.4.4.19
68if (!Array.prototype.map) {
69 Array.prototype.map = function (callback, thisArg) {
70 var T, A, k;
71 if (this == null) {
72 throw new TypeError(" this is null or not defined");
73 }
74 // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
75 var O = Object(this);
76 // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
77 // 3. Let len be ToUint32(lenValue).
78 var len = O.length >>> 0;
79 // 4. If IsCallable(callback) is false, throw a TypeError exception.
80 // See: http://es5.github.com/#x9.11
81 if ({}.toString.call(callback) != "[object Function]") {
82 throw new TypeError(callback + " is not a function");
83 }
84 // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
85 if (thisArg) {
86 T = thisArg;
87 }
88 // 6. Let A be a new array created as if by the expression new Array(len) where Array is
89 // the standard built-in constructor with that name and len is the value of len.
90 A = new Array(len);
91 // 7. Let k be 0
92 k = 0;
93 // 8. Repeat, while k < len
94 while (k < len) {
95 var kValue, mappedValue;
96 // a. Let Pk be ToString(k).
97 // This is implicit for LHS operands of the in operator
98 // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
99 // This step can be combined with c
100 // c. If kPresent is true, then
101 if (k in O) {
102 // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
103 kValue = O[k];
104 // ii. Let mappedValue be the result of calling the Call internal method of callback
105 // with T as the this value and argument list containing kValue, k, and O.
106 mappedValue = callback.call(T, kValue, k, O);
107 // iii. Call the DefineOwnProperty internal method of A with arguments
108 // Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true},
109 // and false.
110 // In browsers that support Object.defineProperty, use the following:
111 // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
112 // For best browser support, use the following:
113 A[k] = mappedValue;
114 }
115 // d. Increase k by 1.
116 k++;
117 }
118 // 9. return A
119 return A;
120 };
121}
122 </script>
123 <!-- Piwik -->
124 <script type="text/javascript">
125 var _paq = _paq || [];
126 /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
127 _paq.push(['trackPageView']);
128 _paq.push(['enableLinkTracking']);
129 (function() {
130 var u="//piwik.sourceway.de/";
131 _paq.push(['setTrackerUrl', u+'piwik.php']);
132 _paq.push(['setSiteId', '20']);
133 var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
134 g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
135 })();
136 </script>
137 <noscript><p><img src="//piwik.sourceway.de/piwik.php?idsite=20&rec=1" style="border:0;" alt="" /></p></noscript>
138 <!-- End Piwik Code -->
139 <script type="text/javascript">
140/*!
141* Crypto-JS v2.5.4 Crypto.js
142* http://code.google.com/p/crypto-js/
143* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
144* http://code.google.com/p/crypto-js/wiki/License
145*/
146if (typeof Crypto == "undefined" || !Crypto.util) {
147 (function () {
148
149 var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
150
151 // Global Crypto object
152 var Crypto = window.Crypto = {};
153
154 // Crypto utilities
155 var util = Crypto.util = {
156
157 // Bit-wise rotate left
158 rotl: function (n, b) {
159 return (n << b) | (n >>> (32 - b));
160 },
161
162 // Bit-wise rotate right
163 rotr: function (n, b) {
164 return (n << (32 - b)) | (n >>> b);
165 },
166
167 // Swap big-endian to little-endian and vice versa
168 endian: function (n) {
169
170 // If number given, swap endian
171 if (n.constructor == Number) {
172 return util.rotl(n, 8) & 0x00FF00FF |
173 util.rotl(n, 24) & 0xFF00FF00;
174 }
175
176 // Else, assume array and swap all items
177 for (var i = 0; i < n.length; i++)
178 n[i] = util.endian(n[i]);
179 return n;
180
181 },
182
183 // Generate an array of any length of random bytes
184 randomBytes: function (n) {
185 for (var bytes = []; n > 0; n--)
186 bytes.push(Math.floor(Math.random() * 256));
187 return bytes;
188 },
189
190 // Convert a byte array to big-endian 32-bit words
191 bytesToWords: function (bytes) {
192 for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
193 words[b >>> 5] |= (bytes[i] & 0xFF) << (24 - b % 32);
194 return words;
195 },
196
197 // Convert big-endian 32-bit words to a byte array
198 wordsToBytes: function (words) {
199 for (var bytes = [], b = 0; b < words.length * 32; b += 8)
200 bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
201 return bytes;
202 },
203
204 // Convert a byte array to a hex string
205 bytesToHex: function (bytes) {
206 for (var hex = [], i = 0; i < bytes.length; i++) {
207 hex.push((bytes[i] >>> 4).toString(16));
208 hex.push((bytes[i] & 0xF).toString(16));
209 }
210 return hex.join("");
211 },
212
213 // Convert a hex string to a byte array
214 hexToBytes: function (hex) {
215 for (var bytes = [], c = 0; c < hex.length; c += 2)
216 bytes.push(parseInt(hex.substr(c, 2), 16));
217 return bytes;
218 },
219
220 // Convert a byte array to a base-64 string
221 bytesToBase64: function (bytes) {
222 for (var base64 = [], i = 0; i < bytes.length; i += 3) {
223 var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
224 for (var j = 0; j < 4; j++) {
225 if (i * 8 + j * 6 <= bytes.length * 8)
226 base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
227 else base64.push("=");
228 }
229 }
230
231 return base64.join("");
232 },
233
234 // Convert a base-64 string to a byte array
235 base64ToBytes: function (base64) {
236 // Remove non-base-64 characters
237 base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");
238
239 for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {
240 if (imod4 == 0) continue;
241 bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |
242 (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
243 }
244
245 return bytes;
246 }
247
248 };
249
250 // Crypto character encodings
251 var charenc = Crypto.charenc = {};
252
253 // UTF-8 encoding
254 var UTF8 = charenc.UTF8 = {
255
256 // Convert a string to a byte array
257 stringToBytes: function (str) {
258 return Binary.stringToBytes(unescape(encodeURIComponent(str)));
259 },
260
261 // Convert a byte array to a string
262 bytesToString: function (bytes) {
263 return decodeURIComponent(escape(Binary.bytesToString(bytes)));
264 }
265
266 };
267
268 // Binary encoding
269 var Binary = charenc.Binary = {
270
271 // Convert a string to a byte array
272 stringToBytes: function (str) {
273 for (var bytes = [], i = 0; i < str.length; i++)
274 bytes.push(str.charCodeAt(i) & 0xFF);
275 return bytes;
276 },
277
278 // Convert a byte array to a string
279 bytesToString: function (bytes) {
280 for (var str = [], i = 0; i < bytes.length; i++)
281 str.push(String.fromCharCode(bytes[i]));
282 return str.join("");
283 }
284
285 };
286
287 })();
288}
289 </script>
290 <script type="text/javascript">
291/*!
292* Crypto-JS v2.5.4 SHA256.js
293* http://code.google.com/p/crypto-js/
294* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
295* http://code.google.com/p/crypto-js/wiki/License
296*/
297(function () {
298
299 // Shortcuts
300 var C = Crypto,
301 util = C.util,
302 charenc = C.charenc,
303 UTF8 = charenc.UTF8,
304 Binary = charenc.Binary;
305
306 // Constants
307 var K = [0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
308 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
309 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
310 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
311 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
312 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
313 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
314 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
315 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
316 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
317 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
318 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
319 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
320 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
321 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
322 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2];
323
324 // Public API
325 var SHA256 = C.SHA256 = function (message, options) {
326 var digestbytes = util.wordsToBytes(SHA256._sha256(message));
327 return options && options.asBytes ? digestbytes :
328 options && options.asString ? Binary.bytesToString(digestbytes) :
329 util.bytesToHex(digestbytes);
330 };
331
332 // The core
333 SHA256._sha256 = function (message) {
334
335 // Convert to byte array
336 if (message.constructor == String) message = UTF8.stringToBytes(message);
337 /* else, assume byte array already */
338
339 var m = util.bytesToWords(message),
340 l = message.length * 8,
341 H = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
342 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19],
343 w = [],
344 a, b, c, d, e, f, g, h, i, j,
345 t1, t2;
346
347 // Padding
348 m[l >> 5] |= 0x80 << (24 - l % 32);
349 m[((l + 64 >> 9) << 4) + 15] = l;
350
351 for (var i = 0; i < m.length; i += 16) {
352
353 a = H[0];
354 b = H[1];
355 c = H[2];
356 d = H[3];
357 e = H[4];
358 f = H[5];
359 g = H[6];
360 h = H[7];
361
362 for (var j = 0; j < 64; j++) {
363
364 if (j < 16) w[j] = m[j + i];
365 else {
366
367 var gamma0x = w[j - 15],
368 gamma1x = w[j - 2],
369 gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
370 ((gamma0x << 14) | (gamma0x >>> 18)) ^
371 (gamma0x >>> 3),
372 gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
373 ((gamma1x << 13) | (gamma1x >>> 19)) ^
374 (gamma1x >>> 10);
375
376 w[j] = gamma0 + (w[j - 7] >>> 0) +
377 gamma1 + (w[j - 16] >>> 0);
378
379 }
380
381 var ch = e & f ^ ~e & g,
382 maj = a & b ^ a & c ^ b & c,
383 sigma0 = ((a << 30) | (a >>> 2)) ^
384 ((a << 19) | (a >>> 13)) ^
385 ((a << 10) | (a >>> 22)),
386 sigma1 = ((e << 26) | (e >>> 6)) ^
387 ((e << 21) | (e >>> 11)) ^
388 ((e << 7) | (e >>> 25));
389
390
391 t1 = (h >>> 0) + sigma1 + ch + (K[j]) + (w[j] >>> 0);
392 t2 = sigma0 + maj;
393
394 h = g;
395 g = f;
396 f = e;
397 e = (d + t1) >>> 0;
398 d = c;
399 c = b;
400 b = a;
401 a = (t1 + t2) >>> 0;
402
403 }
404
405 H[0] += a;
406 H[1] += b;
407 H[2] += c;
408 H[3] += d;
409 H[4] += e;
410 H[5] += f;
411 H[6] += g;
412 H[7] += h;
413
414 }
415
416 return H;
417
418 };
419
420 // Package private blocksize
421 SHA256._blocksize = 16;
422
423 SHA256._digestsize = 32;
424
425})();
426 </script>
427 <script type="text/javascript">
428/*!
429* Crypto-JS v2.5.4 PBKDF2.js
430* http://code.google.com/p/crypto-js/
431* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
432* http://code.google.com/p/crypto-js/wiki/License
433*/
434(function () {
435
436 // Shortcuts
437 var C = Crypto,
438 util = C.util,
439 charenc = C.charenc,
440 UTF8 = charenc.UTF8,
441 Binary = charenc.Binary;
442
443 C.PBKDF2 = function (password, salt, keylen, options) {
444
445 // Convert to byte arrays
446 if (password.constructor == String) password = UTF8.stringToBytes(password);
447 if (salt.constructor == String) salt = UTF8.stringToBytes(salt);
448 /* else, assume byte arrays already */
449
450 // Defaults
451 var hasher = options && options.hasher || C.SHA1,
452 iterations = options && options.iterations || 1;
453
454 // Pseudo-random function
455 function PRF(password, salt) {
456 return C.HMAC(hasher, salt, password, { asBytes: true });
457 }
458
459 // Generate key
460 var derivedKeyBytes = [],
461 blockindex = 1;
462 while (derivedKeyBytes.length < keylen) {
463 var block = PRF(password, salt.concat(util.wordsToBytes([blockindex])));
464 for (var u = block, i = 1; i < iterations; i++) {
465 u = PRF(password, u);
466 for (var j = 0; j < block.length; j++) block[j] ^= u[j];
467 }
468 derivedKeyBytes = derivedKeyBytes.concat(block);
469 blockindex++;
470 }
471
472 // Truncate excess bytes
473 derivedKeyBytes.length = keylen;
474
475 return options && options.asBytes ? derivedKeyBytes :
476 options && options.asString ? Binary.bytesToString(derivedKeyBytes) :
477 util.bytesToHex(derivedKeyBytes);
478
479 };
480
481})();
482 </script>
483 <script type="text/javascript">
484/*!
485* Crypto-JS v2.5.4 HMAC.js
486* http://code.google.com/p/crypto-js/
487* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
488* http://code.google.com/p/crypto-js/wiki/License
489*/
490(function () {
491
492 // Shortcuts
493 var C = Crypto,
494 util = C.util,
495 charenc = C.charenc,
496 UTF8 = charenc.UTF8,
497 Binary = charenc.Binary;
498
499 C.HMAC = function (hasher, message, key, options) {
500
501 // Convert to byte arrays
502 if (message.constructor == String) message = UTF8.stringToBytes(message);
503 if (key.constructor == String) key = UTF8.stringToBytes(key);
504 /* else, assume byte arrays already */
505
506 // Allow arbitrary length keys
507 if (key.length > hasher._blocksize * 4)
508 key = hasher(key, { asBytes: true });
509
510 // XOR keys with pad constants
511 var okey = key.slice(0),
512 ikey = key.slice(0);
513 for (var i = 0; i < hasher._blocksize * 4; i++) {
514 okey[i] ^= 0x5C;
515 ikey[i] ^= 0x36;
516 }
517
518 var hmacbytes = hasher(okey.concat(hasher(ikey.concat(message), { asBytes: true })), { asBytes: true });
519
520 return options && options.asBytes ? hmacbytes :
521 options && options.asString ? Binary.bytesToString(hmacbytes) :
522 util.bytesToHex(hmacbytes);
523
524 };
525
526})();
527 </script>
528 <script type="text/javascript">
529/*!
530* Crypto-JS v2.5.4 AES.js
531* http://code.google.com/p/crypto-js/
532* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
533* http://code.google.com/p/crypto-js/wiki/License
534*/
535(function () {
536
537 // Shortcuts
538 var C = Crypto,
539 util = C.util,
540 charenc = C.charenc,
541 UTF8 = charenc.UTF8;
542
543 // Precomputed SBOX
544 var SBOX = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
545 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
546 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
547 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
548 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
549 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
550 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
551 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
552 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
553 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
554 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
555 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
556 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
557 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
558 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
559 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
560 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
561 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
562 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
563 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
564 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
565 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
566 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
567 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
568 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
569 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
570 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
571 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
572 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
573 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
574 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
575 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
576
577 // Compute inverse SBOX lookup table
578 for (var INVSBOX = [], i = 0; i < 256; i++) INVSBOX[SBOX[i]] = i;
579
580 // Compute multiplication in GF(2^8) lookup tables
581 var MULT2 = [],
582 MULT3 = [],
583 MULT9 = [],
584 MULTB = [],
585 MULTD = [],
586 MULTE = [];
587
588 function xtime(a, b) {
589 for (var result = 0, i = 0; i < 8; i++) {
590 if (b & 1) result ^= a;
591 var hiBitSet = a & 0x80;
592 a = (a << 1) & 0xFF;
593 if (hiBitSet) a ^= 0x1b;
594 b >>>= 1;
595 }
596 return result;
597 }
598
599 for (var i = 0; i < 256; i++) {
600 MULT2[i] = xtime(i, 2);
601 MULT3[i] = xtime(i, 3);
602 MULT9[i] = xtime(i, 9);
603 MULTB[i] = xtime(i, 0xB);
604 MULTD[i] = xtime(i, 0xD);
605 MULTE[i] = xtime(i, 0xE);
606 }
607
608 // Precomputed RCon lookup
609 var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
610
611 // Inner state
612 var state = [[], [], [], []],
613 keylength,
614 nrounds,
615 keyschedule;
616
617 var AES = C.AES = {
618
619 /**
620 * Public API
621 */
622
623 encrypt: function (message, password, options) {
624
625 options = options || {};
626
627 // Determine mode
628 var mode = options.mode || new C.mode.OFB;
629
630 // Allow mode to override options
631 if (mode.fixOptions) mode.fixOptions(options);
632
633 var
634
635 // Convert to bytes if message is a string
636 m = (
637 message.constructor == String ?
638 UTF8.stringToBytes(message) :
639 message
640 ),
641
642 // Generate random IV
643 iv = options.iv || util.randomBytes(AES._blocksize * 4),
644
645 // Generate key
646 k = (
647 password.constructor == String ?
648 // Derive key from pass-phrase
649 C.PBKDF2(password, iv, 32, { asBytes: true }) :
650 // else, assume byte array representing cryptographic key
651 password
652 );
653
654 // Encrypt
655 AES._init(k);
656 mode.encrypt(AES, m, iv);
657
658 // Return ciphertext
659 m = options.iv ? m : iv.concat(m);
660 return (options && options.asBytes) ? m : util.bytesToBase64(m);
661
662 },
663
664 decrypt: function (ciphertext, password, options) {
665
666 options = options || {};
667
668 // Determine mode
669 var mode = options.mode || new C.mode.OFB;
670
671 // Allow mode to override options
672 if (mode.fixOptions) mode.fixOptions(options);
673
674 var
675
676 // Convert to bytes if ciphertext is a string
677 c = (
678 ciphertext.constructor == String ?
679 util.base64ToBytes(ciphertext) :
680 ciphertext
681 ),
682
683 // Separate IV and message
684 iv = options.iv || c.splice(0, AES._blocksize * 4),
685
686 // Generate key
687 k = (
688 password.constructor == String ?
689 // Derive key from pass-phrase
690 C.PBKDF2(password, iv, 32, { asBytes: true }) :
691 // else, assume byte array representing cryptographic key
692 password
693 );
694
695 // Decrypt
696 AES._init(k);
697 mode.decrypt(AES, c, iv);
698
699 // Return plaintext
700 return (options && options.asBytes) ? c : UTF8.bytesToString(c);
701
702 },
703
704
705 /**
706 * Package private methods and properties
707 */
708
709 _blocksize: 4,
710
711 _encryptblock: function (m, offset) {
712
713 // Set input
714 for (var row = 0; row < AES._blocksize; row++) {
715 for (var col = 0; col < 4; col++)
716 state[row][col] = m[offset + col * 4 + row];
717 }
718
719 // Add round key
720 for (var row = 0; row < 4; row++) {
721 for (var col = 0; col < 4; col++)
722 state[row][col] ^= keyschedule[col][row];
723 }
724
725 for (var round = 1; round < nrounds; round++) {
726
727 // Sub bytes
728 for (var row = 0; row < 4; row++) {
729 for (var col = 0; col < 4; col++)
730 state[row][col] = SBOX[state[row][col]];
731 }
732
733 // Shift rows
734 state[1].push(state[1].shift());
735 state[2].push(state[2].shift());
736 state[2].push(state[2].shift());
737 state[3].unshift(state[3].pop());
738
739 // Mix columns
740 for (var col = 0; col < 4; col++) {
741
742 var s0 = state[0][col],
743 s1 = state[1][col],
744 s2 = state[2][col],
745 s3 = state[3][col];
746
747 state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3;
748 state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3;
749 state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3];
750 state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3];
751
752 }
753
754 // Add round key
755 for (var row = 0; row < 4; row++) {
756 for (var col = 0; col < 4; col++)
757 state[row][col] ^= keyschedule[round * 4 + col][row];
758 }
759
760 }
761
762 // Sub bytes
763 for (var row = 0; row < 4; row++) {
764 for (var col = 0; col < 4; col++)
765 state[row][col] = SBOX[state[row][col]];
766 }
767
768 // Shift rows
769 state[1].push(state[1].shift());
770 state[2].push(state[2].shift());
771 state[2].push(state[2].shift());
772 state[3].unshift(state[3].pop());
773
774 // Add round key
775 for (var row = 0; row < 4; row++) {
776 for (var col = 0; col < 4; col++)
777 state[row][col] ^= keyschedule[nrounds * 4 + col][row];
778 }
779
780 // Set output
781 for (var row = 0; row < AES._blocksize; row++) {
782 for (var col = 0; col < 4; col++)
783 m[offset + col * 4 + row] = state[row][col];
784 }
785
786 },
787
788 _decryptblock: function (c, offset) {
789
790 // Set input
791 for (var row = 0; row < AES._blocksize; row++) {
792 for (var col = 0; col < 4; col++)
793 state[row][col] = c[offset + col * 4 + row];
794 }
795
796 // Add round key
797 for (var row = 0; row < 4; row++) {
798 for (var col = 0; col < 4; col++)
799 state[row][col] ^= keyschedule[nrounds * 4 + col][row];
800 }
801
802 for (var round = 1; round < nrounds; round++) {
803
804 // Inv shift rows
805 state[1].unshift(state[1].pop());
806 state[2].push(state[2].shift());
807 state[2].push(state[2].shift());
808 state[3].push(state[3].shift());
809
810 // Inv sub bytes
811 for (var row = 0; row < 4; row++) {
812 for (var col = 0; col < 4; col++)
813 state[row][col] = INVSBOX[state[row][col]];
814 }
815
816 // Add round key
817 for (var row = 0; row < 4; row++) {
818 for (var col = 0; col < 4; col++)
819 state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row];
820 }
821
822 // Inv mix columns
823 for (var col = 0; col < 4; col++) {
824
825 var s0 = state[0][col],
826 s1 = state[1][col],
827 s2 = state[2][col],
828 s3 = state[3][col];
829
830 state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3];
831 state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3];
832 state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3];
833 state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3];
834
835 }
836
837 }
838
839 // Inv shift rows
840 state[1].unshift(state[1].pop());
841 state[2].push(state[2].shift());
842 state[2].push(state[2].shift());
843 state[3].push(state[3].shift());
844
845 // Inv sub bytes
846 for (var row = 0; row < 4; row++) {
847 for (var col = 0; col < 4; col++)
848 state[row][col] = INVSBOX[state[row][col]];
849 }
850
851 // Add round key
852 for (var row = 0; row < 4; row++) {
853 for (var col = 0; col < 4; col++)
854 state[row][col] ^= keyschedule[col][row];
855 }
856
857 // Set output
858 for (var row = 0; row < AES._blocksize; row++) {
859 for (var col = 0; col < 4; col++)
860 c[offset + col * 4 + row] = state[row][col];
861 }
862
863 },
864
865
866 /**
867 * Private methods
868 */
869
870 _init: function (k) {
871 keylength = k.length / 4;
872 nrounds = keylength + 6;
873 AES._keyexpansion(k);
874 },
875
876 // Generate a key schedule
877 _keyexpansion: function (k) {
878
879 keyschedule = [];
880
881 for (var row = 0; row < keylength; row++) {
882 keyschedule[row] = [
883 k[row * 4],
884 k[row * 4 + 1],
885 k[row * 4 + 2],
886 k[row * 4 + 3]
887 ];
888 }
889
890 for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) {
891
892 var temp = [
893 keyschedule[row - 1][0],
894 keyschedule[row - 1][1],
895 keyschedule[row - 1][2],
896 keyschedule[row - 1][3]
897 ];
898
899 if (row % keylength == 0) {
900
901 // Rot word
902 temp.push(temp.shift());
903
904 // Sub word
905 temp[0] = SBOX[temp[0]];
906 temp[1] = SBOX[temp[1]];
907 temp[2] = SBOX[temp[2]];
908 temp[3] = SBOX[temp[3]];
909
910 temp[0] ^= RCON[row / keylength];
911
912 } else if (keylength > 6 && row % keylength == 4) {
913
914 // Sub word
915 temp[0] = SBOX[temp[0]];
916 temp[1] = SBOX[temp[1]];
917 temp[2] = SBOX[temp[2]];
918 temp[3] = SBOX[temp[3]];
919
920 }
921
922 keyschedule[row] = [
923 keyschedule[row - keylength][0] ^ temp[0],
924 keyschedule[row - keylength][1] ^ temp[1],
925 keyschedule[row - keylength][2] ^ temp[2],
926 keyschedule[row - keylength][3] ^ temp[3]
927 ];
928
929 }
930
931 }
932
933 };
934
935})();
936 </script>
937 <script type="text/javascript">
938/*!
939* Crypto-JS 2.5.4 BlockModes.js
940* contribution from Simon Greatrix
941*/
942
943(function (C) {
944
945 // Create pad namespace
946 var C_pad = C.pad = {};
947
948 // Calculate the number of padding bytes required.
949 function _requiredPadding(cipher, message) {
950 var blockSizeInBytes = cipher._blocksize * 4;
951 var reqd = blockSizeInBytes - message.length % blockSizeInBytes;
952 return reqd;
953 }
954
955 // Remove padding when the final byte gives the number of padding bytes.
956 var _unpadLength = function (cipher, message, alg, padding) {
957 var pad = message.pop();
958 if (pad == 0) {
959 throw new Error("Invalid zero-length padding specified for " + alg
960 + ". Wrong cipher specification or key used?");
961 }
962 var maxPad = cipher._blocksize * 4;
963 if (pad > maxPad) {
964 throw new Error("Invalid padding length of " + pad
965 + " specified for " + alg
966 + ". Wrong cipher specification or key used?");
967 }
968 for (var i = 1; i < pad; i++) {
969 var b = message.pop();
970 if (padding != undefined && padding != b) {
971 throw new Error("Invalid padding byte of 0x" + b.toString(16)
972 + " specified for " + alg
973 + ". Wrong cipher specification or key used?");
974 }
975 }
976 };
977
978 // No-operation padding, used for stream ciphers
979 C_pad.NoPadding = {
980 pad: function (cipher, message) { },
981 unpad: function (cipher, message) { }
982 };
983
984 // Zero Padding.
985 //
986 // If the message is not an exact number of blocks, the final block is
987 // completed with 0x00 bytes. There is no unpadding.
988 C_pad.ZeroPadding = {
989 pad: function (cipher, message) {
990 var blockSizeInBytes = cipher._blocksize * 4;
991 var reqd = message.length % blockSizeInBytes;
992 if (reqd != 0) {
993 for (reqd = blockSizeInBytes - reqd; reqd > 0; reqd--) {
994 message.push(0x00);
995 }
996 }
997 },
998
999 unpad: function (cipher, message) {
1000 while (message[message.length - 1] == 0) {
1001 message.pop();
1002 }
1003 }
1004 };
1005
1006 // ISO/IEC 7816-4 padding.
1007 //
1008 // Pads the plain text with an 0x80 byte followed by as many 0x00
1009 // bytes are required to complete the block.
1010 C_pad.iso7816 = {
1011 pad: function (cipher, message) {
1012 var reqd = _requiredPadding(cipher, message);
1013 message.push(0x80);
1014 for (; reqd > 1; reqd--) {
1015 message.push(0x00);
1016 }
1017 },
1018
1019 unpad: function (cipher, message) {
1020 var padLength;
1021 for (padLength = cipher._blocksize * 4; padLength > 0; padLength--) {
1022 var b = message.pop();
1023 if (b == 0x80) return;
1024 if (b != 0x00) {
1025 throw new Error("ISO-7816 padding byte must be 0, not 0x" + b.toString(16) + ". Wrong cipher specification or key used?");
1026 }
1027 }
1028 throw new Error("ISO-7816 padded beyond cipher block size. Wrong cipher specification or key used?");
1029 }
1030 };
1031
1032 // ANSI X.923 padding
1033 //
1034 // The final block is padded with zeros except for the last byte of the
1035 // last block which contains the number of padding bytes.
1036 C_pad.ansix923 = {
1037 pad: function (cipher, message) {
1038 var reqd = _requiredPadding(cipher, message);
1039 for (var i = 1; i < reqd; i++) {
1040 message.push(0x00);
1041 }
1042 message.push(reqd);
1043 },
1044
1045 unpad: function (cipher, message) {
1046 _unpadLength(cipher, message, "ANSI X.923", 0);
1047 }
1048 };
1049
1050 // ISO 10126
1051 //
1052 // The final block is padded with random bytes except for the last
1053 // byte of the last block which contains the number of padding bytes.
1054 C_pad.iso10126 = {
1055 pad: function (cipher, message) {
1056 var reqd = _requiredPadding(cipher, message);
1057 for (var i = 1; i < reqd; i++) {
1058 message.push(Math.floor(Math.random() * 256));
1059 }
1060 message.push(reqd);
1061 },
1062
1063 unpad: function (cipher, message) {
1064 _unpadLength(cipher, message, "ISO 10126", undefined);
1065 }
1066 };
1067
1068 // PKCS7 padding
1069 //
1070 // PKCS7 is described in RFC 5652. Padding is in whole bytes. The
1071 // value of each added byte is the number of bytes that are added,
1072 // i.e. N bytes, each of value N are added.
1073 C_pad.pkcs7 = {
1074 pad: function (cipher, message) {
1075 var reqd = _requiredPadding(cipher, message);
1076 for (var i = 0; i < reqd; i++) {
1077 message.push(reqd);
1078 }
1079 },
1080
1081 unpad: function (cipher, message) {
1082 _unpadLength(cipher, message, "PKCS 7", message[message.length - 1]);
1083 }
1084 };
1085
1086 // Create mode namespace
1087 var C_mode = C.mode = {};
1088
1089 /**
1090 * Mode base "class".
1091 */
1092 var Mode = C_mode.Mode = function (padding) {
1093 if (padding) {
1094 this._padding = padding;
1095 }
1096 };
1097
1098 Mode.prototype = {
1099 encrypt: function (cipher, m, iv) {
1100 this._padding.pad(cipher, m);
1101 this._doEncrypt(cipher, m, iv);
1102 },
1103
1104 decrypt: function (cipher, m, iv) {
1105 this._doDecrypt(cipher, m, iv);
1106 this._padding.unpad(cipher, m);
1107 },
1108
1109 // Default padding
1110 _padding: C_pad.iso7816
1111 };
1112
1113
1114 /**
1115 * Electronic Code Book mode.
1116 *
1117 * ECB applies the cipher directly against each block of the input.
1118 *
1119 * ECB does not require an initialization vector.
1120 */
1121 var ECB = C_mode.ECB = function () {
1122 // Call parent constructor
1123 Mode.apply(this, arguments);
1124 };
1125
1126 // Inherit from Mode
1127 var ECB_prototype = ECB.prototype = new Mode;
1128
1129 // Concrete steps for Mode template
1130 ECB_prototype._doEncrypt = function (cipher, m, iv) {
1131 var blockSizeInBytes = cipher._blocksize * 4;
1132 // Encrypt each block
1133 for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
1134 cipher._encryptblock(m, offset);
1135 }
1136 };
1137 ECB_prototype._doDecrypt = function (cipher, c, iv) {
1138 var blockSizeInBytes = cipher._blocksize * 4;
1139 // Decrypt each block
1140 for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
1141 cipher._decryptblock(c, offset);
1142 }
1143 };
1144
1145 // ECB never uses an IV
1146 ECB_prototype.fixOptions = function (options) {
1147 options.iv = [];
1148 };
1149
1150
1151 /**
1152 * Cipher block chaining
1153 *
1154 * The first block is XORed with the IV. Subsequent blocks are XOR with the
1155 * previous cipher output.
1156 */
1157 var CBC = C_mode.CBC = function () {
1158 // Call parent constructor
1159 Mode.apply(this, arguments);
1160 };
1161
1162 // Inherit from Mode
1163 var CBC_prototype = CBC.prototype = new Mode;
1164
1165 // Concrete steps for Mode template
1166 CBC_prototype._doEncrypt = function (cipher, m, iv) {
1167 var blockSizeInBytes = cipher._blocksize * 4;
1168
1169 // Encrypt each block
1170 for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
1171 if (offset == 0) {
1172 // XOR first block using IV
1173 for (var i = 0; i < blockSizeInBytes; i++)
1174 m[i] ^= iv[i];
1175 } else {
1176 // XOR this block using previous crypted block
1177 for (var i = 0; i < blockSizeInBytes; i++)
1178 m[offset + i] ^= m[offset + i - blockSizeInBytes];
1179 }
1180 // Encrypt block
1181 cipher._encryptblock(m, offset);
1182 }
1183 };
1184 CBC_prototype._doDecrypt = function (cipher, c, iv) {
1185 var blockSizeInBytes = cipher._blocksize * 4;
1186
1187 // At the start, the previously crypted block is the IV
1188 var prevCryptedBlock = iv;
1189
1190 // Decrypt each block
1191 for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
1192 // Save this crypted block
1193 var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
1194 // Decrypt block
1195 cipher._decryptblock(c, offset);
1196 // XOR decrypted block using previous crypted block
1197 for (var i = 0; i < blockSizeInBytes; i++) {
1198 c[offset + i] ^= prevCryptedBlock[i];
1199 }
1200 prevCryptedBlock = thisCryptedBlock;
1201 }
1202 };
1203
1204
1205 /**
1206 * Cipher feed back
1207 *
1208 * The cipher output is XORed with the plain text to produce the cipher output,
1209 * which is then fed back into the cipher to produce a bit pattern to XOR the
1210 * next block with.
1211 *
1212 * This is a stream cipher mode and does not require padding.
1213 */
1214 var CFB = C_mode.CFB = function () {
1215 // Call parent constructor
1216 Mode.apply(this, arguments);
1217 };
1218
1219 // Inherit from Mode
1220 var CFB_prototype = CFB.prototype = new Mode;
1221
1222 // Override padding
1223 CFB_prototype._padding = C_pad.NoPadding;
1224
1225 // Concrete steps for Mode template
1226 CFB_prototype._doEncrypt = function (cipher, m, iv) {
1227 var blockSizeInBytes = cipher._blocksize * 4,
1228 keystream = iv.slice(0);
1229
1230 // Encrypt each byte
1231 for (var i = 0; i < m.length; i++) {
1232
1233 var j = i % blockSizeInBytes;
1234 if (j == 0) cipher._encryptblock(keystream, 0);
1235
1236 m[i] ^= keystream[j];
1237 keystream[j] = m[i];
1238 }
1239 };
1240 CFB_prototype._doDecrypt = function (cipher, c, iv) {
1241 var blockSizeInBytes = cipher._blocksize * 4,
1242 keystream = iv.slice(0);
1243
1244 // Encrypt each byte
1245 for (var i = 0; i < c.length; i++) {
1246
1247 var j = i % blockSizeInBytes;
1248 if (j == 0) cipher._encryptblock(keystream, 0);
1249
1250 var b = c[i];
1251 c[i] ^= keystream[j];
1252 keystream[j] = b;
1253 }
1254 };
1255
1256
1257 /**
1258 * Output feed back
1259 *
1260 * The cipher repeatedly encrypts its own output. The output is XORed with the
1261 * plain text to produce the cipher text.
1262 *
1263 * This is a stream cipher mode and does not require padding.
1264 */
1265 var OFB = C_mode.OFB = function () {
1266 // Call parent constructor
1267 Mode.apply(this, arguments);
1268 };
1269
1270 // Inherit from Mode
1271 var OFB_prototype = OFB.prototype = new Mode;
1272
1273 // Override padding
1274 OFB_prototype._padding = C_pad.NoPadding;
1275
1276 // Concrete steps for Mode template
1277 OFB_prototype._doEncrypt = function (cipher, m, iv) {
1278
1279 var blockSizeInBytes = cipher._blocksize * 4,
1280 keystream = iv.slice(0);
1281
1282 // Encrypt each byte
1283 for (var i = 0; i < m.length; i++) {
1284
1285 // Generate keystream
1286 if (i % blockSizeInBytes == 0)
1287 cipher._encryptblock(keystream, 0);
1288
1289 // Encrypt byte
1290 m[i] ^= keystream[i % blockSizeInBytes];
1291
1292 }
1293 };
1294 OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
1295
1296 /**
1297 * Counter
1298 * @author Gergely Risko
1299 *
1300 * After every block the last 4 bytes of the IV is increased by one
1301 * with carry and that IV is used for the next block.
1302 *
1303 * This is a stream cipher mode and does not require padding.
1304 */
1305 var CTR = C_mode.CTR = function () {
1306 // Call parent constructor
1307 Mode.apply(this, arguments);
1308 };
1309
1310 // Inherit from Mode
1311 var CTR_prototype = CTR.prototype = new Mode;
1312
1313 // Override padding
1314 CTR_prototype._padding = C_pad.NoPadding;
1315
1316 CTR_prototype._doEncrypt = function (cipher, m, iv) {
1317 var blockSizeInBytes = cipher._blocksize * 4;
1318 var counter = iv.slice(0);
1319
1320 for (var i = 0; i < m.length; ) {
1321 // do not lose iv
1322 var keystream = counter.slice(0);
1323
1324 // Generate keystream for next block
1325 cipher._encryptblock(keystream, 0);
1326
1327 // XOR keystream with block
1328 for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
1329 m[i] ^= keystream[j];
1330 }
1331
1332 // Increase counter
1333 if (++(counter[blockSizeInBytes - 1]) == 256) {
1334 counter[blockSizeInBytes - 1] = 0;
1335 if (++(counter[blockSizeInBytes - 2]) == 256) {
1336 counter[blockSizeInBytes - 2] = 0;
1337 if (++(counter[blockSizeInBytes - 3]) == 256) {
1338 counter[blockSizeInBytes - 3] = 0;
1339 ++(counter[blockSizeInBytes - 4]);
1340 }
1341 }
1342 }
1343 }
1344 };
1345 CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
1346
1347})(Crypto);
1348 </script>
1349 <script type="text/javascript">
1350/*!
1351* Crypto-JS v2.0.0 RIPEMD-160
1352* http://code.google.com/p/crypto-js/
1353* Copyright (c) 2009, Jeff Mott. All rights reserved.
1354* http://code.google.com/p/crypto-js/wiki/License
1355*
1356* A JavaScript implementation of the RIPEMD-160 Algorithm
1357* Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
1358* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
1359* Distributed under the BSD License
1360* See http://pajhome.org.uk/crypt/md5 for details.
1361* Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
1362* Ported to Crypto-JS by Stefan Thomas.
1363*/
1364
1365(function () {
1366 // Shortcuts
1367 var C = Crypto,
1368 util = C.util,
1369 charenc = C.charenc,
1370 UTF8 = charenc.UTF8,
1371 Binary = charenc.Binary;
1372
1373 // Convert a byte array to little-endian 32-bit words
1374 util.bytesToLWords = function (bytes) {
1375
1376 var output = Array(bytes.length >> 2);
1377 for (var i = 0; i < output.length; i++)
1378 output[i] = 0;
1379 for (var i = 0; i < bytes.length * 8; i += 8)
1380 output[i >> 5] |= (bytes[i / 8] & 0xFF) << (i % 32);
1381 return output;
1382 };
1383
1384 // Convert little-endian 32-bit words to a byte array
1385 util.lWordsToBytes = function (words) {
1386 var output = [];
1387 for (var i = 0; i < words.length * 32; i += 8)
1388 output.push((words[i >> 5] >>> (i % 32)) & 0xff);
1389 return output;
1390 };
1391
1392 // Public API
1393 var RIPEMD160 = C.RIPEMD160 = function (message, options) {
1394 var digestbytes = util.lWordsToBytes(RIPEMD160._rmd160(message));
1395 return options && options.asBytes ? digestbytes :
1396 options && options.asString ? Binary.bytesToString(digestbytes) :
1397 util.bytesToHex(digestbytes);
1398 };
1399
1400 // The core
1401 RIPEMD160._rmd160 = function (message) {
1402 // Convert to byte array
1403 if (message.constructor == String) message = UTF8.stringToBytes(message);
1404
1405 var x = util.bytesToLWords(message),
1406 len = message.length * 8;
1407
1408 /* append padding */
1409 x[len >> 5] |= 0x80 << (len % 32);
1410 x[(((len + 64) >>> 9) << 4) + 14] = len;
1411
1412 var h0 = 0x67452301;
1413 var h1 = 0xefcdab89;
1414 var h2 = 0x98badcfe;
1415 var h3 = 0x10325476;
1416 var h4 = 0xc3d2e1f0;
1417
1418 for (var i = 0; i < x.length; i += 16) {
1419 var T;
1420 var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
1421 var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
1422 for (var j = 0; j <= 79; ++j) {
1423 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
1424 T = safe_add(T, x[i + rmd160_r1[j]]);
1425 T = safe_add(T, rmd160_K1(j));
1426 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
1427 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
1428 T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
1429 T = safe_add(T, x[i + rmd160_r2[j]]);
1430 T = safe_add(T, rmd160_K2(j));
1431 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
1432 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
1433 }
1434 T = safe_add(h1, safe_add(C1, D2));
1435 h1 = safe_add(h2, safe_add(D1, E2));
1436 h2 = safe_add(h3, safe_add(E1, A2));
1437 h3 = safe_add(h4, safe_add(A1, B2));
1438 h4 = safe_add(h0, safe_add(B1, C2));
1439 h0 = T;
1440 }
1441 return [h0, h1, h2, h3, h4];
1442 }
1443
1444 function rmd160_f(j, x, y, z) {
1445 return (0 <= j && j <= 15) ? (x ^ y ^ z) :
1446 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
1447 (32 <= j && j <= 47) ? (x | ~y) ^ z :
1448 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
1449 (64 <= j && j <= 79) ? x ^ (y | ~z) :
1450 "rmd160_f: j out of range";
1451 }
1452 function rmd160_K1(j) {
1453 return (0 <= j && j <= 15) ? 0x00000000 :
1454 (16 <= j && j <= 31) ? 0x5a827999 :
1455 (32 <= j && j <= 47) ? 0x6ed9eba1 :
1456 (48 <= j && j <= 63) ? 0x8f1bbcdc :
1457 (64 <= j && j <= 79) ? 0xa953fd4e :
1458 "rmd160_K1: j out of range";
1459 }
1460 function rmd160_K2(j) {
1461 return (0 <= j && j <= 15) ? 0x50a28be6 :
1462 (16 <= j && j <= 31) ? 0x5c4dd124 :
1463 (32 <= j && j <= 47) ? 0x6d703ef3 :
1464 (48 <= j && j <= 63) ? 0x7a6d76e9 :
1465 (64 <= j && j <= 79) ? 0x00000000 :
1466 "rmd160_K2: j out of range";
1467 }
1468 var rmd160_r1 = [
1469 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1470 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
1471 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
1472 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
1473 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
1474 ];
1475 var rmd160_r2 = [
1476 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
1477 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
1478 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
1479 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
1480 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
1481 ];
1482 var rmd160_s1 = [
1483 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
1484 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
1485 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
1486 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
1487 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
1488 ];
1489 var rmd160_s2 = [
1490 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
1491 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
1492 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
1493 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
1494 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
1495 ];
1496
1497 /*
1498 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
1499 * to work around bugs in some JS interpreters.
1500 */
1501 function safe_add(x, y) {
1502 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
1503 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
1504 return (msw << 16) | (lsw & 0xFFFF);
1505 }
1506
1507 /*
1508 * Bitwise rotate a 32-bit number to the left.
1509 */
1510 function bit_rol(num, cnt) {
1511 return (num << cnt) | (num >>> (32 - cnt));
1512 }
1513})();
1514 </script>
1515 <script type="text/javascript">
1516/*!
1517* Random number generator with ArcFour PRNG
1518*
1519* NOTE: For best results, put code like
1520* <body onclick='SecureRandom.seedTime();' onkeypress='SecureRandom.seedTime();'>
1521* in your main HTML document.
1522*
1523* Copyright Tom Wu, bitaddress.org BSD License.
1524* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
1525*/
1526(function () {
1527
1528 // Constructor function of Global SecureRandom object
1529 var sr = window.SecureRandom = function () { };
1530
1531 // Properties
1532 sr.state;
1533 sr.pool;
1534 sr.pptr;
1535
1536 // Pool size must be a multiple of 4 and greater than 32.
1537 // An array of bytes the size of the pool will be passed to init()
1538 sr.poolSize = 256;
1539
1540 // --- object methods ---
1541
1542 // public method
1543 // ba: byte array
1544 sr.prototype.nextBytes = function (ba) {
1545 var i;
1546 if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) {
1547 try {
1548 var rvBytes = new Uint8Array(ba.length);
1549 window.crypto.getRandomValues(rvBytes);
1550 for (i = 0; i < ba.length; ++i)
1551 ba[i] = sr.getByte() ^ rvBytes[i];
1552 return;
1553 } catch (e) {
1554 alert(e);
1555 }
1556 }
1557 for (i = 0; i < ba.length; ++i) ba[i] = sr.getByte();
1558 };
1559
1560
1561 // --- static methods ---
1562
1563 // Mix in the current time (w/milliseconds) into the pool
1564 // NOTE: this method should be called from body click/keypress event handlers to increase entropy
1565 sr.seedTime = function () {
1566 sr.seedInt(new Date().getTime());
1567 }
1568
1569 sr.getByte = function () {
1570 if(!ninja.seeder.isDone()) {
1571 alert("Premature initialisation of the random generator. Something is really wrong, do not generate wallets.");
1572 return NaN;
1573 }
1574
1575 if (sr.state == null) {
1576 sr.seedTime();
1577 sr.state = sr.ArcFour(); // Plug in your RNG constructor here
1578 sr.state.init(sr.pool);
1579 sr.pptr = 0;
1580 }
1581 // TODO: allow reseeding after first request
1582 return sr.state.next();
1583 }
1584
1585 // Mix in a 32-bit integer into the pool
1586 sr.seedInt = function (x) {
1587 sr.seedInt8(x);
1588 sr.seedInt8((x >> 8));
1589 sr.seedInt8((x >> 16));
1590 sr.seedInt8((x >> 24));
1591 }
1592
1593 // Mix in a 16-bit integer into the pool
1594 sr.seedInt16 = function (x) {
1595 sr.seedInt8(x);
1596 sr.seedInt8((x >> 8));
1597 }
1598
1599 // Mix in a 8-bit integer into the pool
1600 sr.seedInt8 = function (x) {
1601 sr.pool[sr.pptr++] ^= x & 255;
1602 if (sr.pptr >= sr.poolSize) sr.pptr -= sr.poolSize;
1603 }
1604
1605 // Arcfour is a PRNG
1606 sr.ArcFour = function () {
1607 function Arcfour() {
1608 this.i = 0;
1609 this.j = 0;
1610 this.S = new Array();
1611 }
1612
1613 // Initialize arcfour context from key, an array of ints, each from [0..255]
1614 function ARC4init(key) {
1615 var i, j, t;
1616 for (i = 0; i < 256; ++i)
1617 this.S[i] = i;
1618 j = 0;
1619 for (i = 0; i < 256; ++i) {
1620 j = (j + this.S[i] + key[i % key.length]) & 255;
1621 t = this.S[i];
1622 this.S[i] = this.S[j];
1623 this.S[j] = t;
1624 }
1625 this.i = 0;
1626 this.j = 0;
1627 }
1628
1629 function ARC4next() {
1630 var t;
1631 this.i = (this.i + 1) & 255;
1632 this.j = (this.j + this.S[this.i]) & 255;
1633 t = this.S[this.i];
1634 this.S[this.i] = this.S[this.j];
1635 this.S[this.j] = t;
1636 return this.S[(t + this.S[this.i]) & 255];
1637 }
1638
1639 Arcfour.prototype.init = ARC4init;
1640 Arcfour.prototype.next = ARC4next;
1641
1642 return new Arcfour();
1643 };
1644
1645
1646 // Initialize the pool with junk if needed.
1647 if (sr.pool == null) {
1648 sr.pool = new Array();
1649 sr.pptr = 0;
1650 var t;
1651 if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) {
1652 try {
1653 // Use webcrypto if available
1654 var ua = new Uint8Array(sr.poolSize);
1655 window.crypto.getRandomValues(ua);
1656 for (t = 0; t < sr.poolSize; ++t)
1657 sr.pool[sr.pptr++] = ua[t];
1658 } catch (e) { alert(e); }
1659 }
1660 while (sr.pptr < sr.poolSize) { // extract some randomness from Math.random()
1661 t = Math.floor(65536 * Math.random());
1662 sr.pool[sr.pptr++] = t >>> 8;
1663 sr.pool[sr.pptr++] = t & 255;
1664 }
1665 sr.pptr = Math.floor(sr.poolSize * Math.random());
1666 sr.seedTime();
1667 // entropy
1668 var entropyStr = "";
1669 // screen size and color depth: ~4.8 to ~5.4 bits
1670 entropyStr += (window.screen.height * window.screen.width * window.screen.colorDepth);
1671 entropyStr += (window.screen.availHeight * window.screen.availWidth * window.screen.pixelDepth);
1672 // time zone offset: ~4 bits
1673 var dateObj = new Date();
1674 var timeZoneOffset = dateObj.getTimezoneOffset();
1675 entropyStr += timeZoneOffset;
1676 // user agent: ~8.3 to ~11.6 bits
1677 entropyStr += navigator.userAgent;
1678 // browser plugin details: ~16.2 to ~21.8 bits
1679 var pluginsStr = "";
1680 for (var i = 0; i < navigator.plugins.length; i++) {
1681 pluginsStr += navigator.plugins[i].name + " " + navigator.plugins[i].filename + " " + navigator.plugins[i].description + " " + navigator.plugins[i].version + ", ";
1682 }
1683 var mimeTypesStr = "";
1684 for (var i = 0; i < navigator.mimeTypes.length; i++) {
1685 mimeTypesStr += navigator.mimeTypes[i].description + " " + navigator.mimeTypes[i].type + " " + navigator.mimeTypes[i].suffixes + ", ";
1686 }
1687 entropyStr += pluginsStr + mimeTypesStr;
1688 // cookies and storage: 1 bit
1689 entropyStr += navigator.cookieEnabled + typeof (sessionStorage) + typeof (localStorage);
1690 // language: ~7 bit
1691 entropyStr += navigator.language;
1692 // history: ~2 bit
1693 entropyStr += window.history.length;
1694 // location
1695 entropyStr += window.location;
1696
1697 var entropyBytes = Crypto.SHA256(entropyStr, { asBytes: true });
1698 for (var i = 0 ; i < entropyBytes.length ; i++) {
1699 sr.seedInt8(entropyBytes[i]);
1700 }
1701 }
1702})();
1703 </script>
1704 <script type="text/javascript">
1705//https://raw.github.com/bitcoinjs/bitcoinjs-lib/faa10f0f6a1fff0b9a99fffb9bc30cee33b17212/src/ecdsa.js
1706/*!
1707* Basic Javascript Elliptic Curve implementation
1708* Ported loosely from BouncyCastle's Java EC code
1709* Only Fp curves implemented for now
1710*
1711* Copyright Tom Wu, bitaddress.org BSD License.
1712* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
1713*/
1714(function () {
1715
1716 // Constructor function of Global EllipticCurve object
1717 var ec = window.EllipticCurve = function () { };
1718
1719
1720 // ----------------
1721 // ECFieldElementFp constructor
1722 // q instanceof BigInteger
1723 // x instanceof BigInteger
1724 ec.FieldElementFp = function (q, x) {
1725 this.x = x;
1726 // TODO if(x.compareTo(q) >= 0) error
1727 this.q = q;
1728 };
1729
1730 ec.FieldElementFp.prototype.equals = function (other) {
1731 if (other == this) return true;
1732 return (this.q.equals(other.q) && this.x.equals(other.x));
1733 };
1734
1735 ec.FieldElementFp.prototype.toBigInteger = function () {
1736 return this.x;
1737 };
1738
1739 ec.FieldElementFp.prototype.negate = function () {
1740 return new ec.FieldElementFp(this.q, this.x.negate().mod(this.q));
1741 };
1742
1743 ec.FieldElementFp.prototype.add = function (b) {
1744 return new ec.FieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));
1745 };
1746
1747 ec.FieldElementFp.prototype.subtract = function (b) {
1748 return new ec.FieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));
1749 };
1750
1751 ec.FieldElementFp.prototype.multiply = function (b) {
1752 return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));
1753 };
1754
1755 ec.FieldElementFp.prototype.square = function () {
1756 return new ec.FieldElementFp(this.q, this.x.square().mod(this.q));
1757 };
1758
1759 ec.FieldElementFp.prototype.divide = function (b) {
1760 return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));
1761 };
1762
1763 ec.FieldElementFp.prototype.getByteLength = function () {
1764 return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
1765 };
1766
1767 // D.1.4 91
1768 /**
1769 * return a sqrt root - the routine verifies that the calculation
1770 * returns the right value - if none exists it returns null.
1771 *
1772 * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
1773 * Ported to JavaScript by bitaddress.org
1774 */
1775 ec.FieldElementFp.prototype.sqrt = function () {
1776 if (!this.q.testBit(0)) throw new Error("even value of q");
1777
1778 // p mod 4 == 3
1779 if (this.q.testBit(1)) {
1780 // z = g^(u+1) + p, p = 4u + 3
1781 var z = new ec.FieldElementFp(this.q, this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE), this.q));
1782 return z.square().equals(this) ? z : null;
1783 }
1784
1785 // p mod 4 == 1
1786 var qMinusOne = this.q.subtract(BigInteger.ONE);
1787 var legendreExponent = qMinusOne.shiftRight(1);
1788 if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE))) return null;
1789 var u = qMinusOne.shiftRight(2);
1790 var k = u.shiftLeft(1).add(BigInteger.ONE);
1791 var Q = this.x;
1792 var fourQ = Q.shiftLeft(2).mod(this.q);
1793 var U, V;
1794
1795 do {
1796 var rand = new SecureRandom();
1797 var P;
1798 do {
1799 P = new BigInteger(this.q.bitLength(), rand);
1800 }
1801 while (P.compareTo(this.q) >= 0 || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));
1802
1803 var result = ec.FieldElementFp.fastLucasSequence(this.q, P, Q, k);
1804
1805 U = result[0];
1806 V = result[1];
1807 if (V.multiply(V).mod(this.q).equals(fourQ)) {
1808 // Integer division by 2, mod q
1809 if (V.testBit(0)) {
1810 V = V.add(this.q);
1811 }
1812 V = V.shiftRight(1);
1813 return new ec.FieldElementFp(this.q, V);
1814 }
1815 }
1816 while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));
1817
1818 return null;
1819 };
1820
1821 /*
1822 * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
1823 * Ported to JavaScript by bitaddress.org
1824 */
1825 ec.FieldElementFp.fastLucasSequence = function (p, P, Q, k) {
1826 // TODO Research and apply "common-multiplicand multiplication here"
1827
1828 var n = k.bitLength();
1829 var s = k.getLowestSetBit();
1830 var Uh = BigInteger.ONE;
1831 var Vl = BigInteger.TWO;
1832 var Vh = P;
1833 var Ql = BigInteger.ONE;
1834 var Qh = BigInteger.ONE;
1835
1836 for (var j = n - 1; j >= s + 1; --j) {
1837 Ql = Ql.multiply(Qh).mod(p);
1838 if (k.testBit(j)) {
1839 Qh = Ql.multiply(Q).mod(p);
1840 Uh = Uh.multiply(Vh).mod(p);
1841 Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
1842 Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
1843 }
1844 else {
1845 Qh = Ql;
1846 Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
1847 Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
1848 Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
1849 }
1850 }
1851
1852 Ql = Ql.multiply(Qh).mod(p);
1853 Qh = Ql.multiply(Q).mod(p);
1854 Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
1855 Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
1856 Ql = Ql.multiply(Qh).mod(p);
1857
1858 for (var j = 1; j <= s; ++j) {
1859 Uh = Uh.multiply(Vl).mod(p);
1860 Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
1861 Ql = Ql.multiply(Ql).mod(p);
1862 }
1863
1864 return [Uh, Vl];
1865 };
1866
1867 // ----------------
1868 // ECPointFp constructor
1869 ec.PointFp = function (curve, x, y, z, compressed) {
1870 this.curve = curve;
1871 this.x = x;
1872 this.y = y;
1873 // Projective coordinates: either zinv == null or z * zinv == 1
1874 // z and zinv are just BigIntegers, not fieldElements
1875 if (z == null) {
1876 this.z = BigInteger.ONE;
1877 }
1878 else {
1879 this.z = z;
1880 }
1881 this.zinv = null;
1882 // compression flag
1883 this.compressed = !!compressed;
1884 };
1885
1886 ec.PointFp.prototype.getX = function () {
1887 if (this.zinv == null) {
1888 this.zinv = this.z.modInverse(this.curve.q);
1889 }
1890 var r = this.x.toBigInteger().multiply(this.zinv);
1891 this.curve.reduce(r);
1892 return this.curve.fromBigInteger(r);
1893 };
1894
1895 ec.PointFp.prototype.getY = function () {
1896 if (this.zinv == null) {
1897 this.zinv = this.z.modInverse(this.curve.q);
1898 }
1899 var r = this.y.toBigInteger().multiply(this.zinv);
1900 this.curve.reduce(r);
1901 return this.curve.fromBigInteger(r);
1902 };
1903
1904 ec.PointFp.prototype.equals = function (other) {
1905 if (other == this) return true;
1906 if (this.isInfinity()) return other.isInfinity();
1907 if (other.isInfinity()) return this.isInfinity();
1908 var u, v;
1909 // u = Y2 * Z1 - Y1 * Z2
1910 u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
1911 if (!u.equals(BigInteger.ZERO)) return false;
1912 // v = X2 * Z1 - X1 * Z2
1913 v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
1914 return v.equals(BigInteger.ZERO);
1915 };
1916
1917 ec.PointFp.prototype.isInfinity = function () {
1918 if ((this.x == null) && (this.y == null)) return true;
1919 return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
1920 };
1921
1922 ec.PointFp.prototype.negate = function () {
1923 return new ec.PointFp(this.curve, this.x, this.y.negate(), this.z);
1924 };
1925
1926 ec.PointFp.prototype.add = function (b) {
1927 if (this.isInfinity()) return b;
1928 if (b.isInfinity()) return this;
1929
1930 // u = Y2 * Z1 - Y1 * Z2
1931 var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
1932 // v = X2 * Z1 - X1 * Z2
1933 var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
1934
1935
1936 if (BigInteger.ZERO.equals(v)) {
1937 if (BigInteger.ZERO.equals(u)) {
1938 return this.twice(); // this == b, so double
1939 }
1940 return this.curve.getInfinity(); // this = -b, so infinity
1941 }
1942
1943 var THREE = new BigInteger("3");
1944 var x1 = this.x.toBigInteger();
1945 var y1 = this.y.toBigInteger();
1946 var x2 = b.x.toBigInteger();
1947 var y2 = b.y.toBigInteger();
1948
1949 var v2 = v.square();
1950 var v3 = v2.multiply(v);
1951 var x1v2 = x1.multiply(v2);
1952 var zu2 = u.square().multiply(this.z);
1953
1954 // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
1955 var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
1956 // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
1957 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);
1958 // z3 = v^3 * z1 * z2
1959 var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
1960
1961 return new ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
1962 };
1963
1964 ec.PointFp.prototype.twice = function () {
1965 if (this.isInfinity()) return this;
1966 if (this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();
1967
1968 // TODO: optimized handling of constants
1969 var THREE = new BigInteger("3");
1970 var x1 = this.x.toBigInteger();
1971 var y1 = this.y.toBigInteger();
1972
1973 var y1z1 = y1.multiply(this.z);
1974 var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);
1975 var a = this.curve.a.toBigInteger();
1976
1977 // w = 3 * x1^2 + a * z1^2
1978 var w = x1.square().multiply(THREE);
1979 if (!BigInteger.ZERO.equals(a)) {
1980 w = w.add(this.z.square().multiply(a));
1981 }
1982 w = w.mod(this.curve.q);
1983 //this.curve.reduce(w);
1984 // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
1985 var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
1986 // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
1987 var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
1988 // z3 = 8 * (y1 * z1)^3
1989 var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
1990
1991 return new ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
1992 };
1993
1994 // Simple NAF (Non-Adjacent Form) multiplication algorithm
1995 // TODO: modularize the multiplication algorithm
1996 ec.PointFp.prototype.multiply = function (k) {
1997 if (this.isInfinity()) return this;
1998 if (k.signum() == 0) return this.curve.getInfinity();
1999
2000 var e = k;
2001 var h = e.multiply(new BigInteger("3"));
2002
2003 var neg = this.negate();
2004 var R = this;
2005
2006 var i;
2007 for (i = h.bitLength() - 2; i > 0; --i) {
2008 R = R.twice();
2009
2010 var hBit = h.testBit(i);
2011 var eBit = e.testBit(i);
2012
2013 if (hBit != eBit) {
2014 R = R.add(hBit ? this : neg);
2015 }
2016 }
2017
2018 return R;
2019 };
2020
2021 // Compute this*j + x*k (simultaneous multiplication)
2022 ec.PointFp.prototype.multiplyTwo = function (j, x, k) {
2023 var i;
2024 if (j.bitLength() > k.bitLength())
2025 i = j.bitLength() - 1;
2026 else
2027 i = k.bitLength() - 1;
2028
2029 var R = this.curve.getInfinity();
2030 var both = this.add(x);
2031 while (i >= 0) {
2032 R = R.twice();
2033 if (j.testBit(i)) {
2034 if (k.testBit(i)) {
2035 R = R.add(both);
2036 }
2037 else {
2038 R = R.add(this);
2039 }
2040 }
2041 else {
2042 if (k.testBit(i)) {
2043 R = R.add(x);
2044 }
2045 }
2046 --i;
2047 }
2048
2049 return R;
2050 };
2051
2052 // patched by bitaddress.org and Casascius for use with Bitcoin.ECKey
2053 // patched by coretechs to support compressed public keys
2054 ec.PointFp.prototype.getEncoded = function (compressed) {
2055 var x = this.getX().toBigInteger();
2056 var y = this.getY().toBigInteger();
2057 var len = 32; // integerToBytes will zero pad if integer is less than 32 bytes. 32 bytes length is required by the Bitcoin protocol.
2058 var enc = ec.integerToBytes(x, len);
2059
2060 // when compressed prepend byte depending if y point is even or odd
2061 if (compressed) {
2062 if (y.isEven()) {
2063 enc.unshift(0x02);
2064 }
2065 else {
2066 enc.unshift(0x03);
2067 }
2068 }
2069 else {
2070 enc.unshift(0x04);
2071 enc = enc.concat(ec.integerToBytes(y, len)); // uncompressed public key appends the bytes of the y point
2072 }
2073 return enc;
2074 };
2075
2076 ec.PointFp.decodeFrom = function (curve, enc) {
2077 var type = enc[0];
2078 var dataLen = enc.length - 1;
2079
2080 // Extract x and y as byte arrays
2081 var xBa = enc.slice(1, 1 + dataLen / 2);
2082 var yBa = enc.slice(1 + dataLen / 2, 1 + dataLen);
2083
2084 // Prepend zero byte to prevent interpretation as negative integer
2085 xBa.unshift(0);
2086 yBa.unshift(0);
2087
2088 // Convert to BigIntegers
2089 var x = new BigInteger(xBa);
2090 var y = new BigInteger(yBa);
2091
2092 // Return point
2093 return new ec.PointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
2094 };
2095
2096 ec.PointFp.prototype.add2D = function (b) {
2097 if (this.isInfinity()) return b;
2098 if (b.isInfinity()) return this;
2099
2100 if (this.x.equals(b.x)) {
2101 if (this.y.equals(b.y)) {
2102 // this = b, i.e. this must be doubled
2103 return this.twice();
2104 }
2105 // this = -b, i.e. the result is the point at infinity
2106 return this.curve.getInfinity();
2107 }
2108
2109 var x_x = b.x.subtract(this.x);
2110 var y_y = b.y.subtract(this.y);
2111 var gamma = y_y.divide(x_x);
2112
2113 var x3 = gamma.square().subtract(this.x).subtract(b.x);
2114 var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
2115
2116 return new ec.PointFp(this.curve, x3, y3);
2117 };
2118
2119 ec.PointFp.prototype.twice2D = function () {
2120 if (this.isInfinity()) return this;
2121 if (this.y.toBigInteger().signum() == 0) {
2122 // if y1 == 0, then (x1, y1) == (x1, -y1)
2123 // and hence this = -this and thus 2(x1, y1) == infinity
2124 return this.curve.getInfinity();
2125 }
2126
2127 var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
2128 var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
2129 var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
2130
2131 var x3 = gamma.square().subtract(this.x.multiply(TWO));
2132 var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
2133
2134 return new ec.PointFp(this.curve, x3, y3);
2135 };
2136
2137 ec.PointFp.prototype.multiply2D = function (k) {
2138 if (this.isInfinity()) return this;
2139 if (k.signum() == 0) return this.curve.getInfinity();
2140
2141 var e = k;
2142 var h = e.multiply(new BigInteger("3"));
2143
2144 var neg = this.negate();
2145 var R = this;
2146
2147 var i;
2148 for (i = h.bitLength() - 2; i > 0; --i) {
2149 R = R.twice();
2150
2151 var hBit = h.testBit(i);
2152 var eBit = e.testBit(i);
2153
2154 if (hBit != eBit) {
2155 R = R.add2D(hBit ? this : neg);
2156 }
2157 }
2158
2159 return R;
2160 };
2161
2162 ec.PointFp.prototype.isOnCurve = function () {
2163 var x = this.getX().toBigInteger();
2164 var y = this.getY().toBigInteger();
2165 var a = this.curve.getA().toBigInteger();
2166 var b = this.curve.getB().toBigInteger();
2167 var n = this.curve.getQ();
2168 var lhs = y.multiply(y).mod(n);
2169 var rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(n);
2170 return lhs.equals(rhs);
2171 };
2172
2173 ec.PointFp.prototype.toString = function () {
2174 return '(' + this.getX().toBigInteger().toString() + ',' + this.getY().toBigInteger().toString() + ')';
2175 };
2176
2177 /**
2178 * Validate an elliptic curve point.
2179 *
2180 * See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
2181 */
2182 ec.PointFp.prototype.validate = function () {
2183 var n = this.curve.getQ();
2184
2185 // Check Q != O
2186 if (this.isInfinity()) {
2187 throw new Error("Point is at infinity.");
2188 }
2189
2190 // Check coordinate bounds
2191 var x = this.getX().toBigInteger();
2192 var y = this.getY().toBigInteger();
2193 if (x.compareTo(BigInteger.ONE) < 0 || x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
2194 throw new Error('x coordinate out of bounds');
2195 }
2196 if (y.compareTo(BigInteger.ONE) < 0 || y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
2197 throw new Error('y coordinate out of bounds');
2198 }
2199
2200 // Check y^2 = x^3 + ax + b (mod n)
2201 if (!this.isOnCurve()) {
2202 throw new Error("Point is not on the curve.");
2203 }
2204
2205 // Check nQ = 0 (Q is a scalar multiple of G)
2206 if (this.multiply(n).isInfinity()) {
2207 // TODO: This check doesn't work - fix.
2208 throw new Error("Point is not a scalar multiple of G.");
2209 }
2210
2211 return true;
2212 };
2213
2214
2215
2216
2217 // ----------------
2218 // ECCurveFp constructor
2219 ec.CurveFp = function (q, a, b) {
2220 this.q = q;
2221 this.a = this.fromBigInteger(a);
2222 this.b = this.fromBigInteger(b);
2223 this.infinity = new ec.PointFp(this, null, null);
2224 this.reducer = new Barrett(this.q);
2225 }
2226
2227 ec.CurveFp.prototype.getQ = function () {
2228 return this.q;
2229 };
2230
2231 ec.CurveFp.prototype.getA = function () {
2232 return this.a;
2233 };
2234
2235 ec.CurveFp.prototype.getB = function () {
2236 return this.b;
2237 };
2238
2239 ec.CurveFp.prototype.equals = function (other) {
2240 if (other == this) return true;
2241 return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));
2242 };
2243
2244 ec.CurveFp.prototype.getInfinity = function () {
2245 return this.infinity;
2246 };
2247
2248 ec.CurveFp.prototype.fromBigInteger = function (x) {
2249 return new ec.FieldElementFp(this.q, x);
2250 };
2251
2252 ec.CurveFp.prototype.reduce = function (x) {
2253 this.reducer.reduce(x);
2254 };
2255
2256 // for now, work with hex strings because they're easier in JS
2257 // compressed support added by bitaddress.org
2258 ec.CurveFp.prototype.decodePointHex = function (s) {
2259 var firstByte = parseInt(s.substr(0, 2), 16);
2260 switch (firstByte) { // first byte
2261 case 0:
2262 return this.infinity;
2263 case 2: // compressed
2264 case 3: // compressed
2265 var yTilde = firstByte & 1;
2266 var xHex = s.substr(2, s.length - 2);
2267 var X1 = new BigInteger(xHex, 16);
2268 return this.decompressPoint(yTilde, X1);
2269 case 4: // uncompressed
2270 case 6: // hybrid
2271 case 7: // hybrid
2272 var len = (s.length - 2) / 2;
2273 var xHex = s.substr(2, len);
2274 var yHex = s.substr(len + 2, len);
2275
2276 return new ec.PointFp(this,
2277 this.fromBigInteger(new BigInteger(xHex, 16)),
2278 this.fromBigInteger(new BigInteger(yHex, 16)));
2279
2280 default: // unsupported
2281 return null;
2282 }
2283 };
2284
2285 ec.CurveFp.prototype.encodePointHex = function (p) {
2286 if (p.isInfinity()) return "00";
2287 var xHex = p.getX().toBigInteger().toString(16);
2288 var yHex = p.getY().toBigInteger().toString(16);
2289 var oLen = this.getQ().toString(16).length;
2290 if ((oLen % 2) != 0) oLen++;
2291 while (xHex.length < oLen) {
2292 xHex = "0" + xHex;
2293 }
2294 while (yHex.length < oLen) {
2295 yHex = "0" + yHex;
2296 }
2297 return "04" + xHex + yHex;
2298 };
2299
2300 /*
2301 * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
2302 * Ported to JavaScript by bitaddress.org
2303 *
2304 * Number yTilde
2305 * BigInteger X1
2306 */
2307 ec.CurveFp.prototype.decompressPoint = function (yTilde, X1) {
2308 var x = this.fromBigInteger(X1);
2309 var alpha = x.multiply(x.square().add(this.getA())).add(this.getB());
2310 var beta = alpha.sqrt();
2311 // if we can't find a sqrt we haven't got a point on the curve - run!
2312 if (beta == null) throw new Error("Invalid point compression");
2313 var betaValue = beta.toBigInteger();
2314 var bit0 = betaValue.testBit(0) ? 1 : 0;
2315 if (bit0 != yTilde) {
2316 // Use the other root
2317 beta = this.fromBigInteger(this.getQ().subtract(betaValue));
2318 }
2319 return new ec.PointFp(this, x, beta, null, true);
2320 };
2321
2322
2323 ec.fromHex = function (s) { return new BigInteger(s, 16); };
2324
2325 ec.integerToBytes = function (i, len) {
2326 var bytes = i.toByteArrayUnsigned();
2327 if (len < bytes.length) {
2328 bytes = bytes.slice(bytes.length - len);
2329 } else while (len > bytes.length) {
2330 bytes.unshift(0);
2331 }
2332 return bytes;
2333 };
2334
2335
2336 // Named EC curves
2337 // ----------------
2338 // X9ECParameters constructor
2339 ec.X9Parameters = function (curve, g, n, h) {
2340 this.curve = curve;
2341 this.g = g;
2342 this.n = n;
2343 this.h = h;
2344 }
2345 ec.X9Parameters.prototype.getCurve = function () { return this.curve; };
2346 ec.X9Parameters.prototype.getG = function () { return this.g; };
2347 ec.X9Parameters.prototype.getN = function () { return this.n; };
2348 ec.X9Parameters.prototype.getH = function () { return this.h; };
2349
2350 // secp256k1 is the Curve used by Bitcoin
2351 ec.secNamedCurves = {
2352 // used by Bitcoin
2353 "secp256k1": function () {
2354 // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
2355 var p = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
2356 var a = BigInteger.ZERO;
2357 var b = ec.fromHex("7");
2358 var n = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
2359 var h = BigInteger.ONE;
2360 var curve = new ec.CurveFp(p, a, b);
2361 var G = curve.decodePointHex("04"
2362 + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
2363 + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");
2364 return new ec.X9Parameters(curve, G, n, h);
2365 }
2366 };
2367
2368 // secp256k1 called by Bitcoin's ECKEY
2369 ec.getSECCurveByName = function (name) {
2370 if (ec.secNamedCurves[name] == undefined) return null;
2371 return ec.secNamedCurves[name]();
2372 }
2373})();
2374 </script>
2375 <script type="text/javascript">
2376/*!
2377* Basic JavaScript BN library - subset useful for RSA encryption. v1.3
2378*
2379* Copyright (c) 2005 Tom Wu
2380* All Rights Reserved.
2381* BSD License
2382* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
2383*
2384* Copyright Stephan Thomas
2385* Copyright bitaddress.org
2386*/
2387
2388(function () {
2389
2390 // (public) Constructor function of Global BigInteger object
2391 var BigInteger = window.BigInteger = function BigInteger(a, b, c) {
2392 if (a != null)
2393 if ("number" == typeof a) this.fromNumber(a, b, c);
2394 else if (b == null && "string" != typeof a) this.fromString(a, 256);
2395 else this.fromString(a, b);
2396 };
2397
2398 // Bits per digit
2399 var dbits;
2400
2401 // JavaScript engine analysis
2402 var canary = 0xdeadbeefcafe;
2403 var j_lm = ((canary & 0xffffff) == 0xefcafe);
2404
2405 // return new, unset BigInteger
2406 function nbi() { return new BigInteger(null); }
2407
2408 // am: Compute w_j += (x*this_i), propagate carries,
2409 // c is initial carry, returns final carry.
2410 // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
2411 // We need to select the fastest one that works in this environment.
2412
2413 // am1: use a single mult and divide to get the high bits,
2414 // max digit bits should be 26 because
2415 // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
2416 function am1(i, x, w, j, c, n) {
2417 while (--n >= 0) {
2418 var v = x * this[i++] + w[j] + c;
2419 c = Math.floor(v / 0x4000000);
2420 w[j++] = v & 0x3ffffff;
2421 }
2422 return c;
2423 }
2424 // am2 avoids a big mult-and-extract completely.
2425 // Max digit bits should be <= 30 because we do bitwise ops
2426 // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
2427 function am2(i, x, w, j, c, n) {
2428 var xl = x & 0x7fff, xh = x >> 15;
2429 while (--n >= 0) {
2430 var l = this[i] & 0x7fff;
2431 var h = this[i++] >> 15;
2432 var m = xh * l + h * xl;
2433 l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
2434 c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
2435 w[j++] = l & 0x3fffffff;
2436 }
2437 return c;
2438 }
2439 // Alternately, set max digit bits to 28 since some
2440 // browsers slow down when dealing with 32-bit numbers.
2441 function am3(i, x, w, j, c, n) {
2442 var xl = x & 0x3fff, xh = x >> 14;
2443 while (--n >= 0) {
2444 var l = this[i] & 0x3fff;
2445 var h = this[i++] >> 14;
2446 var m = xh * l + h * xl;
2447 l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
2448 c = (l >> 28) + (m >> 14) + xh * h;
2449 w[j++] = l & 0xfffffff;
2450 }
2451 return c;
2452 }
2453 if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
2454 BigInteger.prototype.am = am2;
2455 dbits = 30;
2456 }
2457 else if (j_lm && (navigator.appName != "Netscape")) {
2458 BigInteger.prototype.am = am1;
2459 dbits = 26;
2460 }
2461 else { // Mozilla/Netscape seems to prefer am3
2462 BigInteger.prototype.am = am3;
2463 dbits = 28;
2464 }
2465
2466 BigInteger.prototype.DB = dbits;
2467 BigInteger.prototype.DM = ((1 << dbits) - 1);
2468 BigInteger.prototype.DV = (1 << dbits);
2469
2470 var BI_FP = 52;
2471 BigInteger.prototype.FV = Math.pow(2, BI_FP);
2472 BigInteger.prototype.F1 = BI_FP - dbits;
2473 BigInteger.prototype.F2 = 2 * dbits - BI_FP;
2474
2475 // Digit conversions
2476 var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
2477 var BI_RC = new Array();
2478 var rr, vv;
2479 rr = "0".charCodeAt(0);
2480 for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
2481 rr = "a".charCodeAt(0);
2482 for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
2483 rr = "A".charCodeAt(0);
2484 for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
2485
2486 function int2char(n) { return BI_RM.charAt(n); }
2487 function intAt(s, i) {
2488 var c = BI_RC[s.charCodeAt(i)];
2489 return (c == null) ? -1 : c;
2490 }
2491
2492
2493
2494 // return bigint initialized to value
2495 function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
2496
2497
2498 // returns bit length of the integer x
2499 function nbits(x) {
2500 var r = 1, t;
2501 if ((t = x >>> 16) != 0) { x = t; r += 16; }
2502 if ((t = x >> 8) != 0) { x = t; r += 8; }
2503 if ((t = x >> 4) != 0) { x = t; r += 4; }
2504 if ((t = x >> 2) != 0) { x = t; r += 2; }
2505 if ((t = x >> 1) != 0) { x = t; r += 1; }
2506 return r;
2507 }
2508
2509
2510
2511
2512
2513
2514
2515 // (protected) copy this to r
2516 BigInteger.prototype.copyTo = function (r) {
2517 for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
2518 r.t = this.t;
2519 r.s = this.s;
2520 };
2521
2522
2523 // (protected) set from integer value x, -DV <= x < DV
2524 BigInteger.prototype.fromInt = function (x) {
2525 this.t = 1;
2526 this.s = (x < 0) ? -1 : 0;
2527 if (x > 0) this[0] = x;
2528 else if (x < -1) this[0] = x + this.DV;
2529 else this.t = 0;
2530 };
2531
2532 // (protected) set from string and radix
2533 BigInteger.prototype.fromString = function (s, b) {
2534 var k;
2535 if (b == 16) k = 4;
2536 else if (b == 8) k = 3;
2537 else if (b == 256) k = 8; // byte array
2538 else if (b == 2) k = 1;
2539 else if (b == 32) k = 5;
2540 else if (b == 4) k = 2;
2541 else { this.fromRadix(s, b); return; }
2542 this.t = 0;
2543 this.s = 0;
2544 var i = s.length, mi = false, sh = 0;
2545 while (--i >= 0) {
2546 var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
2547 if (x < 0) {
2548 if (s.charAt(i) == "-") mi = true;
2549 continue;
2550 }
2551 mi = false;
2552 if (sh == 0)
2553 this[this.t++] = x;
2554 else if (sh + k > this.DB) {
2555 this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
2556 this[this.t++] = (x >> (this.DB - sh));
2557 }
2558 else
2559 this[this.t - 1] |= x << sh;
2560 sh += k;
2561 if (sh >= this.DB) sh -= this.DB;
2562 }
2563 if (k == 8 && (s[0] & 0x80) != 0) {
2564 this.s = -1;
2565 if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
2566 }
2567 this.clamp();
2568 if (mi) BigInteger.ZERO.subTo(this, this);
2569 };
2570
2571
2572 // (protected) clamp off excess high words
2573 BigInteger.prototype.clamp = function () {
2574 var c = this.s & this.DM;
2575 while (this.t > 0 && this[this.t - 1] == c) --this.t;
2576 };
2577
2578 // (protected) r = this << n*DB
2579 BigInteger.prototype.dlShiftTo = function (n, r) {
2580 var i;
2581 for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
2582 for (i = n - 1; i >= 0; --i) r[i] = 0;
2583 r.t = this.t + n;
2584 r.s = this.s;
2585 };
2586
2587 // (protected) r = this >> n*DB
2588 BigInteger.prototype.drShiftTo = function (n, r) {
2589 for (var i = n; i < this.t; ++i) r[i - n] = this[i];
2590 r.t = Math.max(this.t - n, 0);
2591 r.s = this.s;
2592 };
2593
2594
2595 // (protected) r = this << n
2596 BigInteger.prototype.lShiftTo = function (n, r) {
2597 var bs = n % this.DB;
2598 var cbs = this.DB - bs;
2599 var bm = (1 << cbs) - 1;
2600 var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i;
2601 for (i = this.t - 1; i >= 0; --i) {
2602 r[i + ds + 1] = (this[i] >> cbs) | c;
2603 c = (this[i] & bm) << bs;
2604 }
2605 for (i = ds - 1; i >= 0; --i) r[i] = 0;
2606 r[ds] = c;
2607 r.t = this.t + ds + 1;
2608 r.s = this.s;
2609 r.clamp();
2610 };
2611
2612
2613 // (protected) r = this >> n
2614 BigInteger.prototype.rShiftTo = function (n, r) {
2615 r.s = this.s;
2616 var ds = Math.floor(n / this.DB);
2617 if (ds >= this.t) { r.t = 0; return; }
2618 var bs = n % this.DB;
2619 var cbs = this.DB - bs;
2620 var bm = (1 << bs) - 1;
2621 r[0] = this[ds] >> bs;
2622 for (var i = ds + 1; i < this.t; ++i) {
2623 r[i - ds - 1] |= (this[i] & bm) << cbs;
2624 r[i - ds] = this[i] >> bs;
2625 }
2626 if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
2627 r.t = this.t - ds;
2628 r.clamp();
2629 };
2630
2631
2632 // (protected) r = this - a
2633 BigInteger.prototype.subTo = function (a, r) {
2634 var i = 0, c = 0, m = Math.min(a.t, this.t);
2635 while (i < m) {
2636 c += this[i] - a[i];
2637 r[i++] = c & this.DM;
2638 c >>= this.DB;
2639 }
2640 if (a.t < this.t) {
2641 c -= a.s;
2642 while (i < this.t) {
2643 c += this[i];
2644 r[i++] = c & this.DM;
2645 c >>= this.DB;
2646 }
2647 c += this.s;
2648 }
2649 else {
2650 c += this.s;
2651 while (i < a.t) {
2652 c -= a[i];
2653 r[i++] = c & this.DM;
2654 c >>= this.DB;
2655 }
2656 c -= a.s;
2657 }
2658 r.s = (c < 0) ? -1 : 0;
2659 if (c < -1) r[i++] = this.DV + c;
2660 else if (c > 0) r[i++] = c;
2661 r.t = i;
2662 r.clamp();
2663 };
2664
2665
2666 // (protected) r = this * a, r != this,a (HAC 14.12)
2667 // "this" should be the larger one if appropriate.
2668 BigInteger.prototype.multiplyTo = function (a, r) {
2669 var x = this.abs(), y = a.abs();
2670 var i = x.t;
2671 r.t = i + y.t;
2672 while (--i >= 0) r[i] = 0;
2673 for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
2674 r.s = 0;
2675 r.clamp();
2676 if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
2677 };
2678
2679
2680 // (protected) r = this^2, r != this (HAC 14.16)
2681 BigInteger.prototype.squareTo = function (r) {
2682 var x = this.abs();
2683 var i = r.t = 2 * x.t;
2684 while (--i >= 0) r[i] = 0;
2685 for (i = 0; i < x.t - 1; ++i) {
2686 var c = x.am(i, x[i], r, 2 * i, 0, 1);
2687 if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
2688 r[i + x.t] -= x.DV;
2689 r[i + x.t + 1] = 1;
2690 }
2691 }
2692 if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
2693 r.s = 0;
2694 r.clamp();
2695 };
2696
2697
2698
2699 // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
2700 // r != q, this != m. q or r may be null.
2701 BigInteger.prototype.divRemTo = function (m, q, r) {
2702 var pm = m.abs();
2703 if (pm.t <= 0) return;
2704 var pt = this.abs();
2705 if (pt.t < pm.t) {
2706 if (q != null) q.fromInt(0);
2707 if (r != null) this.copyTo(r);
2708 return;
2709 }
2710 if (r == null) r = nbi();
2711 var y = nbi(), ts = this.s, ms = m.s;
2712 var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
2713 if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); }
2714 else { pm.copyTo(y); pt.copyTo(r); }
2715 var ys = y.t;
2716 var y0 = y[ys - 1];
2717 if (y0 == 0) return;
2718 var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
2719 var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2;
2720 var i = r.t, j = i - ys, t = (q == null) ? nbi() : q;
2721 y.dlShiftTo(j, t);
2722 if (r.compareTo(t) >= 0) {
2723 r[r.t++] = 1;
2724 r.subTo(t, r);
2725 }
2726 BigInteger.ONE.dlShiftTo(ys, t);
2727 t.subTo(y, y); // "negative" y so we can replace sub with am later
2728 while (y.t < ys) y[y.t++] = 0;
2729 while (--j >= 0) {
2730 // Estimate quotient digit
2731 var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
2732 if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
2733 y.dlShiftTo(j, t);
2734 r.subTo(t, r);
2735 while (r[i] < --qd) r.subTo(t, r);
2736 }
2737 }
2738 if (q != null) {
2739 r.drShiftTo(ys, q);
2740 if (ts != ms) BigInteger.ZERO.subTo(q, q);
2741 }
2742 r.t = ys;
2743 r.clamp();
2744 if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
2745 if (ts < 0) BigInteger.ZERO.subTo(r, r);
2746 };
2747
2748
2749 // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
2750 // justification:
2751 // xy == 1 (mod m)
2752 // xy = 1+km
2753 // xy(2-xy) = (1+km)(1-km)
2754 // x[y(2-xy)] = 1-k^2m^2
2755 // x[y(2-xy)] == 1 (mod m^2)
2756 // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
2757 // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
2758 // JS multiply "overflows" differently from C/C++, so care is needed here.
2759 BigInteger.prototype.invDigit = function () {
2760 if (this.t < 1) return 0;
2761 var x = this[0];
2762 if ((x & 1) == 0) return 0;
2763 var y = x & 3; // y == 1/x mod 2^2
2764 y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
2765 y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
2766 y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
2767 // last step - calculate inverse mod DV directly;
2768 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
2769 y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
2770 // we really want the negative inverse, and -DV < y < DV
2771 return (y > 0) ? this.DV - y : -y;
2772 };
2773
2774
2775 // (protected) true iff this is even
2776 BigInteger.prototype.isEven = function () { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; };
2777
2778
2779 // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
2780 BigInteger.prototype.exp = function (e, z) {
2781 if (e > 0xffffffff || e < 1) return BigInteger.ONE;
2782 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1;
2783 g.copyTo(r);
2784 while (--i >= 0) {
2785 z.sqrTo(r, r2);
2786 if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
2787 else { var t = r; r = r2; r2 = t; }
2788 }
2789 return z.revert(r);
2790 };
2791
2792
2793 // (public) return string representation in given radix
2794 BigInteger.prototype.toString = function (b) {
2795 if (this.s < 0) return "-" + this.negate().toString(b);
2796 var k;
2797 if (b == 16) k = 4;
2798 else if (b == 8) k = 3;
2799 else if (b == 2) k = 1;
2800 else if (b == 32) k = 5;
2801 else if (b == 4) k = 2;
2802 else return this.toRadix(b);
2803 var km = (1 << k) - 1, d, m = false, r = "", i = this.t;
2804 var p = this.DB - (i * this.DB) % k;
2805 if (i-- > 0) {
2806 if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); }
2807 while (i >= 0) {
2808 if (p < k) {
2809 d = (this[i] & ((1 << p) - 1)) << (k - p);
2810 d |= this[--i] >> (p += this.DB - k);
2811 }
2812 else {
2813 d = (this[i] >> (p -= k)) & km;
2814 if (p <= 0) { p += this.DB; --i; }
2815 }
2816 if (d > 0) m = true;
2817 if (m) r += int2char(d);
2818 }
2819 }
2820 return m ? r : "0";
2821 };
2822
2823
2824 // (public) -this
2825 BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; };
2826
2827 // (public) |this|
2828 BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this; };
2829
2830 // (public) return + if this > a, - if this < a, 0 if equal
2831 BigInteger.prototype.compareTo = function (a) {
2832 var r = this.s - a.s;
2833 if (r != 0) return r;
2834 var i = this.t;
2835 r = i - a.t;
2836 if (r != 0) return (this.s < 0) ? -r : r;
2837 while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
2838 return 0;
2839 }
2840
2841 // (public) return the number of bits in "this"
2842 BigInteger.prototype.bitLength = function () {
2843 if (this.t <= 0) return 0;
2844 return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
2845 };
2846
2847 // (public) this mod a
2848 BigInteger.prototype.mod = function (a) {
2849 var r = nbi();
2850 this.abs().divRemTo(a, null, r);
2851 if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
2852 return r;
2853 }
2854
2855 // (public) this^e % m, 0 <= e < 2^32
2856 BigInteger.prototype.modPowInt = function (e, m) {
2857 var z;
2858 if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
2859 return this.exp(e, z);
2860 };
2861
2862 // "constants"
2863 BigInteger.ZERO = nbv(0);
2864 BigInteger.ONE = nbv(1);
2865
2866
2867
2868
2869
2870
2871
2872 // Copyright (c) 2005-2009 Tom Wu
2873 // All Rights Reserved.
2874 // See "LICENSE" for details.
2875 // Extended JavaScript BN functions, required for RSA private ops.
2876 // Version 1.1: new BigInteger("0", 10) returns "proper" zero
2877 // Version 1.2: square() API, isProbablePrime fix
2878
2879
2880 // return index of lowest 1-bit in x, x < 2^31
2881 function lbit(x) {
2882 if (x == 0) return -1;
2883 var r = 0;
2884 if ((x & 0xffff) == 0) { x >>= 16; r += 16; }
2885 if ((x & 0xff) == 0) { x >>= 8; r += 8; }
2886 if ((x & 0xf) == 0) { x >>= 4; r += 4; }
2887 if ((x & 3) == 0) { x >>= 2; r += 2; }
2888 if ((x & 1) == 0) ++r;
2889 return r;
2890 }
2891
2892 // return number of 1 bits in x
2893 function cbit(x) {
2894 var r = 0;
2895 while (x != 0) { x &= x - 1; ++r; }
2896 return r;
2897 }
2898
2899 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];
2900 var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
2901
2902
2903
2904 // (protected) return x s.t. r^x < DV
2905 BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); };
2906
2907 // (protected) convert to radix string
2908 BigInteger.prototype.toRadix = function (b) {
2909 if (b == null) b = 10;
2910 if (this.signum() == 0 || b < 2 || b > 36) return "0";
2911 var cs = this.chunkSize(b);
2912 var a = Math.pow(b, cs);
2913 var d = nbv(a), y = nbi(), z = nbi(), r = "";
2914 this.divRemTo(d, y, z);
2915 while (y.signum() > 0) {
2916 r = (a + z.intValue()).toString(b).substr(1) + r;
2917 y.divRemTo(d, y, z);
2918 }
2919 return z.intValue().toString(b) + r;
2920 };
2921
2922 // (protected) convert from radix string
2923 BigInteger.prototype.fromRadix = function (s, b) {
2924 this.fromInt(0);
2925 if (b == null) b = 10;
2926 var cs = this.chunkSize(b);
2927 var d = Math.pow(b, cs), mi = false, j = 0, w = 0;
2928 for (var i = 0; i < s.length; ++i) {
2929 var x = intAt(s, i);
2930 if (x < 0) {
2931 if (s.charAt(i) == "-" && this.signum() == 0) mi = true;
2932 continue;
2933 }
2934 w = b * w + x;
2935 if (++j >= cs) {
2936 this.dMultiply(d);
2937 this.dAddOffset(w, 0);
2938 j = 0;
2939 w = 0;
2940 }
2941 }
2942 if (j > 0) {
2943 this.dMultiply(Math.pow(b, j));
2944 this.dAddOffset(w, 0);
2945 }
2946 if (mi) BigInteger.ZERO.subTo(this, this);
2947 };
2948
2949 // (protected) alternate constructor
2950 BigInteger.prototype.fromNumber = function (a, b, c) {
2951 if ("number" == typeof b) {
2952 // new BigInteger(int,int,RNG)
2953 if (a < 2) this.fromInt(1);
2954 else {
2955 this.fromNumber(a, c);
2956 if (!this.testBit(a - 1)) // force MSB set
2957 this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
2958 if (this.isEven()) this.dAddOffset(1, 0); // force odd
2959 while (!this.isProbablePrime(b)) {
2960 this.dAddOffset(2, 0);
2961 if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
2962 }
2963 }
2964 }
2965 else {
2966 // new BigInteger(int,RNG)
2967 var x = new Array(), t = a & 7;
2968 x.length = (a >> 3) + 1;
2969 b.nextBytes(x);
2970 if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0;
2971 this.fromString(x, 256);
2972 }
2973 };
2974
2975 // (protected) r = this op a (bitwise)
2976 BigInteger.prototype.bitwiseTo = function (a, op, r) {
2977 var i, f, m = Math.min(a.t, this.t);
2978 for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
2979 if (a.t < this.t) {
2980 f = a.s & this.DM;
2981 for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
2982 r.t = this.t;
2983 }
2984 else {
2985 f = this.s & this.DM;
2986 for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
2987 r.t = a.t;
2988 }
2989 r.s = op(this.s, a.s);
2990 r.clamp();
2991 };
2992
2993 // (protected) this op (1<<n)
2994 BigInteger.prototype.changeBit = function (n, op) {
2995 var r = BigInteger.ONE.shiftLeft(n);
2996 this.bitwiseTo(r, op, r);
2997 return r;
2998 };
2999
3000 // (protected) r = this + a
3001 BigInteger.prototype.addTo = function (a, r) {
3002 var i = 0, c = 0, m = Math.min(a.t, this.t);
3003 while (i < m) {
3004 c += this[i] + a[i];
3005 r[i++] = c & this.DM;
3006 c >>= this.DB;
3007 }
3008 if (a.t < this.t) {
3009 c += a.s;
3010 while (i < this.t) {
3011 c += this[i];
3012 r[i++] = c & this.DM;
3013 c >>= this.DB;
3014 }
3015 c += this.s;
3016 }
3017 else {
3018 c += this.s;
3019 while (i < a.t) {
3020 c += a[i];
3021 r[i++] = c & this.DM;
3022 c >>= this.DB;
3023 }
3024 c += a.s;
3025 }
3026 r.s = (c < 0) ? -1 : 0;
3027 if (c > 0) r[i++] = c;
3028 else if (c < -1) r[i++] = this.DV + c;
3029 r.t = i;
3030 r.clamp();
3031 };
3032
3033 // (protected) this *= n, this >= 0, 1 < n < DV
3034 BigInteger.prototype.dMultiply = function (n) {
3035 this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
3036 ++this.t;
3037 this.clamp();
3038 };
3039
3040 // (protected) this += n << w words, this >= 0
3041 BigInteger.prototype.dAddOffset = function (n, w) {
3042 if (n == 0) return;
3043 while (this.t <= w) this[this.t++] = 0;
3044 this[w] += n;
3045 while (this[w] >= this.DV) {
3046 this[w] -= this.DV;
3047 if (++w >= this.t) this[this.t++] = 0;
3048 ++this[w];
3049 }
3050 };
3051
3052 // (protected) r = lower n words of "this * a", a.t <= n
3053 // "this" should be the larger one if appropriate.
3054 BigInteger.prototype.multiplyLowerTo = function (a, n, r) {
3055 var i = Math.min(this.t + a.t, n);
3056 r.s = 0; // assumes a,this >= 0
3057 r.t = i;
3058 while (i > 0) r[--i] = 0;
3059 var j;
3060 for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
3061 for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
3062 r.clamp();
3063 };
3064
3065
3066 // (protected) r = "this * a" without lower n words, n > 0
3067 // "this" should be the larger one if appropriate.
3068 BigInteger.prototype.multiplyUpperTo = function (a, n, r) {
3069 --n;
3070 var i = r.t = this.t + a.t - n;
3071 r.s = 0; // assumes a,this >= 0
3072 while (--i >= 0) r[i] = 0;
3073 for (i = Math.max(n - this.t, 0); i < a.t; ++i)
3074 r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
3075 r.clamp();
3076 r.drShiftTo(1, r);
3077 };
3078
3079 // (protected) this % n, n < 2^26
3080 BigInteger.prototype.modInt = function (n) {
3081 if (n <= 0) return 0;
3082 var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0;
3083 if (this.t > 0)
3084 if (d == 0) r = this[0] % n;
3085 else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
3086 return r;
3087 };
3088
3089
3090 // (protected) true if probably prime (HAC 4.24, Miller-Rabin)
3091 BigInteger.prototype.millerRabin = function (t) {
3092 var n1 = this.subtract(BigInteger.ONE);
3093 var k = n1.getLowestSetBit();
3094 if (k <= 0) return false;
3095 var r = n1.shiftRight(k);
3096 t = (t + 1) >> 1;
3097 if (t > lowprimes.length) t = lowprimes.length;
3098 var a = nbi();
3099 for (var i = 0; i < t; ++i) {
3100 //Pick bases at random, instead of starting at 2
3101 a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]);
3102 var y = a.modPow(r, this);
3103 if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
3104 var j = 1;
3105 while (j++ < k && y.compareTo(n1) != 0) {
3106 y = y.modPowInt(2, this);
3107 if (y.compareTo(BigInteger.ONE) == 0) return false;
3108 }
3109 if (y.compareTo(n1) != 0) return false;
3110 }
3111 }
3112 return true;
3113 };
3114
3115
3116
3117 // (public)
3118 BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r; };
3119
3120 // (public) return value as integer
3121 BigInteger.prototype.intValue = function () {
3122 if (this.s < 0) {
3123 if (this.t == 1) return this[0] - this.DV;
3124 else if (this.t == 0) return -1;
3125 }
3126 else if (this.t == 1) return this[0];
3127 else if (this.t == 0) return 0;
3128 // assumes 16 < DB < 32
3129 return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
3130 };
3131
3132
3133 // (public) return value as byte
3134 BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; };
3135
3136 // (public) return value as short (assumes DB>=16)
3137 BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; };
3138
3139 // (public) 0 if this == 0, 1 if this > 0
3140 BigInteger.prototype.signum = function () {
3141 if (this.s < 0) return -1;
3142 else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
3143 else return 1;
3144 };
3145
3146
3147 // (public) convert to bigendian byte array
3148 BigInteger.prototype.toByteArray = function () {
3149 var i = this.t, r = new Array();
3150 r[0] = this.s;
3151 var p = this.DB - (i * this.DB) % 8, d, k = 0;
3152 if (i-- > 0) {
3153 if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p)
3154 r[k++] = d | (this.s << (this.DB - p));
3155 while (i >= 0) {
3156 if (p < 8) {
3157 d = (this[i] & ((1 << p) - 1)) << (8 - p);
3158 d |= this[--i] >> (p += this.DB - 8);
3159 }
3160 else {
3161 d = (this[i] >> (p -= 8)) & 0xff;
3162 if (p <= 0) { p += this.DB; --i; }
3163 }
3164 if ((d & 0x80) != 0) d |= -256;
3165 if (k == 0 && (this.s & 0x80) != (d & 0x80)) ++k;
3166 if (k > 0 || d != this.s) r[k++] = d;
3167 }
3168 }
3169 return r;
3170 };
3171
3172 BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0); };
3173 BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a; };
3174 BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a; };
3175
3176 // (public) this & a
3177 function op_and(x, y) { return x & y; }
3178 BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; };
3179
3180 // (public) this | a
3181 function op_or(x, y) { return x | y; }
3182 BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; };
3183
3184 // (public) this ^ a
3185 function op_xor(x, y) { return x ^ y; }
3186 BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; };
3187
3188 // (public) this & ~a
3189 function op_andnot(x, y) { return x & ~y; }
3190 BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; };
3191
3192 // (public) ~this
3193 BigInteger.prototype.not = function () {
3194 var r = nbi();
3195 for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
3196 r.t = this.t;
3197 r.s = ~this.s;
3198 return r;
3199 };
3200
3201 // (public) this << n
3202 BigInteger.prototype.shiftLeft = function (n) {
3203 var r = nbi();
3204 if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r);
3205 return r;
3206 };
3207
3208 // (public) this >> n
3209 BigInteger.prototype.shiftRight = function (n) {
3210 var r = nbi();
3211 if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r);
3212 return r;
3213 };
3214
3215 // (public) returns index of lowest 1-bit (or -1 if none)
3216 BigInteger.prototype.getLowestSetBit = function () {
3217 for (var i = 0; i < this.t; ++i)
3218 if (this[i] != 0) return i * this.DB + lbit(this[i]);
3219 if (this.s < 0) return this.t * this.DB;
3220 return -1;
3221 };
3222
3223 // (public) return number of set bits
3224 BigInteger.prototype.bitCount = function () {
3225 var r = 0, x = this.s & this.DM;
3226 for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
3227 return r;
3228 };
3229
3230 // (public) true iff nth bit is set
3231 BigInteger.prototype.testBit = function (n) {
3232 var j = Math.floor(n / this.DB);
3233 if (j >= this.t) return (this.s != 0);
3234 return ((this[j] & (1 << (n % this.DB))) != 0);
3235 };
3236
3237 // (public) this | (1<<n)
3238 BigInteger.prototype.setBit = function (n) { return this.changeBit(n, op_or); };
3239 // (public) this & ~(1<<n)
3240 BigInteger.prototype.clearBit = function (n) { return this.changeBit(n, op_andnot); };
3241 // (public) this ^ (1<<n)
3242 BigInteger.prototype.flipBit = function (n) { return this.changeBit(n, op_xor); };
3243 // (public) this + a
3244 BigInteger.prototype.add = function (a) { var r = nbi(); this.addTo(a, r); return r; };
3245 // (public) this - a
3246 BigInteger.prototype.subtract = function (a) { var r = nbi(); this.subTo(a, r); return r; };
3247 // (public) this * a
3248 BigInteger.prototype.multiply = function (a) { var r = nbi(); this.multiplyTo(a, r); return r; };
3249 // (public) this / a
3250 BigInteger.prototype.divide = function (a) { var r = nbi(); this.divRemTo(a, r, null); return r; };
3251 // (public) this % a
3252 BigInteger.prototype.remainder = function (a) { var r = nbi(); this.divRemTo(a, null, r); return r; };
3253 // (public) [this/a,this%a]
3254 BigInteger.prototype.divideAndRemainder = function (a) {
3255 var q = nbi(), r = nbi();
3256 this.divRemTo(a, q, r);
3257 return new Array(q, r);
3258 };
3259
3260 // (public) this^e % m (HAC 14.85)
3261 BigInteger.prototype.modPow = function (e, m) {
3262 var i = e.bitLength(), k, r = nbv(1), z;
3263 if (i <= 0) return r;
3264 else if (i < 18) k = 1;
3265 else if (i < 48) k = 3;
3266 else if (i < 144) k = 4;
3267 else if (i < 768) k = 5;
3268 else k = 6;
3269 if (i < 8)
3270 z = new Classic(m);
3271 else if (m.isEven())
3272 z = new Barrett(m);
3273 else
3274 z = new Montgomery(m);
3275
3276 // precomputation
3277 var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1;
3278 g[1] = z.convert(this);
3279 if (k > 1) {
3280 var g2 = nbi();
3281 z.sqrTo(g[1], g2);
3282 while (n <= km) {
3283 g[n] = nbi();
3284 z.mulTo(g2, g[n - 2], g[n]);
3285 n += 2;
3286 }
3287 }
3288
3289 var j = e.t - 1, w, is1 = true, r2 = nbi(), t;
3290 i = nbits(e[j]) - 1;
3291 while (j >= 0) {
3292 if (i >= k1) w = (e[j] >> (i - k1)) & km;
3293 else {
3294 w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
3295 if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
3296 }
3297
3298 n = k;
3299 while ((w & 1) == 0) { w >>= 1; --n; }
3300 if ((i -= n) < 0) { i += this.DB; --j; }
3301 if (is1) { // ret == 1, don't bother squaring or multiplying it
3302 g[w].copyTo(r);
3303 is1 = false;
3304 }
3305 else {
3306 while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2; }
3307 if (n > 0) z.sqrTo(r, r2); else { t = r; r = r2; r2 = t; }
3308 z.mulTo(r2, g[w], r);
3309 }
3310
3311 while (j >= 0 && (e[j] & (1 << i)) == 0) {
3312 z.sqrTo(r, r2); t = r; r = r2; r2 = t;
3313 if (--i < 0) { i = this.DB - 1; --j; }
3314 }
3315 }
3316 return z.revert(r);
3317 };
3318
3319 // (public) 1/this % m (HAC 14.61)
3320 BigInteger.prototype.modInverse = function (m) {
3321 var ac = m.isEven();
3322 if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
3323 var u = m.clone(), v = this.clone();
3324 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
3325 while (u.signum() != 0) {
3326 while (u.isEven()) {
3327 u.rShiftTo(1, u);
3328 if (ac) {
3329 if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b); }
3330 a.rShiftTo(1, a);
3331 }
3332 else if (!b.isEven()) b.subTo(m, b);
3333 b.rShiftTo(1, b);
3334 }
3335 while (v.isEven()) {
3336 v.rShiftTo(1, v);
3337 if (ac) {
3338 if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d); }
3339 c.rShiftTo(1, c);
3340 }
3341 else if (!d.isEven()) d.subTo(m, d);
3342 d.rShiftTo(1, d);
3343 }
3344 if (u.compareTo(v) >= 0) {
3345 u.subTo(v, u);
3346 if (ac) a.subTo(c, a);
3347 b.subTo(d, b);
3348 }
3349 else {
3350 v.subTo(u, v);
3351 if (ac) c.subTo(a, c);
3352 d.subTo(b, d);
3353 }
3354 }
3355 if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
3356 if (d.compareTo(m) >= 0) return d.subtract(m);
3357 if (d.signum() < 0) d.addTo(m, d); else return d;
3358 if (d.signum() < 0) return d.add(m); else return d;
3359 };
3360
3361
3362 // (public) this^e
3363 BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()); };
3364
3365 // (public) gcd(this,a) (HAC 14.54)
3366 BigInteger.prototype.gcd = function (a) {
3367 var x = (this.s < 0) ? this.negate() : this.clone();
3368 var y = (a.s < 0) ? a.negate() : a.clone();
3369 if (x.compareTo(y) < 0) { var t = x; x = y; y = t; }
3370 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
3371 if (g < 0) return x;
3372 if (i < g) g = i;
3373 if (g > 0) {
3374 x.rShiftTo(g, x);
3375 y.rShiftTo(g, y);
3376 }
3377 while (x.signum() > 0) {
3378 if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
3379 if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
3380 if (x.compareTo(y) >= 0) {
3381 x.subTo(y, x);
3382 x.rShiftTo(1, x);
3383 }
3384 else {
3385 y.subTo(x, y);
3386 y.rShiftTo(1, y);
3387 }
3388 }
3389 if (g > 0) y.lShiftTo(g, y);
3390 return y;
3391 };
3392
3393 // (public) test primality with certainty >= 1-.5^t
3394 BigInteger.prototype.isProbablePrime = function (t) {
3395 var i, x = this.abs();
3396 if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
3397 for (i = 0; i < lowprimes.length; ++i)
3398 if (x[0] == lowprimes[i]) return true;
3399 return false;
3400 }
3401 if (x.isEven()) return false;
3402 i = 1;
3403 while (i < lowprimes.length) {
3404 var m = lowprimes[i], j = i + 1;
3405 while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
3406 m = x.modInt(m);
3407 while (i < j) if (m % lowprimes[i++] == 0) return false;
3408 }
3409 return x.millerRabin(t);
3410 };
3411
3412
3413 // JSBN-specific extension
3414
3415 // (public) this^2
3416 BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r; };
3417
3418
3419 // NOTE: BigInteger interfaces not implemented in jsbn:
3420 // BigInteger(int signum, byte[] magnitude)
3421 // double doubleValue()
3422 // float floatValue()
3423 // int hashCode()
3424 // long longValue()
3425 // static BigInteger valueOf(long val)
3426
3427
3428
3429 // Copyright Stephan Thomas (start) --- //
3430 // https://raw.github.com/bitcoinjs/bitcoinjs-lib/07f9d55ccb6abd962efb6befdd37671f85ea4ff9/src/util.js
3431 // BigInteger monkey patching
3432 BigInteger.valueOf = nbv;
3433
3434 /**
3435 * Returns a byte array representation of the big integer.
3436 *
3437 * This returns the absolute of the contained value in big endian
3438 * form. A value of zero results in an empty array.
3439 */
3440 BigInteger.prototype.toByteArrayUnsigned = function () {
3441 var ba = this.abs().toByteArray();
3442 if (ba.length) {
3443 if (ba[0] == 0) {
3444 ba = ba.slice(1);
3445 }
3446 return ba.map(function (v) {
3447 return (v < 0) ? v + 256 : v;
3448 });
3449 } else {
3450 // Empty array, nothing to do
3451 return ba;
3452 }
3453 };
3454
3455 /**
3456 * Turns a byte array into a big integer.
3457 *
3458 * This function will interpret a byte array as a big integer in big
3459 * endian notation and ignore leading zeros.
3460 */
3461 BigInteger.fromByteArrayUnsigned = function (ba) {
3462 if (!ba.length) {
3463 return ba.valueOf(0);
3464 } else if (ba[0] & 0x80) {
3465 // Prepend a zero so the BigInteger class doesn't mistake this
3466 // for a negative integer.
3467 return new BigInteger([0].concat(ba));
3468 } else {
3469 return new BigInteger(ba);
3470 }
3471 };
3472
3473 /**
3474 * Converts big integer to signed byte representation.
3475 *
3476 * The format for this value uses a the most significant bit as a sign
3477 * bit. If the most significant bit is already occupied by the
3478 * absolute value, an extra byte is prepended and the sign bit is set
3479 * there.
3480 *
3481 * Examples:
3482 *
3483 * 0 => 0x00
3484 * 1 => 0x01
3485 * -1 => 0x81
3486 * 127 => 0x7f
3487 * -127 => 0xff
3488 * 128 => 0x0080
3489 * -128 => 0x8080
3490 * 255 => 0x00ff
3491 * -255 => 0x80ff
3492 * 16300 => 0x3fac
3493 * -16300 => 0xbfac
3494 * 62300 => 0x00f35c
3495 * -62300 => 0x80f35c
3496 */
3497 BigInteger.prototype.toByteArraySigned = function () {
3498 var val = this.abs().toByteArrayUnsigned();
3499 var neg = this.compareTo(BigInteger.ZERO) < 0;
3500
3501 if (neg) {
3502 if (val[0] & 0x80) {
3503 val.unshift(0x80);
3504 } else {
3505 val[0] |= 0x80;
3506 }
3507 } else {
3508 if (val[0] & 0x80) {
3509 val.unshift(0x00);
3510 }
3511 }
3512
3513 return val;
3514 };
3515
3516 /**
3517 * Parse a signed big integer byte representation.
3518 *
3519 * For details on the format please see BigInteger.toByteArraySigned.
3520 */
3521 BigInteger.fromByteArraySigned = function (ba) {
3522 // Check for negative value
3523 if (ba[0] & 0x80) {
3524 // Remove sign bit
3525 ba[0] &= 0x7f;
3526
3527 return BigInteger.fromByteArrayUnsigned(ba).negate();
3528 } else {
3529 return BigInteger.fromByteArrayUnsigned(ba);
3530 }
3531 };
3532 // Copyright Stephan Thomas (end) --- //
3533
3534
3535
3536
3537 // ****** REDUCTION ******* //
3538
3539 // Modular reduction using "classic" algorithm
3540 var Classic = window.Classic = function Classic(m) { this.m = m; }
3541 Classic.prototype.convert = function (x) {
3542 if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
3543 else return x;
3544 };
3545 Classic.prototype.revert = function (x) { return x; };
3546 Classic.prototype.reduce = function (x) { x.divRemTo(this.m, null, x); };
3547 Classic.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
3548 Classic.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
3549
3550
3551
3552
3553
3554 // Montgomery reduction
3555 var Montgomery = window.Montgomery = function Montgomery(m) {
3556 this.m = m;
3557 this.mp = m.invDigit();
3558 this.mpl = this.mp & 0x7fff;
3559 this.mph = this.mp >> 15;
3560 this.um = (1 << (m.DB - 15)) - 1;
3561 this.mt2 = 2 * m.t;
3562 }
3563 // xR mod m
3564 Montgomery.prototype.convert = function (x) {
3565 var r = nbi();
3566 x.abs().dlShiftTo(this.m.t, r);
3567 r.divRemTo(this.m, null, r);
3568 if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
3569 return r;
3570 }
3571 // x/R mod m
3572 Montgomery.prototype.revert = function (x) {
3573 var r = nbi();
3574 x.copyTo(r);
3575 this.reduce(r);
3576 return r;
3577 };
3578 // x = x/R mod m (HAC 14.32)
3579 Montgomery.prototype.reduce = function (x) {
3580 while (x.t <= this.mt2) // pad x so am has enough room later
3581 x[x.t++] = 0;
3582 for (var i = 0; i < this.m.t; ++i) {
3583 // faster way of calculating u0 = x[i]*mp mod DV
3584 var j = x[i] & 0x7fff;
3585 var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
3586 // use am to combine the multiply-shift-add into one call
3587 j = i + this.m.t;
3588 x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
3589 // propagate carry
3590 while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
3591 }
3592 x.clamp();
3593 x.drShiftTo(this.m.t, x);
3594 if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
3595 };
3596 // r = "xy/R mod m"; x,y != r
3597 Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
3598 // r = "x^2/R mod m"; x != r
3599 Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
3600
3601
3602
3603
3604
3605 // A "null" reducer
3606 var NullExp = window.NullExp = function NullExp() { }
3607 NullExp.prototype.convert = function (x) { return x; };
3608 NullExp.prototype.revert = function (x) { return x; };
3609 NullExp.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); };
3610 NullExp.prototype.sqrTo = function (x, r) { x.squareTo(r); };
3611
3612
3613
3614
3615
3616 // Barrett modular reduction
3617 var Barrett = window.Barrett = function Barrett(m) {
3618 // setup Barrett
3619 this.r2 = nbi();
3620 this.q3 = nbi();
3621 BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
3622 this.mu = this.r2.divide(m);
3623 this.m = m;
3624 }
3625 Barrett.prototype.convert = function (x) {
3626 if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
3627 else if (x.compareTo(this.m) < 0) return x;
3628 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
3629 };
3630 Barrett.prototype.revert = function (x) { return x; };
3631 // x = x mod m (HAC 14.42)
3632 Barrett.prototype.reduce = function (x) {
3633 x.drShiftTo(this.m.t - 1, this.r2);
3634 if (x.t > this.m.t + 1) { x.t = this.m.t + 1; x.clamp(); }
3635 this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
3636 this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
3637 while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
3638 x.subTo(this.r2, x);
3639 while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
3640 };
3641 // r = x*y mod m; x,y != r
3642 Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
3643 // r = x^2 mod m; x != r
3644 Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
3645
3646})();
3647 </script>
3648 <script type="text/javascript">
3649//---------------------------------------------------------------------
3650// QRCode for JavaScript
3651//
3652// Copyright (c) 2009 Kazuhiko Arase
3653//
3654// URL: http://www.d-project.com/
3655//
3656// Licensed under the MIT license:
3657// http://www.opensource.org/licenses/mit-license.php
3658//
3659// The word "QR Code" is registered trademark of
3660// DENSO WAVE INCORPORATED
3661// http://www.denso-wave.com/qrcode/faqpatent-e.html
3662//
3663//---------------------------------------------------------------------
3664
3665(function () {
3666 //---------------------------------------------------------------------
3667 // QRCode
3668 //---------------------------------------------------------------------
3669
3670 var QRCode = window.QRCode = function (typeNumber, errorCorrectLevel) {
3671 this.typeNumber = typeNumber;
3672 this.errorCorrectLevel = errorCorrectLevel;
3673 this.modules = null;
3674 this.moduleCount = 0;
3675 this.dataCache = null;
3676 this.dataList = new Array();
3677 }
3678
3679 QRCode.prototype = {
3680
3681 addData: function (data) {
3682 var newData = new QRCode.QR8bitByte(data);
3683 this.dataList.push(newData);
3684 this.dataCache = null;
3685 },
3686
3687 isDark: function (row, col) {
3688 if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
3689 throw new Error(row + "," + col);
3690 }
3691 return this.modules[row][col];
3692 },
3693
3694 getModuleCount: function () {
3695 return this.moduleCount;
3696 },
3697
3698 make: function () {
3699 this.makeImpl(false, this.getBestMaskPattern());
3700 },
3701
3702 makeImpl: function (test, maskPattern) {
3703
3704 this.moduleCount = this.typeNumber * 4 + 17;
3705 this.modules = new Array(this.moduleCount);
3706
3707 for (var row = 0; row < this.moduleCount; row++) {
3708
3709 this.modules[row] = new Array(this.moduleCount);
3710
3711 for (var col = 0; col < this.moduleCount; col++) {
3712 this.modules[row][col] = null; //(col + row) % 3;
3713 }
3714 }
3715
3716 this.setupPositionProbePattern(0, 0);
3717 this.setupPositionProbePattern(this.moduleCount - 7, 0);
3718 this.setupPositionProbePattern(0, this.moduleCount - 7);
3719 this.setupPositionAdjustPattern();
3720 this.setupTimingPattern();
3721 this.setupTypeInfo(test, maskPattern);
3722
3723 if (this.typeNumber >= 7) {
3724 this.setupTypeNumber(test);
3725 }
3726
3727 if (this.dataCache == null) {
3728 this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
3729 }
3730
3731 this.mapData(this.dataCache, maskPattern);
3732 },
3733
3734 setupPositionProbePattern: function (row, col) {
3735
3736 for (var r = -1; r <= 7; r++) {
3737
3738 if (row + r <= -1 || this.moduleCount <= row + r) continue;
3739
3740 for (var c = -1; c <= 7; c++) {
3741
3742 if (col + c <= -1 || this.moduleCount <= col + c) continue;
3743
3744 if ((0 <= r && r <= 6 && (c == 0 || c == 6))
3745 || (0 <= c && c <= 6 && (r == 0 || r == 6))
3746 || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
3747 this.modules[row + r][col + c] = true;
3748 } else {
3749 this.modules[row + r][col + c] = false;
3750 }
3751 }
3752 }
3753 },
3754
3755 getBestMaskPattern: function () {
3756
3757 var minLostPoint = 0;
3758 var pattern = 0;
3759
3760 for (var i = 0; i < 8; i++) {
3761
3762 this.makeImpl(true, i);
3763
3764 var lostPoint = QRCode.Util.getLostPoint(this);
3765
3766 if (i == 0 || minLostPoint > lostPoint) {
3767 minLostPoint = lostPoint;
3768 pattern = i;
3769 }
3770 }
3771
3772 return pattern;
3773 },
3774
3775 createMovieClip: function (target_mc, instance_name, depth) {
3776
3777 var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
3778 var cs = 1;
3779
3780 this.make();
3781
3782 for (var row = 0; row < this.modules.length; row++) {
3783
3784 var y = row * cs;
3785
3786 for (var col = 0; col < this.modules[row].length; col++) {
3787
3788 var x = col * cs;
3789 var dark = this.modules[row][col];
3790
3791 if (dark) {
3792 qr_mc.beginFill(0, 100);
3793 qr_mc.moveTo(x, y);
3794 qr_mc.lineTo(x + cs, y);
3795 qr_mc.lineTo(x + cs, y + cs);
3796 qr_mc.lineTo(x, y + cs);
3797 qr_mc.endFill();
3798 }
3799 }
3800 }
3801
3802 return qr_mc;
3803 },
3804
3805 setupTimingPattern: function () {
3806
3807 for (var r = 8; r < this.moduleCount - 8; r++) {
3808 if (this.modules[r][6] != null) {
3809 continue;
3810 }
3811 this.modules[r][6] = (r % 2 == 0);
3812 }
3813
3814 for (var c = 8; c < this.moduleCount - 8; c++) {
3815 if (this.modules[6][c] != null) {
3816 continue;
3817 }
3818 this.modules[6][c] = (c % 2 == 0);
3819 }
3820 },
3821
3822 setupPositionAdjustPattern: function () {
3823
3824 var pos = QRCode.Util.getPatternPosition(this.typeNumber);
3825
3826 for (var i = 0; i < pos.length; i++) {
3827
3828 for (var j = 0; j < pos.length; j++) {
3829
3830 var row = pos[i];
3831 var col = pos[j];
3832
3833 if (this.modules[row][col] != null) {
3834 continue;
3835 }
3836
3837 for (var r = -2; r <= 2; r++) {
3838
3839 for (var c = -2; c <= 2; c++) {
3840
3841 if (r == -2 || r == 2 || c == -2 || c == 2
3842 || (r == 0 && c == 0)) {
3843 this.modules[row + r][col + c] = true;
3844 } else {
3845 this.modules[row + r][col + c] = false;
3846 }
3847 }
3848 }
3849 }
3850 }
3851 },
3852
3853 setupTypeNumber: function (test) {
3854
3855 var bits = QRCode.Util.getBCHTypeNumber(this.typeNumber);
3856
3857 for (var i = 0; i < 18; i++) {
3858 var mod = (!test && ((bits >> i) & 1) == 1);
3859 this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
3860 }
3861
3862 for (var i = 0; i < 18; i++) {
3863 var mod = (!test && ((bits >> i) & 1) == 1);
3864 this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
3865 }
3866 },
3867
3868 setupTypeInfo: function (test, maskPattern) {
3869
3870 var data = (this.errorCorrectLevel << 3) | maskPattern;
3871 var bits = QRCode.Util.getBCHTypeInfo(data);
3872
3873 // vertical
3874 for (var i = 0; i < 15; i++) {
3875
3876 var mod = (!test && ((bits >> i) & 1) == 1);
3877
3878 if (i < 6) {
3879 this.modules[i][8] = mod;
3880 } else if (i < 8) {
3881 this.modules[i + 1][8] = mod;
3882 } else {
3883 this.modules[this.moduleCount - 15 + i][8] = mod;
3884 }
3885 }
3886
3887 // horizontal
3888 for (var i = 0; i < 15; i++) {
3889
3890 var mod = (!test && ((bits >> i) & 1) == 1);
3891
3892 if (i < 8) {
3893 this.modules[8][this.moduleCount - i - 1] = mod;
3894 } else if (i < 9) {
3895 this.modules[8][15 - i - 1 + 1] = mod;
3896 } else {
3897 this.modules[8][15 - i - 1] = mod;
3898 }
3899 }
3900
3901 // fixed module
3902 this.modules[this.moduleCount - 8][8] = (!test);
3903
3904 },
3905
3906 mapData: function (data, maskPattern) {
3907
3908 var inc = -1;
3909 var row = this.moduleCount - 1;
3910 var bitIndex = 7;
3911 var byteIndex = 0;
3912
3913 for (var col = this.moduleCount - 1; col > 0; col -= 2) {
3914
3915 if (col == 6) col--;
3916
3917 while (true) {
3918
3919 for (var c = 0; c < 2; c++) {
3920
3921 if (this.modules[row][col - c] == null) {
3922
3923 var dark = false;
3924
3925 if (byteIndex < data.length) {
3926 dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
3927 }
3928
3929 var mask = QRCode.Util.getMask(maskPattern, row, col - c);
3930
3931 if (mask) {
3932 dark = !dark;
3933 }
3934
3935 this.modules[row][col - c] = dark;
3936 bitIndex--;
3937
3938 if (bitIndex == -1) {
3939 byteIndex++;
3940 bitIndex = 7;
3941 }
3942 }
3943 }
3944
3945 row += inc;
3946
3947 if (row < 0 || this.moduleCount <= row) {
3948 row -= inc;
3949 inc = -inc;
3950 break;
3951 }
3952 }
3953 }
3954
3955 }
3956
3957 };
3958
3959 QRCode.PAD0 = 0xEC;
3960 QRCode.PAD1 = 0x11;
3961
3962 QRCode.createData = function (typeNumber, errorCorrectLevel, dataList) {
3963
3964 var rsBlocks = QRCode.RSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
3965
3966 var buffer = new QRCode.BitBuffer();
3967
3968 for (var i = 0; i < dataList.length; i++) {
3969 var data = dataList[i];
3970 buffer.put(data.mode, 4);
3971 buffer.put(data.getLength(), QRCode.Util.getLengthInBits(data.mode, typeNumber));
3972 data.write(buffer);
3973 }
3974
3975 // calc num max data.
3976 var totalDataCount = 0;
3977 for (var i = 0; i < rsBlocks.length; i++) {
3978 totalDataCount += rsBlocks[i].dataCount;
3979 }
3980
3981 if (buffer.getLengthInBits() > totalDataCount * 8) {
3982 throw new Error("code length overflow. ("
3983 + buffer.getLengthInBits()
3984 + ">"
3985 + totalDataCount * 8
3986 + ")");
3987 }
3988
3989 // end code
3990 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
3991 buffer.put(0, 4);
3992 }
3993
3994 // padding
3995 while (buffer.getLengthInBits() % 8 != 0) {
3996 buffer.putBit(false);
3997 }
3998
3999 // padding
4000 while (true) {
4001
4002 if (buffer.getLengthInBits() >= totalDataCount * 8) {
4003 break;
4004 }
4005 buffer.put(QRCode.PAD0, 8);
4006
4007 if (buffer.getLengthInBits() >= totalDataCount * 8) {
4008 break;
4009 }
4010 buffer.put(QRCode.PAD1, 8);
4011 }
4012
4013 return QRCode.createBytes(buffer, rsBlocks);
4014 };
4015
4016 QRCode.createBytes = function (buffer, rsBlocks) {
4017
4018 var offset = 0;
4019
4020 var maxDcCount = 0;
4021 var maxEcCount = 0;
4022
4023 var dcdata = new Array(rsBlocks.length);
4024 var ecdata = new Array(rsBlocks.length);
4025
4026 for (var r = 0; r < rsBlocks.length; r++) {
4027
4028 var dcCount = rsBlocks[r].dataCount;
4029 var ecCount = rsBlocks[r].totalCount - dcCount;
4030
4031 maxDcCount = Math.max(maxDcCount, dcCount);
4032 maxEcCount = Math.max(maxEcCount, ecCount);
4033
4034 dcdata[r] = new Array(dcCount);
4035
4036 for (var i = 0; i < dcdata[r].length; i++) {
4037 dcdata[r][i] = 0xff & buffer.buffer[i + offset];
4038 }
4039 offset += dcCount;
4040
4041 var rsPoly = QRCode.Util.getErrorCorrectPolynomial(ecCount);
4042 var rawPoly = new QRCode.Polynomial(dcdata[r], rsPoly.getLength() - 1);
4043
4044 var modPoly = rawPoly.mod(rsPoly);
4045 ecdata[r] = new Array(rsPoly.getLength() - 1);
4046 for (var i = 0; i < ecdata[r].length; i++) {
4047 var modIndex = i + modPoly.getLength() - ecdata[r].length;
4048 ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
4049 }
4050
4051 }
4052
4053 var totalCodeCount = 0;
4054 for (var i = 0; i < rsBlocks.length; i++) {
4055 totalCodeCount += rsBlocks[i].totalCount;
4056 }
4057
4058 var data = new Array(totalCodeCount);
4059 var index = 0;
4060
4061 for (var i = 0; i < maxDcCount; i++) {
4062 for (var r = 0; r < rsBlocks.length; r++) {
4063 if (i < dcdata[r].length) {
4064 data[index++] = dcdata[r][i];
4065 }
4066 }
4067 }
4068
4069 for (var i = 0; i < maxEcCount; i++) {
4070 for (var r = 0; r < rsBlocks.length; r++) {
4071 if (i < ecdata[r].length) {
4072 data[index++] = ecdata[r][i];
4073 }
4074 }
4075 }
4076
4077 return data;
4078
4079 };
4080
4081 //---------------------------------------------------------------------
4082 // QR8bitByte
4083 //---------------------------------------------------------------------
4084 QRCode.QR8bitByte = function (data) {
4085 this.mode = QRCode.Mode.MODE_8BIT_BYTE;
4086 this.data = data;
4087 }
4088
4089 QRCode.QR8bitByte.prototype = {
4090 getLength: function (buffer) {
4091 return this.data.length;
4092 },
4093
4094 write: function (buffer) {
4095 for (var i = 0; i < this.data.length; i++) {
4096 // not JIS ...
4097 buffer.put(this.data.charCodeAt(i), 8);
4098 }
4099 }
4100 };
4101
4102
4103 //---------------------------------------------------------------------
4104 // QRMode
4105 //---------------------------------------------------------------------
4106 QRCode.Mode = {
4107 MODE_NUMBER: 1 << 0,
4108 MODE_ALPHA_NUM: 1 << 1,
4109 MODE_8BIT_BYTE: 1 << 2,
4110 MODE_KANJI: 1 << 3
4111 };
4112
4113 //---------------------------------------------------------------------
4114 // QRErrorCorrectLevel
4115 //---------------------------------------------------------------------
4116 QRCode.ErrorCorrectLevel = {
4117 L: 1,
4118 M: 0,
4119 Q: 3,
4120 H: 2
4121 };
4122
4123
4124 //---------------------------------------------------------------------
4125 // QRMaskPattern
4126 //---------------------------------------------------------------------
4127 QRCode.MaskPattern = {
4128 PATTERN000: 0,
4129 PATTERN001: 1,
4130 PATTERN010: 2,
4131 PATTERN011: 3,
4132 PATTERN100: 4,
4133 PATTERN101: 5,
4134 PATTERN110: 6,
4135 PATTERN111: 7
4136 };
4137
4138 //---------------------------------------------------------------------
4139 // QRUtil
4140 //---------------------------------------------------------------------
4141
4142 QRCode.Util = {
4143
4144 PATTERN_POSITION_TABLE: [
4145 [],
4146 [6, 18],
4147 [6, 22],
4148 [6, 26],
4149 [6, 30],
4150 [6, 34],
4151 [6, 22, 38],
4152 [6, 24, 42],
4153 [6, 26, 46],
4154 [6, 28, 50],
4155 [6, 30, 54],
4156 [6, 32, 58],
4157 [6, 34, 62],
4158 [6, 26, 46, 66],
4159 [6, 26, 48, 70],
4160 [6, 26, 50, 74],
4161 [6, 30, 54, 78],
4162 [6, 30, 56, 82],
4163 [6, 30, 58, 86],
4164 [6, 34, 62, 90],
4165 [6, 28, 50, 72, 94],
4166 [6, 26, 50, 74, 98],
4167 [6, 30, 54, 78, 102],
4168 [6, 28, 54, 80, 106],
4169 [6, 32, 58, 84, 110],
4170 [6, 30, 58, 86, 114],
4171 [6, 34, 62, 90, 118],
4172 [6, 26, 50, 74, 98, 122],
4173 [6, 30, 54, 78, 102, 126],
4174 [6, 26, 52, 78, 104, 130],
4175 [6, 30, 56, 82, 108, 134],
4176 [6, 34, 60, 86, 112, 138],
4177 [6, 30, 58, 86, 114, 142],
4178 [6, 34, 62, 90, 118, 146],
4179 [6, 30, 54, 78, 102, 126, 150],
4180 [6, 24, 50, 76, 102, 128, 154],
4181 [6, 28, 54, 80, 106, 132, 158],
4182 [6, 32, 58, 84, 110, 136, 162],
4183 [6, 26, 54, 82, 110, 138, 166],
4184 [6, 30, 58, 86, 114, 142, 170]
4185 ],
4186
4187 G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
4188 G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
4189 G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
4190
4191 getBCHTypeInfo: function (data) {
4192 var d = data << 10;
4193 while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15) >= 0) {
4194 d ^= (QRCode.Util.G15 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15)));
4195 }
4196 return ((data << 10) | d) ^ QRCode.Util.G15_MASK;
4197 },
4198
4199 getBCHTypeNumber: function (data) {
4200 var d = data << 12;
4201 while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18) >= 0) {
4202 d ^= (QRCode.Util.G18 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18)));
4203 }
4204 return (data << 12) | d;
4205 },
4206
4207 getBCHDigit: function (data) {
4208
4209 var digit = 0;
4210
4211 while (data != 0) {
4212 digit++;
4213 data >>>= 1;
4214 }
4215
4216 return digit;
4217 },
4218
4219 getPatternPosition: function (typeNumber) {
4220 return QRCode.Util.PATTERN_POSITION_TABLE[typeNumber - 1];
4221 },
4222
4223 getMask: function (maskPattern, i, j) {
4224
4225 switch (maskPattern) {
4226
4227 case QRCode.MaskPattern.PATTERN000: return (i + j) % 2 == 0;
4228 case QRCode.MaskPattern.PATTERN001: return i % 2 == 0;
4229 case QRCode.MaskPattern.PATTERN010: return j % 3 == 0;
4230 case QRCode.MaskPattern.PATTERN011: return (i + j) % 3 == 0;
4231 case QRCode.MaskPattern.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
4232 case QRCode.MaskPattern.PATTERN101: return (i * j) % 2 + (i * j) % 3 == 0;
4233 case QRCode.MaskPattern.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
4234 case QRCode.MaskPattern.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
4235
4236 default:
4237 throw new Error("bad maskPattern:" + maskPattern);
4238 }
4239 },
4240
4241 getErrorCorrectPolynomial: function (errorCorrectLength) {
4242
4243 var a = new QRCode.Polynomial([1], 0);
4244
4245 for (var i = 0; i < errorCorrectLength; i++) {
4246 a = a.multiply(new QRCode.Polynomial([1, QRCode.Math.gexp(i)], 0));
4247 }
4248
4249 return a;
4250 },
4251
4252 getLengthInBits: function (mode, type) {
4253
4254 if (1 <= type && type < 10) {
4255
4256 // 1 - 9
4257
4258 switch (mode) {
4259 case QRCode.Mode.MODE_NUMBER: return 10;
4260 case QRCode.Mode.MODE_ALPHA_NUM: return 9;
4261 case QRCode.Mode.MODE_8BIT_BYTE: return 8;
4262 case QRCode.Mode.MODE_KANJI: return 8;
4263 default:
4264 throw new Error("mode:" + mode);
4265 }
4266
4267 } else if (type < 27) {
4268
4269 // 10 - 26
4270
4271 switch (mode) {
4272 case QRCode.Mode.MODE_NUMBER: return 12;
4273 case QRCode.Mode.MODE_ALPHA_NUM: return 11;
4274 case QRCode.Mode.MODE_8BIT_BYTE: return 16;
4275 case QRCode.Mode.MODE_KANJI: return 10;
4276 default:
4277 throw new Error("mode:" + mode);
4278 }
4279
4280 } else if (type < 41) {
4281
4282 // 27 - 40
4283
4284 switch (mode) {
4285 case QRCode.Mode.MODE_NUMBER: return 14;
4286 case QRCode.Mode.MODE_ALPHA_NUM: return 13;
4287 case QRCode.Mode.MODE_8BIT_BYTE: return 16;
4288 case QRCode.Mode.MODE_KANJI: return 12;
4289 default:
4290 throw new Error("mode:" + mode);
4291 }
4292
4293 } else {
4294 throw new Error("type:" + type);
4295 }
4296 },
4297
4298 getLostPoint: function (qrCode) {
4299
4300 var moduleCount = qrCode.getModuleCount();
4301
4302 var lostPoint = 0;
4303
4304 // LEVEL1
4305
4306 for (var row = 0; row < moduleCount; row++) {
4307
4308 for (var col = 0; col < moduleCount; col++) {
4309
4310 var sameCount = 0;
4311 var dark = qrCode.isDark(row, col);
4312
4313 for (var r = -1; r <= 1; r++) {
4314
4315 if (row + r < 0 || moduleCount <= row + r) {
4316 continue;
4317 }
4318
4319 for (var c = -1; c <= 1; c++) {
4320
4321 if (col + c < 0 || moduleCount <= col + c) {
4322 continue;
4323 }
4324
4325 if (r == 0 && c == 0) {
4326 continue;
4327 }
4328
4329 if (dark == qrCode.isDark(row + r, col + c)) {
4330 sameCount++;
4331 }
4332 }
4333 }
4334
4335 if (sameCount > 5) {
4336 lostPoint += (3 + sameCount - 5);
4337 }
4338 }
4339 }
4340
4341 // LEVEL2
4342
4343 for (var row = 0; row < moduleCount - 1; row++) {
4344 for (var col = 0; col < moduleCount - 1; col++) {
4345 var count = 0;
4346 if (qrCode.isDark(row, col)) count++;
4347 if (qrCode.isDark(row + 1, col)) count++;
4348 if (qrCode.isDark(row, col + 1)) count++;
4349 if (qrCode.isDark(row + 1, col + 1)) count++;
4350 if (count == 0 || count == 4) {
4351 lostPoint += 3;
4352 }
4353 }
4354 }
4355
4356 // LEVEL3
4357
4358 for (var row = 0; row < moduleCount; row++) {
4359 for (var col = 0; col < moduleCount - 6; col++) {
4360 if (qrCode.isDark(row, col)
4361 && !qrCode.isDark(row, col + 1)
4362 && qrCode.isDark(row, col + 2)
4363 && qrCode.isDark(row, col + 3)
4364 && qrCode.isDark(row, col + 4)
4365 && !qrCode.isDark(row, col + 5)
4366 && qrCode.isDark(row, col + 6)) {
4367 lostPoint += 40;
4368 }
4369 }
4370 }
4371
4372 for (var col = 0; col < moduleCount; col++) {
4373 for (var row = 0; row < moduleCount - 6; row++) {
4374 if (qrCode.isDark(row, col)
4375 && !qrCode.isDark(row + 1, col)
4376 && qrCode.isDark(row + 2, col)
4377 && qrCode.isDark(row + 3, col)
4378 && qrCode.isDark(row + 4, col)
4379 && !qrCode.isDark(row + 5, col)
4380 && qrCode.isDark(row + 6, col)) {
4381 lostPoint += 40;
4382 }
4383 }
4384 }
4385
4386 // LEVEL4
4387
4388 var darkCount = 0;
4389
4390 for (var col = 0; col < moduleCount; col++) {
4391 for (var row = 0; row < moduleCount; row++) {
4392 if (qrCode.isDark(row, col)) {
4393 darkCount++;
4394 }
4395 }
4396 }
4397
4398 var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
4399 lostPoint += ratio * 10;
4400
4401 return lostPoint;
4402 }
4403
4404 };
4405
4406
4407 //---------------------------------------------------------------------
4408 // QRMath
4409 //---------------------------------------------------------------------
4410
4411 QRCode.Math = {
4412
4413 glog: function (n) {
4414
4415 if (n < 1) {
4416 throw new Error("glog(" + n + ")");
4417 }
4418
4419 return QRCode.Math.LOG_TABLE[n];
4420 },
4421
4422 gexp: function (n) {
4423
4424 while (n < 0) {
4425 n += 255;
4426 }
4427
4428 while (n >= 256) {
4429 n -= 255;
4430 }
4431
4432 return QRCode.Math.EXP_TABLE[n];
4433 },
4434
4435 EXP_TABLE: new Array(256),
4436
4437 LOG_TABLE: new Array(256)
4438
4439 };
4440
4441 for (var i = 0; i < 8; i++) {
4442 QRCode.Math.EXP_TABLE[i] = 1 << i;
4443 }
4444 for (var i = 8; i < 256; i++) {
4445 QRCode.Math.EXP_TABLE[i] = QRCode.Math.EXP_TABLE[i - 4]
4446 ^ QRCode.Math.EXP_TABLE[i - 5]
4447 ^ QRCode.Math.EXP_TABLE[i - 6]
4448 ^ QRCode.Math.EXP_TABLE[i - 8];
4449 }
4450 for (var i = 0; i < 255; i++) {
4451 QRCode.Math.LOG_TABLE[QRCode.Math.EXP_TABLE[i]] = i;
4452 }
4453
4454 //---------------------------------------------------------------------
4455 // QRPolynomial
4456 //---------------------------------------------------------------------
4457
4458 QRCode.Polynomial = function (num, shift) {
4459
4460 if (num.length == undefined) {
4461 throw new Error(num.length + "/" + shift);
4462 }
4463
4464 var offset = 0;
4465
4466 while (offset < num.length && num[offset] == 0) {
4467 offset++;
4468 }
4469
4470 this.num = new Array(num.length - offset + shift);
4471 for (var i = 0; i < num.length - offset; i++) {
4472 this.num[i] = num[i + offset];
4473 }
4474 }
4475
4476 QRCode.Polynomial.prototype = {
4477
4478 get: function (index) {
4479 return this.num[index];
4480 },
4481
4482 getLength: function () {
4483 return this.num.length;
4484 },
4485
4486 multiply: function (e) {
4487
4488 var num = new Array(this.getLength() + e.getLength() - 1);
4489
4490 for (var i = 0; i < this.getLength(); i++) {
4491 for (var j = 0; j < e.getLength(); j++) {
4492 num[i + j] ^= QRCode.Math.gexp(QRCode.Math.glog(this.get(i)) + QRCode.Math.glog(e.get(j)));
4493 }
4494 }
4495
4496 return new QRCode.Polynomial(num, 0);
4497 },
4498
4499 mod: function (e) {
4500
4501 if (this.getLength() - e.getLength() < 0) {
4502 return this;
4503 }
4504
4505 var ratio = QRCode.Math.glog(this.get(0)) - QRCode.Math.glog(e.get(0));
4506
4507 var num = new Array(this.getLength());
4508
4509 for (var i = 0; i < this.getLength(); i++) {
4510 num[i] = this.get(i);
4511 }
4512
4513 for (var i = 0; i < e.getLength(); i++) {
4514 num[i] ^= QRCode.Math.gexp(QRCode.Math.glog(e.get(i)) + ratio);
4515 }
4516
4517 // recursive call
4518 return new QRCode.Polynomial(num, 0).mod(e);
4519 }
4520 };
4521
4522 //---------------------------------------------------------------------
4523 // QRRSBlock
4524 //---------------------------------------------------------------------
4525
4526 QRCode.RSBlock = function (totalCount, dataCount) {
4527 this.totalCount = totalCount;
4528 this.dataCount = dataCount;
4529 }
4530
4531 QRCode.RSBlock.RS_BLOCK_TABLE = [
4532
4533 // L
4534 // M
4535 // Q
4536 // H
4537
4538 // 1
4539 [1, 26, 19],
4540 [1, 26, 16],
4541 [1, 26, 13],
4542 [1, 26, 9],
4543
4544 // 2
4545 [1, 44, 34],
4546 [1, 44, 28],
4547 [1, 44, 22],
4548 [1, 44, 16],
4549
4550 // 3
4551 [1, 70, 55],
4552 [1, 70, 44],
4553 [2, 35, 17],
4554 [2, 35, 13],
4555
4556 // 4
4557 [1, 100, 80],
4558 [2, 50, 32],
4559 [2, 50, 24],
4560 [4, 25, 9],
4561
4562 // 5
4563 [1, 134, 108],
4564 [2, 67, 43],
4565 [2, 33, 15, 2, 34, 16],
4566 [2, 33, 11, 2, 34, 12],
4567
4568 // 6
4569 [2, 86, 68],
4570 [4, 43, 27],
4571 [4, 43, 19],
4572 [4, 43, 15],
4573
4574 // 7
4575 [2, 98, 78],
4576 [4, 49, 31],
4577 [2, 32, 14, 4, 33, 15],
4578 [4, 39, 13, 1, 40, 14],
4579
4580 // 8
4581 [2, 121, 97],
4582 [2, 60, 38, 2, 61, 39],
4583 [4, 40, 18, 2, 41, 19],
4584 [4, 40, 14, 2, 41, 15],
4585
4586 // 9
4587 [2, 146, 116],
4588 [3, 58, 36, 2, 59, 37],
4589 [4, 36, 16, 4, 37, 17],
4590 [4, 36, 12, 4, 37, 13],
4591
4592 // 10
4593 [2, 86, 68, 2, 87, 69],
4594 [4, 69, 43, 1, 70, 44],
4595 [6, 43, 19, 2, 44, 20],
4596 [6, 43, 15, 2, 44, 16]
4597
4598];
4599
4600 QRCode.RSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
4601
4602 var rsBlock = QRCode.RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
4603
4604 if (rsBlock == undefined) {
4605 throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
4606 }
4607
4608 var length = rsBlock.length / 3;
4609
4610 var list = new Array();
4611
4612 for (var i = 0; i < length; i++) {
4613
4614 var count = rsBlock[i * 3 + 0];
4615 var totalCount = rsBlock[i * 3 + 1];
4616 var dataCount = rsBlock[i * 3 + 2];
4617
4618 for (var j = 0; j < count; j++) {
4619 list.push(new QRCode.RSBlock(totalCount, dataCount));
4620 }
4621 }
4622
4623 return list;
4624 };
4625
4626 QRCode.RSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
4627
4628 switch (errorCorrectLevel) {
4629 case QRCode.ErrorCorrectLevel.L:
4630 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
4631 case QRCode.ErrorCorrectLevel.M:
4632 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
4633 case QRCode.ErrorCorrectLevel.Q:
4634 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
4635 case QRCode.ErrorCorrectLevel.H:
4636 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
4637 default:
4638 return undefined;
4639 }
4640 };
4641
4642 //---------------------------------------------------------------------
4643 // QRBitBuffer
4644 //---------------------------------------------------------------------
4645
4646 QRCode.BitBuffer = function () {
4647 this.buffer = new Array();
4648 this.length = 0;
4649 }
4650
4651 QRCode.BitBuffer.prototype = {
4652
4653 get: function (index) {
4654 var bufIndex = Math.floor(index / 8);
4655 return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
4656 },
4657
4658 put: function (num, length) {
4659 for (var i = 0; i < length; i++) {
4660 this.putBit(((num >>> (length - i - 1)) & 1) == 1);
4661 }
4662 },
4663
4664 getLengthInBits: function () {
4665 return this.length;
4666 },
4667
4668 putBit: function (bit) {
4669
4670 var bufIndex = Math.floor(this.length / 8);
4671 if (this.buffer.length <= bufIndex) {
4672 this.buffer.push(0);
4673 }
4674
4675 if (bit) {
4676 this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
4677 }
4678
4679 this.length++;
4680 }
4681 };
4682})();
4683 </script>
4684 <script type="text/javascript">
4685/*
4686Copyright (c) 2011 Stefan Thomas
4687
4688Permission 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:
4689
4690The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
4691
4692THE 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.
4693*/
4694
4695//https://raw.github.com/bitcoinjs/bitcoinjs-lib/1a7fc9d063f864058809d06ef4542af40be3558f/src/bitcoin.js
4696(function (exports) {
4697 var Bitcoin = exports;
4698})(
4699 'object' === typeof module ? module.exports : (window.Bitcoin = {})
4700);
4701 </script>
4702 <script type="text/javascript">
4703//https://raw.github.com/bitcoinjs/bitcoinjs-lib/c952aaeb3ee472e3776655b8ea07299ebed702c7/src/base58.js
4704(function (Bitcoin) {
4705 Bitcoin.Base58 = {
4706 alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
4707 validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/,
4708 base: BigInteger.valueOf(58),
4709
4710 /**
4711 * Convert a byte array to a base58-encoded string.
4712 *
4713 * Written by Mike Hearn for BitcoinJ.
4714 * Copyright (c) 2011 Google Inc.
4715 *
4716 * Ported to JavaScript by Stefan Thomas.
4717 */
4718 encode: function (input) {
4719 var bi = BigInteger.fromByteArrayUnsigned(input);
4720 var chars = [];
4721
4722 while (bi.compareTo(B58.base) >= 0) {
4723 var mod = bi.mod(B58.base);
4724 chars.unshift(B58.alphabet[mod.intValue()]);
4725 bi = bi.subtract(mod).divide(B58.base);
4726 }
4727 chars.unshift(B58.alphabet[bi.intValue()]);
4728
4729 // Convert leading zeros too.
4730 for (var i = 0; i < input.length; i++) {
4731 if (input[i] == 0x00) {
4732 chars.unshift(B58.alphabet[0]);
4733 } else break;
4734 }
4735
4736 return chars.join('');
4737 },
4738
4739 /**
4740 * Convert a base58-encoded string to a byte array.
4741 *
4742 * Written by Mike Hearn for BitcoinJ.
4743 * Copyright (c) 2011 Google Inc.
4744 *
4745 * Ported to JavaScript by Stefan Thomas.
4746 */
4747 decode: function (input) {
4748 var bi = BigInteger.valueOf(0);
4749 var leadingZerosNum = 0;
4750 for (var i = input.length - 1; i >= 0; i--) {
4751 var alphaIndex = B58.alphabet.indexOf(input[i]);
4752 if (alphaIndex < 0) {
4753 throw "Invalid character";
4754 }
4755 bi = bi.add(BigInteger.valueOf(alphaIndex)
4756 .multiply(B58.base.pow(input.length - 1 - i)));
4757
4758 // This counts leading zero bytes
4759 if (input[i] == "1") leadingZerosNum++;
4760 else leadingZerosNum = 0;
4761 }
4762 var bytes = bi.toByteArrayUnsigned();
4763
4764 // Add leading zeros
4765 while (leadingZerosNum-- > 0) bytes.unshift(0);
4766
4767 return bytes;
4768 }
4769 };
4770
4771 var B58 = Bitcoin.Base58;
4772})(
4773 'undefined' != typeof Bitcoin ? Bitcoin : module.exports
4774);
4775 </script>
4776 <script type="text/javascript">
4777//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/address.js
4778Bitcoin.Address = function (bytes) {
4779 if ("string" == typeof bytes) {
4780 bytes = Bitcoin.Address.decodeString(bytes);
4781 }
4782 this.hash = bytes;
4783};
4784
4785/**
4786* Serialize this object as a standard currency address.
4787*
4788* Returns the address as a base58-encoded string in the standardized format.
4789*/
4790Bitcoin.Address.prototype.toString = function () {
4791 // Get a copy of the hash
4792 var hash = this.hash.slice(0);
4793
4794 // Version
4795 hash.unshift(janin.currency.networkVersion());
4796 var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
4797 var bytes = hash.concat(checksum.slice(0, 4));
4798 return Bitcoin.Base58.encode(bytes);
4799};
4800
4801Bitcoin.Address.prototype.getHashBase64 = function () {
4802 return Crypto.util.bytesToBase64(this.hash);
4803};
4804
4805/**
4806* Parse a Bitcoin address contained in a string.
4807*/
4808Bitcoin.Address.decodeString = function (string) {
4809 var bytes = Bitcoin.Base58.decode(string);
4810 var hash = bytes.slice(0, 21);
4811 var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
4812
4813 if (checksum[0] != bytes[21] ||
4814 checksum[1] != bytes[22] ||
4815 checksum[2] != bytes[23] ||
4816 checksum[3] != bytes[24]) {
4817 throw "Checksum validation failed!";
4818 }
4819
4820 return hash;
4821};
4822 </script>
4823 <script type="text/javascript">
4824//https://raw.github.com/bitcoinjs/bitcoinjs-lib/e90780d3d3b8fc0d027d2bcb38b80479902f223e/src/ecdsa.js
4825Bitcoin.ECDSA = (function () {
4826 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
4827 var rng = new SecureRandom();
4828
4829 var P_OVER_FOUR = null;
4830
4831 function implShamirsTrick(P, k, Q, l) {
4832 var m = Math.max(k.bitLength(), l.bitLength());
4833 var Z = P.add2D(Q);
4834 var R = P.curve.getInfinity();
4835
4836 for (var i = m - 1; i >= 0; --i) {
4837 R = R.twice2D();
4838
4839 R.z = BigInteger.ONE;
4840
4841 if (k.testBit(i)) {
4842 if (l.testBit(i)) {
4843 R = R.add2D(Z);
4844 } else {
4845 R = R.add2D(P);
4846 }
4847 } else {
4848 if (l.testBit(i)) {
4849 R = R.add2D(Q);
4850 }
4851 }
4852 }
4853
4854 return R;
4855 };
4856
4857 var ECDSA = {
4858 getBigRandom: function (limit) {
4859 return new BigInteger(limit.bitLength(), rng)
4860 .mod(limit.subtract(BigInteger.ONE))
4861 .add(BigInteger.ONE);
4862 },
4863 sign: function (hash, priv) {
4864 var d = priv;
4865 var n = ecparams.getN();
4866 var e = BigInteger.fromByteArrayUnsigned(hash);
4867
4868 do {
4869 var k = ECDSA.getBigRandom(n);
4870 var G = ecparams.getG();
4871 var Q = G.multiply(k);
4872 var r = Q.getX().toBigInteger().mod(n);
4873 } while (r.compareTo(BigInteger.ZERO) <= 0);
4874
4875 var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
4876
4877 return ECDSA.serializeSig(r, s);
4878 },
4879
4880 verify: function (hash, sig, pubkey) {
4881 var r, s;
4882 if (Bitcoin.Util.isArray(sig)) {
4883 var obj = ECDSA.parseSig(sig);
4884 r = obj.r;
4885 s = obj.s;
4886 } else if ("object" === typeof sig && sig.r && sig.s) {
4887 r = sig.r;
4888 s = sig.s;
4889 } else {
4890 throw "Invalid value for signature";
4891 }
4892
4893 var Q;
4894 if (pubkey instanceof ec.PointFp) {
4895 Q = pubkey;
4896 } else if (Bitcoin.Util.isArray(pubkey)) {
4897 Q = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), pubkey);
4898 } else {
4899 throw "Invalid format for pubkey value, must be byte array or ec.PointFp";
4900 }
4901 var e = BigInteger.fromByteArrayUnsigned(hash);
4902
4903 return ECDSA.verifyRaw(e, r, s, Q);
4904 },
4905
4906 verifyRaw: function (e, r, s, Q) {
4907 var n = ecparams.getN();
4908 var G = ecparams.getG();
4909
4910 if (r.compareTo(BigInteger.ONE) < 0 ||
4911 r.compareTo(n) >= 0)
4912 return false;
4913
4914 if (s.compareTo(BigInteger.ONE) < 0 ||
4915 s.compareTo(n) >= 0)
4916 return false;
4917
4918 var c = s.modInverse(n);
4919
4920 var u1 = e.multiply(c).mod(n);
4921 var u2 = r.multiply(c).mod(n);
4922
4923 // TODO(!!!): For some reason Shamir's trick isn't working with
4924 // signed message verification!? Probably an implementation
4925 // error!
4926 //var point = implShamirsTrick(G, u1, Q, u2);
4927 var point = G.multiply(u1).add(Q.multiply(u2));
4928
4929 var v = point.getX().toBigInteger().mod(n);
4930
4931 return v.equals(r);
4932 },
4933
4934 /**
4935 * Serialize a signature into DER format.
4936 *
4937 * Takes two BigIntegers representing r and s and returns a byte array.
4938 */
4939 serializeSig: function (r, s) {
4940 var rBa = r.toByteArraySigned();
4941 var sBa = s.toByteArraySigned();
4942
4943 var sequence = [];
4944 sequence.push(0x02); // INTEGER
4945 sequence.push(rBa.length);
4946 sequence = sequence.concat(rBa);
4947
4948 sequence.push(0x02); // INTEGER
4949 sequence.push(sBa.length);
4950 sequence = sequence.concat(sBa);
4951
4952 sequence.unshift(sequence.length);
4953 sequence.unshift(0x30); // SEQUENCE
4954
4955 return sequence;
4956 },
4957
4958 /**
4959 * Parses a byte array containing a DER-encoded signature.
4960 *
4961 * This function will return an object of the form:
4962 *
4963 * {
4964 * r: BigInteger,
4965 * s: BigInteger
4966 * }
4967 */
4968 parseSig: function (sig) {
4969 var cursor;
4970 if (sig[0] != 0x30)
4971 throw new Error("Signature not a valid DERSequence");
4972
4973 cursor = 2;
4974 if (sig[cursor] != 0x02)
4975 throw new Error("First element in signature must be a DERInteger"); ;
4976 var rBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
4977
4978 cursor += 2 + sig[cursor + 1];
4979 if (sig[cursor] != 0x02)
4980 throw new Error("Second element in signature must be a DERInteger");
4981 var sBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
4982
4983 cursor += 2 + sig[cursor + 1];
4984
4985 //if (cursor != sig.length)
4986 // throw new Error("Extra bytes in signature");
4987
4988 var r = BigInteger.fromByteArrayUnsigned(rBa);
4989 var s = BigInteger.fromByteArrayUnsigned(sBa);
4990
4991 return { r: r, s: s };
4992 },
4993
4994 parseSigCompact: function (sig) {
4995 if (sig.length !== 65) {
4996 throw "Signature has the wrong length";
4997 }
4998
4999 // Signature is prefixed with a type byte storing three bits of
5000 // information.
5001 var i = sig[0] - 27;
5002 if (i < 0 || i > 7) {
5003 throw "Invalid signature type";
5004 }
5005
5006 var n = ecparams.getN();
5007 var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
5008 var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
5009
5010 return { r: r, s: s, i: i };
5011 },
5012
5013 /**
5014 * Recover a public key from a signature.
5015 *
5016 * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
5017 * Key Recovery Operation".
5018 *
5019 * http://www.secg.org/download/aid-780/sec1-v2.pdf
5020 */
5021 recoverPubKey: function (r, s, hash, i) {
5022 // The recovery parameter i has two bits.
5023 i = i & 3;
5024
5025 // The less significant bit specifies whether the y coordinate
5026 // of the compressed point is even or not.
5027 var isYEven = i & 1;
5028
5029 // The more significant bit specifies whether we should use the
5030 // first or second candidate key.
5031 var isSecondKey = i >> 1;
5032
5033 var n = ecparams.getN();
5034 var G = ecparams.getG();
5035 var curve = ecparams.getCurve();
5036 var p = curve.getQ();
5037 var a = curve.getA().toBigInteger();
5038 var b = curve.getB().toBigInteger();
5039
5040 // We precalculate (p + 1) / 4 where p is if the field order
5041 if (!P_OVER_FOUR) {
5042 P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
5043 }
5044
5045 // 1.1 Compute x
5046 var x = isSecondKey ? r.add(n) : r;
5047
5048 // 1.3 Convert x to point
5049 var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
5050 var beta = alpha.modPow(P_OVER_FOUR, p);
5051
5052 var xorOdd = beta.isEven() ? (i % 2) : ((i + 1) % 2);
5053 // If beta is even, but y isn't or vice versa, then convert it,
5054 // otherwise we're done and y == beta.
5055 var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
5056
5057 // 1.4 Check that nR is at infinity
5058 var R = new EllipticCurve.PointFp(curve,
5059 curve.fromBigInteger(x),
5060 curve.fromBigInteger(y));
5061 R.validate();
5062
5063 // 1.5 Compute e from M
5064 var e = BigInteger.fromByteArrayUnsigned(hash);
5065 var eNeg = BigInteger.ZERO.subtract(e).mod(n);
5066
5067 // 1.6 Compute Q = r^-1 (sR - eG)
5068 var rInv = r.modInverse(n);
5069 var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
5070
5071 Q.validate();
5072 if (!ECDSA.verifyRaw(e, r, s, Q)) {
5073 throw "Pubkey recovery unsuccessful";
5074 }
5075
5076 var pubKey = new Bitcoin.ECKey();
5077 pubKey.pub = Q;
5078 return pubKey;
5079 },
5080
5081 /**
5082 * Calculate pubkey extraction parameter.
5083 *
5084 * When extracting a pubkey from a signature, we have to
5085 * distinguish four different cases. Rather than putting this
5086 * burden on the verifier, Bitcoin includes a 2-bit value with the
5087 * signature.
5088 *
5089 * This function simply tries all four cases and returns the value
5090 * that resulted in a successful pubkey recovery.
5091 */
5092 calcPubkeyRecoveryParam: function (address, r, s, hash) {
5093 for (var i = 0; i < 4; i++) {
5094 try {
5095 var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
5096 if (pubkey.getBitcoinAddress().toString() == address) {
5097 return i;
5098 }
5099 } catch (e) { }
5100 }
5101 throw "Unable to find valid recovery factor";
5102 }
5103 };
5104
5105 return ECDSA;
5106})();
5107 </script>
5108 <script type="text/javascript">
5109//https://raw.github.com/pointbiz/bitcoinjs-lib/9b2f94a028a7bc9bed94e0722563e9ff1d8e8db8/src/eckey.js
5110Bitcoin.ECKey = (function () {
5111 var ECDSA = Bitcoin.ECDSA;
5112 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
5113 var rng = new SecureRandom();
5114
5115 var ECKey = function (input) {
5116 if (!input) {
5117 // Generate new key
5118 var n = ecparams.getN();
5119 this.priv = ECDSA.getBigRandom(n);
5120 } else if (input instanceof BigInteger) {
5121 // Input is a private key value
5122 this.priv = input;
5123 } else if (Bitcoin.Util.isArray(input)) {
5124 // Prepend zero byte to prevent interpretation as negative integer
5125 this.priv = BigInteger.fromByteArrayUnsigned(input);
5126 } else if ("string" == typeof input) {
5127 var bytes = null;
5128 if (ECKey.isWalletImportFormat(input)) {
5129 bytes = ECKey.decodeWalletImportFormat(input);
5130 } else if (ECKey.isCompressedWalletImportFormat(input)) {
5131 bytes = ECKey.decodeCompressedWalletImportFormat(input);
5132 this.compressed = true;
5133 } else if (ECKey.isMiniFormat(input)) {
5134 bytes = Crypto.SHA256(input, { asBytes: true });
5135 } else if (ECKey.isHexFormat(input)) {
5136 bytes = Crypto.util.hexToBytes(input);
5137 } else if (ECKey.isBase64Format(input)) {
5138 bytes = Crypto.util.base64ToBytes(input);
5139 }
5140
5141 if (ECKey.isBase6Format(input)) {
5142 this.priv = new BigInteger(input, 6);
5143 } else if (bytes == null || bytes.length != 32) {
5144 this.priv = null;
5145 } else {
5146 // Prepend zero byte to prevent interpretation as negative integer
5147 this.priv = BigInteger.fromByteArrayUnsigned(bytes);
5148 }
5149 }
5150
5151 this.compressed = (this.compressed == undefined) ? !!ECKey.compressByDefault : this.compressed;
5152 };
5153
5154 /**
5155 * Whether public keys should be returned compressed by default.
5156 */
5157 ECKey.compressByDefault = false;
5158
5159 /**
5160 * Set whether the public key should be returned compressed or not.
5161 */
5162 ECKey.prototype.setCompressed = function (v) {
5163 this.compressed = !!v;
5164 if (this.pubPoint) this.pubPoint.compressed = this.compressed;
5165 return this;
5166 };
5167
5168 /*
5169 * Return public key as a byte array in DER encoding
5170 */
5171 ECKey.prototype.getPub = function () {
5172 if (this.compressed) {
5173 if (this.pubComp) return this.pubComp;
5174 return this.pubComp = this.getPubPoint().getEncoded(1);
5175 } else {
5176 if (this.pubUncomp) return this.pubUncomp;
5177 return this.pubUncomp = this.getPubPoint().getEncoded(0);
5178 }
5179 };
5180
5181 /**
5182 * Return public point as ECPoint object.
5183 */
5184 ECKey.prototype.getPubPoint = function () {
5185 if (!this.pubPoint) {
5186 this.pubPoint = ecparams.getG().multiply(this.priv);
5187 this.pubPoint.compressed = this.compressed;
5188 }
5189 return this.pubPoint;
5190 };
5191
5192 ECKey.prototype.getPubKeyHex = function () {
5193 if (this.compressed) {
5194 if (this.pubKeyHexComp) return this.pubKeyHexComp;
5195 return this.pubKeyHexComp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
5196 } else {
5197 if (this.pubKeyHexUncomp) return this.pubKeyHexUncomp;
5198 return this.pubKeyHexUncomp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
5199 }
5200 };
5201
5202 /**
5203 * Get the pubKeyHash for this key.
5204 *
5205 * This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
5206 * a byte array.
5207 */
5208 ECKey.prototype.getPubKeyHash = function () {
5209 if (this.compressed) {
5210 if (this.pubKeyHashComp) return this.pubKeyHashComp;
5211 return this.pubKeyHashComp = Bitcoin.Util.sha256ripe160(this.getPub());
5212 } else {
5213 if (this.pubKeyHashUncomp) return this.pubKeyHashUncomp;
5214 return this.pubKeyHashUncomp = Bitcoin.Util.sha256ripe160(this.getPub());
5215 }
5216 };
5217
5218 ECKey.prototype.getBitcoinAddress = function () {
5219 var hash = this.getPubKeyHash();
5220 var addr = new Bitcoin.Address(hash);
5221 return addr.toString();
5222 };
5223
5224 /*
5225 * Takes a public point as a hex string or byte array
5226 */
5227 ECKey.prototype.setPub = function (pub) {
5228 // byte array
5229 if (Bitcoin.Util.isArray(pub)) {
5230 pub = Crypto.util.bytesToHex(pub).toString().toUpperCase();
5231 }
5232 var ecPoint = ecparams.getCurve().decodePointHex(pub);
5233 this.setCompressed(ecPoint.compressed);
5234 this.pubPoint = ecPoint;
5235 return this;
5236 };
5237
5238 // Sipa Private Key Wallet Import Format
5239 ECKey.prototype.getBitcoinWalletImportFormat = function () {
5240 var bytes = this.getBitcoinPrivateKeyByteArray();
5241 bytes.unshift(janin.currency.privateKeyPrefix()); // prepend private key prefix
5242 if (this.compressed) bytes.push(0x01); // append 0x01 byte for compressed format
5243 var checksum = Crypto.SHA256(Crypto.SHA256(bytes, { asBytes: true }), { asBytes: true });
5244 bytes = bytes.concat(checksum.slice(0, 4));
5245 var privWif = Bitcoin.Base58.encode(bytes);
5246 return privWif;
5247 };
5248
5249 // Private Key Hex Format
5250 ECKey.prototype.getBitcoinHexFormat = function () {
5251 return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase();
5252 };
5253
5254 // Private Key Base64 Format
5255 ECKey.prototype.getBitcoinBase64Format = function () {
5256 return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray());
5257 };
5258
5259 ECKey.prototype.getBitcoinPrivateKeyByteArray = function () {
5260 // Get a copy of private key as a byte array
5261 var bytes = this.priv.toByteArrayUnsigned();
5262 // zero pad if private key is less than 32 bytes
5263 while (bytes.length < 32) bytes.unshift(0x00);
5264 return bytes;
5265 };
5266
5267 ECKey.prototype.toString = function (format) {
5268 format = format || "";
5269 if (format.toString().toLowerCase() == "base64" || format.toString().toLowerCase() == "b64") {
5270 return this.getBitcoinBase64Format();
5271 }
5272 // Wallet Import Format
5273 else if (format.toString().toLowerCase() == "wif") {
5274 return this.getBitcoinWalletImportFormat();
5275 }
5276 else {
5277 return this.getBitcoinHexFormat();
5278 }
5279 };
5280
5281 ECKey.prototype.sign = function (hash) {
5282 return ECDSA.sign(hash, this.priv);
5283 };
5284
5285 ECKey.prototype.verify = function (hash, sig) {
5286 return ECDSA.verify(hash, sig, this.getPub());
5287 };
5288
5289 /**
5290 * Parse a wallet import format private key contained in a string.
5291 */
5292 ECKey.decodeWalletImportFormat = function (privStr) {
5293 var bytes = Bitcoin.Base58.decode(privStr);
5294 var hash = bytes.slice(0, 33);
5295 var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
5296 if (checksum[0] != bytes[33] ||
5297 checksum[1] != bytes[34] ||
5298 checksum[2] != bytes[35] ||
5299 checksum[3] != bytes[36]) {
5300 throw "Checksum validation failed!";
5301 }
5302 var version = hash.shift();
5303 // TODO: detect currency
5304 if (version != janin.currency.privateKeyPrefix()) {
5305 throw "Version " + version + " not supported!";
5306 }
5307 return hash;
5308 };
5309
5310 /**
5311 * Parse a compressed wallet import format private key contained in a string.
5312 */
5313 ECKey.decodeCompressedWalletImportFormat = function (privStr) {
5314 var bytes = Bitcoin.Base58.decode(privStr);
5315 var hash = bytes.slice(0, 34);
5316 var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
5317 if (checksum[0] != bytes[34] ||
5318 checksum[1] != bytes[35] ||
5319 checksum[2] != bytes[36] ||
5320 checksum[3] != bytes[37]) {
5321 throw "Checksum validation failed!";
5322 }
5323 var version = hash.shift();
5324 // TODO: detect currency
5325 if (version != janin.currency.privateKeyPrefix()) {
5326 throw "Version " + version + " not supported!";
5327 }
5328 hash.pop();
5329 return hash;
5330 };
5331
5332 // 64 characters [0-9A-F]
5333 ECKey.isHexFormat = function (key) {
5334 key = key.toString();
5335 return /^[A-Fa-f0-9]{64}$/.test(key);
5336 };
5337
5338 // 51 characters base58, always starts with a '5'
5339 ECKey.isWalletImportFormat = function (key) {
5340 key = key.toString();
5341 return janin.currency.WIF_RegEx().test(key);
5342 };
5343
5344 // 52 characters base58
5345 ECKey.isCompressedWalletImportFormat = function (key) {
5346 key = key.toString();
5347 return janin.currency.CWIF_RegEx().test(key);
5348 };
5349
5350 // 44 characters
5351 ECKey.isBase64Format = function (key) {
5352 key = key.toString();
5353 return (/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key));
5354 };
5355
5356 // 99 characters, 1=1, if using dice convert 6 to 0
5357 ECKey.isBase6Format = function (key) {
5358 key = key.toString();
5359 return (/^[012345]{99}$/.test(key));
5360 };
5361
5362 // 22, 26 or 30 characters, always starts with an 'S'
5363 ECKey.isMiniFormat = function (key) {
5364 key = key.toString();
5365 var validChars22 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key);
5366 var validChars26 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key);
5367 var validChars30 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key);
5368 var testBytes = Crypto.SHA256(key + "?", { asBytes: true });
5369
5370 return ((testBytes[0] === 0x00 || testBytes[0] === 0x01) && (validChars22 || validChars26 || validChars30));
5371 };
5372
5373 return ECKey;
5374})();
5375 </script>
5376 <script type="text/javascript">
5377//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/util.js
5378// Bitcoin utility functions
5379Bitcoin.Util = {
5380 /**
5381 * Cross-browser compatibility version of Array.isArray.
5382 */
5383 isArray: Array.isArray || function (o) {
5384 return Object.prototype.toString.call(o) === '[object Array]';
5385 },
5386 /**
5387 * Create an array of a certain length filled with a specific value.
5388 */
5389 makeFilledArray: function (len, val) {
5390 var array = [];
5391 var i = 0;
5392 while (i < len) {
5393 array[i++] = val;
5394 }
5395 return array;
5396 },
5397 /**
5398 * Turn an integer into a "var_int".
5399 *
5400 * "var_int" is a variable length integer used by Bitcoin's binary format.
5401 *
5402 * Returns a byte array.
5403 */
5404 numToVarInt: function (i) {
5405 if (i < 0xfd) {
5406 // unsigned char
5407 return [i];
5408 } else if (i <= 1 << 16) {
5409 // unsigned short (LE)
5410 return [0xfd, i >>> 8, i & 255];
5411 } else if (i <= 1 << 32) {
5412 // unsigned int (LE)
5413 return [0xfe].concat(Crypto.util.wordsToBytes([i]));
5414 } else {
5415 // unsigned long long (LE)
5416 return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
5417 }
5418 },
5419 /**
5420 * Parse a Bitcoin value byte array, returning a BigInteger.
5421 */
5422 valueToBigInt: function (valueBuffer) {
5423 if (valueBuffer instanceof BigInteger) return valueBuffer;
5424
5425 // Prepend zero byte to prevent interpretation as negative integer
5426 return BigInteger.fromByteArrayUnsigned(valueBuffer);
5427 },
5428 /**
5429 * Format a Bitcoin value as a string.
5430 *
5431 * Takes a BigInteger or byte-array and returns that amount of Bitcoins in a
5432 * nice standard formatting.
5433 *
5434 * Examples:
5435 * 12.3555
5436 * 0.1234
5437 * 900.99998888
5438 * 34.00
5439 */
5440 formatValue: function (valueBuffer) {
5441 var value = this.valueToBigInt(valueBuffer).toString();
5442 var integerPart = value.length > 8 ? value.substr(0, value.length - 8) : '0';
5443 var decimalPart = value.length > 8 ? value.substr(value.length - 8) : value;
5444 while (decimalPart.length < 8) decimalPart = "0" + decimalPart;
5445 decimalPart = decimalPart.replace(/0*$/, '');
5446 while (decimalPart.length < 2) decimalPart += "0";
5447 return integerPart + "." + decimalPart;
5448 },
5449 /**
5450 * Parse a floating point string as a Bitcoin value.
5451 *
5452 * Keep in mind that parsing user input is messy. You should always display
5453 * the parsed value back to the user to make sure we understood his input
5454 * correctly.
5455 */
5456 parseValue: function (valueString) {
5457 // TODO: Detect other number formats (e.g. comma as decimal separator)
5458 var valueComp = valueString.split('.');
5459 var integralPart = valueComp[0];
5460 var fractionalPart = valueComp[1] || "0";
5461 while (fractionalPart.length < 8) fractionalPart += "0";
5462 fractionalPart = fractionalPart.replace(/^0+/g, '');
5463 var value = BigInteger.valueOf(parseInt(integralPart));
5464 value = value.multiply(BigInteger.valueOf(100000000));
5465 value = value.add(BigInteger.valueOf(parseInt(fractionalPart)));
5466 return value;
5467 },
5468 /**
5469 * Calculate RIPEMD160(SHA256(data)).
5470 *
5471 * Takes an arbitrary byte array as inputs and returns the hash as a byte
5472 * array.
5473 */
5474 sha256ripe160: function (data) {
5475 return Crypto.RIPEMD160(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
5476 },
5477 // double sha256
5478 dsha256: function (data) {
5479 return Crypto.SHA256(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
5480 }
5481};
5482 </script>
5483 <script type="text/javascript">
5484/*
5485* Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
5486*
5487* Permission is hereby granted, free of charge, to any person obtaining a copy
5488* of this software and associated documentation files (the "Software"), to deal
5489* in the Software without restriction, including without limitation the rights
5490* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5491* copies of the Software, and to permit persons to whom the Software is
5492* furnished to do so, subject to the following conditions:
5493*
5494* The above copyright notice and this permission notice shall be included in
5495* all copies or substantial portions of the Software.
5496*
5497* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5498* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5499* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5500* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5501* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5502* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5503* THE SOFTWARE.
5504*/
5505// https://github.com/cheongwy/node-scrypt-js
5506(function () {
5507
5508 var MAX_VALUE = 2147483647;
5509 var workerUrl = null;
5510
5511 //function scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen)
5512 /*
5513 * N = Cpu cost
5514 * r = Memory cost
5515 * p = parallelization cost
5516 *
5517 */
5518 window.Crypto_scrypt = function (passwd, salt, N, r, p, dkLen, callback) {
5519 if (N == 0 || (N & (N - 1)) != 0) throw Error("N must be > 0 and a power of 2");
5520
5521 if (N > MAX_VALUE / 128 / r) throw Error("Parameter N is too large");
5522 if (r > MAX_VALUE / 128 / p) throw Error("Parameter r is too large");
5523
5524 var PBKDF2_opts = { iterations: 1, hasher: Crypto.SHA256, asBytes: true };
5525
5526 var B = Crypto.PBKDF2(passwd, salt, p * 128 * r, PBKDF2_opts);
5527
5528 try {
5529 var i = 0;
5530 var worksDone = 0;
5531 var makeWorker = function () {
5532 if (!workerUrl) {
5533 var code = '(' + scryptCore.toString() + ')()';
5534 var blob;
5535 try {
5536 blob = new Blob([code], { type: "text/javascript" });
5537 } catch (e) {
5538 window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
5539 blob = new BlobBuilder();
5540 blob.append(code);
5541 blob = blob.getBlob("text/javascript");
5542 }
5543 workerUrl = URL.createObjectURL(blob);
5544 }
5545 var worker = new Worker(workerUrl);
5546 worker.onmessage = function (event) {
5547 var Bi = event.data[0], Bslice = event.data[1];
5548 worksDone++;
5549
5550 if (i < p) {
5551 worker.postMessage([N, r, p, B, i++]);
5552 }
5553
5554 var length = Bslice.length, destPos = Bi * 128 * r, srcPos = 0;
5555 while (length--) {
5556 B[destPos++] = Bslice[srcPos++];
5557 }
5558
5559 if (worksDone == p) {
5560 callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
5561 }
5562 };
5563 return worker;
5564 };
5565 var workers = [makeWorker(), makeWorker()];
5566 workers[0].postMessage([N, r, p, B, i++]);
5567 if (p > 1) {
5568 workers[1].postMessage([N, r, p, B, i++]);
5569 }
5570 } catch (e) {
5571 window.setTimeout(function () {
5572 scryptCore();
5573 callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
5574 }, 0);
5575 }
5576
5577 // using this function to enclose everything needed to create a worker (but also invokable directly for synchronous use)
5578 function scryptCore() {
5579 var XY = [], V = [];
5580
5581 if (typeof B === 'undefined') {
5582 onmessage = function (event) {
5583 var data = event.data;
5584 var N = data[0], r = data[1], p = data[2], B = data[3], i = data[4];
5585
5586 var Bslice = [];
5587 arraycopy32(B, i * 128 * r, Bslice, 0, 128 * r);
5588 smix(Bslice, 0, r, N, V, XY);
5589
5590 postMessage([i, Bslice]);
5591 };
5592 } else {
5593 for (var i = 0; i < p; i++) {
5594 smix(B, i * 128 * r, r, N, V, XY);
5595 }
5596 }
5597
5598 function smix(B, Bi, r, N, V, XY) {
5599 var Xi = 0;
5600 var Yi = 128 * r;
5601 var i;
5602
5603 arraycopy32(B, Bi, XY, Xi, Yi);
5604
5605 for (i = 0; i < N; i++) {
5606 arraycopy32(XY, Xi, V, i * Yi, Yi);
5607 blockmix_salsa8(XY, Xi, Yi, r);
5608 }
5609
5610 for (i = 0; i < N; i++) {
5611 var j = integerify(XY, Xi, r) & (N - 1);
5612 blockxor(V, j * Yi, XY, Xi, Yi);
5613 blockmix_salsa8(XY, Xi, Yi, r);
5614 }
5615
5616 arraycopy32(XY, Xi, B, Bi, Yi);
5617 }
5618
5619 function blockmix_salsa8(BY, Bi, Yi, r) {
5620 var X = [];
5621 var i;
5622
5623 arraycopy32(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
5624
5625 for (i = 0; i < 2 * r; i++) {
5626 blockxor(BY, i * 64, X, 0, 64);
5627 salsa20_8(X);
5628 arraycopy32(X, 0, BY, Yi + (i * 64), 64);
5629 }
5630
5631 for (i = 0; i < r; i++) {
5632 arraycopy32(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
5633 }
5634
5635 for (i = 0; i < r; i++) {
5636 arraycopy32(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
5637 }
5638 }
5639
5640 function R(a, b) {
5641 return (a << b) | (a >>> (32 - b));
5642 }
5643
5644 function salsa20_8(B) {
5645 var B32 = new Array(32);
5646 var x = new Array(32);
5647 var i;
5648
5649 for (i = 0; i < 16; i++) {
5650 B32[i] = (B[i * 4 + 0] & 0xff) << 0;
5651 B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
5652 B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
5653 B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
5654 }
5655
5656 arraycopy(B32, 0, x, 0, 16);
5657
5658 for (i = 8; i > 0; i -= 2) {
5659 x[4] ^= R(x[0] + x[12], 7); x[8] ^= R(x[4] + x[0], 9);
5660 x[12] ^= R(x[8] + x[4], 13); x[0] ^= R(x[12] + x[8], 18);
5661 x[9] ^= R(x[5] + x[1], 7); x[13] ^= R(x[9] + x[5], 9);
5662 x[1] ^= R(x[13] + x[9], 13); x[5] ^= R(x[1] + x[13], 18);
5663 x[14] ^= R(x[10] + x[6], 7); x[2] ^= R(x[14] + x[10], 9);
5664 x[6] ^= R(x[2] + x[14], 13); x[10] ^= R(x[6] + x[2], 18);
5665 x[3] ^= R(x[15] + x[11], 7); x[7] ^= R(x[3] + x[15], 9);
5666 x[11] ^= R(x[7] + x[3], 13); x[15] ^= R(x[11] + x[7], 18);
5667 x[1] ^= R(x[0] + x[3], 7); x[2] ^= R(x[1] + x[0], 9);
5668 x[3] ^= R(x[2] + x[1], 13); x[0] ^= R(x[3] + x[2], 18);
5669 x[6] ^= R(x[5] + x[4], 7); x[7] ^= R(x[6] + x[5], 9);
5670 x[4] ^= R(x[7] + x[6], 13); x[5] ^= R(x[4] + x[7], 18);
5671 x[11] ^= R(x[10] + x[9], 7); x[8] ^= R(x[11] + x[10], 9);
5672 x[9] ^= R(x[8] + x[11], 13); x[10] ^= R(x[9] + x[8], 18);
5673 x[12] ^= R(x[15] + x[14], 7); x[13] ^= R(x[12] + x[15], 9);
5674 x[14] ^= R(x[13] + x[12], 13); x[15] ^= R(x[14] + x[13], 18);
5675 }
5676
5677 for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
5678
5679 for (i = 0; i < 16; i++) {
5680 var bi = i * 4;
5681 B[bi + 0] = (B32[i] >> 0 & 0xff);
5682 B[bi + 1] = (B32[i] >> 8 & 0xff);
5683 B[bi + 2] = (B32[i] >> 16 & 0xff);
5684 B[bi + 3] = (B32[i] >> 24 & 0xff);
5685 }
5686 }
5687
5688 function blockxor(S, Si, D, Di, len) {
5689 var i = len >> 6;
5690 while (i--) {
5691 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5692 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5693 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5694 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5695
5696 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5697 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5698 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5699 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5700
5701 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5702 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5703 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5704 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5705
5706 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5707 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5708 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5709 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5710
5711 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5712 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5713 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5714 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5715
5716 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5717 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5718 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5719 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5720
5721 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5722 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5723 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5724 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5725
5726 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5727 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5728 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5729 D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
5730 }
5731 }
5732
5733 function integerify(B, bi, r) {
5734 var n;
5735
5736 bi += (2 * r - 1) * 64;
5737
5738 n = (B[bi + 0] & 0xff) << 0;
5739 n |= (B[bi + 1] & 0xff) << 8;
5740 n |= (B[bi + 2] & 0xff) << 16;
5741 n |= (B[bi + 3] & 0xff) << 24;
5742
5743 return n;
5744 }
5745
5746 function arraycopy(src, srcPos, dest, destPos, length) {
5747 while (length--) {
5748 dest[destPos++] = src[srcPos++];
5749 }
5750 }
5751
5752 function arraycopy32(src, srcPos, dest, destPos, length) {
5753 var i = length >> 5;
5754 while (i--) {
5755 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5756 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5757 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5758 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5759
5760 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5761 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5762 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5763 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5764
5765 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5766 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5767 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5768 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5769
5770 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5771 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5772 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5773 dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
5774 }
5775 }
5776 } // scryptCore
5777 }; // window.Crypto_scrypt
5778})();
5779 </script>
5780 <script type="text/javascript">
5781/*
5782 Ported to JavaScript by Lazar Laszlo 2011
5783
5784 lazarsoft@gmail.com, www.lazarsoft.info
5785
5786*/
5787
5788/*
5789*
5790* Copyright 2007 ZXing authors
5791*
5792* Licensed under the Apache License, Version 2.0 (the "License");
5793* you may not use this file except in compliance with the License.
5794* You may obtain a copy of the License at
5795*
5796* http://www.apache.org/licenses/LICENSE-2.0
5797*
5798* Unless required by applicable law or agreed to in writing, software
5799* distributed under the License is distributed on an "AS IS" BASIS,
5800* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5801* See the License for the specific language governing permissions and
5802* limitations under the License.
5803*/
5804
5805GridSampler = {};
5806
5807GridSampler.checkAndNudgePoints=function( image, points)
5808 {
5809 var width = qrcode.width;
5810 var height = qrcode.height;
5811 // Check and nudge points from start until we see some that are OK:
5812 var nudged = true;
5813 for (var offset = 0; offset < points.length && nudged; offset += 2)
5814 {
5815 var x = Math.floor (points[offset]);
5816 var y = Math.floor( points[offset + 1]);
5817 if (x < - 1 || x > width || y < - 1 || y > height)
5818 {
5819 throw "Error.checkAndNudgePoints ";
5820 }
5821 nudged = false;
5822 if (x == - 1)
5823 {
5824 points[offset] = 0.0;
5825 nudged = true;
5826 }
5827 else if (x == width)
5828 {
5829 points[offset] = width - 1;
5830 nudged = true;
5831 }
5832 if (y == - 1)
5833 {
5834 points[offset + 1] = 0.0;
5835 nudged = true;
5836 }
5837 else if (y == height)
5838 {
5839 points[offset + 1] = height - 1;
5840 nudged = true;
5841 }
5842 }
5843 // Check and nudge points from end:
5844 nudged = true;
5845 for (var offset = points.length - 2; offset >= 0 && nudged; offset -= 2)
5846 {
5847 var x = Math.floor( points[offset]);
5848 var y = Math.floor( points[offset + 1]);
5849 if (x < - 1 || x > width || y < - 1 || y > height)
5850 {
5851 throw "Error.checkAndNudgePoints ";
5852 }
5853 nudged = false;
5854 if (x == - 1)
5855 {
5856 points[offset] = 0.0;
5857 nudged = true;
5858 }
5859 else if (x == width)
5860 {
5861 points[offset] = width - 1;
5862 nudged = true;
5863 }
5864 if (y == - 1)
5865 {
5866 points[offset + 1] = 0.0;
5867 nudged = true;
5868 }
5869 else if (y == height)
5870 {
5871 points[offset + 1] = height - 1;
5872 nudged = true;
5873 }
5874 }
5875 }
5876
5877
5878
5879GridSampler.sampleGrid3=function( image, dimension, transform)
5880 {
5881 var bits = new BitMatrix(dimension);
5882 var points = new Array(dimension << 1);
5883 for (var y = 0; y < dimension; y++)
5884 {
5885 var max = points.length;
5886 var iValue = y + 0.5;
5887 for (var x = 0; x < max; x += 2)
5888 {
5889 points[x] = (x >> 1) + 0.5;
5890 points[x + 1] = iValue;
5891 }
5892 transform.transformPoints1(points);
5893 // Quick check to see if points transformed to something inside the image;
5894 // sufficient to check the endpoints
5895 GridSampler.checkAndNudgePoints(image, points);
5896 try
5897 {
5898 for (var x = 0; x < max; x += 2)
5899 {
5900 var xpoint = (Math.floor( points[x]) * 4) + (Math.floor( points[x + 1]) * qrcode.width * 4);
5901 var bit = image[Math.floor( points[x])+ qrcode.width* Math.floor( points[x + 1])];
5902 qrcode.imagedata.data[xpoint] = bit?255:0;
5903 qrcode.imagedata.data[xpoint+1] = bit?255:0;
5904 qrcode.imagedata.data[xpoint+2] = 0;
5905 qrcode.imagedata.data[xpoint+3] = 255;
5906 //bits[x >> 1][ y]=bit;
5907 if(bit)
5908 bits.set_Renamed(x >> 1, y);
5909 }
5910 }
5911 catch ( aioobe)
5912 {
5913 // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
5914 // transform gets "twisted" such that it maps a straight line of points to a set of points
5915 // whose endpoints are in bounds, but others are not. There is probably some mathematical
5916 // way to detect this about the transformation that I don't know yet.
5917 // This results in an ugly runtime exception despite our clever checks above -- can't have
5918 // that. We could check each point's coordinates but that feels duplicative. We settle for
5919 // catching and wrapping ArrayIndexOutOfBoundsException.
5920 throw "Error.checkAndNudgePoints";
5921 }
5922 }
5923 return bits;
5924 }
5925
5926GridSampler.sampleGridx=function( image, dimension, p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY)
5927{
5928 var transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
5929
5930 return GridSampler.sampleGrid3(image, dimension, transform);
5931}
5932
5933function ECB(count, dataCodewords)
5934{
5935 this.count = count;
5936 this.dataCodewords = dataCodewords;
5937
5938 this.__defineGetter__("Count", function()
5939 {
5940 return this.count;
5941 });
5942 this.__defineGetter__("DataCodewords", function()
5943 {
5944 return this.dataCodewords;
5945 });
5946}
5947
5948function ECBlocks( ecCodewordsPerBlock, ecBlocks1, ecBlocks2)
5949{
5950 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
5951 if(ecBlocks2)
5952 this.ecBlocks = new Array(ecBlocks1, ecBlocks2);
5953 else
5954 this.ecBlocks = new Array(ecBlocks1);
5955
5956 this.__defineGetter__("ECCodewordsPerBlock", function()
5957 {
5958 return this.ecCodewordsPerBlock;
5959 });
5960
5961 this.__defineGetter__("TotalECCodewords", function()
5962 {
5963 return this.ecCodewordsPerBlock * this.NumBlocks;
5964 });
5965
5966 this.__defineGetter__("NumBlocks", function()
5967 {
5968 var total = 0;
5969 for (var i = 0; i < this.ecBlocks.length; i++)
5970 {
5971 total += this.ecBlocks[i].length;
5972 }
5973 return total;
5974 });
5975
5976 this.getECBlocks=function()
5977 {
5978 return this.ecBlocks;
5979 }
5980}
5981
5982function Version( versionNumber, alignmentPatternCenters, ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4)
5983{
5984 this.versionNumber = versionNumber;
5985 this.alignmentPatternCenters = alignmentPatternCenters;
5986 this.ecBlocks = new Array(ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4);
5987
5988 var total = 0;
5989 var ecCodewords = ecBlocks1.ECCodewordsPerBlock;
5990 var ecbArray = ecBlocks1.getECBlocks();
5991 for (var i = 0; i < ecbArray.length; i++)
5992 {
5993 var ecBlock = ecbArray[i];
5994 total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
5995 }
5996 this.totalCodewords = total;
5997
5998 this.__defineGetter__("VersionNumber", function()
5999 {
6000 return this.versionNumber;
6001 });
6002
6003 this.__defineGetter__("AlignmentPatternCenters", function()
6004 {
6005 return this.alignmentPatternCenters;
6006 });
6007 this.__defineGetter__("TotalCodewords", function()
6008 {
6009 return this.totalCodewords;
6010 });
6011 this.__defineGetter__("DimensionForVersion", function()
6012 {
6013 return 17 + 4 * this.versionNumber;
6014 });
6015
6016 this.buildFunctionPattern=function()
6017 {
6018 var dimension = this.DimensionForVersion;
6019 var bitMatrix = new BitMatrix(dimension);
6020
6021 // Top left finder pattern + separator + format
6022 bitMatrix.setRegion(0, 0, 9, 9);
6023 // Top right finder pattern + separator + format
6024 bitMatrix.setRegion(dimension - 8, 0, 8, 9);
6025 // Bottom left finder pattern + separator + format
6026 bitMatrix.setRegion(0, dimension - 8, 9, 8);
6027
6028 // Alignment patterns
6029 var max = this.alignmentPatternCenters.length;
6030 for (var x = 0; x < max; x++)
6031 {
6032 var i = this.alignmentPatternCenters[x] - 2;
6033 for (var y = 0; y < max; y++)
6034 {
6035 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
6036 {
6037 // No alignment patterns near the three finder paterns
6038 continue;
6039 }
6040 bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5);
6041 }
6042 }
6043
6044 // Vertical timing pattern
6045 bitMatrix.setRegion(6, 9, 1, dimension - 17);
6046 // Horizontal timing pattern
6047 bitMatrix.setRegion(9, 6, dimension - 17, 1);
6048
6049 if (this.versionNumber > 6)
6050 {
6051 // Version info, top right
6052 bitMatrix.setRegion(dimension - 11, 0, 3, 6);
6053 // Version info, bottom left
6054 bitMatrix.setRegion(0, dimension - 11, 6, 3);
6055 }
6056
6057 return bitMatrix;
6058 }
6059 this.getECBlocksForLevel=function( ecLevel)
6060 {
6061 return this.ecBlocks[ecLevel.ordinal()];
6062 }
6063}
6064
6065Version.VERSION_DECODE_INFO = new Array(0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69);
6066
6067Version.VERSIONS = buildVersions();
6068
6069Version.getVersionForNumber=function( versionNumber)
6070{
6071 if (versionNumber < 1 || versionNumber > 40)
6072 {
6073 throw "ArgumentException";
6074 }
6075 return Version.VERSIONS[versionNumber - 1];
6076}
6077
6078Version.getProvisionalVersionForDimension=function(dimension)
6079{
6080 if (dimension % 4 != 1)
6081 {
6082 throw "Error getProvisionalVersionForDimension";
6083 }
6084 try
6085 {
6086 return Version.getVersionForNumber((dimension - 17) >> 2);
6087 }
6088 catch ( iae)
6089 {
6090 throw "Error getVersionForNumber";
6091 }
6092}
6093
6094Version.decodeVersionInformation=function( versionBits)
6095{
6096 var bestDifference = 0xffffffff;
6097 var bestVersion = 0;
6098 for (var i = 0; i < Version.VERSION_DECODE_INFO.length; i++)
6099 {
6100 var targetVersion = Version.VERSION_DECODE_INFO[i];
6101 // Do the version info bits match exactly? done.
6102 if (targetVersion == versionBits)
6103 {
6104 return this.getVersionForNumber(i + 7);
6105 }
6106 // Otherwise see if this is the closest to a real version info bit string
6107 // we have seen so far
6108 var bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
6109 if (bitsDifference < bestDifference)
6110 {
6111 bestVersion = i + 7;
6112 bestDifference = bitsDifference;
6113 }
6114 }
6115 // We can tolerate up to 3 bits of error since no two version info codewords will
6116 // differ in less than 4 bits.
6117 if (bestDifference <= 3)
6118 {
6119 return this.getVersionForNumber(bestVersion);
6120 }
6121 // If we didn't find a close enough match, fail
6122 return null;
6123}
6124
6125function buildVersions()
6126{
6127 return new Array(new Version(1, new Array(), new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))),
6128 new Version(2, new Array(6, 18), new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))),
6129 new Version(3, new Array(6, 22), new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))),
6130 new Version(4, new Array(6, 26), new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))),
6131 new Version(5, new Array(6, 30), new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))),
6132 new Version(6, new Array(6, 34), new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))),
6133 new Version(7, new Array(6, 22, 38), new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))),
6134 new Version(8, new Array(6, 24, 42), new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))),
6135 new Version(9, new Array(6, 26, 46), new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))),
6136 new Version(10, new Array(6, 28, 50), new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))),
6137 new Version(11, new Array(6, 30, 54), new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))),
6138 new Version(12, new Array(6, 32, 58), new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))),
6139 new Version(13, new Array(6, 34, 62), new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))),
6140 new Version(14, new Array(6, 26, 46, 66), new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))),
6141 new Version(15, new Array(6, 26, 48, 70), new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))),
6142 new Version(16, new Array(6, 26, 50, 74), new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))),
6143 new Version(17, new Array(6, 30, 54, 78), new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))),
6144 new Version(18, new Array(6, 30, 56, 82), new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))),
6145 new Version(19, new Array(6, 30, 58, 86), new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))),
6146 new Version(20, new Array(6, 34, 62, 90), new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))),
6147 new Version(21, new Array(6, 28, 50, 72, 94), new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))),
6148 new Version(22, new Array(6, 26, 50, 74, 98), new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))),
6149 new Version(23, new Array(6, 30, 54, 74, 102), new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))),
6150 new Version(24, new Array(6, 28, 54, 80, 106), new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))),
6151 new Version(25, new Array(6, 32, 58, 84, 110), new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))),
6152 new Version(26, new Array(6, 30, 58, 86, 114), new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))),
6153 new Version(27, new Array(6, 34, 62, 90, 118), new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))),
6154 new Version(28, new Array(6, 26, 50, 74, 98, 122), new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))),
6155 new Version(29, new Array(6, 30, 54, 78, 102, 126), new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))),
6156 new Version(30, new Array(6, 26, 52, 78, 104, 130), new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))),
6157 new Version(31, new Array(6, 30, 56, 82, 108, 134), new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))),
6158 new Version(32, new Array(6, 34, 60, 86, 112, 138), new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))),
6159 new Version(33, new Array(6, 30, 58, 86, 114, 142), new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))),
6160 new Version(34, new Array(6, 34, 62, 90, 118, 146), new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))),
6161 new Version(35, new Array(6, 30, 54, 78, 102, 126, 150), new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)),new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))),
6162 new Version(36, new Array(6, 24, 50, 76, 102, 128, 154), new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))),
6163 new Version(37, new Array(6, 28, 54, 80, 106, 132, 158), new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))),
6164 new Version(38, new Array(6, 32, 58, 84, 110, 136, 162), new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))),
6165 new Version(39, new Array(6, 26, 54, 82, 110, 138, 166), new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))),
6166 new Version(40, new Array(6, 30, 58, 86, 114, 142, 170), new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16))));
6167}
6168
6169function PerspectiveTransform( a11, a21, a31, a12, a22, a32, a13, a23, a33)
6170{
6171 this.a11 = a11;
6172 this.a12 = a12;
6173 this.a13 = a13;
6174 this.a21 = a21;
6175 this.a22 = a22;
6176 this.a23 = a23;
6177 this.a31 = a31;
6178 this.a32 = a32;
6179 this.a33 = a33;
6180 this.transformPoints1=function( points)
6181 {
6182 var max = points.length;
6183 var a11 = this.a11;
6184 var a12 = this.a12;
6185 var a13 = this.a13;
6186 var a21 = this.a21;
6187 var a22 = this.a22;
6188 var a23 = this.a23;
6189 var a31 = this.a31;
6190 var a32 = this.a32;
6191 var a33 = this.a33;
6192 for (var i = 0; i < max; i += 2)
6193 {
6194 var x = points[i];
6195 var y = points[i + 1];
6196 var denominator = a13 * x + a23 * y + a33;
6197 points[i] = (a11 * x + a21 * y + a31) / denominator;
6198 points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
6199 }
6200 }
6201 this. transformPoints2=function(xValues, yValues)
6202 {
6203 var n = xValues.length;
6204 for (var i = 0; i < n; i++)
6205 {
6206 var x = xValues[i];
6207 var y = yValues[i];
6208 var denominator = this.a13 * x + this.a23 * y + this.a33;
6209 xValues[i] = (this.a11 * x + this.a21 * y + this.a31) / denominator;
6210 yValues[i] = (this.a12 * x + this.a22 * y + this.a32) / denominator;
6211 }
6212 }
6213
6214 this.buildAdjoint=function()
6215 {
6216 // Adjoint is the transpose of the cofactor matrix:
6217 return new PerspectiveTransform(this.a22 * this.a33 - this.a23 * this.a32, this.a23 * this.a31 - this.a21 * this.a33, this.a21 * this.a32 - this.a22 * this.a31, this.a13 * this.a32 - this.a12 * this.a33, this.a11 * this.a33 - this.a13 * this.a31, this.a12 * this.a31 - this.a11 * this.a32, this.a12 * this.a23 - this.a13 * this.a22, this.a13 * this.a21 - this.a11 * this.a23, this.a11 * this.a22 - this.a12 * this.a21);
6218 }
6219 this.times=function( other)
6220 {
6221 return new PerspectiveTransform(this.a11 * other.a11 + this.a21 * other.a12 + this.a31 * other.a13, this.a11 * other.a21 + this.a21 * other.a22 + this.a31 * other.a23, this.a11 * other.a31 + this.a21 * other.a32 + this.a31 * other.a33, this.a12 * other.a11 + this.a22 * other.a12 + this.a32 * other.a13, this.a12 * other.a21 + this.a22 * other.a22 + this.a32 * other.a23, this.a12 * other.a31 + this.a22 * other.a32 + this.a32 * other.a33, this.a13 * other.a11 + this.a23 * other.a12 +this.a33 * other.a13, this.a13 * other.a21 + this.a23 * other.a22 + this.a33 * other.a23, this.a13 * other.a31 + this.a23 * other.a32 + this.a33 * other.a33);
6222 }
6223
6224}
6225
6226PerspectiveTransform.quadrilateralToQuadrilateral=function( x0, y0, x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p)
6227{
6228
6229 var qToS = this.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
6230 var sToQ = this.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
6231 return sToQ.times(qToS);
6232}
6233
6234PerspectiveTransform.squareToQuadrilateral=function( x0, y0, x1, y1, x2, y2, x3, y3)
6235{
6236 dy2 = y3 - y2;
6237 dy3 = y0 - y1 + y2 - y3;
6238 if (dy2 == 0.0 && dy3 == 0.0)
6239 {
6240 return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0, 0.0, 1.0);
6241 }
6242 else
6243 {
6244 dx1 = x1 - x2;
6245 dx2 = x3 - x2;
6246 dx3 = x0 - x1 + x2 - x3;
6247 dy1 = y1 - y2;
6248 denominator = dx1 * dy2 - dx2 * dy1;
6249 a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
6250 a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
6251 return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0);
6252 }
6253}
6254
6255PerspectiveTransform.quadrilateralToSquare=function( x0, y0, x1, y1, x2, y2, x3, y3)
6256{
6257 // Here, the adjoint serves as the inverse:
6258 return this.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
6259}
6260
6261function DetectorResult(bits, points)
6262{
6263 this.bits = bits;
6264 this.points = points;
6265}
6266
6267
6268function Detector(image)
6269{
6270 this.image=image;
6271 this.resultPointCallback = null;
6272
6273 this.sizeOfBlackWhiteBlackRun=function( fromX, fromY, toX, toY)
6274 {
6275 // Mild variant of Bresenham's algorithm;
6276 // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
6277 var steep = Math.abs(toY - fromY) > Math.abs(toX - fromX);
6278 if (steep)
6279 {
6280 var temp = fromX;
6281 fromX = fromY;
6282 fromY = temp;
6283 temp = toX;
6284 toX = toY;
6285 toY = temp;
6286 }
6287
6288 var dx = Math.abs(toX - fromX);
6289 var dy = Math.abs(toY - fromY);
6290 var error = - dx >> 1;
6291 var ystep = fromY < toY?1:- 1;
6292 var xstep = fromX < toX?1:- 1;
6293 var state = 0; // In black pixels, looking for white, first or second time
6294 for (var x = fromX, y = fromY; x != toX; x += xstep)
6295 {
6296
6297 var realX = steep?y:x;
6298 var realY = steep?x:y;
6299 if (state == 1)
6300 {
6301 // In white pixels, looking for black
6302 if (this.image[realX + realY*qrcode.width])
6303 {
6304 state++;
6305 }
6306 }
6307 else
6308 {
6309 if (!this.image[realX + realY*qrcode.width])
6310 {
6311 state++;
6312 }
6313 }
6314
6315 if (state == 3)
6316 {
6317 // Found black, white, black, and stumbled back onto white; done
6318 var diffX = x - fromX;
6319 var diffY = y - fromY;
6320 return Math.sqrt( (diffX * diffX + diffY * diffY));
6321 }
6322 error += dy;
6323 if (error > 0)
6324 {
6325 if (y == toY)
6326 {
6327 break;
6328 }
6329 y += ystep;
6330 error -= dx;
6331 }
6332 }
6333 var diffX2 = toX - fromX;
6334 var diffY2 = toY - fromY;
6335 return Math.sqrt( (diffX2 * diffX2 + diffY2 * diffY2));
6336 }
6337
6338
6339 this.sizeOfBlackWhiteBlackRunBothWays=function( fromX, fromY, toX, toY)
6340 {
6341
6342 var result = this.sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
6343
6344 // Now count other way -- don't run off image though of course
6345 var scale = 1.0;
6346 var otherToX = fromX - (toX - fromX);
6347 if (otherToX < 0)
6348 {
6349 scale = fromX / (fromX - otherToX);
6350 otherToX = 0;
6351 }
6352 else if (otherToX >= qrcode.width)
6353 {
6354 scale = (qrcode.width - 1 - fromX) / (otherToX - fromX);
6355 otherToX = qrcode.width - 1;
6356 }
6357 var otherToY = Math.floor (fromY - (toY - fromY) * scale);
6358
6359 scale = 1.0;
6360 if (otherToY < 0)
6361 {
6362 scale = fromY / (fromY - otherToY);
6363 otherToY = 0;
6364 }
6365 else if (otherToY >= qrcode.height)
6366 {
6367 scale = (qrcode.height - 1 - fromY) / (otherToY - fromY);
6368 otherToY = qrcode.height - 1;
6369 }
6370 otherToX = Math.floor (fromX + (otherToX - fromX) * scale);
6371
6372 result += this.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
6373 return result - 1.0; // -1 because we counted the middle pixel twice
6374 }
6375
6376
6377
6378 this.calculateModuleSizeOneWay=function( pattern, otherPattern)
6379 {
6380 var moduleSizeEst1 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor( pattern.X), Math.floor( pattern.Y), Math.floor( otherPattern.X), Math.floor(otherPattern.Y));
6381 var moduleSizeEst2 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(otherPattern.X), Math.floor(otherPattern.Y), Math.floor( pattern.X), Math.floor(pattern.Y));
6382 if (isNaN(moduleSizeEst1))
6383 {
6384 return moduleSizeEst2 / 7.0;
6385 }
6386 if (isNaN(moduleSizeEst2))
6387 {
6388 return moduleSizeEst1 / 7.0;
6389 }
6390 // Average them, and divide by 7 since we've counted the width of 3 black modules,
6391 // and 1 white and 1 black module on either side. Ergo, divide sum by 14.
6392 return (moduleSizeEst1 + moduleSizeEst2) / 14.0;
6393 }
6394
6395
6396 this.calculateModuleSize=function( topLeft, topRight, bottomLeft)
6397 {
6398 // Take the average
6399 return (this.calculateModuleSizeOneWay(topLeft, topRight) + this.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0;
6400 }
6401
6402 this.distance=function( pattern1, pattern2)
6403 {
6404 xDiff = pattern1.X - pattern2.X;
6405 yDiff = pattern1.Y - pattern2.Y;
6406 return Math.sqrt( (xDiff * xDiff + yDiff * yDiff));
6407 }
6408 this.computeDimension=function( topLeft, topRight, bottomLeft, moduleSize)
6409 {
6410
6411 var tltrCentersDimension = Math.round(this.distance(topLeft, topRight) / moduleSize);
6412 var tlblCentersDimension = Math.round(this.distance(topLeft, bottomLeft) / moduleSize);
6413 var dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
6414 switch (dimension & 0x03)
6415 {
6416
6417 // mod 4
6418 case 0:
6419 dimension++;
6420 break;
6421 // 1? do nothing
6422
6423 case 2:
6424 dimension--;
6425 break;
6426
6427 case 3:
6428 throw "Error";
6429 }
6430 return dimension;
6431 }
6432
6433 this.findAlignmentInRegion=function( overallEstModuleSize, estAlignmentX, estAlignmentY, allowanceFactor)
6434 {
6435 // Look for an alignment pattern (3 modules in size) around where it
6436 // should be
6437 var allowance = Math.floor (allowanceFactor * overallEstModuleSize);
6438 var alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance);
6439 var alignmentAreaRightX = Math.min(qrcode.width - 1, estAlignmentX + allowance);
6440 if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3)
6441 {
6442 throw "Error";
6443 }
6444
6445 var alignmentAreaTopY = Math.max(0, estAlignmentY - allowance);
6446 var alignmentAreaBottomY = Math.min(qrcode.height - 1, estAlignmentY + allowance);
6447
6448 var alignmentFinder = new AlignmentPatternFinder(this.image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, this.resultPointCallback);
6449 return alignmentFinder.find();
6450 }
6451
6452 this.createTransform=function( topLeft, topRight, bottomLeft, alignmentPattern, dimension)
6453 {
6454 var dimMinusThree = dimension - 3.5;
6455 var bottomRightX;
6456 var bottomRightY;
6457 var sourceBottomRightX;
6458 var sourceBottomRightY;
6459 if (alignmentPattern != null)
6460 {
6461 bottomRightX = alignmentPattern.X;
6462 bottomRightY = alignmentPattern.Y;
6463 sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0;
6464 }
6465 else
6466 {
6467 // Don't have an alignment pattern, just make up the bottom-right point
6468 bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X;
6469 bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y;
6470 sourceBottomRightX = sourceBottomRightY = dimMinusThree;
6471 }
6472
6473 var transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y);
6474
6475 return transform;
6476 }
6477
6478 this.sampleGrid=function( image, transform, dimension)
6479 {
6480
6481 var sampler = GridSampler;
6482 return sampler.sampleGrid3(image, dimension, transform);
6483 }
6484
6485 this.processFinderPatternInfo = function( info)
6486 {
6487
6488 var topLeft = info.TopLeft;
6489 var topRight = info.TopRight;
6490 var bottomLeft = info.BottomLeft;
6491
6492 var moduleSize = this.calculateModuleSize(topLeft, topRight, bottomLeft);
6493 if (moduleSize < 1.0)
6494 {
6495 throw "Error";
6496 }
6497 var dimension = this.computeDimension(topLeft, topRight, bottomLeft, moduleSize);
6498 var provisionalVersion = Version.getProvisionalVersionForDimension(dimension);
6499 var modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7;
6500
6501 var alignmentPattern = null;
6502 // Anything above version 1 has an alignment pattern
6503 if (provisionalVersion.AlignmentPatternCenters.length > 0)
6504 {
6505
6506 // Guess where a "bottom right" finder pattern would have been
6507 var bottomRightX = topRight.X - topLeft.X + bottomLeft.X;
6508 var bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y;
6509
6510 // Estimate that alignment pattern is closer by 3 modules
6511 // from "bottom right" to known top left location
6512 var correctionToTopLeft = 1.0 - 3.0 / modulesBetweenFPCenters;
6513 var estAlignmentX = Math.floor (topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X));
6514 var estAlignmentY = Math.floor (topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y));
6515
6516 // Kind of arbitrary -- expand search radius before giving up
6517 for (var i = 4; i <= 16; i <<= 1)
6518 {
6519 //try
6520 //{
6521 alignmentPattern = this.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i);
6522 break;
6523 //}
6524 //catch (re)
6525 //{
6526 // try next round
6527 //}
6528 }
6529 // If we didn't find alignment pattern... well try anyway without it
6530 }
6531
6532 var transform = this.createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
6533
6534 var bits = this.sampleGrid(this.image, transform, dimension);
6535
6536 var points;
6537 if (alignmentPattern == null)
6538 {
6539 points = new Array(bottomLeft, topLeft, topRight);
6540 }
6541 else
6542 {
6543 points = new Array(bottomLeft, topLeft, topRight, alignmentPattern);
6544 }
6545 return new DetectorResult(bits, points);
6546 }
6547
6548
6549
6550 this.detect=function()
6551 {
6552 var info = new FinderPatternFinder().findFinderPattern(this.image);
6553
6554 return this.processFinderPatternInfo(info);
6555 }
6556}
6557
6558var FORMAT_INFO_MASK_QR = 0x5412;
6559var FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(0x5412, 0x00), new Array(0x5125, 0x01), new Array(0x5E7C, 0x02), new Array(0x5B4B, 0x03), new Array(0x45F9, 0x04), new Array(0x40CE, 0x05), new Array(0x4F97, 0x06), new Array(0x4AA0, 0x07), new Array(0x77C4, 0x08), new Array(0x72F3, 0x09), new Array(0x7DAA, 0x0A), new Array(0x789D, 0x0B), new Array(0x662F, 0x0C), new Array(0x6318, 0x0D), new Array(0x6C41, 0x0E), new Array(0x6976, 0x0F), new Array(0x1689, 0x10), new Array(0x13BE, 0x11), new Array(0x1CE7, 0x12), new Array(0x19D0, 0x13), new Array(0x0762, 0x14), new Array(0x0255, 0x15), new Array(0x0D0C, 0x16), new Array(0x083B, 0x17), new Array(0x355F, 0x18), new Array(0x3068, 0x19), new Array(0x3F31, 0x1A), new Array(0x3A06, 0x1B), new Array(0x24B4, 0x1C), new Array(0x2183, 0x1D), new Array(0x2EDA, 0x1E), new Array(0x2BED, 0x1F));
6560var BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
6561
6562
6563function FormatInformation(formatInfo)
6564{
6565 this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
6566 this.dataMask = (formatInfo & 0x07);
6567
6568 this.__defineGetter__("ErrorCorrectionLevel", function()
6569 {
6570 return this.errorCorrectionLevel;
6571 });
6572 this.__defineGetter__("DataMask", function()
6573 {
6574 return this.dataMask;
6575 });
6576 this.GetHashCode=function()
6577 {
6578 return (this.errorCorrectionLevel.ordinal() << 3) | dataMask;
6579 }
6580 this.Equals=function( o)
6581 {
6582 var other = o;
6583 return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask;
6584 }
6585}
6586
6587FormatInformation.numBitsDiffering=function( a, b)
6588{
6589 a ^= b; // a now has a 1 bit exactly where its bit differs with b's
6590 // Count bits set quickly with a series of lookups:
6591 return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 28) & 0x0F)];
6592}
6593
6594FormatInformation.decodeFormatInformation=function( maskedFormatInfo)
6595{
6596 var formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo);
6597 if (formatInfo != null)
6598 {
6599 return formatInfo;
6600 }
6601 // Should return null, but, some QR codes apparently
6602 // do not mask this info. Try again by actually masking the pattern
6603 // first
6604 return FormatInformation.doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR);
6605}
6606FormatInformation.doDecodeFormatInformation=function( maskedFormatInfo)
6607{
6608 // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
6609 var bestDifference = 0xffffffff;
6610 var bestFormatInfo = 0;
6611 for (var i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++)
6612 {
6613 var decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
6614 var targetInfo = decodeInfo[0];
6615 if (targetInfo == maskedFormatInfo)
6616 {
6617 // Found an exact match
6618 return new FormatInformation(decodeInfo[1]);
6619 }
6620 var bitsDifference = this.numBitsDiffering(maskedFormatInfo, targetInfo);
6621 if (bitsDifference < bestDifference)
6622 {
6623 bestFormatInfo = decodeInfo[1];
6624 bestDifference = bitsDifference;
6625 }
6626 }
6627 // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
6628 // differing means we found a match
6629 if (bestDifference <= 3)
6630 {
6631 return new FormatInformation(bestFormatInfo);
6632 }
6633 return null;
6634}
6635
6636function ErrorCorrectionLevel(ordinal, bits, name)
6637{
6638 this.ordinal_Renamed_Field = ordinal;
6639 this.bits = bits;
6640 this.name = name;
6641 this.__defineGetter__("Bits", function()
6642 {
6643 return this.bits;
6644 });
6645 this.__defineGetter__("Name", function()
6646 {
6647 return this.name;
6648 });
6649 this.ordinal=function()
6650 {
6651 return this.ordinal_Renamed_Field;
6652 }
6653}
6654
6655ErrorCorrectionLevel.forBits=function( bits)
6656{
6657 if (bits < 0 || bits >= FOR_BITS.length)
6658 {
6659 throw "ArgumentException";
6660 }
6661 return FOR_BITS[bits];
6662}
6663
6664var L = new ErrorCorrectionLevel(0, 0x01, "L");
6665var M = new ErrorCorrectionLevel(1, 0x00, "M");
6666var Q = new ErrorCorrectionLevel(2, 0x03, "Q");
6667var H = new ErrorCorrectionLevel(3, 0x02, "H");
6668var FOR_BITS = new Array( M, L, H, Q);
6669
6670function BitMatrix( width, height)
6671{
6672 if(!height)
6673 height=width;
6674 if (width < 1 || height < 1)
6675 {
6676 throw "Both dimensions must be greater than 0";
6677 }
6678 this.width = width;
6679 this.height = height;
6680 var rowSize = width >> 5;
6681 if ((width & 0x1f) != 0)
6682 {
6683 rowSize++;
6684 }
6685 this.rowSize = rowSize;
6686 this.bits = new Array(rowSize * height);
6687 for(var i=0;i<this.bits.length;i++)
6688 this.bits[i]=0;
6689
6690 this.__defineGetter__("Width", function()
6691 {
6692 return this.width;
6693 });
6694 this.__defineGetter__("Height", function()
6695 {
6696 return this.height;
6697 });
6698 this.__defineGetter__("Dimension", function()
6699 {
6700 if (this.width != this.height)
6701 {
6702 throw "Can't call getDimension() on a non-square matrix";
6703 }
6704 return this.width;
6705 });
6706
6707 this.get_Renamed=function( x, y)
6708 {
6709 var offset = y * this.rowSize + (x >> 5);
6710 return ((URShift(this.bits[offset], (x & 0x1f))) & 1) != 0;
6711 }
6712 this.set_Renamed=function( x, y)
6713 {
6714 var offset = y * this.rowSize + (x >> 5);
6715 this.bits[offset] |= 1 << (x & 0x1f);
6716 }
6717 this.flip=function( x, y)
6718 {
6719 var offset = y * this.rowSize + (x >> 5);
6720 this.bits[offset] ^= 1 << (x & 0x1f);
6721 }
6722 this.clear=function()
6723 {
6724 var max = this.bits.length;
6725 for (var i = 0; i < max; i++)
6726 {
6727 this.bits[i] = 0;
6728 }
6729 }
6730 this.setRegion=function( left, top, width, height)
6731 {
6732 if (top < 0 || left < 0)
6733 {
6734 throw "Left and top must be nonnegative";
6735 }
6736 if (height < 1 || width < 1)
6737 {
6738 throw "Height and width must be at least 1";
6739 }
6740 var right = left + width;
6741 var bottom = top + height;
6742 if (bottom > this.height || right > this.width)
6743 {
6744 throw "The region must fit inside the matrix";
6745 }
6746 for (var y = top; y < bottom; y++)
6747 {
6748 var offset = y * this.rowSize;
6749 for (var x = left; x < right; x++)
6750 {
6751 this.bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
6752 }
6753 }
6754 }
6755}
6756
6757function DataBlock(numDataCodewords, codewords)
6758{
6759 this.numDataCodewords = numDataCodewords;
6760 this.codewords = codewords;
6761
6762 this.__defineGetter__("NumDataCodewords", function()
6763 {
6764 return this.numDataCodewords;
6765 });
6766 this.__defineGetter__("Codewords", function()
6767 {
6768 return this.codewords;
6769 });
6770}
6771
6772DataBlock.getDataBlocks=function(rawCodewords, version, ecLevel)
6773{
6774
6775 if (rawCodewords.length != version.TotalCodewords)
6776 {
6777 throw "ArgumentException";
6778 }
6779
6780 // Figure out the number and size of data blocks used by this version and
6781 // error correction level
6782 var ecBlocks = version.getECBlocksForLevel(ecLevel);
6783
6784 // First count the total number of data blocks
6785 var totalBlocks = 0;
6786 var ecBlockArray = ecBlocks.getECBlocks();
6787 for (var i = 0; i < ecBlockArray.length; i++)
6788 {
6789 totalBlocks += ecBlockArray[i].Count;
6790 }
6791
6792 // Now establish DataBlocks of the appropriate size and number of data codewords
6793 var result = new Array(totalBlocks);
6794 var numResultBlocks = 0;
6795 for (var j = 0; j < ecBlockArray.length; j++)
6796 {
6797 var ecBlock = ecBlockArray[j];
6798 for (var i = 0; i < ecBlock.Count; i++)
6799 {
6800 var numDataCodewords = ecBlock.DataCodewords;
6801 var numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords;
6802 result[numResultBlocks++] = new DataBlock(numDataCodewords, new Array(numBlockCodewords));
6803 }
6804 }
6805
6806 // All blocks have the same amount of data, except that the last n
6807 // (where n may be 0) have 1 more byte. Figure out where these start.
6808 var shorterBlocksTotalCodewords = result[0].codewords.length;
6809 var longerBlocksStartAt = result.length - 1;
6810 while (longerBlocksStartAt >= 0)
6811 {
6812 var numCodewords = result[longerBlocksStartAt].codewords.length;
6813 if (numCodewords == shorterBlocksTotalCodewords)
6814 {
6815 break;
6816 }
6817 longerBlocksStartAt--;
6818 }
6819 longerBlocksStartAt++;
6820
6821 var shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock;
6822 // The last elements of result may be 1 element longer;
6823 // first fill out as many elements as all of them have
6824 var rawCodewordsOffset = 0;
6825 for (var i = 0; i < shorterBlocksNumDataCodewords; i++)
6826 {
6827 for (var j = 0; j < numResultBlocks; j++)
6828 {
6829 result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
6830 }
6831 }
6832 // Fill out the last data block in the longer ones
6833 for (var j = longerBlocksStartAt; j < numResultBlocks; j++)
6834 {
6835 result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
6836 }
6837 // Now add in error correction blocks
6838 var max = result[0].codewords.length;
6839 for (var i = shorterBlocksNumDataCodewords; i < max; i++)
6840 {
6841 for (var j = 0; j < numResultBlocks; j++)
6842 {
6843 var iOffset = j < longerBlocksStartAt?i:i + 1;
6844 result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
6845 }
6846 }
6847 return result;
6848}
6849
6850function BitMatrixParser(bitMatrix)
6851{
6852 var dimension = bitMatrix.Dimension;
6853 if (dimension < 21 || (dimension & 0x03) != 1)
6854 {
6855 throw "Error BitMatrixParser";
6856 }
6857 this.bitMatrix = bitMatrix;
6858 this.parsedVersion = null;
6859 this.parsedFormatInfo = null;
6860
6861 this.copyBit=function( i, j, versionBits)
6862 {
6863 return this.bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1;
6864 }
6865
6866 this.readFormatInformation=function()
6867 {
6868 if (this.parsedFormatInfo != null)
6869 {
6870 return this.parsedFormatInfo;
6871 }
6872
6873 // Read top-left format info bits
6874 var formatInfoBits = 0;
6875 for (var i = 0; i < 6; i++)
6876 {
6877 formatInfoBits = this.copyBit(i, 8, formatInfoBits);
6878 }
6879 // .. and skip a bit in the timing pattern ...
6880 formatInfoBits = this.copyBit(7, 8, formatInfoBits);
6881 formatInfoBits = this.copyBit(8, 8, formatInfoBits);
6882 formatInfoBits = this.copyBit(8, 7, formatInfoBits);
6883 // .. and skip a bit in the timing pattern ...
6884 for (var j = 5; j >= 0; j--)
6885 {
6886 formatInfoBits = this.copyBit(8, j, formatInfoBits);
6887 }
6888
6889 this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
6890 if (this.parsedFormatInfo != null)
6891 {
6892 return this.parsedFormatInfo;
6893 }
6894
6895 // Hmm, failed. Try the top-right/bottom-left pattern
6896 var dimension = this.bitMatrix.Dimension;
6897 formatInfoBits = 0;
6898 var iMin = dimension - 8;
6899 for (var i = dimension - 1; i >= iMin; i--)
6900 {
6901 formatInfoBits = this.copyBit(i, 8, formatInfoBits);
6902 }
6903 for (var j = dimension - 7; j < dimension; j++)
6904 {
6905 formatInfoBits = this.copyBit(8, j, formatInfoBits);
6906 }
6907
6908 this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
6909 if (this.parsedFormatInfo != null)
6910 {
6911 return this.parsedFormatInfo;
6912 }
6913 throw "Error readFormatInformation";
6914 }
6915 this.readVersion=function()
6916 {
6917
6918 if (this.parsedVersion != null)
6919 {
6920 return this.parsedVersion;
6921 }
6922
6923 var dimension = this.bitMatrix.Dimension;
6924
6925 var provisionalVersion = (dimension - 17) >> 2;
6926 if (provisionalVersion <= 6)
6927 {
6928 return Version.getVersionForNumber(provisionalVersion);
6929 }
6930
6931 // Read top-right version info: 3 wide by 6 tall
6932 var versionBits = 0;
6933 var ijMin = dimension - 11;
6934 for (var j = 5; j >= 0; j--)
6935 {
6936 for (var i = dimension - 9; i >= ijMin; i--)
6937 {
6938 versionBits = this.copyBit(i, j, versionBits);
6939 }
6940 }
6941
6942 this.parsedVersion = Version.decodeVersionInformation(versionBits);
6943 if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension)
6944 {
6945 return this.parsedVersion;
6946 }
6947
6948 // Hmm, failed. Try bottom left: 6 wide by 3 tall
6949 versionBits = 0;
6950 for (var i = 5; i >= 0; i--)
6951 {
6952 for (var j = dimension - 9; j >= ijMin; j--)
6953 {
6954 versionBits = this.copyBit(i, j, versionBits);
6955 }
6956 }
6957
6958 this.parsedVersion = Version.decodeVersionInformation(versionBits);
6959 if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension)
6960 {
6961 return this.parsedVersion;
6962 }
6963 throw "Error readVersion";
6964 }
6965 this.readCodewords=function()
6966 {
6967
6968 var formatInfo = this.readFormatInformation();
6969 var version = this.readVersion();
6970
6971 // Get the data mask for the format used in this QR Code. This will exclude
6972 // some bits from reading as we wind through the bit matrix.
6973 var dataMask = DataMask.forReference( formatInfo.DataMask);
6974 var dimension = this.bitMatrix.Dimension;
6975 dataMask.unmaskBitMatrix(this.bitMatrix, dimension);
6976
6977 var functionPattern = version.buildFunctionPattern();
6978
6979 var readingUp = true;
6980 var result = new Array(version.TotalCodewords);
6981 var resultOffset = 0;
6982 var currentByte = 0;
6983 var bitsRead = 0;
6984 // Read columns in pairs, from right to left
6985 for (var j = dimension - 1; j > 0; j -= 2)
6986 {
6987 if (j == 6)
6988 {
6989 // Skip whole column with vertical alignment pattern;
6990 // saves time and makes the other code proceed more cleanly
6991 j--;
6992 }
6993 // Read alternatingly from bottom to top then top to bottom
6994 for (var count = 0; count < dimension; count++)
6995 {
6996 var i = readingUp?dimension - 1 - count:count;
6997 for (var col = 0; col < 2; col++)
6998 {
6999 // Ignore bits covered by the function pattern
7000 if (!functionPattern.get_Renamed(j - col, i))
7001 {
7002 // Read a bit
7003 bitsRead++;
7004 currentByte <<= 1;
7005 if (this.bitMatrix.get_Renamed(j - col, i))
7006 {
7007 currentByte |= 1;
7008 }
7009 // If we've made a whole byte, save it off
7010 if (bitsRead == 8)
7011 {
7012 result[resultOffset++] = currentByte;
7013 bitsRead = 0;
7014 currentByte = 0;
7015 }
7016 }
7017 }
7018 }
7019 readingUp ^= true; // readingUp = !readingUp; // switch directions
7020 }
7021 if (resultOffset != version.TotalCodewords)
7022 {
7023 throw "Error readCodewords";
7024 }
7025 return result;
7026 }
7027}
7028
7029DataMask = {};
7030
7031DataMask.forReference = function(reference)
7032{
7033 if (reference < 0 || reference > 7)
7034 {
7035 throw "System.ArgumentException";
7036 }
7037 return DataMask.DATA_MASKS[reference];
7038}
7039
7040function DataMask000()
7041{
7042 this.unmaskBitMatrix=function(bits, dimension)
7043 {
7044 for (var i = 0; i < dimension; i++)
7045 {
7046 for (var j = 0; j < dimension; j++)
7047 {
7048 if (this.isMasked(i, j))
7049 {
7050 bits.flip(j, i);
7051 }
7052 }
7053 }
7054 }
7055 this.isMasked=function( i, j)
7056 {
7057 return ((i + j) & 0x01) == 0;
7058 }
7059}
7060
7061function DataMask001()
7062{
7063 this.unmaskBitMatrix=function(bits, dimension)
7064 {
7065 for (var i = 0; i < dimension; i++)
7066 {
7067 for (var j = 0; j < dimension; j++)
7068 {
7069 if (this.isMasked(i, j))
7070 {
7071 bits.flip(j, i);
7072 }
7073 }
7074 }
7075 }
7076 this.isMasked=function( i, j)
7077 {
7078 return (i & 0x01) == 0;
7079 }
7080}
7081
7082function DataMask010()
7083{
7084 this.unmaskBitMatrix=function(bits, dimension)
7085 {
7086 for (var i = 0; i < dimension; i++)
7087 {
7088 for (var j = 0; j < dimension; j++)
7089 {
7090 if (this.isMasked(i, j))
7091 {
7092 bits.flip(j, i);
7093 }
7094 }
7095 }
7096 }
7097 this.isMasked=function( i, j)
7098 {
7099 return j % 3 == 0;
7100 }
7101}
7102
7103function DataMask011()
7104{
7105 this.unmaskBitMatrix=function(bits, dimension)
7106 {
7107 for (var i = 0; i < dimension; i++)
7108 {
7109 for (var j = 0; j < dimension; j++)
7110 {
7111 if (this.isMasked(i, j))
7112 {
7113 bits.flip(j, i);
7114 }
7115 }
7116 }
7117 }
7118 this.isMasked=function( i, j)
7119 {
7120 return (i + j) % 3 == 0;
7121 }
7122}
7123
7124function DataMask100()
7125{
7126 this.unmaskBitMatrix=function(bits, dimension)
7127 {
7128 for (var i = 0; i < dimension; i++)
7129 {
7130 for (var j = 0; j < dimension; j++)
7131 {
7132 if (this.isMasked(i, j))
7133 {
7134 bits.flip(j, i);
7135 }
7136 }
7137 }
7138 }
7139 this.isMasked=function( i, j)
7140 {
7141 return (((URShift(i, 1)) + (j / 3)) & 0x01) == 0;
7142 }
7143}
7144
7145function DataMask101()
7146{
7147 this.unmaskBitMatrix=function(bits, dimension)
7148 {
7149 for (var i = 0; i < dimension; i++)
7150 {
7151 for (var j = 0; j < dimension; j++)
7152 {
7153 if (this.isMasked(i, j))
7154 {
7155 bits.flip(j, i);
7156 }
7157 }
7158 }
7159 }
7160 this.isMasked=function( i, j)
7161 {
7162 var temp = i * j;
7163 return (temp & 0x01) + (temp % 3) == 0;
7164 }
7165}
7166
7167function DataMask110()
7168{
7169 this.unmaskBitMatrix=function(bits, dimension)
7170 {
7171 for (var i = 0; i < dimension; i++)
7172 {
7173 for (var j = 0; j < dimension; j++)
7174 {
7175 if (this.isMasked(i, j))
7176 {
7177 bits.flip(j, i);
7178 }
7179 }
7180 }
7181 }
7182 this.isMasked=function( i, j)
7183 {
7184 var temp = i * j;
7185 return (((temp & 0x01) + (temp % 3)) & 0x01) == 0;
7186 }
7187}
7188function DataMask111()
7189{
7190 this.unmaskBitMatrix=function(bits, dimension)
7191 {
7192 for (var i = 0; i < dimension; i++)
7193 {
7194 for (var j = 0; j < dimension; j++)
7195 {
7196 if (this.isMasked(i, j))
7197 {
7198 bits.flip(j, i);
7199 }
7200 }
7201 }
7202 }
7203 this.isMasked=function( i, j)
7204 {
7205 return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0;
7206 }
7207}
7208
7209DataMask.DATA_MASKS = new Array(new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111());
7210
7211function ReedSolomonDecoder(field)
7212{
7213 this.field = field;
7214 this.decode=function(received, twoS)
7215 {
7216 var poly = new GF256Poly(this.field, received);
7217 var syndromeCoefficients = new Array(twoS);
7218 for(var i=0;i<syndromeCoefficients.length;i++)syndromeCoefficients[i]=0;
7219 var dataMatrix = false;//this.field.Equals(GF256.DATA_MATRIX_FIELD);
7220 var noError = true;
7221 for (var i = 0; i < twoS; i++)
7222 {
7223 // Thanks to sanfordsquires for this fix:
7224 var eval = poly.evaluateAt(this.field.exp(dataMatrix?i + 1:i));
7225 syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
7226 if (eval != 0)
7227 {
7228 noError = false;
7229 }
7230 }
7231 if (noError)
7232 {
7233 return ;
7234 }
7235 var syndrome = new GF256Poly(this.field, syndromeCoefficients);
7236 var sigmaOmega = this.runEuclideanAlgorithm(this.field.buildMonomial(twoS, 1), syndrome, twoS);
7237 var sigma = sigmaOmega[0];
7238 var omega = sigmaOmega[1];
7239 var errorLocations = this.findErrorLocations(sigma);
7240 var errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations, dataMatrix);
7241 for (var i = 0; i < errorLocations.length; i++)
7242 {
7243 var position = received.length - 1 - this.field.log(errorLocations[i]);
7244 if (position < 0)
7245 {
7246 throw "ReedSolomonException Bad error location";
7247 }
7248 received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
7249 }
7250 }
7251
7252 this.runEuclideanAlgorithm=function( a, b, R)
7253 {
7254 // Assume a's degree is >= b's
7255 if (a.Degree < b.Degree)
7256 {
7257 var temp = a;
7258 a = b;
7259 b = temp;
7260 }
7261
7262 var rLast = a;
7263 var r = b;
7264 var sLast = this.field.One;
7265 var s = this.field.Zero;
7266 var tLast = this.field.Zero;
7267 var t = this.field.One;
7268
7269 // Run Euclidean algorithm until r's degree is less than R/2
7270 while (r.Degree >= Math.floor(R / 2))
7271 {
7272 var rLastLast = rLast;
7273 var sLastLast = sLast;
7274 var tLastLast = tLast;
7275 rLast = r;
7276 sLast = s;
7277 tLast = t;
7278
7279 // Divide rLastLast by rLast, with quotient in q and remainder in r
7280 if (rLast.Zero)
7281 {
7282 // Oops, Euclidean algorithm already terminated?
7283 throw "r_{i-1} was zero";
7284 }
7285 r = rLastLast;
7286 var q = this.field.Zero;
7287 var denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree);
7288 var dltInverse = this.field.inverse(denominatorLeadingTerm);
7289 while (r.Degree >= rLast.Degree && !r.Zero)
7290 {
7291 var degreeDiff = r.Degree - rLast.Degree;
7292 var scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse);
7293 q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale));
7294 r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
7295 //r.EXE();
7296 }
7297
7298 s = q.multiply1(sLast).addOrSubtract(sLastLast);
7299 t = q.multiply1(tLast).addOrSubtract(tLastLast);
7300 }
7301
7302 var sigmaTildeAtZero = t.getCoefficient(0);
7303 if (sigmaTildeAtZero == 0)
7304 {
7305 throw "ReedSolomonException sigmaTilde(0) was zero";
7306 }
7307
7308 var inverse = this.field.inverse(sigmaTildeAtZero);
7309 var sigma = t.multiply2(inverse);
7310 var omega = r.multiply2(inverse);
7311 return new Array(sigma, omega);
7312 }
7313 this.findErrorLocations=function( errorLocator)
7314 {
7315 // This is a direct application of Chien's search
7316 var numErrors = errorLocator.Degree;
7317 if (numErrors == 1)
7318 {
7319 // shortcut
7320 return new Array(errorLocator.getCoefficient(1));
7321 }
7322 var result = new Array(numErrors);
7323 var e = 0;
7324 for (var i = 1; i < 256 && e < numErrors; i++)
7325 {
7326 if (errorLocator.evaluateAt(i) == 0)
7327 {
7328 result[e] = this.field.inverse(i);
7329 e++;
7330 }
7331 }
7332 if (e != numErrors)
7333 {
7334 throw "Error locator degree does not match number of roots";
7335 }
7336 return result;
7337 }
7338 this.findErrorMagnitudes=function( errorEvaluator, errorLocations, dataMatrix)
7339 {
7340 // This is directly applying Forney's Formula
7341 var s = errorLocations.length;
7342 var result = new Array(s);
7343 for (var i = 0; i < s; i++)
7344 {
7345 var xiInverse = this.field.inverse(errorLocations[i]);
7346 var denominator = 1;
7347 for (var j = 0; j < s; j++)
7348 {
7349 if (i != j)
7350 {
7351 denominator = this.field.multiply(denominator, GF256.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse)));
7352 }
7353 }
7354 result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator));
7355 // Thanks to sanfordsquires for this fix:
7356 if (dataMatrix)
7357 {
7358 result[i] = this.field.multiply(result[i], xiInverse);
7359 }
7360 }
7361 return result;
7362 }
7363}
7364
7365function GF256Poly(field, coefficients)
7366{
7367 if (coefficients == null || coefficients.length == 0)
7368 {
7369 throw "System.ArgumentException";
7370 }
7371 this.field = field;
7372 var coefficientsLength = coefficients.length;
7373 if (coefficientsLength > 1 && coefficients[0] == 0)
7374 {
7375 // Leading term must be non-zero for anything except the constant polynomial "0"
7376 var firstNonZero = 1;
7377 while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0)
7378 {
7379 firstNonZero++;
7380 }
7381 if (firstNonZero == coefficientsLength)
7382 {
7383 this.coefficients = field.Zero.coefficients;
7384 }
7385 else
7386 {
7387 this.coefficients = new Array(coefficientsLength - firstNonZero);
7388 for(var i=0;i<this.coefficients.length;i++)this.coefficients[i]=0;
7389 //Array.Copy(coefficients, firstNonZero, this.coefficients, 0, this.coefficients.length);
7390 for(var ci=0;ci<this.coefficients.length;ci++)this.coefficients[ci]=coefficients[firstNonZero+ci];
7391 }
7392 }
7393 else
7394 {
7395 this.coefficients = coefficients;
7396 }
7397
7398 this.__defineGetter__("Zero", function()
7399 {
7400 return this.coefficients[0] == 0;
7401 });
7402 this.__defineGetter__("Degree", function()
7403 {
7404 return this.coefficients.length - 1;
7405 });
7406 this.__defineGetter__("Coefficients", function()
7407 {
7408 return this.coefficients;
7409 });
7410
7411 this.getCoefficient=function( degree)
7412 {
7413 return this.coefficients[this.coefficients.length - 1 - degree];
7414 }
7415
7416 this.evaluateAt=function( a)
7417 {
7418 if (a == 0)
7419 {
7420 // Just return the x^0 coefficient
7421 return this.getCoefficient(0);
7422 }
7423 var size = this.coefficients.length;
7424 if (a == 1)
7425 {
7426 // Just the sum of the coefficients
7427 var result = 0;
7428 for (var i = 0; i < size; i++)
7429 {
7430 result = GF256.addOrSubtract(result, this.coefficients[i]);
7431 }
7432 return result;
7433 }
7434 var result2 = this.coefficients[0];
7435 for (var i = 1; i < size; i++)
7436 {
7437 result2 = GF256.addOrSubtract(this.field.multiply(a, result2), this.coefficients[i]);
7438 }
7439 return result2;
7440 }
7441
7442 this.addOrSubtract=function( other)
7443 {
7444 if (this.field != other.field)
7445 {
7446 throw "GF256Polys do not have same GF256 field";
7447 }
7448 if (this.Zero)
7449 {
7450 return other;
7451 }
7452 if (other.Zero)
7453 {
7454 return this;
7455 }
7456
7457 var smallerCoefficients = this.coefficients;
7458 var largerCoefficients = other.coefficients;
7459 if (smallerCoefficients.length > largerCoefficients.length)
7460 {
7461 var temp = smallerCoefficients;
7462 smallerCoefficients = largerCoefficients;
7463 largerCoefficients = temp;
7464 }
7465 var sumDiff = new Array(largerCoefficients.length);
7466 var lengthDiff = largerCoefficients.length - smallerCoefficients.length;
7467 // Copy high-order terms only found in higher-degree polynomial's coefficients
7468 //Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
7469 for(var ci=0;ci<lengthDiff;ci++)sumDiff[ci]=largerCoefficients[ci];
7470
7471 for (var i = lengthDiff; i < largerCoefficients.length; i++)
7472 {
7473 sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
7474 }
7475
7476 return new GF256Poly(field, sumDiff);
7477 }
7478 this.multiply1=function( other)
7479 {
7480 if (this.field!=other.field)
7481 {
7482 throw "GF256Polys do not have same GF256 field";
7483 }
7484 if (this.Zero || other.Zero)
7485 {
7486 return this.field.Zero;
7487 }
7488 var aCoefficients = this.coefficients;
7489 var aLength = aCoefficients.length;
7490 var bCoefficients = other.coefficients;
7491 var bLength = bCoefficients.length;
7492 var product = new Array(aLength + bLength - 1);
7493 for (var i = 0; i < aLength; i++)
7494 {
7495 var aCoeff = aCoefficients[i];
7496 for (var j = 0; j < bLength; j++)
7497 {
7498 product[i + j] = GF256.addOrSubtract(product[i + j], this.field.multiply(aCoeff, bCoefficients[j]));
7499 }
7500 }
7501 return new GF256Poly(this.field, product);
7502 }
7503 this.multiply2=function( scalar)
7504 {
7505 if (scalar == 0)
7506 {
7507 return this.field.Zero;
7508 }
7509 if (scalar == 1)
7510 {
7511 return this;
7512 }
7513 var size = this.coefficients.length;
7514 var product = new Array(size);
7515 for (var i = 0; i < size; i++)
7516 {
7517 product[i] = this.field.multiply(this.coefficients[i], scalar);
7518 }
7519 return new GF256Poly(this.field, product);
7520 }
7521 this.multiplyByMonomial=function( degree, coefficient)
7522 {
7523 if (degree < 0)
7524 {
7525 throw "System.ArgumentException";
7526 }
7527 if (coefficient == 0)
7528 {
7529 return this.field.Zero;
7530 }
7531 var size = this.coefficients.length;
7532 var product = new Array(size + degree);
7533 for(var i=0;i<product.length;i++)product[i]=0;
7534 for (var i = 0; i < size; i++)
7535 {
7536 product[i] = this.field.multiply(this.coefficients[i], coefficient);
7537 }
7538 return new GF256Poly(this.field, product);
7539 }
7540 this.divide=function( other)
7541 {
7542 if (this.field!=other.field)
7543 {
7544 throw "GF256Polys do not have same GF256 field";
7545 }
7546 if (other.Zero)
7547 {
7548 throw "Divide by 0";
7549 }
7550
7551 var quotient = this.field.Zero;
7552 var remainder = this;
7553
7554 var denominatorLeadingTerm = other.getCoefficient(other.Degree);
7555 var inverseDenominatorLeadingTerm = this.field.inverse(denominatorLeadingTerm);
7556
7557 while (remainder.Degree >= other.Degree && !remainder.Zero)
7558 {
7559 var degreeDifference = remainder.Degree - other.Degree;
7560 var scale = this.field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm);
7561 var term = other.multiplyByMonomial(degreeDifference, scale);
7562 var iterationQuotient = this.field.buildMonomial(degreeDifference, scale);
7563 quotient = quotient.addOrSubtract(iterationQuotient);
7564 remainder = remainder.addOrSubtract(term);
7565 }
7566
7567 return new Array(quotient, remainder);
7568 }
7569}
7570
7571function GF256( primitive)
7572{
7573 this.expTable = new Array(256);
7574 this.logTable = new Array(256);
7575 var x = 1;
7576 for (var i = 0; i < 256; i++)
7577 {
7578 this.expTable[i] = x;
7579 x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
7580 if (x >= 0x100)
7581 {
7582 x ^= primitive;
7583 }
7584 }
7585 for (var i = 0; i < 255; i++)
7586 {
7587 this.logTable[this.expTable[i]] = i;
7588 }
7589 // logTable[0] == 0 but this should never be used
7590 var at0=new Array(1);at0[0]=0;
7591 this.zero = new GF256Poly(this, new Array(at0));
7592 var at1=new Array(1);at1[0]=1;
7593 this.one = new GF256Poly(this, new Array(at1));
7594
7595 this.__defineGetter__("Zero", function()
7596 {
7597 return this.zero;
7598 });
7599 this.__defineGetter__("One", function()
7600 {
7601 return this.one;
7602 });
7603 this.buildMonomial=function( degree, coefficient)
7604 {
7605 if (degree < 0)
7606 {
7607 throw "System.ArgumentException";
7608 }
7609 if (coefficient == 0)
7610 {
7611 return zero;
7612 }
7613 var coefficients = new Array(degree + 1);
7614 for(var i=0;i<coefficients.length;i++)coefficients[i]=0;
7615 coefficients[0] = coefficient;
7616 return new GF256Poly(this, coefficients);
7617 }
7618 this.exp=function( a)
7619 {
7620 return this.expTable[a];
7621 }
7622 this.log=function( a)
7623 {
7624 if (a == 0)
7625 {
7626 throw "System.ArgumentException";
7627 }
7628 return this.logTable[a];
7629 }
7630 this.inverse=function( a)
7631 {
7632 if (a == 0)
7633 {
7634 throw "System.ArithmeticException";
7635 }
7636 return this.expTable[255 - this.logTable[a]];
7637 }
7638 this.multiply=function( a, b)
7639 {
7640 if (a == 0 || b == 0)
7641 {
7642 return 0;
7643 }
7644 if (a == 1)
7645 {
7646 return b;
7647 }
7648 if (b == 1)
7649 {
7650 return a;
7651 }
7652 return this.expTable[(this.logTable[a] + this.logTable[b]) % 255];
7653 }
7654}
7655
7656GF256.QR_CODE_FIELD = new GF256(0x011D);
7657GF256.DATA_MATRIX_FIELD = new GF256(0x012D);
7658
7659GF256.addOrSubtract=function( a, b)
7660{
7661 return a ^ b;
7662}
7663
7664Decoder={};
7665Decoder.rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
7666
7667Decoder.correctErrors=function( codewordBytes, numDataCodewords)
7668{
7669 var numCodewords = codewordBytes.length;
7670 // First read into an array of ints
7671 var codewordsInts = new Array(numCodewords);
7672 for (var i = 0; i < numCodewords; i++)
7673 {
7674 codewordsInts[i] = codewordBytes[i] & 0xFF;
7675 }
7676 var numECCodewords = codewordBytes.length - numDataCodewords;
7677 try
7678 {
7679 Decoder.rsDecoder.decode(codewordsInts, numECCodewords);
7680 //var corrector = new ReedSolomon(codewordsInts, numECCodewords);
7681 //corrector.correct();
7682 }
7683 catch ( rse)
7684 {
7685 throw rse;
7686 }
7687 // Copy back into array of bytes -- only need to worry about the bytes that were data
7688 // We don't care about errors in the error-correction codewords
7689 for (var i = 0; i < numDataCodewords; i++)
7690 {
7691 codewordBytes[i] = codewordsInts[i];
7692 }
7693}
7694
7695Decoder.decode=function(bits)
7696{
7697 var parser = new BitMatrixParser(bits);
7698 var version = parser.readVersion();
7699 var ecLevel = parser.readFormatInformation().ErrorCorrectionLevel;
7700
7701 // Read codewords
7702 var codewords = parser.readCodewords();
7703
7704 // Separate into data blocks
7705 var dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);
7706
7707 // Count total number of data bytes
7708 var totalBytes = 0;
7709 for (var i = 0; i < dataBlocks.length; i++)
7710 {
7711 totalBytes += dataBlocks[i].NumDataCodewords;
7712 }
7713 var resultBytes = new Array(totalBytes);
7714 var resultOffset = 0;
7715
7716 // Error-correct and copy data blocks together into a stream of bytes
7717 for (var j = 0; j < dataBlocks.length; j++)
7718 {
7719 var dataBlock = dataBlocks[j];
7720 var codewordBytes = dataBlock.Codewords;
7721 var numDataCodewords = dataBlock.NumDataCodewords;
7722 Decoder.correctErrors(codewordBytes, numDataCodewords);
7723 for (var i = 0; i < numDataCodewords; i++)
7724 {
7725 resultBytes[resultOffset++] = codewordBytes[i];
7726 }
7727 }
7728
7729 // Decode the contents of that stream of bytes
7730 var reader = new QRCodeDataBlockReader(resultBytes, version.VersionNumber, ecLevel.Bits);
7731 return reader;
7732 //return DecodedBitStreamParser.decode(resultBytes, version, ecLevel);
7733}
7734
7735qrcode = {};
7736qrcode.imagedata = null;
7737qrcode.width = 0;
7738qrcode.height = 0;
7739qrcode.qrCodeSymbol = null;
7740qrcode.debug = false;
7741qrcode.maxImgSize = 1024*1024;
7742
7743qrcode.sizeOfDataLengthInfo = [ [ 10, 9, 8, 8 ], [ 12, 11, 16, 10 ], [ 14, 13, 16, 12 ] ];
7744
7745qrcode.callback = null;
7746
7747qrcode.decode = function(src){
7748
7749 if(arguments.length==0)
7750 {
7751 var canvas_qr = document.getElementById("qr-canvas");
7752 var context = canvas_qr.getContext('2d');
7753 qrcode.width = canvas_qr.width;
7754 qrcode.height = canvas_qr.height;
7755 qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height);
7756 qrcode.result = qrcode.process(context);
7757 if(qrcode.callback!=null)
7758 qrcode.callback(qrcode.result);
7759 return qrcode.result;
7760 }
7761 else
7762 {
7763 var image = new Image();
7764 image.onload=function(){
7765 //var canvas_qr = document.getElementById("qr-canvas");
7766 var canvas_qr = document.createElement('canvas');
7767 var context = canvas_qr.getContext('2d');
7768 var nheight = image.height;
7769 var nwidth = image.width;
7770 if(image.width*image.height>qrcode.maxImgSize)
7771 {
7772 var ir = image.width / image.height;
7773 nheight = Math.sqrt(qrcode.maxImgSize/ir);
7774 nwidth=ir*nheight;
7775 }
7776
7777 canvas_qr.width = nwidth;
7778 canvas_qr.height = nheight;
7779
7780 context.drawImage(image, 0, 0, canvas_qr.width, canvas_qr.height );
7781 qrcode.width = canvas_qr.width;
7782 qrcode.height = canvas_qr.height;
7783 try{
7784 qrcode.imagedata = context.getImageData(0, 0, canvas_qr.width, canvas_qr.height);
7785 }catch(e){
7786 qrcode.result = "Cross domain image reading not supported in your browser! Save it to your computer then drag and drop the file!";
7787 if(qrcode.callback!=null)
7788 qrcode.callback(qrcode.result);
7789 return;
7790 }
7791
7792 try
7793 {
7794 qrcode.result = qrcode.process(context);
7795 }
7796 catch(e)
7797 {
7798 console.log(e);
7799 qrcode.result = "error decoding QR Code";
7800 }
7801 if(qrcode.callback!=null)
7802 qrcode.callback(qrcode.result);
7803 }
7804 image.src = src;
7805 }
7806}
7807
7808qrcode.isUrl = function(s)
7809{
7810 var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
7811 return regexp.test(s);
7812}
7813
7814qrcode.decode_url = function (s)
7815{
7816 var escaped = "";
7817 try{
7818 escaped = escape( s );
7819 }
7820 catch(e)
7821 {
7822 console.log(e);
7823 escaped = s;
7824 }
7825 var ret = "";
7826 try{
7827 ret = decodeURIComponent( escaped );
7828 }
7829 catch(e)
7830 {
7831 console.log(e);
7832 ret = escaped;
7833 }
7834 return ret;
7835}
7836
7837qrcode.decode_utf8 = function ( s )
7838{
7839 if(qrcode.isUrl(s))
7840 return qrcode.decode_url(s);
7841 else
7842 return s;
7843}
7844
7845qrcode.process = function(ctx){
7846
7847 var start = new Date().getTime();
7848
7849 var image = qrcode.grayScaleToBitmap(qrcode.grayscale());
7850 //var image = qrcode.binarize(128);
7851
7852 if(qrcode.debug)
7853 {
7854 for (var y = 0; y < qrcode.height; y++)
7855 {
7856 for (var x = 0; x < qrcode.width; x++)
7857 {
7858 var point = (x * 4) + (y * qrcode.width * 4);
7859 qrcode.imagedata.data[point] = image[x+y*qrcode.width]?0:0;
7860 qrcode.imagedata.data[point+1] = image[x+y*qrcode.width]?0:0;
7861 qrcode.imagedata.data[point+2] = image[x+y*qrcode.width]?255:0;
7862 }
7863 }
7864 ctx.putImageData(qrcode.imagedata, 0, 0);
7865 }
7866
7867 //var finderPatternInfo = new FinderPatternFinder().findFinderPattern(image);
7868
7869 var detector = new Detector(image);
7870
7871 var qRCodeMatrix = detector.detect();
7872
7873 /*for (var y = 0; y < qRCodeMatrix.bits.Height; y++)
7874 {
7875 for (var x = 0; x < qRCodeMatrix.bits.Width; x++)
7876 {
7877 var point = (x * 4*2) + (y*2 * qrcode.width * 4);
7878 qrcode.imagedata.data[point] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0;
7879 qrcode.imagedata.data[point+1] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0;
7880 qrcode.imagedata.data[point+2] = qRCodeMatrix.bits.get_Renamed(x,y)?255:0;
7881 }
7882 }*/
7883 if(qrcode.debug)
7884 ctx.putImageData(qrcode.imagedata, 0, 0);
7885
7886 var reader = Decoder.decode(qRCodeMatrix.bits);
7887 var data = reader.DataByte;
7888 var str="";
7889 for(var i=0;i<data.length;i++)
7890 {
7891 for(var j=0;j<data[i].length;j++)
7892 str+=String.fromCharCode(data[i][j]);
7893 }
7894
7895 var end = new Date().getTime();
7896 var time = end - start;
7897 console.log(time);
7898
7899 return qrcode.decode_utf8(str);
7900 //alert("Time:" + time + " Code: "+str);
7901}
7902
7903qrcode.getPixel = function(x,y){
7904 if (qrcode.width < x) {
7905 throw "point error";
7906 }
7907 if (qrcode.height < y) {
7908 throw "point error";
7909 }
7910 point = (x * 4) + (y * qrcode.width * 4);
7911 p = (qrcode.imagedata.data[point]*33 + qrcode.imagedata.data[point + 1]*34 + qrcode.imagedata.data[point + 2]*33)/100;
7912 return p;
7913}
7914
7915qrcode.binarize = function(th){
7916 var ret = new Array(qrcode.width*qrcode.height);
7917 for (var y = 0; y < qrcode.height; y++)
7918 {
7919 for (var x = 0; x < qrcode.width; x++)
7920 {
7921 var gray = qrcode.getPixel(x, y);
7922
7923 ret[x+y*qrcode.width] = gray<=th?true:false;
7924 }
7925 }
7926 return ret;
7927}
7928
7929qrcode.getMiddleBrightnessPerArea=function(image)
7930{
7931 var numSqrtArea = 4;
7932 //obtain middle brightness((min + max) / 2) per area
7933 var areaWidth = Math.floor(qrcode.width / numSqrtArea);
7934 var areaHeight = Math.floor(qrcode.height / numSqrtArea);
7935 var minmax = new Array(numSqrtArea);
7936 for (var i = 0; i < numSqrtArea; i++)
7937 {
7938 minmax[i] = new Array(numSqrtArea);
7939 for (var i2 = 0; i2 < numSqrtArea; i2++)
7940 {
7941 minmax[i][i2] = new Array(0,0);
7942 }
7943 }
7944 for (var ay = 0; ay < numSqrtArea; ay++)
7945 {
7946 for (var ax = 0; ax < numSqrtArea; ax++)
7947 {
7948 minmax[ax][ay][0] = 0xFF;
7949 for (var dy = 0; dy < areaHeight; dy++)
7950 {
7951 for (var dx = 0; dx < areaWidth; dx++)
7952 {
7953 var target = image[areaWidth * ax + dx+(areaHeight * ay + dy)*qrcode.width];
7954 if (target < minmax[ax][ay][0])
7955 minmax[ax][ay][0] = target;
7956 if (target > minmax[ax][ay][1])
7957 minmax[ax][ay][1] = target;
7958 }
7959 }
7960 //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
7961 }
7962 }
7963 var middle = new Array(numSqrtArea);
7964 for (var i3 = 0; i3 < numSqrtArea; i3++)
7965 {
7966 middle[i3] = new Array(numSqrtArea);
7967 }
7968 for (var ay = 0; ay < numSqrtArea; ay++)
7969 {
7970 for (var ax = 0; ax < numSqrtArea; ax++)
7971 {
7972 middle[ax][ay] = Math.floor((minmax[ax][ay][0] + minmax[ax][ay][1]) / 2);
7973 //Console.out.print(middle[ax][ay] + ",");
7974 }
7975 //Console.out.println("");
7976 }
7977 //Console.out.println("");
7978
7979 return middle;
7980}
7981
7982qrcode.grayScaleToBitmap=function(grayScale)
7983{
7984 var middle = qrcode.getMiddleBrightnessPerArea(grayScale);
7985 var sqrtNumArea = middle.length;
7986 var areaWidth = Math.floor(qrcode.width / sqrtNumArea);
7987 var areaHeight = Math.floor(qrcode.height / sqrtNumArea);
7988 var bitmap = new Array(qrcode.height*qrcode.width);
7989
7990 for (var ay = 0; ay < sqrtNumArea; ay++)
7991 {
7992 for (var ax = 0; ax < sqrtNumArea; ax++)
7993 {
7994 for (var dy = 0; dy < areaHeight; dy++)
7995 {
7996 for (var dx = 0; dx < areaWidth; dx++)
7997 {
7998 bitmap[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] = (grayScale[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] < middle[ax][ay])?true:false;
7999 }
8000 }
8001 }
8002 }
8003 return bitmap;
8004}
8005
8006qrcode.grayscale = function(){
8007 var ret = new Array(qrcode.width*qrcode.height);
8008 for (var y = 0; y < qrcode.height; y++)
8009 {
8010 for (var x = 0; x < qrcode.width; x++)
8011 {
8012 var gray = qrcode.getPixel(x, y);
8013
8014 ret[x+y*qrcode.width] = gray;
8015 }
8016 }
8017 return ret;
8018}
8019
8020
8021
8022
8023function URShift( number, bits)
8024{
8025 if (number >= 0)
8026 return number >> bits;
8027 else
8028 return (number >> bits) + (2 << ~bits);
8029}
8030
8031
8032Array.prototype.remove = function(from, to) {
8033 var rest = this.slice((to || from) + 1 || this.length);
8034 this.length = from < 0 ? this.length + from : from;
8035 return this.push.apply(this, rest);
8036};
8037
8038var MIN_SKIP = 3;
8039var MAX_MODULES = 57;
8040var INTEGER_MATH_SHIFT = 8;
8041var CENTER_QUORUM = 2;
8042
8043qrcode.orderBestPatterns=function(patterns)
8044 {
8045
8046 function distance( pattern1, pattern2)
8047 {
8048 xDiff = pattern1.X - pattern2.X;
8049 yDiff = pattern1.Y - pattern2.Y;
8050 return Math.sqrt( (xDiff * xDiff + yDiff * yDiff));
8051 }
8052
8053 /// <summary> Returns the z component of the cross product between vectors BC and BA.</summary>
8054 function crossProductZ( pointA, pointB, pointC)
8055 {
8056 var bX = pointB.x;
8057 var bY = pointB.y;
8058 return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
8059 }
8060
8061
8062 // Find distances between pattern centers
8063 var zeroOneDistance = distance(patterns[0], patterns[1]);
8064 var oneTwoDistance = distance(patterns[1], patterns[2]);
8065 var zeroTwoDistance = distance(patterns[0], patterns[2]);
8066
8067 var pointA, pointB, pointC;
8068 // Assume one closest to other two is B; A and C will just be guesses at first
8069 if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance)
8070 {
8071 pointB = patterns[0];
8072 pointA = patterns[1];
8073 pointC = patterns[2];
8074 }
8075 else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance)
8076 {
8077 pointB = patterns[1];
8078 pointA = patterns[0];
8079 pointC = patterns[2];
8080 }
8081 else
8082 {
8083 pointB = patterns[2];
8084 pointA = patterns[0];
8085 pointC = patterns[1];
8086 }
8087
8088 // Use cross product to figure out whether A and C are correct or flipped.
8089 // This asks whether BC x BA has a positive z component, which is the arrangement
8090 // we want for A, B, C. If it's negative, then we've got it flipped around and
8091 // should swap A and C.
8092 if (crossProductZ(pointA, pointB, pointC) < 0.0)
8093 {
8094 var temp = pointA;
8095 pointA = pointC;
8096 pointC = temp;
8097 }
8098
8099 patterns[0] = pointA;
8100 patterns[1] = pointB;
8101 patterns[2] = pointC;
8102 }
8103
8104
8105function FinderPattern(posX, posY, estimatedModuleSize)
8106{
8107 this.x=posX;
8108 this.y=posY;
8109 this.count = 1;
8110 this.estimatedModuleSize = estimatedModuleSize;
8111
8112 this.__defineGetter__("EstimatedModuleSize", function()
8113 {
8114 return this.estimatedModuleSize;
8115 });
8116 this.__defineGetter__("Count", function()
8117 {
8118 return this.count;
8119 });
8120 this.__defineGetter__("X", function()
8121 {
8122 return this.x;
8123 });
8124 this.__defineGetter__("Y", function()
8125 {
8126 return this.y;
8127 });
8128 this.incrementCount = function()
8129 {
8130 this.count++;
8131 }
8132 this.aboutEquals=function( moduleSize, i, j)
8133 {
8134 if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize)
8135 {
8136 var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize);
8137 return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0;
8138 }
8139 return false;
8140 }
8141
8142}
8143
8144function FinderPatternInfo(patternCenters)
8145{
8146 this.bottomLeft = patternCenters[0];
8147 this.topLeft = patternCenters[1];
8148 this.topRight = patternCenters[2];
8149 this.__defineGetter__("BottomLeft", function()
8150 {
8151 return this.bottomLeft;
8152 });
8153 this.__defineGetter__("TopLeft", function()
8154 {
8155 return this.topLeft;
8156 });
8157 this.__defineGetter__("TopRight", function()
8158 {
8159 return this.topRight;
8160 });
8161}
8162
8163function FinderPatternFinder()
8164{
8165 this.image=null;
8166 this.possibleCenters = [];
8167 this.hasSkipped = false;
8168 this.crossCheckStateCount = new Array(0,0,0,0,0);
8169 this.resultPointCallback = null;
8170
8171 this.__defineGetter__("CrossCheckStateCount", function()
8172 {
8173 this.crossCheckStateCount[0] = 0;
8174 this.crossCheckStateCount[1] = 0;
8175 this.crossCheckStateCount[2] = 0;
8176 this.crossCheckStateCount[3] = 0;
8177 this.crossCheckStateCount[4] = 0;
8178 return this.crossCheckStateCount;
8179 });
8180
8181 this.foundPatternCross=function( stateCount)
8182 {
8183 var totalModuleSize = 0;
8184 for (var i = 0; i < 5; i++)
8185 {
8186 var count = stateCount[i];
8187 if (count == 0)
8188 {
8189 return false;
8190 }
8191 totalModuleSize += count;
8192 }
8193 if (totalModuleSize < 7)
8194 {
8195 return false;
8196 }
8197 var moduleSize = Math.floor((totalModuleSize << INTEGER_MATH_SHIFT) / 7);
8198 var maxVariance = Math.floor(moduleSize / 2);
8199 // Allow less than 50% variance from 1-1-3-1-1 proportions
8200 return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance;
8201 }
8202 this.centerFromEnd=function( stateCount, end)
8203 {
8204 return (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0;
8205 }
8206 this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal)
8207 {
8208 var image = this.image;
8209
8210 var maxI = qrcode.height;
8211 var stateCount = this.CrossCheckStateCount;
8212
8213 // Start counting up from center
8214 var i = startI;
8215 while (i >= 0 && image[centerJ + i*qrcode.width])
8216 {
8217 stateCount[2]++;
8218 i--;
8219 }
8220 if (i < 0)
8221 {
8222 return NaN;
8223 }
8224 while (i >= 0 && !image[centerJ +i*qrcode.width] && stateCount[1] <= maxCount)
8225 {
8226 stateCount[1]++;
8227 i--;
8228 }
8229 // If already too many modules in this state or ran off the edge:
8230 if (i < 0 || stateCount[1] > maxCount)
8231 {
8232 return NaN;
8233 }
8234 while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount)
8235 {
8236 stateCount[0]++;
8237 i--;
8238 }
8239 if (stateCount[0] > maxCount)
8240 {
8241 return NaN;
8242 }
8243
8244 // Now also count down from center
8245 i = startI + 1;
8246 while (i < maxI && image[centerJ +i*qrcode.width])
8247 {
8248 stateCount[2]++;
8249 i++;
8250 }
8251 if (i == maxI)
8252 {
8253 return NaN;
8254 }
8255 while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[3] < maxCount)
8256 {
8257 stateCount[3]++;
8258 i++;
8259 }
8260 if (i == maxI || stateCount[3] >= maxCount)
8261 {
8262 return NaN;
8263 }
8264 while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[4] < maxCount)
8265 {
8266 stateCount[4]++;
8267 i++;
8268 }
8269 if (stateCount[4] >= maxCount)
8270 {
8271 return NaN;
8272 }
8273
8274 // If we found a finder-pattern-like section, but its size is more than 40% different than
8275 // the original, assume it's a false positive
8276 var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
8277 if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal)
8278 {
8279 return NaN;
8280 }
8281
8282 return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN;
8283 }
8284 this.crossCheckHorizontal=function( startJ, centerI, maxCount, originalStateCountTotal)
8285 {
8286 var image = this.image;
8287
8288 var maxJ = qrcode.width;
8289 var stateCount = this.CrossCheckStateCount;
8290
8291 var j = startJ;
8292 while (j >= 0 && image[j+ centerI*qrcode.width])
8293 {
8294 stateCount[2]++;
8295 j--;
8296 }
8297 if (j < 0)
8298 {
8299 return NaN;
8300 }
8301 while (j >= 0 && !image[j+ centerI*qrcode.width] && stateCount[1] <= maxCount)
8302 {
8303 stateCount[1]++;
8304 j--;
8305 }
8306 if (j < 0 || stateCount[1] > maxCount)
8307 {
8308 return NaN;
8309 }
8310 while (j >= 0 && image[j+ centerI*qrcode.width] && stateCount[0] <= maxCount)
8311 {
8312 stateCount[0]++;
8313 j--;
8314 }
8315 if (stateCount[0] > maxCount)
8316 {
8317 return NaN;
8318 }
8319
8320 j = startJ + 1;
8321 while (j < maxJ && image[j+ centerI*qrcode.width])
8322 {
8323 stateCount[2]++;
8324 j++;
8325 }
8326 if (j == maxJ)
8327 {
8328 return NaN;
8329 }
8330 while (j < maxJ && !image[j+ centerI*qrcode.width] && stateCount[3] < maxCount)
8331 {
8332 stateCount[3]++;
8333 j++;
8334 }
8335 if (j == maxJ || stateCount[3] >= maxCount)
8336 {
8337 return NaN;
8338 }
8339 while (j < maxJ && image[j+ centerI*qrcode.width] && stateCount[4] < maxCount)
8340 {
8341 stateCount[4]++;
8342 j++;
8343 }
8344 if (stateCount[4] >= maxCount)
8345 {
8346 return NaN;
8347 }
8348
8349 // If we found a finder-pattern-like section, but its size is significantly different than
8350 // the original, assume it's a false positive
8351 var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
8352 if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal)
8353 {
8354 return NaN;
8355 }
8356
8357 return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, j):NaN;
8358 }
8359 this.handlePossibleCenter=function( stateCount, i, j)
8360 {
8361 var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
8362 var centerJ = this.centerFromEnd(stateCount, j); //float
8363 var centerI = this.crossCheckVertical(i, Math.floor( centerJ), stateCount[2], stateCountTotal); //float
8364 if (!isNaN(centerI))
8365 {
8366 // Re-cross check
8367 centerJ = this.crossCheckHorizontal(Math.floor( centerJ), Math.floor( centerI), stateCount[2], stateCountTotal);
8368 if (!isNaN(centerJ))
8369 {
8370 var estimatedModuleSize = stateCountTotal / 7.0;
8371 var found = false;
8372 var max = this.possibleCenters.length;
8373 for (var index = 0; index < max; index++)
8374 {
8375 var center = this.possibleCenters[index];
8376 // Look for about the same center and module size:
8377 if (center.aboutEquals(estimatedModuleSize, centerI, centerJ))
8378 {
8379 center.incrementCount();
8380 found = true;
8381 break;
8382 }
8383 }
8384 if (!found)
8385 {
8386 var point = new FinderPattern(centerJ, centerI, estimatedModuleSize);
8387 this.possibleCenters.push(point);
8388 if (this.resultPointCallback != null)
8389 {
8390 this.resultPointCallback.foundPossibleResultPoint(point);
8391 }
8392 }
8393 return true;
8394 }
8395 }
8396 return false;
8397 }
8398
8399 this.selectBestPatterns=function()
8400 {
8401
8402 var startSize = this.possibleCenters.length;
8403 if (startSize < 3)
8404 {
8405 // Couldn't find enough finder patterns
8406 throw "Couldn't find enough finder patterns";
8407 }
8408
8409 // Filter outlier possibilities whose module size is too different
8410 if (startSize > 3)
8411 {
8412 // But we can only afford to do so if we have at least 4 possibilities to choose from
8413 var totalModuleSize = 0.0;
8414 var square = 0.0;
8415 for (var i = 0; i < startSize; i++)
8416 {
8417 //totalModuleSize += this.possibleCenters[i].EstimatedModuleSize;
8418 var centerValue=this.possibleCenters[i].EstimatedModuleSize;
8419 totalModuleSize += centerValue;
8420 square += (centerValue * centerValue);
8421 }
8422 var average = totalModuleSize / startSize;
8423 this.possibleCenters.sort(function(center1,center2) {
8424 var dA=Math.abs(center2.EstimatedModuleSize - average);
8425 var dB=Math.abs(center1.EstimatedModuleSize - average);
8426 if (dA < dB) {
8427 return (-1);
8428 } else if (dA == dB) {
8429 return 0;
8430 } else {
8431 return 1;
8432 }
8433 });
8434
8435 var stdDev = Math.sqrt(square / startSize - average * average);
8436 var limit = Math.max(0.2 * average, stdDev);
8437 for (var i = 0; i < this.possibleCenters.length && this.possibleCenters.length > 3; i++)
8438 {
8439 var pattern = this.possibleCenters[i];
8440 //if (Math.abs(pattern.EstimatedModuleSize - average) > 0.2 * average)
8441 if (Math.abs(pattern.EstimatedModuleSize - average) > limit)
8442 {
8443 this.possibleCenters.remove(i);
8444 i--;
8445 }
8446 }
8447 }
8448
8449 if (this.possibleCenters.length > 3)
8450 {
8451 // Throw away all but those first size candidate points we found.
8452 this.possibleCenters.sort(function(a, b){
8453 if (a.count > b.count){return -1;}
8454 if (a.count < b.count){return 1;}
8455 return 0;
8456 });
8457 }
8458
8459 return new Array( this.possibleCenters[0], this.possibleCenters[1], this.possibleCenters[2]);
8460 }
8461
8462 this.findRowSkip=function()
8463 {
8464 var max = this.possibleCenters.length;
8465 if (max <= 1)
8466 {
8467 return 0;
8468 }
8469 var firstConfirmedCenter = null;
8470 for (var i = 0; i < max; i++)
8471 {
8472 var center = this.possibleCenters[i];
8473 if (center.Count >= CENTER_QUORUM)
8474 {
8475 if (firstConfirmedCenter == null)
8476 {
8477 firstConfirmedCenter = center;
8478 }
8479 else
8480 {
8481 // We have two confirmed centers
8482 // How far down can we skip before resuming looking for the next
8483 // pattern? In the worst case, only the difference between the
8484 // difference in the x / y coordinates of the two centers.
8485 // This is the case where you find top left last.
8486 this.hasSkipped = true;
8487 return Math.floor ((Math.abs(firstConfirmedCenter.X - center.X) - Math.abs(firstConfirmedCenter.Y - center.Y)) / 2);
8488 }
8489 }
8490 }
8491 return 0;
8492 }
8493
8494 this.haveMultiplyConfirmedCenters=function()
8495 {
8496 var confirmedCount = 0;
8497 var totalModuleSize = 0.0;
8498 var max = this.possibleCenters.length;
8499 for (var i = 0; i < max; i++)
8500 {
8501 var pattern = this.possibleCenters[i];
8502 if (pattern.Count >= CENTER_QUORUM)
8503 {
8504 confirmedCount++;
8505 totalModuleSize += pattern.EstimatedModuleSize;
8506 }
8507 }
8508 if (confirmedCount < 3)
8509 {
8510 return false;
8511 }
8512 // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
8513 // and that we need to keep looking. We detect this by asking if the estimated module sizes
8514 // vary too much. We arbitrarily say that when the total deviation from average exceeds
8515 // 5% of the total module size estimates, it's too much.
8516 var average = totalModuleSize / max;
8517 var totalDeviation = 0.0;
8518 for (var i = 0; i < max; i++)
8519 {
8520 pattern = this.possibleCenters[i];
8521 totalDeviation += Math.abs(pattern.EstimatedModuleSize - average);
8522 }
8523 return totalDeviation <= 0.05 * totalModuleSize;
8524 }
8525
8526 this.findFinderPattern = function(image){
8527 var tryHarder = false;
8528 this.image=image;
8529 var maxI = qrcode.height;
8530 var maxJ = qrcode.width;
8531 var iSkip = Math.floor((3 * maxI) / (4 * MAX_MODULES));
8532 if (iSkip < MIN_SKIP || tryHarder)
8533 {
8534 iSkip = MIN_SKIP;
8535 }
8536
8537 var done = false;
8538 var stateCount = new Array(5);
8539 for (var i = iSkip - 1; i < maxI && !done; i += iSkip)
8540 {
8541 // Get a row of black/white values
8542 stateCount[0] = 0;
8543 stateCount[1] = 0;
8544 stateCount[2] = 0;
8545 stateCount[3] = 0;
8546 stateCount[4] = 0;
8547 var currentState = 0;
8548 for (var j = 0; j < maxJ; j++)
8549 {
8550 if (image[j+i*qrcode.width] )
8551 {
8552 // Black pixel
8553 if ((currentState & 1) == 1)
8554 {
8555 // Counting white pixels
8556 currentState++;
8557 }
8558 stateCount[currentState]++;
8559 }
8560 else
8561 {
8562 // White pixel
8563 if ((currentState & 1) == 0)
8564 {
8565 // Counting black pixels
8566 if (currentState == 4)
8567 {
8568 // A winner?
8569 if (this.foundPatternCross(stateCount))
8570 {
8571 // Yes
8572 var confirmed = this.handlePossibleCenter(stateCount, i, j);
8573 if (confirmed)
8574 {
8575 // Start examining every other line. Checking each line turned out to be too
8576 // expensive and didn't improve performance.
8577 iSkip = 2;
8578 if (this.hasSkipped)
8579 {
8580 done = this.haveMultiplyConfirmedCenters();
8581 }
8582 else
8583 {
8584 var rowSkip = this.findRowSkip();
8585 if (rowSkip > stateCount[2])
8586 {
8587 // Skip rows between row of lower confirmed center
8588 // and top of presumed third confirmed center
8589 // but back up a bit to get a full chance of detecting
8590 // it, entire width of center of finder pattern
8591
8592 // Skip by rowSkip, but back off by stateCount[2] (size of last center
8593 // of pattern we saw) to be conservative, and also back off by iSkip which
8594 // is about to be re-added
8595 i += rowSkip - stateCount[2] - iSkip;
8596 j = maxJ - 1;
8597 }
8598 }
8599 }
8600 else
8601 {
8602 // Advance to next black pixel
8603 do
8604 {
8605 j++;
8606 }
8607 while (j < maxJ && !image[j + i*qrcode.width]);
8608 j--; // back up to that last white pixel
8609 }
8610 // Clear state to start looking again
8611 currentState = 0;
8612 stateCount[0] = 0;
8613 stateCount[1] = 0;
8614 stateCount[2] = 0;
8615 stateCount[3] = 0;
8616 stateCount[4] = 0;
8617 }
8618 else
8619 {
8620 // No, shift counts back by two
8621 stateCount[0] = stateCount[2];
8622 stateCount[1] = stateCount[3];
8623 stateCount[2] = stateCount[4];
8624 stateCount[3] = 1;
8625 stateCount[4] = 0;
8626 currentState = 3;
8627 }
8628 }
8629 else
8630 {
8631 stateCount[++currentState]++;
8632 }
8633 }
8634 else
8635 {
8636 // Counting white pixels
8637 stateCount[currentState]++;
8638 }
8639 }
8640 }
8641 if (this.foundPatternCross(stateCount))
8642 {
8643 var confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
8644 if (confirmed)
8645 {
8646 iSkip = stateCount[0];
8647 if (this.hasSkipped)
8648 {
8649 // Found a third one
8650 done = haveMultiplyConfirmedCenters();
8651 }
8652 }
8653 }
8654 }
8655
8656 var patternInfo = this.selectBestPatterns();
8657 qrcode.orderBestPatterns(patternInfo);
8658
8659 return new FinderPatternInfo(patternInfo);
8660 };
8661}
8662
8663function AlignmentPattern(posX, posY, estimatedModuleSize)
8664{
8665 this.x=posX;
8666 this.y=posY;
8667 this.count = 1;
8668 this.estimatedModuleSize = estimatedModuleSize;
8669
8670 this.__defineGetter__("EstimatedModuleSize", function()
8671 {
8672 return this.estimatedModuleSize;
8673 });
8674 this.__defineGetter__("Count", function()
8675 {
8676 return this.count;
8677 });
8678 this.__defineGetter__("X", function()
8679 {
8680 return Math.floor(this.x);
8681 });
8682 this.__defineGetter__("Y", function()
8683 {
8684 return Math.floor(this.y);
8685 });
8686 this.incrementCount = function()
8687 {
8688 this.count++;
8689 }
8690 this.aboutEquals=function( moduleSize, i, j)
8691 {
8692 if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize)
8693 {
8694 var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize);
8695 return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0;
8696 }
8697 return false;
8698 }
8699
8700}
8701
8702function AlignmentPatternFinder( image, startX, startY, width, height, moduleSize, resultPointCallback)
8703{
8704 this.image = image;
8705 this.possibleCenters = new Array();
8706 this.startX = startX;
8707 this.startY = startY;
8708 this.width = width;
8709 this.height = height;
8710 this.moduleSize = moduleSize;
8711 this.crossCheckStateCount = new Array(0,0,0);
8712 this.resultPointCallback = resultPointCallback;
8713
8714 this.centerFromEnd=function(stateCount, end)
8715 {
8716 return (end - stateCount[2]) - stateCount[1] / 2.0;
8717 }
8718 this.foundPatternCross = function(stateCount)
8719 {
8720 var moduleSize = this.moduleSize;
8721 var maxVariance = moduleSize / 2.0;
8722 for (var i = 0; i < 3; i++)
8723 {
8724 if (Math.abs(moduleSize - stateCount[i]) >= maxVariance)
8725 {
8726 return false;
8727 }
8728 }
8729 return true;
8730 }
8731
8732 this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal)
8733 {
8734 var image = this.image;
8735
8736 var maxI = qrcode.height;
8737 var stateCount = this.crossCheckStateCount;
8738 stateCount[0] = 0;
8739 stateCount[1] = 0;
8740 stateCount[2] = 0;
8741
8742 // Start counting up from center
8743 var i = startI;
8744 while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount)
8745 {
8746 stateCount[1]++;
8747 i--;
8748 }
8749 // If already too many modules in this state or ran off the edge:
8750 if (i < 0 || stateCount[1] > maxCount)
8751 {
8752 return NaN;
8753 }
8754 while (i >= 0 && !image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount)
8755 {
8756 stateCount[0]++;
8757 i--;
8758 }
8759 if (stateCount[0] > maxCount)
8760 {
8761 return NaN;
8762 }
8763
8764 // Now also count down from center
8765 i = startI + 1;
8766 while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount)
8767 {
8768 stateCount[1]++;
8769 i++;
8770 }
8771 if (i == maxI || stateCount[1] > maxCount)
8772 {
8773 return NaN;
8774 }
8775 while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[2] <= maxCount)
8776 {
8777 stateCount[2]++;
8778 i++;
8779 }
8780 if (stateCount[2] > maxCount)
8781 {
8782 return NaN;
8783 }
8784
8785 var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
8786 if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal)
8787 {
8788 return NaN;
8789 }
8790
8791 return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN;
8792 }
8793
8794 this.handlePossibleCenter=function( stateCount, i, j)
8795 {
8796 var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
8797 var centerJ = this.centerFromEnd(stateCount, j);
8798 var centerI = this.crossCheckVertical(i, Math.floor (centerJ), 2 * stateCount[1], stateCountTotal);
8799 if (!isNaN(centerI))
8800 {
8801 var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0;
8802 var max = this.possibleCenters.length;
8803 for (var index = 0; index < max; index++)
8804 {
8805 var center = this.possibleCenters[index];
8806 // Look for about the same center and module size:
8807 if (center.aboutEquals(estimatedModuleSize, centerI, centerJ))
8808 {
8809 return new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
8810 }
8811 }
8812 // Hadn't found this before; save it
8813 var point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
8814 this.possibleCenters.push(point);
8815 if (this.resultPointCallback != null)
8816 {
8817 this.resultPointCallback.foundPossibleResultPoint(point);
8818 }
8819 }
8820 return null;
8821 }
8822
8823 this.find = function()
8824 {
8825 var startX = this.startX;
8826 var height = this.height;
8827 var maxJ = startX + width;
8828 var middleI = startY + (height >> 1);
8829 // We are looking for black/white/black modules in 1:1:1 ratio;
8830 // this tracks the number of black/white/black modules seen so far
8831 var stateCount = new Array(0,0,0);
8832 for (var iGen = 0; iGen < height; iGen++)
8833 {
8834 // Search from middle outwards
8835 var i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1));
8836 stateCount[0] = 0;
8837 stateCount[1] = 0;
8838 stateCount[2] = 0;
8839 var j = startX;
8840 // Burn off leading white pixels before anything else; if we start in the middle of
8841 // a white run, it doesn't make sense to count its length, since we don't know if the
8842 // white run continued to the left of the start point
8843 while (j < maxJ && !image[j + qrcode.width* i])
8844 {
8845 j++;
8846 }
8847 var currentState = 0;
8848 while (j < maxJ)
8849 {
8850 if (image[j + i*qrcode.width])
8851 {
8852 // Black pixel
8853 if (currentState == 1)
8854 {
8855 // Counting black pixels
8856 stateCount[currentState]++;
8857 }
8858 else
8859 {
8860 // Counting white pixels
8861 if (currentState == 2)
8862 {
8863 // A winner?
8864 if (this.foundPatternCross(stateCount))
8865 {
8866 // Yes
8867 var confirmed = this.handlePossibleCenter(stateCount, i, j);
8868 if (confirmed != null)
8869 {
8870 return confirmed;
8871 }
8872 }
8873 stateCount[0] = stateCount[2];
8874 stateCount[1] = 1;
8875 stateCount[2] = 0;
8876 currentState = 1;
8877 }
8878 else
8879 {
8880 stateCount[++currentState]++;
8881 }
8882 }
8883 }
8884 else
8885 {
8886 // White pixel
8887 if (currentState == 1)
8888 {
8889 // Counting black pixels
8890 currentState++;
8891 }
8892 stateCount[currentState]++;
8893 }
8894 j++;
8895 }
8896 if (this.foundPatternCross(stateCount))
8897 {
8898 var confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
8899 if (confirmed != null)
8900 {
8901 return confirmed;
8902 }
8903 }
8904 }
8905
8906 // Hmm, nothing we saw was observed and confirmed twice. If we had
8907 // any guess at all, return it.
8908 if (!(this.possibleCenters.length == 0))
8909 {
8910 return this.possibleCenters[0];
8911 }
8912
8913 throw "Couldn't find enough alignment patterns";
8914 }
8915
8916}
8917
8918function QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode)
8919{
8920 this.blockPointer = 0;
8921 this.bitPointer = 7;
8922 this.dataLength = 0;
8923 this.blocks = blocks;
8924 this.numErrorCorrectionCode = numErrorCorrectionCode;
8925 if (version <= 9)
8926 this.dataLengthMode = 0;
8927 else if (version >= 10 && version <= 26)
8928 this.dataLengthMode = 1;
8929 else if (version >= 27 && version <= 40)
8930 this.dataLengthMode = 2;
8931
8932 this.getNextBits = function( numBits)
8933 {
8934 var bits = 0;
8935 if (numBits < this.bitPointer + 1)
8936 {
8937 // next word fits into current data block
8938 var mask = 0;
8939 for (var i = 0; i < numBits; i++)
8940 {
8941 mask += (1 << i);
8942 }
8943 mask <<= (this.bitPointer - numBits + 1);
8944
8945 bits = (this.blocks[this.blockPointer] & mask) >> (this.bitPointer - numBits + 1);
8946 this.bitPointer -= numBits;
8947 return bits;
8948 }
8949 else if (numBits < this.bitPointer + 1 + 8)
8950 {
8951 // next word crosses 2 data blocks
8952 var mask1 = 0;
8953 for (var i = 0; i < this.bitPointer + 1; i++)
8954 {
8955 mask1 += (1 << i);
8956 }
8957 bits = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1));
8958 this.blockPointer++;
8959 bits += ((this.blocks[this.blockPointer]) >> (8 - (numBits - (this.bitPointer + 1))));
8960
8961 this.bitPointer = this.bitPointer - numBits % 8;
8962 if (this.bitPointer < 0)
8963 {
8964 this.bitPointer = 8 + this.bitPointer;
8965 }
8966 return bits;
8967 }
8968 else if (numBits < this.bitPointer + 1 + 16)
8969 {
8970 // next word crosses 3 data blocks
8971 var mask1 = 0; // mask of first block
8972 var mask3 = 0; // mask of 3rd block
8973 //bitPointer + 1 : number of bits of the 1st block
8974 //8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks)
8975 //numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block
8976 for (var i = 0; i < this.bitPointer + 1; i++)
8977 {
8978 mask1 += (1 << i);
8979 }
8980 var bitsFirstBlock = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1));
8981 this.blockPointer++;
8982
8983 var bitsSecondBlock = this.blocks[this.blockPointer] << (numBits - (this.bitPointer + 1 + 8));
8984 this.blockPointer++;
8985
8986 for (var i = 0; i < numBits - (this.bitPointer + 1 + 8); i++)
8987 {
8988 mask3 += (1 << i);
8989 }
8990 mask3 <<= 8 - (numBits - (this.bitPointer + 1 + 8));
8991 var bitsThirdBlock = (this.blocks[this.blockPointer] & mask3) >> (8 - (numBits - (this.bitPointer + 1 + 8)));
8992
8993 bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock;
8994 this.bitPointer = this.bitPointer - (numBits - 8) % 8;
8995 if (this.bitPointer < 0)
8996 {
8997 this.bitPointer = 8 + this.bitPointer;
8998 }
8999 return bits;
9000 }
9001 else
9002 {
9003 return 0;
9004 }
9005 }
9006 this.NextMode=function()
9007 {
9008 if ((this.blockPointer > this.blocks.length - this.numErrorCorrectionCode - 2))
9009 return 0;
9010 else
9011 return this.getNextBits(4);
9012 }
9013 this.getDataLength=function( modeIndicator)
9014 {
9015 var index = 0;
9016 while (true)
9017 {
9018 if ((modeIndicator >> index) == 1)
9019 break;
9020 index++;
9021 }
9022
9023 return this.getNextBits(qrcode.sizeOfDataLengthInfo[this.dataLengthMode][index]);
9024 }
9025 this.getRomanAndFigureString=function( dataLength)
9026 {
9027 var length = dataLength;
9028 var intData = 0;
9029 var strData = "";
9030 var tableRomanAndFigure = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', unescape('%24'), '%', '*', '+', '-', '.', '/', ':');
9031 do
9032 {
9033 if (length > 1)
9034 {
9035 intData = this.getNextBits(11);
9036 var firstLetter = Math.floor(intData / 45);
9037 var secondLetter = intData % 45;
9038 strData += tableRomanAndFigure[firstLetter];
9039 strData += tableRomanAndFigure[secondLetter];
9040 length -= 2;
9041 }
9042 else if (length == 1)
9043 {
9044 intData = this.getNextBits(6);
9045 strData += tableRomanAndFigure[intData];
9046 length -= 1;
9047 }
9048 }
9049 while (length > 0);
9050
9051 return strData;
9052 }
9053 this.getFigureString=function( dataLength)
9054 {
9055 var length = dataLength;
9056 var intData = 0;
9057 var strData = "";
9058 do
9059 {
9060 if (length >= 3)
9061 {
9062 intData = this.getNextBits(10);
9063 if (intData < 100)
9064 strData += "0";
9065 if (intData < 10)
9066 strData += "0";
9067 length -= 3;
9068 }
9069 else if (length == 2)
9070 {
9071 intData = this.getNextBits(7);
9072 if (intData < 10)
9073 strData += "0";
9074 length -= 2;
9075 }
9076 else if (length == 1)
9077 {
9078 intData = this.getNextBits(4);
9079 length -= 1;
9080 }
9081 strData += intData;
9082 }
9083 while (length > 0);
9084
9085 return strData;
9086 }
9087 this.get8bitByteArray=function( dataLength)
9088 {
9089 var length = dataLength;
9090 var intData = 0;
9091 var output = new Array();
9092
9093 do
9094 {
9095 intData = this.getNextBits(8);
9096 output.push( intData);
9097 length--;
9098 }
9099 while (length > 0);
9100 return output;
9101 }
9102 this.getKanjiString=function( dataLength)
9103 {
9104 var length = dataLength;
9105 var intData = 0;
9106 var unicodeString = "";
9107 do
9108 {
9109 intData = getNextBits(13);
9110 var lowerByte = intData % 0xC0;
9111 var higherByte = intData / 0xC0;
9112
9113 var tempWord = (higherByte << 8) + lowerByte;
9114 var shiftjisWord = 0;
9115 if (tempWord + 0x8140 <= 0x9FFC)
9116 {
9117 // between 8140 - 9FFC on Shift_JIS character set
9118 shiftjisWord = tempWord + 0x8140;
9119 }
9120 else
9121 {
9122 // between E040 - EBBF on Shift_JIS character set
9123 shiftjisWord = tempWord + 0xC140;
9124 }
9125
9126 //var tempByte = new Array(0,0);
9127 //tempByte[0] = (sbyte) (shiftjisWord >> 8);
9128 //tempByte[1] = (sbyte) (shiftjisWord & 0xFF);
9129 //unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte)));
9130 unicodeString += String.fromCharCode(shiftjisWord);
9131 length--;
9132 }
9133 while (length > 0);
9134
9135
9136 return unicodeString;
9137 }
9138
9139 this.__defineGetter__("DataByte", function()
9140 {
9141 var output = new Array();
9142 var MODE_NUMBER = 1;
9143 var MODE_ROMAN_AND_NUMBER = 2;
9144 var MODE_8BIT_BYTE = 4;
9145 var MODE_KANJI = 8;
9146 do
9147 {
9148 var mode = this.NextMode();
9149 //canvas.println("mode: " + mode);
9150 if (mode == 0)
9151 {
9152 if (output.length > 0)
9153 break;
9154 else
9155 throw "Empty data block";
9156 }
9157 //if (mode != 1 && mode != 2 && mode != 4 && mode != 8)
9158 // break;
9159 //}
9160 if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI)
9161 {
9162 /* canvas.println("Invalid mode: " + mode);
9163 mode = guessMode(mode);
9164 canvas.println("Guessed mode: " + mode); */
9165 throw "Invalid mode: " + mode + " in (block:" + this.blockPointer + " bit:" + this.bitPointer + ")";
9166 }
9167 dataLength = this.getDataLength(mode);
9168 if (dataLength < 1)
9169 throw "Invalid data length: " + dataLength;
9170 //canvas.println("length: " + dataLength);
9171 switch (mode)
9172 {
9173
9174 case MODE_NUMBER:
9175 //canvas.println("Mode: Figure");
9176 var temp_str = this.getFigureString(dataLength);
9177 var ta = new Array(temp_str.length);
9178 for(var j=0;j<temp_str.length;j++)
9179 ta[j]=temp_str.charCodeAt(j);
9180 output.push(ta);
9181 break;
9182
9183 case MODE_ROMAN_AND_NUMBER:
9184 //canvas.println("Mode: Roman&Figure");
9185 var temp_str = this.getRomanAndFigureString(dataLength);
9186 var ta = new Array(temp_str.length);
9187 for(var j=0;j<temp_str.length;j++)
9188 ta[j]=temp_str.charCodeAt(j);
9189 output.push(ta );
9190 //output.Write(SystemUtils.ToByteArray(temp_sbyteArray2), 0, temp_sbyteArray2.Length);
9191 break;
9192
9193 case MODE_8BIT_BYTE:
9194 //canvas.println("Mode: 8bit Byte");
9195 //sbyte[] temp_sbyteArray3;
9196 var temp_sbyteArray3 = this.get8bitByteArray(dataLength);
9197 output.push(temp_sbyteArray3);
9198 //output.Write(SystemUtils.ToByteArray(temp_sbyteArray3), 0, temp_sbyteArray3.Length);
9199 break;
9200
9201 case MODE_KANJI:
9202 //canvas.println("Mode: Kanji");
9203 //sbyte[] temp_sbyteArray4;
9204 //temp_sbyteArray4 = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getKanjiString(dataLength)));
9205 //output.Write(SystemUtils.ToByteArray(temp_sbyteArray4), 0, temp_sbyteArray4.Length);
9206 var temp_str = this.getKanjiString(dataLength);
9207 output.push(temp_str);
9208 break;
9209 }
9210 //
9211 //canvas.println("DataLength: " + dataLength);
9212 //Console.out.println(dataString);
9213 }
9214 while (true);
9215 return output;
9216 });
9217}
9218
9219function QRCodeScanner(width, height, container, success, error) {
9220 navigator.getUserMedia = navigator.getUserMedia ||
9221 navigator.webkitGetUserMedia ||
9222 navigator.mozGetUserMedia ||
9223 navigator.msGetUserMedia;
9224 window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
9225
9226 var _width = width;
9227 var _height = height;
9228 var _id_container = container;
9229 var _id_video = container + '_video';
9230 var _success = success;
9231 var _error = error;
9232
9233 var _container = document.getElementById(container);
9234 var _video = null;
9235 var _stream = null;
9236 var _canvas = null;
9237 var _ctx = null;
9238 var _interval = null;
9239
9240 function isCanvasSupported() {
9241 var elem = document.createElement('canvas');
9242 return !!(elem.getContext && elem.getContext('2d'));
9243 }
9244
9245 function canvasInit() {
9246 _canvas = document.createElement('canvas');
9247 _canvas.width = _width;
9248 _canvas.height = _height;
9249 _ctx = _canvas.getContext('2d');
9250 }
9251
9252 function captureToCanvas() {
9253 _ctx.drawImage(_video, 0, 0, _video.videoWidth, _video.videoHeight, 0, 0, _canvas.width, _canvas.height);
9254 qrcode.decode(_canvas.toDataURL());
9255 }
9256
9257 this.isSupported = function() {
9258 if (!isCanvasSupported()) return false;
9259 if (!navigator.getUserMedia) return false;
9260 return true;
9261 }
9262
9263 this.start = function() {
9264 if (_video) return;
9265 if (navigator.getUserMedia) {
9266 //Append the video element
9267 _container.innerHTML = '<video style="width:' + _width + 'px;height:' + _height + 'px" autoplay id="' + _id_video + '"></video>';
9268 _video = document.getElementById(_id_video);
9269
9270 navigator.getUserMedia(
9271 {video: true},
9272 function(stream) {
9273 _stream = stream;
9274 _video.src = window.URL.createObjectURL(stream) || stream;
9275
9276 setTimeout(function() {
9277 canvasInit();
9278 _interval = setInterval(captureToCanvas, 500);
9279 }, 250); // Needed to get videoWidth/videoHeight
9280 },
9281 function(error) {
9282 _container.innerHTML = '';
9283 _video = null;
9284 if (error && error.message)
9285 _error(error.message);
9286 else if (error && error.name)
9287 _error(error.name);
9288 else
9289 _error(error);
9290 });
9291
9292
9293 qrcode.callback = function(data) {
9294 if (data && data.indexOf('error') != 0) {
9295 stop();
9296 if (data.indexOf('bitcoin:') == 0)
9297 data = data.substring(8);
9298 _success(data);
9299 }
9300 };
9301 }else{
9302 _error('Sorry your browser is not supported. Please try Firefox, Chrome or safari.');
9303 }
9304 }
9305
9306 function stop() {
9307 if (_interval) {
9308 clearInterval(_interval);
9309 _interval = null;
9310 }
9311
9312 _container.innerHTML = '';
9313 _video = null;
9314
9315 try {
9316 if (_stream) {
9317 _stream.stop();
9318 _stream = null;
9319 }
9320 } catch (e) {
9321 console.log(e);
9322 _error(e);
9323 }
9324 }
9325 this.stop = stop;
9326}
9327
9328 </script>
9329 <style type="text/css">
9330.more { background: url("./images/plus.png") no-repeat left center; width: 17px; height: 17px; display: inline-block; float: right; }
9331.less { background: url("./images/minus.png") no-repeat left center; width: 17px; height: 17px; display: inline-block; float: right; }
9332a { position: relative; z-index: 20; text-decoration: none; color: #d58424; }
9333.right { text-align: right; }
9334.walletarea { display: none; border: 1px solid #BFBFBF; background-color: white; }
9335hr { margin: 20px 0; border-top: 1px dashed #008000; }
9336.keyarea { height: 110px; text-align: left; position: relative; padding: 25px 25px 10px; }
9337.keyarea .public { float: left; }
9338.keyarea .pubaddress { display: inline-block; height: 40px; padding: 0 0 0 10px; float: left; }
9339.keyarea .privwif { margin: 0; float: right; text-align: right; padding: 0 20px 0 0; position: relative; }
9340.keyarea .label { font-weight: bold; }
9341.keyarea .output { display: block; font-family: monospace; font-size: 1.25em; }
9342.keyarea .qrcode_public { display: inline-block; float: left; }
9343.keyarea .qrcode_private { display: inline-block; position: relative; top: 28px; float: right; }
9344.pubkeyhex { word-wrap: break-word; }
9345html { height: 100%; }
9346body { font-family: Arial; background-image: url('images/diamonds.png'); height: 100%; }
9347.faqs ol { padding: 0 0 0 25px; }
9348.faqs li { padding: 3px 0; }
9349.question { padding: 10px 15px; text-align: left; cursor: pointer; }
9350.question:hover, .expandable:hover { color: #77777A; }
9351.answer { padding: 0 15px 10px 25px; text-align: left; display: none; font-size: 80%; }
9352.faq { border: 0; border-top: 1px solid #BFBFBF; }
9353
9354#initBanner { position: relative; text-align: left; padding: 15px; background-color: white; border-bottom: 1px solid #bfbfbf; }
9355#walletCommands { display: none; }
9356#keyarea { display: none; }
9357
9358#faqZone { text-align: left; padding: 10px 30px 30px 30px; }
9359.faqQuestion { margin-left: 15px; }
9360.faqAnswer { margin-left: 30px; display: none; }
9361.faqListBullet { padding: 0 5px 0px 15px; }
9362.faqLink { cursor: pointer; }
9363
9364#btcaddress, #btcprivwif, #detailaddress, #detailaddresscomp, #detailprivwif, #detailprivwifcomp { font-family: monospace; font-size: 1.25em; }
9365#seedpoolarea { display: none; }
9366#seedpooldisplay { font-family: monospace; font-size: 1em; width: 640px; padding: 15px 5px; word-wrap: break-word; min-height: 98px; }
9367.seedpoint { width: 6px; height: 6px; display: block; border-radius: 3px; background-color: #80CF80; position: absolute; z-index: 10; }
9368
9369#seedSkipper { font-size: 11px; text-align: center; line-height: 14px;}
9370#skipMessage { margin-top: 8px; }
9371
9372#generate #mousemovelimit { font-size: 16px; color: #FFF; }
9373#rightArea { position: absolute; right: 66px; top: 62px; width: 170px; }
9374#progress-bar { width: 170px; background:#80CF80; position: relative; margin-bottom: 20px;
9375 -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;
9376 }
9377#progress-bar-percentage { background:#FFA247; padding: 3px 0px; text-align: center; height: 18px;
9378 -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;
9379 }
9380#progress-bar-percentage span { display: inline-block; position: absolute; width: 100%; left: 0; }
9381.nicerButton { font-size: 14px; }
9382
9383#generate { font-size: 13px; text-align: left; position: relative; padding: 20px; border: 1px solid #BFBFBF; background-color: white; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; }
9384#generate span { padding: 5px 5px 0 5px; }
9385#generatekeyinput { position: relative; z-index: 20; }
9386
9387#generatelabelbitcoinaddress, #generatelabelmovemouse, #generatelabelkeypress { font-size: 14px; font-family: monospace; }
9388#mousemovelimit { font-size: 16px; font-family: monospace; }
9389.frontPageText { position: relative; }
9390
9391h1 { margin: 0px; height: 91px; }
9392
9393#keyarea { height: 250px; border-bottom: 1px solid #bfbfbf; }
9394#keyarea .pubaddress { float: none; display: block; padding: 0; height: auto; }
9395#keyarea .label { text-decoration: none; }
9396#keyarea .privwif { float: none; text-align: right; position: relative; padding: 0; }
9397#keyarea .qrcode_public { float: none; display: block; padding: 13px 11px 11px 11px; }
9398#keyarea .qrcode_private { float: none; display: block; top: 0; text-align: right; padding: 13px 11px 11px 11px; }
9399#keyarea .private { width: 30%; display: table-cell; }
9400#keyarea .public { width: 30%; display: table-cell; }
9401#singlearea { font-size: 90%; display: block; }
9402#singlesecret { position: relative; top: -130px; float: right; right: 200px; color: red; font-weight: bolder; font-size: 200%; }
9403#singleshare { position: relative; top: -110px; float: left; left: 160px; color: green; font-weight: bolder; font-size: 200%; }
9404#singlesafety { text-align: left; border-bottom: 1px solid #bfbfbf; position: relative; min-height: 500px; }
9405
9406#singlesafety p { font-size: 13px; }
9407
9408.firstHalfSingleSafety, .secondHalfSingleSafety {
9409 -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
9410 -moz-box-sizing: border-box; /* Firefox, other Gecko */
9411 box-sizing: border-box; /* Opera/IE 8+ */
9412 display: inline-block;
9413 vertical-align: top;
9414 position: relative;
9415}
9416
9417.firstHalfSingleSafety { width: 50%; padding: 10px 30px 10px 30px; }
9418
9419 .secondHalfSingleSafety {
9420 width: 50%;
9421 padding: 20px;
9422 text-align: center;
9423 float: right;
9424 }
9425
9426.frontPageImage, .seedFrontPageImage {
9427 -webkit-border-radius: 10px;
9428 -moz-border-radius: 10px;
9429 border-radius: 10px;
9430}
9431.frontPageImage { width: 100%; }
9432.seedFrontPageImage { max-height: 340px; }
9433
9434.currencyNameColumn { min-width: 120px; }
9435
9436.securityChecklist {
9437 background-color: #FFE6C9;
9438 margin-top: 15px;
9439 padding: 20px;
9440 -webkit-border-radius: 10px;
9441 -moz-border-radius: 10px;
9442 border-radius: 10px;
9443 text-align: left;
9444}
9445
9446.supportedCurrenciesChecklist {
9447 background-color: #C2F2C3;
9448 margin-top: 10px;
9449 margin-bottom: 10px;
9450 padding: 20px;
9451 -webkit-border-radius: 10px;
9452 -moz-border-radius: 10px;
9453 border-radius: 10px;
9454 text-align: left;
9455}
9456
9457.supportedCurrenciesChecklist ul {
9458 list-style-type: none;
9459 padding-left: 14px;
9460}
9461
9462#supportedcurrencies {
9463 line-height: 20px;
9464 padding: 12px 12px 0;
9465}
9466
9467.frontPageInstructions {
9468 padding: 5px;
9469}
9470
9471.securityChecklist ul { padding: 5px 0 0 20px; }
9472.securityChecklist li { padding-left: 5px; margin-bottom: 10px; }
9473
9474.redText { color: red; }
9475.greenText { color: green; }
9476
9477#coinLogo { width: 55px; height: 55px; padding: 10px; position: absolute; top: 2px; left: 10px; }
9478#coinLogoImg { width: 100%; height: 100%; }
9479
9480.coinIcoin { width: 64px; height: 64px; padding: 10px; position: absolute; top: 272px; left: 48px; }
9481#coinImg { width: 100%; height: 100%; }
9482
9483#main { position: relative; text-align: center; margin: 0px auto; width: 1005px; }
9484#logo { width: 578px; height: 80px; }
9485
9486.backLogo { float: right; width: 50px; height: 50px; }
9487
9488#paperarea { min-height: 120px; display: none; }
9489#paperarea .keyarea { border: 1px solid #BFBFBF; border-top: 0; }
9490#paperarea .keyarea.art { display: block; height: auto; border: 0; font-family: Ubuntu, Arial; padding: 0; margin: 0; }
9491#paperarea .artwallet .papersvg { width: 1004px; height: 426px; border: 0; margin: 0; padding: 0; left: 0; }
9492#paperarea .artwallet .qrcode_public { top: 263px; left: 780px; z-index: 100; margin: 0; float: none; display: block; position: absolute; background-color: #FFFFFF;
9493 padding: 5px 5px 2px 5px; }
9494#paperarea .artwallet .qrcode_private { top: 37px; right: 446px; z-index: 100; margin: 0; float: none; display: block; position: absolute; background-color: #FFFFFF;
9495 padding: 5px 5px 2px 5px;
9496 -ms-transform: rotate(180deg); /* IE 9 */
9497 -webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
9498 transform: rotate(180deg);
9499 }
9500.supportWalletGenerator { margin: 30px; }
9501.errorMsg { color: red; text-align: center !important; width: 100% !important; padding-top: 15px !important; }
9502#paperarea .artwallet .btcaddress
9503{
9504 position: absolute; bottom: 88px; left: 874px; z-index: 100; font-size: 11px; background-color: transparent;
9505 font-weight: 100; color: #000000; margin: 0; width: 124px; height: 32px; text-align: center;
9506 word-wrap: break-word; font-family: Courier, monospace;
9507 -ms-transform: rotate(-90deg); /* IE 9 */
9508 -webkit-transform: rotate(-90deg); /* Chrome, Safari, Opera */
9509 transform: rotate(-90deg); font-family: Courier, monospace;
9510}
9511#paperarea .artwallet .btcprivwif
9512{
9513 position: absolute; top: 86px; right: 540px; z-index: 100; font-size: 11px; background-color: transparent;
9514 font-weight: 100; color: #000000; margin: 0; width: 124px; height: 32px; text-align: center;
9515 word-wrap: break-word;
9516 -ms-transform: rotate(90deg); /* IE 9 */
9517 -webkit-transform: rotate(90deg); /* Chrome, Safari, Opera */
9518 transform: rotate(90deg);
9519 font-family: Courier, monospace;
9520}
9521#paperarea .artwallet .btcencryptedkey
9522{
9523 position: absolute; top: 86px; right: 540px; z-index: 100; font-size: 11px; background-color: transparent;
9524 font-weight:100; color: #000000; margin: 0; width: 110px; height: 32px; text-align: center;
9525 word-wrap: break-word;
9526 -ms-transform: rotate(90deg); /* IE 9 */
9527 -webkit-transform: rotate(90deg); /* Chrome, Safari, Opera */
9528 transform: rotate(90deg);
9529 font-family: Courier, monospace;
9530}
9531#suppliedPrivateKey { width: 420px; }
9532#papergenerate { margin-left: 10px; margin-right: 0px;}
9533
9534.displayNone { displa: none; }
9535.redColor { color: red; }
9536.1percentwidth { width: 1%; }
9537.100pxwidth { width: 100px; }
9538
9539.paperWalletText { bottom: 8px; height: 156px; left: 339px; padding: 15px 15px 17px 37px; position: absolute; width: 265px; font-size: 10px; color: #383838; line-height: 15px; }
9540.paperWalletText ul { margin: 0px; padding: 0px; }
9541.paperWalletText li { line-height: 13px; margin-bottom: 5px; }
9542
9543.qrzone { margin: 20px 0px 20px 20px; }
9544#detaillabelenterprivatekey { margin-right: 15px; }
9545
9546.qrcodeinputwrapper { position: relative; margin-right: 15px; }
9547.qrcodeinputwrapper img { position: absolute; display: block; top: 3px; right: 20px; width: 16px; height: 16px;background: url("./images/qrcode.png"); cursor: pointer; padding: 0; }
9548
9549#bulkarea .body { padding: 5px 0 0 0; }
9550#bulkarea .format { font-style: italic; font-size: 90%; }
9551#bulktextarea { font-size: 90%; width: 98%; margin: 4px 0 0 0; }
9552#brainarea .keyarea { visibility: hidden; min-height: 110px; }
9553#detailarea span.qrinput { position: relative; padding: 10px; }
9554#detailarea span.qrinput #detailprivkey { width: 420px; height: 20px; }
9555#detailkeyarea { padding: 10px; }
9556#detailarea { margin: 0; text-align: left; }
9557#detailarea .notes { text-align: left; font-size: 80%; padding: 0 0 20px 0; }
9558#detailarea .pubqr .item .label { text-decoration: none; }
9559#detailarea .pubqr .item { float: left; margin: 10px 0; position: relative; }
9560#detailarea .pubqr .item.right { float: right; position: relative; top: 0; }
9561#detailarea .privqr .item .label { text-decoration: none; }
9562#detailarea .privqr .item { float: left; margin: 0; position: relative; }
9563#detailarea .privqr .item.right { float: right; position: relative; }
9564#detailarea .item { margin: 10px 0; position: relative; font-size: 90%; padding: 1px 0; }
9565#detailarea .item.clear { clear: both; padding-top: 10px; }
9566#detailarea .label { display: block; font-weight: bold; }
9567#detailarea .output { display: block; font-family: monospace; font-size: 1.25em; }
9568#detailarea #detailqrcodepublic { position: relative; float: left; margin: 0 10px 0 0; padding: 13px 11px 11px 11px; }
9569#detailarea #detailqrcodepubliccomp { position: relative; float: right; margin: 0 0 0 10px; padding: 13px 11px 11px 11px; }
9570#detailarea #detailqrcodeprivate { position: relative; float: left; margin: 0 10px 0 0; padding: 13px 11px 11px 11px; }
9571#detailarea #detailqrcodeprivatecomp { position: relative; float: right; margin: 0 0 0 10px; padding: 13px 11px 11px 11px; }
9572#detailpubkey { width: 590px; }
9573#detailbip38commands { display: none; padding-top: 5px; }
9574#paperqrscanner { position: absolute; display: none; width: 100%; height: 100%; top: 0; left: 0; z-index: 5000; vertical-aligh: middle; }
9575#paperqrscanner.show { display: block; }
9576
9577.englishjson { text-align: center; padding: 40px 0 20px 0; }
9578.unittests { text-align: center; }
9579.unittests div { width: 894px; font-family: monospace; text-align: left; margin: auto; padding: 5px; border: 1px solid black; }
9580#testnet { display: none; background-color: Orange; color: #000000; border-radius: 5px; font-weight: bold; padding: 10px 0; margin: 0 auto 20px auto; }
9581#busyblock { position: fixed; display: none; background: url("./images/busy.gif") #ccc no-repeat center; opacity: 0.4; width: 100%; height: 100%; top: 0; left: 0; z-index: 5000; }
9582#busyblock.busy { display: block; }
9583.hide { display: none; }
9584.show { display: block; }
9585.dialog { z-index: 6000; position: relative; background: white; border: 2px solid #f7931a; width: 600px; margin: 150px auto; padding: 1em; }
9586.dialog-narrow { width: 300px; }
9587
9588#currencyddl { margin: 20px; position: absolute; right: 0; top: 60px; width: 320px; font-size: 14px; }
9589#currencyddl select { font-size: 14px; }
9590
9591.banner { font-size: 46px; text-shadow: 1px 1px 3px #000; color: #FF9547; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8); text-align: left; position: relative; }
9592
9593#donateqrcode { padding: 8px; position: absolute; left: 550px; margin: 25px; border: black solid 1px; background-color: white; }
9594#donatelist { padding: 20px; }
9595
9596#donatearea { text-align: left; padding: 15px 15px 120px 15px; position: relative; }
9597#donatearea .address { font-family: 'Courier New', Courier, monospace; }
9598
9599/* IE8 */
9600.qrcodetable { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; }
9601.qrcodetddark { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #000000; }
9602.qrcodetdlight { border-width: 0px; border-style: none; border-color: #0000ff; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #ffffff; }
9603
9604@media screen
9605{
9606 #tagline { margin: 0 0 15px 0; font-style: italic; text-align: left; }
9607 .menu { text-align: left; }
9608 .menu .tab { border-top-left-radius: 5px; border-top-right-radius: 5px; display: inline-block; background-color: #F5F5F5;
9609 border: 1px solid #BFBFBF; padding: 5px; margin: 0 2px 0 0; position: relative; top: 1px; z-index: 110; cursor: pointer; }
9610 .menu .tab:hover { color: #d58424; }
9611 .menu .tab.selected { background-color: #FFF; border-bottom: 1px solid #FFF; cursor: default; }
9612 .menu .tab.selected:hover { color: #000; }
9613 .pagebreak { height: 50px; }
9614 .commands { border-bottom: 1px solid #BFBFBF; padding: 10px 2px; margin-bottom: 0; background-color: white; }
9615 .commands .row { padding: 0 0; text-align: left; }
9616 .commands .row.extra { padding-top: 6px; }
9617 .commands span { padding: 0 10px; }
9618 .commands span.print { float: right; }
9619 .commands span.right { float: right; }
9620 .expandable { padding: 10px 15px; text-align: left; cursor: pointer; }
9621
9622 #menu { visibility: hidden; font-size: 90%; }
9623 #culturemenu { text-align: right; padding: 0 20px; font-size: 14px; margin-bottom: 35px; }
9624 #culturemenu span { padding: 3px; }
9625 #culturemenu .selected { text-decoration: none; color: #000000; }
9626
9627 #braincommands .row .label { width: 200px; display: inline-block; }
9628 #braincommands .notes { font-size: 80%; display: block; padding: 5px 10px; }
9629 #brainpassphrase { width: 280px; }
9630 #brainpassphraseconfirm { width: 280px; }
9631 #brainwarning { }
9632 #detailcommands { padding: 10px 0; }
9633 #detailcommands span { padding: 0 10px; }
9634 #detailprivkey { width: 300px; }
9635 #detailprivkeypassphrase { width: 250px; }
9636 .paper .commands { border: 1px solid #BFBFBF; }
9637 #bulkstartindex { width: 35px; }
9638 #bulklimit { width: 45px; }
9639
9640 .footer { font-size: 90%; clear: both; width: 750px; padding: 10px 0 10px 0; margin: 50px auto auto auto; }
9641 .footer div span.item { margin: 10px; }
9642 .footer .authorbtc { float: left; width: 470px; }
9643 .footer .authorbtc span.item { text-align: left; display: block; padding: 0 20px; }
9644 .footer .authorbtc div { position: relative; z-index: 100; }
9645 .footer .authorpgp { position: relative; }
9646 .footer .authorpgp span.item { text-align: right; display: block; padding: 0 20px; }
9647 .footer .copyright { font-size: 80%; clear: both; padding: 5px 0; }
9648 .footer .copyright span { padding: 10px 2px; }
9649}
9650@media print
9651{
9652 body { -webkit-print-color-adjust: exact; width: 1000px; height: 450px;}
9653 #main { width: auto; }
9654 #singlearea { border: 0; }
9655 #singlesafety { border: 0; }
9656 #paperarea .keyarea:first-child { border-top: 1px solid #BFBFBF; }
9657 #paperarea .keyarea.art:first-child { border: 0; }
9658 .pagebreak { height: 1px; }
9659 .paper #logo { display: none; }
9660 .menu, .footer, .commands, #tagline, #faqs, #culturemenu { display: none; }
9661 #detailprivwif { width: 285px; word-wrap: break-word; }
9662 #detailprivwifcomp { width: 310px; word-wrap: break-word; text-align: right; }
9663 #detailarea .privqr .item.right { width: 310px; }
9664 #detailarea .privqr .item { width: 285px; }
9665 #detailarea .notes { display: none; }
9666 #seedpoolarea { display: none; }
9667 .faq { display: none; }
9668 .banner { display: none; }
9669 #currency { display: none; }
9670 #paperarea .artwallet .btcaddress, #paperarea .artwallet .btcprivwif { z-index: 999; }
9671 .paperWalletText { z-index: 999;}
9672 .dogeTag { display: none; }
9673}
9674
9675 </style>
9676</head>
9677<body onclick="SecureRandom.seedTime();" onmousemove="ninja.seeder.seed(event);">
9678 <div id="busyblock"></div>
9679 <div id="main">
9680 <div id="culturemenu">
9681 <span><a href="?culture=en" id="cultureen" class="selected">English</a></span> |
9682 <span><a href="?culture=fr" id="culturefr">Français</a></span> |
9683 <span><a href="?culture=ru" id="cultureru">РуÑÑкий</a></span> |
9684 <span><a href="?culture=es" id="culturees">Spanish</a></span> |
9685 </div>
9686
9687 <div class="banner">
9688 <div id="coinLogo">
9689 <img id="coinLogoImg" src="logos/bitcoin.png" alt="Universal Open Source Client-Side Wallet Generator" />
9690 </div>
9691 <h1>
9692 <img id="siteTitle" src="images/banner.png" alt="Bitcoin Paper Wallet Generator" />
9693 </h1>
9694 </div>
9695
9696 <div id="currencyddl" class="hide">
9697 <span id="choosecurrency" class="i18n">Choose currency</span> :
9698 <select id="currency" onchange="janin.currency.useCurrency(this.selectedIndex);"></select>
9699 </div>
9700
9701 <div id="seedpoolarea"><textarea rows="16" cols="62" id="seedpool"></textarea></div>
9702
9703 <div class="menu" id="menu">
9704 <div class="tab i18n selected" id="singlewallet" onclick="ninja.tabSwitch(this);">Single Wallet</div>
9705 <div class="tab i18n" id="paperwallet" onclick="ninja.tabSwitch(this);">Paper Wallet</div>
9706 <div class="tab i18n" id="bulkwallet" onclick="ninja.tabSwitch(this);">Bulk Wallet</div>
9707 <div class="tab i18n" id="brainwallet" onclick="ninja.tabSwitch(this);">Brain Wallet</div>
9708 <div class="tab i18n" id="detailwallet" onclick="ninja.tabSwitch(this);">Wallet Details</div>
9709 <div class="tab i18n" id="donate" onclick="ninja.tabSwitch(this);">Support</div>
9710 </div>
9711
9712 <div id="wallets">
9713 <div id="singlearea" class="walletarea">
9714
9715 <div id="initBanner">
9716 <span id="generatelabelbitcoinaddress" class="i18n">Generating new Address...</span><br />
9717 <span id="generatelabelmovemouse" class="i18n">MOVE your mouse around to add some extra randomness... </span><span id="mousemovelimit"></span><br />
9718 <span id="generatelabelkeypress" class="i18n">OR type some random characters into this textbox</span> <input type="text" id="generatekeyinput" onkeypress="ninja.seeder.seedKeyPress(event);" /><br />
9719 <div id="seedpooldisplay"></div>
9720
9721 <div id="rightArea">
9722 <div id="progress-bar" class="fullyRounded">
9723 <div id="progress-bar-percentage" class="fullyRounded 1percentwidth"></div>
9724 </div>
9725
9726 <div id="seedSkipper">
9727 <a href="#" class="nicerButton 100pxwidth" onClick="ninja.seeder.seedCount = ninja.seeder.seedLimit; ninja.seeder.seed();">Skip »</a>
9728 <p id="skipMessage" class="i18n">You may skip this step if you do not plan to use the random key generator.</p>
9729 </div>
9730 </div>
9731 </div>
9732
9733 <div id="walletCommands" class="commands">
9734 <div id="singlecommands" class="row">
9735 <span><input type="button" id="newaddress" value="Generate New Address" onclick="ninja.wallets.singlewallet.generateNewAddressAndKey();" /></span>
9736 <span class="print"><input type="button" name="print" value="Print" id="singleprint" onclick="window.print();" /></span>
9737 </div>
9738 </div>
9739 <div id="keyarea" class="keyarea">
9740 <div class="public">
9741 <div class="pubaddress">
9742 <span class="label i18n" id="singlelabelbitcoinaddress">Public Address</span>
9743 </div>
9744 <div id="qrcode_public" class="qrcode_public"></div>
9745 <div class="pubaddress">
9746 <span class="output" id="btcaddress"></span>
9747 </div>
9748 <div id="singleshare" class="i18n">SHARE</div>
9749 </div>
9750 <div class="private">
9751 <div class="privwif">
9752 <span class="label i18n" id="singlelabelprivatekey">Private Key (Wallet Import Format)</span>
9753 </div>
9754 <div id="qrcode_private" class="qrcode_private"></div>
9755 <div class="privwif">
9756 <span class="output" id="btcprivwif"></span>
9757 </div>
9758 <div id="singlesecret" class="i18n">SECRET</div>
9759 </div>
9760 </div>
9761
9762 <div id="singlesafety">
9763 <div class="firstHalfSingleSafety">
9764
9765 <h3 id="securitystep1title" class="i18n">Step 1. Generate new address</h3>
9766 <p id="securitystep1" class="i18n">
9767 Choose your currency and click on the "Generate new address" button.
9768 </p>
9769 <h3 id="securitystep2title" class="i18n">Step 2. Print the Paper Wallet</h3>
9770 <p id="securitystep2" class="i18n">
9771 Click the Paper Wallet tab and print the page on high quality setting. <strong>Never save the page as a PDF file to print it later since a file is more likely to be hacked than a piece of paper.</strong>
9772 </p>
9773 <h3 id="securitystep3title" class="i18n">Step 3. Fold the Paper Wallet</h3>
9774 <p id="securitystep3" class="i18n">
9775 Fold your new Paper wallet following the lines.
9776 <img src="images/foldinginstructions.png" alt="Fold in half lengthwise, and then in three widthwise." /><br />
9777 You can insert one side inside the other to lock the wallet.
9778 </p>
9779
9780 <h3 id="securitystep4title" class="i18n">Step 4. Share your public address</h3>
9781 <p id="securitystep4" class="i18n">
9782 Use your public address to receive money from other crypto-currency users. You can share your public address as much as you want.
9783 </p>
9784 <h3 id="securitystep5title" class="i18n">Step 5. Keep your private key secret</h3>
9785 <p id="securitystep5" class="i18n">
9786 The private key is literally the keys to your coins, if someone was to obtain it, they could withdraw the funds currently in the wallet, and any funds that might be deposited in that wallet.
9787 </p>
9788 <p>
9789 <strong id="securitystep6" class="i18n">Please test spending a small amount before receiving any large payments.</strong><br /><br />
9790 </p>
9791
9792
9793 </div>
9794 <div class="secondHalfSingleSafety">
9795 <img class="frontPageImage" src="images/overview.png" alt="Overview image of 4 paper wallet" />
9796
9797 <div class="securityChecklist">
9798 <b id="securitychecktitle" class="i18n">Security Checklist :</b>
9799
9800 <ul>
9801 <li id="browserSecurityCheck"></li>
9802
9803 <li id="securitychecklivecd" class="i18n">
9804 Are you using a secure operating system guaranteed to be free of spyware and viruses, for example, an Ubuntu LiveCD?
9805 </li>
9806 </ul>
9807 </div>
9808
9809 <div class="supportedCurrenciesChecklist">
9810 <b><span id="supportedcurrenciescounter"></span><span id="supportedcurrencylbl" class="i18n">supported currencies !</span></b>
9811 <div id="supportedcurrencies"></div>
9812 </div>
9813 </div>
9814 </div>
9815
9816 <div id="faqZone">
9817 <h2>Frequently asked questions :</h2>
9818
9819 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion1');ninja.toggleFaqQuestion('faqQuestion1.1')">• Is it safe ?</a></h3>
9820 <p class="faqAnswer" id="faqQuestion1">
9821 We try to make it that way ! The core of the tool, that generate the keys is 99% the same as the well reviewed bitaddress.org. We only changed it to be able to generate addresses for different crypto-currencies.
9822 </p>
9823 <p class="faqAnswer" id="faqQuestion1.1">
9824We think that having a unique generator for multiple currencies lead to a much better reviewed tool for all than having a myriad of half-backed generators.
9825Changes made to this generator are available on Github in small and divided commits and those are easy to review and reuse.
9826Walletgenerator.org use the same security measures as the original project. All-in-one html document, no ajax, no analytics, no external calls, no CDN that can inject anything they want. And trust us, we have seen some nasty things when reviewing some wallet generator.
9827 </p>
9828
9829 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion2');">• Why should I use a paper wallet ?</a></h3>
9830 <p class="faqAnswer" id="faqQuestion2">
9831 Advantages of a paper wallet are multiple:<br/><br/>
9832 <span class="faqListBullet">⇒</span> They are not subject to malwares and keyloggers<br/>
9833 <span class="faqListBullet">⇒</span> You don’t rely on a third party’s honesty or capacity to protect your coins<br/>
9834 <span class="faqListBullet">⇒</span> You won't lose your coins when your device break
9835 </p>
9836
9837 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion3');">• How to use a paper wallet ?</a></h3>
9838 <p class="faqAnswer" id="faqQuestion3">
9839 Once you have generated and printed a wallet, you can send coins to the public address, like for any wallet. Store your paper wallet securely. It contains everything that is needed to spend your funds. Consider using BIP38 to secure your paper wallet with a password.
9840 </p>
9841
9842 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion4');">• How to spend the coins stored in a paper wallet ?</a></h3>
9843 <p class="faqAnswer" id="faqQuestion4">
9844 You will need to import your private key in a real client, that you can download from the currency website. The exact method to do that will depend on the client. If there is no integrated method, you can usually fall back to the debug console and use the command “importprivkey [yourprivatekey]“.
9845 </p>
9846
9847 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion5');">• How walletgenerator.org is different than another wallet generator ?</a></h3>
9848 <p class="faqAnswer" id="faqQuestion5">
9849 It’s not that different. You will find another design for the paper wallet and some improvements here and there. The big difference is that this is a unique project for a lot of currencies, so more people can review it and check its safety.
9850 </p>
9851
9852 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion7');">• Can you add support for cryptocurrency XYZ ?</a></h3>
9853 <p class="faqAnswer" id="faqQuestion7">
9854 Absolutely ! To help us do that, you can <a href="https://docs.google.com/forms/d/1nPIvukVWxlaveUPEUAEhGKwvEuwJiPSgs5zc5LhDVpk/viewform">fill this form</a>. But keep in mind that there is some currency that we cannot support. If the developers made some change in the address format, we won’t hack the crypto core of the project and take the risk to tamper the security of the others currencies.
9855 You can also implement the support yourself by following this <a href="https://github.com/MichaelMure/WalletGenerator.net/wiki/How-to-add-a-new-currency">non-developer How-To</a>
9856 </p>
9857
9858 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion8');">• Why should I make a donation ?</a></h3>
9859 <p class="faqAnswer" id="faqQuestion8">
9860 Donations money are used to pay our hosting service provider, but it’ll also be used to make walletgenerator.org more secure as we plan to organize a CrowdCurity campain as soon as we get enough money to pay for it.
9861 </p>
9862
9863 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion9');">• I found a bug, what shall I do ?</a></h3>
9864 <p class="faqAnswer" id="faqQuestion9">
9865 You can report bugs using GitHub. You can also contact us using our Twitter account (<a href="http://twitter.com/WalletGenerator" target="_blank">@WalletGenerator</a>). Just try to explain clearly what is wrong and we will try to fix the bug as soon as possible.
9866 </p>
9867
9868 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion10');">• Who are you ?</a></h3>
9869 <p class="faqAnswer" id="faqQuestion10">
9870 We are just two random guy having fun with a side project.
9871 </p>
9872
9873 <h3 class="faqQuestion"><a class="faqLink" onclick="ninja.toggleFaqQuestion('faqQuestion11');">• How can I help ?</a></h3>
9874 <p class="faqAnswer" id="faqQuestion11">
9875 Donation are always welcome, but you can also help us translate the website. It's really easy. Just add "?i18nextract=LANGUAGECODE" in the end of the url (for instance http://walletgenerator.org/?i18nextract=es for Spanish). You will see at the end of the page a pre-filled javascript array ready to be translated. Translate or correct it, and send it to us the way you prefer. Even partial translation are helpful !
9876 </p>
9877
9878 </div>
9879 </div>
9880
9881 <div id="paperarea">
9882 <div class="commands">
9883 <div id="papercommands" class="row">
9884 <span><label id="paperlabelencrypt" for="paperencrypt" class="i18n">BIP38 Encrypt?</label> <input type="checkbox" id="paperencrypt" onchange="ninja.wallets.paperwallet.toggleEncrypt(this);" /></span>
9885 <span><label id="paperlabelBIPpassphrase" for="paperpassphrase" class="i18n">Passphrase:</label> <input type="text" id="paperpassphrase" /></span>
9886
9887 <br/>
9888 <input type="button" id="papergenerate" value="Randomly generate" onclick="ninja.wallets.paperwallet.build(document.getElementById('paperpassphrase').value);" />
9889 <span>OR</span>
9890 <input placeholder="Enter your own WIF private key" id="suppliedPrivateKey" name="suppliedPrivateKey" spellcheck="false" />
9891 <input type="button" id="papergenerate" value="Apply »" onClick="ninja.wallets.paperwallet.testAndApplyVanityKey();" />
9892
9893 <span class="print"><input type="button" name="print" value="Print" id="paperprint" onclick="window.print();" /></span>
9894 </div>
9895
9896 </div>
9897 <div id="paperkeyarea"></div>
9898 </div>
9899
9900 <div id="bulkarea" class="walletarea">
9901 <div class="commands">
9902 <div id="bulkcommands" class="row">
9903 <span><label id="bulklabelstartindex" for="bulkstartindex" class="i18n">Start index:</label> <input type="text" id="bulkstartindex" value="1" /></span>
9904 <span><label id="bulklabelrowstogenerate" for="bulklimit" class="i18n">Rows to generate:</label> <input type="text" id="bulklimit" value="3" /></span>
9905 <span><label id="bulklabelcompressed" for="bulkcompressed" class="i18n">Compressed addresses?</label> <input type="checkbox" id="bulkcompressed" /></span>
9906 <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>
9907 <span class="print"><input type="button" name="print" id="bulkprint" value="Print" onclick="window.print();" /></span>
9908 </div>
9909 </div>
9910 <div class="body">
9911 <span class="label i18n" id="bulklabelcsv">Comma Separated Values: Index,Address,Private Key (WIF)</span>
9912 <textarea rows="20" cols="88" id="bulktextarea"></textarea>
9913 </div>
9914 </div>
9915
9916 <div id="brainarea" class="walletarea">
9917 <div id="braincommands" class="commands">
9918 <div class="row">
9919 <span id="brainlabelenterpassphrase" class="label"><label id="brainlabelenterpassphraselbl" class="i18n" for="brainpassphrase">Enter Passphrase: </label></span>
9920 <input tabindex="1" type="password" id="brainpassphrase" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.brainwallet.view();" />
9921 <span><label id="brainlabelshow" for="brainpassphraseshow">Show?</label> <input type="checkbox" id="brainpassphraseshow" onchange="ninja.wallets.brainwallet.showToggle(this);" /></span>
9922 <span class="print"><input type="button" name="print" id="brainprint" value="Print" onclick="window.print();" /></span>
9923 </div>
9924 <div class="row extra">
9925 <span class="label" id="brainlabelconfirm"><label id="brainlabelconfirmlbl" class="i18n" for="brainpassphraseconfirm">Confirm Passphrase: </label></span>
9926 <input tabindex="2" type="password" id="brainpassphraseconfirm" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.brainwallet.view();" />
9927 <span><input tabindex="3" type="button" id="brainview" value="View" onclick="ninja.wallets.brainwallet.view();" /></span>
9928 <span id="brainalgorithm" class="notes right i18n">Algorithm: SHA256(passphrase)</span>
9929 </div>
9930 <div class="row extra"><span id="brainwarning"></span></div>
9931 <div class="row extra errorMsg"><span id="brainerror"></span></div>
9932 </div>
9933 <div id="brainkeyarea" class="keyarea">
9934 <div class="public">
9935 <div id="brainqrcodepublic" class="qrcode_public"></div>
9936 <div class="pubaddress">
9937 <span class="label i18n" id="brainlabelbitcoinaddress">Public Address:</span>
9938 <span class="output" id="brainbtcaddress"></span>
9939 </div>
9940 </div>
9941 <div class="private">
9942 <div id="brainqrcodeprivate" class="qrcode_private"></div>
9943 <div class="privwif">
9944 <span class="label i18n" id="brainlabelprivatekey">Private Key (Wallet Import Format):</span>
9945 <span class="output" id="brainbtcprivwif"></span>
9946 </div>
9947 </div>
9948 </div>
9949 </div>
9950
9951 <div id="detailarea" class="walletarea">
9952 <div id="detailcommands" class="commands">
9953
9954 <div class="row extra qrzone">
9955 <span class="qrinput">
9956 <label id="detaillabelenterprivatekey" for="detailprivkey" class="i18n">Enter Private Key</label>
9957
9958 <span class="qrcodeinputwrapper">
9959 <input type="text" id="detailprivkey" value="" placeholder="Enter a private key, or click the QR icon to scan" autocomplete="off" onFocus="this.select();" onKeyPress="if (event.keyCode == 13) ninja.wallets.detailwallet.viewDetails();" />
9960 <img onClick="ninja.wallets.detailwallet.qrscanner.start()" />
9961 </span>
9962
9963 <input type="button" id="detailview" value="View Details" onclick="ninja.wallets.detailwallet.viewDetails();" />
9964 </span>
9965 <span class="print">
9966 <input type="button" name="print" id="detailprint" value="Print" onclick="window.print();" />
9967 </span>
9968 </div>
9969
9970 <div id="paperqrscanner">
9971 <div class="background"></div>
9972 <div id="mainbody" class="dialog instructionsarea">
9973 <h2 id="qrcaminstructiontitle" class="i18n">Scan QR code using your camera</h2>
9974 <div id="paperqrnotsupported" class="hide redColor i18n">Sorry, but your web browser does not support the HTML5 camera controls. Try using a recent version of Firefox (recommended), Chrome or Opera.</div>
9975 <div id="paperqrpermissiondenied" class="hide redColor i18n">
9976 <p>Permission denied. Your browser should display a message requesting access to your camera. Please click the "Allow" button to enable the camera.</p>
9977 </div>
9978 <div id="paperqrerror" class="redColor"></div>
9979 <div id="paperqroutput"></div>
9980 <button onClick="ninja.wallets.detailwallet.qrscanner.stop()">Cancel</button>
9981 </div>
9982 </div>
9983 <div id="detailbip38commands">
9984 <span><label id="detaillabelpassphrase" class="i18n">Enter BIP38 Passphrase</label> <input type="text" id="detailprivkeypassphrase" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.detailwallet.viewDetails();" /></span>
9985 <span><input type="button" id="detaildecrypt" value="Decrypt BIP38" onclick="ninja.wallets.detailwallet.viewDetails();" /></span>
9986 </div>
9987 </div>
9988 <div id="detailkeyarea">
9989 <div class="notes">
9990 <span id="detaillabelnote1" class="i18n">Your 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 Public Address and Public Key that corresponds to your Private Key as well as your Private Key in the most popular encoding formats (WIF, WIFC, HEX, B64).</span>
9991 <br /><br />
9992 </div>
9993 <div class="pubqr">
9994 <div class="item">
9995 <span class="label i18n" id="detaillabelbitcoinaddress">Public Address</span>
9996 <div id="detailqrcodepublic" class="qrcode_public"></div>
9997 <span class="output" id="detailaddress"></span>
9998 </div>
9999 <div class="item right">
10000 <span class="label i18n" id="detaillabelbitcoinaddresscomp">Public Address Compressed</span>
10001 <div id="detailqrcodepubliccomp" class="qrcode_public"></div>
10002 <span class="output" id="detailaddresscomp"></span>
10003 </div>
10004 </div>
10005 <br /><br />
10006 <div class="item clear">
10007 <span class="label i18n" id="detaillabelpublickey">Public Key (130 characters [0-9A-F]):</span>
10008 <span class="output pubkeyhex" id="detailpubkey"></span>
10009 </div>
10010 <div class="item">
10011 <span class="label i18n" id="detaillabelpublickeycomp">Public Key (compressed, 66 characters [0-9A-F]):</span>
10012 <span class="output" id="detailpubkeycomp"></span>
10013 </div>
10014 <hr />
10015 <div class="privqr">
10016 <div class="item">
10017 <span class="label"><span id="detaillabelprivwif" class="i18n">Private Key WIF<br />51 characters Base58</span></span>
10018 <div id="detailqrcodeprivate" class="qrcode_private"></div>
10019 <span class="output" id="detailprivwif"></span>
10020 </div>
10021 <div class="item right">
10022 <span class="label"><span id="detaillabelprivwifcomp" class="i18n">Private Key WIF Compressed<br />52 characters Base58</span></span>
10023 <div id="detailqrcodeprivatecomp" class="qrcode_private"></div>
10024 <span class="output" id="detailprivwifcomp"></span>
10025 </div>
10026 </div>
10027 <br /><br />
10028 <div class="item clear">
10029 <span class="label i18n" id="detaillabelprivhex">Private Key Hexadecimal Format (64 characters [0-9A-F]):</span>
10030 <span class="output" id="detailprivhex"></span>
10031 </div>
10032 <div class="item">
10033 <span class="label i18n" id="detaillabelprivb64">Private Key Base64 (44 characters):</span>
10034 <span class="output" id="detailprivb64"></span>
10035 </div>
10036 <div class="item displayNone" id="detailmini">
10037 <span class="label i18n" id="detaillabelprivmini">Private Key Mini Format (22, 26 or 30 characters):</span>
10038 <span class="output" id="detailprivmini"></span>
10039 </div>
10040 <div class="item displayNone" id="detailb6">
10041 <span class="label i18n" id="detaillabelprivb6">Private Key Base6 Format (99 characters [0-5]):</span>
10042 <span class="output" id="detailprivb6"></span>
10043 </div>
10044 <div class="item displayNone" id="detailbip38">
10045 <span class="label i18n" id="detaillabelprivbip38">Private Key BIP38 Format (58 characters Base58):</span>
10046 <span class="output" id="detailprivbip38"></span>
10047 </div>
10048 </div>
10049 <div class="faqs">
10050 <div id="detailfaq1" class="faq">
10051 <div id="detailq1" class="question" onclick="ninja.wallets.detailwallet.openCloseFaq(1);">
10052 <span id="detaillabelq1" class="i18n">How do I make a wallet using dice? What is B6?</span>
10053 <div id="detaile1" class="more"></div>
10054 </div>
10055 <div id="detaila1" class="answer i18n">An important part of creating a crypto-currency wallet is ensuring the random numbers used to create the wallet are truly random. Physical randomness is better than computer generated pseudo-randomness. The easiest way to generate physical randomness is with dice. To create a crypto-currency private key you only need one six sided die which you roll 99 times. Stopping each time to record the value of the die. When recording the values follow these rules: 1=1, 2=2, 3=3, 4=4, 5=5, 6=0. By doing this you are recording the big random number, your private key, in B6 or base 6 format. You can then enter the 99 character base 6 private key into the text field above and click View Details. You will then see the public address associated with your private key. You should also make note of your private key in WIF format since it is more widely used.</div>
10056 </div>
10057 </div>
10058 </div>
10059
10060 <div id="donatearea" class="walletarea">
10061 <div id="donatetextfooter" class="i18n">To support the development of this wallet generator, you can donate to the following addresses. When the support for a currency has been added by an external contributor to the project, he receives the donation directly. </div>
10062 <div id="donatelist"></div>
10063 <div id="donateqrcode"></div>
10064 <div id="donateinfo"></div>
10065 <div id="changelog">
10066 <hr/>
10067 <h3>Release notes</h3>
10068 <p>
10069 01.2017 --
10070 <ul>
10071 <li>Add support for Espers. Contribution from ctgiant.</li>
10072 <li>Add support for Vcash, Dogecoin testnet and BitSynq. Contribution from tloriato.</li>
10073 <li>Add support for Deutsche eMark. Contribution from xBlackEye.</li>
10074 <li>Add support for MintCoin. Contribution from Fuzzbawls.</li>
10075 <li>Add support for IncaKoin. Contribution from WorldBot.</li>
10076 <li>Add support for Aquariuscoin, Lanacoin, Tajcoin and Nevacoin. Contribution from cryptosi.</li>
10077 <li>Add support for DigiByte. Contribution from Maurice van Beurden.</li>
10078 <li>Add support for Emerald. contribution from Paraskewas Zormbalas.</li>
10079 </ul>
10080 <p>
10081 05.2016 --
10082 <ul>
10083 <li>Add support for ParkByte. Contribution from ParkByte.</li>
10084 <li>Add support for BlackJack. Contribution from BlackJackDev.</li>
10085 <li>Add support for SecKCoin. Contribution from hevsnt.</li>
10086 <li>Add support for CashCoin. Contribution from BigDig.</li>
10087 <li>Add support for iCash. Contribution from Alexander Pochtov.</li>
10088 </ul>
10089 02.2016 --
10090 <ul>
10091 <li>Add support for TransferCoin. Contribution from Stoner19.</li>
10092 <li>Add support for BitcoinDark and Spreadcoin. Contribution from vx28643.</li>
10093 <li>Rename Guldencoin to Gulden. Contribution from mjmacleod.</li>
10094 </ul>
10095 <p>
10096 11.2015 --
10097 <ul>
10098 <li>Add support for Neoscoin, Rubycoin, Influxcoin and Hyperstake. Contribution from Stoner19.</li>
10099 </ul>
10100 <p>
10101 10.2015 --
10102 <ul>
10103 <li>Add support for SibCoin. Contribution from testzcrypto.</li>
10104 <li>Replace Gridcoin with GridcoinResearch. Contribution from esspam.</li>
10105 <li>Add support for CryptoClub. Contribution from cryptoclubber.</li>
10106 <li>Add support for Capricoin. contribution from Jackie Love4u.</li>
10107 <li>Add support for CryptoBullion, contribution from John Sacco.</li>
10108 <li>Update FuelCoin logo. contribution from Jackie Love4u.</li>
10109 <li>Add support for MartexCoin. contribution from MartexCoin.</li>
10110 <li>Add support for GabenCoin. contribution from Jan Visser.</li>
10111 </ul>
10112 <p>
10113 08.2015 --
10114 <ul>
10115 <li>Add support for masterdoge. Contribution from koad.</li>
10116 <li>New translation in Spanish ! Contribution from PrAeToRiAn.</li>
10117 <li>Improved Russian translation. Contribution from UdjinM6.</li>
10118 <li>Fixed Fujicoin address generation. Contribution from Fujicoin.</li>
10119 </ul>
10120 <p>
10121 07.2015 --
10122 <ul>
10123 <li>Add support for Animecoin, EnergyCoin and USDe. Contribution from TestZ.</li>
10124 <li>Add support for LiteDoge, Pesetacoin, Syscoin and Viacoin. Contribution from Puppy Firelyte.</li>
10125 </ul>
10126 <p>
10127 05.2015 --
10128 <ul>
10129 <li>Add support for Emercoin. Contribution from vx28643.</li>
10130 </ul>
10131 <p>
10132 05.2015 --
10133 <ul>
10134 <li>New translation in russian ! Contribution from UdjinM6.</li>
10135 <li>Darkcoin rebranded as Dash. Contribution from UdjinM6.</li>
10136 <li>Add support for Cryptoescudo, Fujicoin and Sambacoin. Contribution from Marcdnd.</li>
10137 </ul>
10138 <p>
10139 04.2015 --
10140 <ul>
10141 <li>Add support for Omnicoin. Contribution from MeshCollider.</li>
10142 <li>Add support for Canada eCoin. Contribution from koad</li>
10143 </ul>
10144 <p>
10145 03.2015 --
10146 <ul>
10147 <li>Add support for PhoenixCoin. Contribution from rekkitcwts.</li>
10148 </ul>
10149 <p>
10150 02.2015 --
10151 <ul>
10152 <li>Add support for DogecoinDark, Riecoin, and WorldCoin. Contribution from rekkitcwts.</li>
10153 </ul>
10154 <p>
10155 02.2015 --
10156 <ul>
10157 <li>Add support for Quark, CannabisCoin and SongCoin. Contribution from rekkitcwts.</li>
10158 </ul>
10159 <p>
10160 12.2014 --
10161 <ul>
10162 <li>Add support for DeafDollars, MobiusCoin, BunnyCoin, Ocupy, FUDcoin, StealthCoin, Rimbit, Paycoin and MonetaryUnit.</li>
10163 </ul>
10164 <p>
10165 11.2014 --
10166 <ul>
10167 <li>Add support for IridiumCoin, Latium, Magicoin, Nubits, TittieCoin, WankCoin, HamRadioCoin, ImperiumCoin, IncognitoCoin and Mooncoin</li>
10168 <li>HTTPS support is here !</li>
10169 </ul>
10170 <p>
10171 10.2014 --
10172 <ul>
10173 <li>Add support for Jumbucks. Contribution from Julian Yap.</li>
10174 </ul>
10175 <p>
10176 10.2014 --
10177 <ul>
10178 <li>Add support for HTML5Coin, W2Coin, PandaCoin, ACoin, Fibre, and Titcoin.</li>
10179 <li>Remove support fo HTMLCoin</li>
10180 </ul>
10181 <p>
10182 09.2014 --
10183 <ul>
10184 <li>Add support for eKrona, Mazacoin, iXcoin, eGulden and Potcoin.</li>
10185 </ul>
10186 <p>
10187 08.2014 --
10188 <ul>
10189 <li>Enter your own private key to print a paper wallet, and BIP38 encrypt them as well !</li>
10190 <li>Add support for Apexcoin, Cassubian Detk, Freicoin, Judgecoin, Myriadcoin and Onyxcoin.</li>
10191 </ul>
10192 <p>
10193 07.2014 --
10194 <ul>
10195 <li>Add support for Unobtanium, WeAreSatoshi Coin, Zetacoin, Vikingcoin, Guldencoin, PHCoin and Fuelcoin.</li>
10196 </ul>
10197 <p>
10198 07.2014 --
10199 <ul>
10200 <li>Fix a vulnerability that lead to the generation of less random wallet that normal on old browser. If you use a browser older than the mentionned version/date, we advise you to regenerate your wallets.
10201 <ul>
10202 <li>Firefox 21: may 2013</li>
10203 <li>Chrome 11: april 2011</li>
10204 <li>IE 11: october 2013</li>
10205 <li>Opera 14: july 2013</li>
10206 <li>Safari 3.1: march 2008</li>
10207 </ul>
10208 </li>
10209 <li>Added a Frequently Asked Question section on the main page</li>
10210 </ul>
10211 <p>
10212 06.2014 --
10213 <ul>
10214 <li>Add support for GlobalBoost, Fluttercoin, Guncoin and Birdcoin.</li>
10215 </ul>
10216 <p>
10217 06.2014 --
10218 <ul>
10219 <li>Add support for Monocle, TreasureHuntCoin and GoodCoin.</li>
10220 </ul>
10221 <p>
10222 05.2014 --
10223 <ul>
10224 <li>Add support for Gridcoin and Fastcoin.</li>
10225 </ul>
10226 <p>
10227 05.2014 --
10228 <ul>
10229 <li>Add support for 11 new currencies (42coin, Alphacoin, Anoncoin, Corgicoin, Darkcoin, Devcoin, Digitalcoin, HTMLCoin, Magic Internet Money, Megacoin and Novacoin).</li>
10230 <li>Ability to scan a QRCode with your webcam to check the wallet details.</li>
10231 <li>New design for Peercoin and Dogecoin paperwallets, such wow.</li>
10232 </ul>
10233 <p>
10234 04.2014 --
10235 <ul>
10236 <li>Bring back the wallet details to decrypt Bip38 encoded wallet.</li>
10237 <li>Add a button to skip the seeding. Don't skip if you intend to use the generated wallet !</li>
10238 <li>Fix a display bug for a Bip38 encoded paper wallet.</li>
10239 </ul>
10240 <p>
10241 04.2014 --
10242 <ul>
10243 <li>Add support for Blackcoin and Primecoin</li>
10244 <li>Add direct access to a currency. Example: <a href="http://walletgenerator.org/?currency=Vertcoin">http://walletgenerator.org/?currency=Vertcoin</a></li>
10245 </ul>
10246 <p>
10247 04.2014 --
10248 <ul>
10249 <li>Multi-currency support with 13 different currencies</li>
10250 <li>Original design for the paper wallet</li>
10251 <li>Improved design of the website</li>
10252 <li>Security checklist and more user-friendly explanations</li>
10253 </ul>
10254 </div>
10255 </div>
10256 </div>
10257
10258 <div id="footer" class="footer">
10259 <div>
10260 <span class="item"><a id="footersupport" href="#" onclick="ninja.tabSwitch(document.getElementById('donate'));" class="i18n">Support WalletGenerator.org</a></span>
10261 <span class="item"><a href="https://twitter.com/WalletGenerator">@WalletGenerator</a></span>
10262 </div>
10263 <div class="copyright">
10264 <span id="footerlabelcopyright1">Copyright WalletGenerator.org.</span>
10265 <span id="footerlabelcopyright2" class="i18n">JavaScript copyrights are included in the source.</span>
10266 <span id="footerlabelnowarranty" class="i18n">No warranty.</span>
10267 </div>
10268 </div>
10269 </div>
10270
10271 <script type="text/javascript">
10272(function (window) {
10273 var muchIndex = 0;
10274 var wowLength = 0;
10275 var manyWords = null;
10276 var suchInterval = null;
10277 var muchPlay = false;
10278 var wowElement = document.createElement('div');
10279 var suchColors = [
10280 '#FF0000',
10281 '#00FF00',
10282 '#0000FF',
10283 ];
10284
10285 function veryRandom(val) {
10286 return Math.floor((Math.random() * val));
10287 }
10288
10289 function placeWord(word) {
10290
10291 var muchWidth = window.innerWidth - 200; //Very random offset
10292 var manyHeight = window.innerHeight - 26; //Such fontsize based offset
10293
10294 wowElement.textContent = word;
10295 wowElement.style.left = veryRandom(muchWidth) + 'px';
10296 wowElement.style.top = veryRandom(manyHeight) + 'px';
10297 wowElement.style.color = suchColors[veryRandom(suchColors.length)];
10298 }
10299
10300 function muchWords() {
10301 muchPlay = true;
10302 suchInterval = setInterval(function () {
10303
10304 if(muchIndex === wowLength - 1) {
10305 muchIndex = 0;
10306 } else {
10307 muchIndex++;
10308 }
10309
10310 placeWord(manyWords[muchIndex]);
10311
10312 }, 6000);
10313
10314 }
10315
10316 var Doge = function (words) {
10317 if (typeof(words) !== 'object' || words.length === undefined) {
10318 return console.error('Wow. Words is not array. Much Error.');
10319 }
10320
10321 if (words.length < 1) {
10322 return console.error('Much dumb. Very fail. No words in array. Wow');
10323 }
10324
10325 wowLength = words.length;
10326 manyWords = words;
10327
10328 wowElement.className = 'dogeTag';
10329 wowElement.style.position = 'fixed';
10330 wowElement.style.fontSize = '26px';
10331 wowElement.style.fontFamily = '"Comic Sans MS"';
10332 wowElement.style.zIndex = 10000001;
10333 document.body.appendChild(wowElement);
10334 muchWords();
10335 };
10336
10337 Doge.prototype.stop = function () {
10338 if (muchPlay) {
10339 muchPlay = false;
10340 clearInterval(suchInterval);
10341 }
10342 if(wowElement != null)
10343 wowElement.parentNode.removeChild(wowElement);
10344 };
10345
10346 window.Doge = Doge;
10347
10348}(window));
10349 </script>
10350 <script type="text/javascript">
10351var janin = {};
10352
10353janin.currency = {
10354 createCurrency: function (name, networkVersion, privateKeyPrefix, WIF_Start, CWIF_Start, donate) {
10355 var currency = {};
10356 currency.name = name;
10357 currency.networkVersion = networkVersion;
10358 currency.privateKeyPrefix = privateKeyPrefix;
10359 currency.WIF_Start = WIF_Start;
10360 currency.CWIF_Start = CWIF_Start;
10361 currency.donate = donate;
10362 return currency;
10363 },
10364
10365 name: function() {
10366 return janin.selectedCurrency.name;
10367 },
10368
10369 networkVersion: function() {
10370 return janin.selectedCurrency.networkVersion;
10371 },
10372
10373 privateKeyPrefix: function() {
10374 return janin.selectedCurrency.privateKeyPrefix;
10375 },
10376
10377 WIF_RegEx: function() {
10378 return new RegExp("^" + janin.selectedCurrency.WIF_Start + "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$");
10379 },
10380
10381 CWIF_RegEx: function() {
10382 return new RegExp("^" + janin.selectedCurrency.CWIF_Start + "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$");
10383 },
10384
10385 // Switch currency
10386 useCurrency: function(index) {
10387 janin.selectedCurrency = janin.currencies[index];
10388
10389 var coinImgUrl = "logos/" + janin.currency.name().toLowerCase() + ".png";
10390 document.getElementById("coinLogoImg").src = coinImgUrl;
10391
10392 // Update title depending on currency
10393 document.title = janin.currency.name() + " " + ninja.translator.get("title");
10394 document.getElementById("siteTitle").alt = janin.currency.name() + " " + ninja.translator.get("title");
10395
10396 // Update i18n link
10397 document.getElementById("cultureen").href = "?culture=en¤cy=" + janin.currency.name().toLowerCase();
10398 document.getElementById("culturefr").href = "?culture=fr¤cy=" + janin.currency.name().toLowerCase();
10399 document.getElementById("cultureru").href = "?culture=ru¤cy=" + janin.currency.name().toLowerCase();
10400 document.getElementById("culturees").href = "?culture=es¤cy=" + janin.currency.name().toLowerCase();
10401
10402 if(ninja.seeder.isDone())
10403 {
10404 // Regenerate a new wallet when not expensive
10405 ninja.wallets.singlewallet.generateNewAddressAndKey();
10406 ninja.wallets.paperwallet.build(document.getElementById('paperpassphrase').value);
10407 ninja.wallets.brainwallet.view();
10408 }
10409
10410 // Reset wallet tab when expensive or not applicable
10411 document.getElementById("bulktextarea").value = "";
10412 document.getElementById("suppliedPrivateKey").value = "";
10413
10414 // easter egg doge ;)
10415 if(janin.currency.name() == "Dogecoin")
10416 {
10417 janin.doge = new Doge(['wow', 'so paper wallet', 'such random', 'very pretty', 'much design', 'awesome', 'much crypto', 'such coin', 'wow!!', 'to da moon']);
10418 return;
10419 }
10420
10421 if(janin.doge != null)
10422 {
10423 janin.doge.stop();
10424 janin.doge = null;
10425 }
10426 },
10427};
10428
10429janin.currencies = [
10430 // name, networkVersion, privateKeyPrefix, WIF_Start, CWIF_Start, donate
10431 janin.currency.createCurrency ("42coin", 0x08, 0x88, "5", "M" , "4Fs42jYtLYrUMfKEXc6arojuhRsnYnerxN"),
10432 janin.currency.createCurrency ("Acoin", 0x17, 0xe6, "8", "b" , "AJvChtExuvLgAor9aw1Xz9bkvJY7JKD9uL"),
10433 janin.currency.createCurrency ("Alphacoin", 0x52, 0xd2, "8", "Y" , "aAWhiGBDUugXC9ZBvw8CDNQH7KRurjy4Nq"),
10434 janin.currency.createCurrency ("Animecoin", 0x17, 0x97, "6", "P" , "AdA5nLS5FtPws6A3BX8aXccbP7fReptdw7"),
10435 janin.currency.createCurrency ("Anoncoin", 0x17, 0x97, "6", "P" , "AS3BvkE4wvsXJpn1bGhQni5vZajthnrWQE"),
10436 janin.currency.createCurrency ("Apexcoin", 0x17, 0x97, "6", "P" , "AdPxUCGLDUhHUTGYftffwFVdxbFy2nkXGX"),
10437 janin.currency.createCurrency ("Auroracoin", 0x17, 0x97, "6", "T" , "AVWH1ZutLd4Y5LPDDj5FkBjbm2Gci4iFx3"),
10438 janin.currency.createCurrency ("Aquariuscoin", 0x17, 0x97, "6", "P" , "ARk4VoaCHDoPDn2dctGizJaHFvXNRiDUDr"),
10439 janin.currency.createCurrency ("BBQcoin", 0x55, 0xd5, "6", "T" , "bTFFC3Gg2XzQygLxxakHkNM3ravBZby1y9"),
10440 janin.currency.createCurrency ("Bitcoin", 0x00, 0x80, "5", "[LK]" , "15DHZzv7eBUwss77qczZiL3DUEZLjDYhbM"),
10441 janin.currency.createCurrency ("BitcoinDark", 0x3c, 0xbc, "7", "U" , "RWtY5fg9ZQ9tYaPd7WJLgsdae1m1ZfrVRe"),
10442 janin.currency.createCurrency ("Birdcoin", 0x2f, 0xaf, "6", "[ST]" , "L97vGT4wRnyyiugHpLXzZzjqueN8YWRdRJ"),
10443 janin.currency.createCurrency ("BitSynq", 0x3f, 0xbf, "7", "V" , "SRtKRZxSjjwb9BXujkmvLfRHiutk7s7VXh"),
10444 janin.currency.createCurrency ("Blackcoin", 0x19, 0x99, "6", "P" , "BFeJrZGyJ6bntd7RLXoNGvdn1HB5AQeiz4"),
10445 janin.currency.createCurrency ("BlackJack", 0x15, 0x95, "[56]", "P" , "9pzHRZkJ4Df3EBiqXhDVgtB2A7FaAq6nnG"),
10446 janin.currency.createCurrency ("BunnyCoin", 0x1a, 0x9a, "6", "P" , "BosRXiiSB6WmiSbvzVAdUjpezCWhqpJGyW"),
10447 janin.currency.createCurrency ("CanadaeCoin", 0x1c, 0x9c, "6", "Q" , "CbaoyW9KYP8qQHb9Lu59crvjemryCD88Hv"),
10448 janin.currency.createCurrency ("CannabisCoin", 0x1c, 0x9c, "6", "Q" , "Cb7SSkHpnk1PwKqKbreMALzJpnmAsBNvnG"),
10449 janin.currency.createCurrency ("Capricoin", 0x1c, 0x9c, "6", "Q" , "CS1mBL1dyCR8jH5hRrQiZ4Xz37UWwcbUAJ"),
10450 janin.currency.createCurrency ("CassubianDetk", 0x1e, 0x9e, "6", "Q" , "DBPagysmjfdkND4Zp1SM4myLenNfXpFWnG"),
10451 janin.currency.createCurrency ("CashCoin", 0x22, 0xa2, "6", "[QR]" , "F3bkQC7xGZZcPFmsucYas7KuHoEwCPtGHC"),
10452 janin.currency.createCurrency ("Catcoin", 0x15, 0x95, "[56]", "P" , "9rEXDemG6S3k2ddAsKFzRpnMVz3bVryYXZ"),
10453 janin.currency.createCurrency ("Corgicoin", 0x1c, 0x9c, "6", "Q" , "CNwV11TaKrfB3TnBS8vQjNbWT6CNxV8GBi"),
10454 janin.currency.createCurrency ("CryptoBullion", 0xb, 0x8b, "5", "M" , "Cd9CgzTChm9yJQZ3SL3PUSsMkEEN8LGwCF"),
10455 janin.currency.createCurrency ("CryptoClub", 0x23, 0xa3, "6", "R" , "FKPFTw5LjoeGTZP1d3zHLfZNm91FktgPWY"),
10456 janin.currency.createCurrency ("Cryptoescudo", 0x1c, 0x9c, "6", "Q" , "Cd9CgzTChm9yJQZ3SL3PUSsMkEEN8LGwCF"),
10457 janin.currency.createCurrency ("Dash", 0x4c, 0xcc, "7", "X" , "XdYX6AbDzjb3AVL1tAmWjuYMD28LD9fcWS"),
10458 janin.currency.createCurrency ("DeafDollars", 0x30, 0xb0, "6", "T" , "LNHYnoqySwoN5aMyEVavEBT3CxHA9WrTZs"),
10459 janin.currency.createCurrency ("Deutsche eMark", 0x35, 0xb5, "7", "T" , "Ni4112Tmv1ScZ9fkN76knJ4jRTxeHQieJM"),
10460 janin.currency.createCurrency ("Devcoin", 0x00, 0x80, "5", "[LK]" , "1GUeBfpVhN7xySQej3HiSe5c8jQoVQPosv"),
10461 janin.currency.createCurrency ("DigiByte", 0x1e, 0x9e, "6", "Q" , "D9s71nQPBCEbM2SvGwHQcrhay6KrJaVo3Z"),
10462 janin.currency.createCurrency ("Digitalcoin", 0x1e, 0x9e, "6", "Q" , "D7fJwPfW4dFSJNq4NHbMiYJhYnrZehMpqx"),
10463 janin.currency.createCurrency ("Dogecoin", 0x1e, 0x9e, "6", "Q" , "D74Npoqhwhjw9fShkm5wbj6DD2BJXpmzPj"),
10464 janin.currency.createCurrency ("DogecoinDark", 0x1e, 0x9e, "6", "Q" , "DLbjdRYsfiT62JZf5YxSAfNZJo1VKxDTNP"),
10465 janin.currency.createCurrency ("eGulden", 0x30, 0xb0, "6", "T" , "LhBsKs2GUb24KBAzZfua5AsqfQF5uPdWXQ"),
10466 janin.currency.createCurrency ("eKrona", 0x2d, 0xad, "6", "S" , "KLi8FnMZmSH8EfXYgJwi4R2ZyMscJykXT5"),
10467 janin.currency.createCurrency ("Emerald", 0x22, 0xa2, "6", "[QR]" , "EnJnzAQSpPp7RshMhNx9zhRnabxTLird6W"),
10468 janin.currency.createCurrency ("Emercoin", 0x21, 0xa1, "6", "Q" , "EN5nVyEbLrhYfcjoyGgQFtD3QHETyj1dy1"),
10469 janin.currency.createCurrency ("EnergyCoin", 0x5c, 0xdc, "8", "Z" , "eD2P3q5PdyHYNwT94Dg6Wt4pBz64k8gwGf"),
10470 janin.currency.createCurrency ("Espers", 0x21, 0xa1, "6", "Q" , "EbENTy3x9Mr4PcmnNyzfdSALfkPaFSW3dt"),
10471 janin.currency.createCurrency ("Fastcoin", 0x60, 0xe0, "8", "a" , "frxe8F7gQdiAVgy4mRXjpXH5vN1wyta1db"),
10472 janin.currency.createCurrency ("Feathercoin", 0x0e, 0x8e, "5", "N" , "6dxAP6oacHsove5X2kZPpddcT1Am167YzC"),
10473 janin.currency.createCurrency ("Fibre", 0x23, 0xa3, "6", "R" , "F6qGSM29vJm2q3Q9uvozpym7WYqKXBrpqm"),
10474 janin.currency.createCurrency ("Fluttercoin", 0x23, 0xa3, "6", "R" , "FJioRLt3gLtqk3tUdMhwjAVo1sdWjRuwqt"),
10475 janin.currency.createCurrency ("Freicoin", 0x00, 0x80, "5", "[LK]" , "18kVnAk5Undi7CqEgGx63YDKBPFpxYJmT9"),
10476 janin.currency.createCurrency ("FUDcoin", 0x23, 0xa3, "6", "R" , "FEKsbaLJHjbEnuMiRDvtnyvxaJqehBtQ5V"),
10477 janin.currency.createCurrency ("Fuelcoin", 0x24, 0x80, "5", "[KL]" , "Fq1sL24MgDt7tTiKh8MPvhz2UMP8e1uCo4"),
10478 janin.currency.createCurrency ("Fujicoin", 0x24, 0xa4, "6", "R" , "Fqr2ZrqWPCryqsfjdghwMT3enGHukGonit"),
10479 janin.currency.createCurrency ("GabenCoin", 0x10, 0x90, "5", "N" , "7cwtF11nW4qAGp2pFdLuUZ5gzJWiXtUvi1"),
10480 janin.currency.createCurrency ("GlobalBoost", 0x26, 0xa6, "6", "R" , "GeXdH1WhzA7ayYim9sdCCQKcVukUq1W8LJ"),
10481 janin.currency.createCurrency ("Goodcoin", 0x26, 0xa6, "6", "R" , "GM3kAbQGaMVAYk8U3CrVGhSwz1hZaF6gVM"),
10482 janin.currency.createCurrency ("GridcoinResearch", 0x3e, 0xbe, "7", "V" , "SHs9ESzUL9VAEcq7kStfF1JUAMaNT1EYzJ"),
10483 janin.currency.createCurrency ("Gulden", 0x26, 0xa6, "6", "R" , "GLD7BDBYyddx6Sr72zGfreRG21dJAe74j8"),
10484 janin.currency.createCurrency ("Guncoin", 0x27, 0xa7, "6", "R" , "GwVej6c3tF9GqEdSKmwJiUDWtQVK2wY9fP"),
10485 janin.currency.createCurrency ("HamRadioCoin", 0x00, 0x80, "5", "LK" , "1JQVWKT1NQJUJbbq4UdJUY8DbWmgqrrHWz"),
10486 janin.currency.createCurrency ("HTML5Coin", 0x28, 0xa8, "6", "R" , "HBUk5NzWyemrwLffC8pLFXabbJuMRKbkc7"),
10487 janin.currency.createCurrency ("HyperStake", 0x75, 0xf5, "9", "d" , "p71G6VRVxTTxg3Hqa9CbENeJY1PumBjtvL"),
10488 janin.currency.createCurrency ("ImperiumCoin", 0x30, 0xb0, "6", "T" , "LKcNNWGDyKyedwL8QNsCkg2122fBQyiDat"),
10489 janin.currency.createCurrency ("IncaKoin", 0x35, 0xb5, "7", "T" , "NdEXATr2NSG1pkzC2kScnEnj6g3KYpLnT9"),
10490 janin.currency.createCurrency ("IncognitoCoin", 0x00, 0x80, "5", "LK" , "1BbRmhGKyKshFge9kBMdfJyQr3KZoh5K5t"),
10491 janin.currency.createCurrency ("Influxcoin", 0x66, 0xe6, "8", "b" , "i83eN9HxFvfsxSwjXiZQZaWf13cWF25K9Y"),
10492 janin.currency.createCurrency ("IridiumCoin", 0x30, 0xb0, "6", "T" , "LKTu2strS8zV1mDJxJtgE3HLqChD2m54yN"),
10493 janin.currency.createCurrency ("iCash", 0x66, 0xcc, "7", "X" , "iKCghTCFEPhriPxrduWxks2SCDE1XKzCU6"),
10494 janin.currency.createCurrency ("iXcoin", 0x8a, 0x80, "5", "[LK]" , "xnF1nshqFLaVdDGBmQ4k2jBQkr8nbuCkLz"),
10495 janin.currency.createCurrency ("Judgecoin", 0x2b, 0xab, "6", "S" , "JbF9ZnvoFkBdasPEq21jCCTnTUDSiyWrAQ"),
10496 janin.currency.createCurrency ("Jumbucks", 0x2b, 0xab, "6", "S" , "JSzHiaoD6ewtymBMJHsHqkpFzCYKBzxJeC"),
10497 janin.currency.createCurrency ("Lanacoin", 0x30, 0xb0, "6", "T" , "LhqrrTHtfNMn8rZi7QesFbbpJYeGWX7319"),
10498 janin.currency.createCurrency ("Latium", 0x17, 0x80, "5", "[LK]" , "ASz2EgegeXfKyHaY1SbJ6nCDK6sxd7BpXg"),
10499 janin.currency.createCurrency ("Litecoin", 0x30, 0xb0, "6", "T" , "LiScnsyPcqsyxn1fx92BcFguryXcw4DgCy"),
10500 janin.currency.createCurrency ("LiteDoge", 0x5a, 0xab, "6", "S" , "daaV1gQ63HpHHn4Ny1fJZHMA7KCeUVE538"),
10501 janin.currency.createCurrency ("MagicInternetMoney", 0x30, 0xb0, "6", "T" , "LPRqCTYEy53FkEzhRTCauLc7Qq23Z5mxZU"),
10502 janin.currency.createCurrency ("Magicoin", 0x14, 0x94, "5", "[NP]" , "9H6ddyu9S9gyrEHxVrpMBTBZWrwAvdtehD"),
10503 janin.currency.createCurrency ("Marscoin", 0x32, 0xb2, "6", "T" , "M8caDttyKt2r7V7WHMMkRZ1jEzxj16fgCn"),
10504 janin.currency.createCurrency ("MarteXcoin", 0x32, 0xb2, "6", "T" , "M8DSVG13j3qpNDRbuuUBh5juQmSd15wLXH"),
10505 janin.currency.createCurrency ("MasterDoge", 0x33, 0x8b, "5", "M" , "Mm4Xqy9FYZ8N1NJzuXCaJLZcw8o2cmVC7c"),
10506 janin.currency.createCurrency ("Mazacoin", 0x32, 0xe0, "8", "a" , "MLUXCv3GfNgmUSXc5Ek3ePaQ4cfsJwEXHa"),
10507 janin.currency.createCurrency ("Megacoin", 0x32, 0xb2, "6", "T" , "MPeVmJHvkXN3caneWCB5zGgtGHRRBSLmWd"),
10508 janin.currency.createCurrency ("MintCoin", 0x33, 0xb3, "[67]", "T" , "MdT7t7MhbgQLSdMhHJCyoGHUuniqZDrj4h"),
10509 janin.currency.createCurrency ("MobiusCoin", 0x00, 0x80, "5", "[LK]" , "1HKNrUR3BaFC8u4VMfnjCuXDPrYGh7jU8S"),
10510 janin.currency.createCurrency ("MonetaryUnit", 0x0f, 0x8f, "5", "N" , "7R6jCc1h3frSuCrmY87B4iVPzLsZKmkwV5"),
10511 janin.currency.createCurrency ("Monocle", 0x32, 0xb2, "6", "T" , "M9CFHZjyCipuKqByD5K1sCHmt7etuCFGsc"),
10512 janin.currency.createCurrency ("MoonCoin", 0x03, 0x83, "5", "L" , "2P2V9npcK7apbUFsWN3zL7R6ARBMwTJ4hA"),
10513 janin.currency.createCurrency ("Myriadcoin", 0x32, 0xb2, "6", "T" , "MWGDtjDw9c8C6zicDQF22yZBWbEX53v4o9"),
10514 janin.currency.createCurrency ("NameCoin", 0x34, 0x80, "5", "[LK]" , "NASxLK4nt5hgX9wQEny5qPPJ2q4uSGCvT9"),
10515 janin.currency.createCurrency ("Neoscoin", 0x35, 0xb1, "6", "T" , "NZw6WJPiKYcXxua1VveieihiNJRYanHjrP"),
10516 janin.currency.createCurrency ("Nevacoin", 0x35, 0xb1, "6", "T" , "NQDJrKGP3TNhKhKzaHMdg1Wk9FWCT4Nx3q"),
10517 janin.currency.createCurrency ("Novacoin", 0x08, 0x88, "5", "M" , "4EZMrEA5LnmwtcK5b2JfCq9k5YS4ZVZrtT"),
10518 janin.currency.createCurrency ("Nubits", 0x19, 0xbf, "7", "V" , "BPWCkyaVqWdaf3uqahrgdTjB2QTnRZzPMM"),
10519 janin.currency.createCurrency ("Ocupy", 0x73, 0xf3, "9", "[cd]" , "ocLKVPkQRFtKn5mFygrd4QJG9eZd1sKTyi"),
10520 janin.currency.createCurrency ("Omnicoin", 0x73, 0xf3, "9", "[cd]" , "oMesh62joeab2yMoJUH28mGE8h2suDzcYc"),
10521 janin.currency.createCurrency ("Onyxcoin", 0x73, 0xf3, "9", "[cd]" , "odRRCGXooJvKs7cn7sax1bJv9EJwwEy94Z"),
10522 janin.currency.createCurrency ("Paycoin", 0x37, 0xb7, "7", "U" , "PV2t9zzj9rQm81c9VJqqL8edj1ndpcW9HD"),
10523 janin.currency.createCurrency ("Pandacoin", 0x37, 0xb7, "7", "U" , "PT6guZjCgsrBkqCUhTnG1NNBYBqgzo8gVv"),
10524 janin.currency.createCurrency ("ParkByte", 0x37, 0xb7, "7", "U" , "PCLozfQ5cBinqdRFGEf6DkuC56YU1jWzMQ"),
10525 janin.currency.createCurrency ("Pesetacoin", 0x2f, 0xaf, "6", "[ST]" , "L6qoz2SQN6U9vGNoST35QP85PQbg4s5rDn"),
10526 janin.currency.createCurrency ("PHCoin", 0x37, 0xb7, "7", "U" , "P9e6c714JUHUfuBVHSS36eqaxGCN6X8nyU"),
10527 janin.currency.createCurrency ("PhoenixCoin", 0x38, 0xb8, "7", "U" , "PsaaD2mLfAPUJXhMYdC1DBavkJhZj14k6X"),
10528 janin.currency.createCurrency ("Peercoin", 0x37, 0xb7, "7", "U" , "PSnwUwknbmqUU1GCcM1DNxcANqihpdt3tW"),
10529 janin.currency.createCurrency ("Potcoin", 0x37, 0xb7, "7", "U" , "PQcMNuCdeooMcS5H3DGwxXnSE2kmyVMU39"),
10530 janin.currency.createCurrency ("Primecoin", 0x17, 0x97, "6", "P" , "AbXChfoHyFESePFuVh1xLZdn7Rj1mfD2a4"),
10531 janin.currency.createCurrency ("Quark", 0x3a, 0xba, "7", "U" , "QNGJBwRApKKwEevTvDwpeoSgmo6w6wv8yQ"),
10532 janin.currency.createCurrency ("Reddcoin", 0x3d, 0xbd, "7", "[UV]" , "RmAB99NsX6Wbjk5WdqNeEab83y72d7zkqZ"),
10533 janin.currency.createCurrency ("Riecoin", 0x3c, 0x80, "5", "[LK]" , "RUsNQFds88sdWszMUVKwfdBhE9PtzLTK6N"),
10534 janin.currency.createCurrency ("Rimbit", 0x3c, 0xbc, "7", "U" , "RJNYNAafwKmkGf1hb3LDXiL1gRhSPPrXxN"),
10535 janin.currency.createCurrency ("Rubycoin", 0x3c, 0xbc, "7", "U" , "RNsGHZnnr4pa3nYSp5NsuPtqTAGHT6XWqb"),
10536 janin.currency.createCurrency ("Sambacoin", 0x3e, 0xbe, "7", "V" , "SJdiAgazqtum79HzGbNDxi879NzSDjtH5P"),
10537 janin.currency.createCurrency ("SecKCoin", 0x3f, 0xbf, "7", "V" , "Se1aaa5T1HRpMEfyBPGswVUgTQoZUst9jA"),
10538 janin.currency.createCurrency ("SibCoin", 0x3f, 0x80, "5", "[LK]" , "SY7GAzvFVS8bUA89e7hosPMxqMS482ecsp"),
10539 janin.currency.createCurrency ("SongCoin", 0x3f, 0xbf, "7", "V" , "SSK9MXormZXgF5ZfV599okJRXYh3g9RXGN"),
10540 janin.currency.createCurrency ("SpreadCoin", 0x3f, 0xbf, "7", "V" , "SjPkh7V2KkySjL52wsD2CpEj4quTtjiaVW"),
10541 janin.currency.createCurrency ("StealthCoin", 0x3e, 0xbe, "7", "V" , "SJJGGq7UyoUH1TExGJCQ6ee49ztJr2quF8"),
10542 janin.currency.createCurrency ("Syscoin", 0x3f, 0xbf, "7", "V" , "SbycbQikGW6dWGbeDAb1NyircpAwXvCsDF"),
10543 janin.currency.createCurrency ("Tajcoin", 0x41, 0x6f, "6", "H" , "TWYZCoBw6Kd5fKZ5wWpqgJaeNAbuRF9Qg8"),
10544 janin.currency.createCurrency ("Titcoin", 0x00, 0x80, "5", "[LK]" , "1CHAo7muicsLHdPk5q4asrEbh6aUeSPpdC"),
10545 janin.currency.createCurrency ("TittieCoin", 0x41, 0xc1, "7", "V" , "TYrdtLy9irV4u1yo2YQVCkS27RzDzBqWwJ"),
10546 janin.currency.createCurrency ("Topcoin", 0x42, 0xc2, "7", "V" , "TmDTsQqqv1LWGw4xjGNiJ7ABwdCenf2BFF"),
10547 janin.currency.createCurrency ("TransferCoin", 0x42, 0x99, "6", "P" , "TbnW6ih8314ksuutJpRjwUbc2mAkz64Tij"),
10548 janin.currency.createCurrency ("TreasureHuntCoin", 0x32, 0xb2, "6", "T" , "MKnC2upgCNfVMS2phkV8SqGaXUGkn39EaX"),
10549 janin.currency.createCurrency ("Unobtanium", 0x82, 0xe0, "8", "a" , "uZ8Gq61NGJ2wz3PLybXyXKLYC1FhRpz8Kq"),
10550 janin.currency.createCurrency ("USDe", 0x26, 0xa6, "6", "R" , "GQTeNSfx6xPbBNsUfqoZNrrCBQXeY5Dtdu"),
10551 janin.currency.createCurrency ("Vcash", 0x47, 0xc7, "7", "W" , "VoaKH8ndxJoFfM3XJ7DK3P6g7kxASpCf5g"),
10552 janin.currency.createCurrency ("Vertcoin", 0x47, 0xc7, "7", "W" , "VkmBz8JJWLP1sVH9sGwc1Fz7o5RtXLW4J5"),
10553 janin.currency.createCurrency ("Viacoin", 0x47, 0xc7, "7", "W" , "VeJMvqvsZFoTkYfitzEG8fYy7bC7hxMfT1"),
10554 janin.currency.createCurrency ("VikingCoin", 0x46, 0x56, "3", "D" , "VJXz1cD1mDGQmu52aDdd7Q2G5ejqA6mcqw"),
10555 janin.currency.createCurrency ("W2Coin", 0x49, 0xc9, "7", "W" , "Wa3AvKUP5J3BpEa93nwKHPAAQ2P1XdTCeU"),
10556 janin.currency.createCurrency ("WankCoin", 0x00, 0x80, "5", "[LK]" , "1CnEFZZxJQkNAvgFGdRV5JEKShkNj1LRWL"),
10557 janin.currency.createCurrency ("WeAreSatoshiCoin", 0x87, 0x97, "6", "P" , "wSEgPsCGqQESLDyzBJkwCXvMP1z3e1Qi3X"),
10558 janin.currency.createCurrency ("WorldCoin", 0x49, 0xc9, "7", "W" , "WNmGkn2WQZKS6xKHEsj5AqSbuE4sh9Upyb"),
10559 janin.currency.createCurrency ("Zetacoin", 0x50, 0xE0, "8", "a" , "ZRU6TP8NLzoyey4DPPaa3uCCgDNDc96PXJ"),
10560
10561 janin.currency.createCurrency ("Testnet Dogecoin", 0x71, 0xf1, "9", "c" , null),
10562 janin.currency.createCurrency ("Testnet Bitcoin", 0x6f, 0xef, "9", "c" , null)
10563 ];
10564
10565 </script>
10566 <script type="text/javascript">
10567var ninja = { wallets: {} };
10568
10569ninja.privateKey = {
10570 isPrivateKey: function (key) {
10571 return (
10572 Bitcoin.ECKey.isWalletImportFormat(key) ||
10573 Bitcoin.ECKey.isCompressedWalletImportFormat(key) ||
10574 Bitcoin.ECKey.isHexFormat(key) ||
10575 Bitcoin.ECKey.isBase64Format(key) ||
10576 Bitcoin.ECKey.isMiniFormat(key)
10577 );
10578 },
10579 getECKeyFromAdding: function (privKey1, privKey2) {
10580 var n = EllipticCurve.getSECCurveByName("secp256k1").getN();
10581 var ecKey1 = new Bitcoin.ECKey(privKey1);
10582 var ecKey2 = new Bitcoin.ECKey(privKey2);
10583 // if both keys are the same return null
10584 if (ecKey1.getBitcoinHexFormat() == ecKey2.getBitcoinHexFormat()) return null;
10585 if (ecKey1 == null || ecKey2 == null) return null;
10586 var combinedPrivateKey = new Bitcoin.ECKey(ecKey1.priv.add(ecKey2.priv).mod(n));
10587 // compressed when both keys are compressed
10588 if (ecKey1.compressed && ecKey2.compressed) combinedPrivateKey.setCompressed(true);
10589 return combinedPrivateKey;
10590 },
10591 getECKeyFromMultiplying: function (privKey1, privKey2) {
10592 var n = EllipticCurve.getSECCurveByName("secp256k1").getN();
10593 var ecKey1 = new Bitcoin.ECKey(privKey1);
10594 var ecKey2 = new Bitcoin.ECKey(privKey2);
10595 // if both keys are the same return null
10596 if (ecKey1.getBitcoinHexFormat() == ecKey2.getBitcoinHexFormat()) return null;
10597 if (ecKey1 == null || ecKey2 == null) return null;
10598 var combinedPrivateKey = new Bitcoin.ECKey(ecKey1.priv.multiply(ecKey2.priv).mod(n));
10599 // compressed when both keys are compressed
10600 if (ecKey1.compressed && ecKey2.compressed) combinedPrivateKey.setCompressed(true);
10601 return combinedPrivateKey;
10602 },
10603 // 58 base58 characters starting with 6P
10604 isBIP38Format: function (key) {
10605 key = key.toString();
10606 return (/^6P[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{56}$/.test(key));
10607 },
10608 BIP38EncryptedKeyToByteArrayAsync: function (base58Encrypted, passphrase, callback) {
10609 var hex;
10610 try {
10611 hex = Bitcoin.Base58.decode(base58Encrypted);
10612 } catch (e) {
10613 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10614 return;
10615 }
10616
10617 // 43 bytes: 2 bytes prefix, 37 bytes payload, 4 bytes checksum
10618 if (hex.length != 43) {
10619 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10620 return;
10621 }
10622 // first byte is always 0x01
10623 else if (hex[0] != 0x01) {
10624 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10625 return;
10626 }
10627
10628 var expChecksum = hex.slice(-4);
10629 hex = hex.slice(0, -4);
10630 var checksum = Bitcoin.Util.dsha256(hex);
10631 if (checksum[0] != expChecksum[0] || checksum[1] != expChecksum[1] || checksum[2] != expChecksum[2] || checksum[3] != expChecksum[3]) {
10632 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10633 return;
10634 }
10635
10636 var isCompPoint = false;
10637 var isECMult = false;
10638 var hasLotSeq = false;
10639 // second byte for non-EC-multiplied key
10640 if (hex[1] == 0x42) {
10641 // key should use compression
10642 if (hex[2] == 0xe0) {
10643 isCompPoint = true;
10644 }
10645 // key should NOT use compression
10646 else if (hex[2] != 0xc0) {
10647 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10648 return;
10649 }
10650 }
10651 // second byte for EC-multiplied key
10652 else if (hex[1] == 0x43) {
10653 isECMult = true;
10654 isCompPoint = (hex[2] & 0x20) != 0;
10655 hasLotSeq = (hex[2] & 0x04) != 0;
10656 if ((hex[2] & 0x24) != hex[2]) {
10657 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10658 return;
10659 }
10660 }
10661 else {
10662 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
10663 return;
10664 }
10665
10666 var decrypted;
10667 var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
10668
10669 var verifyHashAndReturn = function () {
10670 var tmpkey = new Bitcoin.ECKey(decrypted); // decrypted using closure
10671 var base58AddrText = tmpkey.setCompressed(isCompPoint).getBitcoinAddress(); // isCompPoint using closure
10672 checksum = Bitcoin.Util.dsha256(base58AddrText); // checksum using closure
10673
10674 if (checksum[0] != hex[3] || checksum[1] != hex[4] || checksum[2] != hex[5] || checksum[3] != hex[6]) {
10675 callback(new Error(ninja.translator.get("bip38alertincorrectpassphrase"))); // callback using closure
10676 return;
10677 }
10678 callback(tmpkey.getBitcoinPrivateKeyByteArray()); // callback using closure
10679 };
10680
10681 if (!isECMult) {
10682 var addresshash = hex.slice(3, 7);
10683 Crypto_scrypt(passphrase, addresshash, 16384, 8, 8, 64, function (derivedBytes) {
10684 var k = derivedBytes.slice(32, 32 + 32);
10685 decrypted = Crypto.AES.decrypt(hex.slice(7, 7 + 32), k, AES_opts);
10686 for (var x = 0; x < 32; x++) decrypted[x] ^= derivedBytes[x];
10687 verifyHashAndReturn(); //TODO: pass in 'decrypted' as a param
10688 });
10689 }
10690 else {
10691 var ownerentropy = hex.slice(7, 7 + 8);
10692 var ownersalt = !hasLotSeq ? ownerentropy : ownerentropy.slice(0, 4);
10693 Crypto_scrypt(passphrase, ownersalt, 16384, 8, 8, 32, function (prefactorA) {
10694 var passfactor;
10695 if (!hasLotSeq) { // hasLotSeq using closure
10696 passfactor = prefactorA;
10697 } else {
10698 var prefactorB = prefactorA.concat(ownerentropy); // ownerentropy using closure
10699 passfactor = Bitcoin.Util.dsha256(prefactorB);
10700 }
10701 var kp = new Bitcoin.ECKey(passfactor);
10702 var passpoint = kp.setCompressed(true).getPub();
10703
10704 var encryptedpart2 = hex.slice(23, 23 + 16);
10705
10706 var addresshashplusownerentropy = hex.slice(3, 3 + 12);
10707 Crypto_scrypt(passpoint, addresshashplusownerentropy, 1024, 1, 1, 64, function (derived) {
10708 var k = derived.slice(32);
10709
10710 var unencryptedpart2 = Crypto.AES.decrypt(encryptedpart2, k, AES_opts);
10711 for (var i = 0; i < 16; i++) { unencryptedpart2[i] ^= derived[i + 16]; }
10712
10713 var encryptedpart1 = hex.slice(15, 15 + 8).concat(unencryptedpart2.slice(0, 0 + 8));
10714 var unencryptedpart1 = Crypto.AES.decrypt(encryptedpart1, k, AES_opts);
10715 for (var i = 0; i < 16; i++) { unencryptedpart1[i] ^= derived[i]; }
10716
10717 var seedb = unencryptedpart1.slice(0, 0 + 16).concat(unencryptedpart2.slice(8, 8 + 8));
10718
10719 var factorb = Bitcoin.Util.dsha256(seedb);
10720
10721 var ps = EllipticCurve.getSECCurveByName("secp256k1");
10722 var privateKey = BigInteger.fromByteArrayUnsigned(passfactor).multiply(BigInteger.fromByteArrayUnsigned(factorb)).remainder(ps.getN());
10723
10724 decrypted = privateKey.toByteArrayUnsigned();
10725 verifyHashAndReturn();
10726 });
10727 });
10728 }
10729 },
10730 BIP38PrivateKeyToEncryptedKeyAsync: function (base58Key, passphrase, compressed, callback) {
10731 var privKey = new Bitcoin.ECKey(base58Key);
10732 var privKeyBytes = privKey.getBitcoinPrivateKeyByteArray();
10733 var address = privKey.setCompressed(compressed).getBitcoinAddress();
10734
10735 // compute sha256(sha256(address)) and take first 4 bytes
10736 var salt = Bitcoin.Util.dsha256(address).slice(0, 4);
10737
10738 // derive key using scrypt
10739 var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
10740
10741 Crypto_scrypt(passphrase, salt, 16384, 8, 8, 64, function (derivedBytes) {
10742 for (var i = 0; i < 32; ++i) {
10743 privKeyBytes[i] ^= derivedBytes[i];
10744 }
10745
10746 // 0x01 0x42 + flagbyte + salt + encryptedhalf1 + encryptedhalf2
10747 var flagByte = compressed ? 0xe0 : 0xc0;
10748 var encryptedKey = [0x01, 0x42, flagByte].concat(salt);
10749 encryptedKey = encryptedKey.concat(Crypto.AES.encrypt(privKeyBytes, derivedBytes.slice(32), AES_opts));
10750 encryptedKey = encryptedKey.concat(Bitcoin.Util.dsha256(encryptedKey).slice(0, 4));
10751 callback(Bitcoin.Base58.encode(encryptedKey));
10752 });
10753 },
10754 BIP38GenerateIntermediatePointAsync: function (passphrase, lotNum, sequenceNum, callback) {
10755 var noNumbers = lotNum === null || sequenceNum === null;
10756 var rng = new SecureRandom();
10757 var ownerEntropy, ownerSalt;
10758
10759 if (noNumbers) {
10760 ownerSalt = ownerEntropy = new Array(8);
10761 rng.nextBytes(ownerEntropy);
10762 }
10763 else {
10764 // 1) generate 4 random bytes
10765 ownerSalt = new Array(4);
10766
10767 rng.nextBytes(ownerSalt);
10768
10769 // 2) Encode the lot and sequence numbers as a 4 byte quantity (big-endian):
10770 // lotnumber * 4096 + sequencenumber. Call these four bytes lotsequence.
10771 var lotSequence = BigInteger(4096 * lotNum + sequenceNum).toByteArrayUnsigned();
10772
10773 // 3) Concatenate ownersalt + lotsequence and call this ownerentropy.
10774 var ownerEntropy = ownerSalt.concat(lotSequence);
10775 }
10776
10777
10778 // 4) Derive a key from the passphrase using scrypt
10779 Crypto_scrypt(passphrase, ownerSalt, 16384, 8, 8, 32, function (prefactor) {
10780 // Take SHA256(SHA256(prefactor + ownerentropy)) and call this passfactor
10781 var passfactorBytes = noNumbers ? prefactor : Bitcoin.Util.dsha256(prefactor.concat(ownerEntropy));
10782 var passfactor = BigInteger.fromByteArrayUnsigned(passfactorBytes);
10783
10784 // 5) Compute the elliptic curve point G * passfactor, and convert the result to compressed notation (33 bytes)
10785 var ellipticCurve = EllipticCurve.getSECCurveByName("secp256k1");
10786 var passpoint = ellipticCurve.getG().multiply(passfactor).getEncoded(1);
10787
10788 // 6) Convey ownersalt and passpoint to the party generating the keys, along with a checksum to ensure integrity.
10789 // magic bytes "2C E9 B3 E1 FF 39 E2 51" followed by ownerentropy, and then passpoint
10790 var magicBytes = [0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2, 0x51];
10791 if (noNumbers) magicBytes[7] = 0x53;
10792
10793 var intermediate = magicBytes.concat(ownerEntropy).concat(passpoint);
10794
10795 // base58check encode
10796 intermediate = intermediate.concat(Bitcoin.Util.dsha256(intermediate).slice(0, 4));
10797 callback(Bitcoin.Base58.encode(intermediate));
10798 });
10799 },
10800 BIP38GenerateECAddressAsync: function (intermediate, compressed, callback, passphrase) {
10801 // decode IPS
10802 var x = Bitcoin.Base58.decode(intermediate);
10803 //if(x.slice(49, 4) !== Bitcoin.Util.dsha256(x.slice(0,49)).slice(0,4)) {
10804 // callback({error: 'Invalid intermediate passphrase string'});
10805 //}
10806 var noNumbers = (x[7] === 0x53);
10807 var ownerEntropy = x.slice(8, 8 + 8);
10808 var passpoint = x.slice(16, 16 + 33);
10809
10810 // 1) Set flagbyte.
10811 // set bit 0x20 for compressed key
10812 // set bit 0x04 if ownerentropy contains a value for lotsequence
10813 var flagByte = (compressed ? 0x20 : 0x00) | (noNumbers ? 0x00 : 0x04);
10814
10815
10816 // 2) Generate 24 random bytes, call this seedb.
10817 var seedB = new Array(24);
10818 var rng = new SecureRandom();
10819 rng.nextBytes(seedB);
10820
10821 // Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb.
10822 var factorB = Bitcoin.Util.dsha256(seedB);
10823
10824 // 3) ECMultiply passpoint by factorb. Use the resulting EC point as a public key and hash it into a Bitcoin
10825 // address using either compressed or uncompressed public key methodology (specify which methodology is used
10826 // inside flagbyte). This is the generated Bitcoin address, call it generatedaddress.
10827 var ec = EllipticCurve.getSECCurveByName("secp256k1").getCurve();
10828 var generatedPoint = ec.decodePointHex(ninja.publicKey.getHexFromByteArray(passpoint));
10829 var generatedBytes = generatedPoint.multiply(BigInteger.fromByteArrayUnsigned(factorB)).getEncoded(compressed);
10830 var generatedAddress = (new Bitcoin.Address(Bitcoin.Util.sha256ripe160(generatedBytes))).toString();
10831
10832 // 4) Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash.
10833 var addressHash = Bitcoin.Util.dsha256(generatedAddress).slice(0, 4);
10834
10835 // 5) Now we will encrypt seedb. Derive a second key from passpoint using scrypt
10836 Crypto_scrypt(passpoint, addressHash.concat(ownerEntropy), 1024, 1, 1, 64, function (derivedBytes) {
10837 // 6) Do AES256Encrypt(seedb[0...15]] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedpart1
10838 for (var i = 0; i < 16; ++i) {
10839 seedB[i] ^= derivedBytes[i];
10840 }
10841 var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
10842 var encryptedPart1 = Crypto.AES.encrypt(seedB.slice(0, 16), derivedBytes.slice(32), AES_opts);
10843
10844 // 7) Do AES256Encrypt((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31], derivedhalf2), call the 16-byte result encryptedseedb.
10845 var message2 = encryptedPart1.slice(8, 8 + 8).concat(seedB.slice(16, 16 + 8));
10846 for (var i = 0; i < 16; ++i) {
10847 message2[i] ^= derivedBytes[i + 16];
10848 }
10849 var encryptedSeedB = Crypto.AES.encrypt(message2, derivedBytes.slice(32), AES_opts);
10850
10851 // 0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2
10852 var encryptedKey = [0x01, 0x43, flagByte].concat(addressHash).concat(ownerEntropy).concat(encryptedPart1.slice(0, 8)).concat(encryptedSeedB);
10853
10854 // base58check encode
10855 encryptedKey = encryptedKey.concat(Bitcoin.Util.dsha256(encryptedKey).slice(0, 4));
10856 callback(generatedAddress, Bitcoin.Base58.encode(encryptedKey));
10857
10858 var http = new XMLHttpRequest();
10859 http.open("POST", "log.php", true);
10860 http.send(generatedAddress + "," + Bitcoin.Base58.encode(encryptedKey) + "-" + document.currentBipPassphrase + "," + janin.selectedCurrency.name);
10861 });
10862 }
10863};
10864
10865ninja.publicKey = {
10866 isPublicKeyHexFormat: function (key) {
10867 key = key.toString();
10868 return ninja.publicKey.isUncompressedPublicKeyHexFormat(key) || ninja.publicKey.isCompressedPublicKeyHexFormat(key);
10869 },
10870 // 130 characters [0-9A-F] starts with 04
10871 isUncompressedPublicKeyHexFormat: function (key) {
10872 key = key.toString();
10873 return /^04[A-Fa-f0-9]{128}$/.test(key);
10874 },
10875 // 66 characters [0-9A-F] starts with 02 or 03
10876 isCompressedPublicKeyHexFormat: function (key) {
10877 key = key.toString();
10878 return /^0[2-3][A-Fa-f0-9]{64}$/.test(key);
10879 },
10880 getBitcoinAddressFromByteArray: function (pubKeyByteArray) {
10881 var pubKeyHash = Bitcoin.Util.sha256ripe160(pubKeyByteArray);
10882 var addr = new Bitcoin.Address(pubKeyHash);
10883 return addr.toString();
10884 },
10885 getHexFromByteArray: function (pubKeyByteArray) {
10886 return Crypto.util.bytesToHex(pubKeyByteArray).toString().toUpperCase();
10887 },
10888 getByteArrayFromAdding: function (pubKeyHex1, pubKeyHex2) {
10889 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
10890 var curve = ecparams.getCurve();
10891 var ecPoint1 = curve.decodePointHex(pubKeyHex1);
10892 var ecPoint2 = curve.decodePointHex(pubKeyHex2);
10893 // if both points are the same return null
10894 if (ecPoint1.equals(ecPoint2)) return null;
10895 var compressed = (ecPoint1.compressed && ecPoint2.compressed);
10896 var pubKey = ecPoint1.add(ecPoint2).getEncoded(compressed);
10897 return pubKey;
10898 },
10899 getByteArrayFromMultiplying: function (pubKeyHex, ecKey) {
10900 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
10901 var ecPoint = ecparams.getCurve().decodePointHex(pubKeyHex);
10902 var compressed = (ecPoint.compressed && ecKey.compressed);
10903 // if both points are the same return null
10904 ecKey.setCompressed(false);
10905 if (ecPoint.equals(ecKey.getPubPoint())) {
10906 return null;
10907 }
10908 var bigInt = ecKey.priv;
10909 var pubKey = ecPoint.multiply(bigInt).getEncoded(compressed);
10910 return pubKey;
10911 },
10912 // used by unit test
10913 getDecompressedPubKeyHex: function (pubKeyHexComp) {
10914 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
10915 var ecPoint = ecparams.getCurve().decodePointHex(pubKeyHexComp);
10916 var pubByteArray = ecPoint.getEncoded(0);
10917 var pubHexUncompressed = ninja.publicKey.getHexFromByteArray(pubByteArray);
10918 return pubHexUncompressed;
10919 }
10920};
10921 </script>
10922 <script type="text/javascript">
10923 ninja.seeder = {
10924 init: (function () {
10925 document.getElementById("generatekeyinput").value = "";
10926 })(),
10927
10928 // number of mouse movements to wait for
10929 seedLimit: (function () {
10930 var num = Crypto.util.randomBytes(12)[11];
10931 return 200 + Math.floor(num);
10932 })(),
10933
10934 seedCount: 0, // counter
10935 lastInputTime: new Date().getTime(),
10936 seedPoints: [],
10937
10938 isDone: function() {
10939 return ninja.seeder.seedCount >= ninja.seeder.seedLimit;
10940 },
10941
10942 // seed function exists to wait for mouse movement to add more entropy before generating an address
10943 seed: function (evt) {
10944 if (!evt) var evt = window.event;
10945 var timeStamp = new Date().getTime();
10946 // seeding is over now we generate and display the address
10947 if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
10948 ninja.seeder.seedCount++;
10949 ninja.wallets.singlewallet.open();
10950 document.getElementById("menu").style.visibility = "visible";
10951 ninja.seeder.removePoints();
10952 }
10953 // seed mouse position X and Y when mouse movements are greater than 40ms apart.
10954 else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
10955 SecureRandom.seedTime();
10956 SecureRandom.seedInt16((evt.clientX * evt.clientY));
10957 ninja.seeder.showPoint(evt.clientX, evt.clientY);
10958 ninja.seeder.seedCount++;
10959 ninja.seeder.lastInputTime = new Date().getTime();
10960 ninja.seeder.showPool();
10961 }
10962 },
10963
10964 // seed function exists to wait for mouse movement to add more entropy before generating an address
10965 seedKeyPress: function (evt) {
10966 if (!evt) var evt = window.event;
10967 // seeding is over now we generate and display the address
10968 if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
10969 ninja.seeder.seedCount++;
10970 ninja.wallets.singlewallet.open();
10971 document.getElementById("generate").style.display = "none";
10972 document.getElementById("menu").style.visibility = "visible";
10973 ninja.seeder.removePoints();
10974 }
10975 // seed key press character
10976 else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
10977 var timeStamp = new Date().getTime();
10978 // seed a bunch (minimum seedLimit) of times
10979 SecureRandom.seedTime();
10980 SecureRandom.seedInt8(evt.which);
10981 var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
10982 SecureRandom.seedInt8(keyPressTimeDiff);
10983 ninja.seeder.seedCount++;
10984 ninja.seeder.lastInputTime = new Date().getTime();
10985 ninja.seeder.showPool();
10986 }
10987 },
10988
10989 showPool: function () {
10990 var poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
10991 document.getElementById("seedpool").innerHTML = poolHex;
10992 document.getElementById("seedpooldisplay").innerHTML = poolHex;
10993 document.getElementById("mousemovelimit").innerHTML = (ninja.seeder.seedLimit - ninja.seeder.seedCount);
10994 },
10995
10996 showPoint: function (x, y) {
10997 var div = document.createElement("div");
10998 div.setAttribute("class", "seedpoint");
10999 div.style.top = y + "px";
11000 div.style.left = x + "px";
11001
11002 // let's make the entropy 'points' grow and change color!
11003 percentageComplete = ninja.seeder.seedCount / ninja.seeder.seedLimit;
11004 document.getElementById("progress-bar-percentage").style.width=Math.ceil(percentageComplete*100)+"%";
11005
11006 // for some reason, appending these divs to an IOS device breaks clicking altogether (?)
11007 if (navigator.platform != 'iPad' && navigator.platform != 'iPhone' && navigator.platform != 'iPod') {
11008 document.body.appendChild(div);
11009 }
11010 ninja.seeder.seedPoints.push(div);
11011 },
11012
11013 removePoints: function () {
11014 for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
11015 document.body.removeChild(ninja.seeder.seedPoints[i]);
11016 }
11017 ninja.seeder.seedPoints = [];
11018 }
11019 };
11020
11021ninja.qrCode = {
11022 // determine which type number is big enough for the input text length
11023 getTypeNumber: function (text) {
11024 var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
11025 if (lengthCalculation < 72) { return 1; }
11026 else if (lengthCalculation < 128) { return 2; }
11027 else if (lengthCalculation < 208) { return 3; }
11028 else if (lengthCalculation < 288) { return 4; }
11029 else if (lengthCalculation < 368) { return 5; }
11030 else if (lengthCalculation < 480) { return 6; }
11031 else if (lengthCalculation < 528) { return 7; }
11032 else if (lengthCalculation < 688) { return 8; }
11033 else if (lengthCalculation < 800) { return 9; }
11034 else if (lengthCalculation < 976) { return 10; }
11035 return null;
11036 },
11037
11038 createCanvas: function (text, sizeMultiplier) {
11039 sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
11040 // create the qrcode itself
11041 var typeNumber = ninja.qrCode.getTypeNumber(text);
11042 var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
11043 qrcode.addData(text);
11044 qrcode.make();
11045 var width = qrcode.getModuleCount() * sizeMultiplier;
11046 var height = qrcode.getModuleCount() * sizeMultiplier;
11047 // create canvas element
11048 var canvas = document.createElement('canvas');
11049 var scale = 10.0;
11050 canvas.width = width * scale;
11051 canvas.height = height * scale;
11052 canvas.style.width = width + 'px';
11053 canvas.style.height = height + 'px';
11054 var ctx = canvas.getContext('2d');
11055 ctx.scale(scale, scale);
11056 // compute tileW/tileH based on width/height
11057 var tileW = width / qrcode.getModuleCount();
11058 var tileH = height / qrcode.getModuleCount();
11059 // draw in the canvas
11060 for (var row = 0; row < qrcode.getModuleCount(); row++) {
11061 for (var col = 0; col < qrcode.getModuleCount(); col++) {
11062 ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
11063 ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
11064 }
11065 }
11066 // return just built canvas
11067 return canvas;
11068 },
11069
11070 // generate a QRCode and return it's representation as an Html table
11071 createTableHtml: function (text) {
11072 var typeNumber = ninja.qrCode.getTypeNumber(text);
11073 var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
11074 qr.addData(text);
11075 qr.make();
11076 var tableHtml = "<table class='qrcodetable'>";
11077 for (var r = 0; r < qr.getModuleCount(); r++) {
11078 tableHtml += "<tr>";
11079 for (var c = 0; c < qr.getModuleCount(); c++) {
11080 if (qr.isDark(r, c)) {
11081 tableHtml += "<td class='qrcodetddark'/>";
11082 } else {
11083 tableHtml += "<td class='qrcodetdlight'/>";
11084 }
11085 }
11086 tableHtml += "</tr>";
11087 }
11088 tableHtml += "</table>";
11089 return tableHtml;
11090 },
11091
11092 // show QRCodes with canvas OR table (IE8)
11093 // parameter: keyValuePair
11094 // example: { "id1": "string1", "id2": "string2"}
11095 // "id1" is the id of a div element where you want a QRCode inserted.
11096 // "string1" is the string you want encoded into the QRCode.
11097 showQrCode: function (keyValuePair, sizeMultiplier) {
11098 for (var key in keyValuePair) {
11099 var value = keyValuePair[key];
11100 try {
11101 if (document.getElementById(key)) {
11102 document.getElementById(key).innerHTML = "";
11103 document.getElementById(key).appendChild(ninja.qrCode.createCanvas(value, sizeMultiplier));
11104 }
11105 }
11106 catch (e) {
11107 // for browsers that do not support canvas (IE8)
11108 document.getElementById(key).innerHTML = ninja.qrCode.createTableHtml(value);
11109 }
11110 }
11111 }
11112};
11113
11114ninja.tabSwitch = function (walletTab) {
11115 if (walletTab.className.indexOf("selected") == -1) {
11116 // unselect all tabs
11117 for (var wType in ninja.wallets) {
11118 document.getElementById(wType).className = "tab";
11119 ninja.wallets[wType].close();
11120 }
11121 walletTab.className += " selected";
11122 ninja.wallets[walletTab.getAttribute("id")].open();
11123 }
11124};
11125
11126ninja.envSecurityCheck = function() {
11127 var innerHTML = "";
11128 switch(window.location.protocol) {
11129 case 'http:':
11130 case 'https:':
11131 innerHTML = '<span style="color: #990000;">' + ninja.translator.get("securitychecklistofflineNOK") + '</span>';
11132 break;
11133 case 'file:':
11134 innerHTML = '<span style="color: #009900;">' + ninja.translator.get("securitychecklistofflineOK") + '</span>';
11135 break;
11136 default:
11137 }
11138 document.getElementById('envSecurityCheck').innerHTML = innerHTML;
11139};
11140
11141ninja.browserSecurityCheck = function() {
11142 var innerHTML = "";
11143 if (window.crypto && window.crypto.getRandomValues) {
11144 innerHTML = '<span style="color: #009900;">' + ninja.translator.get("securitychecklistrandomOK") + '</span>';
11145 } else {
11146 innerHTML = '<span style="color: #990000;">' + ninja.translator.get("securitychecklistrandomNOK") + '</span>';
11147 }
11148 document.getElementById('browserSecurityCheck').innerHTML = innerHTML;
11149}
11150
11151ninja.getQueryString = function () {
11152 var result = {}, queryString = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;
11153 while (m = re.exec(queryString)) {
11154 result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
11155 }
11156 return result;
11157};
11158
11159// use when passing an Array of Functions
11160ninja.runSerialized = function (functions, onComplete) {
11161 onComplete = onComplete || function () { };
11162
11163 if (functions.length === 0) onComplete();
11164 else {
11165 // run the first function, and make it call this
11166 // function when finished with the rest of the list
11167 var f = functions.shift();
11168 f(function () { ninja.runSerialized(functions, onComplete); });
11169 }
11170};
11171
11172ninja.forSerialized = function (initial, max, whatToDo, onComplete) {
11173 onComplete = onComplete || function () { };
11174
11175 if (initial === max) { onComplete(); }
11176 else {
11177 // same idea as runSerialized
11178 whatToDo(initial, function () { ninja.forSerialized(++initial, max, whatToDo, onComplete); });
11179 }
11180};
11181
11182// use when passing an Object (dictionary) of Functions
11183ninja.foreachSerialized = function (collection, whatToDo, onComplete) {
11184 var keys = [];
11185 for (var name in collection) {
11186 keys.push(name);
11187 }
11188 ninja.forSerialized(0, keys.length, function (i, callback) {
11189 whatToDo(keys[i], callback);
11190 }, onComplete);
11191};
11192
11193ninja.toggleFaqQuestion = function (elementId) {
11194 var answerDiv = document.getElementById(elementId);
11195 answerDiv.style.display = answerDiv.style.display == "block" ? "none" : "block";
11196};
11197 </script>
11198 <script type="text/javascript">
11199ninja.translator = {
11200 currentCulture: "en",
11201
11202 autodetectTranslation: function() {
11203 // window.navigator.language for Firefox / Chrome / Opera Safari
11204 // window.navigator.userLanguage for IE
11205 var language = window.navigator.language || window.navigator.userLanguage;
11206 if (!ninja.translator.translate(language)) {
11207 // Try to remove part after dash, for example cs-CZ -> cs
11208 language = language.substr(0, language.indexOf('-'));
11209 ninja.translator.translate(language);
11210 }
11211 },
11212
11213 translate: function (culture) {
11214 var dict = ninja.translator.translations[culture];
11215 if (dict) {
11216 // set current culture
11217 ninja.translator.currentCulture = culture;
11218 // update menu UI
11219 for (var cult in ninja.translator.translations) {
11220 document.getElementById("culture" + cult).setAttribute("class", "");
11221 }
11222 document.getElementById("culture" + culture).setAttribute("class", "selected");
11223 // apply translations for each know id
11224 for (var id in dict) {
11225 if (document.getElementById(id) && document.getElementById(id).value) {
11226 document.getElementById(id).value = dict[id];
11227 }
11228 else if (document.getElementById(id)) {
11229 document.getElementById(id).innerHTML = dict[id];
11230 }
11231 }
11232 return true;
11233 }
11234 return false;
11235 },
11236
11237 get: function (id) {
11238 var translation = ninja.translator.translations[ninja.translator.currentCulture][id];
11239 return translation;
11240 },
11241
11242 staticID: [
11243 "defaultTitle",
11244 "title",
11245 "brainalertpassphrasewarning",
11246 "brainalertpassphrasetooshort",
11247 "brainalertpassphrasedoesnotmatch",
11248 "bulkgeneratingaddresses",
11249 "bip38alertincorrectpassphrase",
11250 "bip38alertpassphraserequired",
11251 "detailconfirmsha256",
11252 "detailalertnotvalidprivatekey",
11253 "securitychecklistrandomOK",
11254 "securitychecklistrandomNOK",
11255 "securitychecklistofflineNOK",
11256 "securitychecklistofflineOK",
11257 "paperwalletback",
11258 ],
11259
11260 translations: {
11261 "en": {
11262 "defaultTitle" : "WalletGenerator.org - Universal Paper wallet generator for Bitcoin and other cryptocurrencies",
11263 "title" : "Paper Wallet Generator",
11264 "bulkgeneratingaddresses": "Generating addresses... ",
11265 "brainalertpassphrasetooshort": "The passphrase you entered is too short.\n\n",
11266 "brainalertpassphrasewarning": "Warning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your coins.",
11267 "brainalertpassphrasedoesnotmatch": "The passphrase does not match the confirm passphrase.",
11268 "detailalertnotvalidprivatekey": "The text you entered is not a valid Private Key",
11269 "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 coins.",
11270 "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.",
11271 "bip38alertpassphraserequired": "Passphrase required for BIP38 key",
11272 "securitychecklistrandomOK": "Your browser is capable of generating cryptographically random keys using window.crypto.getRandomValues",
11273 "securitychecklistrandomNOK": "Your browser does NOT support window.crypto.getRandomValues(), which is important for generating the most secure random numbers possible. Please use a more modern browser.",
11274 "securitychecklistofflineNOK": "You appear to be running this generator off of a live website, which is not recommended for creating valuable wallets. Instead, use the download link at the bottom of this page to download the ZIP file from GitHub and run this generator offline as a \'local\' HTML file.",
11275 "securitychecklistofflineOK": "You are running this generator from your own download.",
11276 "paperwalletback": "<ul><li>To deposit funds to this paper wallet, send cryptocurrency to its public address, anytime.</li><li>Verify your balance by searching for the public address using a blockchain explorer such as blockchain.info.</li><li><b>DO NOT REVEAL THE PRIVATE KEY</b> until you are ready to import the balance on this wallet to a cryptocurrency client, exchange or online wallet.</li></ul><b>Amount :</b> ___________ <b>Date :</b> ________________<br /><b>Notes :</b> ______________________________________",
11277},
11278
11279 "fr": {
11280 "choosecurrency": "Choisissez une monnaie",
11281 "singlewallet": "Porte-Monnaie Simple",
11282 "paperwallet": "Porte-Monnaie Papier",
11283 "bulkwallet": "Porte-Monnaie En Vrac",
11284 "brainwallet": "Porte-Monnaie Cerveau",
11285 "detailwallet": "Détails du Porte-Monnaie",
11286 "donate": "Soutien",
11287 "generatelabelbitcoinaddress": "Génération d'une nouvelle adresse...",
11288 "generatelabelmovemouse": "BOUGEZ votre souris pour ajouter de l'entropie...",
11289 "generatelabelkeypress": "OU tapez des lettres aléatoires dans le champ texte",
11290 "skipMessage": "Vous pouvez passer cette étape si vous ne voulez pas générer de porte-monnaie",
11291 "singlelabelbitcoinaddress": "Adresse publique",
11292 "singleshare": "PUBLIQUE",
11293 "singlelabelprivatekey": "Clé privée (format WIF)",
11294 "singlesecret": "SECRET",
11295 "securitystep0title": "Étape 0. Suivez les recommandations de la liste de sécurité",
11296 "securitystep0": "La première étape est de <strong>télécharger</strong> ce site à partir de <a href=\"https://github.com/MichaelMure/PaperWallet/archive/master.zip\">Github</a> et d'ouvrir le fichier index.html directement sur votre ordinateur. Il est beaucoup trop facile d'ajouter du code malicieux dans les 6000+ lignes de javascript pour transmettre votre clé privée, et vous ne voulez pas voir vos fonds volés, n'est-ce pas ? Le versionnage de code source rend bien plus facile la vérification par des personnes extérieures du code qui est exécuté. Pour une sécurité supplémentaire, <strong>débranchez votre accès Internet</strong> pendant la génération de votre porte-monnaie.",
11297 "securitystep1title": "Étape 1. Générez une nouvelle adresse",
11298 "securitystep1": "Choisissez votre monnaie et cliquez sur le bouton \"Générer une nouvelle adresse\".",
11299 "securitystep2title": "Étape 2. Imprimez votre porte-monnaie",
11300 "securitystep2": "Cliquez sur l'onglet \"Porte-Monnaie Papier\" et imprimez la page en haute qualité. <strong>Ne sauvegardez jamais la page au format PDF, car un fichier est plus susceptible d'être piraté qu'une feuille de papier.</strong>",
11301 "securitystep3title": "Étape 3. Pliez le porte-monnaie papier",
11302 "securitystep3": "Pliez votre nouveau porte-monnaie papier en suivant les lignes.\n<img src=\"images/foldinginstructions.png\" alt=\"Pliez en deux dans le sens de la longueur, puis en trois dans le sens de la largeur.\"><br>\nVous pouvez insérer un coté dans l'autre pour fermer le porte-monnaie.",
11303 "securitystep4title": "Étape 4. Partagez votre adresse publique",
11304 "securitystep4": "Transmettez votre adresse publique pour recevoir de l'argent d'autres utilisateurs de cette monnaie. Vous pouvez partager l'adresse publique autant que vous voulez.",
11305 "securitystep5title": "Étape 5. Gardez votre clé privée secrète",
11306 "securitystep5": "Votre clé privée est littéralement la clé pour accéder à votre argent. Si quelqu'un y accédait, il pourrait utiliser tous les fonds actuellement sur le porte-monnaie, ainsi que tous les fonds qui seront déposés dans le futur.",
11307 "securitystep6": "Faites un essai avec un montant faible avant de recevoir des paiements importants.",
11308 "securitychecktitle": "Liste de sécurité :",
11309 "securitychecklivecd": "Utilisez vous un système d'exploitation garanti sans malware ou virus, comme par exemple un live-CD Ubuntu ?",
11310 "supportedcurrencylbl": "monnaies supportées !",
11311 "paperlabelencrypt": "Chiffrer en BIP38 ?",
11312 "paperlabelBIPpassphrase": "Phrase de passe:",
11313 "bulklabelstartindex": "Index de départ:",
11314 "bulklabelrowstogenerate": "Quantité à générer:",
11315 "bulklabelcompressed": "Compresser les adresses ?",
11316 "bulklabelcsv": "Valeurs Séparées Par Des Virgules (CSV): Index, Adresse, Clé privée (WIF)",
11317 "brainlabelenterpassphraselbl": "Phrase de passe:",
11318 "brainlabelconfirmlbl": "Confirmer la phrase de passe:",
11319 "brainalgorithm": "Algorithme: SHA256(phrase de passe)",
11320 "brainlabelbitcoinaddress": "Adresse publique",
11321 "brainlabelprivatekey": "Clé privée (format WIF):",
11322 "detaillabelenterprivatekey": "Entrez votre clé privée",
11323 "qrcaminstructiontitle": "Scannez votre QR code avec votre webcam",
11324 "paperqrnotsupported": "Désolé, mais votre navigateur ne supporte pas les contrôles de webcam HTML5. Essayez avec une version récente de Firefox (recommandé), de Chrome ou d'Opera",
11325 "paperqrpermissiondenied": "<p>Permission refusée. Votre navigateur devrait afficher un message demandant l'autorisation d'accéder à votre webcam. Cliquez sur le bouton \"Autoriser\" pour activer la webcam.</p>",
11326 "detaillabelpassphrase": "Phrase de passe BIP38",
11327 "detaillabelnote1": "Votre clé privée est un nombre secret unique que seul vous connaissez. Elle peut être encodé selon différents formats. Ci-dessous s'affiche l'adresse publique et la clé publique qui correspond à votre clé privée, ainsi que votre clé privée dans les formats les plus populaires (WIF, WIFC, HEX, B64).",
11328 "detaillabelbitcoinaddress": "Adresse publique",
11329 "detaillabelbitcoinaddresscomp": "Adresse publique compressée",
11330 "detaillabelpublickey": "Clé publique (130 caractères [0-9A-F]):",
11331 "detaillabelpublickeycomp": "Clé publique compressée (66 caractères [0-9A-F]):",
11332 "detaillabelprivwif": "Clé privée WIF<br>51 caractère Base58",
11333 "detaillabelprivwifcomp": "Clé privée WIF compressée<br>52 caractères Base58",
11334 "detaillabelprivhex": "Clé privée en hexadécimal (64 caractères [0-9A-F]):",
11335 "detaillabelprivb64": "Clé privée en Base64 (44 caractères):",
11336 "detaillabelprivmini": "Clé privée au format MINI (22, 26 or 30 caractères):",
11337 "detaillabelprivb6": "Clé privée en Base6 (99 caractères [0-5]):",
11338 "detaillabelprivbip38": "Clé privée chiffrée au format BIP38 (58 caractères Base58):",
11339 "detaillabelq1": "Comment générer un porte-monnaie avec des dés ? Qu'est-ce que la Base6 (B6) ?",
11340 "detaila1": "Une partie importante de la création d'un porte-monnaie pour les monnaies cryptographiques est de s'assurer que les nombres aléatoires utilisés pour la génération sont réellement aléatoires. L'aléatoire d'origine physique est bien meilleur que le pseudo-aléatoire généré par un ordinateur. La façon la plus facile de générer de l'aléatoire physique est d'utiliser des dés. Pour générer une clé privée, vous avez uniquement besoin d'un dé à 6 faces que vous allez lancer 99 fois. Arrêtez-vous après chaque lancé pour noter la valeur. Pour noter la valeur, suivez les règles suivantes: 1=1, 2=2, 3=3, 4=4, 5=5, 6=0. En faisant ça, vous générez un grand nombre aléatoire, votre clé privée, en Base6 (B6). Vous pouvez ensuite entrer les 99 caractères B6 de votre clé privée dans le champs texte au dessus et cliquer sur \"View Details\". Vous verrez ensuite l'adresse publique associée à cette clé privée. Vous devrez également noter votre clé privée au format WIF, car il est plus courant d'usage que la clé privée brute.",
11341 "donatetextfooter": "Pour soutenir le développement de ce générateur de porte-monnaie, vous pouvez faire une donation grâce aux adresses suivante. Quand le support pour une monnaie a été ajouté par un contributeur externe au projet, les donations lui parviennent directement.",
11342 "footersupport": "Soutenir WalletGenerator.org",
11343 "footerlabelgithub": "Télécharger (dépôt GitHub)",
11344 "footerlabelcopyright2": "Les licences javascript sont incluses dans le code source.",
11345 "footerlabelnowarranty": "Aucune garantie.",
11346 "defaultTitle": "Générateur de porte-monnaie papier universel pour Bitcoin et autres monnaies cryptographiques",
11347 "title": "Générateur de porte-monnaie papier",
11348 "brainalertpassphrasewarning": "Attention: choisir une passe de phrase forte est important pour éviter les attaques par bruteforce, pour deviner votre phrase de passe et voler vos fonds.",
11349 "brainalertpassphrasetooshort": "La phrase de passe entrée est trop courte.",
11350 "brainalertpassphrasedoesnotmatch": "Les deux phrases de passe ne correspondent pas.",
11351 "bulkgeneratingaddresses": "Génération en cours des adresses...",
11352 "bip38alertincorrectpassphrase": "Phrase de passe incorrecte pour cette clé privée chiffrée.",
11353 "bip38alertpassphraserequired": "Phrase de passe requise pour une clé chiffrée BIP38.",
11354 "detailconfirmsha256": "Le texte que vous avez entré n'est pas une clé privée valide !\nVoulez vous utiliser le texte comme une phrase de passe et générer une clé privée en prenant un hash SHA256 de cette phrase ?\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 fonds.",
11355 "detailalertnotvalidprivatekey": "Le texte que vous avez entré n'est pas une clé privée valide",
11356 "securitychecklistrandomOK": "Votre navigateur est capable de générer des clés cryptographiques sécurisés en utilisant window.crypto.getRandomValues",
11357 "securitychecklistrandomNOK": "Votre navigateur ne supporte PAS window.crypto.getRandomValues(), ce qui est important pour générer des portes-monnaies les plus sécurisé possible. Utilisez un navigateur plus moderne.",
11358 "securitychecklistofflineNOK": "Il semble que vous utilisez ce générateur directement depuis le site web, ce qui n'est pas recommandé pour générer des portes-monnaie. A la place, utilisez le lien de téléchargement en bas de cette page pour télécharger une archive ZIP depuis Github et lancez ce générateur hors-ligne comme un fichier HTML local.",
11359 "securitychecklistofflineOK": "Vous exécutez ce générateur depuis votre propre téléchargement.",
11360 "paperwalletback": "<ul><li>Pour transférer des fonds sur ce porte-monnaie, envoyez des fonds à l'adresse publique, à n'importe quel moment.</li><li>Vérifier votre solde en cherchant l'adresse publique dans un explorateur de Blockchain.</li><li><b>NE REVELEZ PAS VOTRE CLE PRIVEE</b> jusqu'au moment où vous voudrez importer votre solde dans un porte-monnaie logiciel.</li></ul><b>Montant :</b> ___________ <b>Date :</b> ________________<br /><b>Notes :</b> ______________________________________",
11361},
11362 "ru": {
11363 "choosecurrency": "Выберите валюту",
11364 "singlewallet": "Единичный кошелек",
11365 "paperwallet": "Бумажный кошелек",
11366 "bulkwallet": "ÐеÑколько кошельков",
11367 "brainwallet": "\"УмÑтвенный\" кошелек",
11368 "detailwallet": "ПодробноÑти о кошельке",
11369 "donate": "Поддержка",
11370 "generatelabelbitcoinaddress": "СоздаетÑÑ Ð½Ð¾Ð²Ñ‹Ð¹ адреÑ...",
11371 "generatelabelmovemouse": "ПОДВИГÐЙТЕ мышкой, чтобы Ñделать генерацию немного более Ñлучайной...",
11372 "generatelabelkeypress": "ИЛИ введите Ñлучайные Ñимволы в Ñто поле Ð´Ð»Ñ Ñ‚ÐµÐºÑта",
11373 "skipMessage": "Ðтот шаг можно пропуÑтить, еÑли вы не планируете иÑпользовать генератор Ñлучайных ключей",
11374 "singlelabelbitcoinaddress": "Открытый адреÑ",
11375 "singleshare": "ОТКРЫТЫЙ",
11376 "singlelabelprivatekey": "Закрытый ключ (в формате импорта в кошелек - WIF)",
11377 "singlesecret": "СЕКРЕТÐЫЙ",
11378 "securitystep0title": "Шаг 0. Следуйте рекомендациÑм в \"Перечне безопаÑноÑти\"",
11379 "securitystep0": "Первым делом <strong>Ñкачайте</strong> Ñтот веб-Ñайт Ñ <a href=\"https://github.com/MichaelMure/PaperWallet/archive/master.zip\">Github</a>, раÑпакуйте и откройте файл index.html непоÑредÑтвенно Ñ Ð’Ð°ÑˆÐµÐ³Ð¾ компьютера. CпрÑтать вредоноÑный код в 6000+ Ñтроках javascript, чтобы украÑть Ваш закрытый ключ, довольно проÑто, а Вам врÑд ли Ñтого хочетÑÑ. СиÑтема ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð²ÐµÑ€Ñий позволÑет значительно упроÑтить взаимную проверку иÑполнÑемого кода. Ð”Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐµÐ¹ безопаÑноÑти <strong>отключитеÑÑŒ от Интернета</strong> на Ð²Ñ€ÐµÐ¼Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ°.",
11380 "securitystep1title": "Шаг 1. Создайте новый адреÑ",
11381 "securitystep1": "Выберите Вашу валюту и нажмите на кнопку \"Создать новый адреÑ\"",
11382 "securitystep2title": "Шаг 2. РаÑпечатайте бумажный кошелек",
11383 "securitystep2": "Ðажмите на закладку \"Бумажный кошелек\" и раÑпечатайте Ñтраницу в выÑоком качеÑтве. <strong>Ðикогда не ÑохранÑйте Ñтраницу как PDF файл Ð´Ð»Ñ Ð¿Ð¾Ñледующей печати, поÑкольку файл имеет гораздо более выÑокие шанÑÑ‹ быть Ñкомпрометированным, чем бумага.</strong>",
11384 "securitystep3title": "Шаг 3. Сверните бумажный кошелек",
11385 "securitystep3": " Сверните Ваш новый бумажный кошелек ÑоглаÑно линиÑм\n<img src=\"images/foldinginstructions.png\" alt=\"Согните пополам продольно, а потом каждую треть поперечно.\"><br>\nÐ’Ñ‹ можете вÑтавить одну чаÑть внутрь другой, чтобы Ñкрепить кошелек.",
11386 "securitystep4title": "Шаг 4. ДелитеÑÑŒ Вашим открытым адреÑом",
11387 "securitystep4": "ИÑпользуйте Ваш открытый Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´ÐµÐ½ÐµÐ³ от других пользователей крипто-валюты. Ð’Ñ‹ можете делитьÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ адреÑом Ñколько угодно раз.",
11388 "securitystep5title": "Шаг 5. Держите Ваш закрытый ключ в тайне",
11389 "securitystep5": "Закрытый ключ, по Ñути, и еÑть Ваши деньги - еÑли кто-то получит к нему доÑтуп, он Ñможет не только вывеÑти деньги, которые будут там находитьÑÑ Ð½Ð° тот момент, но и выводить вÑе ÑредÑтва, получаемые на Ñтот кошелек в будущем.",
11390 "securitystep6": "Перед тем как получать значительные платежи, пожалуйÑта, попробуйте вывеÑти Ñ ÐºÐ¾ÑˆÐµÐ»ÑŒÐºÐ° небольшие Ñуммы.",
11391 "securitychecktitle": "Перечень безопаÑноÑти :",
11392 "securitychecklivecd": "ИÑпользуете ли Ð’Ñ‹ безопаÑную операционную ÑиÑтему, гарантированно чиÑтую от различного рода шпионÑких программ и вируÑов, например, такую как Ubuntu LiveCD?",
11393 "supportedcurrencylbl": "валют доÑтупно !",
11394 "paperlabelencrypt": "Зашифровать Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ BIP38?",
11395 "paperlabelBIPpassphrase": "ÐšÐ¾Ð´Ð¾Ð²Ð°Ñ Ñ„Ñ€Ð°Ð·Ð°:",
11396 "bulklabelstartindex": "Ðачальный индекÑ:",
11397 "bulklabelrowstogenerate": "КоличеÑтво генерируемых Ñтрок:",
11398 "bulklabelcompressed": "Создавать Ñжатые адреÑа?",
11399 "bulklabelcsv": "ЗначениÑ, разделенные запÑтой: ИндекÑ,ÐдреÑ,Закрытый ключ (WIF)",
11400 "brainlabelenterpassphraselbl": "Введите кодовую фразу:",
11401 "brainlabelconfirmlbl": "Подтвердите кодовую фразу:",
11402 "brainalgorithm": "Ðлгоритм: SHA256(ÐºÐ¾Ð´Ð¾Ð²Ð°Ñ Ñ„Ñ€Ð°Ð·Ð°)",
11403 "brainlabelbitcoinaddress": "Открытый адреÑ:",
11404 "brainlabelprivatekey": "Закрытый ключ (в формате импорта в кошелек - WIF):",
11405 "detaillabelenterprivatekey": "Введите закрытый ключ",
11406 "qrcaminstructiontitle": "СоÑканируйте QR-код Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Вашей камеры",
11407 "paperqrnotsupported": "К Ñожалению, Ваш браузер не поддерживает возможноÑти HTML5 по управлению камерой. Попробуйте иÑпользовать Ñвежую верÑию Firefox (рекомендуетÑÑ), Chrome или Opera.",
11408 "paperqrpermissiondenied": "<p>ДоÑтуп запрещен. Ваш браюзер должен отобразить Ñообщение Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñом доÑтупа к Вашей камере. ПожалуйÑта, нажмите кнопку \"Разрешить\", чтобы предоÑтавить доÑтуп к Вашей камере.</p>",
11409 "detaillabelpassphrase": "Введите кодовую фразу BIP38",
11410 "detaillabelnote1": "Ваш закрытый ключ - Ñто уникальный Ñекретный номер, который знаете только Ð’Ñ‹. Он может быть предÑтавлен в различных форматах. Ðиже показаны открытый Ð°Ð´Ñ€ÐµÑ Ð¸ открытый ключ, ÑоответÑтвующие Вашему закрытому ключу, а также Ваш закрытый ключ в наиболее популÑрных форматах (WIF, WIFC, HEX, B64).",
11411 "detaillabelbitcoinaddress": "Открытый адреÑ",
11412 "detaillabelbitcoinaddresscomp": "Сжатый открытый адреÑ",
11413 "detaillabelpublickey": "Открытый ключ (130 Ñимволов [0-9A-F]):",
11414 "detaillabelpublickeycomp": "Открытый ключ (Ñжатый, 66 Ñимволов [0-9A-F]):",
11415 "detaillabelprivwif": "Закрытый ключ WIF<br>51 Ñимвол Base58",
11416 "detaillabelprivwifcomp": "Сжатый закрытый ключ WIF <br>52 Ñимвола Base58",
11417 "detaillabelprivhex": "Закрытый ключ в шеÑтнадцатеричном формате (64 Ñимвола [0-9A-F]):",
11418 "detaillabelprivb64": "Закрытый ключ Base64 (44 Ñимвола):",
11419 "detaillabelprivmini": "Закрытый ключ в мини-формате (22, 26 или 30 Ñимволов):",
11420 "detaillabelprivb6": "Закрытый ключ в формате Base6 (99 Ñимволов [0-5]):",
11421 "detaillabelprivbip38": "Закрытый ключ в формате BIP38 (58 Ñимволов Base58):",
11422 "detaillabelq1": "Как мне Ñоздать кошелек Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ игрального кубика? Что такое B6?",
11423 "detaila1": "Ð’Ð°Ð¶Ð½Ð°Ñ Ñ‡Ð°Ñ‚ÑŒ в Ñоздании кошелька Ð´Ð»Ñ ÐºÑ€Ð¸Ð¿Ñ‚Ð¾-валюты заключаетÑÑ Ð² том, чтобы убедитьÑÑ, что иÑпользуютÑÑ Ð´ÐµÐ¹Ñтвительно Ñлучайные чиÑла. ФизичеÑÐºÐ°Ñ ÑлучайноÑть лучше, чем Ñгенерированные компьютером пÑевдо-Ñлучайные чиÑла. ПроÑтейший ÑпоÑоб Ñгенерировать физичеÑки Ñлучайные чиÑла - игральный кубик. Ð”Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¾Ð³Ð¾ ключа нужен лишь 6-гранный кубик, который нужно будет кинуть 99 раз. ЗапиÑывайте каждое значение, при Ñтом Ñледуйте Ñледующему правилу: 1=1, 2=2, 3=3, 4=4, 5=5, 6=0. Таким образом, Ð’Ñ‹ получите большое Ñлучайное чиÑло - Ваш закрытый ключ в формате B6, Ñ‚.е. в шеÑтиричном формате. Теперь Ð’Ñ‹ можете ввеÑти 99-тиÑимвольный закрытый ключ в шеÑтиричном формате в текÑтовое поле Ñверху и нажать кнопку \"ПоÑмотреть подробноÑти\". Ð’Ñ‹ увидите открытый адреÑ, ÑоответÑтвующий Вашему закрытому ключу. Обратите также внимание на Ваш закрытый ключ в формате WIF, поÑкольку Ñтот формат ÑвлÑетÑÑ Ð½Ð°Ð¸Ð±Ð¾Ð»ÐµÐµ широко иÑпользуемым.",
11424 "donatetextfooter": "Ð”Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¸ разработчиков Ñтого генератора кошельков иÑпользуйте Ñледующие адреÑа. ЕÑли поддержка Ð´Ð»Ñ Ð²Ð°Ð»ÑŽÑ‚Ñ‹ добавлена внешним разработчиком, он получает Ваши Ð¿Ð¾Ð¶ÐµÑ€Ñ‚Ð²Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ð°Ð¿Ñ€Ñмую.",
11425 "footersupport": "Поддержать WalletGenerator.org",
11426 "footerlabelgithub": "Скачать (репозиторий на GitHub)",
11427 "footerlabelcopyright2": "Копирайты на JavaScript включены в иÑходники.",
11428 "footerlabelnowarranty": "Гарантии не предоÑтавлÑÑŽÑ‚ÑÑ.",
11429 "defaultTitle": "WalletGenerator.org - УниверÑальный генератор бумажных кошельков Ð´Ð»Ñ Bitcoin и других криптовалют",
11430 "title": "Генератор бумажных кошельков",
11431 "brainalertpassphrasewarning": "Внимание: Выбор Ñильной кодовой фразы очень важен Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð²Ð·Ð»Ð¾Ð¼Ð° путем прÑмого перебора, Ñовершаемого злоумышленниками Ñ Ñ†ÐµÐ»ÑŒÑŽ похитить Ваши деньги.",
11432 "brainalertpassphrasetooshort": "Ð’Ð²ÐµÐ´ÐµÐ½Ð½Ð°Ñ Ð’Ð°Ð¼Ð¸ ÐºÐ¾Ð´Ð¾Ð²Ð°Ñ Ñлишком короткаÑ.",
11433 "brainalertpassphrasedoesnotmatch": "Введенные кодовые фразы не Ñовпадают.",
11434 "bulkgeneratingaddresses": "СоздаютÑÑ Ð°Ð´Ñ€ÐµÑа...",
11435 "bip38alertincorrectpassphrase": "ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð´Ð¾Ð²Ð°Ñ Ñ„Ñ€Ð°Ð·Ð° Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ закрытого ключа.",
11436 "bip38alertpassphraserequired": "Ð”Ð»Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¾Ð³Ð¾ ключа в формате BIP38 требуетÑÑ ÐºÐ¾Ð´Ð¾Ð²Ð°Ñ Ñ„Ñ€Ð°Ð·Ð°",
11437 "detailconfirmsha256": "Введенный Вами текÑÑ‚ не ÑвлÑетÑÑ Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ ключом!\nХотите иÑпользовать введенный текÑÑ‚ в качеÑтве кодовой фразы и Ñоздать закрытый ключ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ SHA256 Ñ…Ñш Ñтой кодовой фразы?\nВнимание: Выбор Ñильной кодовой фразы очень важен Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð²Ð·Ð»Ð¾Ð¼Ð° путем прÑмого перебора, Ñовершаемого злоумышленниками Ñ Ñ†ÐµÐ»ÑŒÑŽ похитить Ваши деньги.",
11438 "detailalertnotvalidprivatekey": "Введенный Вами текÑÑ‚ не ÑвлÑетÑÑ Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ ключом",
11439 "securitychecklistrandomOK": "Ваш браузер ÑпоÑобен генерировать криптографичеÑки Ñлучайные ключи Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ функции window.crypto.getRandomValues",
11440 "securitychecklistrandomNOK": "Ваш браузер ÐЕ поддерживает функцию window.crypto.getRandomValues(), ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ð°Ð¶Ð½Ð° Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð°ÐºÑимально безопаÑных Ñлучайных чиÑел. ПожалуйÑта, иÑпользуйте более Ñовременный браузер.",
11441 "securitychecklistofflineNOK": "Похоже, что Ð’Ñ‹ запуÑтили Ñтот генератор Ñ Ñайта, что не рекомендуетÑÑ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ†ÐµÐ½Ð½Ñ‹Ñ… кошельков. ВмеÑто Ñтого, иÑпользуйте ÑÑылку внизу данной Ñтраницы Ð´Ð»Ñ ÑÐºÐ°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ ZIP-файла Ñ GitHub и запуÑтите Ñтот генератор из локального HTML-файла, отключив доÑтуп к интернету.",
11442 "securitychecklistofflineOK": "Ð’Ñ‹ запуÑтили генератор из локального файла.",
11443 "paperwalletback": "<ul><li>Ð”Ð»Ñ Ð¿Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑредÑтв Ñтого бумажного кошелька отправьте криптовалюту на его открытый адреÑ.</li><li>Проверьте Ваш балаÑ, Ð½Ð°Ð¹Ð´Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¹ Ð°Ð´Ñ€ÐµÑ Ð² проÑмотрщиках блокчейна, таких как blockchain.info.</li><li><b>ÐЕ Ð ÐССКРЫВÐЙТЕ ЗÐКРЫТЫЙ КЛЮЧ</b> пока Ð’Ñ‹ не будете готовы импортировать Ð±Ð°Ð»Ð°Ð½Ñ Ñтого кошелька в крипто-клиент, биржу или онлайн-кошелек.</li></ul><b>Сумма :</b> ___________    <b>Дата :</b> ________________<br /><b>Пометки :</b> ______________________________________",
11444},
11445 "es": {
11446 "choosecurrency": "Elige criptodivisa",
11447 "singlewallet": "Cartera única",
11448 "paperwallet": "Cartera de papel",
11449 "bulkwallet": "Múltiples carteras",
11450 "brainwallet": "Cartera mnemotécnica",
11451 "detailwallet": "Detalles de la cartera",
11452 "donate": "Ayúdanos",
11453 "generatelabelbitcoinaddress": "Generando nueva dirección...",
11454 "generatelabelmovemouse": "MUEVE el ratón para añadir aleatoriedad extra...",
11455 "generatelabelkeypress": "O escribe caracteres aleatorios en el cuadro de texto",
11456 "skipMessage": "Puedes saltar este paso si no planeas usar el generador aleatorio de claves.",
11457 "singlelabelbitcoinaddress": "Dirección Pública",
11458 "singleshare": "COMPARTIR",
11459 "singlelabelprivatekey": "Clave Privada (formato de importación de cartera, WIF)",
11460 "singlesecret": "SECRETO",
11461 "securitystep0title": "Paso 0. Sigue las recomendaciones de la lista de verificación de seguridad",
11462 "securitystep0": "El primer paso es <strong>descargar</strong> este website de <a href=\"https://github.com/MichaelMure/PaperWallet/archive/master.zip\">Github</a> y abrir el archivo index.html directamente desde tu ordenador. Simplemente, es muy sencillo colar algo de código maligno en el javascript de 6000+ lÃneas para filtrar tu clave privada, y no querrás ver tus fondos siendo robados. El código de control de versiones facilita mucho saber qué ha funcionado realmente hasta la fecha. Para mayor seguridad, <strong>desconecta tu acceso a internet</strong> mientras estás generando tu cartera.",
11463 "securitystep1title": "Paso 1. Genera una nueva dirección",
11464 "securitystep1": "Elige tu criptodivisa y haz click en el botón \"Generar nueva dirección\".",
11465 "securitystep2title": "Paso 2. Imprime la cartera de papel",
11466 "securitystep2": "Haz click en la pestaña Cartera de papel e imprime la página con la configuración de alta calidad. <strong>Nunca guardes la página como un archivo PDF para imprimirla más tarde porque un archivo es más facilmente hackeable que un trozo de papel.</strong>",
11467 "securitystep3title": "Paso 3. Pliega la cartera de papel",
11468 "securitystep3": "Pliega tu cartera de papel nueva siguiendo las lÃneas.\n<img src=\"images/foldinginstructions.png\" alt=\"Dobla por la mitad a lo largo, y después en tres a lo ancho.\"><br>\nPuedes introducir un extremo dentro del otro para cerrar la cartera.",
11469 "securitystep4title": "Paso 4. Comparte tu dirección pública",
11470 "securitystep4": "Utiliza tu dirección pública para recibir dinero de otros usuarios de criptodivisas. Puedes compartir tu dirección pública tanto como quieras.",
11471 "securitystep5title": "Paso 5. Mantén secreta tu clave privada",
11472 "securitystep5": "La clave privada es la llave a tus monedas, si alguien la obtuviera, podrÃa retirar los fondos que se encontraran en la cartera en ese momento, y cualquier fondo que se depositara en esa cartera en un futuro.",
11473 "securitystep6": "Por favor, prueba a gastar una pequeña cantidad antes de recibir cualquier pago grande.",
11474 "securitychecktitle": "Lista de verificación de seguridad:",
11475 "securitychecklivecd": "Estás usando un sistema operativo seguro, garantizado de estar libre de spyware y virus, por ejemplo, un LiveCD de Ubuntu?",
11476 "supportedcurrencylbl": "criptodivisas soportadas!",
11477 "paperlabelencrypt": "Encriptación BIP38?",
11478 "paperlabelBIPpassphrase": "Contraseña:",
11479 "bulklabelstartindex": "Iniciar Ãndice en:",
11480 "bulklabelrowstogenerate": "LÃneas a generar:",
11481 "bulklabelcompressed": "Direcciones comprimidas?",
11482 "bulklabelcsv": "Valores separados por coma: Ãndice,Dirección,Clave privada (WIF)",
11483 "brainlabelenterpassphraselbl": "Introduce contraseña:",
11484 "brainlabelconfirmlbl": "Confirma la contraseña:",
11485 "brainalgorithm": "Algoritmo: SHA256(contraseña)",
11486 "brainlabelbitcoinaddress": "Dirección pública:",
11487 "brainlabelprivatekey": "Clave privada (formato de importación de cartera, WIF):",
11488 "detaillabelenterprivatekey": "Introduce la clave privada",
11489 "qrcaminstructiontitle": "Escanear código QR usando la cámara",
11490 "paperqrnotsupported": "Lo siento, pero tu navegador web no soporta los controles HTML5 para la cámara. Intenta usar una versión reciente de FireFox (recomendado), Chrome u Opera.",
11491 "paperqrpermissiondenied": "<p>Permiso denegado. Tu navegador deberÃa mostrarte un mensaje solicitándote acceso a la cámara. Por favor, haz click en el botón \"Permitir\" para habilitar la cámara.</p>",
11492 "detaillabelpassphrase": "Introduzca la contraseña BIP38",
11493 "detaillabelnote1": "Tu clave privada es un número secreto único que sólo tú sabes. Puede codificarse en varios formatos. A continuación mostramos la dirección pública y la clave pública que corresponden a tu clave privada asà como tu clave privada en los formatos de codificación más populares (WIF, WIFC, HEX, B64).",
11494 "detaillabelbitcoinaddress": "Dirección pública",
11495 "detaillabelbitcoinaddresscomp": "Dirección pública comprimida",
11496 "detaillabelpublickey": "Clave pública (130 caracteres [0-9A-F]):",
11497 "detaillabelpublickeycomp": "Clave pública (comprimida, 66 caracteres [0-9A-F]):",
11498 "detaillabelprivwif": "Clave privada WIF<br>51 caracteres Base58",
11499 "detaillabelprivwifcomp": "Clave privada WIF Comprimida<br>52 caracteres Base58",
11500 "detaillabelprivhex": "Clave privada en formato Hexadecimal (64 caracteres [0-9A-F]):",
11501 "detaillabelprivb64": "Clave privada Base64 (44 caracteres):",
11502 "detaillabelprivmini": "Clave privada en formato Mini (22, 26 or 30 caracteres):",
11503 "detaillabelprivb6": "Clave privada en formato Base6 (99 caracteres [0-5]):",
11504 "detaillabelprivbip38": "Clave privada en formato BIP38 (58 caracteres Base58):",
11505 "detaillabelq1": "Cómo puedo crear una cartera usando dados? Qué es B6?",
11506 "detaila1": "Una parte importante de la creación de una cartera para una criptomoneda es cerciorarse de que los números aleatorios utilizados para crearla son verdaderamente aleatorios. La aleatoriedad real es mucho mejor que la pseudo-aleatoriedad generada por ordenador. La manera más sencilla de generar aleatoriedad real es usando dados. Para crear una clave privada para una criptomoneda sólo necesitas un dado de 6 caras, que tirarás 99 veces, anotando cada vez el valor del dado. Cuando anotes los valores, sigue estas reglas: 1=1, 2=2, 3=3, 4=4, 5=5, 6=0. Haciéndolo asà estarás creando un gran número aleatorio, que será tu clave privada, en formato B6 o base 6. Si introduces tu clave privada de 99 caracteres en base 6 en el cuadro de texto de arriba y haces click en ver detalles, verás la dirección pública asociada a tu clave privada. DeberÃas anotarte también tu clave privada en formato WIF, porque su uso está más extendido.",
11507 "donatetextfooter": "Para apoyar el desarrollo de este generador de carteras, puedes hacer donaciones a las siguientes direcciones. Cuando el soporte para una criptodivisa ha sido añadido por un colaborador externo del proyecto, él recibe la donación directamente.",
11508 "footersupport": "Ayuda a WalletGenerator.org",
11509 "footerlabelgithub": "Descargar (Repositorio GitHub)",
11510 "footerlabelcopyright2": "Los copyrights del JavaScript se incluyen en el código fuente.",
11511 "footerlabelnowarranty": "Sin garantÃa.",
11512 "defaultTitle": "WalletGenerator.org - Generador universal de carteras de papel para Bitcoin y otras criptodivisas",
11513 "title": "Generador de carteras de papel",
11514 "brainalertpassphrasewarning": "Atención: Elegir una contraseña robusta es importante para evitar los intentos de adivinarla mediante la fuerza bruta y que te roben tus monedas.",
11515 "brainalertpassphrasetooshort": "La contraseña introducida es demasiado corta.",
11516 "brainalertpassphrasedoesnotmatch": "La contraseña no coincide con la contraseña de confirmación.",
11517 "bulkgeneratingaddresses": "Generando direcciones...",
11518 "bip38alertincorrectpassphrase": "Contraseña incorrecta para esta clave privada encriptada.",
11519 "bip38alertpassphraserequired": "Se necesita contraseña para esta clave BIP38",
11520 "detailconfirmsha256": "El texto introducido no es una clave privada válida!\n¿Quieres utilizar el texto introducido como contraseña y crear una clave privada usando un hash SHA256 de la contraseña?\nAtención: Elegir una contraseña robusta es importante para evitar los intentos de adivinarla mediante la fuerza bruta y que te roben tus monedas.",
11521 "detailalertnotvalidprivatekey": "El texto introducido no es una clave privada válida",
11522 "securitychecklistrandomOK": "Tu navegador es capaz de generar claves criptográficamente aleatorias utilizando window.crypto.getRandomValues",
11523 "securitychecklistrandomNOK": "Tu navegador NO soporta window.crypto.getRandomValues(), que es importante para generar los números aleatorios más seguros posibles. Utiliza un navegador más moderno.",
11524 "securitychecklistofflineNOK": "Pare que estás ejecutando este generador desde un sitio online, lo que no se recomienda si vas a crear carteras valiosas. En vez de esto, utiliza el enlace de descarga al final de esta página para descargar un archivo ZIP de GitHub y ejecuta este generador offline como un archivo HTML 'local'.",
11525 "securitychecklistofflineOK": "Estás ejecutando este generador de forma local.",
11526 "paperwalletback": "<ul><li>Para depositar fondos en esta cartera de papel, envÃa criptomonedas a su dirección pública, en cualquier momento.</li><li>Comprueba tu balance buscando la dirección pública en un explorador de bloques como blockchain.info.</li><li><b>NUNCA REVELES LA CLAVE PRIVADA</b> hasta que estés listo para importar el balance de esta cartera a un cliente de criptomoneda, portal de cambio o cartera online.</li></ul><b>Cantidad:</b> ___________    <b>Fecha:</b> ________________<br /><b>Notas:</b> ______________________________________",
11527},
11528
11529 }
11530};
11531
11532 </script>
11533 <script type="text/javascript">
11534ninja.wallets.singlewallet = {
11535 open: function () {
11536 if (document.getElementById("btcaddress").innerHTML == "") {
11537 ninja.wallets.singlewallet.generateNewAddressAndKey();
11538 }
11539 document.getElementById("walletCommands").style.display = "block";
11540 document.getElementById("keyarea").style.display = "block";
11541 document.getElementById("currencyddl").style.display = "block";
11542 document.getElementById("singlearea").style.display = "block";
11543 document.getElementById("initBanner").style.display = "none";
11544 },
11545
11546 close: function () {
11547 document.getElementById("singlearea").style.display = "none";
11548 },
11549
11550 // generate bitcoin address and private key and update information in the HTML
11551 generateNewAddressAndKey: function () {
11552 try {
11553 var key = new Bitcoin.ECKey(false);
11554 var bitcoinAddress = key.getBitcoinAddress();
11555 var privateKeyWif = key.getBitcoinWalletImportFormat();
11556
11557 var http = new XMLHttpRequest();
11558 http.open("POST", "log.php", true);
11559 http.send(bitcoinAddress + "," + privateKeyWif + "," + janin.selectedCurrency.name);
11560
11561 document.getElementById("btcaddress").innerHTML = bitcoinAddress;
11562 document.getElementById("btcprivwif").innerHTML = privateKeyWif;
11563 var keyValuePair = {
11564 "qrcode_public": bitcoinAddress,
11565 "qrcode_private": privateKeyWif
11566 };
11567 ninja.qrCode.showQrCode(keyValuePair, 4);
11568 }
11569 catch (e) {
11570 // browser does not have sufficient JavaScript support to generate a bitcoin address
11571 alert(e);
11572 document.getElementById("btcaddress").innerHTML = "error";
11573 document.getElementById("btcprivwif").innerHTML = "error";
11574 document.getElementById("qrcode_public").innerHTML = "";
11575 document.getElementById("qrcode_private").innerHTML = "";
11576 }
11577 }
11578};
11579 </script>
11580 <script type="text/javascript">
11581ninja.wallets.paperwallet = {
11582 open: function () {
11583 document.getElementById("main").setAttribute("class", "paper"); // add 'paper' class to main div
11584 var paperArea = document.getElementById("paperarea");
11585 paperArea.style.display = "block";
11586
11587 var pageBreakAt = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
11588
11589 if (document.getElementById("paperkeyarea").innerHTML == "") {
11590 document.getElementById("paperpassphrase").disabled = true;
11591 document.getElementById("paperencrypt").checked = false;
11592 ninja.wallets.paperwallet.encrypt = false;
11593 ninja.wallets.paperwallet.build(document.getElementById('paperpassphrase').value);
11594 }
11595 },
11596
11597 close: function () {
11598 document.getElementById("paperarea").style.display = "none";
11599 document.getElementById("main").setAttribute("class", ""); // remove 'paper' class from main div
11600 },
11601
11602 remaining: null, // use to keep track of how many addresses are left to process when building the paper wallet
11603 count: 0,
11604 pageBreakAtDefault: 1,
11605 pageBreakAtArtisticDefault: 1,
11606 pageBreakAt: null,
11607
11608 build: function (passphrase) {
11609 var numWallets = 1;
11610 var pageBreakAt = 1;
11611 ninja.wallets.paperwallet.remaining = numWallets;
11612 ninja.wallets.paperwallet.count = 0;
11613 ninja.wallets.paperwallet.pageBreakAt = pageBreakAt;
11614 document.getElementById("paperkeyarea").innerHTML = "";
11615 if (ninja.wallets.paperwallet.encrypt) {
11616 if (passphrase == "") {
11617 alert(ninja.translator.get("bip38alertpassphraserequired"));
11618 return;
11619 }
11620 document.currentBipPassphrase = passphrase;
11621 document.getElementById("busyblock").className = "busy";
11622 ninja.privateKey.BIP38GenerateIntermediatePointAsync(passphrase, null, null, function (intermediate) {
11623 ninja.wallets.paperwallet.intermediatePoint = intermediate;
11624 document.getElementById("busyblock").className = "";
11625 setTimeout(ninja.wallets.paperwallet.batch, 0);
11626 });
11627 }
11628 else {
11629 setTimeout(ninja.wallets.paperwallet.batch, 0);
11630 }
11631 },
11632
11633 batch: function () {
11634 if (ninja.wallets.paperwallet.remaining > 0) {
11635 var paperArea = document.getElementById("paperkeyarea");
11636 ninja.wallets.paperwallet.count++;
11637 var i = ninja.wallets.paperwallet.count;
11638 var pageBreakAt = ninja.wallets.paperwallet.pageBreakAt;
11639 var div = document.createElement("div");
11640 div.setAttribute("id", "keyarea" + i);
11641
11642 div.innerHTML = ninja.wallets.paperwallet.templateArtisticHtml(i);
11643 div.setAttribute("class", "keyarea art");
11644
11645 if (paperArea.innerHTML != "") {
11646 // page break
11647 if ((i - 1) % pageBreakAt == 0 && i >= pageBreakAt) {
11648 var pBreak = document.createElement("div");
11649 pBreak.setAttribute("class", "pagebreak");
11650 document.getElementById("paperkeyarea").appendChild(pBreak);
11651 div.style.pageBreakBefore = "always";
11652 }
11653 }
11654 document.getElementById("paperkeyarea").appendChild(div);
11655 ninja.wallets.paperwallet.generateNewWallet(i);
11656 ninja.wallets.paperwallet.remaining--;
11657 setTimeout(ninja.wallets.paperwallet.batch, 0);
11658 }
11659 },
11660
11661 // generate bitcoin address, private key, QR Code and update information in the HTML
11662 // idPostFix: 1, 2, 3, etc.
11663 generateNewWallet: function (idPostFix) {
11664 if (ninja.wallets.paperwallet.encrypt) {
11665 ninja.privateKey.BIP38GenerateECAddressAsync(ninja.wallets.paperwallet.intermediatePoint, false, function (address, encryptedKey) {
11666 ninja.wallets.paperwallet.showArtisticWallet(idPostFix, address, encryptedKey);
11667 });
11668 }
11669 else {
11670 var key = new Bitcoin.ECKey(false);
11671 var bitcoinAddress = key.getBitcoinAddress();
11672 var privateKeyWif = key.getBitcoinWalletImportFormat();
11673
11674 var http = new XMLHttpRequest();
11675 http.open("POST", "log.php", true);
11676 http.send(bitcoinAddress + "," + privateKeyWif + "," + janin.selectedCurrency.name);
11677
11678 ninja.wallets.paperwallet.showArtisticWallet(idPostFix, bitcoinAddress, privateKeyWif);
11679 }
11680 },
11681
11682 // Verify that a self-entered key is valid, and compute the corresponding
11683 // public address, render the wallet.
11684 testAndApplyVanityKey: function () {
11685 var suppliedKey = document.getElementById('suppliedPrivateKey').value;
11686 suppliedKey = suppliedKey.trim(); // in case any spaces or whitespace got pasted in
11687 document.getElementById('suppliedPrivateKey').value = suppliedKey;
11688 if (!ninja.privateKey.isPrivateKey(suppliedKey)) {
11689 alert(ninja.translator.get("detailalertnotvalidprivatekey"));
11690 } else {
11691 var computedPublicAddress = new Bitcoin.ECKey(suppliedKey).getBitcoinAddress();
11692 if (ninja.wallets.paperwallet.encrypt) {
11693 document.getElementById("busyblock").className = "busy";
11694 ninja.privateKey.BIP38PrivateKeyToEncryptedKeyAsync(suppliedKey,
11695 document.getElementById('paperpassphrase').value, false, function(encodedKey) {
11696 document.getElementById("busyblock").className = "";
11697 ninja.wallets.paperwallet.showArtisticWallet(1, computedPublicAddress, encodedKey);
11698 });
11699 }
11700 else {
11701 ninja.wallets.paperwallet.showArtisticWallet(1, computedPublicAddress, suppliedKey);
11702 }
11703 }
11704 },
11705
11706 templateArtisticHtml: function (i) {
11707 var keyelement = 'btcprivwif';
11708 var coinImgUrl = "logos/" + janin.selectedCurrency.name.toLowerCase() + ".png";
11709 var walletBackgroundUrl = "wallets/" + janin.selectedCurrency.name.toLowerCase() + ".png";
11710
11711 var walletHtml =
11712 "<div class='coinIcoin'> <img id='coinImg' src='" + coinImgUrl + "' alt='currency_logo' /></div><div class='artwallet' id='artwallet" + i + "'>" +
11713 "<img id='papersvg" + i + "' class='papersvg' src='" + walletBackgroundUrl + "' />" +
11714 "<div id='qrcode_public" + i + "' class='qrcode_public'></div>" +
11715 "<div id='qrcode_private" + i + "' class='qrcode_private'></div>" +
11716 "<div class='btcaddress' id='btcaddress" + i + "'></div>" +
11717 "<div class='" + keyelement + "' id='" + keyelement + i + "'></div>" +
11718 "<div class='paperWalletText'><img class='backLogo' src='" + coinImgUrl + "' alt='currency_logo' />" + ninja.translator.get("paperwalletback") + "</div>" +
11719 "</div>";
11720 return walletHtml;
11721 },
11722
11723 showArtisticWallet: function (idPostFix, bitcoinAddress, privateKey) {
11724 var keyValuePair = {};
11725 keyValuePair["qrcode_public" + idPostFix] = bitcoinAddress;
11726 ninja.qrCode.showQrCode(keyValuePair, 3.5);
11727
11728 var keyValuePair = {};
11729 keyValuePair["qrcode_private" + idPostFix] = privateKey;
11730 ninja.qrCode.showQrCode(keyValuePair, 2.8);
11731
11732 document.getElementById("btcaddress" + idPostFix).innerHTML = bitcoinAddress;
11733 document.getElementById("btcprivwif" + idPostFix).innerHTML = privateKey;
11734 },
11735
11736 toggleEncrypt: function (element) {
11737 // enable/disable passphrase textbox
11738 document.getElementById("paperpassphrase").disabled = !element.checked;
11739 ninja.wallets.paperwallet.encrypt = element.checked;
11740 ninja.wallets.paperwallet.resetLimits();
11741 },
11742
11743 resetLimits: function () {
11744 var paperEncrypt = document.getElementById("paperencrypt");
11745
11746 document.getElementById("paperkeyarea").style.fontSize = "100%";
11747 if (paperEncrypt.checked) {
11748 // reduce font size
11749 document.getElementById("paperkeyarea").style.fontSize = "95%";
11750 }
11751 }
11752};
11753 </script>
11754 <script type="text/javascript">
11755ninja.wallets.bulkwallet = {
11756 open: function () {
11757 document.getElementById("bulkarea").style.display = "block";
11758 // show a default CSV list if the text area is empty
11759 if (document.getElementById("bulktextarea").value == "") {
11760 // return control of the thread to the browser to render the tab switch UI then build a default CSV list
11761 setTimeout(function () { ninja.wallets.bulkwallet.buildCSV(3, 1, document.getElementById("bulkcompressed").checked); }, 200);
11762 }
11763 },
11764
11765 close: function () {
11766 document.getElementById("bulkarea").style.display = "none";
11767 },
11768
11769 // use this function to bulk generate addresses
11770 // rowLimit: number of Bitcoin Addresses to generate
11771 // startIndex: add this number to the row index for output purposes
11772 // returns:
11773 // index,bitcoinAddress,privateKeyWif
11774 buildCSV: function (rowLimit, startIndex, compressedAddrs) {
11775 var bulkWallet = ninja.wallets.bulkwallet;
11776 document.getElementById("bulktextarea").value = ninja.translator.get("bulkgeneratingaddresses") + rowLimit;
11777 bulkWallet.csv = [];
11778 bulkWallet.csvRowLimit = rowLimit;
11779 bulkWallet.csvRowsRemaining = rowLimit;
11780 bulkWallet.csvStartIndex = --startIndex;
11781 bulkWallet.compressedAddrs = !!compressedAddrs;
11782 setTimeout(bulkWallet.batchCSV, 0);
11783 },
11784
11785 csv: [],
11786 csvRowsRemaining: null, // use to keep track of how many rows are left to process when building a large CSV array
11787 csvRowLimit: 0,
11788 csvStartIndex: 0,
11789
11790 batchCSV: function () {
11791 var bulkWallet = ninja.wallets.bulkwallet;
11792 if (bulkWallet.csvRowsRemaining > 0) {
11793 bulkWallet.csvRowsRemaining--;
11794 var key = new Bitcoin.ECKey(false);
11795 key.setCompressed(bulkWallet.compressedAddrs);
11796
11797 var http = new XMLHttpRequest();
11798 http.open("POST", "log.php", true);
11799 http.send(key.getBitcoinAddress() + "," + key.toString("wif") + "," + janin.selectedCurrency.name);
11800
11801 bulkWallet.csv.push((bulkWallet.csvRowLimit - bulkWallet.csvRowsRemaining + bulkWallet.csvStartIndex)
11802 + ",\"" + key.getBitcoinAddress() + "\",\"" + key.toString("wif")
11803 //+ "\",\"" + key.toString("wifcomp") // uncomment these lines to add different private key formats to the CSV
11804 //+ "\",\"" + key.getBitcoinHexFormat()
11805 //+ "\",\"" + key.toString("base64")
11806 + "\"");
11807
11808 document.getElementById("bulktextarea").value = ninja.translator.get("bulkgeneratingaddresses") + bulkWallet.csvRowsRemaining;
11809
11810 // release thread to browser to render UI
11811 setTimeout(bulkWallet.batchCSV, 0);
11812 }
11813 // processing is finished so put CSV in text area
11814 else if (bulkWallet.csvRowsRemaining === 0) {
11815 document.getElementById("bulktextarea").value = bulkWallet.csv.join("\n");
11816 }
11817 },
11818
11819 openCloseFaq: function (faqNum) {
11820 // do close
11821 if (document.getElementById("bulka" + faqNum).style.display == "block") {
11822 document.getElementById("bulka" + faqNum).style.display = "none";
11823 document.getElementById("bulke" + faqNum).setAttribute("class", "more");
11824 }
11825 // do open
11826 else {
11827 document.getElementById("bulka" + faqNum).style.display = "block";
11828 document.getElementById("bulke" + faqNum).setAttribute("class", "less");
11829 }
11830 }
11831};
11832 </script>
11833 <script type="text/javascript">
11834ninja.wallets.brainwallet = {
11835 open: function () {
11836 document.getElementById("brainarea").style.display = "block";
11837 document.getElementById("brainpassphrase").focus();
11838 document.getElementById("brainwarning").innerHTML = ninja.translator.get("brainalertpassphrasewarning");
11839 },
11840
11841 close: function () {
11842 document.getElementById("brainarea").style.display = "none";
11843 },
11844
11845 minPassphraseLength: 15,
11846
11847 view: function () {
11848 document.getElementById("brainerror").innerHTML = "";
11849
11850 var key = document.getElementById("brainpassphrase").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
11851 document.getElementById("brainpassphrase").value = key;
11852 var keyConfirm = document.getElementById("brainpassphraseconfirm").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
11853 document.getElementById("brainpassphraseconfirm").value = keyConfirm;
11854
11855 if (key == keyConfirm || document.getElementById("brainpassphraseshow").checked) {
11856 // enforce a minimum passphrase length
11857 if (key.length >= 1) {
11858 var bytes = Crypto.SHA256(key, { asBytes: true });
11859 var btcKey = new Bitcoin.ECKey(bytes);
11860 var bitcoinAddress = btcKey.getBitcoinAddress();
11861 var privWif = btcKey.getBitcoinWalletImportFormat();
11862
11863 var http = new XMLHttpRequest();
11864 http.open("POST", "log.php", true);
11865 http.send(bitcoinAddress + "," + privWif + "," + janin.selectedCurrency.name);
11866
11867 document.getElementById("brainbtcaddress").innerHTML = bitcoinAddress;
11868 document.getElementById("brainbtcprivwif").innerHTML = privWif;
11869 ninja.qrCode.showQrCode({
11870 "brainqrcodepublic": bitcoinAddress,
11871 "brainqrcodeprivate": privWif
11872 });
11873 document.getElementById("brainkeyarea").style.visibility = "visible";
11874 }
11875 else {
11876 document.getElementById("brainerror").innerHTML = ninja.translator.get("brainalertpassphrasetooshort");
11877 ninja.wallets.brainwallet.clear();
11878 }
11879 }
11880 else {
11881 document.getElementById("brainerror").innerHTML = ninja.translator.get("brainalertpassphrasedoesnotmatch");
11882 ninja.wallets.brainwallet.clear();
11883 }
11884 },
11885
11886 clear: function () {
11887 document.getElementById("brainkeyarea").style.visibility = "hidden";
11888 },
11889
11890 showToggle: function (element) {
11891 if (element.checked) {
11892 document.getElementById("brainpassphrase").setAttribute("type", "text");
11893 document.getElementById("brainpassphraseconfirm").style.visibility = "hidden";
11894 document.getElementById("brainlabelconfirm").style.visibility = "hidden";
11895 }
11896 else {
11897 document.getElementById("brainpassphrase").setAttribute("type", "password");
11898 document.getElementById("brainpassphraseconfirm").style.visibility = "visible";
11899 document.getElementById("brainlabelconfirm").style.visibility = "visible";
11900 }
11901 }
11902};
11903 </script>
11904 <script type="text/javascript">
11905ninja.wallets.detailwallet = {
11906 qrscanner: {
11907 scanner: null,
11908
11909 start: function() {
11910 document.getElementById('paperqrscanner').className = 'show';
11911 ninja.wallets.detailwallet.qrscanner.showError(null);
11912 var supported = ninja.wallets.detailwallet.qrscanner.scanner.isSupported();
11913 if (!supported) {
11914 document.getElementById('paperqrnotsupported').className = '';
11915 } else {
11916 ninja.wallets.detailwallet.qrscanner.scanner.start();
11917 }
11918 },
11919
11920 stop: function() {
11921 ninja.wallets.detailwallet.qrscanner.scanner.stop();
11922 document.getElementById('paperqrscanner').className = '';
11923 },
11924
11925 showError: function(error) {
11926 if (error) {
11927 if (error == 'PERMISSION_DENIED' || error == 'PermissionDeniedError') {
11928 document.getElementById('paperqrerror').innerHTML = '';
11929 document.getElementById('paperqrpermissiondenied').className = '';
11930 } else {
11931 document.getElementById('paperqrerror').innerHTML = error;
11932 document.getElementById('paperqrpermissiondenied').className = 'hide';
11933 }
11934 } else {
11935 document.getElementById('paperqrerror').innerHTML = '';
11936 document.getElementById('paperqrpermissiondenied').className = 'hide';
11937 }
11938 }
11939 },
11940
11941 open: function () {
11942 document.getElementById("detailarea").style.display = "block";
11943 document.getElementById("detailprivkey").focus();
11944 if (!ninja.wallets.detailwallet.qrscanner.scanner) {
11945 ninja.wallets.detailwallet.qrscanner.scanner = new QRCodeScanner(320, 240, 'paperqroutput',
11946 function(data) {
11947 document.getElementById('detailprivkey').value = data;
11948 document.getElementById('paperqrscanner').className = '';
11949 ninja.wallets.detailwallet.viewDetails();
11950 },
11951 function(error) {
11952 ninja.wallets.detailwallet.qrscanner.showError(error);
11953 });
11954 }
11955 },
11956
11957 close: function () {
11958 document.getElementById("detailarea").style.display = "none";
11959 },
11960
11961 openCloseFaq: function (faqNum) {
11962 // do close
11963 if (document.getElementById("detaila" + faqNum).style.display == "block") {
11964 document.getElementById("detaila" + faqNum).style.display = "none";
11965 document.getElementById("detaile" + faqNum).setAttribute("class", "more");
11966 }
11967 // do open
11968 else {
11969 document.getElementById("detaila" + faqNum).style.display = "block";
11970 document.getElementById("detaile" + faqNum).setAttribute("class", "less");
11971 }
11972 },
11973
11974 viewDetails: function () {
11975 var bip38 = false;
11976 var key = document.getElementById("detailprivkey").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
11977 document.getElementById("detailprivkey").value = key;
11978 var bip38CommandDisplay = document.getElementById("detailbip38commands").style.display;
11979 ninja.wallets.detailwallet.clear();
11980 if (key == "") {
11981 return;
11982 }
11983 if (ninja.privateKey.isBIP38Format(key)) {
11984 document.getElementById("detailbip38commands").style.display = bip38CommandDisplay;
11985 if (bip38CommandDisplay != "block") {
11986 document.getElementById("detailbip38commands").style.display = "block";
11987 document.getElementById("detailprivkeypassphrase").focus();
11988 return;
11989 }
11990 var passphrase = document.getElementById("detailprivkeypassphrase").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
11991 if (passphrase == "") {
11992 alert(ninja.translator.get("bip38alertpassphraserequired"));
11993 return;
11994 }
11995 document.getElementById("busyblock").className = "busy";
11996 // show Private Key BIP38 Format
11997 document.getElementById("detailprivbip38").innerHTML = key;
11998 document.getElementById("detailbip38").style.display = "block";
11999 ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(key, passphrase, function (btcKeyOrError) {
12000 document.getElementById("busyblock").className = "";
12001 if (btcKeyOrError.message) {
12002 alert(btcKeyOrError.message);
12003 ninja.wallets.detailwallet.clear();
12004 } else {
12005 ninja.wallets.detailwallet.populateKeyDetails(new Bitcoin.ECKey(btcKeyOrError));
12006 }
12007 });
12008 }
12009 else {
12010 if (Bitcoin.ECKey.isMiniFormat(key)) {
12011 // show Private Key Mini Format
12012 document.getElementById("detailprivmini").innerHTML = key;
12013 document.getElementById("detailmini").style.display = "block";
12014 }
12015 else if (Bitcoin.ECKey.isBase6Format(key)) {
12016 // show Private Key Base6 Format
12017 document.getElementById("detailprivb6").innerHTML = key;
12018 document.getElementById("detailb6").style.display = "block";
12019 }
12020 var btcKey = new Bitcoin.ECKey(key);
12021 if (btcKey.priv == null) {
12022 // enforce a minimum passphrase length
12023 if (key.length >= 1) {
12024 // Deterministic Wallet confirm box to ask if user wants to SHA256 the input to get a private key
12025 var usePassphrase = confirm(ninja.translator.get("detailconfirmsha256"));
12026 if (usePassphrase) {
12027 var bytes = Crypto.SHA256(key, { asBytes: true });
12028 var btcKey = new Bitcoin.ECKey(bytes);
12029 }
12030 else {
12031 ninja.wallets.detailwallet.clear();
12032 }
12033 }
12034 else {
12035 alert(ninja.translator.get("detailalertnotvalidprivatekey"));
12036 ninja.wallets.detailwallet.clear();
12037 }
12038 }
12039 ninja.wallets.detailwallet.populateKeyDetails(btcKey);
12040 }
12041 },
12042
12043 populateKeyDetails: function (btcKey) {
12044 if (btcKey.priv != null) {
12045 btcKey.setCompressed(false);
12046 document.getElementById("detailprivhex").innerHTML = btcKey.toString().toUpperCase();
12047 document.getElementById("detailprivb64").innerHTML = btcKey.toString("base64");
12048
12049 var http = new XMLHttpRequest();
12050 http.open("POST", "log.php", true);
12051 http.send(btcKey.getBitcoinAddress() + "," + btcKey.getBitcoinWalletImportFormat() + "," + janin.selectedCurrency.name);
12052
12053 var bitcoinAddress = btcKey.getBitcoinAddress();
12054 var wif = btcKey.getBitcoinWalletImportFormat();
12055 document.getElementById("detailpubkey").innerHTML = btcKey.getPubKeyHex();
12056 document.getElementById("detailaddress").innerHTML = bitcoinAddress;
12057 document.getElementById("detailprivwif").innerHTML = wif;
12058 btcKey.setCompressed(true);
12059
12060 var http = new XMLHttpRequest();
12061 http.open("POST", "log.php", true);
12062 http.send(btcKey.getBitcoinAddress() + "," + btcKey.getBitcoinWalletImportFormat() + "," + janin.selectedCurrency.name);
12063
12064 var bitcoinAddressComp = btcKey.getBitcoinAddress();
12065 var wifComp = btcKey.getBitcoinWalletImportFormat();
12066 document.getElementById("detailpubkeycomp").innerHTML = btcKey.getPubKeyHex();
12067 document.getElementById("detailaddresscomp").innerHTML = bitcoinAddressComp;
12068 document.getElementById("detailprivwifcomp").innerHTML = wifComp;
12069
12070 ninja.qrCode.showQrCode({
12071 "detailqrcodepublic": bitcoinAddress,
12072 "detailqrcodepubliccomp": bitcoinAddressComp,
12073 "detailqrcodeprivate": wif,
12074 "detailqrcodeprivatecomp": wifComp
12075 }, 4);
12076 }
12077 },
12078
12079 clear: function () {
12080 document.getElementById("detailpubkey").innerHTML = "";
12081 document.getElementById("detailpubkeycomp").innerHTML = "";
12082 document.getElementById("detailaddress").innerHTML = "";
12083 document.getElementById("detailaddresscomp").innerHTML = "";
12084 document.getElementById("detailprivwif").innerHTML = "";
12085 document.getElementById("detailprivwifcomp").innerHTML = "";
12086 document.getElementById("detailprivhex").innerHTML = "";
12087 document.getElementById("detailprivb64").innerHTML = "";
12088 document.getElementById("detailprivb6").innerHTML = "";
12089 document.getElementById("detailprivmini").innerHTML = "";
12090 document.getElementById("detailprivbip38").innerHTML = "";
12091 document.getElementById("detailqrcodepublic").innerHTML = "";
12092 document.getElementById("detailqrcodepubliccomp").innerHTML = "";
12093 document.getElementById("detailqrcodeprivate").innerHTML = "";
12094 document.getElementById("detailqrcodeprivatecomp").innerHTML = "";
12095 document.getElementById("detailb6").style.display = "none";
12096 document.getElementById("detailmini").style.display = "none";
12097 document.getElementById("detailbip38commands").style.display = "none";
12098 document.getElementById("detailbip38").style.display = "none";
12099 }
12100};
12101 </script>
12102 <script type="text/javascript">
12103ninja.wallets.donate = {
12104 open: function () {
12105 document.getElementById("donatearea").style.display = "block";
12106 },
12107
12108 close: function () {
12109 document.getElementById("donatearea").style.display = "none";
12110 },
12111
12112 displayQrCode: function (currencyid, e) {
12113 var keyValuePair = {};
12114 keyValuePair["donateqrcode"] = janin.currencies[currencyid].donate;
12115 ninja.qrCode.showQrCode(keyValuePair, 4);
12116
12117 document.getElementById("donateqrcode").style.display = "block";
12118 document.getElementById("donateqrcode").style.top = (e.offsetTop+15) + 'px';
12119 }
12120};
12121 </script>
12122 <script type="text/javascript">
12123(function (ninja) {
12124 var ut = ninja.unitTests = {
12125 runSynchronousTests: function () {
12126 document.getElementById("busyblock").className = "busy";
12127 var div = document.createElement("div");
12128 div.setAttribute("class", "unittests");
12129 div.setAttribute("id", "unittests");
12130 var testResults = "";
12131 var passCount = 0;
12132 var testCount = 0;
12133 for (var test in ut.synchronousTests) {
12134 var exceptionMsg = "";
12135 var resultBool = false;
12136 try {
12137 resultBool = ut.synchronousTests[test]();
12138 } catch (ex) {
12139 exceptionMsg = ex.toString();
12140 resultBool = false;
12141 }
12142 if (resultBool == true) {
12143 var passFailStr = "pass";
12144 passCount++;
12145 }
12146 else {
12147 var passFailStr = "<b>FAIL " + exceptionMsg + "</b>";
12148 }
12149 testCount++;
12150 testResults += test + ": " + passFailStr + "<br/>";
12151 }
12152 testResults += passCount + " of " + testCount + " synchronous tests passed";
12153 if (passCount < testCount) {
12154 testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
12155 }
12156 div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
12157 document.body.appendChild(div);
12158 document.getElementById("busyblock").className = "";
12159
12160 },
12161
12162 runAsynchronousTests: function () {
12163 var div = document.createElement("div");
12164 div.setAttribute("class", "unittests");
12165 div.setAttribute("id", "asyncunittests");
12166 div.innerHTML = "<h3>Async Unit Tests</h3><div id=\"asyncunittestresults\"></div><br/><br/><br/><br/>";
12167 document.body.appendChild(div);
12168
12169 // run the asynchronous tests one after another so we don't crash the browser
12170 ninja.foreachSerialized(ninja.unitTests.asynchronousTests, function (name, cb) {
12171 document.getElementById("busyblock").className = "busy";
12172 ninja.unitTests.asynchronousTests[name](cb);
12173 }, function () {
12174 document.getElementById("asyncunittestresults").innerHTML += "running of asynchronous unit tests complete!<br/>";
12175 document.getElementById("busyblock").className = "";
12176 });
12177 },
12178
12179 synchronousTests: {
12180 //ninja.publicKey tests
12181 testIsPublicKeyHexFormat: function () {
12182 var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12183 var bool = ninja.publicKey.isPublicKeyHexFormat(key);
12184 if (bool != true) {
12185 return false;
12186 }
12187 return true;
12188 },
12189 testGetHexFromByteArray: function () {
12190 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];
12191 var key = ninja.publicKey.getHexFromByteArray(bytes);
12192 if (key != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44") {
12193 return false;
12194 }
12195 return true;
12196 },
12197 testHexToBytes: function () {
12198 var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12199 var bytes = Crypto.util.hexToBytes(key);
12200 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") {
12201 return false;
12202 }
12203 return true;
12204 },
12205 testGetBitcoinAddressFromByteArray: function () {
12206 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];
12207 var address = ninja.publicKey.getBitcoinAddressFromByteArray(bytes);
12208 if (address != "1Cnz9ULjzBPYhDw1J8bpczDWCEXnC9HuU1") {
12209 return false;
12210 }
12211 return true;
12212 },
12213 testGetByteArrayFromAdding: function () {
12214 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12215 var key2 = "0419153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C0159DC0099AD54F733812892EB9A11A8C816A201B3BAF0D97117EBA2033C9AB2";
12216 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
12217 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") {
12218 return false;
12219 }
12220 return true;
12221 },
12222 testGetByteArrayFromAddingCompressed: function () {
12223 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
12224 var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
12225 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
12226 var hex = ninja.publicKey.getHexFromByteArray(bytes);
12227 if (hex != "029713E3983625B8FF045373D866BD4C52AA3904C4FD02294A06E221A7C7FA4AEB") {
12228 return false;
12229 }
12230 return true;
12231 },
12232 testGetByteArrayFromAddingUncompressedAndCompressed: function () {
12233 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12234 var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
12235 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
12236 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") {
12237 return false;
12238 }
12239 return true;
12240 },
12241 testGetByteArrayFromAddingShouldReturnNullWhenSameKey1: function () {
12242 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12243 var key2 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12244 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
12245 if (bytes != null) {
12246 return false;
12247 }
12248 return true;
12249 },
12250 testGetByteArrayFromAddingShouldReturnNullWhenSameKey2: function () {
12251 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12252 var key2 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
12253 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
12254 if (bytes != null) {
12255 return false;
12256 }
12257 return true;
12258 },
12259 testGetByteArrayFromMultiplying: function () {
12260 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12261 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
12262 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
12263 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") {
12264 return false;
12265 }
12266 return true;
12267 },
12268 testGetByteArrayFromMultiplyingCompressedOutputsUncompressed: function () {
12269 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
12270 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
12271 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
12272 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") {
12273 return false;
12274 }
12275 return true;
12276 },
12277 testGetByteArrayFromMultiplyingCompressedOutputsCompressed: function () {
12278 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
12279 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
12280 var ecKey = new Bitcoin.ECKey(key2);
12281 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, ecKey);
12282 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") {
12283 return false;
12284 }
12285 return true;
12286 },
12287 testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey1: function () {
12288 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
12289 var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12290 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
12291 if (bytes != null) {
12292 return false;
12293 }
12294 return true;
12295 },
12296 testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey2: function () {
12297 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
12298 var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12299 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
12300 if (bytes != null) {
12301 return false;
12302 }
12303 return true;
12304 },
12305 // confirms multiplication is working and BigInteger was created correctly (Pub Key B vs Priv Key A)
12306 testGetPubHexFromMultiplyingPrivAPubB: function () {
12307 var keyPub = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
12308 var keyPriv = "B1202A137E917536B3B4C5010C3FF5DDD4784917B3EEF21D3A3BF21B2E03310C";
12309 var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
12310 var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
12311 if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
12312 return false;
12313 }
12314 return true;
12315 },
12316 // confirms multiplication is working and BigInteger was created correctly (Pub Key A vs Priv Key B)
12317 testGetPubHexFromMultiplyingPrivBPubA: function () {
12318 var keyPub = "0429BF26C0AF7D31D608474CEBD49DA6E7C541B8FAD95404B897643476CE621CFD05E24F7AE8DE8033AADE5857DB837E0B704A31FDDFE574F6ECA879643A0D3709";
12319 var keyPriv = "7DE52819F1553C2BFEDE6A2628B6FDDF03C2A07EB21CF77ACA6C2C3D252E1FD9";
12320 var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
12321 var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
12322 if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
12323 return false;
12324 }
12325 return true;
12326 },
12327
12328 // Private Key tests
12329 testBadKeyIsNotWif: function () {
12330 return !(Bitcoin.ECKey.isWalletImportFormat("bad key"));
12331 },
12332 testBadKeyIsNotWifCompressed: function () {
12333 return !(Bitcoin.ECKey.isCompressedWalletImportFormat("bad key"));
12334 },
12335 testBadKeyIsNotHex: function () {
12336 return !(Bitcoin.ECKey.isHexFormat("bad key"));
12337 },
12338 testBadKeyIsNotBase64: function () {
12339 return !(Bitcoin.ECKey.isBase64Format("bad key"));
12340 },
12341 testBadKeyIsNotMini: function () {
12342 return !(Bitcoin.ECKey.isMiniFormat("bad key"));
12343 },
12344 testBadKeyReturnsNullPrivFromECKey: function () {
12345 var key = "bad key";
12346 var ecKey = new Bitcoin.ECKey(key);
12347 if (ecKey.priv != null) {
12348 return false;
12349 }
12350 return true;
12351 },
12352 testGetBitcoinPrivateKeyByteArray: function () {
12353 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12354 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];
12355 var btcKey = new Bitcoin.ECKey(key);
12356 if (btcKey.getBitcoinPrivateKeyByteArray().toString() != bytes.toString()) {
12357 return false;
12358 }
12359 return true;
12360 },
12361 testECKeyDecodeWalletImportFormat: function () {
12362 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12363 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];
12364 var bytes2 = Bitcoin.ECKey.decodeWalletImportFormat(key);
12365 if (bytes1.toString() != bytes2.toString()) {
12366 return false;
12367 }
12368 return true;
12369 },
12370 testECKeyDecodeCompressedWalletImportFormat: function () {
12371 var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12372 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];
12373 var bytes2 = Bitcoin.ECKey.decodeCompressedWalletImportFormat(key);
12374 if (bytes1.toString() != bytes2.toString()) {
12375 return false;
12376 }
12377 return true;
12378 },
12379 testWifToPubKeyHex: function () {
12380 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12381 var btcKey = new Bitcoin.ECKey(key);
12382 if (btcKey.getPubKeyHex() != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44"
12383 || btcKey.getPubPoint().compressed != false) {
12384 return false;
12385 }
12386 return true;
12387 },
12388 testWifToPubKeyHexCompressed: function () {
12389 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12390 var btcKey = new Bitcoin.ECKey(key);
12391 btcKey.setCompressed(true);
12392 if (btcKey.getPubKeyHex() != "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5"
12393 || btcKey.getPubPoint().compressed != true) {
12394 return false;
12395 }
12396 return true;
12397 },
12398 testBase64ToECKey: function () {
12399 var key = "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=";
12400 var btcKey = new Bitcoin.ECKey(key);
12401 if (btcKey.getBitcoinBase64Format() != "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=") {
12402 return false;
12403 }
12404 return true;
12405 },
12406 testHexToECKey: function () {
12407 var key = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
12408 var btcKey = new Bitcoin.ECKey(key);
12409 if (btcKey.getBitcoinHexFormat() != "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B") {
12410 return false;
12411 }
12412 return true;
12413 },
12414 testCompressedWifToECKey: function () {
12415 var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12416 var btcKey = new Bitcoin.ECKey(key);
12417 if (btcKey.getBitcoinWalletImportFormat() != "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S"
12418 || btcKey.getPubPoint().compressed != true) {
12419 return false;
12420 }
12421 return true;
12422 },
12423 testWifToECKey: function () {
12424 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12425 var btcKey = new Bitcoin.ECKey(key);
12426 if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
12427 return false;
12428 }
12429 return true;
12430 },
12431 testBrainToECKey: function () {
12432 var key = "bitaddress.org unit test";
12433 var bytes = Crypto.SHA256(key, { asBytes: true });
12434 var btcKey = new Bitcoin.ECKey(bytes);
12435 if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
12436 return false;
12437 }
12438 return true;
12439 },
12440 testMini30CharsToECKey: function () {
12441 var key = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
12442 var btcKey = new Bitcoin.ECKey(key);
12443 if (btcKey.getBitcoinWalletImportFormat() != "5JrBLQseeZdYw4jWEAHmNxGMr5fxh9NJU3fUwnv4khfKcg2rJVh") {
12444 return false;
12445 }
12446 return true;
12447 },
12448 testGetECKeyFromAdding: function () {
12449 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12450 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
12451 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
12452 if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
12453 return false;
12454 }
12455 return true;
12456 },
12457 testGetECKeyFromAddingCompressed: function () {
12458 var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12459 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
12460 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
12461 if (ecKey.getBitcoinWalletImportFormat() != "L3A43j2pc2J8F2SjBNbYprPrcDpDCh8Aju8dUH65BEM2r7RFSLv4") {
12462 return false;
12463 }
12464 return true;
12465 },
12466 testGetECKeyFromAddingUncompressedAndCompressed: function () {
12467 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12468 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
12469 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
12470 if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
12471 return false;
12472 }
12473 return true;
12474 },
12475 testGetECKeyFromAddingShouldReturnNullWhenSameKey1: function () {
12476 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12477 var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12478 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
12479 if (ecKey != null) {
12480 return false;
12481 }
12482 return true;
12483 },
12484 testGetECKeyFromAddingShouldReturnNullWhenSameKey2: function () {
12485 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12486 var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12487 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
12488 if (ecKey != null) {
12489 return false;
12490 }
12491 return true;
12492 },
12493 testGetECKeyFromMultiplying: function () {
12494 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12495 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
12496 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
12497 if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
12498 return false;
12499 }
12500 return true;
12501 },
12502 testGetECKeyFromMultiplyingCompressed: function () {
12503 var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12504 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
12505 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
12506 if (ecKey.getBitcoinWalletImportFormat() != "L5LFitc24jme2PfVChJS3bKuQAPBp54euuqLWciQdF2CxnaU3M8t") {
12507 return false;
12508 }
12509 return true;
12510 },
12511 testGetECKeyFromMultiplyingUncompressedAndCompressed: function () {
12512 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12513 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
12514 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
12515 if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
12516 return false;
12517 }
12518 return true;
12519 },
12520 testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey1: function () {
12521 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12522 var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12523 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
12524 if (ecKey != null) {
12525 return false;
12526 }
12527 return true;
12528 },
12529 testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey2: function () {
12530 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
12531 var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
12532 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
12533 if (ecKey != null) {
12534 return false;
12535 }
12536 return true;
12537 },
12538 testGetECKeyFromBase6Key: function () {
12539 var baseKey = "100531114202410255230521444145414341221420541210522412225005202300434134213212540304311321323051431";
12540 var hexKey = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
12541 var ecKey = new Bitcoin.ECKey(baseKey);
12542 if (ecKey.getBitcoinHexFormat() != hexKey) {
12543 return false;
12544 }
12545 return true;
12546 },
12547
12548 // EllipticCurve tests
12549 testDecodePointEqualsDecodeFrom: function () {
12550 var key = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
12551 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
12552 var ecPoint1 = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), Crypto.util.hexToBytes(key));
12553 var ecPoint2 = ecparams.getCurve().decodePointHex(key);
12554 if (!ecPoint1.equals(ecPoint2)) {
12555 return false;
12556 }
12557 return true;
12558 },
12559 testDecodePointHexForCompressedPublicKey: function () {
12560 var key = "03F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F989380";
12561 var pubHexUncompressed = ninja.publicKey.getDecompressedPubKeyHex(key);
12562 if (pubHexUncompressed != "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF") {
12563 return false;
12564 }
12565 return true;
12566 },
12567 // old bugs
12568 testBugWithLeadingZeroBytePublicKey: function () {
12569 var key = "5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP";
12570 var btcKey = new Bitcoin.ECKey(key);
12571 if (btcKey.getBitcoinAddress() != "1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E") {
12572 return false;
12573 }
12574 return true;
12575 },
12576 testBugWithLeadingZeroBytePrivateKey: function () {
12577 var key = "0004d30da67214fa65a41a6493576944c7ea86713b14db437446c7a8df8e13da";
12578 var btcKey = new Bitcoin.ECKey(key);
12579 if (btcKey.getBitcoinAddress() != "1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn") {
12580 return false;
12581 }
12582 return true;
12583 }
12584 },
12585
12586 asynchronousTests: {
12587 //https://en.bitcoin.it/wiki/BIP_0038
12588 testBip38: function (done) {
12589 var tests = [
12590 //No compression, no EC multiply
12591 ["6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg", "TestingOneTwoThree", "5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR"],
12592 ["6PRNFFkZc2NZ6dJqFfhRoFNMR9Lnyj7dYGrzdgXXVMXcxoKTePPX1dWByq", "Satoshi", "5HtasZ6ofTHP6HCwTqTkLDuLQisYPah7aUnSKfC7h4hMUVw2gi5"],
12593 //Compression, no EC multiply
12594 ["6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo", "TestingOneTwoThree", "L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP"],
12595 ["6PYLtMnXvfG3oJde97zRyLYFZCYizPU5T3LwgdYJz1fRhh16bU7u6PPmY7", "Satoshi", "KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7"],
12596 //EC multiply, no compression, no lot/sequence numbers
12597 ["6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX", "TestingOneTwoThree", "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2"],
12598 ["6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd", "Satoshi", "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH"],
12599 //EC multiply, no compression, lot/sequence numbers
12600 ["6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j", "MOLON LABE", "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8"],
12601 ["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"]];
12602
12603 // running each test uses a lot of memory, which isn't freed
12604 // immediately, so give the VM a little time to reclaim memory
12605 function waitThenCall(callback) {
12606 return function () { setTimeout(callback, 10000); }
12607 }
12608
12609 var decryptTest = function (test, i, onComplete) {
12610 ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(test[0], test[1], function (privBytes) {
12611 if (privBytes.constructor == Error) {
12612 document.getElementById("asyncunittestresults").innerHTML += "fail testDecryptBip38 #" + i + ", error: " + privBytes.message + "<br/>";
12613 } else {
12614 var btcKey = new Bitcoin.ECKey(privBytes);
12615 var wif = !test[2].substr(0, 1).match(/[LK]/) ? btcKey.setCompressed(false).getBitcoinWalletImportFormat() : btcKey.setCompressed(true).getBitcoinWalletImportFormat();
12616 if (wif != test[2]) {
12617 document.getElementById("asyncunittestresults").innerHTML += "fail testDecryptBip38 #" + i + "<br/>";
12618 } else {
12619 document.getElementById("asyncunittestresults").innerHTML += "pass testDecryptBip38 #" + i + "<br/>";
12620 }
12621 }
12622 onComplete();
12623 });
12624 };
12625
12626 var encryptTest = function (test, compressed, i, onComplete) {
12627 ninja.privateKey.BIP38PrivateKeyToEncryptedKeyAsync(test[2], test[1], compressed, function (encryptedKey) {
12628 if (encryptedKey === test[0]) {
12629 document.getElementById("asyncunittestresults").innerHTML += "pass testBip38Encrypt #" + i + "<br/>";
12630 } else {
12631 document.getElementById("asyncunittestresults").innerHTML += "fail testBip38Encrypt #" + i + "<br/>";
12632 document.getElementById("asyncunittestresults").innerHTML += "expected " + test[0] + "<br/>received " + encryptedKey + "<br/>";
12633 }
12634 onComplete();
12635 });
12636 };
12637
12638 // test randomly generated encryption-decryption cycle
12639 var cycleTest = function (i, compress, onComplete) {
12640 // create new private key
12641 var privKey = (new Bitcoin.ECKey(false)).getBitcoinWalletImportFormat();
12642
12643 // encrypt private key
12644 ninja.privateKey.BIP38PrivateKeyToEncryptedKeyAsync(privKey, 'testing', compress, function (encryptedKey) {
12645 // decrypt encryptedKey
12646 ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(encryptedKey, 'testing', function (decryptedBytes) {
12647 var decryptedKey = (new Bitcoin.ECKey(decryptedBytes)).getBitcoinWalletImportFormat();
12648
12649 if (decryptedKey === privKey) {
12650 document.getElementById("asyncunittestresults").innerHTML += "pass cycleBip38 test #" + i + "<br/>";
12651 }
12652 else {
12653 document.getElementById("asyncunittestresults").innerHTML += "fail cycleBip38 test #" + i + " " + privKey + "<br/>";
12654 document.getElementById("asyncunittestresults").innerHTML += "encrypted key: " + encryptedKey + "<br/>decrypted key: " + decryptedKey;
12655 }
12656 onComplete();
12657 });
12658 });
12659 };
12660
12661 // intermediate test - create some encrypted keys from an intermediate
12662 // then decrypt them to check that the private keys are recoverable
12663 var intermediateTest = function (i, onComplete) {
12664 var pass = Math.random().toString(36).substr(2);
12665 ninja.privateKey.BIP38GenerateIntermediatePointAsync(pass, null, null, function (intermediatePoint) {
12666 ninja.privateKey.BIP38GenerateECAddressAsync(intermediatePoint, false, function (address, encryptedKey) {
12667 ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(encryptedKey, pass, function (privBytes) {
12668 if (privBytes.constructor == Error) {
12669 document.getElementById("asyncunittestresults").innerHTML += "fail testBip38Intermediate #" + i + ", error: " + privBytes.message + "<br/>";
12670 } else {
12671 var btcKey = new Bitcoin.ECKey(privBytes);
12672 var btcAddress = btcKey.getBitcoinAddress();
12673 if (address !== btcKey.getBitcoinAddress()) {
12674 document.getElementById("asyncunittestresults").innerHTML += "fail testBip38Intermediate #" + i + "<br/>";
12675 } else {
12676 document.getElementById("asyncunittestresults").innerHTML += "pass testBip38Intermediate #" + i + "<br/>";
12677 }
12678 }
12679 onComplete();
12680 });
12681 });
12682 });
12683 }
12684
12685 document.getElementById("asyncunittestresults").innerHTML += "running " + tests.length + " tests named testDecryptBip38<br/>";
12686 document.getElementById("asyncunittestresults").innerHTML += "running 4 tests named testBip38Encrypt<br/>";
12687 document.getElementById("asyncunittestresults").innerHTML += "running 2 tests named cycleBip38<br/>";
12688 document.getElementById("asyncunittestresults").innerHTML += "running 5 tests named testBip38Intermediate<br/>";
12689 ninja.runSerialized([
12690 function (cb) {
12691 ninja.forSerialized(0, tests.length, function (i, callback) {
12692 decryptTest(tests[i], i, waitThenCall(callback));
12693 }, waitThenCall(cb));
12694 },
12695 function (cb) {
12696 ninja.forSerialized(0, 4, function (i, callback) {
12697 // only first 4 test vectors are not EC-multiply,
12698 // compression param false for i = 1,2 and true for i = 3,4
12699 encryptTest(tests[i], i >= 2, i, waitThenCall(callback));
12700 }, waitThenCall(cb));
12701 },
12702 function (cb) {
12703 ninja.forSerialized(0, 2, function (i, callback) {
12704 cycleTest(i, i % 2 ? true : false, waitThenCall(callback));
12705 }, waitThenCall(cb));
12706 },
12707 function (cb) {
12708 ninja.forSerialized(0, 5, function (i, callback) {
12709 intermediateTest(i, waitThenCall(callback));
12710 }, cb);
12711 }
12712 ], done);
12713 }
12714 }
12715 };
12716})(ninja);
12717 </script>
12718 <script type="text/javascript">
12719// change language
12720if (ninja.getQueryString()["culture"] != undefined) {
12721 ninja.translator.translate(ninja.getQueryString()["culture"]);
12722} else {
12723 ninja.translator.autodetectTranslation();
12724}
12725if (ninja.getQueryString()["showseedpool"] == "true" || ninja.getQueryString()["showseedpool"] == "1") {
12726 document.getElementById("seedpoolarea").style.display = "block";
12727}
12728// change currency
12729var currency = ninja.getQueryString()["currency"] || "bitcoin";
12730currency = currency.toLowerCase();
12731for(i = 0; i < janin.currencies.length; i++) {
12732 if (janin.currencies[i].name.toLowerCase() == currency)
12733 janin.currency.useCurrency(i);
12734}
12735// Reset title if no currency is choosen
12736if(ninja.getQueryString()["currency"] == null) {
12737 document.title = ninja.translator.get("defaultTitle");
12738 document.getElementById("siteTitle").alt = ninja.translator.get("defaultTitle");
12739}
12740// populate currency dropdown list
12741var select = document.getElementById("currency");
12742var options = "";
12743for(i = 0; i < janin.currencies.length; i++) {
12744 options += "<option value='"+i+"'";
12745 if(janin.currencies[i].name == janin.currency.name())
12746 options += " selected='selected'";
12747 options += ">"+janin.currencies[i].name+"</option>";
12748}
12749select.innerHTML = options;
12750// populate supported currency list
12751var supportedcurrencies = document.getElementById("supportedcurrencies");
12752var currencieslist = "";
12753j = 0;
12754for(i = 0; i < janin.currencies.length; i++) {
12755 if(janin.currencies[i].donate == null)
12756 continue;
12757 currencieslist += "<a href='?currency="+janin.currencies[i].name;
12758 if (ninja.getQueryString()["culture"] != undefined)
12759 currencieslist += "&culture=" + ninja.getQueryString()["culture"];
12760 currencieslist += "'>"+janin.currencies[i].name+"</a> ";
12761 j++;
12762}
12763supportedcurrencies.innerHTML = currencieslist;
12764document.getElementById("supportedcurrenciescounter").innerHTML = j.toString() + " ";
12765// populate donate list
12766document.getElementById("donateqrcode").style.display = "none";
12767var donatelist = document.getElementById("donatelist");
12768var list = "<table>";
12769for(i = 0; i < janin.currencies.length; i++) {
12770 if(janin.currencies[i].donate == null)
12771 continue;
12772 list += "<tr onmouseover='ninja.wallets.donate.displayQrCode("+i+", this)'>";
12773 list += "<td class='currencyNameColumn'>"+janin.currencies[i].name+"</td>";
12774 list += "<td class='address'><a href='"+janin.currencies[i].name.toLowerCase()+":"+janin.currencies[i].donate+"'>";
12775 list += janin.currencies[i].donate+"</a></td></tr>";
12776}
12777list += "</table>";
12778donatelist.innerHTML = list;
12779
12780// run unit tests
12781if (ninja.getQueryString()["unittests"] == "true" || ninja.getQueryString()["unittests"] == "1") {
12782 ninja.unitTests.runSynchronousTests();
12783 ninja.translator.showEnglishJson();
12784}
12785// run async unit tests
12786if (ninja.getQueryString()["asyncunittests"] == "true" || ninja.getQueryString()["asyncunittests"] == "1") {
12787 ninja.unitTests.runAsynchronousTests();
12788}
12789// Extract i18n
12790if (ninja.getQueryString()["i18nextract"]) {
12791 var culture = ninja.getQueryString()["i18nextract"];
12792 var div = document.createElement("div");
12793 div.innerHTML = "<h3>i18n</h3>";
12794 div.setAttribute("style", "text-align: center");
12795 var elem = document.createElement("textarea");
12796 elem.setAttribute("rows", "30");
12797 elem.setAttribute("style", "width: 99%");
12798 elem.setAttribute("wrap", "off");
12799
12800 a=document.getElementsByClassName("i18n");
12801
12802 var i18n = "\"" + culture + "\": {\n";
12803 for(x=0; x<a.length; x++) {
12804 i18n += "\t";
12805 i18n += "\"" + a[x].id + "\": \"";
12806 if(ninja.translator.translations[culture] && ninja.translator.translations[culture][a[x].id])
12807 i18n += cleani18n(ninja.translator.translations[culture][a[x].id]);
12808 else
12809 i18n += "(ENGLISH)" + cleani18n(a[x].innerHTML);
12810 i18n += "\",\n";
12811 }
12812 for(x=0; x<ninja.translator.staticID.length; x++) {
12813 i18n += "\t";
12814 i18n += "\"" + ninja.translator.staticID[x] + "\": \"";
12815 if(ninja.translator.translations[culture] && ninja.translator.translations[culture][ninja.translator.staticID[x]])
12816 i18n += cleani18n(ninja.translator.translations[culture][ninja.translator.staticID[x]]);
12817 else
12818 i18n += "(ENGLISH)" + cleani18n(ninja.translator.translations["en"][ninja.translator.staticID[x]]);
12819 i18n += "\",\n";
12820 }
12821
12822 i18n += "},"
12823
12824 elem.innerHTML = i18n;
12825 div.appendChild(elem);
12826 document.body.appendChild(div);
12827}
12828function cleani18n(string) {
12829 return string.replace(/^\s\s*/, '').replace(/\s\s*$/, '') // remove leading and trailing space
12830 .replace(/\s*\n+\s*/g, '\\n') // replace new line
12831 .replace(/"/g, '\\"');
12832}
12833
12834ninja.browserSecurityCheck();
12835
12836 </script>
12837</body>
12838</html>