]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blobdiff - src/js/entropy.js
Add experimental incomplete combined js libs
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / src / js / entropy.js
index d04d861dfa16b44f23b41398ebaa2418b3b129e1..a4c762263c5e2e735eb9d5bc58f1120dca4ac0cf 100644 (file)
@@ -67,9 +67,9 @@ window.Entropy = new (function() {
         return ints;
     }
 
-    this.fromString = function(rawEntropyStr) {
+    this.fromString = function(rawEntropyStr, baseStr) {
         // Find type of entropy being used (binary, hex, dice etc)
-        var base = getBase(rawEntropyStr);
+        var base = getBase(rawEntropyStr, baseStr);
         // Convert dice to base6 entropy (ie 1-6 to 0-5)
         // This is done by changing all 6s to 0s
         if (base.str == "dice") {
@@ -120,9 +120,13 @@ window.Entropy = new (function() {
         while (entropyBin.length < expectedBits) {
             entropyBin = "0" + entropyBin;
         }
+        // Calculate the number of bits per event
+        var bitsPerEvent = Math.log2(base.asInt);
         // Cards binary must be handled differently, since they're not replaced
         if (base.asInt == 52) {
-            entropyBin = getCardBinary(base.parts);
+            var cardEntropy = processCardEntropy(base.parts);
+            entropyBin = cardEntropy.binaryStr;
+            bitsPerEvent = cardEntropy.bitsPerEvent;
         }
         // Supply a 'filtered' entropy string for display purposes
         var entropyClean = base.parts.join("");
@@ -144,6 +148,7 @@ window.Entropy = new (function() {
             binaryStr: entropyBin,
             cleanStr: entropyClean,
             cleanHtml: entropyHtml,
+            bitsPerEvent: bitsPerEvent,
             base: base,
         }
         return e;
@@ -161,13 +166,14 @@ window.Entropy = new (function() {
         return s;
     }
 
-    function getBase(str) {
+    function getBase(str, baseStr) {
         // Need to get the lowest base for the supplied entropy.
         // This prevents interpreting, say, dice rolls as hexadecimal.
         var binaryMatches = matchers.binary(str);
         var hexMatches = matchers.hex(str);
+        var autodetect = baseStr === undefined;
         // Find the lowest base that can be used, whilst ignoring any irrelevant chars
-        if (binaryMatches.length == hexMatches.length && hexMatches.length > 0) {
+        if ((binaryMatches.length == hexMatches.length && hexMatches.length > 0 && autodetect) || baseStr === "binary") {
             var ints = binaryMatches.map(function(i) { return parseInt(i, 2) });
             return {
                 ints: ints,
@@ -178,7 +184,7 @@ window.Entropy = new (function() {
             }
         }
         var cardMatches = matchers.card(str);
-        if (cardMatches.length >= hexMatches.length / 2) {
+        if ((cardMatches.length >= hexMatches.length / 2 && autodetect) || baseStr === "card") {
             var ints = convertCardsToInts(cardMatches);
             return {
                 ints: ints,
@@ -189,7 +195,7 @@ window.Entropy = new (function() {
             }
         }
         var diceMatches = matchers.dice(str);
-        if (diceMatches.length == hexMatches.length && hexMatches.length > 0) {
+        if ((diceMatches.length == hexMatches.length && hexMatches.length > 0 && autodetect) || baseStr === "dice") {
             var ints = diceMatches.map(function(i) { return parseInt(i) });
             return {
                 ints: ints,
@@ -200,7 +206,7 @@ window.Entropy = new (function() {
             }
         }
         var base6Matches = matchers.base6(str);
-        if (base6Matches.length == hexMatches.length && hexMatches.length > 0) {
+        if ((base6Matches.length == hexMatches.length && hexMatches.length > 0 && autodetect) || baseStr === "base 6") {
             var ints = base6Matches.map(function(i) { return parseInt(i) });
             return {
                 ints: ints,
@@ -211,7 +217,7 @@ window.Entropy = new (function() {
             }
         }
         var base10Matches = matchers.base10(str);
-        if (base10Matches.length == hexMatches.length && hexMatches.length > 0) {
+        if ((base10Matches.length == hexMatches.length && hexMatches.length > 0 && autodetect) || baseStr === "base 10") {
             var ints = base10Matches.map(function(i) { return parseInt(i) });
             return {
                 ints: ints,
@@ -236,7 +242,7 @@ window.Entropy = new (function() {
     // total possible entropy is measured using n!, not base^n.
     // eg the second last card can be only one of two, not one of fifty two
     // so the added entropy for that card is only one bit at most
-    function getCardBinary(cards) {
+    function processCardEntropy(cards) {
         // Track how many instances of each card have been used, and thus
         // how many decks are in use.
         var cardCounts = {};
@@ -258,7 +264,12 @@ window.Entropy = new (function() {
         }
         // Work out the total number of bits for this many decks
         // See http://crypto.stackexchange.com/q/41886
-        var gainedBits = Math.log2(factorial(52 * numberOfDecks));
+        var gainedBits = 0;
+        // Equivalent of Math.log2(factorial(52*numberOfDecks))
+        // which becomes infinity for numberOfDecks > 4
+        for (var i=1; i<=52*numberOfDecks; i++) {
+            gainedBits = gainedBits + Math.log2(i);
+        }
         var lostBits = 52 * Math.log2(factorial(numberOfDecks));
         var maxBits = gainedBits - lostBits;
         // Convert the drawn cards to a binary representation.
@@ -283,15 +294,12 @@ window.Entropy = new (function() {
         // Create a normalized string of the selected cards
         var normalizedCards = cards.join("").toUpperCase();
         // Convert to binary using the SHA256 hash of the normalized cards.
-        // If the number of bits is more than 256, multiple rounds of hashing
+        // If the number of bits is more than 256, multiple hashes
         // are used until the required number of bits is reached.
         var entropyBin = "";
         var iterations = 0;
         while (entropyBin.length < numberOfBits) {
-            var hashedCards = sjcl.hash.sha256.hash(normalizedCards);
-            for (var j=0; j<iterations; j++) {
-                hashedCards = sjcl.hash.sha256.hash(hashedCards);
-            }
+            var hashedCards = sjcl.hash.sha256.hash(normalizedCards + ":" + iterations);
             var hashHex = sjcl.codec.hex.fromBits(hashedCards);
             for (var i=0; i<hashHex.length; i++) {
                 var decimal = parseInt(hashHex[i], 16);
@@ -305,7 +313,12 @@ window.Entropy = new (function() {
         }
         // Truncate to the appropriate number of bits.
         entropyBin = entropyBin.substring(0, numberOfBits);
-        return entropyBin;
+        // Get the number of bits per event
+        bitsPerEvent = maxBits / totalCards;
+        return {
+            binaryStr: entropyBin,
+            bitsPerEvent: bitsPerEvent,
+        }
     }
 
     // Polyfill for Math.log2