diff --git a/README b/README index e7651a7..8cd5610 100644 --- a/README +++ b/README @@ -3,24 +3,37 @@ If you're on already at https://github.com/cantonbecker/bitcoinpaperwallet Then just look for the button that says "Download ZIP". Look to your right --> ******************************************************************************* -*** bitcoinpaperwallet *** +*** bitcoinpaperwallet.com *** This project is a fork of bitaddress.org, the original trustworthy -JavaScript powered offline bitcoin address generator. +JavaScript powered offline bitcoin address generator. -Here's how this project differs: - -1) This generator is ONLY for printing paper wallets. Use bitaddress.org if -you need to bulk-generate addresses, etc. - -2) This attractive paper wallet design is two-sided and folds up to +This attractive paper wallet design is two-sided and folds up to hide the private key. Optional tamper-evident hologram tape can be purchased -to provide extra security against snooping. +to provide extra security against snooping. This generator is ONLY +for generating secure paper wallets, either using Javascript-based cryptography +or by supplying keys you have generated using your own means (vanitygen, dice.) -3) A tool is included to help calibrate the printer output for proper -sizing and two-sided alignment. +Use bitaddress.org if you need BIP38, brain wallets, or bulk addresses. -4) Images and resources have been moved out of the .html file (where they were + +*** HOW TO USE THIS GENERATOR *** + +1) Extract the ZIP file +2) Open up the 'generate-wallet.html' file with your web browser. +3) Follow the steps for calibrating your printer and then printing + the front and back of each wallet. Use landscape mode when printing! + +Rendering and printing seems to work best using: + + OS X: Safari or Chrome or Firefox + Windows: Chrome or Firefox + Linux: Firefox + + +*** COMPARED WITH BITADDRESS.ORG *** + +Images and resources have been moved out of the .html file (where they were base-64 encoded) and into an images directory to make the code easier to review. All cryptographic functions are verifiably identical to those in bitaddress.org. @@ -29,16 +42,6 @@ All cryptographic functions are verifiably identical to those in bitaddress.org. You can also bypass the random key generator and supply your own keys or so-called "vanity addresses". -*** HOW TO USE THIS GENERATOR *** - -1) Extract the ZIP file -2) Open up the 'generate-wallet.html' file with your web browser. - -Rendering and printing seems to work best using: - - OS X: Safari or Chrome or Firefox - Windows: Chrome or Firefox - Linux: Firefox *** HOW TO VERIFY THE AUTHENTICITY OF THIS DOWNLOAD *** @@ -47,12 +50,19 @@ named generate-wallet.html.sig which you can use to: * Verify that generate-wallet.html hasn't been tampered with, and * Get proof that it really was authored by Canton Becker (canton@gmail.com) - whose GPG public key and fingerprint can be confirmed at http://cantonbecker.com + whose GPG public key and fingerprint should be confirmed at http://cantonbecker.com -For example, if you have GPG installed, you can type: -gpg --verify --with-fingerprint generate-wallet.html.sig generate-wallet.html +For example, if you have GPG installed, you should be able cd to the appropriate +directory and type in these two commands: -And then verify the signature's fingerprint against Canton Becker's published signatures. + gpg --recv-key 36E1D9B6 + gpg --verify --with-fingerprint generate-wallet.html.sig generate-wallet.html + +And then verify the resulting signature's fingerprint against Canton Becker's +published fingerprint at http://cantonbecker.com + +If you get warnings like "This key is not certified, there is no indication that +the key belongs to the owner" do not worry, this is normal. - Canton Becker http://cantonbecker.com diff --git a/generate-wallet.html b/generate-wallet.html index 7bd0200..7d751e5 100644 --- a/generate-wallet.html +++ b/generate-wallet.html @@ -1624,7 +1624,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { sr.pptr = 0; var t; // Use webcrypto if available; -- Thanks to Gavin Andresen for this contribution - // see http://www.w3.org/2012/webcrypto/WebCryptoAPI/#Crypto-method-getRandomValues + // see http://www.w3.org/TR/WebCryptoAPI/#RandomSource-interface if (window.crypto && window.crypto.getRandomValues) { sr.pool = new Uint8Array(sr.poolSize); window.crypto.getRandomValues(sr.pool); @@ -1835,14 +1835,18 @@ if (typeof Crypto == "undefined" || !Crypto.util) { if (this.zinv == null) { this.zinv = this.z.modInverse(this.curve.q); } - return this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q)); + var r = this.x.toBigInteger().multiply(this.zinv); + this.curve.reduce(r); + return this.curve.fromBigInteger(r); }; ec.PointFp.prototype.getY = function () { if (this.zinv == null) { this.zinv = this.z.modInverse(this.curve.q); } - return this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q)); + var r = this.y.toBigInteger().multiply(this.zinv); + this.curve.reduce(r); + return this.curve.fromBigInteger(r); }; ec.PointFp.prototype.equals = function (other) { @@ -1924,6 +1928,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { w = w.add(this.z.square().multiply(a)); } w = w.mod(this.curve.q); + //this.curve.reduce(w); // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1) var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q); // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3 @@ -2164,6 +2169,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { this.a = this.fromBigInteger(a); this.b = this.fromBigInteger(b); this.infinity = new ec.PointFp(this, null, null); + this.reducer = new Barrett(this.q); } ec.CurveFp.prototype.getQ = function () { @@ -2191,6 +2197,10 @@ if (typeof Crypto == "undefined" || !Crypto.util) { return new ec.FieldElementFp(this.q, x); }; + ec.CurveFp.prototype.reduce = function (x) { + this.reducer.reduce(x); + }; + // for now, work with hex strings because they're easier in JS // compressed support added by bitaddress.org ec.CurveFp.prototype.decodePointHex = function (s) { @@ -2220,6 +2230,21 @@ if (typeof Crypto == "undefined" || !Crypto.util) { } }; + ec.CurveFp.prototype.encodePointHex = function (p) { + if (p.isInfinity()) return "00"; + var xHex = p.getX().toBigInteger().toString(16); + var yHex = p.getY().toBigInteger().toString(16); + var oLen = this.getQ().toString(16).length; + if ((oLen % 2) != 0) oLen++; + while (xHex.length < oLen) { + xHex = "0" + xHex; + } + while (yHex.length < oLen) { + yHex = "0" + yHex; + } + return "04" + xHex + yHex; + }; + /* * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) * Ported to JavaScript by bitaddress.org @@ -2448,7 +2473,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { this.t = 1; this.s = (x < 0) ? -1 : 0; if (x > 0) this[0] = x; - else if (x < -1) this[0] = x + DV; + else if (x < -1) this[0] = x + this.DV; else this.t = 0; }; @@ -3460,7 +3485,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { // ****** REDUCTION ******* // // Modular reduction using "classic" algorithm - function Classic(m) { this.m = m; } + var Classic = window.Classic = 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; @@ -3475,7 +3500,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { // Montgomery reduction - function Montgomery(m) { + var Montgomery = window.Montgomery = function Montgomery(m) { this.m = m; this.mp = m.invDigit(); this.mpl = this.mp & 0x7fff; @@ -3526,7 +3551,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { // A "null" reducer - function NullExp() { } + var NullExp = window.NullExp = 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); }; @@ -3537,7 +3562,7 @@ if (typeof Crypto == "undefined" || !Crypto.util) { // Barrett modular reduction - function Barrett(m) { + var Barrett = window.Barrett = function Barrett(m) { // setup Barrett this.r2 = nbi(); this.q3 = nbi(); @@ -5069,8 +5094,10 @@ Bitcoin.ECKey = (function () { } else if (ECKey.isBase64Format(input)) { bytes = Crypto.util.base64ToBytes(input); } - - if (bytes == null || bytes.length != 32) { + + if (ECKey.isBase6Format(input)) { + this.priv = new BigInteger(input, 6); + } else if (bytes == null || bytes.length != 32) { this.priv = null; } else { // Prepend zero byte to prevent interpretation as negative integer @@ -5287,6 +5314,12 @@ Bitcoin.ECKey = (function () { return (/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key)); }; + // 99 characters, 1=1, if using dice convert 6 to 0 + ECKey.isBase6Format = function (key) { + key = key.toString(); + return (/^[012345]{99}$/.test(key)); + }; + // 22, 26 or 30 characters, always starts with an 'S' ECKey.isMiniFormat = function (key) { key = key.toString(); @@ -6439,6 +6472,8 @@ Bitcoin.Util = { } .instructionsarea { padding: 0 25px; } + .instructionsarea { font-size: 12px; line-height: 18px; } + .instructionsarea li { padding-bottom: 8px; list-style: none; } .highlighted { font-size: 14px; padding: 8px; background-color: #ebfdbf;} @@ -6534,7 +6569,7 @@ Bitcoin.Util = { } - +
@@ -6544,8 +6579,8 @@ Bitcoin.Util = { Français -->  
-
Open Source JavaScript Bitcoin Wallet Generator Updated October 1, 2013
-
For help, security tips, or wallet supplies visit bitcoinpaperwallet.com
+
Open Source JavaScript Bitcoin Wallet Generator Updated December 3, 2013
+
For help, security tips, or wallet making supplies visit bitcoinpaperwallet.com
@@ -6612,7 +6684,7 @@ Bitcoin.Util = {
-

To calibrate your printer, print out this page in LANDSCAPE (wide) format. Based on the results, adjust the "zoom" and "horizontal shift" until the printed ruler closely matches a real ruler, and has equal margins on the left and right sides of the page. Once you have a properly sized & centered ruler, go on to step 2.

PS: Once you get your wallets printing out properly, please consider sending feedback so we can share successful print settings with others.

+

To calibrate your output, print out this page in LANDSCAPE (wide) format. Based on the results, adjust the "zoom" and "horizontal shift" until your printed ruler approximates a real ruler, and leaves equal margins on the left and right sides of the page. Consider letting us know what settings worked best.

Print Calibration Test @@ -6622,21 +6694,7 @@ Bitcoin.Util = {
Zoom / Shift : Default
-
- - - - +
@@ -6718,12 +6776,11 @@ Bitcoin.Util = {
Finally seal your wallet by placing two strips of sturdy light-blocking tape over the top and bottom edges of the private (folded) area. A zip-seal bag will keep it safe from moisture (especially important for inkjet prints.)

- + Purchase hologram stickers and/or zip-sealing bags » +

Sealed Wallet

- Click here to order some holographic tamper-evident tape and/or zip-sealing waterproof bags » -

How to add funds to your wallet:

@@ -6732,7 +6789,7 @@ Bitcoin.Util = {

How to withdraw funds from your wallet:

- Click here for important tips on withdrawing funds from your wallet » + You should expect to withdraw the entire balance of the wallet by importing it (or "sweeping" it) to a live wallet, e.g. a Bitcoin wallet application or online service like blockchain.info or coinbase.com. Click here for important tips on withdrawing funds from your wallet »
@@ -6757,13 +6814,14 @@ Bitcoin.Util = { @@ -7950,6 +8008,39 @@ Bitcoin.Util = { } } + function guessPrinterSettings() { + // detect browser / OS human-readable + txt = "

User-agent: " + navigator.userAgent + "
 
"; + var parser = new UAParser(); + parser.setUA(navigator.userAgent); + var result = parser.getResult(); + txt+=result.browser.name + " version " + result.browser.version + " (" + result.engine.name + ")
"; + txt+=result.os.name + " version " + result.os.version + " (" + result.cpu.architecture + ")
"; + txt += "

"; + document.getElementById("browserinfo").innerHTML=txt; + + // some common printer calibration settings here + if (result.browser.name == 'Safari') { // OS X Safari + document.getElementById("printerzoom").value = 5; + document.getElementById("printershift").value = 6; + } else if (result.browser.name == 'Chrome' && result.os.name == 'Mac OS X') { + document.getElementById("printerzoom").value = 3; + document.getElementById("printershift").value = 3; + } else if (result.browser.name == 'Firefox' && result.os.name == 'Ubuntu') { // live CD? + document.getElementById("printerzoom").value = 2; + document.getElementById("printershift").value = 3; + } else if (result.browser.name == 'Iceweasel' && result.os.name == 'Debian') { + document.getElementById("printerzoom").value = 1.8; + document.getElementById("printershift").value = 2.9; + } else if (result.browser.name == 'IE' && result.os.name == 'Windows') { + document.getElementById("printerzoom").value = 5; + document.getElementById("printershift").value = 6; + } + + updateCalibrationInfo(); + + } + diff --git a/generate-wallet.html.sig b/generate-wallet.html.sig index 332d912..858a6e5 100644 Binary files a/generate-wallet.html.sig and b/generate-wallet.html.sig differ