aboutsummaryrefslogtreecommitdiff
path: root/tests.js
diff options
context:
space:
mode:
authorIan Coleman <coleman.ian@gmail.com>2016-11-03 16:34:56 +1100
committerIan Coleman <coleman.ian@gmail.com>2016-11-04 15:14:13 +1100
commitc6624d51f4e5607202e48903352574c47571baab (patch)
treeee57075575c8f9b88e13eb7efff083bb9fa2b39c /tests.js
parentd737abf6809622228faf7d5fe54101e2d87d72a4 (diff)
downloadBIP39-c6624d51f4e5607202e48903352574c47571baab.tar.gz
BIP39-c6624d51f4e5607202e48903352574c47571baab.tar.zst
BIP39-c6624d51f4e5607202e48903352574c47571baab.zip
Entropy can be supplied by user
Diffstat (limited to 'tests.js')
-rw-r--r--tests.js607
1 files changed, 607 insertions, 0 deletions
diff --git a/tests.js b/tests.js
index 914be24..ec368cb 100644
--- a/tests.js
+++ b/tests.js
@@ -1960,6 +1960,613 @@ page.open(url, function(status) {
1960}); 1960});
1961}, 1961},
1962 1962
1963// Entropy unit tests
1964function() {
1965page.open(url, function(status) {
1966 var error = page.evaluate(function() {
1967 var e;
1968 // binary entropy is detected
1969 e = Entropy.fromString("01010101");
1970 if (e.base.str != "binary") {
1971 return "Binary entropy not detected correctly";
1972 }
1973 // base6 entropy is detected
1974 e = Entropy.fromString("012345012345");
1975 if (e.base.str != "base 6") {
1976 return "base6 entropy not detected correctly";
1977 }
1978 // dice entropy is detected
1979 e = Entropy.fromString("123456123456");
1980 if (e.base.str != "base 6 (dice)") {
1981 return "dice entropy not detected correctly";
1982 }
1983 // base10 entropy is detected
1984 e = Entropy.fromString("0123456789");
1985 if (e.base.str != "base 10") {
1986 return "base10 entropy not detected correctly";
1987 }
1988 // hex entropy is detected
1989 e = Entropy.fromString("0123456789ABCDEF");
1990 if (e.base.str != "hexadecimal") {
1991 return "hexadecimal entropy not detected correctly";
1992 }
1993 // entropy is case insensitive
1994 e = Entropy.fromString("aBcDeF");
1995 if (e.cleanStr != "aBcDeF") {
1996 return "Entropy should not be case sensitive";
1997 }
1998 // dice entropy is converted to base6
1999 e = Entropy.fromString("123456");
2000 if (e.cleanStr != "012345") {
2001 return "Dice entropy is not automatically converted to base6";
2002 }
2003 // dice entropy is preferred to base6 if ambiguous
2004 e = Entropy.fromString("12345");
2005 if (e.base.str != "base 6 (dice)") {
2006 return "dice not used as default over base 6";
2007 }
2008 // unused characters are ignored
2009 e = Entropy.fromString("fghijkl");
2010 if (e.cleanStr != "f") {
2011 return "additional characters are not ignored";
2012 }
2013 // the lowest base is used by default
2014 // 7 could be decimal or hexadecimal, but should be detected as decimal
2015 e = Entropy.fromString("7");
2016 if (e.base.str != "base 10") {
2017 return "lowest base is not used";
2018 }
2019 // Hexadecimal representation is returned
2020 e = Entropy.fromString("1010");
2021 if (e.hexStr != "A") {
2022 return "Hexadecimal representation not returned";
2023 }
2024 // Leading zeros are retained
2025 e = Entropy.fromString("000A");
2026 if (e.cleanStr != "000A") {
2027 return "Leading zeros are not retained";
2028 }
2029 // Leading zeros are correctly preserved for hex in binary string
2030 e = Entropy.fromString("2A");
2031 if (e.binaryStr != "00101010") {
2032 return "Hex leading zeros are not correct in binary";
2033 }
2034 // Keyboard mashing results in weak entropy
2035 // Despite being a long string, it's less than 30 bits of entropy
2036 e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj");
2037 if (e.binaryStr.length >= 30) {
2038 return "Keyboard mashing should produce weak entropy";
2039 }
2040 return false;
2041 });
2042 if (error) {
2043 console.log("Entropy unit tests");
2044 console.log(error);
2045 fail();
2046 };
2047 next();
2048});
2049},
2050
2051// Entropy can be entered by the user
2052function() {
2053page.open(url, function(status) {
2054 expected = {
2055 mnemonic: "abandon abandon ability",
2056 address: "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug",
2057 }
2058 // use entropy
2059 page.evaluate(function() {
2060 $(".use-entropy").prop("checked", true).trigger("change");
2061 $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
2062 });
2063 // check the mnemonic is set and address is correct
2064 waitForGenerate(function() {
2065 var actual = page.evaluate(function() {
2066 return {
2067 address: $(".address:first").text(),
2068 mnemonic: $(".phrase").val(),
2069 }
2070 });
2071 if (actual.mnemonic != expected.mnemonic) {
2072 console.log("Entropy does not generate correct mnemonic");
2073 console.log("Expected: " + expected.mnemonic);
2074 console.log("Got: " + actual.mnemonic);
2075 fail();
2076 }
2077 if (actual.address != expected.address) {
2078 console.log("Entropy does not generate correct address");
2079 console.log("Expected: " + expected.address);
2080 console.log("Got: " + actual.address);
2081 fail();
2082 }
2083 next();
2084 });
2085});
2086},
2087
2088// A warning about entropy is shown to the user, with additional information
2089function() {
2090page.open(url, function(status) {
2091 // get text content from entropy sections of page
2092 var hasWarning = page.evaluate(function() {
2093 var entropyText = $(".entropy-container").text();
2094 var warning = "mnemonic may be insecure";
2095 if (entropyText.indexOf(warning) == -1) {
2096 return false;
2097 }
2098 var readMoreText = $("#entropy-notes").parent().text();
2099 var goodSources = "flipping a fair coin, rolling a fair dice, noise measurements etc";
2100 if (readMoreText.indexOf(goodSources) == -1) {
2101 return false;
2102 }
2103 return true;
2104 });
2105 // check the warnings and information are shown
2106 if (!hasWarning) {
2107 console.log("Page does not contain warning about using own entropy");
2108 fail();
2109 }
2110 next();
2111});
2112},
2113
2114// The types of entropy available are described to the user
2115function() {
2116page.open(url, function(status) {
2117 // get placeholder text for entropy field
2118 var placeholder = page.evaluate(function() {
2119 return $(".entropy").attr("placeholder");
2120 });
2121 var options = [
2122 "binary",
2123 "base 6",
2124 "dice",
2125 "base 10",
2126 "hexadecimal",
2127 ];
2128 for (var i=0; i<options.length; i++) {
2129 var option = options[i];
2130 if (placeholder.indexOf(option) == -1) {
2131 console.log("Available entropy type is not shown to user: " + option);
2132 fail();
2133 }
2134 }
2135 next();
2136});
2137},
2138
2139// The actual entropy used is shown to the user
2140function() {
2141page.open(url, function(status) {
2142 // use entropy
2143 var badEntropySource = page.evaluate(function() {
2144 var entropy = "Not A Very Good Entropy Source At All";
2145 $(".use-entropy").prop("checked", true).trigger("change");
2146 $(".entropy").val(entropy).trigger("input");
2147 });
2148 // check the actual entropy being used is shown
2149 waitForGenerate(function() {
2150 var expectedText = "AedEceAA";
2151 var entropyText = page.evaluate(function() {
2152 return $(".entropy-container").text();
2153 });
2154 if (entropyText.indexOf(expectedText) == -1) {
2155 console.log("Actual entropy used is not shown");
2156 fail();
2157 }
2158 next();
2159 });
2160});
2161},
2162
2163// Binary entropy can be entered
2164function() {
2165page.open(url, function(status) {
2166 // use entropy
2167 page.evaluate(function() {
2168 $(".use-entropy").prop("checked", true).trigger("change");
2169 $(".entropy").val("01").trigger("input");
2170 });
2171 // check the entropy is shown to be the correct type
2172 waitForGenerate(function() {
2173 var entropyText = page.evaluate(function() {
2174 return $(".entropy-container").text();
2175 });
2176 if (entropyText.indexOf("binary") == -1) {
2177 console.log("Binary entropy is not detected and presented to user");
2178 fail();
2179 }
2180 next();
2181 });
2182});
2183},
2184
2185// Base 6 entropy can be entered
2186function() {
2187page.open(url, function(status) {
2188 // use entropy
2189 page.evaluate(function() {
2190 $(".use-entropy").prop("checked", true).trigger("change");
2191 $(".entropy").val("012345").trigger("input");
2192 });
2193 // check the entropy is shown to be the correct type
2194 waitForGenerate(function() {
2195 var entropyText = page.evaluate(function() {
2196 return $(".entropy-container").text();
2197 });
2198 if (entropyText.indexOf("base 6") == -1) {
2199 console.log("Base 6 entropy is not detected and presented to user");
2200 fail();
2201 }
2202 next();
2203 });
2204});
2205},
2206
2207// Base 6 dice entropy can be entered
2208function() {
2209page.open(url, function(status) {
2210 // use entropy
2211 page.evaluate(function() {
2212 $(".use-entropy").prop("checked", true).trigger("change");
2213 $(".entropy").val("123456").trigger("input");
2214 });
2215 // check the entropy is shown to be the correct type
2216 waitForGenerate(function() {
2217 var entropyText = page.evaluate(function() {
2218 return $(".entropy-container").text();
2219 });
2220 if (entropyText.indexOf("dice") == -1) {
2221 console.log("Dice entropy is not detected and presented to user");
2222 fail();
2223 }
2224 next();
2225 });
2226});
2227},
2228
2229// Base 10 entropy can be entered
2230function() {
2231page.open(url, function(status) {
2232 // use entropy
2233 page.evaluate(function() {
2234 $(".use-entropy").prop("checked", true).trigger("change");
2235 $(".entropy").val("789").trigger("input");
2236 });
2237 // check the entropy is shown to be the correct type
2238 waitForGenerate(function() {
2239 var entropyText = page.evaluate(function() {
2240 return $(".entropy-container").text();
2241 });
2242 if (entropyText.indexOf("base 10") == -1) {
2243 console.log("Base 10 entropy is not detected and presented to user");
2244 fail();
2245 }
2246 next();
2247 });
2248});
2249},
2250
2251// Hexadecimal entropy can be entered
2252function() {
2253page.open(url, function(status) {
2254 // use entropy
2255 page.evaluate(function() {
2256 $(".use-entropy").prop("checked", true).trigger("change");
2257 $(".entropy").val("abcdef").trigger("input");
2258 });
2259 // check the entropy is shown to be the correct type
2260 waitForGenerate(function() {
2261 var entropyText = page.evaluate(function() {
2262 return $(".entropy-container").text();
2263 });
2264 if (entropyText.indexOf("hexadecimal") == -1) {
2265 console.log("Hexadecimal entropy is not detected and presented to user");
2266 fail();
2267 }
2268 next();
2269 });
2270});
2271},
2272
2273// Dice entropy value is shown as the converted base 6 value
2274function() {
2275page.open(url, function(status) {
2276 // use entropy
2277 page.evaluate(function() {
2278 $(".use-entropy").prop("checked", true).trigger("change");
2279 $(".entropy").val("123456").trigger("input");
2280 });
2281 // check the entropy is shown as base 6, not as the original dice value
2282 waitForGenerate(function() {
2283 var entropyText = page.evaluate(function() {
2284 return $(".entropy-container").text();
2285 });
2286 if (entropyText.indexOf("012345") == -1) {
2287 console.log("Dice entropy is not shown to user as base 6 value");
2288 fail();
2289 }
2290 if (entropyText.indexOf("123456") > -1) {
2291 console.log("Dice entropy value is shown instead of true base 6 value");
2292 fail();
2293 }
2294 next();
2295 });
2296});
2297},
2298
2299// The number of bits of entropy accumulated is shown
2300function() {
2301page.open(url, function(status) {
2302 var tests = {
2303 "0000 0000 0000 0000 0000": "20",
2304 "0": "1",
2305 "0000": "4",
2306 "6": "3",
2307 "7": "3",
2308 "8": "4",
2309 "F": "4",
2310 "29": "5",
2311 "0A": "8",
2312 "1A": "8", // hex is always multiple of 4 bits of entropy
2313 "2A": "8",
2314 "4A": "8",
2315 "8A": "8",
2316 "FA": "8",
2317 "000A": "16",
2318 "2220": "10",
2319 "2221": "9", // uses dice, so entropy is actually 1110
2320 "2227": "12",
2321 "222F": "16",
2322 "FFFF": "16",
2323 }
2324 // Arrange tests in array so last one can be easily detected
2325 var entropys = [];
2326 var results = [];
2327 for (var entropy in tests) {
2328 entropys.push(entropy);
2329 results.push(tests[entropy]);
2330 }
2331 // use entropy
2332 page.evaluate(function(e) {
2333 $(".use-entropy").prop("checked", true).trigger("change");
2334 });
2335 // Run each test
2336 var nextTest = function runNextTest(i) {
2337 var entropy = entropys[i];
2338 var expected = results[i];
2339 // set entropy
2340 page.evaluate(function(e) {
2341 $(".addresses").empty(); // bit of a hack, but needed for waitForGenerate
2342 $(".entropy").val(e).trigger("input");
2343 }, entropy);
2344 // check the number of bits of entropy is shown
2345 waitForGenerate(function() {
2346 var entropyText = page.evaluate(function() {
2347 return $(".entropy-container").text();
2348 });
2349 if (entropyText.indexOf("Have " + expected + " bits of entropy") == -1) {
2350 console.log("Accumulated entropy is not shown correctly for " + entropy);
2351 fail();
2352 }
2353 var isLastTest = i == results.length - 1;
2354 if (isLastTest) {
2355 next();
2356 }
2357 else {
2358 runNextTest(i+1);
2359 }
2360 });
2361 }
2362 nextTest(0);
2363});
2364},
2365
2366// The number of bits of entropy to reach the next mnemonic strength is shown
2367function() {
2368page.open(url, function(status) {
2369 // use entropy
2370 page.evaluate(function() {
2371 $(".use-entropy").prop("checked", true).trigger("change");
2372 $(".entropy").val("7654321").trigger("input");
2373 });
2374 // check the amount of additional entropy required is shown
2375 waitForGenerate(function() {
2376 var entropyText = page.evaluate(function() {
2377 return $(".entropy-container").text();
2378 });
2379 if (entropyText.indexOf("3 more base 10 chars required") == -1) {
2380 console.log("Additional entropy requirement is not shown");
2381 fail();
2382 }
2383 next();
2384 });
2385});
2386},
2387
2388// The next strength above 0-word mnemonics is considered extremely weak
2389// The next strength above 3-word mnemonics is considered very weak
2390// The next strength above 6-word mnemonics is considered weak
2391// The next strength above 9-word mnemonics is considered strong
2392// The next strength above 12-word mnemonics is considered very strong
2393// The next strength above 15-word mnemonics is considered extremely strong
2394function() {
2395page.open(url, function(status) {
2396 var tests = [
2397 {
2398 entropy: "A",
2399 words: 0,
2400 nextStrength: "an extremely weak",
2401 },
2402 {
2403 entropy: "AAAAAAAA",
2404 words: 3,
2405 nextStrength: "a very weak",
2406 },
2407 {
2408 entropy: "AAAAAAAA B",
2409 words: 3,
2410 nextStrength: "a very weak",
2411 },
2412 {
2413 entropy: "AAAAAAAA BBBBBBBB",
2414 words: 6,
2415 nextStrength: "a weak",
2416 },
2417 {
2418 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
2419 words: 9,
2420 nextStrength: "a strong",
2421 },
2422 {
2423 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
2424 words: 12,
2425 nextStrength: "a very strong",
2426 },
2427 {
2428 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE",
2429 words: 15,
2430 nextStrength: "an extremely strong",
2431 }
2432 ];
2433 // use entropy
2434 page.evaluate(function() {
2435 $(".use-entropy").prop("checked", true).trigger("change");
2436 });
2437 var nextTest = function runNextTest(i) {
2438 test = tests[i];
2439 page.evaluate(function(e) {
2440 $(".addresses").empty();
2441 $(".entropy").val(e).trigger("input");
2442 }, test.entropy);
2443 waitForGenerate(function() {
2444 // check the strength of the current mnemonic
2445 var mnemonic = page.evaluate(function() {
2446 return $(".phrase").val();
2447 });
2448 if (test.words == 0) {
2449 if (mnemonic.length > 0) {
2450 console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words);
2451 console.log("Mnemonic: " + mnemonic);
2452 fail();
2453 }
2454 }
2455 else {
2456 if (mnemonic.split(" ").length != test.words) {
2457 console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words);
2458 console.log("Mnemonic: " + mnemonic);
2459 fail();
2460 }
2461 }
2462 // check the strength of the next mnemonic is shown
2463 var entropyText = page.evaluate(function() {
2464 return $(".entropy-container").text();
2465 });
2466 if (entropyText.indexOf("required to generate " + test.nextStrength + " mnemonic") == -1) {
2467 console.log("Strength indicator for " + test.nextStrength + " mnemonic is incorrect");
2468 fail();
2469 }
2470 var isLastTest = i == tests.length - 1;
2471 if (isLastTest) {
2472 next();
2473 }
2474 else {
2475 runNextTest(i+1);
2476 }
2477 });
2478 }
2479 nextTest(0);
2480});
2481},
2482
2483// Entropy is truncated from the right
2484function() {
2485page.open(url, function(status) {
2486 var expected = "abandon abandon ability";
2487 // use entropy
2488 page.evaluate(function() {
2489 $(".use-entropy").prop("checked", true).trigger("change");
2490 var entropy = "00000000 00000000 00000000 00000000";
2491 entropy += "11111111 11111111 11111111 1111"; // Missing last byte, only first 8 bytes are used
2492 $(".entropy").val(entropy).trigger("input");
2493 });
2494 // check the entropy is truncated from the right
2495 waitForGenerate(function() {
2496 var actual = page.evaluate(function() {
2497 return $(".phrase").val();
2498 });
2499 if (actual != expected) {
2500 console.log("Entropy is not truncated from the right");
2501 console.log("Expected: " + expected);
2502 console.log("Got: " + actual);
2503 fail();
2504 }
2505 next();
2506 });
2507});
2508},
2509
2510// Very large entropy results in very long mnemonics
2511function() {
2512page.open(url, function(status) {
2513 // use entropy
2514 page.evaluate(function() {
2515 $(".use-entropy").prop("checked", true).trigger("change");
2516 var entropy = "";
2517 // Generate a very long entropy string
2518 for (var i=0; i<33; i++) {
2519 entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
2520 }
2521 $(".entropy").val(entropy).trigger("input");
2522 });
2523 // check the mnemonic is very long
2524 waitForGenerate(function() {
2525 var wordCount = page.evaluate(function() {
2526 return $(".phrase").val().split(" ").length;
2527 });
2528 if (wordCount != 99) {
2529 console.log("Large entropy does not generate long mnemonic");
2530 console.log("Expected 99 words, got " + wordCount);
2531 fail();
2532 }
2533 next();
2534 });
2535});
2536},
2537
2538// Is compatible with bip32jp entropy
2539// https://bip32jp.github.io/english/index.html
2540// NOTES:
2541// Is incompatible with:
2542// base 6 with leading zeros
2543// base 6 wth 12 words / 53 chars
2544// base 20
2545function() {
2546page.open(url, function(status) {
2547 var expected = "defy trip fatal jaguar mean rack rifle survey satisfy drift twist champion steel wife state furnace night consider glove olympic oblige donor novel left";
2548 // use entropy
2549 page.evaluate(function() {
2550 $(".use-entropy").prop("checked", true).trigger("change");
2551 var entropy = "123450123450123450123450123450123450123450123450123450123450123450123450123450123450123450123450123";
2552 $(".entropy").val(entropy).trigger("input");
2553 });
2554 // check the mnemonic matches the expected value from bip32jp
2555 waitForGenerate(function() {
2556 var actual = page.evaluate(function() {
2557 return $(".phrase").val();
2558 });
2559 if (actual != expected) {
2560 console.log("Mnemonic does not match bip32jp for base 6 entropy");
2561 console.log("Expected: " + expected);
2562 console.log("Got: " + actual);
2563 fail();
2564 }
2565 next();
2566 });
2567});
2568},
2569
1963// If you wish to add more tests, do so here... 2570// If you wish to add more tests, do so here...
1964 2571
1965// Here is a blank test template 2572// Here is a blank test template