]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blob - src/js/entropy.js
2 * Detects entropy from a string.
10 * card [A2-9TJQK][CDHS]
12 * Automatically uses lowest entropy to avoid issues such as interpretting 0101
13 * as hexadecimal which would be 16 bits when really it's only 4 bits of binary
17 window
.Entropy
= new (function() {
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
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
44 "0": "00", // equivalent to 0 in base 6
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
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
150 // matchers returns an array of the matched events for each type of entropy.
152 // matchers.binary("010") returns ["0", "1", "0"]
153 // matchers.binary("a10") returns ["1", "0"]
154 // matchers.hex("a10") returns ["a", "1", "0"]
156 binary: function(str
) {
157 return str
.match(/[0-1]/gi) || [];
159 base6: function(str
) {
160 return str
.match(/[0-5]/gi) || [];
162 dice: function(str
) {
163 return str
.match(/[1-6]/gi) || []; // ie dice numbers
165 base10: function(str
) {
166 return str
.match(/[0-9]/gi) || [];
169 return str
.match(/[0-9A-F]/gi) || [];
171 card: function(str
) {
172 // Format is NumberSuit, eg
175 // TD ten of diamonds
177 // QH queen of hearts
179 return str
.match(/([A2-9TJQK][CDHS])/gi) || [];
183 this.fromString = function(rawEntropyStr
, baseStr
) {
184 // Find type of entropy being used (binary, hex, dice etc)
185 var base
= getBase(rawEntropyStr
, baseStr
);
186 // Convert dice to base6 entropy (ie 1-6 to 0-5)
187 // This is done by changing all 6s to 0s
188 if (base
.str
== "dice") {
190 for (var i
=0; i
<base
.events
.length
; i
++) {
191 var c
= base
.events
[i
];
192 if ("12345".indexOf(c
) > -1) {
193 newEvents
[i
] = base
.events
[i
];
199 base
.str
= "base 6 (dice)";
200 base
.events
= newEvents
;
201 base
.matcher
= matchers
.base6
;
203 // Detect empty entropy
204 if (base
.events
.length
== 0) {
212 // Convert entropy events to binary
213 var entropyBin
= base
.events
.map(function(e
) {
214 return eventBits
[base
.str
][e
.toLowerCase()];
216 // Get average bits per event
217 // which may be adjusted for bias if log2(base) is fractional
218 var bitsPerEvent
= base
.bitsPerEvent
;
219 // Supply a 'filtered' entropy string for display purposes
220 var entropyClean
= base
.events
.join("");
221 var entropyHtml
= base
.events
.join("");
222 if (base
.asInt
== 52) {
223 entropyClean
= base
.events
.join(" ").toUpperCase();
224 entropyClean
= entropyClean
.replace(/C
/g
, "\u2663");
225 entropyClean
= entropyClean
.replace(/D
/g
, "\u2666");
226 entropyClean
= entropyClean
.replace(/H
/g
, "\u2665");
227 entropyClean
= entropyClean
.replace(/S
/g
, "\u2660");
228 entropyHtml
= base
.events
.join(" ").toUpperCase();
229 entropyHtml
= entropyHtml
.replace(/C
/g
, "<span class='card-suit club'>\u2663</span>");
230 entropyHtml
= entropyHtml
.replace(/D
/g
, "<span class='card-suit diamond'>\u2666</span>");
231 entropyHtml
= entropyHtml
.replace(/H
/g
, "<span class='card-suit heart'>\u2665</span>");
232 entropyHtml
= entropyHtml
.replace(/S
/g
, "<span class='card-suit spade'>\u2660</span>");
236 binaryStr: entropyBin
,
237 cleanStr: entropyClean
,
238 cleanHtml: entropyHtml
,
239 bitsPerEvent: bitsPerEvent
,
245 function getBase(str
, baseStr
) {
246 // Need to get the lowest base for the supplied entropy.
247 // This prevents interpreting, say, dice rolls as hexadecimal.
248 var binaryMatches
= matchers
.binary(str
);
249 var hexMatches
= matchers
.hex(str
);
250 var autodetect
= baseStr
=== undefined;
251 // Find the lowest base that can be used, whilst ignoring any irrelevant chars
252 if ((binaryMatches
.length
== hexMatches
.length
&& hexMatches
.length
> 0 && autodetect
) || baseStr
=== "binary") {
253 var ints
= binaryMatches
.map(function(i
) { return parseInt(i
, 2) });
256 events: binaryMatches
,
257 matcher: matchers
.binary
,
263 var cardMatches
= matchers
.card(str
);
264 if ((cardMatches
.length
>= hexMatches
.length
/ 2 && autodetect
) || baseStr
=== "card") {
268 matcher: matchers
.card
,
270 bitsPerEvent: (32*5 + 16*4 + 4*2) / 52, // see cardBits
274 var diceMatches
= matchers
.dice(str
);
275 if ((diceMatches
.length
== hexMatches
.length
&& hexMatches
.length
> 0 && autodetect
) || baseStr
=== "dice") {
276 var ints
= diceMatches
.map(function(i
) { return parseInt(i
) });
280 matcher: matchers
.dice
,
282 bitsPerEvent: (4*2 + 2*1) / 6, // see diceBits
286 var base6Matches
= matchers
.base6(str
);
287 if ((base6Matches
.length
== hexMatches
.length
&& hexMatches
.length
> 0 && autodetect
) || baseStr
=== "base 6") {
288 var ints
= base6Matches
.map(function(i
) { return parseInt(i
) });
291 events: base6Matches
,
292 matcher: matchers
.base6
,
294 bitsPerEvent: (4*2 + 2*1) / 6, // see diceBits
298 var base10Matches
= matchers
.base10(str
);
299 if ((base10Matches
.length
== hexMatches
.length
&& hexMatches
.length
> 0 && autodetect
) || baseStr
=== "base 10") {
300 var ints
= base10Matches
.map(function(i
) { return parseInt(i
) });
303 events: base10Matches
,
304 matcher: matchers
.base10
,
306 bitsPerEvent: (8*3 + 2*1) / 10, // see b10Bits
310 var ints
= hexMatches
.map(function(i
) { return parseInt(i
, 16) });
314 matcher: matchers
.hex
,