diff options
-rwxr-xr-x | dev_env_setup.sh | 58 | ||||
-rw-r--r-- | src/index.html | 2 | ||||
-rw-r--r-- | src/js/entropy.js | 345 | ||||
-rw-r--r-- | src/js/index.js | 8 | ||||
-rw-r--r-- | tests/spec/tests.js | 96 |
5 files changed, 274 insertions, 235 deletions
diff --git a/dev_env_setup.sh b/dev_env_setup.sh new file mode 100755 index 0000000..68af109 --- /dev/null +++ b/dev_env_setup.sh | |||
@@ -0,0 +1,58 @@ | |||
1 | # this script is intended to be run in a VM | ||
2 | # running ubuntu 20.04 server | ||
3 | # from the root directory of this repo | ||
4 | |||
5 | echo "This script is intended to be run in a VM." | ||
6 | echo "It may do things to your OS that you don't want to be peristent." | ||
7 | echo "Please type virtualmachine to continue, or Ctrl-C to quit." | ||
8 | |||
9 | read passage | ||
10 | |||
11 | if [ "$passage" = "virtualmachine" ]; then | ||
12 | echo "Installing dev environment" | ||
13 | else | ||
14 | echo "Did not type virtualmachine, quitting with no changes applied" | ||
15 | exit | ||
16 | fi | ||
17 | |||
18 | # set up place for local binaries | ||
19 | mkdir $HOME/.bin | ||
20 | echo "export PATH=$PATH:$HOME/.bin" >> $HOME/.bashrc | ||
21 | source $HOME/.bashrc | ||
22 | |||
23 | # allow python3 to be run with python command | ||
24 | ln -s /usr/bin/python3 $HOME/.bin/python | ||
25 | |||
26 | # install firefox and other dependencies | ||
27 | sudo apt-get -y install firefox unzip openjdk-11-jre-headless xvfb libxi6 libgconf-2-4 | ||
28 | # install chrome | ||
29 | curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add | ||
30 | sudo sh -c "echo \"deb https://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google-chrome.list" | ||
31 | sudo apt-get -y update | ||
32 | sudo apt-get -y install google-chrome-stable | ||
33 | |||
34 | # install nodejs for running tests | ||
35 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.36.0/install.sh | bash | ||
36 | # load nvm | ||
37 | source $HOME/.bashrc | ||
38 | export NVM_DIR="$HOME/.nvm" | ||
39 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm | ||
40 | [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion | ||
41 | # install latest node | ||
42 | nvm install node | ||
43 | # install jasmine | ||
44 | cd tests | ||
45 | npm install --global jasmine | ||
46 | npm install selenium-webdriver | ||
47 | # install gecko webdriver for firefox | ||
48 | wget https://github.com/mozilla/geckodriver/releases/download/v0.27.0/geckodriver-v0.27.0-linux64.tar.gz --output-document=/tmp/geckodriver.tar.gz | ||
49 | tar -xf /tmp/geckodriver.tar.gz -C $HOME/.bin | ||
50 | # install chrome webdriver for chromium | ||
51 | wget https://chromedriver.storage.googleapis.com/85.0.4183.87/chromedriver_linux64.zip --output-document=/tmp/chromedriver.zip | ||
52 | unzip /tmp/chromedriver.zip -d $HOME/.bin | ||
53 | |||
54 | # to run tests | ||
55 | # cd tests | ||
56 | # Xvfb :1 -screen 1 1024x768x24 & export DISPLAY=:1.1 | ||
57 | # BROWSER=firefox jasmine spec/tests.js | ||
58 | # BROWSER=chrome jasmine spec/tests.js | ||
diff --git a/src/index.html b/src/index.html index 7eb123c..f66d4ed 100644 --- a/src/index.html +++ b/src/index.html | |||
@@ -86,7 +86,7 @@ | |||
86 | <div class="row"> | 86 | <div class="row"> |
87 | <label class="col-sm-3 control-label">Entropy Type</label> | 87 | <label class="col-sm-3 control-label">Entropy Type</label> |
88 | <div class="type col-sm-3 form-control-static"></div> | 88 | <div class="type col-sm-3 form-control-static"></div> |
89 | <label class="col-sm-3 control-label">Bits Per Event</label> | 89 | <label class="col-sm-3 control-label">Avg Bits Per Event</label> |
90 | <div class="bits-per-event col-sm-3 form-control-static"></div> | 90 | <div class="bits-per-event col-sm-3 form-control-static"></div> |
91 | </div> | 91 | </div> |
92 | <div class="row"> | 92 | <div class="row"> |
diff --git a/src/js/entropy.js b/src/js/entropy.js index 62b2711..3b62e10 100644 --- a/src/js/entropy.js +++ b/src/js/entropy.js | |||
@@ -16,7 +16,136 @@ | |||
16 | 16 | ||
17 | window.Entropy = new (function() { | 17 | window.Entropy = new (function() { |
18 | 18 | ||
19 | var TWO = new libs.BigInteger.BigInteger(2); | 19 | let eventBits = { |
20 | |||
21 | "binary": { | ||
22 | "0": "0", | ||
23 | "1": "1", | ||
24 | }, | ||
25 | |||
26 | // log2(6) = 2.58496 bits per roll, with bias | ||
27 | // 4 rolls give 2 bits each | ||
28 | // 2 rolls give 1 bit each | ||
29 | // Average (4*2 + 2*1) / 6 = 1.66 bits per roll without bias | ||
30 | "base 6": { | ||
31 | "0": "00", | ||
32 | "1": "01", | ||
33 | "2": "10", | ||
34 | "3": "11", | ||
35 | "4": "0", | ||
36 | "5": "1", | ||
37 | }, | ||
38 | |||
39 | // log2(6) = 2.58496 bits per roll, with bias | ||
40 | // 4 rolls give 2 bits each | ||
41 | // 2 rolls give 1 bit each | ||
42 | // Average (4*2 + 2*1) / 6 = 1.66 bits per roll without bias | ||
43 | "base 6 (dice)": { | ||
44 | "0": "00", // equivalent to 0 in base 6 | ||
45 | "1": "01", | ||
46 | "2": "10", | ||
47 | "3": "11", | ||
48 | "4": "0", | ||
49 | "5": "1", | ||
50 | }, | ||
51 | |||
52 | // log2(10) = 3.321928 bits per digit, with bias | ||
53 | // 8 digits give 3 bits each | ||
54 | // 2 digits give 1 bit each | ||
55 | // Average (8*3 + 2*1) / 10 = 2.6 bits per digit without bias | ||
56 | "base 10": { | ||
57 | "0": "000", | ||
58 | "1": "001", | ||
59 | "2": "010", | ||
60 | "3": "011", | ||
61 | "4": "100", | ||
62 | "5": "101", | ||
63 | "6": "110", | ||
64 | "7": "111", | ||
65 | "8": "0", | ||
66 | "9": "1", | ||
67 | }, | ||
68 | |||
69 | "hexadecimal": { | ||
70 | "0": "0000", | ||
71 | "1": "0001", | ||
72 | "2": "0010", | ||
73 | "3": "0011", | ||
74 | "4": "0100", | ||
75 | "5": "0101", | ||
76 | "6": "0110", | ||
77 | "7": "0111", | ||
78 | "8": "1000", | ||
79 | "9": "1001", | ||
80 | "a": "1010", | ||
81 | "b": "1011", | ||
82 | "c": "1100", | ||
83 | "d": "1101", | ||
84 | "e": "1110", | ||
85 | "f": "1111", | ||
86 | }, | ||
87 | |||
88 | // log2(52) = 5.7004 bits per card, with bias | ||
89 | // 32 cards give 5 bits each | ||
90 | // 16 cards give 4 bits each | ||
91 | // 4 cards give 2 bits each | ||
92 | // Average (32*5 + 16*4 + 4*2) / 52 = 4.46 bits per card without bias | ||
93 | "card": { | ||
94 | "ac": "00000", | ||
95 | "2c": "00001", | ||
96 | "3c": "00010", | ||
97 | "4c": "00011", | ||
98 | "5c": "00100", | ||
99 | "6c": "00101", | ||
100 | "7c": "00110", | ||
101 | "8c": "00111", | ||
102 | "9c": "01000", | ||
103 | "tc": "01001", | ||
104 | "jc": "01010", | ||
105 | "qc": "01011", | ||
106 | "kc": "01100", | ||
107 | "ad": "01101", | ||
108 | "2d": "01110", | ||
109 | "3d": "01111", | ||
110 | "4d": "10000", | ||
111 | "5d": "10001", | ||
112 | "6d": "10010", | ||
113 | "7d": "10011", | ||
114 | "8d": "10100", | ||
115 | "9d": "10101", | ||
116 | "td": "10110", | ||
117 | "jd": "10111", | ||
118 | "qd": "11000", | ||
119 | "kd": "11001", | ||
120 | "ah": "11010", | ||
121 | "2h": "11011", | ||
122 | "3h": "11100", | ||
123 | "4h": "11101", | ||
124 | "5h": "11110", | ||
125 | "6h": "11111", | ||
126 | "7h": "0000", | ||
127 | "8h": "0001", | ||
128 | "9h": "0010", | ||
129 | "th": "0011", | ||
130 | "jh": "0100", | ||
131 | "qh": "0101", | ||
132 | "kh": "0110", | ||
133 | "as": "0111", | ||
134 | "2s": "1000", | ||
135 | "3s": "1001", | ||
136 | "4s": "1010", | ||
137 | "5s": "1011", | ||
138 | "6s": "1100", | ||
139 | "7s": "1101", | ||
140 | "8s": "1110", | ||
141 | "9s": "1111", | ||
142 | "ts": "00", | ||
143 | "js": "01", | ||
144 | "qs": "10", | ||
145 | "ks": "11", | ||
146 | }, | ||
147 | |||
148 | } | ||
20 | 149 | ||
21 | // matchers returns an array of the matched events for each type of entropy. | 150 | // matchers returns an array of the matched events for each type of entropy. |
22 | // eg | 151 | // eg |
@@ -51,48 +180,28 @@ window.Entropy = new (function() { | |||
51 | } | 180 | } |
52 | } | 181 | } |
53 | 182 | ||
54 | // Convert array of cards from ["ac", "4d", "ks"] | ||
55 | // to numbers between 0 and 51 [0, 16, 51] | ||
56 | function convertCardsToInts(cards) { | ||
57 | var ints = []; | ||
58 | var values = "a23456789tjqk"; | ||
59 | var suits = "cdhs"; | ||
60 | for (var i=0; i<cards.length; i++) { | ||
61 | var card = cards[i].toLowerCase(); | ||
62 | var value = card[0]; | ||
63 | var suit = card[1]; | ||
64 | var asInt = 13 * suits.indexOf(suit) + values.indexOf(value); | ||
65 | ints.push(asInt); | ||
66 | } | ||
67 | return ints; | ||
68 | } | ||
69 | |||
70 | this.fromString = function(rawEntropyStr, baseStr) { | 183 | this.fromString = function(rawEntropyStr, baseStr) { |
71 | // Find type of entropy being used (binary, hex, dice etc) | 184 | // Find type of entropy being used (binary, hex, dice etc) |
72 | var base = getBase(rawEntropyStr, baseStr); | 185 | var base = getBase(rawEntropyStr, baseStr); |
73 | // Convert dice to base6 entropy (ie 1-6 to 0-5) | 186 | // Convert dice to base6 entropy (ie 1-6 to 0-5) |
74 | // This is done by changing all 6s to 0s | 187 | // This is done by changing all 6s to 0s |
75 | if (base.str == "dice") { | 188 | if (base.str == "dice") { |
76 | var newParts = []; | 189 | var newEvents = []; |
77 | var newInts = []; | 190 | for (var i=0; i<base.events.length; i++) { |
78 | for (var i=0; i<base.parts.length; i++) { | 191 | var c = base.events[i]; |
79 | var c = base.parts[i]; | ||
80 | if ("12345".indexOf(c) > -1) { | 192 | if ("12345".indexOf(c) > -1) { |
81 | newParts[i] = base.parts[i]; | 193 | newEvents[i] = base.events[i]; |
82 | newInts[i] = base.ints[i]; | ||
83 | } | 194 | } |
84 | else { | 195 | else { |
85 | newParts[i] = "0"; | 196 | newEvents[i] = "0"; |
86 | newInts[i] = 0; | ||
87 | } | 197 | } |
88 | } | 198 | } |
89 | base.str = "base 6 (dice)"; | 199 | base.str = "base 6 (dice)"; |
90 | base.ints = newInts; | 200 | base.events = newEvents; |
91 | base.parts = newParts; | ||
92 | base.matcher = matchers.base6; | 201 | base.matcher = matchers.base6; |
93 | } | 202 | } |
94 | // Detect empty entropy | 203 | // Detect empty entropy |
95 | if (base.parts.length == 0) { | 204 | if (base.events.length == 0) { |
96 | return { | 205 | return { |
97 | binaryStr: "", | 206 | binaryStr: "", |
98 | cleanStr: "", | 207 | cleanStr: "", |
@@ -100,44 +209,23 @@ window.Entropy = new (function() { | |||
100 | base: base, | 209 | base: base, |
101 | }; | 210 | }; |
102 | } | 211 | } |
103 | // Convert base.ints to BigInteger. | 212 | // Convert entropy events to binary |
104 | // Due to using unusual bases, eg cards of base52, this is not as simple as | 213 | var entropyBin = base.events.map(function(e) { |
105 | // using BigInteger.parse() | 214 | return eventBits[base.str][e.toLowerCase()]; |
106 | var entropyInt = libs.BigInteger.BigInteger.ZERO; | 215 | }).join(""); |
107 | for (var i=base.ints.length-1; i>=0; i--) { | 216 | // Get average bits per event |
108 | var thisInt = libs.BigInteger.BigInteger.parse(base.ints[i]); | 217 | // which may be adjusted for bias if log2(base) is fractional |
109 | var power = (base.ints.length - 1) - i; | 218 | var bitsPerEvent = base.bitsPerEvent; |
110 | var additionalEntropy = libs.BigInteger.BigInteger.parse(base.asInt).pow(power).multiply(thisInt); | ||
111 | entropyInt = entropyInt.add(additionalEntropy); | ||
112 | } | ||
113 | // Convert entropy to binary | ||
114 | var entropyBin = entropyInt.toString(2); | ||
115 | // If the first integer is small, it must be padded with zeros. | ||
116 | // Otherwise the chance of the first bit being 1 is 100%, which is | ||
117 | // obviously incorrect. | ||
118 | // This is not perfect for non-2^n bases. | ||
119 | var expectedBits = Math.floor(base.parts.length * Math.log2(base.asInt)); | ||
120 | while (entropyBin.length < expectedBits) { | ||
121 | entropyBin = "0" + entropyBin; | ||
122 | } | ||
123 | // Calculate the number of bits per event | ||
124 | var bitsPerEvent = Math.log2(base.asInt); | ||
125 | // Cards binary must be handled differently, since they're not replaced | ||
126 | if (base.asInt == 52) { | ||
127 | var cardEntropy = processCardEntropy(base.parts); | ||
128 | entropyBin = cardEntropy.binaryStr; | ||
129 | bitsPerEvent = cardEntropy.bitsPerEvent; | ||
130 | } | ||
131 | // Supply a 'filtered' entropy string for display purposes | 219 | // Supply a 'filtered' entropy string for display purposes |
132 | var entropyClean = base.parts.join(""); | 220 | var entropyClean = base.events.join(""); |
133 | var entropyHtml = base.parts.join(""); | 221 | var entropyHtml = base.events.join(""); |
134 | if (base.asInt == 52) { | 222 | if (base.asInt == 52) { |
135 | entropyClean = base.parts.join(" ").toUpperCase(); | 223 | entropyClean = base.events.join(" ").toUpperCase(); |
136 | entropyClean = entropyClean.replace(/C/g, "\u2663"); | 224 | entropyClean = entropyClean.replace(/C/g, "\u2663"); |
137 | entropyClean = entropyClean.replace(/D/g, "\u2666"); | 225 | entropyClean = entropyClean.replace(/D/g, "\u2666"); |
138 | entropyClean = entropyClean.replace(/H/g, "\u2665"); | 226 | entropyClean = entropyClean.replace(/H/g, "\u2665"); |
139 | entropyClean = entropyClean.replace(/S/g, "\u2660"); | 227 | entropyClean = entropyClean.replace(/S/g, "\u2660"); |
140 | entropyHtml = base.parts.join(" ").toUpperCase(); | 228 | entropyHtml = base.events.join(" ").toUpperCase(); |
141 | entropyHtml = entropyHtml.replace(/C/g, "<span class='card-suit club'>\u2663</span>"); | 229 | entropyHtml = entropyHtml.replace(/C/g, "<span class='card-suit club'>\u2663</span>"); |
142 | entropyHtml = entropyHtml.replace(/D/g, "<span class='card-suit diamond'>\u2666</span>"); | 230 | entropyHtml = entropyHtml.replace(/D/g, "<span class='card-suit diamond'>\u2666</span>"); |
143 | entropyHtml = entropyHtml.replace(/H/g, "<span class='card-suit heart'>\u2665</span>"); | 231 | entropyHtml = entropyHtml.replace(/H/g, "<span class='card-suit heart'>\u2665</span>"); |
@@ -154,18 +242,6 @@ window.Entropy = new (function() { | |||
154 | return e; | 242 | return e; |
155 | } | 243 | } |
156 | 244 | ||
157 | function getSortedDeck() { | ||
158 | var s = []; | ||
159 | var suits = "CDHS"; | ||
160 | var values = "A23456789TJQK"; | ||
161 | for (var i=0; i<suits.length; i++) { | ||
162 | for (var j=0; j<values.length; j++) { | ||
163 | s.push(values[j]+suits[i]); | ||
164 | } | ||
165 | } | ||
166 | return s; | ||
167 | } | ||
168 | |||
169 | function getBase(str, baseStr) { | 245 | function getBase(str, baseStr) { |
170 | // Need to get the lowest base for the supplied entropy. | 246 | // Need to get the lowest base for the supplied entropy. |
171 | // This prevents interpreting, say, dice rolls as hexadecimal. | 247 | // This prevents interpreting, say, dice rolls as hexadecimal. |
@@ -177,20 +253,21 @@ window.Entropy = new (function() { | |||
177 | var ints = binaryMatches.map(function(i) { return parseInt(i, 2) }); | 253 | var ints = binaryMatches.map(function(i) { return parseInt(i, 2) }); |
178 | return { | 254 | return { |
179 | ints: ints, | 255 | ints: ints, |
180 | parts: binaryMatches, | 256 | events: binaryMatches, |
181 | matcher: matchers.binary, | 257 | matcher: matchers.binary, |
182 | asInt: 2, | 258 | asInt: 2, |
259 | bitsPerEvent: 1, | ||
183 | str: "binary", | 260 | str: "binary", |
184 | } | 261 | } |
185 | } | 262 | } |
186 | var cardMatches = matchers.card(str); | 263 | var cardMatches = matchers.card(str); |
187 | if ((cardMatches.length >= hexMatches.length / 2 && autodetect) || baseStr === "card") { | 264 | if ((cardMatches.length >= hexMatches.length / 2 && autodetect) || baseStr === "card") { |
188 | var ints = convertCardsToInts(cardMatches); | ||
189 | return { | 265 | return { |
190 | ints: ints, | 266 | ints: ints, |
191 | parts: cardMatches, | 267 | events: cardMatches, |
192 | matcher: matchers.card, | 268 | matcher: matchers.card, |
193 | asInt: 52, | 269 | asInt: 52, |
270 | bitsPerEvent: (32*5 + 16*4 + 4*2) / 52, // see cardBits | ||
194 | str: "card", | 271 | str: "card", |
195 | } | 272 | } |
196 | } | 273 | } |
@@ -199,9 +276,10 @@ window.Entropy = new (function() { | |||
199 | var ints = diceMatches.map(function(i) { return parseInt(i) }); | 276 | var ints = diceMatches.map(function(i) { return parseInt(i) }); |
200 | return { | 277 | return { |
201 | ints: ints, | 278 | ints: ints, |
202 | parts: diceMatches, | 279 | events: diceMatches, |
203 | matcher: matchers.dice, | 280 | matcher: matchers.dice, |
204 | asInt: 6, | 281 | asInt: 6, |
282 | bitsPerEvent: (4*2 + 2*1) / 6, // see diceBits | ||
205 | str: "dice", | 283 | str: "dice", |
206 | } | 284 | } |
207 | } | 285 | } |
@@ -210,9 +288,10 @@ window.Entropy = new (function() { | |||
210 | var ints = base6Matches.map(function(i) { return parseInt(i) }); | 288 | var ints = base6Matches.map(function(i) { return parseInt(i) }); |
211 | return { | 289 | return { |
212 | ints: ints, | 290 | ints: ints, |
213 | parts: base6Matches, | 291 | events: base6Matches, |
214 | matcher: matchers.base6, | 292 | matcher: matchers.base6, |
215 | asInt: 6, | 293 | asInt: 6, |
294 | bitsPerEvent: (4*2 + 2*1) / 6, // see diceBits | ||
216 | str: "base 6", | 295 | str: "base 6", |
217 | } | 296 | } |
218 | } | 297 | } |
@@ -221,126 +300,22 @@ window.Entropy = new (function() { | |||
221 | var ints = base10Matches.map(function(i) { return parseInt(i) }); | 300 | var ints = base10Matches.map(function(i) { return parseInt(i) }); |
222 | return { | 301 | return { |
223 | ints: ints, | 302 | ints: ints, |
224 | parts: base10Matches, | 303 | events: base10Matches, |
225 | matcher: matchers.base10, | 304 | matcher: matchers.base10, |
226 | asInt: 10, | 305 | asInt: 10, |
306 | bitsPerEvent: (8*3 + 2*1) / 10, // see b10Bits | ||
227 | str: "base 10", | 307 | str: "base 10", |
228 | } | 308 | } |
229 | } | 309 | } |
230 | var ints = hexMatches.map(function(i) { return parseInt(i, 16) }); | 310 | var ints = hexMatches.map(function(i) { return parseInt(i, 16) }); |
231 | return { | 311 | return { |
232 | ints: ints, | 312 | ints: ints, |
233 | parts: hexMatches, | 313 | events: hexMatches, |
234 | matcher: matchers.hex, | 314 | matcher: matchers.hex, |
235 | asInt: 16, | 315 | asInt: 16, |
316 | bitsPerEvent: 4, | ||
236 | str: "hexadecimal", | 317 | str: "hexadecimal", |
237 | } | 318 | } |
238 | } | 319 | } |
239 | 320 | ||
240 | // Assume cards are NOT replaced. | ||
241 | // Additional entropy decreases as more cards are used. This means | ||
242 | // total possible entropy is measured using n!, not base^n. | ||
243 | // eg the second last card can be only one of two, not one of fifty two | ||
244 | // so the added entropy for that card is only one bit at most | ||
245 | function processCardEntropy(cards) { | ||
246 | // Track how many instances of each card have been used, and thus | ||
247 | // how many decks are in use. | ||
248 | var cardCounts = {}; | ||
249 | var numberOfDecks = 0; | ||
250 | // Work out number of decks by max(duplicates) | ||
251 | for (var i=0; i<cards.length; i++) { | ||
252 | // Get the card that was drawn | ||
253 | var cardLower = cards[i]; | ||
254 | var card = cardLower.toUpperCase(); | ||
255 | // Initialize the count for this card if needed | ||
256 | if (!(card in cardCounts)) { | ||
257 | cardCounts[card] = 0; | ||
258 | } | ||
259 | cardCounts[card] += 1; | ||
260 | // See if this is max(duplicates) | ||
261 | if (cardCounts[card] > numberOfDecks) { | ||
262 | numberOfDecks = cardCounts[card]; | ||
263 | } | ||
264 | } | ||
265 | // Work out the total number of bits for this many decks | ||
266 | // See http://crypto.stackexchange.com/q/41886 | ||
267 | var gainedBits = 0; | ||
268 | // Equivalent of Math.log2(factorial(52*numberOfDecks)) | ||
269 | // which becomes infinity for numberOfDecks > 4 | ||
270 | for (var i=1; i<=52*numberOfDecks; i++) { | ||
271 | gainedBits = gainedBits + Math.log2(i); | ||
272 | } | ||
273 | var lostBits = 52 * Math.log2(factorial(numberOfDecks)); | ||
274 | var maxBits = gainedBits - lostBits; | ||
275 | // Convert the drawn cards to a binary representation. | ||
276 | // The exact technique for doing this is unclear. | ||
277 | // See | ||
278 | // http://crypto.stackexchange.com/a/41896 | ||
279 | // "I even doubt that this is well defined (only the average entropy | ||
280 | // is, I believe)." | ||
281 | // See | ||
282 | // https://github.com/iancoleman/bip39/issues/33#issuecomment-263021856 | ||
283 | // "The binary representation can be the first log(permutations,2) bits | ||
284 | // of the sha-2 hash of the normalized deck string." | ||
285 | // | ||
286 | // In this specific implementation, the first N bits of the hash of the | ||
287 | // normalized cards string is being used. Uppercase, no spaces; eg | ||
288 | // sha256("AH8DQSTC2H") | ||
289 | var totalCards = numberOfDecks * 52; | ||
290 | var percentUsed = cards.length / totalCards; | ||
291 | // Calculate the average number of bits of entropy for the number of | ||
292 | // cards drawn. | ||
293 | var numberOfBits = Math.floor(maxBits * percentUsed); | ||
294 | // Create a normalized string of the selected cards | ||
295 | var normalizedCards = cards.join("").toUpperCase(); | ||
296 | // Convert to binary using the SHA256 hash of the normalized cards. | ||
297 | // If the number of bits is more than 256, multiple hashes | ||
298 | // are used until the required number of bits is reached. | ||
299 | var entropyBin = ""; | ||
300 | var iterations = 0; | ||
301 | while (entropyBin.length < numberOfBits) { | ||
302 | var hashedCards = sjcl.hash.sha256.hash(normalizedCards + ":" + iterations); | ||
303 | var hashHex = sjcl.codec.hex.fromBits(hashedCards); | ||
304 | for (var i=0; i<hashHex.length; i++) { | ||
305 | var decimal = parseInt(hashHex[i], 16); | ||
306 | var binary = decimal.toString(2); | ||
307 | while (binary.length < 4) { | ||
308 | binary = "0" + binary; | ||
309 | } | ||
310 | entropyBin = entropyBin + binary; | ||
311 | } | ||
312 | iterations = iterations + 1; | ||
313 | } | ||
314 | // Truncate to the appropriate number of bits. | ||
315 | entropyBin = entropyBin.substring(0, numberOfBits); | ||
316 | // Get the number of bits per event | ||
317 | bitsPerEvent = maxBits / totalCards; | ||
318 | return { | ||
319 | binaryStr: entropyBin, | ||
320 | bitsPerEvent: bitsPerEvent, | ||
321 | } | ||
322 | } | ||
323 | |||
324 | // Polyfill for Math.log2 | ||
325 | // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2#Polyfill | ||
326 | Math.log2 = Math.log2 || function(x) { | ||
327 | // The polyfill isn't good enough because of the poor accuracy of | ||
328 | // Math.LOG2E | ||
329 | // log2(8) gave 2.9999999999999996 which when floored causes issues. | ||
330 | // So instead use the BigInteger library to get it right. | ||
331 | return libs.BigInteger.BigInteger.log(x) / libs.BigInteger.BigInteger.log(2); | ||
332 | }; | ||
333 | |||
334 | // Depends on BigInteger | ||
335 | function factorial(n) { | ||
336 | if (n == 0) { | ||
337 | return 1; | ||
338 | } | ||
339 | f = libs.BigInteger.BigInteger.ONE; | ||
340 | for (var i=1; i<=n; i++) { | ||
341 | f = f.multiply(new libs.BigInteger.BigInteger(i)); | ||
342 | } | ||
343 | return f; | ||
344 | } | ||
345 | |||
346 | })(); | 321 | })(); |
diff --git a/src/js/index.js b/src/js/index.js index cd3f769..dc24963 100644 --- a/src/js/index.js +++ b/src/js/index.js | |||
@@ -1726,7 +1726,7 @@ | |||
1726 | var numberOfBits = entropy.binaryStr.length; | 1726 | var numberOfBits = entropy.binaryStr.length; |
1727 | var timeToCrack = "unknown"; | 1727 | var timeToCrack = "unknown"; |
1728 | try { | 1728 | try { |
1729 | var z = libs.zxcvbn(entropy.base.parts.join("")); | 1729 | var z = libs.zxcvbn(entropy.base.events.join("")); |
1730 | timeToCrack = z.crack_times_display.offline_fast_hashing_1e10_per_second; | 1730 | timeToCrack = z.crack_times_display.offline_fast_hashing_1e10_per_second; |
1731 | if (z.feedback.warning != "") { | 1731 | if (z.feedback.warning != "") { |
1732 | timeToCrack = timeToCrack + " - " + z.feedback.warning; | 1732 | timeToCrack = timeToCrack + " - " + z.feedback.warning; |
@@ -1745,7 +1745,7 @@ | |||
1745 | DOM.entropyFiltered.html(entropy.cleanHtml); | 1745 | DOM.entropyFiltered.html(entropy.cleanHtml); |
1746 | DOM.entropyType.text(entropyTypeStr); | 1746 | DOM.entropyType.text(entropyTypeStr); |
1747 | DOM.entropyCrackTime.text(timeToCrack); | 1747 | DOM.entropyCrackTime.text(timeToCrack); |
1748 | DOM.entropyEventCount.text(entropy.base.ints.length); | 1748 | DOM.entropyEventCount.text(entropy.base.events.length); |
1749 | DOM.entropyBits.text(numberOfBits); | 1749 | DOM.entropyBits.text(numberOfBits); |
1750 | DOM.entropyWordCount.text(wordCount); | 1750 | DOM.entropyWordCount.text(wordCount); |
1751 | DOM.entropyBinary.text(spacedBinaryStr); | 1751 | DOM.entropyBinary.text(spacedBinaryStr); |
@@ -1770,8 +1770,8 @@ | |||
1770 | // Detect duplicates | 1770 | // Detect duplicates |
1771 | var dupes = []; | 1771 | var dupes = []; |
1772 | var dupeTracker = {}; | 1772 | var dupeTracker = {}; |
1773 | for (var i=0; i<entropy.base.parts.length; i++) { | 1773 | for (var i=0; i<entropy.base.events.length; i++) { |
1774 | var card = entropy.base.parts[i]; | 1774 | var card = entropy.base.events[i]; |
1775 | var cardUpper = card.toUpperCase(); | 1775 | var cardUpper = card.toUpperCase(); |
1776 | if (cardUpper in dupeTracker) { | 1776 | if (cardUpper in dupeTracker) { |
1777 | dupes.push(card); | 1777 | dupes.push(card); |
diff --git a/tests/spec/tests.js b/tests/spec/tests.js index 73e3087..58318db 100644 --- a/tests/spec/tests.js +++ b/tests/spec/tests.js | |||
@@ -3130,7 +3130,7 @@ it("Shows the number of bits of entropy for 4 bits of binary", function(done) { | |||
3130 | testEntropyBits(done, "0000", "4"); | 3130 | testEntropyBits(done, "0000", "4"); |
3131 | }); | 3131 | }); |
3132 | it("Shows the number of bits of entropy for 1 character of base 6 (dice)", function(done) { | 3132 | it("Shows the number of bits of entropy for 1 character of base 6 (dice)", function(done) { |
3133 | // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits) | 3133 | // 6 in card is 0 in base 6, 0 is mapped to 00 by entropy.js |
3134 | testEntropyBits(done, "6", "2"); | 3134 | testEntropyBits(done, "6", "2"); |
3135 | }); | 3135 | }); |
3136 | it("Shows the number of bits of entropy for 1 character of base 10 with 3 bits", function(done) { | 3136 | it("Shows the number of bits of entropy for 1 character of base 10 with 3 bits", function(done) { |
@@ -3138,13 +3138,15 @@ it("Shows the number of bits of entropy for 1 character of base 10 with 3 bits", | |||
3138 | testEntropyBits(done, "7", "3"); | 3138 | testEntropyBits(done, "7", "3"); |
3139 | }); | 3139 | }); |
3140 | it("Shows the number of bits of entropy for 1 character of base 10 with 4 bis", function(done) { | 3140 | it("Shows the number of bits of entropy for 1 character of base 10 with 4 bis", function(done) { |
3141 | testEntropyBits(done, "8", "4"); | 3141 | // 8 in base 10 is mapped to 0 by entropy.js |
3142 | testEntropyBits(done, "8", "1"); | ||
3142 | }); | 3143 | }); |
3143 | it("Shows the number of bits of entropy for 1 character of hex", function(done) { | 3144 | it("Shows the number of bits of entropy for 1 character of hex", function(done) { |
3144 | testEntropyBits(done, "F", "4"); | 3145 | testEntropyBits(done, "F", "4"); |
3145 | }); | 3146 | }); |
3146 | it("Shows the number of bits of entropy for 2 characters of base 10", function(done) { | 3147 | it("Shows the number of bits of entropy for 2 characters of base 10", function(done) { |
3147 | testEntropyBits(done, "29", "6"); | 3148 | // 2 as base 10 is binary 010, 9 is mapped to binary 1 by entropy.js |
3149 | testEntropyBits(done, "29", "4"); | ||
3148 | }); | 3150 | }); |
3149 | it("Shows the number of bits of entropy for 2 characters of hex", function(done) { | 3151 | it("Shows the number of bits of entropy for 2 characters of hex", function(done) { |
3150 | testEntropyBits(done, "0A", "8"); | 3152 | testEntropyBits(done, "0A", "8"); |
@@ -3169,17 +3171,17 @@ it("Shows the number of bits of entropy for 4 characters of hex with leading zer | |||
3169 | testEntropyBits(done, "000A", "16"); | 3171 | testEntropyBits(done, "000A", "16"); |
3170 | }); | 3172 | }); |
3171 | it("Shows the number of bits of entropy for 4 characters of base 6", function(done) { | 3173 | it("Shows the number of bits of entropy for 4 characters of base 6", function(done) { |
3172 | testEntropyBits(done, "5555", "11"); | 3174 | // 5 in base 6 is mapped to binary 1 |
3175 | testEntropyBits(done, "5555", "4"); | ||
3173 | }); | 3176 | }); |
3174 | it("Shows the number of bits of entropy for 4 characters of base 6 dice", function(done) { | 3177 | it("Shows the number of bits of entropy for 4 characters of base 6 dice", function(done) { |
3175 | // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of | 3178 | // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of |
3176 | // 2.58 bits, which is 10.32 bits (rounded down to 10 bits) | 3179 | // binary 00 |
3177 | testEntropyBits(done, "6666", "10"); | 3180 | testEntropyBits(done, "6666", "8"); |
3178 | }); | 3181 | }); |
3179 | it("Shows the number of bits of entropy for 4 charactes of base 10", function(done) { | 3182 | it("Shows the number of bits of entropy for 4 charactes of base 10", function(done) { |
3180 | // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded | 3183 | // 2 in base 10 is binary 010 and 7 is binary 111 so is 4 events of 3 bits |
3181 | // down to 13) | 3184 | testEntropyBits(done, "2227", "12"); |
3182 | testEntropyBits(done, "2227", "13"); | ||
3183 | }); | 3185 | }); |
3184 | it("Shows the number of bits of entropy for 4 characters of hex with 2 leading zeros", function(done) { | 3186 | it("Shows the number of bits of entropy for 4 characters of hex with 2 leading zeros", function(done) { |
3185 | testEntropyBits(done, "222F", "16"); | 3187 | testEntropyBits(done, "222F", "16"); |
@@ -3188,13 +3190,16 @@ it("Shows the number of bits of entropy for 4 characters of hex starting with F" | |||
3188 | testEntropyBits(done, "FFFF", "16"); | 3190 | testEntropyBits(done, "FFFF", "16"); |
3189 | }); | 3191 | }); |
3190 | it("Shows the number of bits of entropy for 10 characters of base 10", function(done) { | 3192 | it("Shows the number of bits of entropy for 10 characters of base 10", function(done) { |
3191 | // 10 events at 3.32 bits per event | 3193 | // 10 events with 3 bits for each event |
3192 | testEntropyBits(done, "0000101017", "33"); | 3194 | testEntropyBits(done, "0000101017", "30"); |
3195 | }); | ||
3196 | it("Shows the number of bits of entropy for 10 characters of base 10 account for bias", function(done) { | ||
3197 | // 9 events with 3 bits per event and 1 event with 1 bit per event | ||
3198 | testEntropyBits(done, "0000101018", "28"); | ||
3193 | }); | 3199 | }); |
3194 | it("Shows the number of bits of entropy for a full deck of cards", function(done) { | 3200 | it("Shows the number of bits of entropy for a full deck of cards", function(done) { |
3195 | // cards are not replaced, so a full deck is not 52^52 entropy which is 296 | 3201 | // removing bias is 32*5 + 16*4 + 4*2 |
3196 | // bits, it's 52!, which is 225 bits | 3202 | testEntropyBits(done, "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "232"); |
3197 | testEntropyBits(done, "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225"); | ||
3198 | }); | 3203 | }); |
3199 | 3204 | ||
3200 | it("Shows details about the entered entropy", function(done) { | 3205 | it("Shows details about the entered entropy", function(done) { |
@@ -3320,7 +3325,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3320 | entropy: "7d", | 3325 | entropy: "7d", |
3321 | type: "card", | 3326 | type: "card", |
3322 | events: "1", | 3327 | events: "1", |
3323 | bits: "4", | 3328 | bits: "5", |
3324 | words: 0, | 3329 | words: 0, |
3325 | strength: "less than a second", | 3330 | strength: "less than a second", |
3326 | } | 3331 | } |
@@ -3332,7 +3337,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3332 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", | 3337 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", |
3333 | type: "card (full deck)", | 3338 | type: "card (full deck)", |
3334 | events: "52", | 3339 | events: "52", |
3335 | bits: "225", | 3340 | bits: "232", |
3336 | words: 21, | 3341 | words: 21, |
3337 | strength: "centuries", | 3342 | strength: "centuries", |
3338 | } | 3343 | } |
@@ -3344,7 +3349,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3344 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d", | 3349 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d", |
3345 | type: "card (full deck, 1 duplicate: 3d)", | 3350 | type: "card (full deck, 1 duplicate: 3d)", |
3346 | events: "53", | 3351 | events: "53", |
3347 | bits: "254", | 3352 | bits: "237", |
3348 | words: 21, | 3353 | words: 21, |
3349 | strength: "centuries", | 3354 | strength: "centuries", |
3350 | } | 3355 | } |
@@ -3356,7 +3361,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3356 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d", | 3361 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d", |
3357 | type: "card (2 duplicates: 3d 4d, 1 missing: KS)", | 3362 | type: "card (2 duplicates: 3d 4d, 1 missing: KS)", |
3358 | events: "53", | 3363 | events: "53", |
3359 | bits: "254", | 3364 | bits: "240", |
3360 | words: 21, | 3365 | words: 21, |
3361 | strength: "centuries", | 3366 | strength: "centuries", |
3362 | } | 3367 | } |
@@ -3368,8 +3373,8 @@ it("Shows details about the entered entropy", function(done) { | |||
3368 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d", | 3373 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d", |
3369 | type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)", | 3374 | type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)", |
3370 | events: "55", | 3375 | events: "55", |
3371 | bits: "264", | 3376 | bits: "250", |
3372 | words: 24, | 3377 | words: 21, |
3373 | strength: "centuries", | 3378 | strength: "centuries", |
3374 | } | 3379 | } |
3375 | ); | 3380 | ); |
@@ -3377,13 +3382,12 @@ it("Shows details about the entered entropy", function(done) { | |||
3377 | it("Shows details about the entered entropy", function(done) { | 3382 | it("Shows details about the entered entropy", function(done) { |
3378 | testEntropyFeedback(done, | 3383 | testEntropyFeedback(done, |
3379 | // Next test was throwing uncaught error in zxcvbn | 3384 | // Next test was throwing uncaught error in zxcvbn |
3380 | // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2 | ||
3381 | { | 3385 | { |
3382 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", | 3386 | entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", |
3383 | type: "card (full deck, 52 duplicates: ac 2c 3c...)", | 3387 | type: "card (full deck, 52 duplicates: ac 2c 3c...)", |
3384 | events: "104", | 3388 | events: "104", |
3385 | bits: "499", | 3389 | bits: "464", |
3386 | words: 45, | 3390 | words: 42, |
3387 | strength: "centuries", | 3391 | strength: "centuries", |
3388 | } | 3392 | } |
3389 | ); | 3393 | ); |
@@ -3395,7 +3399,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3395 | entropy: "asAS", | 3399 | entropy: "asAS", |
3396 | type: "card (1 duplicate: AS)", | 3400 | type: "card (1 duplicate: AS)", |
3397 | events: "2", | 3401 | events: "2", |
3398 | bits: "9", | 3402 | bits: "8", |
3399 | words: 0, | 3403 | words: 0, |
3400 | strength: "less than a second", | 3404 | strength: "less than a second", |
3401 | } | 3405 | } |
@@ -3407,7 +3411,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3407 | entropy: "ASas", | 3411 | entropy: "ASas", |
3408 | type: "card (1 duplicate: as)", | 3412 | type: "card (1 duplicate: as)", |
3409 | events: "2", | 3413 | events: "2", |
3410 | bits: "9", | 3414 | bits: "8", |
3411 | words: 0, | 3415 | words: 0, |
3412 | strength: "less than a second", | 3416 | strength: "less than a second", |
3413 | } | 3417 | } |
@@ -3420,8 +3424,8 @@ it("Shows details about the entered entropy", function(done) { | |||
3420 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", | 3424 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", |
3421 | type: "card (1 missing: 9C)", | 3425 | type: "card (1 missing: 9C)", |
3422 | events: "51", | 3426 | events: "51", |
3423 | bits: "221", | 3427 | bits: "227", |
3424 | words: 18, | 3428 | words: 21, |
3425 | strength: "centuries", | 3429 | strength: "centuries", |
3426 | } | 3430 | } |
3427 | ); | 3431 | ); |
@@ -3432,7 +3436,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3432 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", | 3436 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", |
3433 | type: "card (2 missing: 9C 5D)", | 3437 | type: "card (2 missing: 9C 5D)", |
3434 | events: "50", | 3438 | events: "50", |
3435 | bits: "216", | 3439 | bits: "222", |
3436 | words: 18, | 3440 | words: 18, |
3437 | strength: "centuries", | 3441 | strength: "centuries", |
3438 | } | 3442 | } |
@@ -3444,7 +3448,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3444 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", | 3448 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", |
3445 | type: "card (4 missing: 9C 5D QD...)", | 3449 | type: "card (4 missing: 9C 5D QD...)", |
3446 | events: "48", | 3450 | events: "48", |
3447 | bits: "208", | 3451 | bits: "212", |
3448 | words: 18, | 3452 | words: 18, |
3449 | strength: "centuries", | 3453 | strength: "centuries", |
3450 | } | 3454 | } |
@@ -3457,20 +3461,21 @@ it("Shows details about the entered entropy", function(done) { | |||
3457 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks", | 3461 | entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks", |
3458 | type: "card", | 3462 | type: "card", |
3459 | events: "45", | 3463 | events: "45", |
3460 | bits: "195", | 3464 | bits: "198", |
3461 | words: 18, | 3465 | words: 18, |
3462 | strength: "centuries", | 3466 | strength: "centuries", |
3463 | } | 3467 | } |
3464 | ); | 3468 | ); |
3465 | }); | 3469 | }); |
3466 | it("Shows details about the entered entropy", function(done) { | 3470 | it("Shows details about the entered entropy", function(done) { |
3471 | // multiple decks does not affect the bits per event | ||
3472 | // since the bits are hardcoded in entropy.js | ||
3467 | testEntropyFeedback(done, | 3473 | testEntropyFeedback(done, |
3468 | // Multiple decks of cards increases bits per event | ||
3469 | { | 3474 | { |
3470 | entropy: "3d", | 3475 | entropy: "3d", |
3471 | events: "1", | 3476 | events: "1", |
3472 | bits: "4", | 3477 | bits: "5", |
3473 | bitsPerEvent: "4.34", | 3478 | bitsPerEvent: "4.46", |
3474 | } | 3479 | } |
3475 | ); | 3480 | ); |
3476 | }); | 3481 | }); |
@@ -3479,8 +3484,8 @@ it("Shows details about the entered entropy", function(done) { | |||
3479 | { | 3484 | { |
3480 | entropy: "3d3d", | 3485 | entropy: "3d3d", |
3481 | events: "2", | 3486 | events: "2", |
3482 | bits: "9", | 3487 | bits: "10", |
3483 | bitsPerEvent: "4.80", | 3488 | bitsPerEvent: "4.46", |
3484 | } | 3489 | } |
3485 | ); | 3490 | ); |
3486 | }); | 3491 | }); |
@@ -3490,7 +3495,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3490 | entropy: "3d3d3d", | 3495 | entropy: "3d3d3d", |
3491 | events: "3", | 3496 | events: "3", |
3492 | bits: "15", | 3497 | bits: "15", |
3493 | bitsPerEvent: "5.01", | 3498 | bitsPerEvent: "4.46", |
3494 | } | 3499 | } |
3495 | ); | 3500 | ); |
3496 | }); | 3501 | }); |
@@ -3500,7 +3505,7 @@ it("Shows details about the entered entropy", function(done) { | |||
3500 | entropy: "3d3d3d3d", | 3505 | entropy: "3d3d3d3d", |
3501 | events: "4", | 3506 | events: "4", |
3502 | bits: "20", | 3507 | bits: "20", |
3503 | bitsPerEvent: "5.14", | 3508 | bitsPerEvent: "4.46", |
3504 | } | 3509 | } |
3505 | ); | 3510 | ); |
3506 | }); | 3511 | }); |
@@ -3509,8 +3514,8 @@ it("Shows details about the entered entropy", function(done) { | |||
3509 | { | 3514 | { |
3510 | entropy: "3d3d3d3d3d", | 3515 | entropy: "3d3d3d3d3d", |
3511 | events: "5", | 3516 | events: "5", |
3512 | bits: "26", | 3517 | bits: "25", |
3513 | bitsPerEvent: "5.22", | 3518 | bitsPerEvent: "4.46", |
3514 | } | 3519 | } |
3515 | ); | 3520 | ); |
3516 | }); | 3521 | }); |
@@ -3519,8 +3524,8 @@ it("Shows details about the entered entropy", function(done) { | |||
3519 | { | 3524 | { |
3520 | entropy: "3d3d3d3d3d3d", | 3525 | entropy: "3d3d3d3d3d3d", |
3521 | events: "6", | 3526 | events: "6", |
3522 | bits: "31", | 3527 | bits: "30", |
3523 | bitsPerEvent: "5.28", | 3528 | bitsPerEvent: "4.46", |
3524 | } | 3529 | } |
3525 | ); | 3530 | ); |
3526 | }); | 3531 | }); |
@@ -3529,8 +3534,8 @@ it("Shows details about the entered entropy", function(done) { | |||
3529 | { | 3534 | { |
3530 | entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d", | 3535 | entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d", |
3531 | events: "33", | 3536 | events: "33", |
3532 | bits: "184", | 3537 | bits: "165", |
3533 | bitsPerEvent: "5.59", | 3538 | bitsPerEvent: "4.46", |
3534 | strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"', | 3539 | strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"', |
3535 | } | 3540 | } |
3536 | ); | 3541 | ); |
@@ -3581,10 +3586,11 @@ it('Converts very long entropy to very long mnemonics', function(done) { | |||
3581 | // https://bip32jp.github.io/english/index.html | 3586 | // https://bip32jp.github.io/english/index.html |
3582 | // NOTES: | 3587 | // NOTES: |
3583 | // Is incompatible with: | 3588 | // Is incompatible with: |
3589 | // base 6 | ||
3584 | // base 20 | 3590 | // base 20 |
3585 | it('Is compatible with bip32jp.github.io', function(done) { | 3591 | it('Is compatible with bip32jp.github.io', function(done) { |
3586 | var entropy = "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543"; | 3592 | var entropy = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; |
3587 | var expectedPhrase = "train then jungle barely whip fiber purpose puppy eagle cloud clump hospital robot brave balcony utility detect estate old green desk skill multiply virus"; | 3593 | var expectedPhrase = "primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary foster"; |
3588 | driver.findElement(By.css('.use-entropy')) | 3594 | driver.findElement(By.css('.use-entropy')) |
3589 | .click(); | 3595 | .click(); |
3590 | driver.findElement(By.css('.entropy')) | 3596 | driver.findElement(By.css('.entropy')) |