aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/index.html34
-rw-r--r--src/js/index.js109
2 files changed, 120 insertions, 23 deletions
diff --git a/src/index.html b/src/index.html
index 6708675..ea7096c 100644
--- a/src/index.html
+++ b/src/index.html
@@ -67,14 +67,14 @@
67 <div class="col-sm-10"> 67 <div class="col-sm-10">
68 <div class="input-group"> 68 <div class="input-group">
69 <select id="strength" class="strength form-control"> 69 <select id="strength" class="strength form-control">
70 <option val="3">3</option> 70 <option value="3">3</option>
71 <option val="6">6</option> 71 <option value="6">6</option>
72 <option val="9">9</option> 72 <option value="9">9</option>
73 <option val="12">12</option> 73 <option value="12">12</option>
74 <option val="15" selected>15</option> 74 <option value="15" selected>15</option>
75 <option val="18">18</option> 75 <option value="18">18</option>
76 <option val="21">21</option> 76 <option value="21">21</option>
77 <option val="24">24</option> 77 <option value="24">24</option>
78 </select> 78 </select>
79 <span class="input-group-btn"> 79 <span class="input-group-btn">
80 <button class="btn generate">Generate Random Mnemonic</button> 80 <button class="btn generate">Generate Random Mnemonic</button>
@@ -105,7 +105,7 @@
105 <div class="form-group"> 105 <div class="form-group">
106 <label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label> 106 <label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label>
107 <div class="col-sm-10"> 107 <div class="col-sm-10">
108 <textarea id="root-key" class="root-key form-control" readonly="readonly"></textarea> 108 <textarea id="root-key" class="root-key form-control"></textarea>
109 </div> 109 </div>
110 </div> 110 </div>
111 </form> 111 </form>
@@ -187,6 +187,13 @@
187 </div> 187 </div>
188 </div> 188 </div>
189 <div class="form-group"> 189 <div class="form-group">
190 <div class="col-sm-2"></div>
191 <label class="col-sm-10">
192 <input class="hardened-addresses" type="checkbox">
193 Use hardened addresses
194 </label>
195 </div>
196 <div class="form-group">
190 <label class="col-sm-2 control-label">Hive Wallet</label> 197 <label class="col-sm-2 control-label">Hive Wallet</label>
191 <div class="col-sm-10"> 198 <div class="col-sm-10">
192 <p class="form-control no-border"> 199 <p class="form-control no-border">
@@ -204,6 +211,15 @@
204 </p> 211 </p>
205 </div> 212 </div>
206 </div> 213 </div>
214 <div class="form-group">
215 <label for="core-path" class="col-sm-2 control-label">Bitcoin Core</label>
216 <div class="col-sm-10">
217 <p class="form-control no-border">
218 Use path <code>m/0'/0'</code> with hardened addresses.
219 For more info see the <a href="https://github.com/bitcoin/bitcoin/pull/8035" target="_blank">Bitcoin Core BIP32 implementation</a>
220 </p>
221 </div>
222 </div>
207 </form> 223 </form>
208 </div> 224 </div>
209 </div> 225 </div>
diff --git a/src/js/index.js b/src/js/index.js
index f3582b0..8f7d658 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -12,6 +12,7 @@
12 var showPrivKey = true; 12 var showPrivKey = true;
13 13
14 var phraseChangeTimeoutEvent = null; 14 var phraseChangeTimeoutEvent = null;
15 var rootKeyChangedTimeoutEvent = null;
15 16
16 var DOM = {}; 17 var DOM = {};
17 DOM.network = $(".network"); 18 DOM.network = $(".network");
@@ -34,6 +35,7 @@
34 DOM.bip44account = $("#bip44 .account"); 35 DOM.bip44account = $("#bip44 .account");
35 DOM.bip44change = $("#bip44 .change"); 36 DOM.bip44change = $("#bip44 .change");
36 DOM.strength = $(".strength"); 37 DOM.strength = $(".strength");
38 DOM.hardenedAddresses = $(".hardened-addresses");
37 DOM.addresses = $(".addresses"); 39 DOM.addresses = $(".addresses");
38 DOM.rowsToAdd = $(".rows-to-add"); 40 DOM.rowsToAdd = $(".rows-to-add");
39 DOM.more = $(".more"); 41 DOM.more = $(".more");
@@ -50,12 +52,14 @@
50 DOM.passphrase.on("input", delayedPhraseChanged); 52 DOM.passphrase.on("input", delayedPhraseChanged);
51 DOM.generate.on("click", generateClicked); 53 DOM.generate.on("click", generateClicked);
52 DOM.more.on("click", showMore); 54 DOM.more.on("click", showMore);
53 DOM.bip32path.on("input", delayedPhraseChanged); 55 DOM.rootKey.on("input", delayedRootKeyChanged);
54 DOM.bip44purpose.on("input", delayedPhraseChanged); 56 DOM.bip32path.on("input", calcForDerivationPath);
55 DOM.bip44coin.on("input", delayedPhraseChanged); 57 DOM.bip44purpose.on("input", calcForDerivationPath);
56 DOM.bip44account.on("input", delayedPhraseChanged); 58 DOM.bip44coin.on("input", calcForDerivationPath);
57 DOM.bip44change.on("input", delayedPhraseChanged); 59 DOM.bip44account.on("input", calcForDerivationPath);
58 DOM.tab.on("click", delayedPhraseChanged); 60 DOM.bip44change.on("input", calcForDerivationPath);
61 DOM.tab.on("shown.bs.tab", calcForDerivationPath);
62 DOM.hardenedAddresses.on("change", calcForDerivationPath);
59 DOM.indexToggle.on("click", toggleIndexes); 63 DOM.indexToggle.on("click", toggleIndexes);
60 DOM.addressToggle.on("click", toggleAddresses); 64 DOM.addressToggle.on("click", toggleAddresses);
61 DOM.privateKeyToggle.on("click", togglePrivateKeys); 65 DOM.privateKeyToggle.on("click", togglePrivateKeys);
@@ -68,9 +72,14 @@
68 // Event handlers 72 // Event handlers
69 73
70 function networkChanged(e) { 74 function networkChanged(e) {
71 var network = e.target.value; 75 var networkIndex = e.target.value;
72 networks[network].onSelect(); 76 networks[networkIndex].onSelect();
73 delayedPhraseChanged(); 77 if (seed != null) {
78 phraseChanged();
79 }
80 else {
81 rootKeyChanged();
82 }
74 } 83 }
75 84
76 function delayedPhraseChanged() { 85 function delayedPhraseChanged() {
@@ -87,12 +96,57 @@
87 hideValidationError(); 96 hideValidationError();
88 // Get the mnemonic phrase 97 // Get the mnemonic phrase
89 var phrase = DOM.phrase.val(); 98 var phrase = DOM.phrase.val();
90 var passphrase = DOM.passphrase.val();
91 var errorText = findPhraseErrors(phrase); 99 var errorText = findPhraseErrors(phrase);
92 if (errorText) { 100 if (errorText) {
93 showValidationError(errorText); 101 showValidationError(errorText);
94 return; 102 return;
95 } 103 }
104 // Calculate and display
105 var passphrase = DOM.passphrase.val();
106 calcBip32RootKeyFromSeed(phrase, passphrase);
107 calcForDerivationPath();
108 hidePending();
109 }
110
111 function delayedRootKeyChanged() {
112 // Warn if there is an existing mnemonic or passphrase.
113 if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) {
114 if (!confirm("This will clear existing mnemonic and passphrase")) {
115 DOM.rootKey.val(bip32RootKey);
116 return
117 }
118 }
119 hideValidationError();
120 showPending();
121 // Clear existing mnemonic and passphrase
122 DOM.phrase.val("");
123 DOM.passphrase.val("");
124 seed = null;
125 if (rootKeyChangedTimeoutEvent != null) {
126 clearTimeout(rootKeyChangedTimeoutEvent);
127 }
128 rootKeyChangedTimeoutEvent = setTimeout(rootKeyChanged, 400);
129 }
130
131 function rootKeyChanged() {
132 showPending();
133 hideValidationError();
134 // Validate the root key TODO
135 var rootKeyBase58 = DOM.rootKey.val();
136 var errorText = validateRootKey(rootKeyBase58);
137 if (errorText) {
138 showValidationError(errorText);
139 return;
140 }
141 // Calculate and display
142 calcBip32RootKeyFromBase58(rootKeyBase58);
143 calcForDerivationPath();
144 hidePending();
145 }
146
147 function calcForDerivationPath() {
148 showPending();
149 hideValidationError();
96 // Get the derivation path 150 // Get the derivation path
97 var derivationPath = getDerivationPath(); 151 var derivationPath = getDerivationPath();
98 var errorText = findDerivationPathErrors(derivationPath); 152 var errorText = findDerivationPathErrors(derivationPath);
@@ -100,8 +154,7 @@
100 showValidationError(errorText); 154 showValidationError(errorText);
101 return; 155 return;
102 } 156 }
103 // Calculate and display 157 calcBip32ExtendedKey(derivationPath);
104 calcBip32Seed(phrase, passphrase, derivationPath);
105 displayBip32Info(); 158 displayBip32Info();
106 hidePending(); 159 hidePending();
107 } 160 }
@@ -148,9 +201,16 @@
148 return words; 201 return words;
149 } 202 }
150 203
151 function calcBip32Seed(phrase, passphrase, path) { 204 function calcBip32RootKeyFromSeed(phrase, passphrase) {
152 seed = mnemonic.toSeed(phrase, passphrase); 205 seed = mnemonic.toSeed(phrase, passphrase);
153 bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network); 206 bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network);
207 }
208
209 function calcBip32RootKeyFromBase58(rootKeyBase58) {
210 bip32RootKey = bitcoin.HDNode.fromBase58(rootKeyBase58);
211 }
212
213 function calcBip32ExtendedKey(path) {
154 bip32ExtendedKey = bip32RootKey; 214 bip32ExtendedKey = bip32RootKey;
155 // Derive the key from the path 215 // Derive the key from the path
156 var pathBits = path.split("/"); 216 var pathBits = path.split("/");
@@ -213,6 +273,16 @@
213 return false; 273 return false;
214 } 274 }
215 275
276 function validateRootKey(rootKeyBase58) {
277 try {
278 bitcoin.HDNode.fromBase58(rootKeyBase58);
279 }
280 catch (e) {
281 return "Invalid root key";
282 }
283 return "";
284 }
285
216 function getDerivationPath() { 286 function getDerivationPath() {
217 if (DOM.bip44tab.hasClass("active")) { 287 if (DOM.bip44tab.hasClass("active")) {
218 var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44); 288 var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
@@ -299,16 +369,27 @@
299 369
300 function TableRow(index) { 370 function TableRow(index) {
301 371
372 var useHardenedAddresses = DOM.hardenedAddresses.prop("checked");
373
302 function init() { 374 function init() {
303 calculateValues(); 375 calculateValues();
304 } 376 }
305 377
306 function calculateValues() { 378 function calculateValues() {
307 setTimeout(function() { 379 setTimeout(function() {
308 var key = bip32ExtendedKey.derive(index); 380 var key = "";
381 if (useHardenedAddresses) {
382 key = bip32ExtendedKey.deriveHardened(index);
383 }
384 else {
385 key = bip32ExtendedKey.derive(index);
386 }
309 var address = key.getAddress().toString(); 387 var address = key.getAddress().toString();
310 var privkey = key.privKey.toWIF(network); 388 var privkey = key.privKey.toWIF(network);
311 var indexText = getDerivationPath() + "/" + index; 389 var indexText = getDerivationPath() + "/" + index;
390 if (useHardenedAddresses) {
391 indexText = indexText + "'";
392 }
312 addAddressToList(indexText, address, privkey); 393 addAddressToList(indexText, address, privkey);
313 }, 50) 394 }, 50)
314 } 395 }