aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Coleman <coleman.ian@gmail.com>2016-11-07 16:01:21 +1100
committerIan Coleman <coleman.ian@gmail.com>2016-11-07 16:01:21 +1100
commitadc8ce127d4f8ea0d7e5ede6a82c2791d60ff4d2 (patch)
treeda8a4bfe57f207d52822cab17ae7a8af150271bf
parent6606c50fd3af59483a5524170d9d2c3ec213a60f (diff)
downloadBIP39-adc8ce127d4f8ea0d7e5ede6a82c2791d60ff4d2.tar.gz
BIP39-adc8ce127d4f8ea0d7e5ede6a82c2791d60ff4d2.tar.zst
BIP39-adc8ce127d4f8ea0d7e5ede6a82c2791d60ff4d2.zip
Cards can be used for entropy
Format is [A2-9TJQK][CDHS]
-rw-r--r--src/js/entropy.js123
-rw-r--r--src/js/index.js21
-rw-r--r--tests.js231
3 files changed, 278 insertions, 97 deletions
diff --git a/src/js/entropy.js b/src/js/entropy.js
index 5b687d8..92300af 100644
--- a/src/js/entropy.js
+++ b/src/js/entropy.js
@@ -36,6 +36,32 @@ window.Entropy = new (function() {
36 hex: function(str) { 36 hex: function(str) {
37 return str.match(/[0-9A-F]/gi) || []; 37 return str.match(/[0-9A-F]/gi) || [];
38 }, 38 },
39 card: function(str) {
40 // Format is NumberSuit, eg
41 // AH ace of hearts
42 // 8C eight of clubs
43 // TD ten of diamonds
44 // JS jack of spades
45 // QH queen of hearts
46 // KC king of clubs
47 return str.match(/([A2-9TJQK][CDHS])/gi) || [];
48 }
49 }
50
51 // Convert array of cards from ["ac", "4d", "ks"]
52 // to numbers between 0 and 51 [0, 16, 51]
53 function convertCardsToInts(cards) {
54 var ints = [];
55 var values = "a23456789tjqk";
56 var suits = "cdhs";
57 for (var i=0; i<cards.length; i++) {
58 var card = cards[i].toLowerCase();
59 var value = card[0];
60 var suit = card[1];
61 var asInt = 13 * suits.indexOf(suit) + values.indexOf(value);
62 ints.push(asInt);
63 }
64 return ints;
39 } 65 }
40 66
41 this.fromString = function(rawEntropyStr) { 67 this.fromString = function(rawEntropyStr) {
@@ -62,61 +88,61 @@ window.Entropy = new (function() {
62 if (base.parts.length == 0) { 88 if (base.parts.length == 0) {
63 return { 89 return {
64 binaryStr: "", 90 binaryStr: "",
65 hexStr: "",
66 cleanStr: "", 91 cleanStr: "",
67 base: base, 92 base: base,
68 }; 93 };
69 } 94 }
70 // Pull leading zeros off 95 // Pull leading zeros off
71 var leadingZeros = []; 96 var leadingZeros = [];
72 while (base.parts[0] == "0") { 97 while (base.ints[0] == "0") {
73 leadingZeros.push("0"); 98 leadingZeros.push("0");
74 base.parts.shift(); 99 base.ints.shift();
75 } 100 }
76 // Convert leading zeros to binary equivalent 101 // Convert leading zeros to binary equivalent
77 var numBinLeadingZeros = Math.ceil(Math.log2(base.asInt) * leadingZeros.length); 102 var numBinLeadingZeros = Math.floor(Math.log2(base.asInt) * leadingZeros.length);
78 var binLeadingZeros = ""; 103 var binLeadingZeros = "";
79 for (var i=0; i<numBinLeadingZeros; i++) { 104 for (var i=0; i<numBinLeadingZeros; i++) {
80 binLeadingZeros += "0"; 105 binLeadingZeros += "0";
81 } 106 }
82 // Convert leading zeros to hex equivalent
83 var numHexLeadingZeros = Math.floor(numBinLeadingZeros / 4);
84 var hexLeadingZeros = "";
85 for (var i=0; i<numHexLeadingZeros; i++) {
86 hexLeadingZeros += "0";
87 }
88 // Handle entropy of zero 107 // Handle entropy of zero
89 if (base.parts.length == 0) { 108 if (base.ints.length == 0) {
90 return { 109 return {
91 binaryStr: binLeadingZeros, 110 binaryStr: binLeadingZeros,
92 hexStr: hexLeadingZeros || "0",
93 cleanStr: leadingZeros, 111 cleanStr: leadingZeros,
94 base: base, 112 base: base,
95 } 113 }
96 } 114 }
97 // If using hex, should always be multiples of 4 bits, which can get 115 // If the first integer is small, it must be padded with zeros.
98 // out of sync if first number has leading 0 bits, eg 2 in hex is 0010 116 // Otherwise the chance of the first bit being 1 is 100%, which is
99 // which would show up as 10, thus missing 2 bits it should have. 117 // obviously incorrect.
100 if (base.asInt == 16) { 118 // This is not perfect for unusual bases, eg base 6 has 2.6 bits, so is
101 var firstDigit = parseInt(base.parts[0], 16); 119 // slightly biased toward having leading zeros, but it's still better
102 if (firstDigit >= 4 && firstDigit < 8) { 120 // than ignoring it completely.
103 binLeadingZeros += "0"; 121 // TODO: revise this, it seems very fishy. For example, in base 10, there are
104 } 122 // 8 opportunities to start with 0 but only 2 to start with 1
105 else if (firstDigit >= 2 && firstDigit < 4) { 123 var firstInt = base.ints[0];
106 binLeadingZeros += "00"; 124 var firstIntBits = Math.floor(Math.log2(firstInt))+1;
107 } 125 var maxFirstIntBits = Math.floor(Math.log2(base.asInt-1))+1;
108 else if (firstDigit >= 1 && firstDigit < 2) { 126 var missingFirstIntBits = maxFirstIntBits - firstIntBits;
109 binLeadingZeros += "000"; 127 var firstIntLeadingZeros = "";
110 } 128 for (var i=0; i<missingFirstIntBits; i++) {
129 binLeadingZeros += "0";
130 }
131 // Convert base.ints to BigInteger.
132 // Due to using unusual bases, eg cards of base52, this is not as simple as
133 // using BigInteger.parse()
134 var entropyInt = BigInteger.ZERO;
135 for (var i=base.ints.length-1; i>=0; i--) {
136 var thisInt = BigInteger.parse(base.ints[i]);
137 var power = (base.ints.length - 1) - i;
138 var additionalEntropy = BigInteger.parse(base.asInt).pow(power).multiply(thisInt);
139 entropyInt = entropyInt.add(additionalEntropy);
111 } 140 }
112 // Convert entropy to different foramts 141 // Convert entropy to different formats
113 var entropyInt = BigInteger.parse(base.parts.join(""), base.asInt);
114 var entropyBin = binLeadingZeros + entropyInt.toString(2); 142 var entropyBin = binLeadingZeros + entropyInt.toString(2);
115 var entropyHex = hexLeadingZeros + entropyInt.toString(16); 143 var entropyClean = base.parts.join("");
116 var entropyClean = leadingZeros.join("") + base.parts.join("");
117 var e = { 144 var e = {
118 binaryStr: entropyBin, 145 binaryStr: entropyBin,
119 hexStr: entropyHex,
120 cleanStr: entropyClean, 146 cleanStr: entropyClean,
121 base: base, 147 base: base,
122 } 148 }
@@ -129,17 +155,32 @@ window.Entropy = new (function() {
129 var binaryMatches = matchers.binary(str); 155 var binaryMatches = matchers.binary(str);
130 var hexMatches = matchers.hex(str); 156 var hexMatches = matchers.hex(str);
131 // Find the lowest base that can be used, whilst ignoring any irrelevant chars 157 // Find the lowest base that can be used, whilst ignoring any irrelevant chars
132 if (binaryMatches.length == hexMatches.length) { 158 if (binaryMatches.length == hexMatches.length && hexMatches.length > 0) {
159 var ints = binaryMatches.map(function(i) { return parseInt(i, 2) });
133 return { 160 return {
161 ints: ints,
134 parts: binaryMatches, 162 parts: binaryMatches,
135 matcher: matchers.binary, 163 matcher: matchers.binary,
136 asInt: 2, 164 asInt: 2,
137 str: "binary", 165 str: "binary",
138 } 166 }
139 } 167 }
168 var cardMatches = matchers.card(str);
169 if (cardMatches.length >= hexMatches.length / 2) {
170 var ints = convertCardsToInts(cardMatches);
171 return {
172 ints: ints,
173 parts: cardMatches,
174 matcher: matchers.card,
175 asInt: 52,
176 str: "card",
177 }
178 }
140 var diceMatches = matchers.dice(str); 179 var diceMatches = matchers.dice(str);
141 if (diceMatches.length == hexMatches.length) { 180 if (diceMatches.length == hexMatches.length && hexMatches.length > 0) {
181 var ints = diceMatches.map(function(i) { return parseInt(i) });
142 return { 182 return {
183 ints: ints,
143 parts: diceMatches, 184 parts: diceMatches,
144 matcher: matchers.dice, 185 matcher: matchers.dice,
145 asInt: 6, 186 asInt: 6,
@@ -147,8 +188,10 @@ window.Entropy = new (function() {
147 } 188 }
148 } 189 }
149 var base6Matches = matchers.base6(str); 190 var base6Matches = matchers.base6(str);
150 if (base6Matches.length == hexMatches.length) { 191 if (base6Matches.length == hexMatches.length && hexMatches.length > 0) {
192 var ints = base6Matches.map(function(i) { return parseInt(i) });
151 return { 193 return {
194 ints: ints,
152 parts: base6Matches, 195 parts: base6Matches,
153 matcher: matchers.base6, 196 matcher: matchers.base6,
154 asInt: 6, 197 asInt: 6,
@@ -156,15 +199,19 @@ window.Entropy = new (function() {
156 } 199 }
157 } 200 }
158 var base10Matches = matchers.base10(str); 201 var base10Matches = matchers.base10(str);
159 if (base10Matches.length == hexMatches.length) { 202 if (base10Matches.length == hexMatches.length && hexMatches.length > 0) {
203 var ints = base10Matches.map(function(i) { return parseInt(i) });
160 return { 204 return {
205 ints: ints,
161 parts: base10Matches, 206 parts: base10Matches,
162 matcher: matchers.base10, 207 matcher: matchers.base10,
163 asInt: 10, 208 asInt: 10,
164 str: "base 10", 209 str: "base 10",
165 } 210 }
166 } 211 }
212 var ints = hexMatches.map(function(i) { return parseInt(i, 16) });
167 return { 213 return {
214 ints: ints,
168 parts: hexMatches, 215 parts: hexMatches,
169 matcher: matchers.hex, 216 matcher: matchers.hex,
170 asInt: 16, 217 asInt: 16,
@@ -175,7 +222,11 @@ window.Entropy = new (function() {
175 // Polyfill for Math.log2 222 // Polyfill for Math.log2
176 // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2#Polyfill 223 // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2#Polyfill
177 Math.log2 = Math.log2 || function(x) { 224 Math.log2 = Math.log2 || function(x) {
178 return Math.log(x) * Math.LOG2E; 225 // The polyfill isn't good enough because of the poor accuracy of
226 // Math.LOG2E
227 // log2(8) gave 2.9999999999999996 which when floored causes issues.
228 // So instead use the BigInteger library to get it right.
229 return BigInteger.log(x) / BigInteger.log(2);
179 }; 230 };
180 231
181})(); 232})();
diff --git a/src/js/index.js b/src/js/index.js
index 1cc77d3..a717a9e 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -738,33 +738,36 @@
738 // Show entropy details 738 // Show entropy details
739 var extraBits = 32 - (entropy.binaryStr.length % 32); 739 var extraBits = 32 - (entropy.binaryStr.length % 32);
740 var extraChars = Math.ceil(extraBits * Math.log(2) / Math.log(entropy.base.asInt)); 740 var extraChars = Math.ceil(extraBits * Math.log(2) / Math.log(entropy.base.asInt));
741 var words = Math.floor(entropy.binaryStr.length / 32) * 3;
741 var strength = "an extremely weak"; 742 var strength = "an extremely weak";
742 if (entropy.hexStr.length >= 8) { 743 if (words >= 3) {
743 strength = "a very weak"; 744 strength = "a very weak";
744 } 745 }
745 if (entropy.hexStr.length >= 12) { 746 if (words >= 6) {
746 strength = "a weak"; 747 strength = "a weak";
747 } 748 }
748 if (entropy.hexStr.length >= 24) { 749 if (words >= 9) {
749 strength = "a strong"; 750 strength = "a strong";
750 } 751 }
751 if (entropy.hexStr.length >= 32) { 752 if (words >= 12) {
752 strength = "a very strong"; 753 strength = "a very strong";
753 } 754 }
754 if (entropy.hexStr.length >= 40) { 755 if (words >= 15) {
755 strength = "an extremely strong"; 756 strength = "an extremely strong";
756 } 757 }
757 if (entropy.hexStr.length >=48) { 758 if (words >= 18) {
758 strength = "an even stronger" 759 strength = "an even stronger"
759 } 760 }
760 var msg = "Have " + entropy.binaryStr.length + " bits of entropy, " + extraChars + " more " + entropy.base.str + " chars required to generate " + strength + " mnemonic: " + entropy.cleanStr; 761 var msg = "Have " + entropy.binaryStr.length + " bits of entropy, " + extraChars + " more " + entropy.base.str + " chars required to generate " + strength + " mnemonic: " + entropy.cleanStr;
761 showEntropyError(msg); 762 showEntropyError(msg);
762 // Discard trailing entropy 763 // Discard trailing entropy
763 var hexStr = entropy.hexStr.substring(0, Math.floor(entropy.hexStr.length / 8) * 8); 764 var bitsToUse = Math.floor(entropy.binaryStr.length / 32) * 32;
765 var binaryStr = entropy.binaryStr.substring(0, bitsToUse);
764 // Convert entropy string to numeric array 766 // Convert entropy string to numeric array
765 var entropyArr = []; 767 var entropyArr = [];
766 for (var i=0; i<hexStr.length / 2; i++) { 768 for (var i=0; i<binaryStr.length / 8; i++) {
767 var entropyByte = parseInt(hexStr[i*2].concat(hexStr[i*2+1]), 16); 769 var byteAsBits = binaryStr.substring(i*8, i*8+8);
770 var entropyByte = parseInt(byteAsBits, 2);
768 entropyArr.push(entropyByte) 771 entropyArr.push(entropyByte)
769 } 772 }
770 // Convert entropy array to mnemonic 773 // Convert entropy array to mnemonic
diff --git a/tests.js b/tests.js
index 1841af6..8de6391 100644
--- a/tests.js
+++ b/tests.js
@@ -1997,85 +1997,212 @@ page.open(url, function(status) {
1997// Entropy unit tests 1997// Entropy unit tests
1998function() { 1998function() {
1999page.open(url, function(status) { 1999page.open(url, function(status) {
2000 var error = page.evaluate(function() { 2000 var response = page.evaluate(function() {
2001 var e; 2001 var e;
2002 // binary entropy is detected 2002 // binary entropy is detected
2003 e = Entropy.fromString("01010101"); 2003 try {
2004 if (e.base.str != "binary") { 2004 e = Entropy.fromString("01010101");
2005 return "Binary entropy not detected correctly"; 2005 if (e.base.str != "binary") {
2006 return "Binary entropy not detected correctly";
2007 }
2008 }
2009 catch (e) {
2010 return e.message;
2006 } 2011 }
2007 // base6 entropy is detected 2012 // base6 entropy is detected
2008 e = Entropy.fromString("012345012345"); 2013 try {
2009 if (e.base.str != "base 6") { 2014 e = Entropy.fromString("012345012345");
2010 return "base6 entropy not detected correctly"; 2015 if (e.base.str != "base 6") {
2016 return "base6 entropy not detected correctly";
2017 }
2018 }
2019 catch (e) {
2020 return e.message;
2011 } 2021 }
2012 // dice entropy is detected 2022 // dice entropy is detected
2013 e = Entropy.fromString("123456123456"); 2023 try {
2014 if (e.base.str != "base 6 (dice)") { 2024 e = Entropy.fromString("123456123456");
2015 return "dice entropy not detected correctly"; 2025 if (e.base.str != "base 6 (dice)") {
2026 return "dice entropy not detected correctly";
2027 }
2028 }
2029 catch (e) {
2030 return e.message;
2016 } 2031 }
2017 // base10 entropy is detected 2032 // base10 entropy is detected
2018 e = Entropy.fromString("0123456789"); 2033 try {
2019 if (e.base.str != "base 10") { 2034 e = Entropy.fromString("0123456789");
2020 return "base10 entropy not detected correctly"; 2035 if (e.base.str != "base 10") {
2036 return "base10 entropy not detected correctly";
2037 }
2038 }
2039 catch (e) {
2040 return e.message;
2021 } 2041 }
2022 // hex entropy is detected 2042 // hex entropy is detected
2023 e = Entropy.fromString("0123456789ABCDEF"); 2043 try {
2024 if (e.base.str != "hexadecimal") { 2044 e = Entropy.fromString("0123456789ABCDEF");
2025 return "hexadecimal entropy not detected correctly"; 2045 if (e.base.str != "hexadecimal") {
2046 return "hexadecimal entropy not detected correctly";
2047 }
2048 }
2049 catch (e) {
2050 return e.message;
2051 }
2052 // card entropy is detected
2053 try {
2054 e = Entropy.fromString("AC4DTHKS");
2055 if (e.base.str != "card") {
2056 return "card entropy not detected correctly";
2057 }
2058 }
2059 catch (e) {
2060 return e.message;
2026 } 2061 }
2027 // entropy is case insensitive 2062 // entropy is case insensitive
2028 e = Entropy.fromString("aBcDeF"); 2063 try {
2029 if (e.cleanStr != "aBcDeF") { 2064 e = Entropy.fromString("aBcDeF");
2030 return "Entropy should not be case sensitive"; 2065 if (e.cleanStr != "aBcDeF") {
2066 return "Entropy should not be case sensitive";
2067 }
2068 }
2069 catch (e) {
2070 return e.message;
2031 } 2071 }
2032 // dice entropy is converted to base6 2072 // dice entropy is converted to base6
2033 e = Entropy.fromString("123456"); 2073 try {
2034 if (e.cleanStr != "012345") { 2074 e = Entropy.fromString("123456");
2035 return "Dice entropy is not automatically converted to base6"; 2075 if (e.cleanStr != "012345") {
2076 return "Dice entropy is not automatically converted to base6";
2077 }
2078 }
2079 catch (e) {
2080 return e.message;
2036 } 2081 }
2037 // dice entropy is preferred to base6 if ambiguous 2082 // dice entropy is preferred to base6 if ambiguous
2038 e = Entropy.fromString("12345"); 2083 try {
2039 if (e.base.str != "base 6 (dice)") { 2084 e = Entropy.fromString("12345");
2040 return "dice not used as default over base 6"; 2085 if (e.base.str != "base 6 (dice)") {
2086 return "dice not used as default over base 6";
2087 }
2088 }
2089 catch (e) {
2090 return e.message;
2041 } 2091 }
2042 // unused characters are ignored 2092 // unused characters are ignored
2043 e = Entropy.fromString("fghijkl"); 2093 try {
2044 if (e.cleanStr != "f") { 2094 e = Entropy.fromString("fghijkl");
2045 return "additional characters are not ignored"; 2095 if (e.cleanStr != "f") {
2096 return "additional characters are not ignored";
2097 }
2098 }
2099 catch (e) {
2100 return e.message;
2046 } 2101 }
2047 // the lowest base is used by default 2102 // the lowest base is used by default
2048 // 7 could be decimal or hexadecimal, but should be detected as decimal 2103 // 7 could be decimal or hexadecimal, but should be detected as decimal
2049 e = Entropy.fromString("7"); 2104 try {
2050 if (e.base.str != "base 10") { 2105 e = Entropy.fromString("7");
2051 return "lowest base is not used"; 2106 if (e.base.str != "base 10") {
2107 return "lowest base is not used";
2108 }
2052 } 2109 }
2053 // Hexadecimal representation is returned 2110 catch (e) {
2054 e = Entropy.fromString("1010"); 2111 return e.message;
2055 if (e.hexStr != "A") {
2056 return "Hexadecimal representation not returned";
2057 } 2112 }
2058 // Leading zeros are retained 2113 // Leading zeros are retained
2059 e = Entropy.fromString("000A"); 2114 try {
2060 if (e.cleanStr != "000A") { 2115 e = Entropy.fromString("000A");
2061 return "Leading zeros are not retained"; 2116 if (e.cleanStr != "000A") {
2117 return "Leading zeros are not retained";
2118 }
2119 }
2120 catch (e) {
2121 return e.message;
2062 } 2122 }
2063 // Leading zeros are correctly preserved for hex in binary string 2123 // Leading zeros are correctly preserved for hex in binary string
2064 e = Entropy.fromString("2A"); 2124 try {
2065 if (e.binaryStr != "00101010") { 2125 e = Entropy.fromString("2A");
2066 return "Hex leading zeros are not correct in binary"; 2126 if (e.binaryStr != "00101010") {
2127 return "Hex leading zeros are not correct in binary";
2128 }
2129 }
2130 catch (e) {
2131 return e.message;
2132 }
2133 // Leading zeros are correctly preserved for base 6 in binary string
2134 try {
2135 e = Entropy.fromString("2");
2136 if (e.binaryStr != "010") {
2137 return "Base 6 leading zeros are not correct in binary";
2138 }
2139 }
2140 catch (e) {
2141 return e.message;
2067 } 2142 }
2068 // Keyboard mashing results in weak entropy 2143 // Keyboard mashing results in weak entropy
2069 // Despite being a long string, it's less than 30 bits of entropy 2144 // Despite being a long string, it's less than 30 bits of entropy
2070 e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj"); 2145 try {
2071 if (e.binaryStr.length >= 30) { 2146 e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj");
2072 return "Keyboard mashing should produce weak entropy"; 2147 if (e.binaryStr.length >= 30) {
2148 return "Keyboard mashing should produce weak entropy";
2149 }
2073 } 2150 }
2074 return false; 2151 catch (e) {
2152 return e.message;
2153 }
2154 // Card entropy is used if every pair could be a card
2155 try {
2156 e = Entropy.fromString("4c3c2c");
2157 if (e.base.str != "card") {
2158 return "Card entropy not used if all pairs are cards";
2159 }
2160 }
2161 catch (e) {
2162 return e.message;
2163 }
2164 // Card entropy uses base 52
2165 // [ cards, binary ]
2166 try {
2167 var cards = [
2168 [ "ac", "00000" ],
2169 [ "acac", "00000000000" ],
2170 [ "acac2c", "00000000000000001" ],
2171 [ "acks", "00000110011" ],
2172 [ "acacks", "00000000000110011" ],
2173 [ "2c", "000001" ],
2174 [ "3d", "001111" ],
2175 [ "4h", "011101" ],
2176 [ "5s", "101011" ],
2177 [ "6c", "000101" ],
2178 [ "7d", "010011" ],
2179 [ "8h", "100001" ],
2180 [ "9s", "101111" ],
2181 [ "tc", "001001" ],
2182 [ "jd", "010111" ],
2183 [ "qh", "100101" ],
2184 [ "ks", "110011" ],
2185 [ "ks2c", "101001011101" ],
2186 [ "KS2C", "101001011101" ],
2187 ];
2188 for (var i=0; i<cards.length; i++) {
2189 var card = cards[i][0];
2190 var result = cards[i][1];
2191 e = Entropy.fromString(card);
2192 console.log(e.binary + " " + result);
2193 if (e.binaryStr !== result) {
2194 return "card entropy not parsed correctly: " + result + " != " + e.binaryStr;
2195 }
2196 }
2197 }
2198 catch (e) {
2199 return e.message;
2200 }
2201 return "PASS";
2075 }); 2202 });
2076 if (error) { 2203 if (response != "PASS") {
2077 console.log("Entropy unit tests"); 2204 console.log("Entropy unit tests");
2078 console.log(error); 2205 console.log(response);
2079 fail(); 2206 fail();
2080 }; 2207 };
2081 next(); 2208 next();
@@ -2339,10 +2466,10 @@ page.open(url, function(status) {
2339 [ "0", "1" ], 2466 [ "0", "1" ],
2340 [ "0000", "4" ], 2467 [ "0000", "4" ],
2341 [ "6", "3" ], 2468 [ "6", "3" ],
2342 [ "7", "3" ], 2469 [ "7", "4" ],
2343 [ "8", "4" ], 2470 [ "8", "4" ],
2344 [ "F", "4" ], 2471 [ "F", "4" ],
2345 [ "29", "5" ], 2472 [ "29", "7" ],
2346 [ "0A", "8" ], 2473 [ "0A", "8" ],
2347 [ "1A", "8" ], // hex is always multiple of 4 bits of entropy 2474 [ "1A", "8" ], // hex is always multiple of 4 bits of entropy
2348 [ "2A", "8" ], 2475 [ "2A", "8" ],
@@ -2350,9 +2477,9 @@ page.open(url, function(status) {
2350 [ "8A", "8" ], 2477 [ "8A", "8" ],
2351 [ "FA", "8" ], 2478 [ "FA", "8" ],
2352 [ "000A", "16" ], 2479 [ "000A", "16" ],
2353 [ "2220", "10" ], 2480 [ "2220", "11" ],
2354 [ "2221", "9" ], // uses dice, so entropy is actually 1110 2481 [ "2221", "11" ], // uses dice, so entropy is actually 1110
2355 [ "2227", "12" ], 2482 [ "2227", "14" ],
2356 [ "222F", "16" ], 2483 [ "222F", "16" ],
2357 [ "FFFF", "16" ], 2484 [ "FFFF", "16" ],
2358 ] 2485 ]