+ Why should I use a Bulk Wallet to accept Bitcoins on my website?
+
+
+
The traditional approach to accepting bitcoins on your website requires that you install the official bitcoin client daemon ("bitcoind"). Many website hosting packages don't support installing the bitcoin daemon. Also, running the bitcoin daemon on your web server means your private keys are hosted on the server and could get stolen if your web server is hacked. When using a Bulk Wallet you can upload only the bitcoin addresses and not the private keys to your web server. Then you don't have to worry about your bitcoin wallet being stolen if your web server is hacked.
+
+
+
+ How do I use a Bulk Wallet to accept Bitcoins on my website?
+
+
+
+
+
Use the Bulk Wallet tab to pre-generate a large number of bitcoin addresses (10,000+). Copy and paste the generated comma separated values (CSV) list to a secure text file on your computer. Backup the file you just created to a secure location.
+
Import the bitcoin addresses into a database table on your web server. (Don't put the wallet/private keys on your web server, otherwise you risk hackers stealing your coins. Just the bitcoin addresses as they will be shown to customers.)
+
Provide an option on your website's shopping cart for your customer to pay in Bitcoin. When the customer chooses to pay in Bitcoin you will then display one of the addresses from your database to the customer as his "payment address" and save it with his shopping cart order.
+
You now need to be notified when the payment arrives. Google "bitcoin payment notification" and subscribe to at least one bitcoin payment notification service. There are various services that will notify you via Web Services, API, SMS, Email, etc. Once you receive this notification, which could be programmatically automated, you can process the customer's order. To manually check if a payment has arrived you can use Block Explorer. Replace THEADDRESSGOESHERE with the bitcoin address you are checking. It could take between 10 minutes to one hour for the transaction to be confirmed. http://www.blockexplorer.com/address/THEADDRESSGOESHERE
Unconfirmed transactions can be viewed at: http://blockchain.info/ You should see the transaction there within 30 seconds.
+
Bitcoins will safely pile up on the block chain. Use the original wallet file you generated in step 1 to spend them.
Copy and paste the above into the Your-Part-Public-Key field in the Vanity Pool Website.
+
+
+ Step 1 Private Key:
+
+
Copy and paste the above Private Key field into a text file. Ideally save to an encrypted drive. You will need this to retrieve the Bitcoin Private Key once the Pool has found your prefix.
+
+
+
+ Step 2 - Calculate your Vanity Wallet
+
+
+
+
+ Enter Your Part Private Key (generated in Step 1 above and previously saved):
+ [NOTE: this input box can accept a public key or private key]
+
+
+
+ Enter Pool Part Private Key (from Vanity Pool):
+ [NOTE: this input box can accept a public key or private key]
+
+
+
+
+
+
+
+
+
+
+ Vanity Bitcoin Address:
+
+
The above is your new address that should include your required prefix.
+
+
+
+ Vanity Public Key (HEX):
+
+
The above is the Public Key in hexadecimal format.
+
+
+
+ Vanity Private Key (WIF):
+
+
The above is the Private Key to load into your wallet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Your Bitcoin Private Key is a unique secret number that only you know. It can be encoded in a number of different formats. Below we show the Bitcoin Address and Public Key that corresponds to your Private Key as well as your Private Key in the most popular encoding formats (WIF, HEX, B64, MINI).
+
+ Bitcoin v0.6+ stores public keys in compressed format. The client now also supports import and export of private keys with importprivkey/dumpprivkey. The format of the exported private key is determined by whether the address was generated in an old or new wallet.
+
+
+
+ Bitcoin Address
+
+
+
+
+ Bitcoin Address Compressed
+
+
+
+
+
+
+ Public Key (130 characters [0-9A-F]):
+
+
+
+ Public Key (compressed, 66 characters [0-9A-F]):
+
+
- Why should I use a Bulk Wallet to accept Bitcoins on my website?
-
-
-
The traditional approach to accepting bitcoins on your website requires that you install the official bitcoin client daemon ("bitcoind"). Many website hosting packages don't support installing the bitcoin daemon. Also, running the bitcoin daemon on your web server means your private keys are hosted on the server and could get stolen if your web server is hacked. When using a Bulk Wallet you can upload only the bitcoin addresses and not the private keys to your web server. Then you don't have to worry about your bitcoin wallet being stolen if your web server is hacked.
-
-
-
- How do I use a Bulk Wallet to accept Bitcoins on my website?
-
-
-
-
-
Use the Bulk Wallet tab to pre-generate a large number of bitcoin addresses (10,000+). Copy and paste the generated comma separated values (CSV) list to a secure text file on your computer. Backup the file you just created to a secure location.
-
Import the bitcoin addresses into a database table on your web server. (Don't put the wallet/private keys on your web server, otherwise you risk hackers stealing your coins. Just the bitcoin addresses as they will be shown to customers.)
-
Provide an option on your website's shopping cart for your customer to pay in Bitcoin. When the customer chooses to pay in Bitcoin you will then display one of the addresses from your database to the customer as his "payment address" and save it with his shopping cart order.
-
You now need to be notified when the payment arrives. Google "bitcoin payment notification" and subscribe to at least one bitcoin payment notification service. There are various services that will notify you via Web Services, API, SMS, Email, etc. Once you receive this notification, which could be programmatically automated, you can process the customer's order. To manually check if a payment has arrived you can use Block Explorer. Replace THEADDRESSGOESHERE with the bitcoin address you are checking. It could take between 10 minutes to one hour for the transaction to be confirmed. http://www.blockexplorer.com/address/THEADDRESSGOESHERE
Unconfirmed transactions can be viewed at: http://blockchain.info/ You should see the transaction there within 30 seconds.
-
Bitcoins will safely pile up on the block chain. Use the original wallet file you generated in step 1 to spend them.
Copy and paste the above into the Your-Part-Public-Key field in the Vanity Pool Website.
-
-
- Step 1 Private Key:
-
-
Copy and paste the above Private Key field into a text file. Ideally save to an encrypted drive. You will need this to retrieve the Bitcoin Private Key once the Pool has found your prefix.
-
-
-
- Step 2 - Calculate your Vanity Wallet
-
-
-
-
- Enter Your Part Private Key (generated in Step 1 above and previously saved):
- [NOTE: this input box can accept a public key or private key]
-
-
-
- Enter Pool Part Private Key (from Vanity Pool):
- [NOTE: this input box can accept a public key or private key]
-
-
-
-
-
-
-
-
-
-
- Vanity Bitcoin Address:
-
-
The above is your new address that should include your required prefix.
-
-
-
- Vanity Public Key (HEX):
-
-
The above is the Public Key in hexadecimal format.
-
-
-
- Vanity Private Key (WIF):
-
-
The above is the Private Key to load into your wallet.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Your Bitcoin Private Key is a unique secret number that only you know. It can be encoded in a number of different formats. Below we show the Bitcoin Address and Public Key that corresponds to your Private Key as well as your Private Key in the most popular encoding formats (WIF, HEX, B64, MINI).
-
- Bitcoin v0.6+ stores public keys in compressed format. The client now also supports import and export of private keys with importprivkey/dumpprivkey. The format of the exported private key is determined by whether the address was generated in an old or new wallet.
-
-
-
- Bitcoin Address
-
-
-
-
- Bitcoin Address Compressed
-
-
-
-
-
-
- Public Key (130 characters [0-9A-F]):
-
-
-
- Public Key (compressed, 66 characters [0-9A-F]):
-
-
- Private Key WIF Compressed 52 characters base58, starts with a'K' or 'L'
-
-
-
-
-
-
- Private Key Hexadecimal Format (64 characters [0-9A-F]):
-
-
-
- Private Key Base64 (44 characters):
-
-
-
- Private Key Mini Format (22, 26 or 30 characters, starts with an 'S'):
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ninja.translator = {
+ currentCulture: "en",
+
+ translate: function (culture) {
+ var dict = ninja.translator.translations[culture];
+ if (dict) {
+ // set current culture
+ ninja.translator.currentCulture = culture;
+ // update menu UI
+ for (var cult in ninja.translator.translations) {
+ document.getElementById("culture" + cult).setAttribute("class", "");
+ }
+ document.getElementById("culture" + culture).setAttribute("class", "selected");
+ // apply translations
+ for (var id in dict) {
+ if (document.getElementById(id) && document.getElementById(id).value) {
+ document.getElementById(id).value = dict[id];
+ }
+ else if (document.getElementById(id)) {
+ document.getElementById(id).innerHTML = dict[id];
+ }
+ }
+ }
+ },
+
+ get: function (id) {
+ var translation = ninja.translator.translations[ninja.translator.currentCulture][id];
+ return translation;
+ },
+
+ translations: {
+ "en": {
+ // javascript alerts or messages
+ "testneteditionactivated": "TESTNET EDITION ACTIVATED",
+ "paperlabelbitcoinaddress": "Bitcoin Address:",
+ "paperlabelprivatekey": "Private Key (Wallet Import Format):",
+ "bulkgeneratingaddresses": "Generating addresses... ",
+ "brainalertpassphrasetooshort": "The passphrase you entered is too short.\n\nWarning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your bitcoins.",
+ "brainalertpassphrasedoesnotmatch": "The passphrase does not match the confirm passphrase.",
+ "detailalertnotvalidprivatekey": "The text you entered is not a valid Private Key",
+ "detailconfirmsha256": "The text you entered is not a valid Private Key!\n\nWould you like to use the entered text as a passphrase and create a Private Key using a SHA256 hash of the passphrase?\n\nWarning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your bitcoins.",
+ "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.",
+ "bip38alertpassphraserequired": "Passphrase required for BIP38 key",
+ "vanityinvalidinputcouldnotcombinekeys": "Invalid input. Could not combine keys.",
+ "vanityalertinvalidinputpublickeysmatch": "Invalid input. The Public Key of both entries match. You must input two different keys.",
+ "vanityalertinvalidinputcannotmultiple": "Invalid input. Cannot multiply two public keys. Select 'Add' to add two public keys to get a bitcoin address.",
+ "vanityprivatekeyonlyavailable": "Only available when combining two private keys",
+ "vanityalertinvalidinputprivatekeysmatch": "Invalid input. The Private Key of both entries match. You must input two different keys."
+ },
+
+ "es": {
+ // javascript alerts or messages
+ "testneteditionactivated": "Testnet se activa",
+ "paperlabelbitcoinaddress": "Dirección Bitcoin:",
+ "paperlabelprivatekey": "Clave privada (formato para importar):",
+ "bulkgeneratingaddresses": "Generación de direcciones... ",
+ "brainalertpassphrasetooshort": "La contraseña introducida es demasiado corta.\n\nAviso: Es importante escoger una contraseña fuerte para evitar ataques de fuerza bruta a fin de adivinarla y robar tus bitcoins.",
+ "brainalertpassphrasedoesnotmatch": "Las contraseñas no coinciden.",
+ "detailalertnotvalidprivatekey": "El texto que has introducido no es una clave privada válida",
+ "detailconfirmsha256": "El texto que has introducido no es una clave privada válida\n\n¿Quieres usar ese texto como si fuera una contraseña y generar una clave privada usando un hash SHA256 de tal contraseña?\n\nAviso: Es importante escoger una contraseña fuerte para evitar ataques de fuerza bruta a fin de adivinarla y robar tus bitcoins.",
+ "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.", //TODO: please translate
+ "bip38alertpassphraserequired": "Passphrase required for BIP38 key", //TODO: please translate
+ "vanityinvalidinputcouldnotcombinekeys": "Entrada no válida. No se puede combinar llaves.",
+ "vanityalertinvalidinputpublickeysmatch": "Entrada no válida. La clave pública de ambos coincidan entradas. Debe introducir dos claves diferentes.",
+ "vanityalertinvalidinputcannotmultiple": "Entrada no válida. No se puede multiplicar dos claves públicas. Seleccione 'Añadir' para agregar dos claves públicas para obtener una dirección bitcoin.",
+ "vanityprivatekeyonlyavailable": "Sólo está disponible cuando se combinan dos claves privadas",
+ "vanityalertinvalidinputprivatekeysmatch": "Entrada no válida. La clave privada de ambos coincidan entradas. Debe introducir dos claves diferentes.",
+
+ // header and menu html
+ "tagline": "Generador de carteras Bitcoin de código abierto en lado de cliente con Javascript",
+ "generatelabelbitcoinaddress": "Generando dirección Bitcoin...",
+ "generatelabelmovemouse": "Mueve un poco el ratón para crear entropía...",
+ "singlewallet": "Una sola cartera",
+ "paperwallet": "Cartera en papel",
+ "bulkwallet": "Direcciones en masa",
+ "brainwallet": "Cartera mental",
+ "vanitywallet": "Cartera personalizada",
+ "detailwallet": "Detalles de la cartera",
+
+ // footer html
+ "footerlabeldonations": "Donaciones:",
+ "footerlabeltranslatedby": "Traducción: 12345Vypv2QSmuRXcciT5oEB27mPbWGeva",
+ "footerlabelpgp": "Clave pública PGP",
+ "footerlabelversion": "Histórico de versiones",
+ "footerlabelgithub": "Repositorio GitHub",
+ "footerlabelcopyright1": "Copyright bitaddress.org.",
+ "footerlabelcopyright2": "Copyright del código JavaScript: en el fuente.",
+ "footerlabelnowarranty": "Sin garantía.",
+
+ // single wallet html
+ "newaddress": "Generar dirección",
+ "singleprint": "Imprimir",
+ "singlelabelbitcoinaddress": "Dirección Bitcoin",
+ "singlelabelprivatekey": "Clave privada (formato para importar):",
+
+ // paper wallet html
+ "paperlabelhideart": "Ocultar diseño",
+ "paperlabeladdressesperpage": "Direcciones por página:",
+ "paperlabeladdressestogenerate": "Direcciones en total:",
+ "papergenerate": "Generar",
+ "paperprint": "Imprimir",
+
+ // bulk wallet html
+ "bulklabelstartindex": "Empezar en:",
+ "bulklabelrowstogenerate": "Filas a generar:",
+ "bulklabelcompressed": "Compressed addresses?", //TODO: please translate
+ "bulkgenerate": "Generar",
+ "bulkprint": "Imprimir",
+ "bulklabelcsv": "Valores separados por coma:",
+ "bulklabelformat": "Índice,Dirección,Clave privada (formato para importar)",
+ "bulklabelq1": "¿Por qué debo usar \"Direcciones en masa\" para aceptar Bitcoins en mi web?",
+ "bulka1": "La forma tradicional de aceptar bitcoins en tu web requiere tener instalado el cliente oficial de bitcoin (\"bitcoind\"). Sin embargo muchos servicios de hosting no permiten instalar dicho cliente. Además, ejecutar el cliente en tu servidor supone que las claves privadas están también en el servidor y podrían ser comprometidas en caso de intrusión. Al usar este mecanismo, puedes subir al servidor sólo las dirección de bitcoin y no las claves privadas. De esta forma no te tienes que preocupar de que alguien robe la cartera si se cuelan en el servidor.",
+ "bulklabelq2": "¿Cómo uso \"Direcciones en masa\" para aceptar bitcoins en mi web?",
+ "bulklabela2li1": "Usa el tab \"Direcciones en masa\" para generar por anticipado muchas direcciones (más de 10000). Copia y pega la lista de valores separados por comas (CSV) a un archivo de texto seguro (cifrado) en tu ordenador. Guarda una copia de seguridad en algún lugar seguro.",
+ "bulklabela2li2": "Importa las direcciones en la base de datos de tu servidor. No subas la cartera ni las claves públicas, o de lo contrario te lo pueden robar. Sube sólo las direcciones, ya que es lo que se va a mostrar a los clientes.",
+ "bulklabela2li3": "Ofrece una alternativa en el carro de la compra de tu web para que los clientes paguen con Bitcoin. Cuando el cliente elija pagar con Bitcoin, les muestras una de las direcciones de la base de datos como su \"dirección de pago\" y guardas esto junto con el pedido.",
+ "bulklabela2li4": "Ahora te hace falta recibir una notificación del pago. Busca en google \"notificación de pagos bitcoin\" (o \"bitcoin payment notification\" en inglés) y suscríbete a alguno de los servicios que aparezcan. Hay varios de ellos, que te pueden notificar vía Web services, API, SMS, email, etc. Una vez te llegue la notificación, lo cual puede ser automatizado, entonces ya puedes procesar el pedido. Para comprobar a mano si has recibido un pago, puedes usar Block Explorer: reemplaza DIRECCION a continuación por la dirección que estés comprobando. La transacción puede tardar entre 10 minutos y una hora en ser confirmada. http://www.blockexplorer.com/address/DIRECCION
Puedes ver las transacciones sin confirmar en: http://blockchain.info/ Las transacciones sin confirmar suelen aparecer ahí en unos 30 segundos.",
+ "bulklabela2li5": "Las bitcoins que recibas se almacenarán de forma segura en la cadena de bloques. Usa la cartera original que generaste en el paso 1 para usarlas.",
+
+ // brain wallet html
+ "brainlabelenterpassphrase": "Contraseña:",
+ "brainlabelshow": "Mostrar",
+ "brainprint": "Imprimir",
+ "brainlabelconfirm": "Confirmar contraseña:",
+ "brainview": "Ver",
+ "brainalgorithm": "Algoritmo: SHA256(contraseña)",
+ "brainlabelbitcoinaddress": "Dirección Bitcoin:",
+ "brainlabelprivatekey": "Clave privada (formato para importar):",
+
+ // vanity wallet html
+ "vanitylabelstep1": "Paso 1 - Genera tu par de claves",
+ "vanitynewkeypair": "Generar",
+ "vanitylabelstep1publickey": "Clave pública:",
+ "vanitylabelstep1pubnotes": "Copia y pega la línea de arriba en el campo \"Your-Part-Public-Key\" de la web de Vanity Pool.",
+ "vanitylabelstep1privatekey": "Clave privada:",
+ "vanitylabelstep1privnotes": "Copia y pega la clave pública de arriba en un archivo de texto. Es mejor que lo almacenes en un volumen cifrado. Lo necesitarás para recuperar la clave privada una vez Vanity Pool haya encontrado tu prefijo.",
+ "vanitylabelstep2calculateyourvanitywallet": "Paso 2 - Calcula tu cartera personalizada",
+ "vanitylabelenteryourpart": "Introduce la clave privada generada en el paso 1, y que has guardado:",
+ "vanitylabelenteryourpoolpart": "Introduce la clave privada obtenida de la Vanity Pool:",
+ "vanitylabelnote1": "[NOTA: esta casilla de entrada puede aceptar una clave pública o clave privada]",
+ "vanitylabelnote2": "[NOTA: esta casilla de entrada puede aceptar una clave pública o clave privada]",
+ "vanitylabelradioadd": "Añadir",
+ "vanitylabelradiomultiply": "Multiplicar",
+ "vanitycalc": "Calcular cartera personalizada",
+ "vanitylabelbitcoinaddress": "Dirección Bitcoin personalizada:",
+ "vanitylabelnotesbitcoinaddress": "Esta es tu nueva dirección, que debería tener el prefijo deseado.",
+ "vanitylabelpublickeyhex": "Clave pública personalizada (HEX):",
+ "vanitylabelnotespublickeyhex": "Lo anterior es la clave pública en formato hexadecimal.",
+ "vanitylabelprivatekey": "Clave privada personalizada (formato para importar):",
+ "vanitylabelnotesprivatekey": "Esto es la clave privada para introducir en tu cartera.",
+
+ // detail wallet html
+ "detaillabelenterprivatekey": "Introduce la clave privada (en cualquier formato)",
+ "detailview": "Ver detalles",
+ "detailprint": "Imprimir",
+ "detaillabelnote1": "Tu clave privada es un número secreto, único, que sólo tú conoces. Se puede expresar en varios formatos. Aquí abajo mostramos la dirección y la clave pública que se corresponden con tu clave privada, así como la clave privada en los formatos más conocidos (para importar, hex, base64 y mini).",
+ "detaillabelnote2": "Bitcoin v0.6+ almacena las claves públicas comprimidas. El cliente también soporta importar/exportar claves privadas usando importprivkey/dumpprivkey. El formato de las claves privadas exportadas depende de si la dirección se generó en una cartera antigua o nueva.",
+ "detaillabelbitcoinaddress": "Dirección Bitcoin:",
+ "detaillabelbitcoinaddresscomp": "Dirección Bitcoin (comprimida):",
+ "detaillabelpublickey": "Clave pública (130 caracteres [0-9A-F]):",
+ "detaillabelpublickeycomp": "Clave pública (comprimida, 66 caracteres [0-9A-F]):",
+ "detaillabelprivwif": "Clave privada para importar (51 caracteres en base58, empieza con un",
+ "detaillabelprivwifcomp": "Clave privada para importar (comprimida, 52 caracteres en base58, empieza con",
+ "detailcompwifprefix": "'K' o 'L'",
+ "detaillabelprivhex": "Clave privada en formato hexadecimal (64 caracteres [0-9A-F]):",
+ "detaillabelprivb64": "Clave privada en base64 (44 caracteres):",
+ "detaillabelprivmini": "Clave privada en formato mini (22, 26 o 30 caracteres, empieza por 'S'):",
+ "detaillabelpassphrase": "BIP38 Passphrase", //TODO: please translate
+ "detaildecrypt": "Decrypt BIP38" //TODO: please translate
+ },
+
+ "fr": {
+ "testneteditionactivated": "ÉDITION TESTNET ACTIVÉE",
+ "paperlabelbitcoinaddress": "Adresse Bitcoin:",
+ "paperlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
+ "bulkgeneratingaddresses": "Création de l'adresse... ",
+ "brainalertpassphrasetooshort": "Le mot de passe que vous avez entré est trop court.\n\nAttention: Choisir un mot de passe solide est important pour vous protéger des attaques bruteforce visant à trouver votre mot de passe et voler vos Bitcoins.",
+ "brainalertpassphrasedoesnotmatch": "Le mot de passe ne correspond pas au mot de passe de vérification.",
+ "detailalertnotvalidprivatekey": "Le texte que vous avez entré n'est pas une Clé Privée valide",
+ "detailconfirmsha256": "Le texte que vous avez entré n'est pas une Clé Privée valide!\n\nVoulez-vous utiliser le texte comme un mot de passe et créer une Clé Privée à partir d'un hash SHA256 de ce mot de passe?\n\nAttention: Choisir un mot de passe solide est important pour vous protéger des attaques bruteforce visant à trouver votre mot de passe et voler vos Bitcoins.",
+ "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.", //TODO: please translate
+ "bip38alertpassphraserequired": "Passphrase required for BIP38 key", //TODO: please translate
+ "vanityinvalidinputcouldnotcombinekeys": "Entrée non valide. Impossible de combiner les clés.",
+ "vanityalertinvalidinputpublickeysmatch": "Entrée non valide. La clé publique des deux entrées est identique. Vous devez entrer deux clés différentes.",
+ "vanityalertinvalidinputcannotmultiple": "Entrée non valide. Il n'est pas possible de multiplier deux clés publiques. Sélectionner 'Ajouter' pour ajouter deux clés publiques pour obtenir une adresse Bitcoin.",
+ "vanityprivatekeyonlyavailable": "Seulement disponible si vos combinez deux clés privées",
+ "vanityalertinvalidinputprivatekeysmatch": "Entrée non valide. La clé Privée des deux entrées est identique. Vous devez entrer deux clés différentes.",
+ "tagline": "Générateur De Porte-Monnaie Bitcoin Javascript Hors-Ligne",
+ "generatelabelbitcoinaddress": "Création de l'adresse Bitcoin...",
+ "generatelabelmovemouse": "BOUGEZ votre souris pour ajouter de l'entropie...",
+ "singlewallet": "Porte-Monnaie Simple",
+ "paperwallet": "Porte-Monnaie Papier",
+ "bulkwallet": "Porte-Monnaie En Vrac",
+ "brainwallet": "Porte-Monnaie Cerveau",
+ "vanitywallet": "Porte-Monnaie Vanité",
+ "detailwallet": "Détails du Porte-Monnaie",
+ "footerlabeldonations": "Dons:",
+ "footerlabeltranslatedby": "Traduction: 1Gy7NYSJNUYqUdXTBow5d7bCUEJkUFDFSq",
+ "footerlabelpgp": "Clé Publique PGP",
+ "footerlabelversion": "Historique De Version Signé",
+ "footerlabelgithub": "Dépôt GitHub",
+ "footerlabelcopyright1": "Copyright bitaddress.org.",
+ "footerlabelcopyright2": "Les droits d'auteurs JavaScript sont inclus dans le code source.",
+ "footerlabelnowarranty": "Aucune garantie.",
+ "newaddress": "Générer Une Nouvelle Adresse",
+ "singleprint": "Imprimer",
+ "singlelabelbitcoinaddress": "Adresse Bitcoin:",
+ "singlelabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
+ "paperlabelhideart": "Retirer Le Style?",
+ "paperlabeladdressesperpage": "Adresses par page:",
+ "paperlabeladdressestogenerate": "Nombre d'adresses à créer:",
+ "papergenerate": "Générer",
+ "paperprint": "Imprimer",
+ "bulklabelstartindex": "Commencer à l'index:",
+ "bulklabelrowstogenerate": "Colonnes à générer:",
+ "bulklabelcompressed": "Compressed addresses?", //TODO: please translate
+ "bulkgenerate": "Générer",
+ "bulkprint": "Imprimer",
+ "bulklabelcsv": "Valeurs Séparées Par Des Virgules (CSV):",
+ "bulklabelformat": "Index,Adresse,Clé Privée (WIF)",
+ "bulklabelq1": "Pourquoi utiliserais-je un Porte-monnaie en vrac pour accepter les Bitcoins sur mon site web?",
+ "bulka1": "L'approche traditionnelle pour accepter des Bitcoins sur votre site web requière l'installation du logiciel Bitcoin officiel (\"bitcoind\"). Plusieurs hébergeurs ne supportent pas l'installation du logiciel Bitcoin. De plus, faire fonctionner le logiciel Bitcoin sur votre serveur web signifie que vos clés privées sont hébergées sur le serveur et pourraient donc être volées si votre serveur web était compromis. En utilisant un Porte-monnaie en vrac, vous pouvez publiquer seulement les adresses Bitcoin sur votre serveur et non les clés privées. Vous n'avez alors pas à vous inquiéter du risque de vous faire voler votre porte-monnaie si votre serveur était compromis.",
+ "bulklabelq2": "Comment utiliser le Porte-monnaie en vrac pour utiliser le Bitcoin sur mon site web?",
+ "bulklabela2li1": "Utilisez le Porte-monnaie en vrac pour pré-générer une large quantité d'adresses Bitcoin (10,000+). Copiez collez les données séparées par des virgules (CSV) dans un fichier texte sécurisé dans votre ordinateur. Sauvegardez ce fichier dans un endroit sécurisé.",
+ "bulklabela2li2": "Importez les adresses Bitcoin dans une base de donnée sur votre serveur web. (N'ajoutez pas le porte-monnaie ou les clés privées sur votre serveur web, sinon vous courrez le risque de vous faire voler si votre serveur est compromis. Ajoutez seulement les adresses Bitcoin qui seront visibles à vos visiteurs.)",
+ "bulklabela2li3": "Ajoutez une option dans votre panier en ligne pour que vos clients puissent vous payer en Bitcoin. Quand un client choisi de vous payer en Bitcoin, vous pouvez afficher une des adresses de votre base de donnée comme \"adresse de paiment\" pour votre client et sauvegarder cette adresse avec sa commande.",
+ "bulklabela2li4": "Vous avez maintenant besoin d'être avisé quand le paiement est reçu. Cherchez \"bitcoin payment notification\" sur Google et inscrivez-vous à un service de notification de paiement Bitcoin. Il y a plusieurs services qui vous avertiront via des services Web, API, SMS, Email, etc. Une fois que vous avez reçu la notification, qui devrait être programmée automatiquement, vous pouvez traiter la commande de votre client. Pour vérifier manuellement si un paiement est arrivé, vous pouvez utiliser Block Explorer. Remplacez ADRESSE par l'adresse Bitcoin que vous souhaitez vérifier. La confirmation de la transaction pourrait prendre de 10 à 60 minutes pour être confirmée. http://www.blockexplorer.com/address/ADRESSE
Les transactions non confirmées peuvent être visualisées ici: http://blockchain.info/ Vous devriez voir la transaction à l'intérieur de 30 secondes.",
+ "bulklabela2li5": "Les Bitcoins vos s'accumuler de façon sécuritaire dans la chaîne de blocs. Utilisez le porte-monnaie original que vous avez généré à l'étape 1 pour les dépenser.",
+ "brainlabelenterpassphrase": "Entrez votre mot de passe: ",
+ "brainlabelshow": "Afficher?",
+ "brainprint": "Imprimer",
+ "brainlabelconfirm": "Confirmer le mot de passe: ",
+ "brainview": "Visualiser",
+ "brainalgorithm": "Algorithme: SHA256(mot de passe)",
+ "brainlabelbitcoinaddress": "Adresse Bitcoin:",
+ "brainlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
+ "vanitylabelstep1": "Étape 1 - Générer votre \"Étape 1 Paire De Clés\"",
+ "vanitynewkeypair": "Générer",
+ "vanitylabelstep1publickey": "Étape 1 Clé Publique:",
+ "vanitylabelstep1pubnotes": "Copiez celle-ci dans la case Votre-Clé-Publique du site de Vanity Pool.",
+ "vanitylabelstep1privatekey": "Step 1 Clé Privée:",
+ "vanitylabelstep1privnotes": "Copiez la cette Clé Privée dans un fichier texte. Idéalement, sauvegardez la dans un fichier encrypté. Vous en aurez besoin pour récupérer la Clé Privée lors que Vanity Pool aura trouvé votre préfixe.",
+ "vanitylabelstep2calculateyourvanitywallet": "Étape 2 - Calculer votre Porte-monnaie Vanité",
+ "vanitylabelenteryourpart": "Entrez votre Clé Privée (générée à l'étape 1 plus haut et précédemment sauvegardée):",
+ "vanitylabelenteryourpoolpart": "Entrez la Clé Privée (provenant de Vanity Pool):",
+ "vanitylabelnote1": "[NOTE: cette case peut accepter une clé publique ou un clé privée]",
+ "vanitylabelnote2": "[NOTE: cette case peut accepter une clé publique ou un clé privée]",
+ "vanitylabelradioadd": "Ajouter",
+ "vanitylabelradiomultiply": "Multiplier",
+ "vanitycalc": "Calculer Le Porte-monnaie Vanité",
+ "vanitylabelbitcoinaddress": "Adresse Bitcoin Vanité:",
+ "vanitylabelnotesbitcoinaddress": "Ci-haut est votre nouvelle adresse qui devrait inclure le préfix requis.",
+ "vanitylabelpublickeyhex": "Clé Public Vanité (HEX):",
+ "vanitylabelnotespublickeyhex": "Celle-ci est la Clé Publique dans le format hexadécimal. ",
+ "vanitylabelprivatekey": "Clé Privée Vanité (WIF):",
+ "vanitylabelnotesprivatekey": "Celle-ci est la Clé Privée pour accéder à votre porte-monnaie. ",
+ "detaillabelenterprivatekey": "Entrez la Clé Privée (quel que soit son format)",
+ "detailview": "Voir les détails",
+ "detailprint": "Imprimer",
+ "detaillabelnote1": "Votre Clé Privée Bitcoin est un nombre secret que vous êtes le seul à connaître. Il peut être encodé sous la forme d'un nombre sous différents formats. Ci-bas, nous affichons l'adresse Bitcoin et la Clé Publique qui corresponds à la Clé Privée ainsi que la Clé Privée dans les formats d'encodage les plus populaires (WIF, HEX, B64, MINI).",
+ "detaillabelnote2": "Bitcoin v0.6+ conserve les clés publiques dans un format compressé. Le logiciel supporte maintenant aussi l'importation et l'exportation de clés privées avec importprivkey/dumpprivkey. Le format de la clé privée exportée est déterminé selon la version du porte-monnaie Bitcoin.",
+ "detaillabelbitcoinaddress": "Adresse Bitcoin:",
+ "detaillabelbitcoinaddresscomp": "Adresse Bitcoin (compressée):",
+ "detaillabelpublickey": "Clé Publique (130 caractères [0-9A-F]):",
+ "detaillabelpublickeycomp": "Clé Publique (compressée, 66 caractères [0-9A-F]):",
+ "detaillabelprivwif": "Clé Privée WIF (51 caractères base58, débute avec un a",
+ "detaillabelprivwifcomp": "Clé Privée WIF (compressée, 52 caractères base58, débute avec un a",
+ "detailcompwifprefix": "'K' ou 'L'",
+ "detaillabelprivhex": "Clé Privée Format Hexadecimal (64 caractères [0-9A-F]):",
+ "detaillabelprivb64": "Clé Privée Base64 (44 caractères):",
+ "detaillabelprivmini": "Clé Privée Format Mini (22, 26 ou 30 caractères, débute avec un 'S'):",
+ "detaillabelpassphrase": "BIP38 Passphrase", //TODO: please translate
+ "detaildecrypt": "Decrypt BIP38" //TODO: please translate
+ }
+ }
+};
+
+ninja.translator.showEnglishJson = function () {
+ var english = ninja.translator.translations["en"];
+ var spanish = ninja.translator.translations["es"];
+ var spanishClone = {};
+ for (var key in spanish) {
+ spanishClone[key] = spanish[key];
+ }
+ var newLang = {};
+ for (var key in english) {
+ newLang[key] = english[key];
+ delete spanishClone[key];
+ }
+ for (var key in spanishClone) {
+ if (document.getElementById(key)) {
+ if (document.getElementById(key).value) {
+ newLang[key] = document.getElementById(key).value;
+ }
+ else {
+ newLang[key] = document.getElementById(key).innerHTML;
+ }
+ }
+ }
+ var div = document.createElement("div");
+ div.setAttribute("class", "englishjson");
+ div.innerHTML = "
English Json
";
+ var elem = document.createElement("textarea");
+ elem.setAttribute("rows", "35");
+ elem.setAttribute("cols", "110");
+ elem.setAttribute("wrap", "off");
+ var langJson = "{\n";
+ for (var key in newLang) {
+ langJson += "\t\"" + key + "\"" + ": " + "\"" + newLang[key].replace(/\"/g, "\\\"").replace(/\n/g, "\\n") + "\",\n";
+ }
+ langJson = langJson.substr(0, langJson.length - 2);
+ langJson += "\n}\n";
+ elem.innerHTML = langJson;
+ div.appendChild(elem);
+ document.body.appendChild(div);
+};
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0e333f1
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "bitaddress.org",
+ "version": "2.5.0",
+ "description": "Open Source JavaScript Client-Side Bitcoin Wallet Generator",
+ "main": "Gruntfile.js",
+ "dependencies": {
+ "grunt": "~0.4.1",
+ "grunt-combine": "~0.8.3"
+ },
+ "devDependencies": {},
+ "scripts": {
+ "test": ""
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/pointbiz/bitaddress.org.git"
+ },
+ "keywords": [
+ "bitcoin address wallet generator"
+ ],
+ "author": "pointbiz",
+ "license": "MIT",
+ "readmeFilename": "README",
+ "gitHead": "d77aaf687fca1f0e28388b0a8de5eb3d89d4fad3",
+ "bugs": {
+ "url": "https://github.com/pointbiz/bitaddress.org/issues"
+ }
+}
diff --git a/src/array.map.js b/src/array.map.js
new file mode 100644
index 0000000..d1b362f
--- /dev/null
+++ b/src/array.map.js
@@ -0,0 +1,57 @@
+// Array.prototype.map function is in the public domain.
+// Production steps of ECMA-262, Edition 5, 15.4.4.19
+// Reference: http://es5.github.com/#x15.4.4.19
+if (!Array.prototype.map) {
+ Array.prototype.map = function (callback, thisArg) {
+ var T, A, k;
+ if (this == null) {
+ throw new TypeError(" this is null or not defined");
+ }
+ // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
+ var O = Object(this);
+ // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
+ // 3. Let len be ToUint32(lenValue).
+ var len = O.length >>> 0;
+ // 4. If IsCallable(callback) is false, throw a TypeError exception.
+ // See: http://es5.github.com/#x9.11
+ if ({}.toString.call(callback) != "[object Function]") {
+ throw new TypeError(callback + " is not a function");
+ }
+ // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
+ if (thisArg) {
+ T = thisArg;
+ }
+ // 6. Let A be a new array created as if by the expression new Array(len) where Array is
+ // the standard built-in constructor with that name and len is the value of len.
+ A = new Array(len);
+ // 7. Let k be 0
+ k = 0;
+ // 8. Repeat, while k < len
+ while (k < len) {
+ var kValue, mappedValue;
+ // a. Let Pk be ToString(k).
+ // This is implicit for LHS operands of the in operator
+ // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
+ // This step can be combined with c
+ // c. If kPresent is true, then
+ if (k in O) {
+ // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
+ kValue = O[k];
+ // ii. Let mappedValue be the result of calling the Call internal method of callback
+ // with T as the this value and argument list containing kValue, k, and O.
+ mappedValue = callback.call(T, kValue, k, O);
+ // iii. Call the DefineOwnProperty internal method of A with arguments
+ // Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true},
+ // and false.
+ // In browsers that support Object.defineProperty, use the following:
+ // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
+ // For best browser support, use the following:
+ A[k] = mappedValue;
+ }
+ // d. Increase k by 1.
+ k++;
+ }
+ // 9. return A
+ return A;
+ };
+}
\ No newline at end of file
diff --git a/src/biginteger.js b/src/biginteger.js
new file mode 100644
index 0000000..5e77c36
--- /dev/null
+++ b/src/biginteger.js
@@ -0,0 +1,1271 @@
+/*!
+* Basic JavaScript BN library - subset useful for RSA encryption. v1.3
+*
+* Copyright (c) 2005 Tom Wu
+* All Rights Reserved.
+* BSD License
+* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
+*
+* Copyright Stephan Thomas
+* Copyright bitaddress.org
+*/
+
+(function () {
+
+ // (public) Constructor function of Global BigInteger object
+ var BigInteger = window.BigInteger = function BigInteger(a, b, c) {
+ if (a != null)
+ if ("number" == typeof a) this.fromNumber(a, b, c);
+ else if (b == null && "string" != typeof a) this.fromString(a, 256);
+ else this.fromString(a, b);
+ };
+
+ // Bits per digit
+ var dbits;
+
+ // JavaScript engine analysis
+ var canary = 0xdeadbeefcafe;
+ var j_lm = ((canary & 0xffffff) == 0xefcafe);
+
+ // return new, unset BigInteger
+ function nbi() { return new BigInteger(null); }
+
+ // am: Compute w_j += (x*this_i), propagate carries,
+ // c is initial carry, returns final carry.
+ // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+ // We need to select the fastest one that works in this environment.
+
+ // am1: use a single mult and divide to get the high bits,
+ // max digit bits should be 26 because
+ // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+ function am1(i, x, w, j, c, n) {
+ while (--n >= 0) {
+ var v = x * this[i++] + w[j] + c;
+ c = Math.floor(v / 0x4000000);
+ w[j++] = v & 0x3ffffff;
+ }
+ return c;
+ }
+ // am2 avoids a big mult-and-extract completely.
+ // Max digit bits should be <= 30 because we do bitwise ops
+ // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+ function am2(i, x, w, j, c, n) {
+ var xl = x & 0x7fff, xh = x >> 15;
+ while (--n >= 0) {
+ var l = this[i] & 0x7fff;
+ var h = this[i++] >> 15;
+ var m = xh * l + h * xl;
+ l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
+ c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
+ w[j++] = l & 0x3fffffff;
+ }
+ return c;
+ }
+ // Alternately, set max digit bits to 28 since some
+ // browsers slow down when dealing with 32-bit numbers.
+ function am3(i, x, w, j, c, n) {
+ var xl = x & 0x3fff, xh = x >> 14;
+ while (--n >= 0) {
+ var l = this[i] & 0x3fff;
+ var h = this[i++] >> 14;
+ var m = xh * l + h * xl;
+ l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
+ c = (l >> 28) + (m >> 14) + xh * h;
+ w[j++] = l & 0xfffffff;
+ }
+ return c;
+ }
+ if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
+ BigInteger.prototype.am = am2;
+ dbits = 30;
+ }
+ else if (j_lm && (navigator.appName != "Netscape")) {
+ BigInteger.prototype.am = am1;
+ dbits = 26;
+ }
+ else { // Mozilla/Netscape seems to prefer am3
+ BigInteger.prototype.am = am3;
+ dbits = 28;
+ }
+
+ BigInteger.prototype.DB = dbits;
+ BigInteger.prototype.DM = ((1 << dbits) - 1);
+ BigInteger.prototype.DV = (1 << dbits);
+
+ var BI_FP = 52;
+ BigInteger.prototype.FV = Math.pow(2, BI_FP);
+ BigInteger.prototype.F1 = BI_FP - dbits;
+ BigInteger.prototype.F2 = 2 * dbits - BI_FP;
+
+ // Digit conversions
+ var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+ var BI_RC = new Array();
+ var rr, vv;
+ rr = "0".charCodeAt(0);
+ for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+ rr = "a".charCodeAt(0);
+ for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+ rr = "A".charCodeAt(0);
+ for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+ function int2char(n) { return BI_RM.charAt(n); }
+ function intAt(s, i) {
+ var c = BI_RC[s.charCodeAt(i)];
+ return (c == null) ? -1 : c;
+ }
+
+
+
+ // return bigint initialized to value
+ function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
+
+
+ // returns bit length of the integer x
+ function nbits(x) {
+ var r = 1, t;
+ if ((t = x >>> 16) != 0) { x = t; r += 16; }
+ if ((t = x >> 8) != 0) { x = t; r += 8; }
+ if ((t = x >> 4) != 0) { x = t; r += 4; }
+ if ((t = x >> 2) != 0) { x = t; r += 2; }
+ if ((t = x >> 1) != 0) { x = t; r += 1; }
+ return r;
+ }
+
+
+
+
+
+
+
+ // (protected) copy this to r
+ BigInteger.prototype.copyTo = function (r) {
+ for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
+ r.t = this.t;
+ r.s = this.s;
+ };
+
+
+ // (protected) set from integer value x, -DV <= x < DV
+ BigInteger.prototype.fromInt = function (x) {
+ this.t = 1;
+ this.s = (x < 0) ? -1 : 0;
+ if (x > 0) this[0] = x;
+ else if (x < -1) this[0] = x + DV;
+ else this.t = 0;
+ };
+
+ // (protected) set from string and radix
+ BigInteger.prototype.fromString = function (s, b) {
+ var k;
+ if (b == 16) k = 4;
+ else if (b == 8) k = 3;
+ else if (b == 256) k = 8; // byte array
+ else if (b == 2) k = 1;
+ else if (b == 32) k = 5;
+ else if (b == 4) k = 2;
+ else { this.fromRadix(s, b); return; }
+ this.t = 0;
+ this.s = 0;
+ var i = s.length, mi = false, sh = 0;
+ while (--i >= 0) {
+ var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
+ if (x < 0) {
+ if (s.charAt(i) == "-") mi = true;
+ continue;
+ }
+ mi = false;
+ if (sh == 0)
+ this[this.t++] = x;
+ else if (sh + k > this.DB) {
+ this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
+ this[this.t++] = (x >> (this.DB - sh));
+ }
+ else
+ this[this.t - 1] |= x << sh;
+ sh += k;
+ if (sh >= this.DB) sh -= this.DB;
+ }
+ if (k == 8 && (s[0] & 0x80) != 0) {
+ this.s = -1;
+ if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
+ }
+ this.clamp();
+ if (mi) BigInteger.ZERO.subTo(this, this);
+ };
+
+
+ // (protected) clamp off excess high words
+ BigInteger.prototype.clamp = function () {
+ var c = this.s & this.DM;
+ while (this.t > 0 && this[this.t - 1] == c) --this.t;
+ };
+
+ // (protected) r = this << n*DB
+ BigInteger.prototype.dlShiftTo = function (n, r) {
+ var i;
+ for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
+ for (i = n - 1; i >= 0; --i) r[i] = 0;
+ r.t = this.t + n;
+ r.s = this.s;
+ };
+
+ // (protected) r = this >> n*DB
+ BigInteger.prototype.drShiftTo = function (n, r) {
+ for (var i = n; i < this.t; ++i) r[i - n] = this[i];
+ r.t = Math.max(this.t - n, 0);
+ r.s = this.s;
+ };
+
+
+ // (protected) r = this << n
+ BigInteger.prototype.lShiftTo = function (n, r) {
+ var bs = n % this.DB;
+ var cbs = this.DB - bs;
+ var bm = (1 << cbs) - 1;
+ var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i;
+ for (i = this.t - 1; i >= 0; --i) {
+ r[i + ds + 1] = (this[i] >> cbs) | c;
+ c = (this[i] & bm) << bs;
+ }
+ for (i = ds - 1; i >= 0; --i) r[i] = 0;
+ r[ds] = c;
+ r.t = this.t + ds + 1;
+ r.s = this.s;
+ r.clamp();
+ };
+
+
+ // (protected) r = this >> n
+ BigInteger.prototype.rShiftTo = function (n, r) {
+ r.s = this.s;
+ var ds = Math.floor(n / this.DB);
+ if (ds >= this.t) { r.t = 0; return; }
+ var bs = n % this.DB;
+ var cbs = this.DB - bs;
+ var bm = (1 << bs) - 1;
+ r[0] = this[ds] >> bs;
+ for (var i = ds + 1; i < this.t; ++i) {
+ r[i - ds - 1] |= (this[i] & bm) << cbs;
+ r[i - ds] = this[i] >> bs;
+ }
+ if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
+ r.t = this.t - ds;
+ r.clamp();
+ };
+
+
+ // (protected) r = this - a
+ BigInteger.prototype.subTo = function (a, r) {
+ var i = 0, c = 0, m = Math.min(a.t, this.t);
+ while (i < m) {
+ c += this[i] - a[i];
+ r[i++] = c & this.DM;
+ c >>= this.DB;
+ }
+ if (a.t < this.t) {
+ c -= a.s;
+ while (i < this.t) {
+ c += this[i];
+ r[i++] = c & this.DM;
+ c >>= this.DB;
+ }
+ c += this.s;
+ }
+ else {
+ c += this.s;
+ while (i < a.t) {
+ c -= a[i];
+ r[i++] = c & this.DM;
+ c >>= this.DB;
+ }
+ c -= a.s;
+ }
+ r.s = (c < 0) ? -1 : 0;
+ if (c < -1) r[i++] = this.DV + c;
+ else if (c > 0) r[i++] = c;
+ r.t = i;
+ r.clamp();
+ };
+
+
+ // (protected) r = this * a, r != this,a (HAC 14.12)
+ // "this" should be the larger one if appropriate.
+ BigInteger.prototype.multiplyTo = function (a, r) {
+ var x = this.abs(), y = a.abs();
+ var i = x.t;
+ r.t = i + y.t;
+ while (--i >= 0) r[i] = 0;
+ for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
+ r.s = 0;
+ r.clamp();
+ if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
+ };
+
+
+ // (protected) r = this^2, r != this (HAC 14.16)
+ BigInteger.prototype.squareTo = function (r) {
+ var x = this.abs();
+ var i = r.t = 2 * x.t;
+ while (--i >= 0) r[i] = 0;
+ for (i = 0; i < x.t - 1; ++i) {
+ var c = x.am(i, x[i], r, 2 * i, 0, 1);
+ if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
+ r[i + x.t] -= x.DV;
+ r[i + x.t + 1] = 1;
+ }
+ }
+ if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
+ r.s = 0;
+ r.clamp();
+ };
+
+
+
+ // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+ // r != q, this != m. q or r may be null.
+ BigInteger.prototype.divRemTo = function (m, q, r) {
+ var pm = m.abs();
+ if (pm.t <= 0) return;
+ var pt = this.abs();
+ if (pt.t < pm.t) {
+ if (q != null) q.fromInt(0);
+ if (r != null) this.copyTo(r);
+ return;
+ }
+ if (r == null) r = nbi();
+ var y = nbi(), ts = this.s, ms = m.s;
+ var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
+ if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); }
+ else { pm.copyTo(y); pt.copyTo(r); }
+ var ys = y.t;
+ var y0 = y[ys - 1];
+ if (y0 == 0) return;
+ var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
+ var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2;
+ var i = r.t, j = i - ys, t = (q == null) ? nbi() : q;
+ y.dlShiftTo(j, t);
+ if (r.compareTo(t) >= 0) {
+ r[r.t++] = 1;
+ r.subTo(t, r);
+ }
+ BigInteger.ONE.dlShiftTo(ys, t);
+ t.subTo(y, y); // "negative" y so we can replace sub with am later
+ while (y.t < ys) y[y.t++] = 0;
+ while (--j >= 0) {
+ // Estimate quotient digit
+ var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
+ if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
+ y.dlShiftTo(j, t);
+ r.subTo(t, r);
+ while (r[i] < --qd) r.subTo(t, r);
+ }
+ }
+ if (q != null) {
+ r.drShiftTo(ys, q);
+ if (ts != ms) BigInteger.ZERO.subTo(q, q);
+ }
+ r.t = ys;
+ r.clamp();
+ if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
+ if (ts < 0) BigInteger.ZERO.subTo(r, r);
+ };
+
+
+ // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+ // justification:
+ // xy == 1 (mod m)
+ // xy = 1+km
+ // xy(2-xy) = (1+km)(1-km)
+ // x[y(2-xy)] = 1-k^2m^2
+ // x[y(2-xy)] == 1 (mod m^2)
+ // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+ // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+ // JS multiply "overflows" differently from C/C++, so care is needed here.
+ BigInteger.prototype.invDigit = function () {
+ if (this.t < 1) return 0;
+ var x = this[0];
+ if ((x & 1) == 0) return 0;
+ var y = x & 3; // y == 1/x mod 2^2
+ y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
+ y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
+ y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
+ // last step - calculate inverse mod DV directly;
+ // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+ y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
+ // we really want the negative inverse, and -DV < y < DV
+ return (y > 0) ? this.DV - y : -y;
+ };
+
+
+ // (protected) true iff this is even
+ BigInteger.prototype.isEven = function () { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; };
+
+
+ // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+ BigInteger.prototype.exp = function (e, z) {
+ if (e > 0xffffffff || e < 1) return BigInteger.ONE;
+ var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1;
+ g.copyTo(r);
+ while (--i >= 0) {
+ z.sqrTo(r, r2);
+ if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
+ else { var t = r; r = r2; r2 = t; }
+ }
+ return z.revert(r);
+ };
+
+
+ // (public) return string representation in given radix
+ BigInteger.prototype.toString = function (b) {
+ if (this.s < 0) return "-" + this.negate().toString(b);
+ var k;
+ if (b == 16) k = 4;
+ else if (b == 8) k = 3;
+ else if (b == 2) k = 1;
+ else if (b == 32) k = 5;
+ else if (b == 4) k = 2;
+ else return this.toRadix(b);
+ var km = (1 << k) - 1, d, m = false, r = "", i = this.t;
+ var p = this.DB - (i * this.DB) % k;
+ if (i-- > 0) {
+ if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); }
+ while (i >= 0) {
+ if (p < k) {
+ d = (this[i] & ((1 << p) - 1)) << (k - p);
+ d |= this[--i] >> (p += this.DB - k);
+ }
+ else {
+ d = (this[i] >> (p -= k)) & km;
+ if (p <= 0) { p += this.DB; --i; }
+ }
+ if (d > 0) m = true;
+ if (m) r += int2char(d);
+ }
+ }
+ return m ? r : "0";
+ };
+
+
+ // (public) -this
+ BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; };
+
+ // (public) |this|
+ BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this; };
+
+ // (public) return + if this > a, - if this < a, 0 if equal
+ BigInteger.prototype.compareTo = function (a) {
+ var r = this.s - a.s;
+ if (r != 0) return r;
+ var i = this.t;
+ r = i - a.t;
+ if (r != 0) return (this.s < 0) ? -r : r;
+ while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
+ return 0;
+ }
+
+ // (public) return the number of bits in "this"
+ BigInteger.prototype.bitLength = function () {
+ if (this.t <= 0) return 0;
+ return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
+ };
+
+ // (public) this mod a
+ BigInteger.prototype.mod = function (a) {
+ var r = nbi();
+ this.abs().divRemTo(a, null, r);
+ if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
+ return r;
+ }
+
+ // (public) this^e % m, 0 <= e < 2^32
+ BigInteger.prototype.modPowInt = function (e, m) {
+ var z;
+ if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
+ return this.exp(e, z);
+ };
+
+ // "constants"
+ BigInteger.ZERO = nbv(0);
+ BigInteger.ONE = nbv(1);
+
+
+
+
+
+
+
+ // Copyright (c) 2005-2009 Tom Wu
+ // All Rights Reserved.
+ // See "LICENSE" for details.
+ // Extended JavaScript BN functions, required for RSA private ops.
+ // Version 1.1: new BigInteger("0", 10) returns "proper" zero
+ // Version 1.2: square() API, isProbablePrime fix
+
+
+ // return index of lowest 1-bit in x, x < 2^31
+ function lbit(x) {
+ if (x == 0) return -1;
+ var r = 0;
+ if ((x & 0xffff) == 0) { x >>= 16; r += 16; }
+ if ((x & 0xff) == 0) { x >>= 8; r += 8; }
+ if ((x & 0xf) == 0) { x >>= 4; r += 4; }
+ if ((x & 3) == 0) { x >>= 2; r += 2; }
+ if ((x & 1) == 0) ++r;
+ return r;
+ }
+
+ // return number of 1 bits in x
+ function cbit(x) {
+ var r = 0;
+ while (x != 0) { x &= x - 1; ++r; }
+ return r;
+ }
+
+ var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
+ var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
+
+
+
+ // (protected) return x s.t. r^x < DV
+ BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); };
+
+ // (protected) convert to radix string
+ BigInteger.prototype.toRadix = function (b) {
+ if (b == null) b = 10;
+ if (this.signum() == 0 || b < 2 || b > 36) return "0";
+ var cs = this.chunkSize(b);
+ var a = Math.pow(b, cs);
+ var d = nbv(a), y = nbi(), z = nbi(), r = "";
+ this.divRemTo(d, y, z);
+ while (y.signum() > 0) {
+ r = (a + z.intValue()).toString(b).substr(1) + r;
+ y.divRemTo(d, y, z);
+ }
+ return z.intValue().toString(b) + r;
+ };
+
+ // (protected) convert from radix string
+ BigInteger.prototype.fromRadix = function (s, b) {
+ this.fromInt(0);
+ if (b == null) b = 10;
+ var cs = this.chunkSize(b);
+ var d = Math.pow(b, cs), mi = false, j = 0, w = 0;
+ for (var i = 0; i < s.length; ++i) {
+ var x = intAt(s, i);
+ if (x < 0) {
+ if (s.charAt(i) == "-" && this.signum() == 0) mi = true;
+ continue;
+ }
+ w = b * w + x;
+ if (++j >= cs) {
+ this.dMultiply(d);
+ this.dAddOffset(w, 0);
+ j = 0;
+ w = 0;
+ }
+ }
+ if (j > 0) {
+ this.dMultiply(Math.pow(b, j));
+ this.dAddOffset(w, 0);
+ }
+ if (mi) BigInteger.ZERO.subTo(this, this);
+ };
+
+ // (protected) alternate constructor
+ BigInteger.prototype.fromNumber = function (a, b, c) {
+ if ("number" == typeof b) {
+ // new BigInteger(int,int,RNG)
+ if (a < 2) this.fromInt(1);
+ else {
+ this.fromNumber(a, c);
+ if (!this.testBit(a - 1)) // force MSB set
+ this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
+ if (this.isEven()) this.dAddOffset(1, 0); // force odd
+ while (!this.isProbablePrime(b)) {
+ this.dAddOffset(2, 0);
+ if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
+ }
+ }
+ }
+ else {
+ // new BigInteger(int,RNG)
+ var x = new Array(), t = a & 7;
+ x.length = (a >> 3) + 1;
+ b.nextBytes(x);
+ if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0;
+ this.fromString(x, 256);
+ }
+ };
+
+ // (protected) r = this op a (bitwise)
+ BigInteger.prototype.bitwiseTo = function (a, op, r) {
+ var i, f, m = Math.min(a.t, this.t);
+ for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
+ if (a.t < this.t) {
+ f = a.s & this.DM;
+ for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
+ r.t = this.t;
+ }
+ else {
+ f = this.s & this.DM;
+ for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
+ r.t = a.t;
+ }
+ r.s = op(this.s, a.s);
+ r.clamp();
+ };
+
+ // (protected) this op (1<>= this.DB;
+ }
+ if (a.t < this.t) {
+ c += a.s;
+ while (i < this.t) {
+ c += this[i];
+ r[i++] = c & this.DM;
+ c >>= this.DB;
+ }
+ c += this.s;
+ }
+ else {
+ c += this.s;
+ while (i < a.t) {
+ c += a[i];
+ r[i++] = c & this.DM;
+ c >>= this.DB;
+ }
+ c += a.s;
+ }
+ r.s = (c < 0) ? -1 : 0;
+ if (c > 0) r[i++] = c;
+ else if (c < -1) r[i++] = this.DV + c;
+ r.t = i;
+ r.clamp();
+ };
+
+ // (protected) this *= n, this >= 0, 1 < n < DV
+ BigInteger.prototype.dMultiply = function (n) {
+ this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
+ ++this.t;
+ this.clamp();
+ };
+
+ // (protected) this += n << w words, this >= 0
+ BigInteger.prototype.dAddOffset = function (n, w) {
+ if (n == 0) return;
+ while (this.t <= w) this[this.t++] = 0;
+ this[w] += n;
+ while (this[w] >= this.DV) {
+ this[w] -= this.DV;
+ if (++w >= this.t) this[this.t++] = 0;
+ ++this[w];
+ }
+ };
+
+ // (protected) r = lower n words of "this * a", a.t <= n
+ // "this" should be the larger one if appropriate.
+ BigInteger.prototype.multiplyLowerTo = function (a, n, r) {
+ var i = Math.min(this.t + a.t, n);
+ r.s = 0; // assumes a,this >= 0
+ r.t = i;
+ while (i > 0) r[--i] = 0;
+ var j;
+ for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
+ for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
+ r.clamp();
+ };
+
+
+ // (protected) r = "this * a" without lower n words, n > 0
+ // "this" should be the larger one if appropriate.
+ BigInteger.prototype.multiplyUpperTo = function (a, n, r) {
+ --n;
+ var i = r.t = this.t + a.t - n;
+ r.s = 0; // assumes a,this >= 0
+ while (--i >= 0) r[i] = 0;
+ for (i = Math.max(n - this.t, 0); i < a.t; ++i)
+ r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
+ r.clamp();
+ r.drShiftTo(1, r);
+ };
+
+ // (protected) this % n, n < 2^26
+ BigInteger.prototype.modInt = function (n) {
+ if (n <= 0) return 0;
+ var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0;
+ if (this.t > 0)
+ if (d == 0) r = this[0] % n;
+ else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
+ return r;
+ };
+
+
+ // (protected) true if probably prime (HAC 4.24, Miller-Rabin)
+ BigInteger.prototype.millerRabin = function (t) {
+ var n1 = this.subtract(BigInteger.ONE);
+ var k = n1.getLowestSetBit();
+ if (k <= 0) return false;
+ var r = n1.shiftRight(k);
+ t = (t + 1) >> 1;
+ if (t > lowprimes.length) t = lowprimes.length;
+ var a = nbi();
+ for (var i = 0; i < t; ++i) {
+ //Pick bases at random, instead of starting at 2
+ a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]);
+ var y = a.modPow(r, this);
+ if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
+ var j = 1;
+ while (j++ < k && y.compareTo(n1) != 0) {
+ y = y.modPowInt(2, this);
+ if (y.compareTo(BigInteger.ONE) == 0) return false;
+ }
+ if (y.compareTo(n1) != 0) return false;
+ }
+ }
+ return true;
+ };
+
+
+
+ // (public)
+ BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r; };
+
+ // (public) return value as integer
+ BigInteger.prototype.intValue = function () {
+ if (this.s < 0) {
+ if (this.t == 1) return this[0] - this.DV;
+ else if (this.t == 0) return -1;
+ }
+ else if (this.t == 1) return this[0];
+ else if (this.t == 0) return 0;
+ // assumes 16 < DB < 32
+ return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
+ };
+
+
+ // (public) return value as byte
+ BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; };
+
+ // (public) return value as short (assumes DB>=16)
+ BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; };
+
+ // (public) 0 if this == 0, 1 if this > 0
+ BigInteger.prototype.signum = function () {
+ if (this.s < 0) return -1;
+ else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
+ else return 1;
+ };
+
+
+ // (public) convert to bigendian byte array
+ BigInteger.prototype.toByteArray = function () {
+ var i = this.t, r = new Array();
+ r[0] = this.s;
+ var p = this.DB - (i * this.DB) % 8, d, k = 0;
+ if (i-- > 0) {
+ if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p)
+ r[k++] = d | (this.s << (this.DB - p));
+ while (i >= 0) {
+ if (p < 8) {
+ d = (this[i] & ((1 << p) - 1)) << (8 - p);
+ d |= this[--i] >> (p += this.DB - 8);
+ }
+ else {
+ d = (this[i] >> (p -= 8)) & 0xff;
+ if (p <= 0) { p += this.DB; --i; }
+ }
+ if ((d & 0x80) != 0) d |= -256;
+ if (k == 0 && (this.s & 0x80) != (d & 0x80)) ++k;
+ if (k > 0 || d != this.s) r[k++] = d;
+ }
+ }
+ return r;
+ };
+
+ BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0); };
+ BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a; };
+ BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a; };
+
+ // (public) this & a
+ function op_and(x, y) { return x & y; }
+ BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; };
+
+ // (public) this | a
+ function op_or(x, y) { return x | y; }
+ BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; };
+
+ // (public) this ^ a
+ function op_xor(x, y) { return x ^ y; }
+ BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; };
+
+ // (public) this & ~a
+ function op_andnot(x, y) { return x & ~y; }
+ BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; };
+
+ // (public) ~this
+ BigInteger.prototype.not = function () {
+ var r = nbi();
+ for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
+ r.t = this.t;
+ r.s = ~this.s;
+ return r;
+ };
+
+ // (public) this << n
+ BigInteger.prototype.shiftLeft = function (n) {
+ var r = nbi();
+ if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r);
+ return r;
+ };
+
+ // (public) this >> n
+ BigInteger.prototype.shiftRight = function (n) {
+ var r = nbi();
+ if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r);
+ return r;
+ };
+
+ // (public) returns index of lowest 1-bit (or -1 if none)
+ BigInteger.prototype.getLowestSetBit = function () {
+ for (var i = 0; i < this.t; ++i)
+ if (this[i] != 0) return i * this.DB + lbit(this[i]);
+ if (this.s < 0) return this.t * this.DB;
+ return -1;
+ };
+
+ // (public) return number of set bits
+ BigInteger.prototype.bitCount = function () {
+ var r = 0, x = this.s & this.DM;
+ for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
+ return r;
+ };
+
+ // (public) true iff nth bit is set
+ BigInteger.prototype.testBit = function (n) {
+ var j = Math.floor(n / this.DB);
+ if (j >= this.t) return (this.s != 0);
+ return ((this[j] & (1 << (n % this.DB))) != 0);
+ };
+
+ // (public) this | (1< 1) {
+ var g2 = nbi();
+ z.sqrTo(g[1], g2);
+ while (n <= km) {
+ g[n] = nbi();
+ z.mulTo(g2, g[n - 2], g[n]);
+ n += 2;
+ }
+ }
+
+ var j = e.t - 1, w, is1 = true, r2 = nbi(), t;
+ i = nbits(e[j]) - 1;
+ while (j >= 0) {
+ if (i >= k1) w = (e[j] >> (i - k1)) & km;
+ else {
+ w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
+ if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
+ }
+
+ n = k;
+ while ((w & 1) == 0) { w >>= 1; --n; }
+ if ((i -= n) < 0) { i += this.DB; --j; }
+ if (is1) { // ret == 1, don't bother squaring or multiplying it
+ g[w].copyTo(r);
+ is1 = false;
+ }
+ else {
+ while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2; }
+ if (n > 0) z.sqrTo(r, r2); else { t = r; r = r2; r2 = t; }
+ z.mulTo(r2, g[w], r);
+ }
+
+ while (j >= 0 && (e[j] & (1 << i)) == 0) {
+ z.sqrTo(r, r2); t = r; r = r2; r2 = t;
+ if (--i < 0) { i = this.DB - 1; --j; }
+ }
+ }
+ return z.revert(r);
+ };
+
+ // (public) 1/this % m (HAC 14.61)
+ BigInteger.prototype.modInverse = function (m) {
+ var ac = m.isEven();
+ if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
+ var u = m.clone(), v = this.clone();
+ var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
+ while (u.signum() != 0) {
+ while (u.isEven()) {
+ u.rShiftTo(1, u);
+ if (ac) {
+ if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b); }
+ a.rShiftTo(1, a);
+ }
+ else if (!b.isEven()) b.subTo(m, b);
+ b.rShiftTo(1, b);
+ }
+ while (v.isEven()) {
+ v.rShiftTo(1, v);
+ if (ac) {
+ if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d); }
+ c.rShiftTo(1, c);
+ }
+ else if (!d.isEven()) d.subTo(m, d);
+ d.rShiftTo(1, d);
+ }
+ if (u.compareTo(v) >= 0) {
+ u.subTo(v, u);
+ if (ac) a.subTo(c, a);
+ b.subTo(d, b);
+ }
+ else {
+ v.subTo(u, v);
+ if (ac) c.subTo(a, c);
+ d.subTo(b, d);
+ }
+ }
+ if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
+ if (d.compareTo(m) >= 0) return d.subtract(m);
+ if (d.signum() < 0) d.addTo(m, d); else return d;
+ if (d.signum() < 0) return d.add(m); else return d;
+ };
+
+
+ // (public) this^e
+ BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()); };
+
+ // (public) gcd(this,a) (HAC 14.54)
+ BigInteger.prototype.gcd = function (a) {
+ var x = (this.s < 0) ? this.negate() : this.clone();
+ var y = (a.s < 0) ? a.negate() : a.clone();
+ if (x.compareTo(y) < 0) { var t = x; x = y; y = t; }
+ var i = x.getLowestSetBit(), g = y.getLowestSetBit();
+ if (g < 0) return x;
+ if (i < g) g = i;
+ if (g > 0) {
+ x.rShiftTo(g, x);
+ y.rShiftTo(g, y);
+ }
+ while (x.signum() > 0) {
+ if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
+ if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
+ if (x.compareTo(y) >= 0) {
+ x.subTo(y, x);
+ x.rShiftTo(1, x);
+ }
+ else {
+ y.subTo(x, y);
+ y.rShiftTo(1, y);
+ }
+ }
+ if (g > 0) y.lShiftTo(g, y);
+ return y;
+ };
+
+ // (public) test primality with certainty >= 1-.5^t
+ BigInteger.prototype.isProbablePrime = function (t) {
+ var i, x = this.abs();
+ if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
+ for (i = 0; i < lowprimes.length; ++i)
+ if (x[0] == lowprimes[i]) return true;
+ return false;
+ }
+ if (x.isEven()) return false;
+ i = 1;
+ while (i < lowprimes.length) {
+ var m = lowprimes[i], j = i + 1;
+ while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
+ m = x.modInt(m);
+ while (i < j) if (m % lowprimes[i++] == 0) return false;
+ }
+ return x.millerRabin(t);
+ };
+
+
+ // JSBN-specific extension
+
+ // (public) this^2
+ BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r; };
+
+
+ // NOTE: BigInteger interfaces not implemented in jsbn:
+ // BigInteger(int signum, byte[] magnitude)
+ // double doubleValue()
+ // float floatValue()
+ // int hashCode()
+ // long longValue()
+ // static BigInteger valueOf(long val)
+
+
+
+ // Copyright Stephan Thomas (start) --- //
+ // https://raw.github.com/bitcoinjs/bitcoinjs-lib/07f9d55ccb6abd962efb6befdd37671f85ea4ff9/src/util.js
+ // BigInteger monkey patching
+ BigInteger.valueOf = nbv;
+
+ /**
+ * Returns a byte array representation of the big integer.
+ *
+ * This returns the absolute of the contained value in big endian
+ * form. A value of zero results in an empty array.
+ */
+ BigInteger.prototype.toByteArrayUnsigned = function () {
+ var ba = this.abs().toByteArray();
+ if (ba.length) {
+ if (ba[0] == 0) {
+ ba = ba.slice(1);
+ }
+ return ba.map(function (v) {
+ return (v < 0) ? v + 256 : v;
+ });
+ } else {
+ // Empty array, nothing to do
+ return ba;
+ }
+ };
+
+ /**
+ * Turns a byte array into a big integer.
+ *
+ * This function will interpret a byte array as a big integer in big
+ * endian notation and ignore leading zeros.
+ */
+ BigInteger.fromByteArrayUnsigned = function (ba) {
+ if (!ba.length) {
+ return ba.valueOf(0);
+ } else if (ba[0] & 0x80) {
+ // Prepend a zero so the BigInteger class doesn't mistake this
+ // for a negative integer.
+ return new BigInteger([0].concat(ba));
+ } else {
+ return new BigInteger(ba);
+ }
+ };
+
+ /**
+ * Converts big integer to signed byte representation.
+ *
+ * The format for this value uses a the most significant bit as a sign
+ * bit. If the most significant bit is already occupied by the
+ * absolute value, an extra byte is prepended and the sign bit is set
+ * there.
+ *
+ * Examples:
+ *
+ * 0 => 0x00
+ * 1 => 0x01
+ * -1 => 0x81
+ * 127 => 0x7f
+ * -127 => 0xff
+ * 128 => 0x0080
+ * -128 => 0x8080
+ * 255 => 0x00ff
+ * -255 => 0x80ff
+ * 16300 => 0x3fac
+ * -16300 => 0xbfac
+ * 62300 => 0x00f35c
+ * -62300 => 0x80f35c
+ */
+ BigInteger.prototype.toByteArraySigned = function () {
+ var val = this.abs().toByteArrayUnsigned();
+ var neg = this.compareTo(BigInteger.ZERO) < 0;
+
+ if (neg) {
+ if (val[0] & 0x80) {
+ val.unshift(0x80);
+ } else {
+ val[0] |= 0x80;
+ }
+ } else {
+ if (val[0] & 0x80) {
+ val.unshift(0x00);
+ }
+ }
+
+ return val;
+ };
+
+ /**
+ * Parse a signed big integer byte representation.
+ *
+ * For details on the format please see BigInteger.toByteArraySigned.
+ */
+ BigInteger.fromByteArraySigned = function (ba) {
+ // Check for negative value
+ if (ba[0] & 0x80) {
+ // Remove sign bit
+ ba[0] &= 0x7f;
+
+ return BigInteger.fromByteArrayUnsigned(ba).negate();
+ } else {
+ return BigInteger.fromByteArrayUnsigned(ba);
+ }
+ };
+ // Copyright Stephan Thomas (end) --- //
+
+
+
+
+ // ****** REDUCTION ******* //
+
+ // Modular reduction using "classic" algorithm
+ function Classic(m) { this.m = m; }
+ Classic.prototype.convert = function (x) {
+ if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+ else return x;
+ };
+ Classic.prototype.revert = function (x) { return x; };
+ Classic.prototype.reduce = function (x) { x.divRemTo(this.m, null, x); };
+ Classic.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
+ Classic.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
+
+
+
+
+
+ // Montgomery reduction
+ function Montgomery(m) {
+ this.m = m;
+ this.mp = m.invDigit();
+ this.mpl = this.mp & 0x7fff;
+ this.mph = this.mp >> 15;
+ this.um = (1 << (m.DB - 15)) - 1;
+ this.mt2 = 2 * m.t;
+ }
+ // xR mod m
+ Montgomery.prototype.convert = function (x) {
+ var r = nbi();
+ x.abs().dlShiftTo(this.m.t, r);
+ r.divRemTo(this.m, null, r);
+ if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
+ return r;
+ }
+ // x/R mod m
+ Montgomery.prototype.revert = function (x) {
+ var r = nbi();
+ x.copyTo(r);
+ this.reduce(r);
+ return r;
+ };
+ // x = x/R mod m (HAC 14.32)
+ Montgomery.prototype.reduce = function (x) {
+ while (x.t <= this.mt2) // pad x so am has enough room later
+ x[x.t++] = 0;
+ for (var i = 0; i < this.m.t; ++i) {
+ // faster way of calculating u0 = x[i]*mp mod DV
+ var j = x[i] & 0x7fff;
+ var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
+ // use am to combine the multiply-shift-add into one call
+ j = i + this.m.t;
+ x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
+ // propagate carry
+ while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
+ }
+ x.clamp();
+ x.drShiftTo(this.m.t, x);
+ if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
+ };
+ // r = "xy/R mod m"; x,y != r
+ Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
+ // r = "x^2/R mod m"; x != r
+ Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
+
+
+
+
+
+ // A "null" reducer
+ function NullExp() { }
+ NullExp.prototype.convert = function (x) { return x; };
+ NullExp.prototype.revert = function (x) { return x; };
+ NullExp.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); };
+ NullExp.prototype.sqrTo = function (x, r) { x.squareTo(r); };
+
+
+
+
+
+ // Barrett modular reduction
+ function Barrett(m) {
+ // setup Barrett
+ this.r2 = nbi();
+ this.q3 = nbi();
+ BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
+ this.mu = this.r2.divide(m);
+ this.m = m;
+ }
+ Barrett.prototype.convert = function (x) {
+ if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
+ else if (x.compareTo(this.m) < 0) return x;
+ else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
+ };
+ Barrett.prototype.revert = function (x) { return x; };
+ // x = x mod m (HAC 14.42)
+ Barrett.prototype.reduce = function (x) {
+ x.drShiftTo(this.m.t - 1, this.r2);
+ if (x.t > this.m.t + 1) { x.t = this.m.t + 1; x.clamp(); }
+ this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
+ this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
+ while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
+ x.subTo(this.r2, x);
+ while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
+ };
+ // r = x*y mod m; x,y != r
+ Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
+ // r = x^2 mod m; x != r
+ Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
+
+})();
\ No newline at end of file
diff --git a/src/bitaddress-ui.html b/src/bitaddress-ui.html
new file mode 100644
index 0000000..7954bb1
--- /dev/null
+++ b/src/bitaddress-ui.html
@@ -0,0 +1,428 @@
+
+
+
+
+
+ bitaddress.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Why should I use a Bulk Wallet to accept Bitcoins on my website?
+
+
+
The traditional approach to accepting bitcoins on your website requires that you install the official bitcoin client daemon ("bitcoind"). Many website hosting packages don't support installing the bitcoin daemon. Also, running the bitcoin daemon on your web server means your private keys are hosted on the server and could get stolen if your web server is hacked. When using a Bulk Wallet you can upload only the bitcoin addresses and not the private keys to your web server. Then you don't have to worry about your bitcoin wallet being stolen if your web server is hacked.
+
+
+
+ How do I use a Bulk Wallet to accept Bitcoins on my website?
+
+
+
+
+
Use the Bulk Wallet tab to pre-generate a large number of bitcoin addresses (10,000+). Copy and paste the generated comma separated values (CSV) list to a secure text file on your computer. Backup the file you just created to a secure location.
+
Import the bitcoin addresses into a database table on your web server. (Don't put the wallet/private keys on your web server, otherwise you risk hackers stealing your coins. Just the bitcoin addresses as they will be shown to customers.)
+
Provide an option on your website's shopping cart for your customer to pay in Bitcoin. When the customer chooses to pay in Bitcoin you will then display one of the addresses from your database to the customer as his "payment address" and save it with his shopping cart order.
+
You now need to be notified when the payment arrives. Google "bitcoin payment notification" and subscribe to at least one bitcoin payment notification service. There are various services that will notify you via Web Services, API, SMS, Email, etc. Once you receive this notification, which could be programmatically automated, you can process the customer's order. To manually check if a payment has arrived you can use Block Explorer. Replace THEADDRESSGOESHERE with the bitcoin address you are checking. It could take between 10 minutes to one hour for the transaction to be confirmed. http://www.blockexplorer.com/address/THEADDRESSGOESHERE
Unconfirmed transactions can be viewed at: http://blockchain.info/ You should see the transaction there within 30 seconds.
+
Bitcoins will safely pile up on the block chain. Use the original wallet file you generated in step 1 to spend them.
Copy and paste the above into the Your-Part-Public-Key field in the Vanity Pool Website.
+
+
+ Step 1 Private Key:
+
+
Copy and paste the above Private Key field into a text file. Ideally save to an encrypted drive. You will need this to retrieve the Bitcoin Private Key once the Pool has found your prefix.
+
+
+
+ Step 2 - Calculate your Vanity Wallet
+
+
+
+
+ Enter Your Part Private Key (generated in Step 1 above and previously saved):
+ [NOTE: this input box can accept a public key or private key]
+
+
+
+ Enter Pool Part Private Key (from Vanity Pool):
+ [NOTE: this input box can accept a public key or private key]
+
+
+
+
+
+
+
+
+
+
+ Vanity Bitcoin Address:
+
+
The above is your new address that should include your required prefix.
+
+
+
+ Vanity Public Key (HEX):
+
+
The above is the Public Key in hexadecimal format.
+
+
+
+ Vanity Private Key (WIF):
+
+
The above is the Private Key to load into your wallet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Your Bitcoin Private Key is a unique secret number that only you know. It can be encoded in a number of different formats. Below we show the Bitcoin Address and Public Key that corresponds to your Private Key as well as your Private Key in the most popular encoding formats (WIF, HEX, B64, MINI).
+
+ Bitcoin v0.6+ stores public keys in compressed format. The client now also supports import and export of private keys with importprivkey/dumpprivkey. The format of the exported private key is determined by whether the address was generated in an old or new wallet.
+
+
+
+ Bitcoin Address
+
+
+
+
+ Bitcoin Address Compressed
+
+
+
+
+
+
+ Public Key (130 characters [0-9A-F]):
+
+
+
+ Public Key (compressed, 66 characters [0-9A-F]):
+
+
";
+ return walletHtml;
+ },
+
+ showArtisticWallet: function (idPostFix, bitcoinAddress, privateKeyWif) {
+ var keyValuePair = {};
+ keyValuePair["qrcode_public" + idPostFix] = bitcoinAddress;
+ keyValuePair["qrcode_private" + idPostFix] = privateKeyWif;
+ ninja.qrCode.showQrCode(keyValuePair, 2.5);
+ document.getElementById("btcaddress" + idPostFix).innerHTML = bitcoinAddress;
+ document.getElementById("btcprivwif" + idPostFix).innerHTML = privateKeyWif;
+
+ // CODE to modify SVG DOM elements
+ //var paperSvg = document.getElementById("papersvg" + idPostFix);
+ //if (paperSvg) {
+ // svgDoc = paperSvg.contentDocument;
+ // if (svgDoc) {
+ // var bitcoinAddressElement = svgDoc.getElementById("bitcoinaddress");
+ // var privateKeyElement = svgDoc.getElementById("privatekey");
+ // if (bitcoinAddressElement && privateKeyElement) {
+ // bitcoinAddressElement.textContent = bitcoinAddress;
+ // privateKeyElement.textContent = privateKeyWif;
+ // }
+ // }
+ //}
+ },
+
+ toggleArt: function (element) {
+ if (!element.checked) {
+ // show Art
+ document.getElementById("paperlimitperpage").value = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
+ document.getElementById("paperlimit").value = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
+ }
+ else {
+ // hide Art
+ document.getElementById("paperlimitperpage").value = ninja.wallets.paperwallet.pageBreakAtDefault;
+ document.getElementById("paperlimit").value = ninja.wallets.paperwallet.pageBreakAtDefault;
+ }
+ }
+};
\ No newline at end of file
diff --git a/src/ninja.singlewallet.js b/src/ninja.singlewallet.js
new file mode 100644
index 0000000..9a32cb3
--- /dev/null
+++ b/src/ninja.singlewallet.js
@@ -0,0 +1,36 @@
+ninja.wallets.singlewallet = {
+ open: function () {
+ if (document.getElementById("btcaddress").innerHTML == "") {
+ ninja.wallets.singlewallet.generateNewAddressAndKey();
+ }
+ document.getElementById("singlearea").style.display = "block";
+ },
+
+ close: function () {
+ document.getElementById("singlearea").style.display = "none";
+ },
+
+ // generate bitcoin address and private key and update information in the HTML
+ generateNewAddressAndKey: function () {
+ try {
+ var key = new Bitcoin.ECKey(false);
+ var bitcoinAddress = key.getBitcoinAddress();
+ var privateKeyWif = key.getBitcoinWalletImportFormat();
+ document.getElementById("btcaddress").innerHTML = bitcoinAddress;
+ document.getElementById("btcprivwif").innerHTML = privateKeyWif;
+ var keyValuePair = {
+ "qrcode_public": bitcoinAddress,
+ "qrcode_private": privateKeyWif
+ };
+ ninja.qrCode.showQrCode(keyValuePair);
+ }
+ catch (e) {
+ // browser does not have sufficient JavaScript support to generate a bitcoin address
+ alert(e);
+ document.getElementById("btcaddress").innerHTML = "error";
+ document.getElementById("btcprivwif").innerHTML = "error";
+ document.getElementById("qrcode_public").innerHTML = "";
+ document.getElementById("qrcode_private").innerHTML = "";
+ }
+ }
+};
\ No newline at end of file
diff --git a/src/ninja.translator.js b/src/ninja.translator.js
new file mode 100644
index 0000000..37f0dce
--- /dev/null
+++ b/src/ninja.translator.js
@@ -0,0 +1,316 @@
+ninja.translator = {
+ currentCulture: "en",
+
+ translate: function (culture) {
+ var dict = ninja.translator.translations[culture];
+ if (dict) {
+ // set current culture
+ ninja.translator.currentCulture = culture;
+ // update menu UI
+ for (var cult in ninja.translator.translations) {
+ document.getElementById("culture" + cult).setAttribute("class", "");
+ }
+ document.getElementById("culture" + culture).setAttribute("class", "selected");
+ // apply translations
+ for (var id in dict) {
+ if (document.getElementById(id) && document.getElementById(id).value) {
+ document.getElementById(id).value = dict[id];
+ }
+ else if (document.getElementById(id)) {
+ document.getElementById(id).innerHTML = dict[id];
+ }
+ }
+ }
+ },
+
+ get: function (id) {
+ var translation = ninja.translator.translations[ninja.translator.currentCulture][id];
+ return translation;
+ },
+
+ translations: {
+ "en": {
+ // javascript alerts or messages
+ "testneteditionactivated": "TESTNET EDITION ACTIVATED",
+ "paperlabelbitcoinaddress": "Bitcoin Address:",
+ "paperlabelprivatekey": "Private Key (Wallet Import Format):",
+ "bulkgeneratingaddresses": "Generating addresses... ",
+ "brainalertpassphrasetooshort": "The passphrase you entered is too short.\n\nWarning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your bitcoins.",
+ "brainalertpassphrasedoesnotmatch": "The passphrase does not match the confirm passphrase.",
+ "detailalertnotvalidprivatekey": "The text you entered is not a valid Private Key",
+ "detailconfirmsha256": "The text you entered is not a valid Private Key!\n\nWould you like to use the entered text as a passphrase and create a Private Key using a SHA256 hash of the passphrase?\n\nWarning: Choosing a strong passphrase is important to avoid brute force attempts to guess your passphrase and steal your bitcoins.",
+ "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.",
+ "bip38alertpassphraserequired": "Passphrase required for BIP38 key",
+ "vanityinvalidinputcouldnotcombinekeys": "Invalid input. Could not combine keys.",
+ "vanityalertinvalidinputpublickeysmatch": "Invalid input. The Public Key of both entries match. You must input two different keys.",
+ "vanityalertinvalidinputcannotmultiple": "Invalid input. Cannot multiply two public keys. Select 'Add' to add two public keys to get a bitcoin address.",
+ "vanityprivatekeyonlyavailable": "Only available when combining two private keys",
+ "vanityalertinvalidinputprivatekeysmatch": "Invalid input. The Private Key of both entries match. You must input two different keys."
+ },
+
+ "es": {
+ // javascript alerts or messages
+ "testneteditionactivated": "Testnet se activa",
+ "paperlabelbitcoinaddress": "Dirección Bitcoin:",
+ "paperlabelprivatekey": "Clave privada (formato para importar):",
+ "bulkgeneratingaddresses": "Generación de direcciones... ",
+ "brainalertpassphrasetooshort": "La contraseña introducida es demasiado corta.\n\nAviso: Es importante escoger una contraseña fuerte para evitar ataques de fuerza bruta a fin de adivinarla y robar tus bitcoins.",
+ "brainalertpassphrasedoesnotmatch": "Las contraseñas no coinciden.",
+ "detailalertnotvalidprivatekey": "El texto que has introducido no es una clave privada válida",
+ "detailconfirmsha256": "El texto que has introducido no es una clave privada válida\n\n¿Quieres usar ese texto como si fuera una contraseña y generar una clave privada usando un hash SHA256 de tal contraseña?\n\nAviso: Es importante escoger una contraseña fuerte para evitar ataques de fuerza bruta a fin de adivinarla y robar tus bitcoins.",
+ "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.", //TODO: please translate
+ "bip38alertpassphraserequired": "Passphrase required for BIP38 key", //TODO: please translate
+ "vanityinvalidinputcouldnotcombinekeys": "Entrada no válida. No se puede combinar llaves.",
+ "vanityalertinvalidinputpublickeysmatch": "Entrada no válida. La clave pública de ambos coincidan entradas. Debe introducir dos claves diferentes.",
+ "vanityalertinvalidinputcannotmultiple": "Entrada no válida. No se puede multiplicar dos claves públicas. Seleccione 'Añadir' para agregar dos claves públicas para obtener una dirección bitcoin.",
+ "vanityprivatekeyonlyavailable": "Sólo está disponible cuando se combinan dos claves privadas",
+ "vanityalertinvalidinputprivatekeysmatch": "Entrada no válida. La clave privada de ambos coincidan entradas. Debe introducir dos claves diferentes.",
+
+ // header and menu html
+ "tagline": "Generador de carteras Bitcoin de código abierto en lado de cliente con Javascript",
+ "generatelabelbitcoinaddress": "Generando dirección Bitcoin...",
+ "generatelabelmovemouse": "Mueve un poco el ratón para crear entropía...",
+ "singlewallet": "Una sola cartera",
+ "paperwallet": "Cartera en papel",
+ "bulkwallet": "Direcciones en masa",
+ "brainwallet": "Cartera mental",
+ "vanitywallet": "Cartera personalizada",
+ "detailwallet": "Detalles de la cartera",
+
+ // footer html
+ "footerlabeldonations": "Donaciones:",
+ "footerlabeltranslatedby": "Traducción: 12345Vypv2QSmuRXcciT5oEB27mPbWGeva",
+ "footerlabelpgp": "Clave pública PGP",
+ "footerlabelversion": "Histórico de versiones",
+ "footerlabelgithub": "Repositorio GitHub",
+ "footerlabelcopyright1": "Copyright bitaddress.org.",
+ "footerlabelcopyright2": "Copyright del código JavaScript: en el fuente.",
+ "footerlabelnowarranty": "Sin garantía.",
+
+ // single wallet html
+ "newaddress": "Generar dirección",
+ "singleprint": "Imprimir",
+ "singlelabelbitcoinaddress": "Dirección Bitcoin",
+ "singlelabelprivatekey": "Clave privada (formato para importar):",
+
+ // paper wallet html
+ "paperlabelhideart": "Ocultar diseño",
+ "paperlabeladdressesperpage": "Direcciones por página:",
+ "paperlabeladdressestogenerate": "Direcciones en total:",
+ "papergenerate": "Generar",
+ "paperprint": "Imprimir",
+
+ // bulk wallet html
+ "bulklabelstartindex": "Empezar en:",
+ "bulklabelrowstogenerate": "Filas a generar:",
+ "bulklabelcompressed": "Compressed addresses?", //TODO: please translate
+ "bulkgenerate": "Generar",
+ "bulkprint": "Imprimir",
+ "bulklabelcsv": "Valores separados por coma:",
+ "bulklabelformat": "Índice,Dirección,Clave privada (formato para importar)",
+ "bulklabelq1": "¿Por qué debo usar \"Direcciones en masa\" para aceptar Bitcoins en mi web?",
+ "bulka1": "La forma tradicional de aceptar bitcoins en tu web requiere tener instalado el cliente oficial de bitcoin (\"bitcoind\"). Sin embargo muchos servicios de hosting no permiten instalar dicho cliente. Además, ejecutar el cliente en tu servidor supone que las claves privadas están también en el servidor y podrían ser comprometidas en caso de intrusión. Al usar este mecanismo, puedes subir al servidor sólo las dirección de bitcoin y no las claves privadas. De esta forma no te tienes que preocupar de que alguien robe la cartera si se cuelan en el servidor.",
+ "bulklabelq2": "¿Cómo uso \"Direcciones en masa\" para aceptar bitcoins en mi web?",
+ "bulklabela2li1": "Usa el tab \"Direcciones en masa\" para generar por anticipado muchas direcciones (más de 10000). Copia y pega la lista de valores separados por comas (CSV) a un archivo de texto seguro (cifrado) en tu ordenador. Guarda una copia de seguridad en algún lugar seguro.",
+ "bulklabela2li2": "Importa las direcciones en la base de datos de tu servidor. No subas la cartera ni las claves públicas, o de lo contrario te lo pueden robar. Sube sólo las direcciones, ya que es lo que se va a mostrar a los clientes.",
+ "bulklabela2li3": "Ofrece una alternativa en el carro de la compra de tu web para que los clientes paguen con Bitcoin. Cuando el cliente elija pagar con Bitcoin, les muestras una de las direcciones de la base de datos como su \"dirección de pago\" y guardas esto junto con el pedido.",
+ "bulklabela2li4": "Ahora te hace falta recibir una notificación del pago. Busca en google \"notificación de pagos bitcoin\" (o \"bitcoin payment notification\" en inglés) y suscríbete a alguno de los servicios que aparezcan. Hay varios de ellos, que te pueden notificar vía Web services, API, SMS, email, etc. Una vez te llegue la notificación, lo cual puede ser automatizado, entonces ya puedes procesar el pedido. Para comprobar a mano si has recibido un pago, puedes usar Block Explorer: reemplaza DIRECCION a continuación por la dirección que estés comprobando. La transacción puede tardar entre 10 minutos y una hora en ser confirmada. http://www.blockexplorer.com/address/DIRECCION
Puedes ver las transacciones sin confirmar en: http://blockchain.info/ Las transacciones sin confirmar suelen aparecer ahí en unos 30 segundos.",
+ "bulklabela2li5": "Las bitcoins que recibas se almacenarán de forma segura en la cadena de bloques. Usa la cartera original que generaste en el paso 1 para usarlas.",
+
+ // brain wallet html
+ "brainlabelenterpassphrase": "Contraseña:",
+ "brainlabelshow": "Mostrar",
+ "brainprint": "Imprimir",
+ "brainlabelconfirm": "Confirmar contraseña:",
+ "brainview": "Ver",
+ "brainalgorithm": "Algoritmo: SHA256(contraseña)",
+ "brainlabelbitcoinaddress": "Dirección Bitcoin:",
+ "brainlabelprivatekey": "Clave privada (formato para importar):",
+
+ // vanity wallet html
+ "vanitylabelstep1": "Paso 1 - Genera tu par de claves",
+ "vanitynewkeypair": "Generar",
+ "vanitylabelstep1publickey": "Clave pública:",
+ "vanitylabelstep1pubnotes": "Copia y pega la línea de arriba en el campo \"Your-Part-Public-Key\" de la web de Vanity Pool.",
+ "vanitylabelstep1privatekey": "Clave privada:",
+ "vanitylabelstep1privnotes": "Copia y pega la clave pública de arriba en un archivo de texto. Es mejor que lo almacenes en un volumen cifrado. Lo necesitarás para recuperar la clave privada una vez Vanity Pool haya encontrado tu prefijo.",
+ "vanitylabelstep2calculateyourvanitywallet": "Paso 2 - Calcula tu cartera personalizada",
+ "vanitylabelenteryourpart": "Introduce la clave privada generada en el paso 1, y que has guardado:",
+ "vanitylabelenteryourpoolpart": "Introduce la clave privada obtenida de la Vanity Pool:",
+ "vanitylabelnote1": "[NOTA: esta casilla de entrada puede aceptar una clave pública o clave privada]",
+ "vanitylabelnote2": "[NOTA: esta casilla de entrada puede aceptar una clave pública o clave privada]",
+ "vanitylabelradioadd": "Añadir",
+ "vanitylabelradiomultiply": "Multiplicar",
+ "vanitycalc": "Calcular cartera personalizada",
+ "vanitylabelbitcoinaddress": "Dirección Bitcoin personalizada:",
+ "vanitylabelnotesbitcoinaddress": "Esta es tu nueva dirección, que debería tener el prefijo deseado.",
+ "vanitylabelpublickeyhex": "Clave pública personalizada (HEX):",
+ "vanitylabelnotespublickeyhex": "Lo anterior es la clave pública en formato hexadecimal.",
+ "vanitylabelprivatekey": "Clave privada personalizada (formato para importar):",
+ "vanitylabelnotesprivatekey": "Esto es la clave privada para introducir en tu cartera.",
+
+ // detail wallet html
+ "detaillabelenterprivatekey": "Introduce la clave privada (en cualquier formato)",
+ "detailview": "Ver detalles",
+ "detailprint": "Imprimir",
+ "detaillabelnote1": "Tu clave privada es un número secreto, único, que sólo tú conoces. Se puede expresar en varios formatos. Aquí abajo mostramos la dirección y la clave pública que se corresponden con tu clave privada, así como la clave privada en los formatos más conocidos (para importar, hex, base64 y mini).",
+ "detaillabelnote2": "Bitcoin v0.6+ almacena las claves públicas comprimidas. El cliente también soporta importar/exportar claves privadas usando importprivkey/dumpprivkey. El formato de las claves privadas exportadas depende de si la dirección se generó en una cartera antigua o nueva.",
+ "detaillabelbitcoinaddress": "Dirección Bitcoin:",
+ "detaillabelbitcoinaddresscomp": "Dirección Bitcoin (comprimida):",
+ "detaillabelpublickey": "Clave pública (130 caracteres [0-9A-F]):",
+ "detaillabelpublickeycomp": "Clave pública (comprimida, 66 caracteres [0-9A-F]):",
+ "detaillabelprivwif": "Clave privada para importar (51 caracteres en base58, empieza con un",
+ "detaillabelprivwifcomp": "Clave privada para importar (comprimida, 52 caracteres en base58, empieza con",
+ "detailcompwifprefix": "'K' o 'L'",
+ "detaillabelprivhex": "Clave privada en formato hexadecimal (64 caracteres [0-9A-F]):",
+ "detaillabelprivb64": "Clave privada en base64 (44 caracteres):",
+ "detaillabelprivmini": "Clave privada en formato mini (22, 26 o 30 caracteres, empieza por 'S'):",
+ "detaillabelpassphrase": "BIP38 Passphrase", //TODO: please translate
+ "detaildecrypt": "Decrypt BIP38" //TODO: please translate
+ },
+
+ "fr": {
+ "testneteditionactivated": "ÉDITION TESTNET ACTIVÉE",
+ "paperlabelbitcoinaddress": "Adresse Bitcoin:",
+ "paperlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
+ "bulkgeneratingaddresses": "Création de l'adresse... ",
+ "brainalertpassphrasetooshort": "Le mot de passe que vous avez entré est trop court.\n\nAttention: Choisir un mot de passe solide est important pour vous protéger des attaques bruteforce visant à trouver votre mot de passe et voler vos Bitcoins.",
+ "brainalertpassphrasedoesnotmatch": "Le mot de passe ne correspond pas au mot de passe de vérification.",
+ "detailalertnotvalidprivatekey": "Le texte que vous avez entré n'est pas une Clé Privée valide",
+ "detailconfirmsha256": "Le texte que vous avez entré n'est pas une Clé Privée valide!\n\nVoulez-vous utiliser le texte comme un mot de passe et créer une Clé Privée à partir d'un hash SHA256 de ce mot de passe?\n\nAttention: Choisir un mot de passe solide est important pour vous protéger des attaques bruteforce visant à trouver votre mot de passe et voler vos Bitcoins.",
+ "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.", //TODO: please translate
+ "bip38alertpassphraserequired": "Passphrase required for BIP38 key", //TODO: please translate
+ "vanityinvalidinputcouldnotcombinekeys": "Entrée non valide. Impossible de combiner les clés.",
+ "vanityalertinvalidinputpublickeysmatch": "Entrée non valide. La clé publique des deux entrées est identique. Vous devez entrer deux clés différentes.",
+ "vanityalertinvalidinputcannotmultiple": "Entrée non valide. Il n'est pas possible de multiplier deux clés publiques. Sélectionner 'Ajouter' pour ajouter deux clés publiques pour obtenir une adresse Bitcoin.",
+ "vanityprivatekeyonlyavailable": "Seulement disponible si vos combinez deux clés privées",
+ "vanityalertinvalidinputprivatekeysmatch": "Entrée non valide. La clé Privée des deux entrées est identique. Vous devez entrer deux clés différentes.",
+ "tagline": "Générateur De Porte-Monnaie Bitcoin Javascript Hors-Ligne",
+ "generatelabelbitcoinaddress": "Création de l'adresse Bitcoin...",
+ "generatelabelmovemouse": "BOUGEZ votre souris pour ajouter de l'entropie...",
+ "singlewallet": "Porte-Monnaie Simple",
+ "paperwallet": "Porte-Monnaie Papier",
+ "bulkwallet": "Porte-Monnaie En Vrac",
+ "brainwallet": "Porte-Monnaie Cerveau",
+ "vanitywallet": "Porte-Monnaie Vanité",
+ "detailwallet": "Détails du Porte-Monnaie",
+ "footerlabeldonations": "Dons:",
+ "footerlabeltranslatedby": "Traduction: 1Gy7NYSJNUYqUdXTBow5d7bCUEJkUFDFSq",
+ "footerlabelpgp": "Clé Publique PGP",
+ "footerlabelversion": "Historique De Version Signé",
+ "footerlabelgithub": "Dépôt GitHub",
+ "footerlabelcopyright1": "Copyright bitaddress.org.",
+ "footerlabelcopyright2": "Les droits d'auteurs JavaScript sont inclus dans le code source.",
+ "footerlabelnowarranty": "Aucune garantie.",
+ "newaddress": "Générer Une Nouvelle Adresse",
+ "singleprint": "Imprimer",
+ "singlelabelbitcoinaddress": "Adresse Bitcoin:",
+ "singlelabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
+ "paperlabelhideart": "Retirer Le Style?",
+ "paperlabeladdressesperpage": "Adresses par page:",
+ "paperlabeladdressestogenerate": "Nombre d'adresses à créer:",
+ "papergenerate": "Générer",
+ "paperprint": "Imprimer",
+ "bulklabelstartindex": "Commencer à l'index:",
+ "bulklabelrowstogenerate": "Colonnes à générer:",
+ "bulklabelcompressed": "Compressed addresses?", //TODO: please translate
+ "bulkgenerate": "Générer",
+ "bulkprint": "Imprimer",
+ "bulklabelcsv": "Valeurs Séparées Par Des Virgules (CSV):",
+ "bulklabelformat": "Index,Adresse,Clé Privée (WIF)",
+ "bulklabelq1": "Pourquoi utiliserais-je un Porte-monnaie en vrac pour accepter les Bitcoins sur mon site web?",
+ "bulka1": "L'approche traditionnelle pour accepter des Bitcoins sur votre site web requière l'installation du logiciel Bitcoin officiel (\"bitcoind\"). Plusieurs hébergeurs ne supportent pas l'installation du logiciel Bitcoin. De plus, faire fonctionner le logiciel Bitcoin sur votre serveur web signifie que vos clés privées sont hébergées sur le serveur et pourraient donc être volées si votre serveur web était compromis. En utilisant un Porte-monnaie en vrac, vous pouvez publiquer seulement les adresses Bitcoin sur votre serveur et non les clés privées. Vous n'avez alors pas à vous inquiéter du risque de vous faire voler votre porte-monnaie si votre serveur était compromis.",
+ "bulklabelq2": "Comment utiliser le Porte-monnaie en vrac pour utiliser le Bitcoin sur mon site web?",
+ "bulklabela2li1": "Utilisez le Porte-monnaie en vrac pour pré-générer une large quantité d'adresses Bitcoin (10,000+). Copiez collez les données séparées par des virgules (CSV) dans un fichier texte sécurisé dans votre ordinateur. Sauvegardez ce fichier dans un endroit sécurisé.",
+ "bulklabela2li2": "Importez les adresses Bitcoin dans une base de donnée sur votre serveur web. (N'ajoutez pas le porte-monnaie ou les clés privées sur votre serveur web, sinon vous courrez le risque de vous faire voler si votre serveur est compromis. Ajoutez seulement les adresses Bitcoin qui seront visibles à vos visiteurs.)",
+ "bulklabela2li3": "Ajoutez une option dans votre panier en ligne pour que vos clients puissent vous payer en Bitcoin. Quand un client choisi de vous payer en Bitcoin, vous pouvez afficher une des adresses de votre base de donnée comme \"adresse de paiment\" pour votre client et sauvegarder cette adresse avec sa commande.",
+ "bulklabela2li4": "Vous avez maintenant besoin d'être avisé quand le paiement est reçu. Cherchez \"bitcoin payment notification\" sur Google et inscrivez-vous à un service de notification de paiement Bitcoin. Il y a plusieurs services qui vous avertiront via des services Web, API, SMS, Email, etc. Une fois que vous avez reçu la notification, qui devrait être programmée automatiquement, vous pouvez traiter la commande de votre client. Pour vérifier manuellement si un paiement est arrivé, vous pouvez utiliser Block Explorer. Remplacez ADRESSE par l'adresse Bitcoin que vous souhaitez vérifier. La confirmation de la transaction pourrait prendre de 10 à 60 minutes pour être confirmée. http://www.blockexplorer.com/address/ADRESSE
Les transactions non confirmées peuvent être visualisées ici: http://blockchain.info/ Vous devriez voir la transaction à l'intérieur de 30 secondes.",
+ "bulklabela2li5": "Les Bitcoins vos s'accumuler de façon sécuritaire dans la chaîne de blocs. Utilisez le porte-monnaie original que vous avez généré à l'étape 1 pour les dépenser.",
+ "brainlabelenterpassphrase": "Entrez votre mot de passe: ",
+ "brainlabelshow": "Afficher?",
+ "brainprint": "Imprimer",
+ "brainlabelconfirm": "Confirmer le mot de passe: ",
+ "brainview": "Visualiser",
+ "brainalgorithm": "Algorithme: SHA256(mot de passe)",
+ "brainlabelbitcoinaddress": "Adresse Bitcoin:",
+ "brainlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
+ "vanitylabelstep1": "Étape 1 - Générer votre \"Étape 1 Paire De Clés\"",
+ "vanitynewkeypair": "Générer",
+ "vanitylabelstep1publickey": "Étape 1 Clé Publique:",
+ "vanitylabelstep1pubnotes": "Copiez celle-ci dans la case Votre-Clé-Publique du site de Vanity Pool.",
+ "vanitylabelstep1privatekey": "Step 1 Clé Privée:",
+ "vanitylabelstep1privnotes": "Copiez la cette Clé Privée dans un fichier texte. Idéalement, sauvegardez la dans un fichier encrypté. Vous en aurez besoin pour récupérer la Clé Privée lors que Vanity Pool aura trouvé votre préfixe.",
+ "vanitylabelstep2calculateyourvanitywallet": "Étape 2 - Calculer votre Porte-monnaie Vanité",
+ "vanitylabelenteryourpart": "Entrez votre Clé Privée (générée à l'étape 1 plus haut et précédemment sauvegardée):",
+ "vanitylabelenteryourpoolpart": "Entrez la Clé Privée (provenant de Vanity Pool):",
+ "vanitylabelnote1": "[NOTE: cette case peut accepter une clé publique ou un clé privée]",
+ "vanitylabelnote2": "[NOTE: cette case peut accepter une clé publique ou un clé privée]",
+ "vanitylabelradioadd": "Ajouter",
+ "vanitylabelradiomultiply": "Multiplier",
+ "vanitycalc": "Calculer Le Porte-monnaie Vanité",
+ "vanitylabelbitcoinaddress": "Adresse Bitcoin Vanité:",
+ "vanitylabelnotesbitcoinaddress": "Ci-haut est votre nouvelle adresse qui devrait inclure le préfix requis.",
+ "vanitylabelpublickeyhex": "Clé Public Vanité (HEX):",
+ "vanitylabelnotespublickeyhex": "Celle-ci est la Clé Publique dans le format hexadécimal. ",
+ "vanitylabelprivatekey": "Clé Privée Vanité (WIF):",
+ "vanitylabelnotesprivatekey": "Celle-ci est la Clé Privée pour accéder à votre porte-monnaie. ",
+ "detaillabelenterprivatekey": "Entrez la Clé Privée (quel que soit son format)",
+ "detailview": "Voir les détails",
+ "detailprint": "Imprimer",
+ "detaillabelnote1": "Votre Clé Privée Bitcoin est un nombre secret que vous êtes le seul à connaître. Il peut être encodé sous la forme d'un nombre sous différents formats. Ci-bas, nous affichons l'adresse Bitcoin et la Clé Publique qui corresponds à la Clé Privée ainsi que la Clé Privée dans les formats d'encodage les plus populaires (WIF, HEX, B64, MINI).",
+ "detaillabelnote2": "Bitcoin v0.6+ conserve les clés publiques dans un format compressé. Le logiciel supporte maintenant aussi l'importation et l'exportation de clés privées avec importprivkey/dumpprivkey. Le format de la clé privée exportée est déterminé selon la version du porte-monnaie Bitcoin.",
+ "detaillabelbitcoinaddress": "Adresse Bitcoin:",
+ "detaillabelbitcoinaddresscomp": "Adresse Bitcoin (compressée):",
+ "detaillabelpublickey": "Clé Publique (130 caractères [0-9A-F]):",
+ "detaillabelpublickeycomp": "Clé Publique (compressée, 66 caractères [0-9A-F]):",
+ "detaillabelprivwif": "Clé Privée WIF (51 caractères base58, débute avec un a",
+ "detaillabelprivwifcomp": "Clé Privée WIF (compressée, 52 caractères base58, débute avec un a",
+ "detailcompwifprefix": "'K' ou 'L'",
+ "detaillabelprivhex": "Clé Privée Format Hexadecimal (64 caractères [0-9A-F]):",
+ "detaillabelprivb64": "Clé Privée Base64 (44 caractères):",
+ "detaillabelprivmini": "Clé Privée Format Mini (22, 26 ou 30 caractères, débute avec un 'S'):",
+ "detaillabelpassphrase": "BIP38 Passphrase", //TODO: please translate
+ "detaildecrypt": "Decrypt BIP38" //TODO: please translate
+ }
+ }
+};
+
+ninja.translator.showEnglishJson = function () {
+ var english = ninja.translator.translations["en"];
+ var spanish = ninja.translator.translations["es"];
+ var spanishClone = {};
+ for (var key in spanish) {
+ spanishClone[key] = spanish[key];
+ }
+ var newLang = {};
+ for (var key in english) {
+ newLang[key] = english[key];
+ delete spanishClone[key];
+ }
+ for (var key in spanishClone) {
+ if (document.getElementById(key)) {
+ if (document.getElementById(key).value) {
+ newLang[key] = document.getElementById(key).value;
+ }
+ else {
+ newLang[key] = document.getElementById(key).innerHTML;
+ }
+ }
+ }
+ var div = document.createElement("div");
+ div.setAttribute("class", "englishjson");
+ div.innerHTML = "
English Json
";
+ var elem = document.createElement("textarea");
+ elem.setAttribute("rows", "35");
+ elem.setAttribute("cols", "110");
+ elem.setAttribute("wrap", "off");
+ var langJson = "{\n";
+ for (var key in newLang) {
+ langJson += "\t\"" + key + "\"" + ": " + "\"" + newLang[key].replace(/\"/g, "\\\"").replace(/\n/g, "\\n") + "\",\n";
+ }
+ langJson = langJson.substr(0, langJson.length - 2);
+ langJson += "\n}\n";
+ elem.innerHTML = langJson;
+ div.appendChild(elem);
+ document.body.appendChild(div);
+};
\ No newline at end of file
diff --git a/src/ninja.unittests.js b/src/ninja.unittests.js
new file mode 100644
index 0000000..65db589
--- /dev/null
+++ b/src/ninja.unittests.js
@@ -0,0 +1,502 @@
+(function (ninja) {
+ var ut = ninja.unitTests = {
+ runSynchronousTests: function () {
+ document.getElementById("busyblock").className = "busy";
+ var div = document.createElement("div");
+ div.setAttribute("class", "unittests");
+ div.setAttribute("id", "unittests");
+ var testResults = "";
+ var passCount = 0;
+ var testCount = 0;
+ for (var test in ut.synchronousTests) {
+ var exceptionMsg = "";
+ var resultBool = false;
+ try {
+ resultBool = ut.synchronousTests[test]();
+ } catch (ex) {
+ exceptionMsg = ex.toString();
+ resultBool = false;
+ }
+ if (resultBool == true) {
+ var passFailStr = "pass";
+ passCount++;
+ }
+ else {
+ var passFailStr = "FAIL " + exceptionMsg + "";
+ }
+ testCount++;
+ testResults += test + ": " + passFailStr + " ";
+ }
+ testResults += passCount + " of " + testCount + " synchronous tests passed";
+ if (passCount < testCount) {
+ testResults += "" + (testCount - passCount) + " unit test(s) failed";
+ }
+ div.innerHTML = "
Unit Tests
" + testResults + "
";
+ document.body.appendChild(div);
+ document.getElementById("busyblock").className = "";
+
+ },
+
+ runAsynchronousTests: function () {
+ document.getElementById("busyblock").className = "busy";
+ // run the asynchronous tests one after another so we don't crash the browser
+ ninja.foreachSerialized(ninja.unitTests.asynchronousTests, function (name, cb) {
+ ninja.unitTests.asynchronousTests[name](cb);
+ }, function () {
+ document.getElementById("unittestresults").innerHTML += "running of asynchronous unit tests complete! ";
+ document.getElementById("busyblock").className = "";
+ });
+ },
+
+ synchronousTests: {
+ //ninja.publicKey tests
+ testIsPublicKeyHexFormat: function () {
+ var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var bool = ninja.publicKey.isPublicKeyHexFormat(key);
+ if (bool != true) {
+ return false;
+ }
+ return true;
+ },
+ testGetHexFromByteArray: function () {
+ var bytes = [4, 120, 152, 47, 64, 250, 12, 11, 122, 85, 113, 117, 131, 175, 201, 154, 78, 223, 211, 1, 162, 114, 157, 197, 155, 11, 142, 185, 225, 134, 146, 188, 181, 33, 240, 84, 250, 217, 130, 175, 76, 193, 147, 58, 253, 31, 27, 86, 62, 167, 121, 166, 170, 108, 206, 54, 163, 11, 148, 125, 214, 83, 230, 62, 68];
+ var key = ninja.publicKey.getHexFromByteArray(bytes);
+ if (key != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44") {
+ return false;
+ }
+ return true;
+ },
+ testHexToBytes: function () {
+ var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var bytes = Crypto.util.hexToBytes(key);
+ if (bytes.toString() != "4,120,152,47,64,250,12,11,122,85,113,117,131,175,201,154,78,223,211,1,162,114,157,197,155,11,142,185,225,134,146,188,181,33,240,84,250,217,130,175,76,193,147,58,253,31,27,86,62,167,121,166,170,108,206,54,163,11,148,125,214,83,230,62,68") {
+ return false;
+ }
+ return true;
+ },
+ testGetBitcoinAddressFromByteArray: function () {
+ var bytes = [4, 120, 152, 47, 64, 250, 12, 11, 122, 85, 113, 117, 131, 175, 201, 154, 78, 223, 211, 1, 162, 114, 157, 197, 155, 11, 142, 185, 225, 134, 146, 188, 181, 33, 240, 84, 250, 217, 130, 175, 76, 193, 147, 58, 253, 31, 27, 86, 62, 167, 121, 166, 170, 108, 206, 54, 163, 11, 148, 125, 214, 83, 230, 62, 68];
+ var address = ninja.publicKey.getBitcoinAddressFromByteArray(bytes);
+ if (address != "1Cnz9ULjzBPYhDw1J8bpczDWCEXnC9HuU1") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromAdding: function () {
+ var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var key2 = "0419153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C0159DC0099AD54F733812892EB9A11A8C816A201B3BAF0D97117EBA2033C9AB2";
+ var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
+ if (bytes.toString() != "4,151,19,227,152,54,37,184,255,4,83,115,216,102,189,76,82,170,57,4,196,253,2,41,74,6,226,33,167,199,250,74,235,223,128,233,99,150,147,92,57,39,208,84,196,71,68,248,166,106,138,95,172,253,224,70,187,65,62,92,81,38,253,79,0") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromAddingCompressed: function () {
+ var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
+ var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
+ var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
+ var hex = ninja.publicKey.getHexFromByteArray(bytes);
+ if (hex != "029713E3983625B8FF045373D866BD4C52AA3904C4FD02294A06E221A7C7FA4AEB") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromAddingUncompressedAndCompressed: function () {
+ var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
+ var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
+ if (bytes.toString() != "4,151,19,227,152,54,37,184,255,4,83,115,216,102,189,76,82,170,57,4,196,253,2,41,74,6,226,33,167,199,250,74,235,223,128,233,99,150,147,92,57,39,208,84,196,71,68,248,166,106,138,95,172,253,224,70,187,65,62,92,81,38,253,79,0") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromAddingShouldReturnNullWhenSameKey1: function () {
+ var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var key2 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
+ if (bytes != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromAddingShouldReturnNullWhenSameKey2: function () {
+ var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var key2 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
+ var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
+ if (bytes != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromMultiplying: function () {
+ var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
+ if (bytes.toString() != "4,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57,115,35,54,105,7,180,5,106,217,57,229,127,174,145,215,79,121,163,191,211,143,215,50,48,156,211,178,72,226,68,150,52") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromMultiplyingCompressedOutputsUncompressed: function () {
+ var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
+ var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
+ if (bytes.toString() != "4,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57,115,35,54,105,7,180,5,106,217,57,229,127,174,145,215,79,121,163,191,211,143,215,50,48,156,211,178,72,226,68,150,52") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromMultiplyingCompressedOutputsCompressed: function () {
+ var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
+ var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
+ var ecKey = new Bitcoin.ECKey(key2);
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, ecKey);
+ if (bytes.toString() != "2,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57") {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey1: function () {
+ var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
+ var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
+ if (bytes != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey2: function () {
+ var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
+ var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
+ if (bytes != null) {
+ return false;
+ }
+ return true;
+ },
+ // confirms multiplication is working and BigInteger was created correctly (Pub Key B vs Priv Key A)
+ testGetPubHexFromMultiplyingPrivAPubB: function () {
+ var keyPub = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
+ var keyPriv = "B1202A137E917536B3B4C5010C3FF5DDD4784917B3EEF21D3A3BF21B2E03310C";
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
+ var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
+ if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
+ return false;
+ }
+ return true;
+ },
+ // confirms multiplication is working and BigInteger was created correctly (Pub Key A vs Priv Key B)
+ testGetPubHexFromMultiplyingPrivBPubA: function () {
+ var keyPub = "0429BF26C0AF7D31D608474CEBD49DA6E7C541B8FAD95404B897643476CE621CFD05E24F7AE8DE8033AADE5857DB837E0B704A31FDDFE574F6ECA879643A0D3709";
+ var keyPriv = "7DE52819F1553C2BFEDE6A2628B6FDDF03C2A07EB21CF77ACA6C2C3D252E1FD9";
+ var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
+ var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
+ if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
+ return false;
+ }
+ return true;
+ },
+
+ // Private Key tests
+ testBadKeyIsNotWif: function () {
+ return !(Bitcoin.ECKey.isWalletImportFormat("bad key"));
+ },
+ testBadKeyIsNotWifCompressed: function () {
+ return !(Bitcoin.ECKey.isCompressedWalletImportFormat("bad key"));
+ },
+ testBadKeyIsNotHex: function () {
+ return !(Bitcoin.ECKey.isHexFormat("bad key"));
+ },
+ testBadKeyIsNotBase64: function () {
+ return !(Bitcoin.ECKey.isBase64Format("bad key"));
+ },
+ testBadKeyIsNotMini: function () {
+ return !(Bitcoin.ECKey.isMiniFormat("bad key"));
+ },
+ testBadKeyReturnsNullPrivFromECKey: function () {
+ var key = "bad key";
+ var ecKey = new Bitcoin.ECKey(key);
+ if (ecKey.priv != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetBitcoinPrivateKeyByteArray: function () {
+ var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var bytes = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinPrivateKeyByteArray().toString() != bytes.toString()) {
+ return false;
+ }
+ return true;
+ },
+ testECKeyDecodeWalletImportFormat: function () {
+ var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var bytes1 = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
+ var bytes2 = Bitcoin.ECKey.decodeWalletImportFormat(key);
+ if (bytes1.toString() != bytes2.toString()) {
+ return false;
+ }
+ return true;
+ },
+ testECKeyDecodeCompressedWalletImportFormat: function () {
+ var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var bytes1 = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
+ var bytes2 = Bitcoin.ECKey.decodeCompressedWalletImportFormat(key);
+ if (bytes1.toString() != bytes2.toString()) {
+ return false;
+ }
+ return true;
+ },
+ testWifToPubKeyHex: function () {
+ var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getPubKeyHex() != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44"
+ || btcKey.getPubPoint().compressed != false) {
+ return false;
+ }
+ return true;
+ },
+ testWifToPubKeyHexCompressed: function () {
+ var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var btcKey = new Bitcoin.ECKey(key);
+ btcKey.setCompressed(true);
+ if (btcKey.getPubKeyHex() != "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5"
+ || btcKey.getPubPoint().compressed != true) {
+ return false;
+ }
+ return true;
+ },
+ testBase64ToECKey: function () {
+ var key = "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinBase64Format() != "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=") {
+ return false;
+ }
+ return true;
+ },
+ testHexToECKey: function () {
+ var key = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinHexFormat() != "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B") {
+ return false;
+ }
+ return true;
+ },
+ testCompressedWifToECKey: function () {
+ var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinWalletImportFormat() != "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S"
+ || btcKey.getPubPoint().compressed != true) {
+ return false;
+ }
+ return true;
+ },
+ testWifToECKey: function () {
+ var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
+ return false;
+ }
+ return true;
+ },
+ testBrainToECKey: function () {
+ var key = "bitaddress.org unit test";
+ var bytes = Crypto.SHA256(key, { asBytes: true });
+ var btcKey = new Bitcoin.ECKey(bytes);
+ if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
+ return false;
+ }
+ return true;
+ },
+ testMini30CharsToECKey: function () {
+ var key = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinWalletImportFormat() != "5JrBLQseeZdYw4jWEAHmNxGMr5fxh9NJU3fUwnv4khfKcg2rJVh") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromAdding: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
+ var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
+ if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromAddingCompressed: function () {
+ var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
+ var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
+ if (ecKey.getBitcoinWalletImportFormat() != "L3A43j2pc2J8F2SjBNbYprPrcDpDCh8Aju8dUH65BEM2r7RFSLv4") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromAddingUncompressedAndCompressed: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
+ var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
+ if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromAddingShouldReturnNullWhenSameKey1: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
+ if (ecKey != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromAddingShouldReturnNullWhenSameKey2: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
+ if (ecKey != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromMultiplying: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
+ var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
+ if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromMultiplyingCompressed: function () {
+ var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
+ var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
+ if (ecKey.getBitcoinWalletImportFormat() != "L5LFitc24jme2PfVChJS3bKuQAPBp54euuqLWciQdF2CxnaU3M8t") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromMultiplyingUncompressedAndCompressed: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
+ var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
+ if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey1: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
+ if (ecKey != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey2: function () {
+ var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
+ var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
+ var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
+ if (ecKey != null) {
+ return false;
+ }
+ return true;
+ },
+ testGetECKeyFromBase6Key: function () {
+ var base = 6;
+ var baseKey = "100531114202410255230521444145414341221420541210522412225005202300434134213212540304311321323051431";
+ var hexKey = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
+ var bigInt = new BigInteger(baseKey, base);
+ var ecKey = new Bitcoin.ECKey(bigInt);
+ if (ecKey.getBitcoinHexFormat() != hexKey) {
+ return false;
+ }
+ return true;
+ },
+
+ // EllipticCurve tests
+ testDecodePointEqualsDecodeFrom: function () {
+ var key = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
+ var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
+ var ecPoint1 = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), Crypto.util.hexToBytes(key));
+ var ecPoint2 = ecparams.getCurve().decodePointHex(key);
+ if (!ecPoint1.equals(ecPoint2)) {
+ return false;
+ }
+ return true;
+ },
+ testDecodePointHexForCompressedPublicKey: function () {
+ var key = "03F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F989380";
+ var pubHexUncompressed = ninja.publicKey.getDecompressedPubKeyHex(key);
+ if (pubHexUncompressed != "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF") {
+ return false;
+ }
+ return true;
+ },
+ // old bugs
+ testBugWithLeadingZeroBytePublicKey: function () {
+ var key = "5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinAddress() != "1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E") {
+ return false;
+ }
+ return true;
+ },
+ testBugWithLeadingZeroBytePrivateKey: function () {
+ var key = "0004d30da67214fa65a41a6493576944c7ea86713b14db437446c7a8df8e13da";
+ var btcKey = new Bitcoin.ECKey(key);
+ if (btcKey.getBitcoinAddress() != "1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn") {
+ return false;
+ }
+ return true;
+ }
+ },
+
+ asynchronousTests: {
+ testBip38: function (done) {
+ var tests = [["6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg", "TestingOneTwoThree", "5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR"],
+ ["6PRNFFkZc2NZ6dJqFfhRoFNMR9Lnyj7dYGrzdgXXVMXcxoKTePPX1dWByq", "Satoshi", "5HtasZ6ofTHP6HCwTqTkLDuLQisYPah7aUnSKfC7h4hMUVw2gi5"],
+ ["6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo", "TestingOneTwoThree", "L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP"],
+ ["6PYLtMnXvfG3oJde97zRyLYFZCYizPU5T3LwgdYJz1fRhh16bU7u6PPmY7", "Satoshi", "KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7"],
+ ["6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX", "TestingOneTwoThree", "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2"],
+ ["6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd", "Satoshi", "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH"],
+ ["6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j", "MOLON LABE", "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8"],
+ ["6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH", Crypto.charenc.UTF8.bytesToString([206, 156, 206, 159, 206, 155, 206, 169, 206, 157, 32, 206, 155, 206, 145, 206, 146, 206, 149])/*UTF-8 characters, encoded in source so they don't get corrupted*/, "5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D"]];
+ // running each test uses a lot of memory, which isn't freed
+ // immediately, so give the VM a little time to reclaim memory
+ function waitThenCall(callback) {
+ return function () { setTimeout(callback, 6000); }
+ }
+
+ var decryptTest = function (test, i, onComplete) {
+ ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(test[0], test[1], function (privBytes) {
+ if (privBytes.constructor == Error) {
+ document.getElementById("unittestresults").innerHTML += "fail testDecryptBip38 #" + i + ", error: " + privBytes.message + " ";
+ } else {
+ var btcKey = new Bitcoin.ECKey(privBytes);
+ var wif = !test[2].substr(0, 1).match(/[LK]/) ? btcKey.setCompressed(false).getBitcoinWalletImportFormat() : btcKey.setCompressed(true).getBitcoinWalletImportFormat();
+ if (wif != test[2]) {
+ document.getElementById("unittestresults").innerHTML += "fail testDecryptBip38 #" + i + " ";
+ } else {
+ document.getElementById("unittestresults").innerHTML += "pass testDecryptBip38 #" + i + " ";
+ }
+ }
+ onComplete();
+ });
+ }
+
+ document.getElementById("unittestresults").innerHTML += "running " + tests.length + " tests named testDecryptBip38 ";
+ ninja.runSerialized([function (cb) {
+ ninja.forSerialized(0, tests.length, function (i, callback) {
+ decryptTest(tests[i], i, waitThenCall(callback));
+ }, waitThenCall(cb));
+ } ], done);
+ }
+ }
+ };
+})(ninja);
\ No newline at end of file
diff --git a/src/ninja.vanitywallet.js b/src/ninja.vanitywallet.js
new file mode 100644
index 0000000..02e8467
--- /dev/null
+++ b/src/ninja.vanitywallet.js
@@ -0,0 +1,114 @@
+ninja.wallets.vanitywallet = {
+ open: function () {
+ document.getElementById("vanityarea").style.display = "block";
+ },
+
+ close: function () {
+ document.getElementById("vanityarea").style.display = "none";
+ document.getElementById("vanitystep1area").style.display = "none";
+ document.getElementById("vanitystep2area").style.display = "none";
+ document.getElementById("vanitystep1icon").setAttribute("class", "more");
+ document.getElementById("vanitystep2icon").setAttribute("class", "more");
+ },
+
+ generateKeyPair: function () {
+ var key = new Bitcoin.ECKey(false);
+ var publicKey = key.getPubKeyHex();
+ var privateKey = key.getBitcoinHexFormat();
+ document.getElementById("vanitypubkey").innerHTML = publicKey;
+ document.getElementById("vanityprivatekey").innerHTML = privateKey;
+ document.getElementById("vanityarea").style.display = "block";
+ document.getElementById("vanitystep1area").style.display = "none";
+ },
+
+ addKeys: function () {
+ var privateKeyWif = ninja.translator.get("vanityinvalidinputcouldnotcombinekeys");
+ var bitcoinAddress = ninja.translator.get("vanityinvalidinputcouldnotcombinekeys");
+ var publicKeyHex = ninja.translator.get("vanityinvalidinputcouldnotcombinekeys");
+ try {
+ var input1KeyString = document.getElementById("vanityinput1").value;
+ var input2KeyString = document.getElementById("vanityinput2").value;
+
+ // both inputs are public keys
+ if (ninja.publicKey.isPublicKeyHexFormat(input1KeyString) && ninja.publicKey.isPublicKeyHexFormat(input2KeyString)) {
+ // add both public keys together
+ if (document.getElementById("vanityradioadd").checked) {
+ var pubKeyByteArray = ninja.publicKey.getByteArrayFromAdding(input1KeyString, input2KeyString);
+ if (pubKeyByteArray == null) {
+ alert(ninja.translator.get("vanityalertinvalidinputpublickeysmatch"));
+ }
+ else {
+ privateKeyWif = ninja.translator.get("vanityprivatekeyonlyavailable");
+ bitcoinAddress = ninja.publicKey.getBitcoinAddressFromByteArray(pubKeyByteArray);
+ publicKeyHex = ninja.publicKey.getHexFromByteArray(pubKeyByteArray);
+ }
+ }
+ else {
+ alert(ninja.translator.get("vanityalertinvalidinputcannotmultiple"));
+ }
+ }
+ // one public key and one private key
+ else if ((ninja.publicKey.isPublicKeyHexFormat(input1KeyString) && ninja.privateKey.isPrivateKey(input2KeyString))
+ || (ninja.publicKey.isPublicKeyHexFormat(input2KeyString) && ninja.privateKey.isPrivateKey(input1KeyString))
+ ) {
+ privateKeyWif = ninja.translator.get("vanityprivatekeyonlyavailable");
+ var pubKeyHex = (ninja.publicKey.isPublicKeyHexFormat(input1KeyString)) ? input1KeyString : input2KeyString;
+ var ecKey = (ninja.privateKey.isPrivateKey(input1KeyString)) ? new Bitcoin.ECKey(input1KeyString) : new Bitcoin.ECKey(input2KeyString);
+ // add
+ if (document.getElementById("vanityradioadd").checked) {
+ var pubKeyCombined = ninja.publicKey.getByteArrayFromAdding(pubKeyHex, ecKey.getPubKeyHex());
+ }
+ // multiply
+ else {
+ var pubKeyCombined = ninja.publicKey.getByteArrayFromMultiplying(pubKeyHex, ecKey);
+ }
+ if (pubKeyCombined == null) {
+ alert(ninja.translator.get("vanityalertinvalidinputpublickeysmatch"));
+ } else {
+ bitcoinAddress = ninja.publicKey.getBitcoinAddressFromByteArray(pubKeyCombined);
+ publicKeyHex = ninja.publicKey.getHexFromByteArray(pubKeyCombined);
+ }
+ }
+ // both inputs are private keys
+ else if (ninja.privateKey.isPrivateKey(input1KeyString) && ninja.privateKey.isPrivateKey(input2KeyString)) {
+ var combinedPrivateKey;
+ // add both private keys together
+ if (document.getElementById("vanityradioadd").checked) {
+ combinedPrivateKey = ninja.privateKey.getECKeyFromAdding(input1KeyString, input2KeyString);
+ }
+ // multiply both private keys together
+ else {
+ combinedPrivateKey = ninja.privateKey.getECKeyFromMultiplying(input1KeyString, input2KeyString);
+ }
+ if (combinedPrivateKey == null) {
+ alert(ninja.translator.get("vanityalertinvalidinputprivatekeysmatch"));
+ }
+ else {
+ bitcoinAddress = combinedPrivateKey.getBitcoinAddress();
+ privateKeyWif = combinedPrivateKey.getBitcoinWalletImportFormat();
+ publicKeyHex = combinedPrivateKey.getPubKeyHex();
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+ document.getElementById("vanityprivatekeywif").innerHTML = privateKeyWif;
+ document.getElementById("vanityaddress").innerHTML = bitcoinAddress;
+ document.getElementById("vanitypublickeyhex").innerHTML = publicKeyHex;
+ document.getElementById("vanitystep2area").style.display = "block";
+ document.getElementById("vanitystep2icon").setAttribute("class", "less");
+ },
+
+ openCloseStep: function (num) {
+ // do close
+ if (document.getElementById("vanitystep" + num + "area").style.display == "block") {
+ document.getElementById("vanitystep" + num + "area").style.display = "none";
+ document.getElementById("vanitystep" + num + "icon").setAttribute("class", "more");
+ }
+ // do open
+ else {
+ document.getElementById("vanitystep" + num + "area").style.display = "block";
+ document.getElementById("vanitystep" + num + "icon").setAttribute("class", "less");
+ }
+ }
+};
\ No newline at end of file
diff --git a/src/qrcode.js b/src/qrcode.js
new file mode 100644
index 0000000..21a311d
--- /dev/null
+++ b/src/qrcode.js
@@ -0,0 +1,1034 @@
+//---------------------------------------------------------------------
+// QRCode for JavaScript
+//
+// Copyright (c) 2009 Kazuhiko Arase
+//
+// URL: http://www.d-project.com/
+//
+// Licensed under the MIT license:
+// http://www.opensource.org/licenses/mit-license.php
+//
+// The word "QR Code" is registered trademark of
+// DENSO WAVE INCORPORATED
+// http://www.denso-wave.com/qrcode/faqpatent-e.html
+//
+//---------------------------------------------------------------------
+
+(function () {
+ //---------------------------------------------------------------------
+ // QRCode
+ //---------------------------------------------------------------------
+
+ var QRCode = window.QRCode = function (typeNumber, errorCorrectLevel) {
+ this.typeNumber = typeNumber;
+ this.errorCorrectLevel = errorCorrectLevel;
+ this.modules = null;
+ this.moduleCount = 0;
+ this.dataCache = null;
+ this.dataList = new Array();
+ }
+
+ QRCode.prototype = {
+
+ addData: function (data) {
+ var newData = new QRCode.QR8bitByte(data);
+ this.dataList.push(newData);
+ this.dataCache = null;
+ },
+
+ isDark: function (row, col) {
+ if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+ throw new Error(row + "," + col);
+ }
+ return this.modules[row][col];
+ },
+
+ getModuleCount: function () {
+ return this.moduleCount;
+ },
+
+ make: function () {
+ this.makeImpl(false, this.getBestMaskPattern());
+ },
+
+ makeImpl: function (test, maskPattern) {
+
+ this.moduleCount = this.typeNumber * 4 + 17;
+ this.modules = new Array(this.moduleCount);
+
+ for (var row = 0; row < this.moduleCount; row++) {
+
+ this.modules[row] = new Array(this.moduleCount);
+
+ for (var col = 0; col < this.moduleCount; col++) {
+ this.modules[row][col] = null; //(col + row) % 3;
+ }
+ }
+
+ this.setupPositionProbePattern(0, 0);
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
+ this.setupPositionAdjustPattern();
+ this.setupTimingPattern();
+ this.setupTypeInfo(test, maskPattern);
+
+ if (this.typeNumber >= 7) {
+ this.setupTypeNumber(test);
+ }
+
+ if (this.dataCache == null) {
+ this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+ }
+
+ this.mapData(this.dataCache, maskPattern);
+ },
+
+ setupPositionProbePattern: function (row, col) {
+
+ for (var r = -1; r <= 7; r++) {
+
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+ for (var c = -1; c <= 7; c++) {
+
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+ if ((0 <= r && r <= 6 && (c == 0 || c == 6))
+ || (0 <= c && c <= 6 && (r == 0 || r == 6))
+ || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ },
+
+ getBestMaskPattern: function () {
+
+ var minLostPoint = 0;
+ var pattern = 0;
+
+ for (var i = 0; i < 8; i++) {
+
+ this.makeImpl(true, i);
+
+ var lostPoint = QRCode.Util.getLostPoint(this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ },
+
+ createMovieClip: function (target_mc, instance_name, depth) {
+
+ var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+ var cs = 1;
+
+ this.make();
+
+ for (var row = 0; row < this.modules.length; row++) {
+
+ var y = row * cs;
+
+ for (var col = 0; col < this.modules[row].length; col++) {
+
+ var x = col * cs;
+ var dark = this.modules[row][col];
+
+ if (dark) {
+ qr_mc.beginFill(0, 100);
+ qr_mc.moveTo(x, y);
+ qr_mc.lineTo(x + cs, y);
+ qr_mc.lineTo(x + cs, y + cs);
+ qr_mc.lineTo(x, y + cs);
+ qr_mc.endFill();
+ }
+ }
+ }
+
+ return qr_mc;
+ },
+
+ setupTimingPattern: function () {
+
+ for (var r = 8; r < this.moduleCount - 8; r++) {
+ if (this.modules[r][6] != null) {
+ continue;
+ }
+ this.modules[r][6] = (r % 2 == 0);
+ }
+
+ for (var c = 8; c < this.moduleCount - 8; c++) {
+ if (this.modules[6][c] != null) {
+ continue;
+ }
+ this.modules[6][c] = (c % 2 == 0);
+ }
+ },
+
+ setupPositionAdjustPattern: function () {
+
+ var pos = QRCode.Util.getPatternPosition(this.typeNumber);
+
+ for (var i = 0; i < pos.length; i++) {
+
+ for (var j = 0; j < pos.length; j++) {
+
+ var row = pos[i];
+ var col = pos[j];
+
+ if (this.modules[row][col] != null) {
+ continue;
+ }
+
+ for (var r = -2; r <= 2; r++) {
+
+ for (var c = -2; c <= 2; c++) {
+
+ if (r == -2 || r == 2 || c == -2 || c == 2
+ || (r == 0 && c == 0)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ },
+
+ setupTypeNumber: function (test) {
+
+ var bits = QRCode.Util.getBCHTypeNumber(this.typeNumber);
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+ }
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+ }
+ },
+
+ setupTypeInfo: function (test, maskPattern) {
+
+ var data = (this.errorCorrectLevel << 3) | maskPattern;
+ var bits = QRCode.Util.getBCHTypeInfo(data);
+
+ // vertical
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 6) {
+ this.modules[i][8] = mod;
+ } else if (i < 8) {
+ this.modules[i + 1][8] = mod;
+ } else {
+ this.modules[this.moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 8) {
+ this.modules[8][this.moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ this.modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ this.modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ this.modules[this.moduleCount - 8][8] = (!test);
+
+ },
+
+ mapData: function (data, maskPattern) {
+
+ var inc = -1;
+ var row = this.moduleCount - 1;
+ var bitIndex = 7;
+ var byteIndex = 0;
+
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+ if (col == 6) col--;
+
+ while (true) {
+
+ for (var c = 0; c < 2; c++) {
+
+ if (this.modules[row][col - c] == null) {
+
+ var dark = false;
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ var mask = QRCode.Util.getMask(maskPattern, row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ this.modules[row][col - c] = dark;
+ bitIndex--;
+
+ if (bitIndex == -1) {
+ byteIndex++;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || this.moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+
+ }
+
+ };
+
+ QRCode.PAD0 = 0xEC;
+ QRCode.PAD1 = 0x11;
+
+ QRCode.createData = function (typeNumber, errorCorrectLevel, dataList) {
+
+ var rsBlocks = QRCode.RSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+ var buffer = new QRCode.BitBuffer();
+
+ for (var i = 0; i < dataList.length; i++) {
+ var data = dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRCode.Util.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new Error("code length overflow. ("
+ + buffer.getLengthInBits()
+ + ">"
+ + totalDataCount * 8
+ + ")");
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD1, 8);
+ }
+
+ return QRCode.createBytes(buffer, rsBlocks);
+ };
+
+ QRCode.createBytes = function (buffer, rsBlocks) {
+
+ var offset = 0;
+
+ var maxDcCount = 0;
+ var maxEcCount = 0;
+
+ var dcdata = new Array(rsBlocks.length);
+ var ecdata = new Array(rsBlocks.length);
+
+ for (var r = 0; r < rsBlocks.length; r++) {
+
+ var dcCount = rsBlocks[r].dataCount;
+ var ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (var i = 0; i < dcdata[r].length; i++) {
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+ }
+ offset += dcCount;
+
+ var rsPoly = QRCode.Util.getErrorCorrectPolynomial(ecCount);
+ var rawPoly = new QRCode.Polynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ var modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (var i = 0; i < ecdata[r].length; i++) {
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+ }
+
+ }
+
+ var totalCodeCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ var data = new Array(totalCodeCount);
+ var index = 0;
+
+ for (var i = 0; i < maxDcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < dcdata[r].length) {
+ data[index++] = dcdata[r][i];
+ }
+ }
+ }
+
+ for (var i = 0; i < maxEcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < ecdata[r].length) {
+ data[index++] = ecdata[r][i];
+ }
+ }
+ }
+
+ return data;
+
+ };
+
+ //---------------------------------------------------------------------
+ // QR8bitByte
+ //---------------------------------------------------------------------
+ QRCode.QR8bitByte = function (data) {
+ this.mode = QRCode.Mode.MODE_8BIT_BYTE;
+ this.data = data;
+ }
+
+ QRCode.QR8bitByte.prototype = {
+ getLength: function (buffer) {
+ return this.data.length;
+ },
+
+ write: function (buffer) {
+ for (var i = 0; i < this.data.length; i++) {
+ // not JIS ...
+ buffer.put(this.data.charCodeAt(i), 8);
+ }
+ }
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMode
+ //---------------------------------------------------------------------
+ QRCode.Mode = {
+ MODE_NUMBER: 1 << 0,
+ MODE_ALPHA_NUM: 1 << 1,
+ MODE_8BIT_BYTE: 1 << 2,
+ MODE_KANJI: 1 << 3
+ };
+
+ //---------------------------------------------------------------------
+ // QRErrorCorrectLevel
+ //---------------------------------------------------------------------
+ QRCode.ErrorCorrectLevel = {
+ L: 1,
+ M: 0,
+ Q: 3,
+ H: 2
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMaskPattern
+ //---------------------------------------------------------------------
+ QRCode.MaskPattern = {
+ PATTERN000: 0,
+ PATTERN001: 1,
+ PATTERN010: 2,
+ PATTERN011: 3,
+ PATTERN100: 4,
+ PATTERN101: 5,
+ PATTERN110: 6,
+ PATTERN111: 7
+ };
+
+ //---------------------------------------------------------------------
+ // QRUtil
+ //---------------------------------------------------------------------
+
+ QRCode.Util = {
+
+ PATTERN_POSITION_TABLE: [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ],
+
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+ getBCHTypeInfo: function (data) {
+ var d = data << 10;
+ while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15) >= 0) {
+ d ^= (QRCode.Util.G15 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15)));
+ }
+ return ((data << 10) | d) ^ QRCode.Util.G15_MASK;
+ },
+
+ getBCHTypeNumber: function (data) {
+ var d = data << 12;
+ while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18) >= 0) {
+ d ^= (QRCode.Util.G18 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18)));
+ }
+ return (data << 12) | d;
+ },
+
+ getBCHDigit: function (data) {
+
+ var digit = 0;
+
+ while (data != 0) {
+ digit++;
+ data >>>= 1;
+ }
+
+ return digit;
+ },
+
+ getPatternPosition: function (typeNumber) {
+ return QRCode.Util.PATTERN_POSITION_TABLE[typeNumber - 1];
+ },
+
+ getMask: function (maskPattern, i, j) {
+
+ switch (maskPattern) {
+
+ case QRCode.MaskPattern.PATTERN000: return (i + j) % 2 == 0;
+ case QRCode.MaskPattern.PATTERN001: return i % 2 == 0;
+ case QRCode.MaskPattern.PATTERN010: return j % 3 == 0;
+ case QRCode.MaskPattern.PATTERN011: return (i + j) % 3 == 0;
+ case QRCode.MaskPattern.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+ case QRCode.MaskPattern.PATTERN101: return (i * j) % 2 + (i * j) % 3 == 0;
+ case QRCode.MaskPattern.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+ case QRCode.MaskPattern.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+ default:
+ throw new Error("bad maskPattern:" + maskPattern);
+ }
+ },
+
+ getErrorCorrectPolynomial: function (errorCorrectLength) {
+
+ var a = new QRCode.Polynomial([1], 0);
+
+ for (var i = 0; i < errorCorrectLength; i++) {
+ a = a.multiply(new QRCode.Polynomial([1, QRCode.Math.gexp(i)], 0));
+ }
+
+ return a;
+ },
+
+ getLengthInBits: function (mode, type) {
+
+ if (1 <= type && type < 10) {
+
+ // 1 - 9
+
+ switch (mode) {
+ case QRCode.Mode.MODE_NUMBER: return 10;
+ case QRCode.Mode.MODE_ALPHA_NUM: return 9;
+ case QRCode.Mode.MODE_8BIT_BYTE: return 8;
+ case QRCode.Mode.MODE_KANJI: return 8;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 27) {
+
+ // 10 - 26
+
+ switch (mode) {
+ case QRCode.Mode.MODE_NUMBER: return 12;
+ case QRCode.Mode.MODE_ALPHA_NUM: return 11;
+ case QRCode.Mode.MODE_8BIT_BYTE: return 16;
+ case QRCode.Mode.MODE_KANJI: return 10;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 41) {
+
+ // 27 - 40
+
+ switch (mode) {
+ case QRCode.Mode.MODE_NUMBER: return 14;
+ case QRCode.Mode.MODE_ALPHA_NUM: return 13;
+ case QRCode.Mode.MODE_8BIT_BYTE: return 16;
+ case QRCode.Mode.MODE_KANJI: return 12;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else {
+ throw new Error("type:" + type);
+ }
+ },
+
+ getLostPoint: function (qrCode) {
+
+ var moduleCount = qrCode.getModuleCount();
+
+ var lostPoint = 0;
+
+ // LEVEL1
+
+ for (var row = 0; row < moduleCount; row++) {
+
+ for (var col = 0; col < moduleCount; col++) {
+
+ var sameCount = 0;
+ var dark = qrCode.isDark(row, col);
+
+ for (var r = -1; r <= 1; r++) {
+
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (var c = -1; c <= 1; c++) {
+
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrCode.isDark(row + r, col + c)) {
+ sameCount++;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ }
+
+ // LEVEL2
+
+ for (var row = 0; row < moduleCount - 1; row++) {
+ for (var col = 0; col < moduleCount - 1; col++) {
+ var count = 0;
+ if (qrCode.isDark(row, col)) count++;
+ if (qrCode.isDark(row + 1, col)) count++;
+ if (qrCode.isDark(row, col + 1)) count++;
+ if (qrCode.isDark(row + 1, col + 1)) count++;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+
+ for (var row = 0; row < moduleCount; row++) {
+ for (var col = 0; col < moduleCount - 6; col++) {
+ if (qrCode.isDark(row, col)
+ && !qrCode.isDark(row, col + 1)
+ && qrCode.isDark(row, col + 2)
+ && qrCode.isDark(row, col + 3)
+ && qrCode.isDark(row, col + 4)
+ && !qrCode.isDark(row, col + 5)
+ && qrCode.isDark(row, col + 6)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount - 6; row++) {
+ if (qrCode.isDark(row, col)
+ && !qrCode.isDark(row + 1, col)
+ && qrCode.isDark(row + 2, col)
+ && qrCode.isDark(row + 3, col)
+ && qrCode.isDark(row + 4, col)
+ && !qrCode.isDark(row + 5, col)
+ && qrCode.isDark(row + 6, col)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+
+ var darkCount = 0;
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount; row++) {
+ if (qrCode.isDark(row, col)) {
+ darkCount++;
+ }
+ }
+ }
+
+ var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ }
+
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMath
+ //---------------------------------------------------------------------
+
+ QRCode.Math = {
+
+ glog: function (n) {
+
+ if (n < 1) {
+ throw new Error("glog(" + n + ")");
+ }
+
+ return QRCode.Math.LOG_TABLE[n];
+ },
+
+ gexp: function (n) {
+
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return QRCode.Math.EXP_TABLE[n];
+ },
+
+ EXP_TABLE: new Array(256),
+
+ LOG_TABLE: new Array(256)
+
+ };
+
+ for (var i = 0; i < 8; i++) {
+ QRCode.Math.EXP_TABLE[i] = 1 << i;
+ }
+ for (var i = 8; i < 256; i++) {
+ QRCode.Math.EXP_TABLE[i] = QRCode.Math.EXP_TABLE[i - 4]
+ ^ QRCode.Math.EXP_TABLE[i - 5]
+ ^ QRCode.Math.EXP_TABLE[i - 6]
+ ^ QRCode.Math.EXP_TABLE[i - 8];
+ }
+ for (var i = 0; i < 255; i++) {
+ QRCode.Math.LOG_TABLE[QRCode.Math.EXP_TABLE[i]] = i;
+ }
+
+ //---------------------------------------------------------------------
+ // QRPolynomial
+ //---------------------------------------------------------------------
+
+ QRCode.Polynomial = function (num, shift) {
+
+ if (num.length == undefined) {
+ throw new Error(num.length + "/" + shift);
+ }
+
+ var offset = 0;
+
+ while (offset < num.length && num[offset] == 0) {
+ offset++;
+ }
+
+ this.num = new Array(num.length - offset + shift);
+ for (var i = 0; i < num.length - offset; i++) {
+ this.num[i] = num[i + offset];
+ }
+ }
+
+ QRCode.Polynomial.prototype = {
+
+ get: function (index) {
+ return this.num[index];
+ },
+
+ getLength: function () {
+ return this.num.length;
+ },
+
+ multiply: function (e) {
+
+ var num = new Array(this.getLength() + e.getLength() - 1);
+
+ for (var i = 0; i < this.getLength(); i++) {
+ for (var j = 0; j < e.getLength(); j++) {
+ num[i + j] ^= QRCode.Math.gexp(QRCode.Math.glog(this.get(i)) + QRCode.Math.glog(e.get(j)));
+ }
+ }
+
+ return new QRCode.Polynomial(num, 0);
+ },
+
+ mod: function (e) {
+
+ if (this.getLength() - e.getLength() < 0) {
+ return this;
+ }
+
+ var ratio = QRCode.Math.glog(this.get(0)) - QRCode.Math.glog(e.get(0));
+
+ var num = new Array(this.getLength());
+
+ for (var i = 0; i < this.getLength(); i++) {
+ num[i] = this.get(i);
+ }
+
+ for (var i = 0; i < e.getLength(); i++) {
+ num[i] ^= QRCode.Math.gexp(QRCode.Math.glog(e.get(i)) + ratio);
+ }
+
+ // recursive call
+ return new QRCode.Polynomial(num, 0).mod(e);
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRRSBlock
+ //---------------------------------------------------------------------
+
+ QRCode.RSBlock = function (totalCount, dataCount) {
+ this.totalCount = totalCount;
+ this.dataCount = dataCount;
+ }
+
+ QRCode.RSBlock.RS_BLOCK_TABLE = [
+
+ // L
+ // M
+ // Q
+ // H
+
+ // 1
+ [1, 26, 19],
+ [1, 26, 16],
+ [1, 26, 13],
+ [1, 26, 9],
+
+ // 2
+ [1, 44, 34],
+ [1, 44, 28],
+ [1, 44, 22],
+ [1, 44, 16],
+
+ // 3
+ [1, 70, 55],
+ [1, 70, 44],
+ [2, 35, 17],
+ [2, 35, 13],
+
+ // 4
+ [1, 100, 80],
+ [2, 50, 32],
+ [2, 50, 24],
+ [4, 25, 9],
+
+ // 5
+ [1, 134, 108],
+ [2, 67, 43],
+ [2, 33, 15, 2, 34, 16],
+ [2, 33, 11, 2, 34, 12],
+
+ // 6
+ [2, 86, 68],
+ [4, 43, 27],
+ [4, 43, 19],
+ [4, 43, 15],
+
+ // 7
+ [2, 98, 78],
+ [4, 49, 31],
+ [2, 32, 14, 4, 33, 15],
+ [4, 39, 13, 1, 40, 14],
+
+ // 8
+ [2, 121, 97],
+ [2, 60, 38, 2, 61, 39],
+ [4, 40, 18, 2, 41, 19],
+ [4, 40, 14, 2, 41, 15],
+
+ // 9
+ [2, 146, 116],
+ [3, 58, 36, 2, 59, 37],
+ [4, 36, 16, 4, 37, 17],
+ [4, 36, 12, 4, 37, 13],
+
+ // 10
+ [2, 86, 68, 2, 87, 69],
+ [4, 69, 43, 1, 70, 44],
+ [6, 43, 19, 2, 44, 20],
+ [6, 43, 15, 2, 44, 16]
+
+];
+
+ QRCode.RSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
+
+ var rsBlock = QRCode.RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+ if (rsBlock == undefined) {
+ throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
+ }
+
+ var length = rsBlock.length / 3;
+
+ var list = new Array();
+
+ for (var i = 0; i < length; i++) {
+
+ var count = rsBlock[i * 3 + 0];
+ var totalCount = rsBlock[i * 3 + 1];
+ var dataCount = rsBlock[i * 3 + 2];
+
+ for (var j = 0; j < count; j++) {
+ list.push(new QRCode.RSBlock(totalCount, dataCount));
+ }
+ }
+
+ return list;
+ };
+
+ QRCode.RSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
+
+ switch (errorCorrectLevel) {
+ case QRCode.ErrorCorrectLevel.L:
+ return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+ case QRCode.ErrorCorrectLevel.M:
+ return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+ case QRCode.ErrorCorrectLevel.Q:
+ return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+ case QRCode.ErrorCorrectLevel.H:
+ return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+ default:
+ return undefined;
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRBitBuffer
+ //---------------------------------------------------------------------
+
+ QRCode.BitBuffer = function () {
+ this.buffer = new Array();
+ this.length = 0;
+ }
+
+ QRCode.BitBuffer.prototype = {
+
+ get: function (index) {
+ var bufIndex = Math.floor(index / 8);
+ return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+ },
+
+ put: function (num, length) {
+ for (var i = 0; i < length; i++) {
+ this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+ }
+ },
+
+ getLengthInBits: function () {
+ return this.length;
+ },
+
+ putBit: function (bit) {
+
+ var bufIndex = Math.floor(this.length / 8);
+ if (this.buffer.length <= bufIndex) {
+ this.buffer.push(0);
+ }
+
+ if (bit) {
+ this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+ }
+
+ this.length++;
+ }
+ };
+})();
\ No newline at end of file
diff --git a/src/securerandom.js b/src/securerandom.js
new file mode 100644
index 0000000..be388c9
--- /dev/null
+++ b/src/securerandom.js
@@ -0,0 +1,130 @@
+/*!
+* Random number generator with ArcFour PRNG
+*
+* NOTE: For best results, put code like
+*
+* in your main HTML document.
+*
+* Copyright Tom Wu, bitaddress.org BSD License.
+* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
+*/
+(function () {
+
+ // Constructor function of Global SecureRandom object
+ var sr = window.SecureRandom = function () { };
+
+ // Properties
+ sr.state;
+ sr.pool;
+ sr.pptr;
+
+ // Pool size must be a multiple of 4 and greater than 32.
+ // An array of bytes the size of the pool will be passed to init()
+ sr.poolSize = 256;
+
+
+ // --- object methods ---
+
+ // public method
+ // ba: byte array
+ sr.prototype.nextBytes = function (ba) {
+ var i;
+ for (i = 0; i < ba.length; ++i) ba[i] = sr.getByte();
+ };
+
+
+ // --- static methods ---
+
+ // Mix in the current time (w/milliseconds) into the pool
+ // NOTE: this method should be called from body click/keypress event handlers to increase entropy
+ sr.seedTime = function () {
+ sr.seedInt(new Date().getTime());
+ }
+
+ sr.getByte = function () {
+ if (sr.state == null) {
+ sr.seedTime();
+ sr.state = sr.ArcFour(); // Plug in your RNG constructor here
+ sr.state.init(sr.pool);
+ for (sr.pptr = 0; sr.pptr < sr.pool.length; ++sr.pptr)
+ sr.pool[sr.pptr] = 0;
+ sr.pptr = 0;
+ }
+ // TODO: allow reseeding after first request
+ return sr.state.next();
+ }
+
+ // Mix in a 32-bit integer into the pool
+ sr.seedInt = function (x) {
+ sr.pool[sr.pptr++] ^= x & 255;
+ sr.pool[sr.pptr++] ^= (x >> 8) & 255;
+ sr.pool[sr.pptr++] ^= (x >> 16) & 255;
+ sr.pool[sr.pptr++] ^= (x >> 24) & 255;
+ if (sr.pptr >= sr.poolSize) sr.pptr -= sr.poolSize;
+ }
+
+
+ // Arcfour is a PRNG
+ sr.ArcFour = function () {
+ function Arcfour() {
+ this.i = 0;
+ this.j = 0;
+ this.S = new Array();
+ }
+
+ // Initialize arcfour context from key, an array of ints, each from [0..255]
+ function ARC4init(key) {
+ var i, j, t;
+ for (i = 0; i < 256; ++i)
+ this.S[i] = i;
+ j = 0;
+ for (i = 0; i < 256; ++i) {
+ j = (j + this.S[i] + key[i % key.length]) & 255;
+ t = this.S[i];
+ this.S[i] = this.S[j];
+ this.S[j] = t;
+ }
+ this.i = 0;
+ this.j = 0;
+ }
+
+ function ARC4next() {
+ var t;
+ this.i = (this.i + 1) & 255;
+ this.j = (this.j + this.S[this.i]) & 255;
+ t = this.S[this.i];
+ this.S[this.i] = this.S[this.j];
+ this.S[this.j] = t;
+ return this.S[(t + this.S[this.i]) & 255];
+ }
+
+ Arcfour.prototype.init = ARC4init;
+ Arcfour.prototype.next = ARC4next;
+
+ return new Arcfour();
+ };
+
+
+ // Initialize the pool with junk if needed.
+ if (sr.pool == null) {
+ sr.pool = new Array();
+ sr.pptr = 0;
+ var t;
+ if (navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) {
+ // Extract entropy (256 bits) from NS4 RNG if available
+ var z = window.crypto.random(32);
+ for (t = 0; t < z.length; ++t)
+ sr.pool[sr.pptr++] = z.charCodeAt(t) & 255;
+ }
+ while (sr.pptr < sr.poolSize) { // extract some randomness from Math.random()
+ t = Math.floor(65536 * Math.random());
+ sr.pool[sr.pptr++] = t >>> 8;
+ sr.pool[sr.pptr++] = t & 255;
+ }
+ sr.pptr = 0;
+ sr.seedTime();
+ // entropy
+ sr.seedInt(window.screenX);
+ sr.seedInt(window.screenY);
+ }
+})();
\ No newline at end of file