From 9e97eb7684bf2c2d9c5276561f29fe50caf31f82 Mon Sep 17 00:00:00 2001 From: Ian Coleman Date: Thu, 17 Nov 2016 14:36:12 +1100 Subject: [PATCH] Card entropy corrections compiled into standalone --- bip39-standalone.html | 128 +++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 44 deletions(-) diff --git a/bip39-standalone.html b/bip39-standalone.html index 5fd3517..8476014 100644 --- a/bip39-standalone.html +++ b/bip39-standalone.html @@ -17940,6 +17940,7 @@ var time_estimates;time_estimates={estimate_attack_times:function(e){var t,n,s,o * dice 6 [1-6] * decimal [0-9] * hexadecimal [0-9A-F] + * card [A2-9TJQK][CDHS] * * Automatically uses lowest entropy to avoid issues such as interpretting 0101 * as hexadecimal which would be 16 bits when really it's only 4 bits of binary @@ -18050,6 +18051,40 @@ window.Entropy = new (function() { while (entropyBin.length < expectedBits) { entropyBin = "0" + entropyBin; } + // Assume cards are NOT replaced. + // Additional entropy decreases as more cards are used. This means + // 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 + if (base.asInt == 52) { + // Get the maximum value WITHOUT replacement + var totalDecks = Math.ceil(base.parts.length / 52); + var totalCards = totalDecks * 52; + var totalCombos = factorial(52).pow(totalDecks); + var totalRemainingCards = totalCards - base.parts.length; + var remainingDecks = Math.floor(totalRemainingCards / 52); + var remainingCards = totalRemainingCards % 52; + var remainingCombos = factorial(52).pow(remainingDecks).multiply(factorial(remainingCards)); + var currentCombos = totalCombos.divide(remainingCombos); + var numberOfBits = Math.log2(currentCombos); + var maxWithoutReplace = BigInteger.pow(2, numberOfBits); + // aggresive flooring of numberOfBits by BigInteger.pow means a + // more accurate result can be had for small numbers using the + // built-in Math.pow function. + if (numberOfBits < 32) { + maxWithoutReplace = BigInteger(Math.round(Math.pow(2, numberOfBits))); + } + // Get the maximum value WITH replacement + var maxWithReplace = BigInteger.pow(52, base.parts.length); + // Calculate the new value by scaling the original value down + var withoutReplace = entropyInt.multiply(maxWithoutReplace).divide(maxWithReplace); + // Left pad with zeros based on number of bits + var entropyBin = withoutReplace.toString(2); + var numberOfBitsInt = Math.floor(numberOfBits); + while (entropyBin.length < numberOfBitsInt) { + entropyBin = "0" + entropyBin; + } + } // Supply a 'filtered' entropy string for display purposes var entropyClean = base.parts.join(""); var entropyHtml = base.parts.join(""); @@ -18065,6 +18100,7 @@ window.Entropy = new (function() { entropyHtml = entropyHtml.replace(/H/g, "\u2665"); entropyHtml = entropyHtml.replace(/S/g, "\u2660"); } + // Return the result var e = { binaryStr: entropyBin, cleanStr: entropyClean, @@ -18154,6 +18190,18 @@ window.Entropy = new (function() { return BigInteger.log(x) / BigInteger.log(2); }; + // Depends on BigInteger + function factorial(n) { + if (n == 0) { + return 1; + } + f = BigInteger.ONE; + for (var i=1; i<=n; i++) { + f = f.multiply(new BigInteger(i)); + } + return f; + } + })();