]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blob - src/js/index.js
3 var mnemonic
= new Mnemonic("english");
5 var bip32RootKey
= null;
6 var bip32ExtendedKey
= null;
7 var network
= bitcoin
.networks
.bitcoin
;
8 var addressRowTemplate
= $("#address-row-template");
11 var showAddress
= true;
12 var showPrivKey
= true;
14 var phraseChangeTimeoutEvent
= null;
17 DOM
.network
= $(".network");
18 DOM
.phraseNetwork
= $("#network-phrase");
19 DOM
.phrase
= $(".phrase");
20 DOM
.passphrase
= $(".passphrase");
21 DOM
.generate
= $(".generate");
22 DOM
.seed
= $(".seed");
23 DOM
.rootKey
= $(".root-key");
24 DOM
.extendedPrivKey
= $(".extended-priv-key");
25 DOM
.extendedPubKey
= $(".extended-pub-key");
26 DOM
.bip32tab
= $("#bip32-tab");
27 DOM
.bip44tab
= $("#bip44-tab");
28 DOM
.bip32panel
= $("#bip32");
29 DOM
.bip44panel
= $("#bip44");
30 DOM
.bip32path
= $("#bip32-path");
31 DOM
.bip44path
= $("#bip44-path");
32 DOM
.bip44purpose
= $("#bip44 .purpose");
33 DOM
.bip44coin
= $("#bip44 .coin");
34 DOM
.bip44account
= $("#bip44 .account");
35 DOM
.bip44change
= $("#bip44 .change");
36 DOM
.strength
= $(".strength");
37 DOM
.addresses
= $(".addresses");
38 DOM
.rowsToAdd
= $(".rows-to-add");
39 DOM
.more
= $(".more");
40 DOM
.feedback
= $(".feedback");
41 DOM
.tab
= $(".derivation-type a");
42 DOM
.indexToggle
= $(".index-toggle");
43 DOM
.addressToggle
= $(".address-toggle");
44 DOM
.privateKeyToggle
= $(".private-key-toggle");
46 var derivationPath
= $(".tab-pane.active .path").val();
50 DOM
.network
.on("change", networkChanged
);
51 DOM
.phrase
.on("input", delayedPhraseChanged
);
52 DOM
.passphrase
.on("input", delayedPhraseChanged
);
53 DOM
.generate
.on("click", generateClicked
);
54 DOM
.more
.on("click", showMore
);
55 DOM
.bip32path
.on("input", bip32Changed
);
56 DOM
.bip44purpose
.on("input", bip44Changed
);
57 DOM
.bip44coin
.on("input", bip44Changed
);
58 DOM
.bip44account
.on("input", bip44Changed
);
59 DOM
.bip44change
.on("input", bip44Changed
);
60 DOM
.tab
.on("click", tabClicked
);
61 DOM
.indexToggle
.on("click", toggleIndexes
);
62 DOM
.addressToggle
.on("click", toggleAddresses
);
63 DOM
.privateKeyToggle
.on("click", togglePrivateKeys
);
66 hideValidationError();
67 populateNetworkSelect();
72 function networkChanged(e
) {
73 var network
= e
.target
.value
;
74 networks
[network
].onSelect();
75 setBip44DerivationPath();
76 delayedPhraseChanged();
79 function delayedPhraseChanged() {
80 hideValidationError();
82 if (phraseChangeTimeoutEvent
!= null) {
83 clearTimeout(phraseChangeTimeoutEvent
);
85 phraseChangeTimeoutEvent
= setTimeout(phraseChanged
, 400);
88 function phraseChanged() {
90 hideValidationError();
91 // Get the mnemonic phrase
92 var phrase
= DOM
.phrase
.val();
93 var passphrase
= DOM
.passphrase
.val();
94 var errorText
= findPhraseErrors(phrase
);
96 showValidationError(errorText
);
99 // Get the derivation path
100 var errorText
= findDerivationPathErrors();
102 showValidationError(errorText
);
105 // Calculate and display
106 calcBip32Seed(phrase
, passphrase
, derivationPath
);
111 function generateClicked() {
114 setTimeout(function() {
115 var phrase
= generateRandomPhrase();
123 function tabClicked(e
) {
124 var activePath
= $(e
.target
.getAttribute("href") + " .path");
125 derivationPath
= activePath
.val();
129 function derivationChanged() {
130 delayedPhraseChanged();
133 function bip32Changed() {
134 derivationPath
= DOM
.bip32path
.val();
138 function bip44Changed() {
139 setBip44DerivationPath();
143 function toggleIndexes() {
144 showIndex
= !showIndex
;
145 $("td.index span").toggleClass("invisible");
148 function toggleAddresses() {
149 showAddress
= !showAddress
;
150 $("td.address span").toggleClass("invisible");
153 function togglePrivateKeys() {
154 showPrivKey
= !showPrivKey
;
155 $("td.privkey span").toggleClass("invisible");
160 function generateRandomPhrase() {
161 if (!hasStrongRandom()) {
162 var errorText
= "This browser does not support strong randomness";
163 showValidationError(errorText
);
166 var numWords
= parseInt(DOM
.strength
.val());
167 var strength
= numWords
/ 3 * 32;
168 var words
= mnemonic
.generate(strength
);
169 DOM
.phrase
.val(words
);
173 function calcBip32Seed(phrase
, passphrase
, path
) {
174 seed
= mnemonic
.toSeed(phrase
, passphrase
);
175 bip32RootKey
= bitcoin
.HDNode
.fromSeedHex(seed
, network
);
176 bip32ExtendedKey
= bip32RootKey
;
177 // Derive the key from the path
178 var pathBits
= path
.split("/");
179 for (var i
=0; i
<pathBits
.length
; i
++) {
180 var bit
= pathBits
[i
];
181 var index
= parseInt(bit
);
185 var hardened
= bit
[bit
.length
-1] == "'";
187 bip32ExtendedKey
= bip32ExtendedKey
.deriveHardened(index
);
190 bip32ExtendedKey
= bip32ExtendedKey
.derive(index
);
195 function showValidationError(errorText
) {
201 function hideValidationError() {
207 function findPhraseErrors(phrase
) {
208 // TODO make this right
209 // Preprocess the words
210 phrase
= mnemonic
.normalizeString(phrase
);
211 var parts
= phrase
.split(" ");
213 for (var i
=0; i
<parts
.length
; i
++) {
215 if (part
.length
> 0) {
216 // TODO check that lowercasing is always valid to do
217 proper
.push(part
.toLowerCase());
220 // TODO some levenstein on the words
221 var properPhrase
= proper
.join(' ');
222 // Check the words are valid
223 var isValid
= mnemonic
.check(properPhrase
);
225 return "Invalid mnemonic";
230 function findDerivationPathErrors(path
) {
235 function displayBip32Info() {
238 var rootKey
= bip32RootKey
.toBase58();
239 DOM
.rootKey
.val(rootKey
);
240 var extendedPrivKey
= bip32ExtendedKey
.toBase58();
241 DOM
.extendedPrivKey
.val(extendedPrivKey
);
242 var extendedPubKey
= bip32ExtendedKey
.toBase58(false);
243 DOM
.extendedPubKey
.val(extendedPubKey
);
244 // Display the addresses and privkeys
245 clearAddressesList();
246 displayAddresses(0, 20);
249 function displayAddresses(start
, total
) {
250 for (var i
=0; i
<total
; i
++) {
251 var index
= i
+ start
;
256 function TableRow(index
) {
262 function calculateValues() {
263 setTimeout(function() {
264 var key
= bip32ExtendedKey
.derive(index
);
265 var address
= key
.getAddress().toString();
266 var privkey
= key
.privKey
.toWIF(network
);
267 addAddressToList(index
, address
, privkey
);
275 function showMore() {
276 var start
= DOM
.addresses
.children().length
;
277 var rowsToAdd
= parseInt(DOM
.rowsToAdd
.val());
278 if (isNaN(rowsToAdd
)) {
280 DOM
.rowsToAdd
.val("20");
282 if (rowsToAdd
> 200) {
283 var msg
= "Generating " + rowsToAdd
+ " rows could take a while. ";
284 msg
+= "Do you want to continue?";
289 displayAddresses(start
, rowsToAdd
);
292 function clearDisplay() {
293 clearAddressesList();
295 hideValidationError();
298 function clearAddressesList() {
299 DOM
.addresses
.empty();
302 function clearKey() {
304 DOM
.extendedPrivKey
.val("");
305 DOM
.extendedPubKey
.val("");
308 function addAddressToList(index
, address
, privkey
) {
309 var row
= $(addressRowTemplate
.html());
311 var indexCell
= row
.find(".index span");
312 var addressCell
= row
.find(".address span");
313 var privkeyCell
= row
.find(".privkey span");
315 var indexText
= derivationPath
+ "/" + index
;
316 indexCell
.text(indexText
);
317 addressCell
.text(address
);
318 privkeyCell
.text(privkey
);
321 indexCell
.addClass("invisible");
324 addressCell
.addClass("invisible");
327 privkeyCell
.addClass("invisible");
329 DOM
.addresses
.append(row
);
332 function hasStrongRandom() {
333 return 'crypto' in window
&& window
['crypto'] !== null;
336 function disableForms() {
337 $("form").on("submit", function(e
) {
342 function setBip44DerivationPath() {
343 var purpose
= parseIntNoNaN(DOM
.bip44purpose
.val(), 44);
344 var coin
= parseIntNoNaN(DOM
.bip44coin
.val(), 0);
345 var account
= parseIntNoNaN(DOM
.bip44account
.val(), 0);
346 var change
= parseIntNoNaN(DOM
.bip44change
.val(), 0);
348 path
+= purpose
+ "'/";
350 path
+= account
+ "'/";
352 DOM
.bip44path
.val(path
);
353 derivationPath
= DOM
.bip44path
.val();
356 function parseIntNoNaN(val
, defaultVal
) {
357 var v
= parseInt(val
);
364 function showPending() {
366 .text("Calculating...")
370 function hidePending() {
376 function populateNetworkSelect() {
377 for (var i
=0; i
<networks
.length
; i
++) {
378 var network
= networks
[i
];
379 var option
= $("<option>");
380 option
.attr("value", i
);
381 option
.text(network
.name
);
382 DOM
.phraseNetwork
.append(option
);
389 onSelect: function() {
390 network
= bitcoin
.networks
.bitcoin
;
391 DOM
.bip44coin
.val(0);
395 name: "Bitcoin Testnet",
396 onSelect: function() {
397 network
= bitcoin
.networks
.testnet
;
398 DOM
.bip44coin
.val(1);
403 onSelect: function() {
404 network
= bitcoin
.networks
.litecoin
;
405 DOM
.bip44coin
.val(2);
410 onSelect: function() {
411 network
= bitcoin
.networks
.dogecoin
;
412 DOM
.bip44coin
.val(3);
417 onSelect: function() {
418 network
= bitcoin
.networks
.shadow
;
419 DOM
.bip44coin
.val(35);
423 name: "ShadowCash Testnet",
424 onSelect: function() {
425 network
= bitcoin
.networks
.shadowtn
;
426 DOM
.bip44coin
.val(1);
431 onSelect: function() {
432 network
= bitcoin
.networks
.viacoin
;
433 DOM
.bip44coin
.val(14);
437 name: "Viacoin Testnet",
438 onSelect: function() {
439 network
= bitcoin
.networks
.viacointestnet
;
440 DOM
.bip44coin
.val(1);
445 onSelect: function() {
446 network
= bitcoin
.networks
.jumbucks
;
447 DOM
.bip44coin
.val(26);
452 onSelect: function() {
453 network
= bitcoin
.networks
.clam
;
454 DOM
.bip44coin
.val(23);