aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Coleman <coleman.ian@gmail.com>2016-11-30 15:30:19 +1100
committerIan Coleman <coleman.ian@gmail.com>2016-11-30 15:30:19 +1100
commit87ad2c6e4c7987320d8ce147fe9310b702c5deea (patch)
tree6dc821981e0fcb86371b52d4a8b1b1ba528346b3
parentc3c3df473e0e5114b75dbe835ada59a0e8066543 (diff)
downloadBIP39-87ad2c6e4c7987320d8ce147fe9310b702c5deea.tar.gz
BIP39-87ad2c6e4c7987320d8ce147fe9310b702c5deea.tar.zst
BIP39-87ad2c6e4c7987320d8ce147fe9310b702c5deea.zip
Card entropy has improved conversion to binary
See http://crypto.stackexchange.com/q/41886 and https://github.com/iancoleman/bip39/issues/33#issuecomment-263021856
-rw-r--r--src/js/entropy.js169
-rw-r--r--tests.js215
2 files changed, 117 insertions, 267 deletions
diff --git a/src/js/entropy.js b/src/js/entropy.js
index 8a0c799..d04d861 100644
--- a/src/js/entropy.js
+++ b/src/js/entropy.js
@@ -120,97 +120,9 @@ window.Entropy = new (function() {
120 while (entropyBin.length < expectedBits) { 120 while (entropyBin.length < expectedBits) {
121 entropyBin = "0" + entropyBin; 121 entropyBin = "0" + entropyBin;
122 } 122 }
123 // Assume cards are NOT replaced. 123 // Cards binary must be handled differently, since they're not replaced
124 // Additional entropy decreases as more cards are used. This means
125 // total possible entropy is measured using n!, not base^n.
126 // eg the second last card can be only one of two, not one of fifty two
127 // so the added entropy for that card is only one bit at most
128 if (base.asInt == 52) { 124 if (base.asInt == 52) {
129 var totalDecks = Math.ceil(base.parts.length / 52); 125 entropyBin = getCardBinary(base.parts);
130 var totalCards = totalDecks * 52;
131 var totalCombos = factorial(52).pow(totalDecks);
132 var totalRemainingCards = totalCards - base.parts.length;
133 var remainingDecks = Math.floor(totalRemainingCards / 52);
134 var remainingCards = totalRemainingCards % 52;
135 var remainingCombos = factorial(52).pow(remainingDecks).multiply(factorial(remainingCards));
136 var currentCombos = totalCombos.divide(remainingCombos);
137 var numberOfBits = Math.log2(currentCombos);
138 var maxWithoutReplace = BigInteger.pow(2, numberOfBits);
139 // Use a bunch of sorted decks to measure entropy from, populated
140 // as needed.
141 var sortedDecks = [];
142 // Initialize the final entropy value for these cards
143 var entropyInt = BigInteger.ZERO;
144 // Track how many instances of each card have been used, and thus
145 // how many decks are in use.
146 var cardCounts = {};
147 // Track the total bits of entropy that remain, which diminishes as
148 // each card is drawn.
149 var totalBitsLeft = numberOfBits;
150 // Work out entropy contribution of each card drawn
151 for (var i=0; i<base.parts.length; i++) {
152 // Get the card that was drawn
153 var cardLower = base.parts[i];
154 var card = cardLower.toUpperCase();
155 // Initialize the deck for this card if needed, to track how
156 // much entropy it adds.
157 if (!(card in cardCounts)) {
158 cardCounts[card] = 0;
159 }
160 // Get the deck this card is from
161 var deckIndex = cardCounts[card];
162 while (deckIndex > sortedDecks.length-1) {
163 sortedDecks.push(getSortedDeck());
164 }
165 // See how many bits this card contributes (depends on how many
166 // are left in the deck it's from)
167 var deckForCard = sortedDecks[deckIndex];
168 var cardsLeftInDeck = deckForCard.length;
169 var additionalBits = Math.log2(cardsLeftInDeck);
170 // Work out the min and max value for this card
171 var nextTotalBitsLeft = totalBitsLeft - additionalBits;
172 var minPossibleNewEntropy = TWO.pow(nextTotalBitsLeft).subtract(1);
173 var maxPossibleNewEntropy = TWO.pow(totalBitsLeft).subtract(1);
174 var diff = maxPossibleNewEntropy.subtract(minPossibleNewEntropy);
175 // BigInteger aggresively floors numbers which greatly affects
176 // the small numbers. In that case, use native Math library
177 var useBigInt = totalBitsLeft >= 32;
178 if (!useBigInt) {
179 minPossibleNewEntropy = Math.round(Math.pow(2, nextTotalBitsLeft)-1);
180 maxPossibleNewEntropy = Math.round(Math.pow(2, totalBitsLeft)-1);
181 diff = maxPossibleNewEntropy - minPossibleNewEntropy;
182 }
183 // Scale the value between possible min and max depending on
184 // this card value
185 var thisCardIndex = deckForCard.indexOf(card);
186 var toAdd = BigInteger.ZERO;
187 if (cardsLeftInDeck > 1) {
188 if (useBigInt) {
189 toAdd = diff.multiply(thisCardIndex)
190 .divide(deckForCard.length - 1)
191 .add(minPossibleNewEntropy);
192 }
193 else {
194 var ratio = thisCardIndex / (deckForCard.length -1);
195 var f = diff * ratio;
196 toAdd = new BigInteger(f).add(minPossibleNewEntropy);
197 }
198 }
199 // Add this card entropy to existing entropy
200 entropyInt = entropyInt.add(toAdd);
201 // Remove this card from the deck it comes from
202 deckForCard.splice(thisCardIndex,1);
203 // Ensure the next insance of this card uses the next deck
204 cardCounts[card] = cardCounts[card] + 1;
205 // Next card drawn has less total remaining bits to work with
206 totalBitsLeft = nextTotalBitsLeft;
207 }
208 // Convert to binary
209 var entropyBin = entropyInt.toString(2);
210 var numberOfBitsInt = Math.floor(numberOfBits);
211 while (entropyBin.length < numberOfBitsInt) {
212 entropyBin = "0" + entropyBin;
213 }
214 } 126 }
215 // Supply a 'filtered' entropy string for display purposes 127 // Supply a 'filtered' entropy string for display purposes
216 var entropyClean = base.parts.join(""); 128 var entropyClean = base.parts.join("");
@@ -319,6 +231,83 @@ window.Entropy = new (function() {
319 } 231 }
320 } 232 }
321 233
234 // Assume cards are NOT replaced.
235 // Additional entropy decreases as more cards are used. This means
236 // total possible entropy is measured using n!, not base^n.
237 // eg the second last card can be only one of two, not one of fifty two
238 // so the added entropy for that card is only one bit at most
239 function getCardBinary(cards) {
240 // Track how many instances of each card have been used, and thus
241 // how many decks are in use.
242 var cardCounts = {};
243 var numberOfDecks = 0;
244 // Work out number of decks by max(duplicates)
245 for (var i=0; i<cards.length; i++) {
246 // Get the card that was drawn
247 var cardLower = cards[i];
248 var card = cardLower.toUpperCase();
249 // Initialize the count for this card if needed
250 if (!(card in cardCounts)) {
251 cardCounts[card] = 0;
252 }
253 cardCounts[card] += 1;
254 // See if this is max(duplicates)
255 if (cardCounts[card] > numberOfDecks) {
256 numberOfDecks = cardCounts[card];
257 }
258 }
259 // Work out the total number of bits for this many decks
260 // See http://crypto.stackexchange.com/q/41886
261 var gainedBits = Math.log2(factorial(52 * numberOfDecks));
262 var lostBits = 52 * Math.log2(factorial(numberOfDecks));
263 var maxBits = gainedBits - lostBits;
264 // Convert the drawn cards to a binary representation.
265 // The exact technique for doing this is unclear.
266 // See
267 // http://crypto.stackexchange.com/a/41896
268 // "I even doubt that this is well defined (only the average entropy
269 // is, I believe)."
270 // See
271 // https://github.com/iancoleman/bip39/issues/33#issuecomment-263021856
272 // "The binary representation can be the first log(permutations,2) bits
273 // of the sha-2 hash of the normalized deck string."
274 //
275 // In this specific implementation, the first N bits of the hash of the
276 // normalized cards string is being used. Uppercase, no spaces; eg
277 // sha256("AH8DQSTC2H")
278 var totalCards = numberOfDecks * 52;
279 var percentUsed = cards.length / totalCards;
280 // Calculate the average number of bits of entropy for the number of
281 // cards drawn.
282 var numberOfBits = Math.floor(maxBits * percentUsed);
283 // Create a normalized string of the selected cards
284 var normalizedCards = cards.join("").toUpperCase();
285 // Convert to binary using the SHA256 hash of the normalized cards.
286 // If the number of bits is more than 256, multiple rounds of hashing
287 // are used until the required number of bits is reached.
288 var entropyBin = "";
289 var iterations = 0;
290 while (entropyBin.length < numberOfBits) {
291 var hashedCards = sjcl.hash.sha256.hash(normalizedCards);
292 for (var j=0; j<iterations; j++) {
293 hashedCards = sjcl.hash.sha256.hash(hashedCards);
294 }
295 var hashHex = sjcl.codec.hex.fromBits(hashedCards);
296 for (var i=0; i<hashHex.length; i++) {
297 var decimal = parseInt(hashHex[i], 16);
298 var binary = decimal.toString(2);
299 while (binary.length < 4) {
300 binary = "0" + binary;
301 }
302 entropyBin = entropyBin + binary;
303 }
304 iterations = iterations + 1;
305 }
306 // Truncate to the appropriate number of bits.
307 entropyBin = entropyBin.substring(0, numberOfBits);
308 return entropyBin;
309 }
310
322 // Polyfill for Math.log2 311 // Polyfill for Math.log2
323 // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2#Polyfill 312 // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2#Polyfill
324 Math.log2 = Math.log2 || function(x) { 313 Math.log2 = Math.log2 || function(x) {
diff --git a/tests.js b/tests.js
index c7d92e4..4f8f60f 100644
--- a/tests.js
+++ b/tests.js
@@ -2149,10 +2149,11 @@ page.open(url, function(status) {
2149 catch (e) { 2149 catch (e) {
2150 return e.message; 2150 return e.message;
2151 } 2151 }
2152 // Leading zeros for card entropy as binary string 2152 // Leading zeros for card entropy as binary string.
2153 // Card entropy is hashed so 2c does not produce leading zeros.
2153 try { 2154 try {
2154 e = Entropy.fromString("2c"); 2155 e = Entropy.fromString("4c");
2155 if (e.binaryStr != "00001") { 2156 if (e.binaryStr != "0001") {
2156 return "Card entropy as binary has leading zeros"; 2157 return "Card entropy as binary has leading zeros";
2157 } 2158 }
2158 } 2159 }
@@ -2184,24 +2185,24 @@ page.open(url, function(status) {
2184 // [ cards, binary ] 2185 // [ cards, binary ]
2185 try { 2186 try {
2186 var cards = [ 2187 var cards = [
2187 [ "ac", "00000" ], 2188 [ "ac", "0100" ],
2188 [ "acqs", "00001100011" ], 2189 [ "acqs", "10111101" ],
2189 [ "acks", "00001100100" ], 2190 [ "acks", "11110000" ],
2190 [ "2cac", "00001100101" ], 2191 [ "2cac", "11000010" ],
2191 [ "2c", "00001" ], 2192 [ "2c", "1000" ],
2192 [ "3d", "01111" ], 2193 [ "3d", "1111" ],
2193 [ "4h", "11101" ], 2194 [ "4h", "0011" ],
2194 [ "5s", "101011" ], 2195 [ "5s", "1001" ],
2195 [ "6c", "00101" ], 2196 [ "6c", "1011" ],
2196 [ "7d", "10011" ], 2197 [ "7d", "1101" ],
2197 [ "8h", "100001" ], 2198 [ "8h", "1011" ],
2198 [ "9s", "101111" ], 2199 [ "9s", "1010" ],
2199 [ "tc", "01001" ], 2200 [ "tc", "1101" ],
2200 [ "jd", "10111" ], 2201 [ "jd", "1101" ],
2201 [ "qh", "100101" ], 2202 [ "qh", "1100" ],
2202 [ "ks", "110011" ], 2203 [ "ks", "1111" ],
2203 [ "ks2c", "101001011100" ], 2204 [ "ks2c", "10000001" ],
2204 [ "KS2C", "101001011100" ], 2205 [ "KS2C", "10000001" ],
2205 ]; 2206 ];
2206 for (var i=0; i<cards.length; i++) { 2207 for (var i=0; i<cards.length; i++) {
2207 var card = cards[i][0]; 2208 var card = cards[i][0];
@@ -2644,7 +2645,7 @@ page.open(url, function(status) {
2644 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d", 2645 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
2645 type: "card (full deck, 1 duplicate: 3d)", 2646 type: "card (full deck, 1 duplicate: 3d)",
2646 events: 53, 2647 events: 53,
2647 bits: 231, 2648 bits: 254,
2648 words: 21, 2649 words: 21,
2649 strength: "extremely strong", 2650 strength: "extremely strong",
2650 }, 2651 },
@@ -2652,7 +2653,7 @@ page.open(url, function(status) {
2652 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d", 2653 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
2653 type: "card (2 duplicates: 3d 4d, 1 missing: KS)", 2654 type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
2654 events: 53, 2655 events: 53,
2655 bits: 231, 2656 bits: 254,
2656 words: 21, 2657 words: 21,
2657 strength: "extremely strong", 2658 strength: "extremely strong",
2658 }, 2659 },
@@ -2660,8 +2661,8 @@ page.open(url, function(status) {
2660 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d", 2661 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
2661 type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)", 2662 type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
2662 events: 53, 2663 events: 53,
2663 bits: 242, 2664 bits: 264,
2664 words: 21, 2665 words: 24,
2665 strength: "extremely strong", 2666 strength: "extremely strong",
2666 }, 2667 },
2667 // Next test was throwing uncaught error in zxcvbn 2668 // Next test was throwing uncaught error in zxcvbn
@@ -2670,8 +2671,8 @@ page.open(url, function(status) {
2670 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", 2671 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2671 type: "card (full deck, 52 duplicates: ac 2c 3c...)", 2672 type: "card (full deck, 52 duplicates: ac 2c 3c...)",
2672 events: 104, 2673 events: 104,
2673 bits: 451, 2674 bits: 499,
2674 words: 42, 2675 words: 45,
2675 strength: "extremely strong", 2676 strength: "extremely strong",
2676 }, 2677 },
2677 // Case insensitivity to duplicate cards 2678 // Case insensitivity to duplicate cards
@@ -2679,7 +2680,7 @@ page.open(url, function(status) {
2679 entropy: "asAS", 2680 entropy: "asAS",
2680 type: "card (1 duplicate: AS)", 2681 type: "card (1 duplicate: AS)",
2681 events: 2, 2682 events: 2,
2682 bits: 12, 2683 bits: 9,
2683 words: 0, 2684 words: 0,
2684 strength: "extremely weak", 2685 strength: "extremely weak",
2685 }, 2686 },
@@ -2687,7 +2688,7 @@ page.open(url, function(status) {
2687 entropy: "ASas", 2688 entropy: "ASas",
2688 type: "card (1 duplicate: as)", 2689 type: "card (1 duplicate: as)",
2689 events: 2, 2690 events: 2,
2690 bits: 12, 2691 bits: 9,
2691 words: 0, 2692 words: 0,
2692 strength: "extremely weak", 2693 strength: "extremely weak",
2693 }, 2694 },
@@ -2696,23 +2697,23 @@ page.open(url, function(status) {
2696 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", 2697 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2697 type: "card (1 missing: 9C)", 2698 type: "card (1 missing: 9C)",
2698 events: 51, 2699 events: 51,
2699 bits: 225, 2700 bits: 221,
2700 words: 21, 2701 words: 18,
2701 strength: "extremely strong", 2702 strength: "extremely strong",
2702 }, 2703 },
2703 { 2704 {
2704 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", 2705 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2705 type: "card (2 missing: 9C 5D)", 2706 type: "card (2 missing: 9C 5D)",
2706 events: 50, 2707 events: 50,
2707 bits: 224, 2708 bits: 216,
2708 words: 21, 2709 words: 18,
2709 strength: "extremely strong", 2710 strength: "extremely strong",
2710 }, 2711 },
2711 { 2712 {
2712 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", 2713 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2713 type: "card (4 missing: 9C 5D QD...)", 2714 type: "card (4 missing: 9C 5D QD...)",
2714 events: 48, 2715 events: 48,
2715 bits: 220, 2716 bits: 208,
2716 words: 18, 2717 words: 18,
2717 strength: "extremely strong", 2718 strength: "extremely strong",
2718 }, 2719 },
@@ -2721,140 +2722,10 @@ page.open(url, function(status) {
2721 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks", 2722 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
2722 type: "card", 2723 type: "card",
2723 events: 45, 2724 events: 45,
2724 bits: 213, 2725 bits: 195,
2725 words: 18, 2726 words: 18,
2726 strength: "extremely strong", 2727 strength: "extremely strong",
2727 }, 2728 },
2728 // Additional entropy from each card decreases as deck is depleted.
2729 // Check the boundaries of this depletion
2730 // See table at https://github.com/iancoleman/bip39/issues/33#issuecomment-262855862
2731 // for following values of 'events, bits, words'
2732 // 2 cards remaining = 21 words
2733 {
2734 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjs",
2735 type: "card (2 missing: QS KS)",
2736 events: 50,
2737 bits: 224,
2738 words: 21,
2739 strength: "extremely strong",
2740 },
2741 // 3 cards remaining = 18 words
2742 {
2743 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9sts",
2744 type: "card (3 missing: JS QS KS)",
2745 events: 49,
2746 bits: 222, // table uses different rounding - 222.99604
2747 words: 18,
2748 strength: "extremely strong",
2749 },
2750 // 13 cards remaining = 18 words
2751 {
2752 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkh",
2753 type: "card",
2754 events: 39,
2755 bits: 193,
2756 words: 18,
2757 strength: "extremely strong",
2758 },
2759 // 14 cards remaining = 15 words
2760 {
2761 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqh",
2762 type: "card",
2763 events: 38,
2764 bits: 189,
2765 words: 15,
2766 strength: "very strong",
2767 },
2768 // 21 cards remaining = 15 words
2769 {
2770 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h",
2771 type: "card",
2772 events: 31,
2773 bits: 160,
2774 words: 15,
2775 strength: "very strong",
2776 },
2777 // 22 cards remaining = 12 words
2778 {
2779 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h",
2780 type: "card",
2781 events: 30,
2782 bits: 155,
2783 words: 12,
2784 strength: "strong",
2785 },
2786 // 27 cards remaining = 12 words
2787 {
2788 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqd",
2789 type: "card",
2790 events: 25,
2791 bits: 132,
2792 words: 12,
2793 strength: "strong",
2794 },
2795 // 28 cards remaining = 9 words
2796 {
2797 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjd",
2798 type: "card",
2799 events: 24,
2800 bits: 127,
2801 words: 9,
2802 strength: "weak",
2803 },
2804 // 34 cards remaining = 9 words
2805 {
2806 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d",
2807 type: "card",
2808 events: 18,
2809 bits: 97,
2810 words: 9,
2811 strength: "weak",
2812 },
2813 // 35 cards remaining = 6 words
2814 {
2815 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d",
2816 type: "card",
2817 events: 17,
2818 bits: 92,
2819 words: 6,
2820 strength: "very weak",
2821 },
2822 // 40 cards remaining = 6 words
2823 {
2824 entropy: "ac2c3c4c5c6c7c8c9ctcjcqc",
2825 type: "card",
2826 events: 12,
2827 bits: 66,
2828 words: 6,
2829 strength: "very weak",
2830 },
2831 // 41 cards remaining = 3 words
2832 {
2833 entropy: "ac2c3c4c5c6c7c8c9ctcjc",
2834 type: "card",
2835 events: 11,
2836 bits: 61,
2837 words: 3,
2838 strength: "extremely weak",
2839 },
2840 // 46 cards remaining = 3 words
2841 {
2842 entropy: "ac2c3c4c5c6c",
2843 type: "card",
2844 events: 6,
2845 bits: 33,
2846 words: 3,
2847 strength: "extremely weak",
2848 },
2849 // 47 cards remaining = 0 words
2850 {
2851 entropy: "ac2c3c4c5c",
2852 type: "card",
2853 events: 5,
2854 bits: 28,
2855 words: 0,
2856 strength: "extremely weak",
2857 },
2858 ]; 2729 ];
2859 // use entropy 2730 // use entropy
2860 page.evaluate(function() { 2731 page.evaluate(function() {
@@ -2894,6 +2765,7 @@ page.open(url, function(status) {
2894 if (test.words == 0) { 2765 if (test.words == 0) {
2895 if (mnemonic.length > 0) { 2766 if (mnemonic.length > 0) {
2896 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words); 2767 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
2768 console.log("Entropy: " + test.entropy);
2897 console.log("Mnemonic: " + mnemonic); 2769 console.log("Mnemonic: " + mnemonic);
2898 fail(); 2770 fail();
2899 } 2771 }
@@ -2901,6 +2773,7 @@ page.open(url, function(status) {
2901 else { 2773 else {
2902 if (mnemonic.split(" ").length != test.words) { 2774 if (mnemonic.split(" ").length != test.words) {
2903 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words); 2775 console.log("Mnemonic length for " + test.strength + " strength is not " + test.words);
2776 console.log("Entropy: " + test.entropy);
2904 console.log("Mnemonic: " + mnemonic); 2777 console.log("Mnemonic: " + mnemonic);
2905 fail(); 2778 fail();
2906 } 2779 }
@@ -3107,18 +2980,6 @@ page.open(url, function(status) {
3107 var newPhrase = page.evaluate(function() { 2980 var newPhrase = page.evaluate(function() {
3108 return $(".phrase").val(); 2981 return $(".phrase").val();
3109 }); 2982 });
3110 // check raw entropy is in use, ie the first bits should remain the same
3111 var startLength = 20;
3112 var originalPhraseStart = originalPhrase.substring(0,startLength);
3113 var newPhraseStart = newPhrase.substring(0,startLength);
3114 if (newPhraseStart != originalPhraseStart) {
3115 console.log("Changing last 12 cards changed first portion of mnemonic");
3116 console.log("Original:");
3117 console.log(originalPhrase);
3118 console.log("New:");
3119 console.log(newPhrase);
3120 fail();
3121 }
3122 // check the phrase has changed 2983 // check the phrase has changed
3123 if (newPhrase == originalPhrase) { 2984 if (newPhrase == originalPhrase) {
3124 console.log("Changing last 12 cards does not change mnemonic"); 2985 console.log("Changing last 12 cards does not change mnemonic");