]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blame - tests.js
deleting the remaining checksum from the private key
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / tests.js
CommitLineData
88e2cdaa
IC
1// Usage:
2// $ phantomjs tests.js
3
4
5var page = require('webpage').create();
6var url = 'src/index.html';
ddeb8613 7var testMaxTime = 20000;
88e2cdaa 8
e00964cc
IC
9page.viewportSize = {
10 width: 1024,
11 height: 720
12};
13
88e2cdaa
IC
14page.onResourceError = function(e) {
15 console.log("Error loading " + e.url);
16 phantom.exit();
17}
18
19function fail() {
20 console.log("Failed");
21 phantom.exit();
22}
23
3eef9d0d
IC
24function waitForGenerate(fn, maxTime) {
25 if (!maxTime) {
26 maxTime = testMaxTime;
27 }
28 var start = new Date().getTime();
29 var prevAddressCount = -1;
30 var wait = function keepWaiting() {
31 var now = new Date().getTime();
32 var hasTimedOut = now - start > maxTime;
33 var addressCount = page.evaluate(function() {
34 return $(".address").length;
35 });
36 var hasFinished = addressCount > 0 && addressCount == prevAddressCount;
37 prevAddressCount = addressCount;
38 if (hasFinished) {
39 fn();
40 }
41 else if (hasTimedOut) {
42 console.log("Test timed out");
43 fn();
44 }
45 else {
46 setTimeout(keepWaiting, 100);
47 }
48 }
49 wait();
50}
51
c3719b00
IC
52function waitForFeedback(fn, maxTime) {
53 if (!maxTime) {
54 maxTime = testMaxTime;
55 }
56 var start = new Date().getTime();
57 var wait = function keepWaiting() {
58 var now = new Date().getTime();
59 var hasTimedOut = now - start > maxTime;
60 if (hasTimedOut) {
61 console.log("Test timed out");
62 fn();
63 return;
64 }
65 var feedback = page.evaluate(function() {
66 var feedback = $(".feedback");
67 if (feedback.css("display") == "none") {
68 return "";
69 }
70 return feedback.text();
71 });
72 var hasFinished = feedback.length > 0 && feedback != "Calculating...";
73 if (hasFinished) {
74 fn();
75 }
76 else {
77 setTimeout(keepWaiting, 100);
78 }
79 }
80 wait();
81}
82
057722b0
IC
83function waitForEntropyFeedback(fn, maxTime) {
84 if (!maxTime) {
85 maxTime = testMaxTime;
86 }
87 var origFeedback = page.evaluate(function() {
dd944906 88 return $(".entropy-container").text();
057722b0
IC
89 });
90 var start = new Date().getTime();
91 var wait = function keepWaiting() {
92 var now = new Date().getTime();
93 var hasTimedOut = now - start > maxTime;
94 if (hasTimedOut) {
95 console.log("Test timed out");
96 fn();
97 return;
98 }
99 var feedback = page.evaluate(function() {
dd944906 100 return $(".entropy-container").text();
057722b0
IC
101 });
102 var hasFinished = feedback != origFeedback;
103 if (hasFinished) {
104 fn();
105 }
106 else {
107 setTimeout(keepWaiting, 100);
108 }
109 }
110 wait();
111}
112
88e2cdaa
IC
113function next() {
114 if (tests.length > 0) {
115 var testsStr = tests.length == 1 ? "test" : "tests";
116 console.log(tests.length + " " + testsStr + " remaining");
117 tests.shift()();
118 }
119 else {
120 console.log("Finished with 0 failures");
121 phantom.exit();
122 }
123}
124
fb372687
IC
125/**
126 * Randomize array element order in-place.
127 * Using Durstenfeld shuffle algorithm.
128 * See http://stackoverflow.com/a/12646864
129 */
130function shuffle(array) {
131 for (var i = array.length - 1; i > 0; i--) {
132 var j = Math.floor(Math.random() * (i + 1));
133 var temp = array[i];
134 array[i] = array[j];
135 array[j] = temp;
136 }
137 return array;
138}
139
88e2cdaa
IC
140tests = [
141
142// Page loads with status of 'success'
143function() {
144page.open(url, function(status) {
145 if (status != "success") {
146 console.log("Page did not load with status 'success'");
147 fail();
148 }
149 next();
150});
151},
152
153// Page has text
154function() {
155page.open(url, function(status) {
156 var content = page.evaluate(function() {
157 return document.body.textContent.trim();
158 });
159 if (!content) {
160 console.log("Page does not have text");
161 fail();
162 }
163 next();
164});
165},
166
167// Entering mnemonic generates addresses
168function() {
169page.open(url, function(status) {
88e2cdaa
IC
170 // set the phrase
171 page.evaluate(function() {
172 $(".phrase").val("abandon abandon ability").trigger("input");
173 });
174 // get the address
3eef9d0d 175 waitForGenerate(function() {
06c4c6e3
IC
176 var addressCount = page.evaluate(function() {
177 return $(".address").length;
88e2cdaa 178 });
06c4c6e3
IC
179 if (addressCount != 20) {
180 console.log("Mnemonic did not generate addresses");
88e2cdaa
IC
181 console.log("Expected: " + expected);
182 console.log("Got: " + actual);
183 fail();
184 }
185 next();
3eef9d0d 186 });
88e2cdaa
IC
187});
188},
189
190// Random button generates random mnemonic
191function() {
192page.open(url, function(status) {
193 // check initial phrase is empty
194 var phrase = page.evaluate(function() {
195 return $(".phrase").text();
196 });
197 if (phrase != "") {
198 console.log("Initial phrase is not blank");
199 fail();
200 }
201 // press the 'generate' button
202 page.evaluate(function() {
203 $(".generate").click();
204 });
205 // get the new phrase
3eef9d0d 206 waitForGenerate(function() {
88e2cdaa
IC
207 var phrase = page.evaluate(function() {
208 return $(".phrase").val();
209 });
210 if (phrase.length <= 0) {
211 console.log("Phrase not generated by pressing button");
212 fail();
213 }
214 next();
3eef9d0d 215 });
88e2cdaa
IC
216});
217},
218
219// Mnemonic length can be customized
220function() {
221page.open(url, function(status) {
222 // set the length to 6
54563907 223 var expectedLength = "6";
88e2cdaa 224 page.evaluate(function() {
54563907
IC
225 $(".strength option[selected]").removeAttr("selected");
226 $(".strength option[value=6]").prop("selected", true);
88e2cdaa
IC
227 });
228 // press the 'generate' button
229 page.evaluate(function() {
230 $(".generate").click();
231 });
232 // check the new phrase is six words long
3eef9d0d 233 waitForGenerate(function() {
88e2cdaa
IC
234 var actualLength = page.evaluate(function() {
235 var words = $(".phrase").val().split(" ");
236 return words.length;
237 });
238 if (actualLength != expectedLength) {
239 console.log("Phrase not generated with correct length");
240 console.log("Expected: " + expectedLength);
241 console.log("Actual: " + actualLength);
242 fail();
243 }
54563907 244 next();
3eef9d0d 245 });
88e2cdaa
IC
246});
247},
248
88e2cdaa 249// Passphrase can be set
54563907
IC
250function() {
251page.open(url, function(status) {
252 // set the phrase and passphrase
253 var expected = "15pJzUWPGzR7avffV9nY5by4PSgSKG9rba";
254 page.evaluate(function() {
255 $(".phrase").val("abandon abandon ability");
256 $(".passphrase").val("secure_passphrase").trigger("input");
257 });
258 // check the address is generated correctly
3eef9d0d 259 waitForGenerate(function() {
54563907
IC
260 var actual = page.evaluate(function() {
261 return $(".address:first").text();
262 });
263 if (actual != expected) {
264 console.log("Passphrase results in wrong address");
265 console.log("Expected: " + expected);
266 console.log("Actual: " + actual);
267 fail();
268 }
269 next();
3eef9d0d 270 });
54563907
IC
271});
272},
273
88e2cdaa 274// Network can be set to bitcoin testnet
54563907
IC
275function() {
276page.open(url, function(status) {
59193779 277 // set the phrase and coin
54563907
IC
278 var expected = "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi";
279 page.evaluate(function() {
280 $(".phrase").val("abandon abandon ability");
281 $(".phrase").trigger("input");
282 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
283 $(".network option").filter(function() {
284 return $(this).html() == "Bitcoin Testnet";
285 }).prop("selected", true);
54563907
IC
286 $(".network").trigger("change");
287 });
288 // check the address is generated correctly
3eef9d0d 289 waitForGenerate(function() {
54563907
IC
290 var actual = page.evaluate(function() {
291 return $(".address:first").text();
292 });
293 if (actual != expected) {
294 console.log("Bitcoin testnet address is incorrect");
295 console.log("Expected: " + expected);
296 console.log("Actual: " + actual);
297 fail();
298 }
299 next();
3eef9d0d 300 });
54563907
IC
301});
302},
303
88e2cdaa 304// Network can be set to litecoin
59193779
IC
305function() {
306page.open(url, function(status) {
307 // set the phrase and coin
308 var expected = "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn";
309 page.evaluate(function() {
310 $(".phrase").val("abandon abandon ability");
311 $(".phrase").trigger("input");
312 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
313 $(".network option").filter(function() {
314 return $(this).html() == "Litecoin";
315 }).prop("selected", true);
59193779 316 $(".network").trigger("change");
a96cfdf3 317 });
318 // check the address is generated correctly
319 waitForGenerate(function() {
320 var actual = page.evaluate(function() {
321 return $(".address:first").text();
322 });
323 if (actual != expected) {
324 console.log("Litecoin address is incorrect");
325 console.log("Expected: " + expected);
326 console.log("Actual: " + actual);
327 fail();
328 }
329 next();
330 });
331});
332},
333
334// Network can be set to ripple
335function() {
336page.open(url, function(status) {
337 // set the phrase and coin
338 var expected = "rLTFnqbmCVPGx6VfaygdtuKWJgcN4v1zRS";
339 page.evaluate(function() {
340 $(".phrase").val("ill clump only blind unit burden thing track silver cloth review awake useful craft whale all satisfy else trophy sunset walk vanish hope valve");
341 $(".phrase").trigger("input");
342 $(".network option[selected]").removeAttr("selected");
343 $(".network option").filter(function() {
344 return $(this).html() == "Ripple";
345 }).prop("selected", true);
346 $(".network").trigger("change");
59193779
IC
347 });
348 // check the address is generated correctly
3eef9d0d 349 waitForGenerate(function() {
59193779
IC
350 var actual = page.evaluate(function() {
351 return $(".address:first").text();
352 });
353 if (actual != expected) {
354 console.log("Litecoin address is incorrect");
355 console.log("Expected: " + expected);
356 console.log("Actual: " + actual);
357 fail();
358 }
359 next();
3eef9d0d 360 });
59193779
IC
361});
362},
363
88e2cdaa 364// Network can be set to dogecoin
59193779
IC
365function() {
366page.open(url, function(status) {
367 // set the phrase and coin
368 var expected = "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA";
369 page.evaluate(function() {
370 $(".phrase").val("abandon abandon ability");
371 $(".phrase").trigger("input");
372 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
373 $(".network option").filter(function() {
374 return $(this).html() == "Dogecoin";
375 }).prop("selected", true);
59193779
IC
376 $(".network").trigger("change");
377 });
378 // check the address is generated correctly
3eef9d0d 379 waitForGenerate(function() {
59193779
IC
380 var actual = page.evaluate(function() {
381 return $(".address:first").text();
382 });
383 if (actual != expected) {
384 console.log("Dogecoin address is incorrect");
385 console.log("Expected: " + expected);
386 console.log("Actual: " + actual);
387 fail();
388 }
389 next();
3eef9d0d 390 });
59193779
IC
391});
392},
393
88e2cdaa 394// Network can be set to shadowcash
59193779
IC
395function() {
396page.open(url, function(status) {
397 // set the phrase and coin
398 var expected = "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG";
399 page.evaluate(function() {
400 $(".phrase").val("abandon abandon ability");
401 $(".phrase").trigger("input");
402 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
403 $(".network option").filter(function() {
404 return $(this).html() == "ShadowCash";
405 }).prop("selected", true);
59193779
IC
406 $(".network").trigger("change");
407 });
408 // check the address is generated correctly
3eef9d0d 409 waitForGenerate(function() {
59193779
IC
410 var actual = page.evaluate(function() {
411 return $(".address:first").text();
412 });
413 if (actual != expected) {
414 console.log("Shadowcash address is incorrect");
415 console.log("Expected: " + expected);
416 console.log("Actual: " + actual);
417 fail();
418 }
419 next();
3eef9d0d 420 });
59193779
IC
421});
422},
423
88e2cdaa 424// Network can be set to shadowcash testnet
59193779
IC
425function() {
426page.open(url, function(status) {
427 // set the phrase and coin
428 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
429 page.evaluate(function() {
430 $(".phrase").val("abandon abandon ability");
431 $(".phrase").trigger("input");
432 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
433 $(".network option").filter(function() {
434 return $(this).html() == "ShadowCash Testnet";
435 }).prop("selected", true);
59193779
IC
436 $(".network").trigger("change");
437 });
438 // check the address is generated correctly
3eef9d0d 439 waitForGenerate(function() {
59193779
IC
440 var actual = page.evaluate(function() {
441 return $(".address:first").text();
442 });
443 if (actual != expected) {
444 console.log("Shadowcash testnet address is incorrect");
445 console.log("Expected: " + expected);
446 console.log("Actual: " + actual);
447 fail();
448 }
449 next();
3eef9d0d 450 });
59193779
IC
451});
452},
453
88e2cdaa 454// Network can be set to viacoin
59193779
IC
455function() {
456page.open(url, function(status) {
457 // set the phrase and coin
458 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
459 page.evaluate(function() {
460 $(".phrase").val("abandon abandon ability");
461 $(".phrase").trigger("input");
462 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
463 $(".network option").filter(function() {
464 return $(this).html() == "Viacoin";
465 }).prop("selected", true);
59193779
IC
466 $(".network").trigger("change");
467 });
468 // check the address is generated correctly
3eef9d0d 469 waitForGenerate(function() {
59193779
IC
470 var actual = page.evaluate(function() {
471 return $(".address:first").text();
472 });
473 if (actual != expected) {
474 console.log("Viacoin address is incorrect");
475 console.log("Expected: " + expected);
476 console.log("Actual: " + actual);
477 fail();
478 }
479 next();
3eef9d0d 480 });
59193779
IC
481});
482},
483
88e2cdaa 484// Network can be set to viacoin testnet
59193779
IC
485function() {
486page.open(url, function(status) {
487 // set the phrase and coin
488 var expected = "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe";
489 page.evaluate(function() {
490 $(".phrase").val("abandon abandon ability");
491 $(".phrase").trigger("input");
492 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
493 $(".network option").filter(function() {
494 return $(this).html() == "Viacoin Testnet";
495 }).prop("selected", true);
59193779
IC
496 $(".network").trigger("change");
497 });
498 // check the address is generated correctly
3eef9d0d 499 waitForGenerate(function() {
59193779
IC
500 var actual = page.evaluate(function() {
501 return $(".address:first").text();
502 });
503 if (actual != expected) {
504 console.log("Viacoin testnet address is incorrect");
505 console.log("Expected: " + expected);
506 console.log("Actual: " + actual);
507 fail();
508 }
509 next();
3eef9d0d 510 });
59193779
IC
511});
512},
513
88e2cdaa 514// Network can be set to jumbucks
59193779
IC
515function() {
516page.open(url, function(status) {
517 // set the phrase and coin
518 var expected = "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew";
519 page.evaluate(function() {
520 $(".phrase").val("abandon abandon ability");
521 $(".phrase").trigger("input");
522 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
523 $(".network option").filter(function() {
524 return $(this).html() == "Jumbucks";
525 }).prop("selected", true);
59193779
IC
526 $(".network").trigger("change");
527 });
528 // check the address is generated correctly
3eef9d0d 529 waitForGenerate(function() {
59193779
IC
530 var actual = page.evaluate(function() {
531 return $(".address:first").text();
532 });
533 if (actual != expected) {
534 console.log("Jumbucks address is incorrect");
535 console.log("Expected: " + expected);
536 console.log("Actual: " + actual);
537 fail();
538 }
539 next();
3eef9d0d 540 });
59193779
IC
541});
542},
543
88e2cdaa 544// Network can be set to clam
59193779
IC
545function() {
546page.open(url, function(status) {
547 // set the phrase and coin
548 var expected = "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y";
549 page.evaluate(function() {
550 $(".phrase").val("abandon abandon ability");
551 $(".phrase").trigger("input");
552 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
553 $(".network option").filter(function() {
554 return $(this).html() == "CLAM";
555 }).prop("selected", true);
59193779
IC
556 $(".network").trigger("change");
557 });
558 // check the address is generated correctly
3eef9d0d 559 waitForGenerate(function() {
59193779
IC
560 var actual = page.evaluate(function() {
561 return $(".address:first").text();
562 });
563 if (actual != expected) {
564 console.log("CLAM address is incorrect");
565 console.log("Expected: " + expected);
566 console.log("Actual: " + actual);
567 fail();
f3fad1b5
IC
568 }
569 next();
570 });
571});
572},
573
574// Network can be set to dash
575function() {
576page.open(url, function(status) {
577 // set the phrase and coin
578 var expected = "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT";
579 page.evaluate(function() {
580 $(".phrase").val("abandon abandon ability");
581 $(".phrase").trigger("input");
582 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
583 $(".network option").filter(function() {
584 return $(this).html() == "DASH";
585 }).prop("selected", true);
f3fad1b5
IC
586 $(".network").trigger("change");
587 });
588 // check the address is generated correctly
589 waitForGenerate(function() {
590 var actual = page.evaluate(function() {
591 return $(".address:first").text();
592 });
593 if (actual != expected) {
594 console.log("DASH address is incorrect");
595 console.log("Expected: " + expected);
596 console.log("Actual: " + actual);
597 fail();
00fd1a03 598 }
599 next();
600 });
601});
602},
603
604// Network can be set to game
605function() {
606page.open(url, function(status) {
607 // set the phrase and coin
608 var expected = "GSMY9bAp36cMR4zyT4uGVS7GFjpdXbao5Q";
609 page.evaluate(function() {
610 $(".phrase").val("abandon abandon ability");
611 $(".phrase").trigger("input");
612 $(".network option[selected]").removeAttr("selected");
613 $(".network option").filter(function() {
614 return $(this).html() == "GAME";
615 }).prop("selected", true);
616 $(".network").trigger("change");
617 });
618 // check the address is generated correctly
619 waitForGenerate(function() {
620 var actual = page.evaluate(function() {
621 return $(".address:first").text();
622 });
623 if (actual != expected) {
624 console.log("GAME address is incorrect");
625 console.log("Expected: " + expected);
626 console.log("Actual: " + actual);
627 fail();
59193779 628 }
bfb3dab6
IC
629 next();
630 });
631});
632},
633
634// Network can be set to namecoin
635function() {
636page.open(url, function(status) {
637 // set the phrase and coin
638 var expected = "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2";
639 page.evaluate(function() {
640 $(".phrase").val("abandon abandon ability");
641 $(".phrase").trigger("input");
642 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
643 $(".network option").filter(function() {
644 return $(this).html() == "Namecoin";
645 }).prop("selected", true);
bfb3dab6
IC
646 $(".network").trigger("change");
647 });
648 // check the address is generated correctly
649 waitForGenerate(function() {
650 var actual = page.evaluate(function() {
651 return $(".address:first").text();
652 });
653 if (actual != expected) {
654 console.log("Namecoin address is incorrect");
655 console.log("Expected: " + expected);
656 console.log("Actual: " + actual);
657 fail();
658 }
659 next();
660 });
661});
662},
663
664// Network can be set to peercoin
665function() {
666page.open(url, function(status) {
667 // set the phrase and coin
668 var expected = "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm";
669 page.evaluate(function() {
670 $(".phrase").val("abandon abandon ability");
671 $(".phrase").trigger("input");
672 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
673 $(".network option").filter(function() {
674 return $(this).html() == "Peercoin";
675 }).prop("selected", true);
bfb3dab6
IC
676 $(".network").trigger("change");
677 });
678 // check the address is generated correctly
679 waitForGenerate(function() {
680 var actual = page.evaluate(function() {
681 return $(".address:first").text();
682 });
683 if (actual != expected) {
684 console.log("Peercoin address is incorrect");
685 console.log("Expected: " + expected);
686 console.log("Actual: " + actual);
687 fail();
688 }
59193779 689 next();
3eef9d0d 690 });
59193779
IC
691});
692},
693
24137d96
IC
694// Network can be set to ethereum
695function() {
696
697page.open(url, function(status) {
698
699 // set the phrase and coin
700 page.evaluate(function() {
701 $(".phrase").val("abandon abandon ability");
702 $(".phrase").trigger("input");
703 $(".network option[selected]").removeAttr("selected");
52d589ea
IC
704 $(".network option").filter(function() {
705 return $(this).html() == "Ethereum";
706 }).prop("selected", true);
24137d96
IC
707 $(".network").trigger("change");
708 });
709 waitForGenerate(function() {
710 // check the address is generated correctly
711 // this value comes from
712 // https://www.myetherwallet.com/#view-wallet-info
49b21f12 713 // Unusual capitalization is due to checksum
24137d96
IC
714 var expected = "0xe5815d5902Ad612d49283DEdEc02100Bd44C2772";
715 var actual = page.evaluate(function() {
716 return $(".address:first").text();
717 });
49b21f12 718 if (actual != expected) {
24137d96
IC
719 console.log("Ethereum address is incorrect");
720 console.log("Expected: " + expected);
721 console.log("Actual: " + actual);
722 fail();
723 }
724 // check the private key is correct
725 // this private key can be imported into
726 // https://www.myetherwallet.com/#view-wallet-info
727 // and it should correlate to the address above
728 var expected = "8f253078b73d7498302bb78c171b23ce7a8fb511987d2b2702b731638a4a15e7";
729 var actual = page.evaluate(function() {
730 return $(".privkey:first").text();
731 });
732 if (actual != expected) {
733 console.log("Ethereum privkey is incorrect");
734 console.log("Expected: " + expected);
735 console.log("Actual: " + actual);
736 fail();
737 }
738 // check the public key is correct
739 // TODO
740 // don't have any third-party source to generate the expected value
741 //var expected = "?";
742 //var actual = page.evaluate(function() {
743 // return $(".pubkey:first").text();
744 //});
745 //if (actual != expected) {
746 // console.log("Ethereum privkey is incorrect");
747 // console.log("Expected: " + expected);
748 // console.log("Actual: " + actual);
749 // fail();
750 //}
751 next();
752 });
753});
754},
755
88e2cdaa 756// BIP39 seed is set from phrase
c196ad55
IC
757function() {
758page.open(url, function(status) {
759 // set the phrase
760 var expected = "20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3";
761 page.evaluate(function() {
762 $(".phrase").val("abandon abandon ability");
763 $(".phrase").trigger("input");
764 });
765 // check the address is generated correctly
3eef9d0d 766 waitForGenerate(function() {
c196ad55
IC
767 var actual = page.evaluate(function() {
768 return $(".seed").val();
769 });
770 if (actual != expected) {
771 console.log("BIP39 seed is incorrectly generated from mnemonic");
772 console.log("Expected: " + expected);
773 console.log("Actual: " + actual);
774 fail();
775 }
776 next();
3eef9d0d 777 });
c196ad55
IC
778});
779},
780
88e2cdaa 781// BIP32 root key is set from phrase
ec60b662
IC
782function() {
783page.open(url, function(status) {
784 // set the phrase
785 var expected = "xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi";
786 page.evaluate(function() {
787 $(".phrase").val("abandon abandon ability");
788 $(".phrase").trigger("input");
789 });
790 // check the address is generated correctly
3eef9d0d 791 waitForGenerate(function() {
ec60b662
IC
792 var actual = page.evaluate(function() {
793 return $(".root-key").val();
794 });
795 if (actual != expected) {
796 console.log("Root key is incorrectly generated from mnemonic");
797 console.log("Expected: " + expected);
798 console.log("Actual: " + actual);
799 fail();
800 }
801 next();
3eef9d0d 802 });
ec60b662
IC
803});
804},
805
88e2cdaa 806// Tabs show correct addresses when changed
cf7258fd
IC
807function() {
808page.open(url, function(status) {
809 // set the phrase
810 var expected = "17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz";
811 page.evaluate(function() {
812 $(".phrase").val("abandon abandon ability");
813 $(".phrase").trigger("input");
814 });
815 // change tabs
816 waitForGenerate(function() {
817 page.evaluate(function() {
818 $("#bip32-tab a").click();
819 });
820 // check the address is generated correctly
821 waitForGenerate(function() {
822 var actual = page.evaluate(function() {
823 return $(".address:first").text();
824 });
825 if (actual != expected) {
826 console.log("Clicking tab generates incorrect address");
827 console.log("Expected: " + expected);
828 console.log("Actual: " + actual);
829 fail();
830 }
831 next();
832 });
833 });
834});
835},
88e2cdaa
IC
836
837// BIP44 derivation path is shown
d077e1e7
IC
838function() {
839page.open(url, function(status) {
840 // set the phrase
841 var expected = "m/44'/0'/0'/0";
842 page.evaluate(function() {
843 $(".phrase").val("abandon abandon ability");
844 $(".phrase").trigger("input");
845 });
846 // check the derivation path of the first address
847 waitForGenerate(function() {
848 var actual = page.evaluate(function() {
849 return $("#bip44 .path").val();
850 });
851 if (actual != expected) {
852 console.log("BIP44 derivation path is incorrect");
853 console.log("Expected: " + expected);
854 console.log("Actual: " + actual);
855 fail();
856 }
857 next();
858 });
859});
860},
861
88e2cdaa 862// BIP44 extended private key is shown
4fd2925d
IC
863function() {
864page.open(url, function(status) {
865 // set the phrase
866 var expected = "xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG";
867 page.evaluate(function() {
868 $(".phrase").val("abandon abandon ability");
869 $(".phrase").trigger("input");
870 });
06286adb 871 // check the BIP44 extended private key
4fd2925d
IC
872 waitForGenerate(function() {
873 var actual = page.evaluate(function() {
874 return $(".extended-priv-key").val();
875 });
876 if (actual != expected) {
877 console.log("BIP44 extended private key is incorrect");
878 console.log("Expected: " + expected);
879 console.log("Actual: " + actual);
880 fail();
881 }
882 next();
883 });
884});
885},
886
88e2cdaa 887// BIP44 extended public key is shown
39fd45bb
IC
888function() {
889page.open(url, function(status) {
890 // set the phrase
891 var expected = "xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM";
892 page.evaluate(function() {
893 $(".phrase").val("abandon abandon ability");
894 $(".phrase").trigger("input");
895 });
06286adb 896 // check the BIP44 extended public key
39fd45bb
IC
897 waitForGenerate(function() {
898 var actual = page.evaluate(function() {
899 return $(".extended-pub-key").val();
900 });
901 if (actual != expected) {
902 console.log("BIP44 extended public key is incorrect");
903 console.log("Expected: " + expected);
904 console.log("Actual: " + actual);
905 fail();
906 }
907 next();
908 });
909});
910},
911
06286adb
IC
912// BIP44 purpose field changes address list
913function() {
914page.open(url, function(status) {
915 // set the phrase
916 var expected = "1JbDzRJ2cDT8aat2xwKd6Pb2zzavow5MhF";
917 page.evaluate(function() {
918 $(".phrase").val("abandon abandon ability");
919 $(".phrase").trigger("input");
920 });
921 waitForGenerate(function() {
922 // change the bip44 purpose field to 45
923 page.evaluate(function() {
924 $("#bip44 .purpose").val("45");
925 $("#bip44 .purpose").trigger("input");
926 });
927 waitForGenerate(function() {
928 // check the address for the new derivation path
929 var actual = page.evaluate(function() {
930 return $(".address:first").text();
931 });
932 if (actual != expected) {
933 console.log("BIP44 purpose field generates incorrect address");
934 console.log("Expected: " + expected);
935 console.log("Actual: " + actual);
936 fail();
937 }
938 next();
939 });
940 });
941});
942},
943
88e2cdaa 944// BIP44 coin field changes address list
9eb72cdf
IC
945function() {
946page.open(url, function(status) {
947 // set the phrase
948 var expected = "1F6dB2djQYrxoyfZZmfr6D5voH8GkJTghk";
949 page.evaluate(function() {
950 $(".phrase").val("abandon abandon ability");
951 $(".phrase").trigger("input");
952 });
953 waitForGenerate(function() {
954 // change the bip44 purpose field to 45
955 page.evaluate(function() {
956 $("#bip44 .coin").val("1");
957 $("#bip44 .coin").trigger("input");
958 });
959 waitForGenerate(function() {
960 // check the address for the new derivation path
961 var actual = page.evaluate(function() {
962 return $(".address:first").text();
963 });
964 if (actual != expected) {
965 console.log("BIP44 coin field generates incorrect address");
966 console.log("Expected: " + expected);
967 console.log("Actual: " + actual);
968 fail();
969 }
970 next();
971 });
972 });
973});
974},
975
88e2cdaa 976// BIP44 account field changes address list
048bc3e0
IC
977function() {
978page.open(url, function(status) {
979 // set the phrase
980 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
981 page.evaluate(function() {
982 $(".phrase").val("abandon abandon ability");
983 $(".phrase").trigger("input");
984 });
985 waitForGenerate(function() {
986 // change the bip44 purpose field to 45
987 page.evaluate(function() {
988 $("#bip44 .account").val("1");
989 $("#bip44 .account").trigger("input");
990 });
991 waitForGenerate(function() {
992 // check the address for the new derivation path
993 var actual = page.evaluate(function() {
994 return $(".address:first").text();
995 });
996 if (actual != expected) {
997 console.log("BIP44 account field generates incorrect address");
998 console.log("Expected: " + expected);
999 console.log("Actual: " + actual);
1000 fail();
1001 }
1002 next();
1003 });
1004 });
1005});
1006},
1007
fa4da086
IC
1008// BIP44 change field changes address list
1009function() {
1010page.open(url, function(status) {
1011 // set the phrase
1012 var expected = "1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo";
1013 page.evaluate(function() {
1014 $(".phrase").val("abandon abandon ability");
1015 $(".phrase").trigger("input");
1016 });
1017 waitForGenerate(function() {
1018 // change the bip44 purpose field to 45
1019 page.evaluate(function() {
1020 $("#bip44 .change").val("1");
1021 $("#bip44 .change").trigger("input");
1022 });
1023 waitForGenerate(function() {
1024 // check the address for the new derivation path
1025 var actual = page.evaluate(function() {
1026 return $(".address:first").text();
1027 });
1028 if (actual != expected) {
1029 console.log("BIP44 change field generates incorrect address");
1030 console.log("Expected: " + expected);
1031 console.log("Actual: " + actual);
1032 fail();
1033 }
1034 next();
1035 });
1036 });
1037});
1038},
048bc3e0 1039
88e2cdaa 1040// BIP32 derivation path can be set
651382a3
IC
1041function() {
1042page.open(url, function(status) {
1043 // set the phrase
1044 var expected = "16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L";
1045 page.evaluate(function() {
1046 $(".phrase").val("abandon abandon ability");
1047 $(".phrase").trigger("input");
1048 });
1049 // change tabs
1050 waitForGenerate(function() {
1051 page.evaluate(function() {
1052 $("#bip32-tab a").click();
1053 });
1054 // set the derivation path to m/1
1055 waitForGenerate(function() {
1056 page.evaluate(function() {
1057 $("#bip32 .path").val("m/1");
1058 $("#bip32 .path").trigger("input");
1059 });
1060 // check the address is generated correctly
1061 waitForGenerate(function() {
1062 var actual = page.evaluate(function() {
1063 return $(".address:first").text();
1064 });
1065 if (actual != expected) {
1066 console.log("Custom BIP32 path generates incorrect address");
1067 console.log("Expected: " + expected);
1068 console.log("Actual: " + actual);
1069 fail();
1070 }
1071 next();
1072 });
1073 });
1074 });
1075});
1076},
1077
88e2cdaa 1078// BIP32 can use hardened derivation paths
651382a3
IC
1079function() {
1080page.open(url, function(status) {
1081 // set the phrase
1082 var expected = "14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4";
1083 page.evaluate(function() {
1084 $(".phrase").val("abandon abandon ability");
1085 $(".phrase").trigger("input");
1086 });
1087 // change tabs
1088 waitForGenerate(function() {
1089 page.evaluate(function() {
1090 $("#bip32-tab a").click();
1091 });
1092 // set the derivation path to m/0'
1093 waitForGenerate(function() {
1094 page.evaluate(function() {
1095 $("#bip32 .path").val("m/0'");
1096 $("#bip32 .path").trigger("input");
1097 });
1098 // check the address is generated correctly
1099 waitForGenerate(function() {
1100 var actual = page.evaluate(function() {
1101 return $(".address:first").text();
1102 });
1103 if (actual != expected) {
1104 console.log("Hardened BIP32 path generates incorrect address");
1105 console.log("Expected: " + expected);
1106 console.log("Actual: " + actual);
1107 fail();
1108 }
1109 next();
1110 });
1111 });
1112 });
1113});
1114},
1115
88e2cdaa 1116// BIP32 extended private key is shown
9e9dcfda
IC
1117function() {
1118page.open(url, function(status) {
1119 // set the phrase
1120 var expected = "xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe";
1121 page.evaluate(function() {
1122 $(".phrase").val("abandon abandon ability");
1123 $(".phrase").trigger("input");
1124 });
1125 // change tabs
1126 waitForGenerate(function() {
1127 page.evaluate(function() {
1128 $("#bip32-tab a").click();
1129 });
1130 // check the extended private key is generated correctly
1131 waitForGenerate(function() {
1132 var actual = page.evaluate(function() {
1133 return $(".extended-priv-key").val();
1134 });
1135 if (actual != expected) {
1136 console.log("BIP32 extended private key is incorrect");
1137 console.log("Expected: " + expected);
1138 console.log("Actual: " + actual);
1139 fail();
1140 }
1141 next();
1142 });
1143 });
1144});
1145},
1146
88e2cdaa 1147// BIP32 extended public key is shown
9e9dcfda
IC
1148function() {
1149page.open(url, function(status) {
1150 // set the phrase
1151 var expected = "xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P";
1152 page.evaluate(function() {
1153 $(".phrase").val("abandon abandon ability");
1154 $(".phrase").trigger("input");
1155 });
1156 // change tabs
1157 waitForGenerate(function() {
1158 page.evaluate(function() {
1159 $("#bip32-tab a").click();
1160 });
1161 // check the extended public key is generated correctly
1162 waitForGenerate(function() {
1163 var actual = page.evaluate(function() {
1164 return $(".extended-pub-key").val();
1165 });
1166 if (actual != expected) {
1167 console.log("BIP32 extended public key is incorrect");
1168 console.log("Expected: " + expected);
1169 console.log("Actual: " + actual);
1170 fail();
1171 }
1172 next();
1173 });
1174 });
1175});
1176},
88e2cdaa
IC
1177
1178// Derivation path is shown in table
5f844c62
IC
1179function() {
1180page.open(url, function(status) {
1181 // set the phrase
1182 var expected = "m/44'/0'/0'/0/0";
1183 page.evaluate(function() {
1184 $(".phrase").val("abandon abandon ability");
1185 $(".phrase").trigger("input");
1186 });
1187 // check for derivation path in table
1188 waitForGenerate(function() {
1189 var actual = page.evaluate(function() {
1190 return $(".index:first").text();
1191 });
1192 if (actual != expected) {
1193 console.log("Derivation path shown incorrectly in table");
1194 console.log("Expected: " + expected);
1195 console.log("Actual: " + actual);
1196 fail();
1197 }
1198 next();
1199 });
1200});
1201},
1202
88e2cdaa 1203// Derivation path for address can be hardened
4974fd7f
IC
1204function() {
1205page.open(url, function(status) {
1206 // set the phrase
1207 var expected = "18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd";
1208 page.evaluate(function() {
1209 $(".phrase").val("abandon abandon ability");
1210 $(".phrase").trigger("input");
1211 });
1212 // change tabs
1213 waitForGenerate(function() {
1214 page.evaluate(function() {
1215 $("#bip32-tab a").click();
1216 });
1217 waitForGenerate(function() {
1218 // select the hardened addresses option
1219 page.evaluate(function() {
1220 $(".hardened-addresses").prop("checked", true);
1221 $(".hardened-addresses").trigger("change");
1222 });
1223 waitForGenerate(function() {
1224 // check the generated address is hardened
1225 var actual = page.evaluate(function() {
1226 return $(".address:first").text();
1227 });
1228 if (actual != expected) {
1229 console.log("Hardened address is incorrect");
1230 console.log("Expected: " + expected);
1231 console.log("Actual: " + actual);
1232 fail();
1233 }
1234 next();
1235 });
1236 });
1237 });
1238});
1239},
1240
88e2cdaa 1241// Derivation path visibility can be toggled
a775b5c6
IC
1242function() {
1243page.open(url, function(status) {
1244 // set the phrase
1245 page.evaluate(function() {
1246 $(".phrase").val("abandon abandon ability");
1247 $(".phrase").trigger("input");
1248 });
a775b5c6
IC
1249 waitForGenerate(function() {
1250 // toggle path visibility
1251 page.evaluate(function() {
1252 $(".index-toggle").click();
1253 });
1254 // check the path is not visible
1255 var isInvisible = page.evaluate(function() {
1256 return $(".index:first span").hasClass("invisible");
1257 });
1258 if (!isInvisible) {
1259 console.log("Toggled derivation path is visible");
1260 fail();
1261 }
1262 next();
1263 });
1264});
1265},
1266
88e2cdaa 1267// Address is shown
06c4c6e3
IC
1268function() {
1269page.open(url, function(status) {
1270 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1271 // set the phrase
1272 page.evaluate(function() {
1273 $(".phrase").val("abandon abandon ability").trigger("input");
1274 });
1275 // get the address
1276 waitForGenerate(function() {
1277 var actual = page.evaluate(function() {
1278 return $(".address:first").text();
1279 });
1280 if (actual != expected) {
1281 console.log("Address is not shown");
1282 console.log("Expected: " + expected);
1283 console.log("Got: " + actual);
1284 fail();
1285 }
1286 next();
1287 });
1288});
1289},
1290
88e2cdaa 1291// Addresses are shown in order of derivation path
3f1faa4d
IC
1292function() {
1293page.open(url, function(status) {
1294 // set the phrase
1295 page.evaluate(function() {
1296 $(".phrase").val("abandon abandon ability").trigger("input");
1297 });
1298 // get the derivation paths
1299 waitForGenerate(function() {
1300 var paths = page.evaluate(function() {
1301 return $(".index").map(function(i, e) {
1302 return $(e).text();
1303 });
1304 });
1305 if (paths.length != 20) {
1306 console.log("Total paths is less than expected: " + paths.length);
1307 fail();
1308 }
1309 for (var i=0; i<paths.length; i++) {
1310 var expected = "m/44'/0'/0'/0/" + i;
1311 var actual = paths[i];
1312 if (actual != expected) {
1313 console.log("Path " + i + " is incorrect");
1314 console.log("Expected: " + expected);
1315 console.log("Actual: " + actual);
1316 fail();
1317 }
1318 }
1319 next();
1320 });
1321});
1322},
21372fab 1323
88e2cdaa 1324// Address visibility can be toggled
21372fab
IC
1325function() {
1326page.open(url, function(status) {
1327 // set the phrase
1328 page.evaluate(function() {
1329 $(".phrase").val("abandon abandon ability");
1330 $(".phrase").trigger("input");
1331 });
1332 waitForGenerate(function() {
1333 // toggle address visibility
1334 page.evaluate(function() {
1335 $(".address-toggle").click();
1336 });
1337 // check the address is not visible
1338 var isInvisible = page.evaluate(function() {
1339 return $(".address:first span").hasClass("invisible");
1340 });
1341 if (!isInvisible) {
1342 console.log("Toggled address is visible");
1343 fail();
1344 }
1345 next();
1346 });
1347});
1348},
1349
1b12b2f5
IC
1350// Public key is shown
1351function() {
1352page.open(url, function(status) {
1353 var expected = "033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3";
1354 // set the phrase
1355 page.evaluate(function() {
1356 $(".phrase").val("abandon abandon ability").trigger("input");
1357 });
1358 // get the address
1359 waitForGenerate(function() {
1360 var actual = page.evaluate(function() {
1361 return $(".pubkey:first").text();
1362 });
1363 if (actual != expected) {
1364 console.log("Public key is not shown");
1365 console.log("Expected: " + expected);
1366 console.log("Got: " + actual);
1367 fail();
1368 }
1369 next();
1370 });
1371});
1372},
1373
1374// Public key visibility can be toggled
1375function() {
1376page.open(url, function(status) {
1377 // set the phrase
1378 page.evaluate(function() {
1379 $(".phrase").val("abandon abandon ability");
1380 $(".phrase").trigger("input");
1381 });
1382 waitForGenerate(function() {
1383 // toggle public key visibility
1384 page.evaluate(function() {
1385 $(".public-key-toggle").click();
1386 });
1387 // check the public key is not visible
1388 var isInvisible = page.evaluate(function() {
1389 return $(".pubkey:first span").hasClass("invisible");
1390 });
1391 if (!isInvisible) {
1392 console.log("Toggled public key is visible");
1393 fail();
1394 }
1395 next();
1396 });
1397});
1398},
1399
88e2cdaa 1400// Private key is shown
8cd5e231
IC
1401function() {
1402page.open(url, function(status) {
1403 var expected = "L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE";
1404 // set the phrase
1405 page.evaluate(function() {
1406 $(".phrase").val("abandon abandon ability").trigger("input");
1407 });
1408 // get the address
1409 waitForGenerate(function() {
1410 var actual = page.evaluate(function() {
1411 return $(".privkey:first").text();
1412 });
1413 if (actual != expected) {
1414 console.log("Private key is not shown");
1415 console.log("Expected: " + expected);
1416 console.log("Got: " + actual);
1417 fail();
1418 }
1419 next();
1420 });
1421});
1422},
1423
88e2cdaa 1424// Private key visibility can be toggled
6848d03b
IC
1425function() {
1426page.open(url, function(status) {
1427 // set the phrase
1428 page.evaluate(function() {
1429 $(".phrase").val("abandon abandon ability");
1430 $(".phrase").trigger("input");
1431 });
1432 waitForGenerate(function() {
1433 // toggle private key visibility
1434 page.evaluate(function() {
1435 $(".private-key-toggle").click();
1436 });
1437 // check the private key is not visible
1438 var isInvisible = page.evaluate(function() {
1439 return $(".privkey:first span").hasClass("invisible");
1440 });
1441 if (!isInvisible) {
1442 console.log("Toggled private key is visible");
1443 fail();
1444 }
1445 next();
1446 });
1447});
1448},
88e2cdaa
IC
1449
1450// More addresses can be generated
35631659
IC
1451function() {
1452page.open(url, function(status) {
1453 // set the phrase
1454 page.evaluate(function() {
1455 $(".phrase").val("abandon abandon ability");
1456 $(".phrase").trigger("input");
1457 });
1458 waitForGenerate(function() {
1459 // generate more addresses
1460 page.evaluate(function() {
1461 $(".more").click();
1462 });
1463 waitForGenerate(function() {
1464 // check there are more addresses
1465 var addressCount = page.evaluate(function() {
1466 return $(".address").length;
1467 });
1468 if (addressCount != 40) {
1469 console.log("More addresses cannot be generated");
1470 fail();
1471 }
1472 next();
1473 });
1474 });
1475});
1476},
1477
88e2cdaa 1478// A custom number of additional addresses can be generated
8a89b9da
IC
1479function() {
1480page.open(url, function(status) {
1481 // set the phrase
1482 page.evaluate(function() {
1483 $(".phrase").val("abandon abandon ability");
1484 $(".phrase").trigger("input");
1485 });
1486 waitForGenerate(function() {
1487 // get the current number of addresses
1488 var oldAddressCount = page.evaluate(function() {
1489 return $(".address").length;
1490 });
1491 // set a custom number of additional addresses
1492 page.evaluate(function() {
1493 $(".rows-to-add").val(1);
1494 });
1495 // generate more addresses
1496 page.evaluate(function() {
1497 $(".more").click();
1498 });
1499 waitForGenerate(function() {
1500 // check there are the correct number of addresses
1501 var newAddressCount = page.evaluate(function() {
1502 return $(".address").length;
1503 });
1504 if (newAddressCount - oldAddressCount != 1) {
1505 console.log("Number of additional addresses cannot be customized");
1506 console.log(newAddressCount)
1507 console.log(oldAddressCount)
1508 fail();
1509 }
1510 next();
1511 });
1512 });
1513});
1514},
1515
88e2cdaa 1516// Additional addresses are shown in order of derivation path
4d387bf5
IC
1517function() {
1518page.open(url, function(status) {
1519 // set the phrase
1520 page.evaluate(function() {
1521 $(".phrase").val("abandon abandon ability").trigger("input");
1522 });
1523 waitForGenerate(function() {
1524 // generate more addresses
1525 page.evaluate(function() {
1526 $(".more").click();
1527 });
1528 // get the derivation paths
1529 waitForGenerate(function() {
1530 var paths = page.evaluate(function() {
1531 return $(".index").map(function(i, e) {
1532 return $(e).text();
1533 });
1534 });
1535 if (paths.length != 40) {
1536 console.log("Total additional paths is less than expected: " + paths.length);
1537 fail();
1538 }
1539 for (var i=0; i<paths.length; i++) {
1540 var expected = "m/44'/0'/0'/0/" + i;
1541 var actual = paths[i];
1542 if (actual != expected) {
1543 console.log("Path " + i + " is not in correct order");
1544 console.log("Expected: " + expected);
1545 console.log("Actual: " + actual);
1546 fail();
1547 }
1548 }
1549 next();
1550 });
1551 });
1552});
1553},
88e2cdaa
IC
1554
1555// BIP32 root key can be set by the user
61ed16a9
IC
1556function() {
1557page.open(url, function(status) {
1558 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
1559 // set the root key
1560 page.evaluate(function() {
1561 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1562 });
1563 waitForGenerate(function() {
1564 var actual = page.evaluate(function() {
1565 return $(".address:first").text();
1566 });
1567 if (actual != expected) {
bc324fd2 1568 console.log("Setting BIP32 root key results in wrong address");
61ed16a9
IC
1569 console.log("Expected: " + expected);
1570 console.log("Actual: " + actual);
1571 fail();
1572 }
1573 next();
1574 });
1575});
1576},
1577
54563907 1578// Setting BIP32 root key clears the existing phrase, passphrase and seed
bc324fd2
IC
1579function() {
1580page.open(url, function(status) {
1581 var expected = "";
1582 // set a mnemonic
1583 page.evaluate(function() {
1584 $(".phrase").val("A non-blank but invalid value");
1585 });
1586 // Accept any confirm dialogs
1587 page.onConfirm = function() {
1588 return true;
1589 };
1590 // set the root key
1591 page.evaluate(function() {
1592 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1593 });
1594 waitForGenerate(function() {
1595 var actual = page.evaluate(function() {
1596 return $(".phrase").val();
1597 });
1598 if (actual != expected) {
1599 console.log("Phrase not cleared when setting BIP32 root key");
1600 console.log("Expected: " + expected);
1601 console.log("Actual: " + actual);
1602 fail();
1603 }
1604 next();
1605 });
1606});
1607},
1608
54563907 1609// Clearing of phrase, passphrase and seed can be cancelled by user
abfbe450
IC
1610function() {
1611page.open(url, function(status) {
1612 var expected = "abandon abandon ability";
1613 // set a mnemonic
1614 page.evaluate(function() {
1615 $(".phrase").val("abandon abandon ability");
1616 });
1617 // Cancel any confirm dialogs
1618 page.onConfirm = function() {
1619 return false;
1620 };
1621 // set the root key
1622 page.evaluate(function() {
1623 $(".root-key").val("xprv9s21ZrQH143K3d3vzEDD3KpSKmxsZ3y7CqhAL1tinwtP6wqK4TKEKjpBuo6P2hUhB6ZENo7TTSRytiP857hBZVpBdk8PooFuRspE1eywwNZ").trigger("input");
1624 });
1625 var actual = page.evaluate(function() {
1626 return $(".phrase").val();
1627 });
1628 if (actual != expected) {
1629 console.log("Phrase not retained when cancelling changes to BIP32 root key");
1630 console.log("Expected: " + expected);
1631 console.log("Actual: " + actual);
1632 fail();
1633 }
1634 next();
1635});
1636},
7ff86d4c 1637
88e2cdaa 1638// Custom BIP32 root key is used when changing the derivation path
7ff86d4c
IC
1639function() {
1640page.open(url, function(status) {
1641 var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H";
1642 // set the root key
1643 page.evaluate(function() {
1644 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
1645 });
1646 waitForGenerate(function() {
1647 // change the derivation path
1648 page.evaluate(function() {
1649 $("#account").val("1").trigger("input");
1650 });
1651 // check the bip32 root key is used for derivation, not the blank phrase
1652 waitForGenerate(function() {
1653 var actual = page.evaluate(function() {
1654 return $(".address:first").text();
1655 });
1656 if (actual != expected) {
1657 console.log("Changing the derivation path does not use BIP32 root key");
1658 console.log("Expected: " + expected);
1659 console.log("Actual: " + actual);
1660 fail();
1661 }
1662 next();
1663 });
1664 });
1665});
1666},
88e2cdaa
IC
1667
1668// Incorrect mnemonic shows error
c3719b00
IC
1669function() {
1670page.open(url, function(status) {
1671 // set the root key
1672 page.evaluate(function() {
1673 $(".phrase").val("abandon abandon abandon").trigger("input");
1674 });
1675 waitForFeedback(function() {
1676 // check there is an error shown
1677 var feedback = page.evaluate(function() {
1678 return $(".feedback").text();
1679 });
1680 if (feedback.length <= 0) {
1681 console.log("Invalid mnemonic does not show error");
1682 fail();
1683 }
1684 next();
1685 });
1686});
1687},
1688
88e2cdaa 1689// Incorrect word shows suggested replacement
20f80cfa
IC
1690function() {
1691page.open(url, function(status) {
1692 // set the root key
1693 page.evaluate(function() {
1694 $(".phrase").val("abandon abandon abiliti").trigger("input");
1695 });
1696 // check there is a suggestion shown
1697 waitForFeedback(function() {
1698 var feedback = page.evaluate(function() {
1699 return $(".feedback").text();
1700 });
1701 if (feedback.indexOf("did you mean ability?") < 0) {
1702 console.log("Incorrect word does not show suggested replacement");
1703 console.log("Error: " + error);
1704 fail();
6ea15134
IC
1705 }
1706 next();
1707 });
1708});
1709},
1710
1711// Github pull request 48
1712// First four letters of word shows that word, not closest
1713// since first four letters gives unique word in BIP39 wordlist
1714// eg ille should show illegal, not idle
1715function() {
1716page.open(url, function(status) {
1717 // set the incomplete word
1718 page.evaluate(function() {
1719 $(".phrase").val("ille").trigger("input");
1720 });
1721 // check there is a suggestion shown
1722 waitForFeedback(function() {
1723 var feedback = page.evaluate(function() {
1724 return $(".feedback").text();
1725 });
1726 if (feedback.indexOf("did you mean illegal?") < 0) {
1727 console.log("Start of word does not show correct suggestion");
1728 console.log("Error: " + error);
1729 fail();
20f80cfa
IC
1730 }
1731 next();
1732 });
1733});
1734},
1735
88e2cdaa 1736// Incorrect BIP32 root key shows error
02f4a90e
IC
1737function() {
1738page.open(url, function(status) {
1739 // set the root key
1740 page.evaluate(function() {
1741 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj").trigger("input");
1742 });
1743 // check there is an error shown
1744 waitForFeedback(function() {
1745 var feedback = page.evaluate(function() {
1746 return $(".feedback").text();
1747 });
1748 if (feedback != "Invalid root key") {
1749 console.log("Invalid root key does not show error");
1750 console.log("Error: " + error);
1751 fail();
1752 }
1753 next();
1754 });
1755});
1756},
1757
88e2cdaa 1758// Derivation path not starting with m shows error
f976b541
IC
1759function() {
1760page.open(url, function(status) {
1761 // set the mnemonic phrase
1762 page.evaluate(function() {
1763 $(".phrase").val("abandon abandon ability").trigger("input");
1764 });
1765 waitForGenerate(function() {
1766 // select the bip32 tab so custom derivation path can be set
1767 page.evaluate(function() {
1768 $("#bip32-tab a").click();
1769 });
1770 waitForGenerate(function() {
1771 // set the incorrect derivation path
1772 page.evaluate(function() {
1773 $("#bip32 .path").val("n/0").trigger("input");
1774 });
1775 waitForFeedback(function() {
1776 var feedback = page.evaluate(function() {
1777 return $(".feedback").text();
1778 });
1779 if (feedback != "First character must be 'm'") {
1780 console.log("Derivation path not starting with m should show error");
1781 console.log("Error: " + error);
1782 fail();
1783 }
1784 next();
1785 });
1786 });
1787 });
1788});
1789},
1790
88e2cdaa 1791// Derivation path containing invalid characters shows useful error
55c0ffcb
IC
1792function() {
1793page.open(url, function(status) {
1794 // set the mnemonic phrase
1795 page.evaluate(function() {
1796 $(".phrase").val("abandon abandon ability").trigger("input");
1797 });
1798 waitForGenerate(function() {
1799 // select the bip32 tab so custom derivation path can be set
1800 page.evaluate(function() {
1801 $("#bip32-tab a").click();
1802 });
1803 waitForGenerate(function() {
1804 // set the incorrect derivation path
1805 page.evaluate(function() {
1806 $("#bip32 .path").val("m/1/0wrong1/1").trigger("input");
1807 });
1808 waitForFeedback(function() {
1809 var feedback = page.evaluate(function() {
1810 return $(".feedback").text();
1811 });
1812 if (feedback != "Invalid characters 0wrong1 found at depth 2") {
1813 console.log("Derivation path with invalid characters should show error");
1814 console.log("Error: " + error);
1815 fail();
1816 }
1817 next();
1818 });
1819 });
1820 });
1821});
1822},
88e2cdaa
IC
1823
1824// Github Issue 11: Default word length is 15
b630f83d 1825// https://github.com/iancoleman/bip39/issues/11
ca976aa9
IC
1826function() {
1827page.open(url, function(status) {
1828 // get the word length
1829 var defaultLength = page.evaluate(function() {
1830 return $(".strength").val();
1831 });
1832 if (defaultLength != 15) {
1833 console.log("Default word length is not 15");
1834 fail();
1835 }
1836 next();
1837});
1838},
1839
88e2cdaa
IC
1840
1841// Github Issue 12: Generate more rows with private keys hidden
b630f83d 1842// https://github.com/iancoleman/bip39/issues/12
c97627fa
IC
1843function() {
1844page.open(url, function(status) {
1845 // set the phrase
1846 page.evaluate(function() {
1847 $(".phrase").val("abandon abandon ability");
1848 $(".phrase").trigger("input");
1849 });
1850 waitForGenerate(function() {
1851 // toggle private keys hidden, then generate more addresses
1852 page.evaluate(function() {
1853 $(".private-key-toggle").click();
1854 $(".more").click();
1855 });
1856 waitForGenerate(function() {
1857 // check more have been generated
1858 var expected = 40;
1859 var numPrivKeys = page.evaluate(function() {
1860 return $(".privkey").length;
1861 });
1862 if (numPrivKeys != expected) {
1863 console.log("Wrong number of addresses when clicking 'more' with hidden privkeys");
1864 console.log("Expected: " + expected);
1865 console.log("Actual: " + numPrivKeys);
1866 fail();
1867 }
1868 // check no private keys are shown
1869 var numHiddenPrivKeys = page.evaluate(function() {
1870 return $(".privkey span[class=invisible]").length;
1871 });
1872 if (numHiddenPrivKeys != expected) {
1873 console.log("Generating more does not retain hidden state of privkeys");
1874 console.log("Expected: " + expected);
1875 console.log("Actual: " + numHiddenPrivKeys);
1876 fail();
1877 }
1878 next();
1879 });
1880 });
1881});
1882},
88e2cdaa
IC
1883
1884// Github Issue 19: Mnemonic is not sensitive to whitespace
b630f83d 1885// https://github.com/iancoleman/bip39/issues/19
a7becc43
IC
1886function() {
1887page.open(url, function(status) {
1888 // set the phrase
1889 var expected = "xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC";
1890 page.evaluate(function() {
1891 var doubleSpace = " ";
1892 $(".phrase").val("urge cat" + doubleSpace + "bid");
1893 $(".phrase").trigger("input");
1894 });
1895 waitForGenerate(function() {
1896 // Check the bip32 root key is correct
1897 var actual = page.evaluate(function() {
1898 return $(".root-key").val();
1899 });
1900 if (actual != expected) {
1901 console.log("Mnemonic is sensitive to whitespace");
1902 console.log("Expected: " + expected);
1903 console.log("Actual: " + actual);
1904 fail();
1905 }
1906 next();
1907 });
1908});
1909},
88e2cdaa 1910
e3001539 1911// Github Issue 23: Part 1: Use correct derivation path when changing tabs
b630f83d 1912// https://github.com/iancoleman/bip39/issues/23
e3001539
IC
1913function() {
1914page.open(url, function(status) {
1915 // 1) and 2) set the phrase
1916 page.evaluate(function() {
1917 $(".phrase").val("abandon abandon ability").trigger("input");
1918 });
1919 waitForGenerate(function() {
1920 // 3) select bip32 tab
1921 page.evaluate(function() {
1922 $("#bip32-tab a").click();
1923 });
1924 waitForGenerate(function() {
1925 // 4) switch from bitcoin to litecoin
1926 page.evaluate(function() {
52d589ea
IC
1927 $(".network option").filter(function() {
1928 return $(this).html() == "Litecoin";
1929 }).prop("selected", true);
1930 $(".network").trigger("change");
e3001539
IC
1931 });
1932 waitForGenerate(function() {
1933 // 5) Check derivation path is displayed correctly
1934 var expected = "m/0/0";
1935 var actual = page.evaluate(function() {
1936 return $(".index:first").text();
1937 });
1938 if (actual != expected) {
1939 console.log("Github Issue 23 Part 1: derivation path display error");
1940 console.log("Expected: " + expected);
1941 console.log("Actual: " + actual);
1942 fail();
1943 }
1944 // 5) Check address is displayed correctly
1945 var expected = "LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5";
1946 var actual = page.evaluate(function() {
1947 return $(".address:first").text();
1948 });
1949 if (actual != expected) {
1950 console.log("Github Issue 23 Part 1: address display error");
1951 console.log("Expected: " + expected);
1952 console.log("Actual: " + actual);
1953 fail();
1954 }
1955 next();
1956 });
1957 });
1958 });
1959});
1960},
1961
1962// Github Issue 23 Part 2: Coin selection in derivation path
b630f83d 1963// https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
af4fd3a2
IC
1964function() {
1965page.open(url, function(status) {
1966 // set the phrase
1967 page.evaluate(function() {
1968 $(".phrase").val("abandon abandon ability").trigger("input");
1969 });
1970 waitForGenerate(function() {
1971 // switch from bitcoin to clam
1972 page.evaluate(function() {
52d589ea
IC
1973 $(".network option").filter(function() {
1974 return $(this).html() == "CLAM";
1975 }).prop("selected", true);
1976 $(".network").trigger("change");
af4fd3a2
IC
1977 });
1978 waitForGenerate(function() {
1979 // check derivation path is displayed correctly
1980 var expected = "m/44'/23'/0'/0/0";
1981 var actual = page.evaluate(function() {
1982 return $(".index:first").text();
1983 });
1984 if (actual != expected) {
1985 console.log("Github Issue 23 Part 2: Coin in BIP44 derivation path is incorrect");
1986 console.log("Expected: " + expected);
1987 console.log("Actual: " + actual);
1988 fail();
1989 }
1990 next();
1991 });
1992 });
1993});
1994},
88e2cdaa 1995
f3d0aca1 1996// Github Issue 26: When using a Root key derrived altcoins are incorrect
b630f83d 1997// https://github.com/iancoleman/bip39/issues/26
558ef9ac
IC
1998function() {
1999page.open(url, function(status) {
2000 // 1) 2) and 3) set the root key
2001 page.evaluate(function() {
2002 $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input");
2003 });
2004 waitForGenerate(function() {
2005 // 4) switch from bitcoin to viacoin
2006 page.evaluate(function() {
52d589ea
IC
2007 $(".network option").filter(function() {
2008 return $(this).html() == "Viacoin";
2009 }).prop("selected", true);
2010 $(".network").trigger("change");
558ef9ac
IC
2011 });
2012 waitForGenerate(function() {
2013 // 5) ensure the derived address is correct
2014 var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT";
2015 var actual = page.evaluate(function() {
2016 return $(".address:first").text();
2017 });
2018 if (actual != expected) {
2019 console.log("Github Issue 26: address is incorrect when changing networks and using root-key to derive");
2020 console.log("Expected: " + expected);
2021 console.log("Actual: " + actual);
2022 fail();
2023 }
2024 next();
2025 });
2026 });
2027});
2028},
f3d0aca1 2029
e1bae843
IC
2030// Selecting a language with no existing phrase should generate a phrase in
2031// that language.
2032function() {
2033page.open(url, function(status) {
2034 // Select a language
2035 // Need to manually simulate hash being set due to quirk between
2036 // 'click' event triggered by javascript vs triggered by mouse.
2037 // Perhaps look into page.sendEvent
2038 // http://phantomjs.org/api/webpage/method/send-event.html
2039 page.evaluate(function() {
2040 window.location.hash = "#japanese";
2041 $("a[href='#japanese']").trigger("click");
2042 });
2043 waitForGenerate(function() {
2044 // Check the mnemonic is in Japanese
2045 var phrase = page.evaluate(function() {
2046 return $(".phrase").val();
2047 });
2048 if (phrase.length <= 0) {
2049 console.log("No Japanese phrase generated");
2050 fail();
2051 }
2052 if (phrase.charCodeAt(0) < 128) {
2053 console.log("First character of Japanese phrase is ascii");
2054 console.log("Phrase: " + phrase);
2055 fail();
2056 }
2057 next();
2058 });
2059});
2060},
2061
2062// Selecting a language with existing phrase should update the phrase to use
2063// that language.
2064function() {
2065page.open(url, function(status) {
2066 // Set the phrase to an English phrase.
2067 page.evaluate(function() {
2068 $(".phrase").val("abandon abandon ability").trigger("input");
2069 });
2070 waitForGenerate(function() {
2071 // Change to Italian
2072 // Need to manually simulate hash being set due to quirk between
2073 // 'click' event triggered by javascript vs triggered by mouse.
2074 // Perhaps look into page.sendEvent
2075 // http://phantomjs.org/api/webpage/method/send-event.html
2076 page.evaluate(function() {
2077 window.location.hash = "#italian";
2078 $("a[href='#italian']").trigger("click");
2079 });
2080 waitForGenerate(function() {
2081 // Check only the language changes, not the phrase
2082 var expected = "abaco abaco abbaglio";
2083 var actual = page.evaluate(function() {
2084 return $(".phrase").val();
2085 });
2086 if (actual != expected) {
2087 console.log("Changing language with existing phrase");
2088 console.log("Expected: " + expected);
2089 console.log("Actual: " + actual);
2090 fail();
2091 }
2092 // Check the address is correct
2093 var expected = "1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV";
2094 var actual = page.evaluate(function() {
2095 return $(".address:first").text();
2096 });
2097 if (actual != expected) {
2098 console.log("Changing language generates incorrect address");
2099 console.log("Expected: " + expected);
2100 console.log("Actual: " + actual);
2101 fail();
2102 }
2103 next();
2104 });
2105 });
2106});
2107},
2108
2109// Suggested replacement for erroneous word in non-English language
2110function() {
2111page.open(url, function(status) {
2112 // Set an incorrect phrase in Italian
2113 page.evaluate(function() {
2114 $(".phrase").val("abaco abaco zbbaglio").trigger("input");
2115 });
2116 waitForFeedback(function() {
2117 // Check the suggestion is correct
2118 var feedback = page.evaluate(function() {
2119 return $(".feedback").text();
2120 });
2121 if (feedback.indexOf("did you mean abbaglio?") < 0) {
2122 console.log("Incorrect Italian word does not show suggested replacement");
2123 console.log("Error: " + error);
2124 fail();
2125 }
2126 next();
2127 });
2128});
2129},
2130
2131
2132// Japanese word does not break across lines.
2133// Point 2 from
2134// https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
2135function() {
2136page.open(url, function(status) {
2137 hasWordBreakCss = page.content.indexOf("word-break: keep-all;") > -1;
2138 if (!hasWordBreakCss) {
2139 console.log("Japanese words can break across lines mid-word");
2140 console.log("Check CSS for '.phrase { word-break: keep-all; }'");
2141 fail();
2142 }
2143 // Run the next test
2144 next();
2145});
2146},
2147
2148// Language can be specified at page load using hash value in url
2149function() {
2150page.open(url, function(status) {
2151 // Set the page hash as if it were on a fresh page load
2152 page.evaluate(function() {
2153 window.location.hash = "#japanese";
2154 });
2155 // Generate a random phrase
2156 page.evaluate(function() {
2157 $(".generate").trigger("click");
2158 });
2159 waitForGenerate(function() {
2160 // Check the phrase is in Japanese
2161 var phrase = page.evaluate(function() {
2162 return $(".phrase").val();
2163 });
2164 if (phrase.length <= 0) {
2165 console.log("No phrase generated using url hash");
2166 fail();
2167 }
2168 if (phrase.charCodeAt(0) < 128) {
2169 console.log("Language not detected from url hash on page load.");
2170 console.log("Phrase: " + phrase);
2171 fail();
2172 }
2173 next();
2174 });
2175});
2176},
2177
c6624d51
IC
2178// Entropy unit tests
2179function() {
2180page.open(url, function(status) {
adc8ce12 2181 var response = page.evaluate(function() {
c6624d51
IC
2182 var e;
2183 // binary entropy is detected
adc8ce12
IC
2184 try {
2185 e = Entropy.fromString("01010101");
2186 if (e.base.str != "binary") {
2187 return "Binary entropy not detected correctly";
2188 }
2189 }
2190 catch (e) {
2191 return e.message;
c6624d51
IC
2192 }
2193 // base6 entropy is detected
adc8ce12
IC
2194 try {
2195 e = Entropy.fromString("012345012345");
2196 if (e.base.str != "base 6") {
2197 return "base6 entropy not detected correctly";
2198 }
2199 }
2200 catch (e) {
2201 return e.message;
c6624d51
IC
2202 }
2203 // dice entropy is detected
adc8ce12
IC
2204 try {
2205 e = Entropy.fromString("123456123456");
2206 if (e.base.str != "base 6 (dice)") {
2207 return "dice entropy not detected correctly";
2208 }
2209 }
2210 catch (e) {
2211 return e.message;
c6624d51
IC
2212 }
2213 // base10 entropy is detected
adc8ce12
IC
2214 try {
2215 e = Entropy.fromString("0123456789");
2216 if (e.base.str != "base 10") {
2217 return "base10 entropy not detected correctly";
2218 }
2219 }
2220 catch (e) {
2221 return e.message;
c6624d51
IC
2222 }
2223 // hex entropy is detected
adc8ce12
IC
2224 try {
2225 e = Entropy.fromString("0123456789ABCDEF");
2226 if (e.base.str != "hexadecimal") {
2227 return "hexadecimal entropy not detected correctly";
2228 }
2229 }
2230 catch (e) {
2231 return e.message;
2232 }
2233 // card entropy is detected
2234 try {
2235 e = Entropy.fromString("AC4DTHKS");
2236 if (e.base.str != "card") {
2237 return "card entropy not detected correctly";
2238 }
2239 }
2240 catch (e) {
2241 return e.message;
c6624d51
IC
2242 }
2243 // entropy is case insensitive
adc8ce12
IC
2244 try {
2245 e = Entropy.fromString("aBcDeF");
2246 if (e.cleanStr != "aBcDeF") {
2247 return "Entropy should not be case sensitive";
2248 }
2249 }
2250 catch (e) {
2251 return e.message;
c6624d51
IC
2252 }
2253 // dice entropy is converted to base6
adc8ce12
IC
2254 try {
2255 e = Entropy.fromString("123456");
425b75a9 2256 if (e.cleanStr != "123450") {
adc8ce12
IC
2257 return "Dice entropy is not automatically converted to base6";
2258 }
2259 }
2260 catch (e) {
2261 return e.message;
c6624d51
IC
2262 }
2263 // dice entropy is preferred to base6 if ambiguous
adc8ce12
IC
2264 try {
2265 e = Entropy.fromString("12345");
2266 if (e.base.str != "base 6 (dice)") {
2267 return "dice not used as default over base 6";
2268 }
2269 }
2270 catch (e) {
2271 return e.message;
c6624d51
IC
2272 }
2273 // unused characters are ignored
adc8ce12
IC
2274 try {
2275 e = Entropy.fromString("fghijkl");
2276 if (e.cleanStr != "f") {
2277 return "additional characters are not ignored";
2278 }
2279 }
2280 catch (e) {
2281 return e.message;
c6624d51
IC
2282 }
2283 // the lowest base is used by default
2284 // 7 could be decimal or hexadecimal, but should be detected as decimal
adc8ce12
IC
2285 try {
2286 e = Entropy.fromString("7");
2287 if (e.base.str != "base 10") {
2288 return "lowest base is not used";
2289 }
c6624d51 2290 }
adc8ce12
IC
2291 catch (e) {
2292 return e.message;
c6624d51
IC
2293 }
2294 // Leading zeros are retained
adc8ce12
IC
2295 try {
2296 e = Entropy.fromString("000A");
2297 if (e.cleanStr != "000A") {
2298 return "Leading zeros are not retained";
2299 }
2300 }
2301 catch (e) {
2302 return e.message;
c6624d51
IC
2303 }
2304 // Leading zeros are correctly preserved for hex in binary string
adc8ce12
IC
2305 try {
2306 e = Entropy.fromString("2A");
2307 if (e.binaryStr != "00101010") {
2308 return "Hex leading zeros are not correct in binary";
2309 }
2310 }
2311 catch (e) {
2312 return e.message;
2313 }
1cf1bbaf
IC
2314 // Leading zeros for base 6 as binary string
2315 // 20 = 2 events at 2.58 bits per event = 5 bits
2316 // 20 in base 6 = 12 in base 10 = 1100 in base 2
2317 // so it needs 1 bit of padding to be the right bit length
adc8ce12 2318 try {
1cf1bbaf
IC
2319 e = Entropy.fromString("20");
2320 if (e.binaryStr != "01100") {
0d0f07f9
IC
2321 return "Base 6 as binary has leading zeros";
2322 }
2323 }
2324 catch (e) {
2325 return e.message;
2326 }
1cf1bbaf 2327 // Leading zeros for base 10 as binary string
0d0f07f9 2328 try {
1cf1bbaf
IC
2329 e = Entropy.fromString("17");
2330 if (e.binaryStr != "010001") {
0d0f07f9
IC
2331 return "Base 10 as binary has leading zeros";
2332 }
2333 }
2334 catch (e) {
2335 return e.message;
2336 }
87ad2c6e 2337 // Leading zeros for card entropy as binary string.
9d33c892 2338 // Card entropy is hashed so 2c does not necessarily produce leading zeros.
0d0f07f9 2339 try {
9d33c892
IC
2340 e = Entropy.fromString("2c");
2341 if (e.binaryStr != "0010") {
0d0f07f9 2342 return "Card entropy as binary has leading zeros";
adc8ce12
IC
2343 }
2344 }
2345 catch (e) {
2346 return e.message;
c6624d51
IC
2347 }
2348 // Keyboard mashing results in weak entropy
2349 // Despite being a long string, it's less than 30 bits of entropy
adc8ce12
IC
2350 try {
2351 e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj");
2352 if (e.binaryStr.length >= 30) {
2353 return "Keyboard mashing should produce weak entropy";
2354 }
c6624d51 2355 }
adc8ce12
IC
2356 catch (e) {
2357 return e.message;
2358 }
2359 // Card entropy is used if every pair could be a card
2360 try {
2361 e = Entropy.fromString("4c3c2c");
2362 if (e.base.str != "card") {
2363 return "Card entropy not used if all pairs are cards";
2364 }
2365 }
2366 catch (e) {
2367 return e.message;
2368 }
2369 // Card entropy uses base 52
2370 // [ cards, binary ]
2371 try {
2372 var cards = [
9d33c892
IC
2373 [ "ac", "0101" ],
2374 [ "acqs", "11011100" ],
2375 [ "acks", "01011100" ],
2376 [ "2cac", "11111000" ],
2377 [ "2c", "0010" ],
2378 [ "3d", "0001" ],
2379 [ "4h", "1001" ],
87ad2c6e 2380 [ "5s", "1001" ],
9d33c892
IC
2381 [ "6c", "0000" ],
2382 [ "7d", "0001" ],
87ad2c6e 2383 [ "8h", "1011" ],
9d33c892
IC
2384 [ "9s", "0010" ],
2385 [ "tc", "1001" ],
2386 [ "jd", "1111" ],
2387 [ "qh", "0010" ],
2388 [ "ks", "0101" ],
2389 [ "ks2c", "01010100" ],
2390 [ "KS2C", "01010100" ],
adc8ce12
IC
2391 ];
2392 for (var i=0; i<cards.length; i++) {
2393 var card = cards[i][0];
2394 var result = cards[i][1];
2395 e = Entropy.fromString(card);
2396 console.log(e.binary + " " + result);
2397 if (e.binaryStr !== result) {
886f06ee 2398 return "card entropy " + card + " not parsed correctly: " + result + " != " + e.binaryStr;
adc8ce12
IC
2399 }
2400 }
2401 }
2402 catch (e) {
2403 return e.message;
2404 }
2405 return "PASS";
c6624d51 2406 });
adc8ce12 2407 if (response != "PASS") {
c6624d51 2408 console.log("Entropy unit tests");
adc8ce12 2409 console.log(response);
c6624d51
IC
2410 fail();
2411 };
2412 next();
2413});
2414},
2415
2416// Entropy can be entered by the user
2417function() {
2418page.open(url, function(status) {
2419 expected = {
2420 mnemonic: "abandon abandon ability",
2421 address: "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug",
2422 }
2423 // use entropy
2424 page.evaluate(function() {
2425 $(".use-entropy").prop("checked", true).trigger("change");
2426 $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
2427 });
2428 // check the mnemonic is set and address is correct
2429 waitForGenerate(function() {
2430 var actual = page.evaluate(function() {
2431 return {
2432 address: $(".address:first").text(),
2433 mnemonic: $(".phrase").val(),
2434 }
2435 });
2436 if (actual.mnemonic != expected.mnemonic) {
2437 console.log("Entropy does not generate correct mnemonic");
2438 console.log("Expected: " + expected.mnemonic);
2439 console.log("Got: " + actual.mnemonic);
2440 fail();
2441 }
2442 if (actual.address != expected.address) {
2443 console.log("Entropy does not generate correct address");
2444 console.log("Expected: " + expected.address);
2445 console.log("Got: " + actual.address);
2446 fail();
2447 }
2448 next();
2449 });
2450});
2451},
2452
2453// A warning about entropy is shown to the user, with additional information
2454function() {
2455page.open(url, function(status) {
2456 // get text content from entropy sections of page
2457 var hasWarning = page.evaluate(function() {
2458 var entropyText = $(".entropy-container").text();
2459 var warning = "mnemonic may be insecure";
2460 if (entropyText.indexOf(warning) == -1) {
2461 return false;
2462 }
2463 var readMoreText = $("#entropy-notes").parent().text();
2464 var goodSources = "flipping a fair coin, rolling a fair dice, noise measurements etc";
2465 if (readMoreText.indexOf(goodSources) == -1) {
2466 return false;
2467 }
2468 return true;
2469 });
2470 // check the warnings and information are shown
2471 if (!hasWarning) {
2472 console.log("Page does not contain warning about using own entropy");
2473 fail();
2474 }
2475 next();
2476});
2477},
2478
2479// The types of entropy available are described to the user
2480function() {
2481page.open(url, function(status) {
2482 // get placeholder text for entropy field
2483 var placeholder = page.evaluate(function() {
2484 return $(".entropy").attr("placeholder");
2485 });
2486 var options = [
2487 "binary",
2488 "base 6",
2489 "dice",
2490 "base 10",
2491 "hexadecimal",
439f0e25 2492 "cards",
c6624d51
IC
2493 ];
2494 for (var i=0; i<options.length; i++) {
2495 var option = options[i];
2496 if (placeholder.indexOf(option) == -1) {
2497 console.log("Available entropy type is not shown to user: " + option);
2498 fail();
2499 }
2500 }
2501 next();
2502});
2503},
2504
2505// The actual entropy used is shown to the user
2506function() {
2507page.open(url, function(status) {
2508 // use entropy
2509 var badEntropySource = page.evaluate(function() {
2510 var entropy = "Not A Very Good Entropy Source At All";
2511 $(".use-entropy").prop("checked", true).trigger("change");
2512 $(".entropy").val(entropy).trigger("input");
2513 });
2514 // check the actual entropy being used is shown
057722b0 2515 waitForEntropyFeedback(function() {
c6624d51
IC
2516 var expectedText = "AedEceAA";
2517 var entropyText = page.evaluate(function() {
2518 return $(".entropy-container").text();
2519 });
2520 if (entropyText.indexOf(expectedText) == -1) {
2521 console.log("Actual entropy used is not shown");
2522 fail();
2523 }
2524 next();
2525 });
2526});
2527},
2528
2529// Binary entropy can be entered
2530function() {
2531page.open(url, function(status) {
2532 // use entropy
2533 page.evaluate(function() {
2534 $(".use-entropy").prop("checked", true).trigger("change");
2535 $(".entropy").val("01").trigger("input");
2536 });
2537 // check the entropy is shown to be the correct type
057722b0 2538 waitForEntropyFeedback(function() {
c6624d51
IC
2539 var entropyText = page.evaluate(function() {
2540 return $(".entropy-container").text();
2541 });
2542 if (entropyText.indexOf("binary") == -1) {
2543 console.log("Binary entropy is not detected and presented to user");
2544 fail();
2545 }
2546 next();
2547 });
2548});
2549},
2550
2551// Base 6 entropy can be entered
2552function() {
2553page.open(url, function(status) {
2554 // use entropy
2555 page.evaluate(function() {
2556 $(".use-entropy").prop("checked", true).trigger("change");
2557 $(".entropy").val("012345").trigger("input");
2558 });
2559 // check the entropy is shown to be the correct type
057722b0 2560 waitForEntropyFeedback(function() {
c6624d51
IC
2561 var entropyText = page.evaluate(function() {
2562 return $(".entropy-container").text();
2563 });
2564 if (entropyText.indexOf("base 6") == -1) {
2565 console.log("Base 6 entropy is not detected and presented to user");
2566 fail();
2567 }
2568 next();
2569 });
2570});
2571},
2572
2573// Base 6 dice entropy can be entered
2574function() {
2575page.open(url, function(status) {
2576 // use entropy
2577 page.evaluate(function() {
2578 $(".use-entropy").prop("checked", true).trigger("change");
2579 $(".entropy").val("123456").trigger("input");
2580 });
2581 // check the entropy is shown to be the correct type
057722b0 2582 waitForEntropyFeedback(function() {
c6624d51
IC
2583 var entropyText = page.evaluate(function() {
2584 return $(".entropy-container").text();
2585 });
2586 if (entropyText.indexOf("dice") == -1) {
2587 console.log("Dice entropy is not detected and presented to user");
2588 fail();
2589 }
2590 next();
2591 });
2592});
2593},
2594
2595// Base 10 entropy can be entered
2596function() {
2597page.open(url, function(status) {
2598 // use entropy
2599 page.evaluate(function() {
2600 $(".use-entropy").prop("checked", true).trigger("change");
2601 $(".entropy").val("789").trigger("input");
2602 });
2603 // check the entropy is shown to be the correct type
057722b0 2604 waitForEntropyFeedback(function() {
c6624d51
IC
2605 var entropyText = page.evaluate(function() {
2606 return $(".entropy-container").text();
2607 });
2608 if (entropyText.indexOf("base 10") == -1) {
2609 console.log("Base 10 entropy is not detected and presented to user");
2610 fail();
2611 }
2612 next();
2613 });
2614});
2615},
2616
2617// Hexadecimal entropy can be entered
2618function() {
2619page.open(url, function(status) {
2620 // use entropy
2621 page.evaluate(function() {
2622 $(".use-entropy").prop("checked", true).trigger("change");
2623 $(".entropy").val("abcdef").trigger("input");
2624 });
2625 // check the entropy is shown to be the correct type
057722b0 2626 waitForEntropyFeedback(function() {
c6624d51
IC
2627 var entropyText = page.evaluate(function() {
2628 return $(".entropy-container").text();
2629 });
2630 if (entropyText.indexOf("hexadecimal") == -1) {
2631 console.log("Hexadecimal entropy is not detected and presented to user");
2632 fail();
2633 }
2634 next();
2635 });
2636});
2637},
2638
2639// Dice entropy value is shown as the converted base 6 value
2640function() {
2641page.open(url, function(status) {
2642 // use entropy
2643 page.evaluate(function() {
2644 $(".use-entropy").prop("checked", true).trigger("change");
2645 $(".entropy").val("123456").trigger("input");
2646 });
2647 // check the entropy is shown as base 6, not as the original dice value
057722b0 2648 waitForEntropyFeedback(function() {
c6624d51
IC
2649 var entropyText = page.evaluate(function() {
2650 return $(".entropy-container").text();
2651 });
425b75a9 2652 if (entropyText.indexOf("123450") == -1) {
c6624d51
IC
2653 console.log("Dice entropy is not shown to user as base 6 value");
2654 fail();
2655 }
2656 if (entropyText.indexOf("123456") > -1) {
2657 console.log("Dice entropy value is shown instead of true base 6 value");
2658 fail();
2659 }
2660 next();
2661 });
2662});
2663},
2664
2665// The number of bits of entropy accumulated is shown
2666function() {
2667page.open(url, function(status) {
057722b0
IC
2668 //[ entropy, bits ]
2669 var tests = [
2670 [ "0000 0000 0000 0000 0000", "20" ],
2671 [ "0", "1" ],
2672 [ "0000", "4" ],
0d0f07f9
IC
2673 [ "6", "2" ], // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits)
2674 [ "7", "3" ], // 7 in base 10 is 111 in base 2, no leading zeros
057722b0
IC
2675 [ "8", "4" ],
2676 [ "F", "4" ],
1cf1bbaf 2677 [ "29", "6" ],
057722b0
IC
2678 [ "0A", "8" ],
2679 [ "1A", "8" ], // hex is always multiple of 4 bits of entropy
2680 [ "2A", "8" ],
2681 [ "4A", "8" ],
2682 [ "8A", "8" ],
2683 [ "FA", "8" ],
2684 [ "000A", "16" ],
0d0f07f9
IC
2685 [ "5555", "11" ],
2686 [ "6666", "10" ], // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
1cf1bbaf 2687 [ "2227", "13" ], // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded down to 13)
057722b0
IC
2688 [ "222F", "16" ],
2689 [ "FFFF", "16" ],
1cf1bbaf 2690 [ "0000101017", "33" ], // 10 events at 3.32 bits per event
6422c1cd 2691 [ "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225" ], // cards are not replaced, so a full deck is not 52^52 entropy which is 296 bits, it's 52!, which is 225 bits
057722b0 2692 ]
c6624d51
IC
2693 // use entropy
2694 page.evaluate(function(e) {
2695 $(".use-entropy").prop("checked", true).trigger("change");
2696 });
2697 // Run each test
2698 var nextTest = function runNextTest(i) {
057722b0
IC
2699 var entropy = tests[i][0];
2700 var expected = tests[i][1];
c6624d51
IC
2701 // set entropy
2702 page.evaluate(function(e) {
c6624d51
IC
2703 $(".entropy").val(e).trigger("input");
2704 }, entropy);
2705 // check the number of bits of entropy is shown
057722b0 2706 waitForEntropyFeedback(function() {
c6624d51 2707 var entropyText = page.evaluate(function() {
dd944906 2708 return $(".entropy-container").text();
c6624d51 2709 });
1cf1bbaf 2710 if (entropyText.replace(/\s/g,"").indexOf("Bits" + expected) == -1) {
c6624d51
IC
2711 console.log("Accumulated entropy is not shown correctly for " + entropy);
2712 fail();
2713 }
057722b0 2714 var isLastTest = i == tests.length - 1;
c6624d51
IC
2715 if (isLastTest) {
2716 next();
2717 }
2718 else {
2719 runNextTest(i+1);
2720 }
2721 });
2722 }
2723 nextTest(0);
2724});
2725},
2726
fb353f9d 2727// There is feedback provided about the supplied entropy
c6624d51
IC
2728function() {
2729page.open(url, function(status) {
2730 var tests = [
2731 {
2732 entropy: "A",
fb353f9d
IC
2733 filtered: "A",
2734 type: "hexadecimal",
2735 events: 1,
2736 bits: 4,
c6624d51 2737 words: 0,
1cf1bbaf 2738 strength: "extremely weak",
c6624d51
IC
2739 },
2740 {
2741 entropy: "AAAAAAAA",
fb353f9d
IC
2742 filtered: "AAAAAAAA",
2743 type: "hexadecimal",
2744 events: 8,
2745 bits: 32,
c6624d51 2746 words: 3,
1cf1bbaf 2747 strength: "extremely weak",
c6624d51
IC
2748 },
2749 {
2750 entropy: "AAAAAAAA B",
fb353f9d
IC
2751 filtered: "AAAAAAAAB",
2752 type: "hexadecimal",
2753 events: 9,
2754 bits: 36,
c6624d51 2755 words: 3,
1cf1bbaf 2756 strength: "extremely weak",
c6624d51
IC
2757 },
2758 {
2759 entropy: "AAAAAAAA BBBBBBBB",
fb353f9d
IC
2760 filtered: "AAAAAAAABBBBBBBB",
2761 type: "hexadecimal",
2762 events: 16,
2763 bits: 64,
c6624d51 2764 words: 6,
1cf1bbaf 2765 strength: "very weak",
c6624d51
IC
2766 },
2767 {
2768 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
fb353f9d
IC
2769 filtered: "AAAAAAAABBBBBBBBCCCCCCCC",
2770 type: "hexadecimal",
2771 events: 24,
2772 bits: 96,
c6624d51 2773 words: 9,
1cf1bbaf 2774 strength: "weak",
c6624d51
IC
2775 },
2776 {
2777 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
fb353f9d
IC
2778 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD",
2779 type: "hexadecimal",
2780 events: 32,
2781 bits: 128,
c6624d51 2782 words: 12,
e6a799cc
IC
2783 strength: "easily cracked",
2784 },
2785 {
2786 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA",
2787 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA",
2788 type: "hexadecimal",
2789 events: 32,
2790 bits: 128,
2791 words: 12,
1cf1bbaf 2792 strength: "strong",
c6624d51
IC
2793 },
2794 {
e6a799cc
IC
2795 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE",
2796 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE",
fb353f9d
IC
2797 type: "hexadecimal",
2798 events: 40,
2799 bits: 160,
c6624d51 2800 words: 15,
1cf1bbaf
IC
2801 strength: "very strong",
2802 },
2803 {
e6a799cc
IC
2804 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF",
2805 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF",
fb353f9d
IC
2806 type: "hexadecimal",
2807 events: 48,
2808 bits: 192,
1cf1bbaf
IC
2809 words: 18,
2810 strength: "extremely strong",
fb353f9d 2811 },
391c7f26
IC
2812 {
2813 entropy: "7d",
2814 type: "card",
2815 events: 1,
2816 bits: 5,
2817 words: 0,
2818 strength: "extremely weak",
2819 },
2820 {
2821 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2822 type: "card (full deck)",
2823 events: 52,
6422c1cd
IC
2824 bits: 225,
2825 words: 21,
391c7f26
IC
2826 strength: "extremely strong",
2827 },
2828 {
2829 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
2830 type: "card (full deck, 1 duplicate: 3d)",
2831 events: 53,
87ad2c6e 2832 bits: 254,
6422c1cd 2833 words: 21,
391c7f26
IC
2834 strength: "extremely strong",
2835 },
2836 {
2837 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
bbc29c80 2838 type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
391c7f26 2839 events: 53,
87ad2c6e 2840 bits: 254,
6422c1cd 2841 words: 21,
391c7f26
IC
2842 strength: "extremely strong",
2843 },
2844 {
2845 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
bbc29c80 2846 type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
391c7f26 2847 events: 53,
87ad2c6e
IC
2848 bits: 264,
2849 words: 24,
391c7f26
IC
2850 strength: "extremely strong",
2851 },
9bc39377 2852 // Next test was throwing uncaught error in zxcvbn
6422c1cd 2853 // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
9bc39377
IC
2854 {
2855 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2856 type: "card (full deck, 52 duplicates: ac 2c 3c...)",
2857 events: 104,
87ad2c6e
IC
2858 bits: 499,
2859 words: 45,
9bc39377
IC
2860 strength: "extremely strong",
2861 },
5c653a12
IC
2862 // Case insensitivity to duplicate cards
2863 {
2864 entropy: "asAS",
2865 type: "card (1 duplicate: AS)",
2866 events: 2,
87ad2c6e 2867 bits: 9,
5c653a12
IC
2868 words: 0,
2869 strength: "extremely weak",
2870 },
2871 {
2872 entropy: "ASas",
2873 type: "card (1 duplicate: as)",
2874 events: 2,
87ad2c6e 2875 bits: 9,
5c653a12
IC
2876 words: 0,
2877 strength: "extremely weak",
2878 },
bbc29c80
IC
2879 // Missing cards are detected
2880 {
2881 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2882 type: "card (1 missing: 9C)",
2883 events: 51,
87ad2c6e
IC
2884 bits: 221,
2885 words: 18,
bbc29c80
IC
2886 strength: "extremely strong",
2887 },
2888 {
2889 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2890 type: "card (2 missing: 9C 5D)",
2891 events: 50,
87ad2c6e
IC
2892 bits: 216,
2893 words: 18,
bbc29c80
IC
2894 strength: "extremely strong",
2895 },
2896 {
2897 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2898 type: "card (4 missing: 9C 5D QD...)",
2899 events: 48,
87ad2c6e 2900 bits: 208,
6422c1cd 2901 words: 18,
bbc29c80
IC
2902 strength: "extremely strong",
2903 },
2904 // More than six missing cards does not show message
2905 {
2906 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
2907 type: "card",
2908 events: 45,
87ad2c6e 2909 bits: 195,
6422c1cd 2910 words: 18,
bbc29c80
IC
2911 strength: "extremely strong",
2912 },
fc7c248f
IC
2913 // Multiple decks of cards increases bits per event
2914 {
2915 entropy: "3d",
2916 events: 1,
2917 bits: 4,
2918 bitsPerEvent: 4.34,
2919 },
2920 {
2921 entropy: "3d3d",
2922 events: 2,
2923 bits: 9,
2924 bitsPerEvent: 4.80,
2925 },
2926 {
2927 entropy: "3d3d3d",
2928 events: 3,
2929 bits: 15,
2930 bitsPerEvent: 5.01,
2931 },
2932 {
2933 entropy: "3d3d3d3d",
2934 events: 4,
2935 bits: 20,
2936 bitsPerEvent: 5.14,
2937 },
2938 {
2939 entropy: "3d3d3d3d3d",
2940 events: 5,
2941 bits: 26,
2942 bitsPerEvent: 5.22,
2943 },
2944 {
2945 entropy: "3d3d3d3d3d3d",
2946 events: 6,
2947 bits: 31,
2948 bitsPerEvent: 5.28,
2949 },
2950 {
2951 entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
2952 events: 33,
2953 bits: 184,
2954 bitsPerEvent: 5.59,
2955 strength: 'easily cracked - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
2956 },
c6624d51
IC
2957 ];
2958 // use entropy
2959 page.evaluate(function() {
2960 $(".use-entropy").prop("checked", true).trigger("change");
2961 });
2962 var nextTest = function runNextTest(i) {
fb353f9d 2963 function getFeedbackError(expected, actual) {
391c7f26 2964 if ("filtered" in expected && actual.indexOf(expected.filtered) == -1) {
fb353f9d
IC
2965 return "Filtered value not in feedback";
2966 }
fc7c248f 2967 if ("type" in expected && actual.indexOf(expected.type) == -1) {
fb353f9d
IC
2968 return "Entropy type not in feedback";
2969 }
fc7c248f 2970 if ("events" in expected && actual.indexOf(expected.events) == -1) {
fb353f9d
IC
2971 return "Event count not in feedback";
2972 }
fc7c248f 2973 if ("bits" in expected && actual.indexOf(expected.bits) == -1) {
fb353f9d
IC
2974 return "Bit count not in feedback";
2975 }
fc7c248f 2976 if ("strength" in expected && actual.indexOf(expected.strength) == -1) {
fb353f9d
IC
2977 return "Strength not in feedback";
2978 }
fc7c248f
IC
2979 if ("bitsPerEvent" in expected && actual.indexOf(expected.bitsPerEvent) == -1) {
2980 return "bitsPerEvent not in feedback";
2981 }
fb353f9d
IC
2982 return false;
2983 }
c6624d51
IC
2984 test = tests[i];
2985 page.evaluate(function(e) {
2986 $(".addresses").empty();
057722b0 2987 $(".phrase").val("");
c6624d51
IC
2988 $(".entropy").val(e).trigger("input");
2989 }, test.entropy);
fb353f9d 2990 waitForEntropyFeedback(function() {
c6624d51
IC
2991 var mnemonic = page.evaluate(function() {
2992 return $(".phrase").val();
2993 });
fb353f9d 2994 // Check mnemonic length
fc7c248f 2995 if ("words" in test && test.words == 0) {
fb353f9d
IC
2996 if (mnemonic.length > 0) {
2997 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
87ad2c6e 2998 console.log("Entropy: " + test.entropy);
fb353f9d
IC
2999 console.log("Mnemonic: " + mnemonic);
3000 fail();
3001 }
3002 }
fc7c248f 3003 else if ("words" in test) {
fb353f9d
IC
3004 if (mnemonic.split(" ").length != test.words) {
3005 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
87ad2c6e 3006 console.log("Entropy: " + test.entropy);
fb353f9d
IC
3007 console.log("Mnemonic: " + mnemonic);
3008 fail();
3009 }
3010 }
3011 // check feedback
3012 var feedback = page.evaluate(function() {
dd944906 3013 return $(".entropy-container").text();
fb353f9d
IC
3014 });
3015 var feedbackError = getFeedbackError(test, feedback);
3016 if (feedbackError) {
3017 console.log("Entropy feedback for " + test.entropy + " returned error");
3018 console.log(feedbackError);
c6624d51
IC
3019 fail();
3020 }
fb353f9d 3021 // Run next test
c6624d51
IC
3022 var isLastTest = i == tests.length - 1;
3023 if (isLastTest) {
3024 next();
3025 }
3026 else {
3027 runNextTest(i+1);
3028 }
fb353f9d 3029 });
c6624d51
IC
3030 }
3031 nextTest(0);
3032});
3033},
3034
d6fd8ebf 3035// Entropy is truncated from the left
c6624d51
IC
3036function() {
3037page.open(url, function(status) {
d6fd8ebf 3038 var expected = "avocado zoo zone";
c6624d51
IC
3039 // use entropy
3040 page.evaluate(function() {
3041 $(".use-entropy").prop("checked", true).trigger("change");
3042 var entropy = "00000000 00000000 00000000 00000000";
d6fd8ebf 3043 entropy += "11111111 11111111 11111111 1111"; // Missing last byte
c6624d51
IC
3044 $(".entropy").val(entropy).trigger("input");
3045 });
3046 // check the entropy is truncated from the right
3047 waitForGenerate(function() {
3048 var actual = page.evaluate(function() {
3049 return $(".phrase").val();
3050 });
3051 if (actual != expected) {
3052 console.log("Entropy is not truncated from the right");
3053 console.log("Expected: " + expected);
3054 console.log("Got: " + actual);
3055 fail();
3056 }
3057 next();
3058 });
3059});
3060},
3061
3062// Very large entropy results in very long mnemonics
3063function() {
3064page.open(url, function(status) {
3065 // use entropy
3066 page.evaluate(function() {
3067 $(".use-entropy").prop("checked", true).trigger("change");
3068 var entropy = "";
3069 // Generate a very long entropy string
3070 for (var i=0; i<33; i++) {
3071 entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
3072 }
3073 $(".entropy").val(entropy).trigger("input");
3074 });
3075 // check the mnemonic is very long
3076 waitForGenerate(function() {
3077 var wordCount = page.evaluate(function() {
3078 return $(".phrase").val().split(" ").length;
3079 });
3080 if (wordCount != 99) {
3081 console.log("Large entropy does not generate long mnemonic");
3082 console.log("Expected 99 words, got " + wordCount);
3083 fail();
3084 }
3085 next();
3086 });
3087});
3088},
3089
3090// Is compatible with bip32jp entropy
3091// https://bip32jp.github.io/english/index.html
3092// NOTES:
3093// Is incompatible with:
c6624d51
IC
3094// base 20
3095function() {
3096page.open(url, function(status) {
0d0f07f9 3097 var expected = "train then jungle barely whip fiber purpose puppy eagle cloud clump hospital robot brave balcony utility detect estate old green desk skill multiply virus";
c6624d51
IC
3098 // use entropy
3099 page.evaluate(function() {
3100 $(".use-entropy").prop("checked", true).trigger("change");
0d0f07f9 3101 var entropy = "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543";
c6624d51
IC
3102 $(".entropy").val(entropy).trigger("input");
3103 });
3104 // check the mnemonic matches the expected value from bip32jp
3105 waitForGenerate(function() {
3106 var actual = page.evaluate(function() {
3107 return $(".phrase").val();
3108 });
3109 if (actual != expected) {
3110 console.log("Mnemonic does not match bip32jp for base 6 entropy");
3111 console.log("Expected: " + expected);
3112 console.log("Got: " + actual);
3113 fail();
3114 }
3115 next();
3116 });
3117});
3118},
3119
057722b0
IC
3120// Blank entropy does not generate mnemonic or addresses
3121function() {
3122page.open(url, function(status) {
3123 // use entropy
3124 page.evaluate(function() {
3125 $(".use-entropy").prop("checked", true).trigger("change");
3126 $(".entropy").val("").trigger("input");
3127 });
3128 waitForFeedback(function() {
3129 // check there is no mnemonic
3130 var phrase = page.evaluate(function() {
3131 return $(".phrase").val();
3132 });
3133 if (phrase != "") {
3134 console.log("Blank entropy does not result in blank mnemonic");
3135 console.log("Got: " + phrase);
3136 fail();
3137 }
3138 // check there are no addresses displayed
3139 var addresses = page.evaluate(function() {
3140 return $(".address").length;
3141 });
3142 if (addresses != 0) {
3143 console.log("Blank entropy does not result in zero addresses");
3144 fail();
3145 }
3146 // Check the feedback says 'blank entropy'
3147 var feedback = page.evaluate(function() {
3148 return $(".feedback").text();
3149 });
3150 if (feedback != "Blank entropy") {
3151 console.log("Blank entropy does not show feedback message");
3152 fail();
3153 }
3154 next();
3155 });
3156});
3157},
3158
3599674d
IC
3159// Mnemonic length can be selected even for weak entropy
3160function() {
3161page.open(url, function(status) {
3162 // use entropy
3163 page.evaluate(function() {
3164 $(".use-entropy").prop("checked", true).trigger("change");
3165 $(".entropy").val("012345");
3166 $(".mnemonic-length").val("18").trigger("change");
3167 });
3168 // check the mnemonic is the correct length
3169 waitForGenerate(function() {
3170 var phrase = page.evaluate(function() {
3171 return $(".phrase").val();
3172 });
3173 var numberOfWords = phrase.split(/\s/g).length;
3174 if (numberOfWords != 18) {
3175 console.log("Weak entropy cannot be overridden to give 18 word mnemonic");
3176 console.log(phrase);
3177 fail();
3178 }
3179 next();
3180 });
3181});
3182},
3183
886f06ee
IC
3184// Github issue 33
3185// https://github.com/iancoleman/bip39/issues/33
3186// Final cards should contribute entropy
3187function() {
3188page.open(url, function(status) {
3189 // use entropy
3190 page.evaluate(function() {
3191 $(".use-entropy").prop("checked", true).trigger("change");
3192 $(".entropy").val("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-6C TS TH 4H KC 5H 2H AH 2C 8D 3H 5D").trigger("input");
3193 });
3194 // get the mnemonic
3195 waitForGenerate(function() {
3196 var originalPhrase = page.evaluate(function() {
3197 return $(".phrase").val();
3198 });
3199 // Set the last 12 cards to be AS
3200 page.evaluate(function() {
3201 $(".addresses").empty();
3202 $(".entropy").val("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-AS AS AS AS AS AS AS AS AS AS AS AS").trigger("input");
3203 });
3204 // get the new mnemonic
3205 waitForGenerate(function() {
3206 var newPhrase = page.evaluate(function() {
3207 return $(".phrase").val();
3208 });
92e73fd9 3209 // check the phrase has changed
886f06ee
IC
3210 if (newPhrase == originalPhrase) {
3211 console.log("Changing last 12 cards does not change mnemonic");
3212 console.log("Original:");
3213 console.log(originalPhrase);
3214 console.log("New:");
3215 console.log(newPhrase);
3216 fail();
3217 }
3218 next();
3219 });
3220 });
3221});
3222},
3223
e00964cc
IC
3224// Github issue 35
3225// https://github.com/iancoleman/bip39/issues/35
3226// QR Code support
3227function() {
3228page.open(url, function(status) {
3229 // use entropy
3230 page.evaluate(function() {
3231 $(".generate").click();
3232 });
3233 waitForGenerate(function() {
3234 var p = page.evaluate(function() {
3235 // get position of mnemonic element
3236 return $(".phrase").offset();
3237 });
3238 p.top = Math.ceil(p.top);
3239 p.left = Math.ceil(p.left);
3240 // check the qr code shows
3241 page.sendEvent("mousemove", p.left+4, p.top+4);
3242 var qrShowing = page.evaluate(function() {
3243 return $(".qr-container").find("canvas").length > 0;
3244 });
3245 if (!qrShowing) {
3246 console.log("QR Code does not show");
3247 fail();
3248 }
3249 // check the qr code hides
3250 page.sendEvent("mousemove", p.left-4, p.top-4);
3251 var qrHidden = page.evaluate(function() {
3252 return $(".qr-container").find("canvas").length == 0;
3253 });
3254 if (!qrHidden) {
3255 console.log("QR Code does not hide");
3256 fail();
3257 }
3258 next();
3259 });
3260});
3261},
3262
c554e6ff
IC
3263// BIP44 account extendend private key is shown
3264// github issue 37 - compatibility with electrum
3265function() {
3266page.open(url, function(status) {
3267 // set the phrase
3268 var expected = "xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ";
3269 page.evaluate(function() {
3270 $(".phrase").val("abandon abandon ability");
3271 $(".phrase").trigger("input");
3272 });
3273 // check the BIP44 account extended private key
3274 waitForGenerate(function() {
3275 var actual = page.evaluate(function() {
3276 return $(".account-xprv").val();
3277 });
3278 if (actual != expected) {
3279 console.log("BIP44 account extended private key is incorrect");
3280 console.log("Expected: " + expected);
3281 console.log("Actual: " + actual);
3282 fail();
3283 }
3284 next();
3285 });
3286});
3287},
3288
3289// BIP44 account extendend public key is shown
3290// github issue 37 - compatibility with electrum
3291function() {
3292page.open(url, function(status) {
3293 // set the phrase
3294 var expected = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3295 page.evaluate(function() {
3296 $(".phrase").val("abandon abandon ability");
3297 $(".phrase").trigger("input");
3298 });
3299 // check the BIP44 account extended public key
3300 waitForGenerate(function() {
3301 var actual = page.evaluate(function() {
3302 return $(".account-xpub").val();
3303 });
3304 if (actual != expected) {
3305 console.log("BIP44 account extended public key is incorrect");
3306 console.log("Expected: " + expected);
ba3cb9ec
IC
3307 console.log("Actual: " + actual);
3308 fail();
3309 }
3310 next();
3311 });
3312});
3313},
3314
3315// github issue 40
3316// BIP32 root key can be set as an xpub
3317function() {
3318page.open(url, function(status) {
3319 // set the phrase
3320 page.evaluate(function() {
3321 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3322 var bip44AccountXpub = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3323 $("#root-key").val(bip44AccountXpub);
3324 $("#root-key").trigger("input");
3325 });
3326 waitForFeedback(function() {
3327 page.evaluate(function() {
3328 // Use bip32 tab
3329 $("#bip32-tab a").click();
3330 });
3331 waitForGenerate(function() {
3332 page.evaluate(function() {
3333 // derive external addresses for this xpub
3334 var firstAccountDerivationPath = "m/0";
3335 $("#bip32-path").val(firstAccountDerivationPath);
3336 $("#bip32-path").trigger("input");
3337 });
3338 waitForGenerate(function() {
3339 // check the addresses are generated
3340 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
3341 var actual = page.evaluate(function() {
3342 return $(".address:first").text();
3343 });
3344 if (actual != expected) {
3345 console.log("xpub key does not generate addresses in table");
3346 console.log("Expected: " + expected);
3347 console.log("Actual: " + actual);
3348 fail();
3349 }
3350 // check the xprv key is not set
3351 var expected = "NA";
3352 var actual = page.evaluate(function() {
3353 return $(".extended-priv-key").val();
3354 });
3355 if (actual != expected) {
3356 console.log("xpub key as root shows derived bip32 xprv key");
3357 console.log("Expected: " + expected);
3358 console.log("Actual: " + actual);
3359 fail();
3360 }
3361 // check the private key is not set
3362 var expected = "NA";
3363 var actual = page.evaluate(function() {
3364 return $(".privkey:first").text();
3365 });
3366 if (actual != expected) {
3367 console.log("xpub key generates private key in addresses table");
3368 console.log("Expected: " + expected);
3369 console.log("Actual: " + actual);
3370 fail();
3371 }
3372 next();
3373 });
3374 });
3375 });
3376});
3377},
3378
3379// github issue 40
3380// xpub for bip32 root key will not work with hardened derivation paths
3381function() {
3382page.open(url, function(status) {
3383 // set the phrase
3384 page.evaluate(function() {
3385 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3386 var bip44AccountXpub = "xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf";
3387 $("#root-key").val(bip44AccountXpub);
3388 $("#root-key").trigger("input");
3389 });
3390 waitForFeedback(function() {
3391 // Check feedback is correct
3392 var expected = "Hardened derivation path is invalid with xpub key";
3393 var actual = page.evaluate(function() {
3394 return $(".feedback").text();
3395 });
3396 if (actual != expected) {
3397 console.log("xpub key with hardened derivation path does not show feedback");
3398 console.log("Expected: " + expected);
3399 console.log("Actual: " + actual);
3400 fail();
3401 }
3402 // Check no addresses are shown
3403 var expected = 0;
3404 var actual = page.evaluate(function() {
3405 return $(".addresses tr").length;
3406 });
3407 if (actual != expected) {
3408 console.log("addresses still show after setting xpub key with hardened derivation path");
3409 console.log("Expected: " + expected);
c554e6ff
IC
3410 console.log("Actual: " + actual);
3411 fail();
3412 }
3413 next();
3414 });
3415});
3416},
3417
0a1f0259
IC
3418// github issue 39
3419// no root key shows feedback
3420function() {
3421page.open(url, function(status) {
3422 // click the bip32 tab on fresh page
3423 page.evaluate(function() {
3424 $("#bip32-tab a").click();
3425 });
3426 waitForFeedback(function() {
3427 // Check feedback is correct
3428 var expected = "No root key";
3429 var actual = page.evaluate(function() {
3430 return $(".feedback").text();
3431 });
3432 if (actual != expected) {
3433 console.log("Blank root key not detected");
3434 console.log("Expected: " + expected);
3435 console.log("Actual: " + actual);
3436 fail();
3437 }
3438 next();
3439 });
3440});
3441},
886f06ee 3442
40892aba
IC
3443// Github issue 44
3444// display error switching tabs while addresses are generating
3445function() {
3446page.open(url, function(status) {
3447 // set the phrase
3448 page.evaluate(function() {
3449 $(".phrase").val("abandon abandon ability").trigger("input");
3450 });
3451 waitForGenerate(function() {
3452 // set to generate 500 more addresses
3453 // generate more addresses
3454 // change tabs which should cancel the previous generating
3455 page.evaluate(function() {
3456 $(".rows-to-add").val("100");
3457 $(".more").click();
3458 $("#bip32-tab a").click();
3459 });
3460 // check the derivation paths are in order and of the right quantity
3461 waitForGenerate(function() {
3462 var paths = page.evaluate(function() {
3463 return $(".index").map(function(i, e) {
3464 return $(e).text();
3465 });
3466 });
3467 for (var i=0; i<paths.length; i++) {
3468 var expected = "m/0/" + i;
3469 var actual = paths[i];
3470 if (actual != expected) {
3471 console.log("Path " + i + " is not in correct order");
3472 console.log("Expected: " + expected);
3473 console.log("Actual: " + actual);
3474 fail();
3475 }
3476 }
3477 if (paths.length != 20) {
3478 console.log("Generation was not cancelled by new action");
3479 fail();
3480 }
3481 next();
3482 });
3483 });
3484});
3485},
3486
53aaab27
IC
3487// Github issue 49
3488// padding for binary should give length with multiple of 256
3489// hashed entropy 1111 is length 252, so requires 4 leading zeros
3490// prior to issue 49 it would only generate 2 leading zeros, ie missing 2
3491function() {
3492page.open(url, function(status) {
3493 expected = "avocado valid quantum cross link predict excuse edit street able flame large galaxy ginger nuclear"
3494 // use entropy
3495 page.evaluate(function() {
3496 $(".use-entropy").prop("checked", true).trigger("change");
5ed50bd9 3497 $(".mnemonic-length").val("15");
53aaab27
IC
3498 $(".entropy").val("1111").trigger("input");
3499 });
3500 waitForGenerate(function() {
3501 // get the mnemonic
3502 var actual = page.evaluate(function() {
3503 return $(".phrase").val();
3504 });
3505 // check the mnemonic is correct
3506 if (actual != expected) {
3507 console.log("Left padding error for entropy");
3508 console.log("Expected: " + expected);
3509 console.log("Actual: " + actual);
3510 fail();
3511 }
3512 next();
3513 });
3514});
3515},
3516
cdfaaf00
IC
3517// Github pull request 55
3518// https://github.com/iancoleman/bip39/pull/55
3519// Client select
3520function() {
3521page.open(url, function(status) {
3522 // set mnemonic and select bip32 tab
3523 page.evaluate(function() {
3524 $("#bip32-tab a").click();
3525 $(".phrase").val("abandon abandon ability").trigger("input");
3526 });
3527 waitForGenerate(function() {
3528 // BITCOIN CORE
3529 // set bip32 client to bitcoin core
3530 page.evaluate(function() {
3531 var bitcoinCoreIndex = "0";
3532 $("#bip32-client").val(bitcoinCoreIndex).trigger("change");
3533 });
3534 waitForGenerate(function() {
3535 // get the derivation path
3536 var actual = page.evaluate(function() {
3537 return $("#bip32-path").val();
3538 });
3539 // check the derivation path is correct
3540 expected = "m/0'/0'"
3541 if (actual != expected) {
3542 console.log("Selecting Bitcoin Core client does not set correct derivation path");
3543 console.log("Expected: " + expected);
3544 console.log("Actual: " + actual);
3545 fail();
3546 }
3547 // get hardened addresses
3548 var usesHardenedAddresses = page.evaluate(function() {
3549 return $(".hardened-addresses").prop("checked");
3550 });
3551 // check hardened addresses is selected
3552 if(!usesHardenedAddresses) {
3553 console.log("Selecting Bitcoin Core client does not use hardened addresses");
3554 fail();
3555 }
3556 // check input is readonly
3557 var pathIsReadonly = page.evaluate(function() {
3558 return $("#bip32-path").prop("readonly");
3559 });
3560 if (!pathIsReadonly) {
3561 console.log("Selecting Bitcoin Core client does not set derivation path to readonly");
3562 fail();
3563 }
3564 // MULTIBIT
3565 // set bip32 client to multibit
3566 page.evaluate(function() {
3567 var multibitIndex = "2";
3568 $("#bip32-client").val(multibitIndex).trigger("change");
3569 });
3570 waitForGenerate(function() {
3571 // get the derivation path
3572 var actual = page.evaluate(function() {
3573 return $("#bip32-path").val();
3574 });
3575 // check the derivation path is correct
3576 expected = "m/0'/0"
3577 if (actual != expected) {
3578 console.log("Selecting Multibit client does not set correct derivation path");
3579 console.log("Expected: " + expected);
3580 console.log("Actual: " + actual);
3581 fail();
3582 }
3583 // get hardened addresses
3584 var usesHardenedAddresses = page.evaluate(function() {
3585 return $(".hardened-addresses").prop("checked");
3586 });
3587 // check hardened addresses is selected
3588 if(usesHardenedAddresses) {
3589 console.log("Selecting Multibit client does not uncheck hardened addresses");
3590 fail();
3591 }
3592 // CUSTOM DERIVATION PATH
3593 // check input is not readonly
3594 page.evaluate(function() {
3595 $("#bip32-client").val("custom").trigger("change");
3596 });
3597 // do not wait for generate, since there is no change to the
3598 // derivation path there is no new generation performed
3599 var pathIsReadonly = page.evaluate(function() {
3600 return $("#bip32-path").prop("readonly");
3601 });
3602 if (pathIsReadonly) {
3603 console.log("Selecting Custom Derivation Path does not allow derivation path input");
3604 fail();
3605 }
3606 next();
3607 });
3608 });
3609 });
3610});
3611},
3612
e6f08c6a
IC
3613// github issue 58
3614// https://github.com/iancoleman/bip39/issues/58
3615// bip32 derivation is correct, does not drop leading zeros
3616// see also
3617// https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846
3618function() {
3619page.open(url, function(status) {
3620 // set the phrase and passphrase
3621 var expected = "17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F";
3622 // Note that bitcore generates an incorrect address
3623 // 13EuKhffWkBE2KUwcbkbELZb1MpzbimJ3Y
3624 // see the medium.com link above for more details
3625 page.evaluate(function() {
3626 $(".phrase").val("fruit wave dwarf banana earth journey tattoo true farm silk olive fence");
3627 $(".passphrase").val("banana").trigger("input");
3628 });
3629 // check the address is generated correctly
3630 waitForGenerate(function() {
3631 var actual = page.evaluate(function() {
3632 return $(".address:first").text();
3633 });
3634 if (actual != expected) {
3635 console.log("BIP32 derivation is incorrect");
3636 console.log("Expected: " + expected);
d2d98ef7
IC
3637 console.log("Actual: " + actual);
3638 fail();
3639 }
3640 next();
3641 });
3642});
3643},
3644
3645
3646// github issue 60
3647// Japanese mnemonics generate incorrect bip32 seed
3648// BIP39 seed is set from phrase
3649function() {
3650page.open(url, function(status) {
3651 // set the phrase
3652 var expected = "a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55";
3653 page.evaluate(function() {
3654 $(".phrase").val("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら");
3655 $("#passphrase").val("メートルガバヴァぱばぐゞちぢ十人十色");
3656 $("#passphrase").trigger("input");
3657 });
3658 // check the seed is generated correctly
3659 waitForGenerate(function() {
3660 var actual = page.evaluate(function() {
3661 return $(".seed").val();
3662 });
3663 if (actual != expected) {
3664 console.log("BIP39 seed is incorrectly generated from Japanese mnemonic");
3665 console.log("Expected: " + expected);
e6f08c6a
IC
3666 console.log("Actual: " + actual);
3667 fail();
3668 }
3669 next();
3670 });
3671});
3672},
3673
b0fb45b9
IC
3674// If you wish to add more tests, do so here...
3675
3676// Here is a blank test template
3677/*
3678
3679function() {
3680page.open(url, function(status) {
3681 // Do something on the page
3682 page.evaluate(function() {
3683 $(".phrase").val("abandon abandon ability").trigger("input");
3684 });
3685 waitForGenerate(function() {
3686 // Check the result of doing the thing
3687 var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug";
3688 var actual = page.evaluate(function() {
3689 return $(".address:first").text();
3690 });
3691 if (actual != expected) {
3692 console.log("A specific message about what failed");
3693 console.log("Expected: " + expected);
3694 console.log("Actual: " + actual);
3695 fail();
3696 }
3697 // Run the next test
3698 next();
3699 });
3700});
3701},
3702
3703*/
3704
88e2cdaa
IC
3705];
3706
3707console.log("Running tests...");
fb372687 3708tests = shuffle(tests);
88e2cdaa 3709next();