X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=src%2Fjs%2Fentropy.js;h=0b76dcfef0afbdfb8f8de5103bb090828718fa9f;hb=b54c12180e5f4eb633e587551715707ec0523943;hp=5b687d8f6e3d1091ba2796a9d14629d9952ecff4;hpb=6606c50fd3af59483a5524170d9d2c3ec213a60f;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FBIP39.git diff --git a/src/js/entropy.js b/src/js/entropy.js index 5b687d8..0b76dcf 100644 --- a/src/js/entropy.js +++ b/src/js/entropy.js @@ -36,88 +36,106 @@ window.Entropy = new (function() { hex: function(str) { return str.match(/[0-9A-F]/gi) || []; }, + card: function(str) { + // Format is NumberSuit, eg + // AH ace of hearts + // 8C eight of clubs + // TD ten of diamonds + // JS jack of spades + // QH queen of hearts + // KC king of clubs + return str.match(/([A2-9TJQK][CDHS])/gi) || []; + } + } + + // Convert array of cards from ["ac", "4d", "ks"] + // to numbers between 0 and 51 [0, 16, 51] + function convertCardsToInts(cards) { + var ints = []; + var values = "a23456789tjqk"; + var suits = "cdhs"; + for (var i=0; i -1) { - newRawEntropyStr += (parseInt(c) - 1).toString(); + var newParts = []; + var newInts = []; + for (var i=0; i -1) { + newParts[i] = base.parts[i]; + newInts[i] = base.ints[i]; } else { - newRawEntropyStr += c + newParts[i] = "0"; + newInts[i] = 0; } } - rawEntropyStr = newRawEntropyStr; base.str = "base 6 (dice)"; - base.parts = matchers.base6(rawEntropyStr); + base.ints = newInts; + base.parts = newParts; base.matcher = matchers.base6; } // Detect empty entropy if (base.parts.length == 0) { return { binaryStr: "", - hexStr: "", cleanStr: "", + cleanHtml: "", base: base, }; } - // Pull leading zeros off - var leadingZeros = []; - while (base.parts[0] == "0") { - leadingZeros.push("0"); - base.parts.shift(); + // Convert base.ints to BigInteger. + // Due to using unusual bases, eg cards of base52, this is not as simple as + // using BigInteger.parse() + var entropyInt = BigInteger.ZERO; + for (var i=base.ints.length-1; i>=0; i--) { + var thisInt = BigInteger.parse(base.ints[i]); + var power = (base.ints.length - 1) - i; + var additionalEntropy = BigInteger.parse(base.asInt).pow(power).multiply(thisInt); + entropyInt = entropyInt.add(additionalEntropy); } - // Convert leading zeros to binary equivalent - var numBinLeadingZeros = Math.ceil(Math.log2(base.asInt) * leadingZeros.length); - var binLeadingZeros = ""; - for (var i=0; i= 4 && firstDigit < 8) { - binLeadingZeros += "0"; - } - else if (firstDigit >= 2 && firstDigit < 4) { - binLeadingZeros += "00"; - } - else if (firstDigit >= 1 && firstDigit < 2) { - binLeadingZeros += "000"; - } + // Supply a 'filtered' entropy string for display purposes + var entropyClean = base.parts.join(""); + var entropyHtml = base.parts.join(""); + if (base.asInt == 52) { + entropyClean = base.parts.join(" ").toUpperCase(); + entropyClean = entropyClean.replace(/C/g, "\u2663"); + entropyClean = entropyClean.replace(/D/g, "\u2666"); + entropyClean = entropyClean.replace(/H/g, "\u2665"); + entropyClean = entropyClean.replace(/S/g, "\u2660"); + entropyHtml = base.parts.join(" ").toUpperCase(); + entropyHtml = entropyHtml.replace(/C/g, "\u2663"); + entropyHtml = entropyHtml.replace(/D/g, "\u2666"); + entropyHtml = entropyHtml.replace(/H/g, "\u2665"); + entropyHtml = entropyHtml.replace(/S/g, "\u2660"); } - // Convert entropy to different foramts - var entropyInt = BigInteger.parse(base.parts.join(""), base.asInt); - var entropyBin = binLeadingZeros + entropyInt.toString(2); - var entropyHex = hexLeadingZeros + entropyInt.toString(16); - var entropyClean = leadingZeros.join("") + base.parts.join(""); var e = { binaryStr: entropyBin, - hexStr: entropyHex, cleanStr: entropyClean, + cleanHtml: entropyHtml, base: base, } return e; @@ -129,17 +147,32 @@ window.Entropy = new (function() { var binaryMatches = matchers.binary(str); var hexMatches = matchers.hex(str); // Find the lowest base that can be used, whilst ignoring any irrelevant chars - if (binaryMatches.length == hexMatches.length) { + if (binaryMatches.length == hexMatches.length && hexMatches.length > 0) { + var ints = binaryMatches.map(function(i) { return parseInt(i, 2) }); return { + ints: ints, parts: binaryMatches, matcher: matchers.binary, asInt: 2, str: "binary", } } + var cardMatches = matchers.card(str); + if (cardMatches.length >= hexMatches.length / 2) { + var ints = convertCardsToInts(cardMatches); + return { + ints: ints, + parts: cardMatches, + matcher: matchers.card, + asInt: 52, + str: "card", + } + } var diceMatches = matchers.dice(str); - if (diceMatches.length == hexMatches.length) { + if (diceMatches.length == hexMatches.length && hexMatches.length > 0) { + var ints = diceMatches.map(function(i) { return parseInt(i) }); return { + ints: ints, parts: diceMatches, matcher: matchers.dice, asInt: 6, @@ -147,8 +180,10 @@ window.Entropy = new (function() { } } var base6Matches = matchers.base6(str); - if (base6Matches.length == hexMatches.length) { + if (base6Matches.length == hexMatches.length && hexMatches.length > 0) { + var ints = base6Matches.map(function(i) { return parseInt(i) }); return { + ints: ints, parts: base6Matches, matcher: matchers.base6, asInt: 6, @@ -156,15 +191,19 @@ window.Entropy = new (function() { } } var base10Matches = matchers.base10(str); - if (base10Matches.length == hexMatches.length) { + if (base10Matches.length == hexMatches.length && hexMatches.length > 0) { + var ints = base10Matches.map(function(i) { return parseInt(i) }); return { + ints: ints, parts: base10Matches, matcher: matchers.base10, asInt: 10, str: "base 10", } } + var ints = hexMatches.map(function(i) { return parseInt(i, 16) }); return { + ints: ints, parts: hexMatches, matcher: matchers.hex, asInt: 16, @@ -175,7 +214,11 @@ window.Entropy = new (function() { // Polyfill for Math.log2 // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2#Polyfill Math.log2 = Math.log2 || function(x) { - return Math.log(x) * Math.LOG2E; + // The polyfill isn't good enough because of the poor accuracy of + // Math.LOG2E + // log2(8) gave 2.9999999999999996 which when floored causes issues. + // So instead use the BigInteger library to get it right. + return BigInteger.log(x) / BigInteger.log(2); }; })();