aboutsummaryrefslogtreecommitdiff
path: root/bip39-standalone.html
diff options
context:
space:
mode:
authorIan Coleman <coleman.ian@gmail.com>2016-11-17 14:36:12 +1100
committerIan Coleman <coleman.ian@gmail.com>2016-11-17 14:36:12 +1100
commit9e97eb7684bf2c2d9c5276561f29fe50caf31f82 (patch)
tree961abe6b656d14d75233b8382fb794745393877a /bip39-standalone.html
parentb0c07d72e78a07ec08d40b51fd9688893c8354ee (diff)
downloadBIP39-9e97eb7684bf2c2d9c5276561f29fe50caf31f82.tar.gz
BIP39-9e97eb7684bf2c2d9c5276561f29fe50caf31f82.tar.zst
BIP39-9e97eb7684bf2c2d9c5276561f29fe50caf31f82.zip
Card entropy corrections compiled into standalone
Diffstat (limited to 'bip39-standalone.html')
-rw-r--r--bip39-standalone.html128
1 files 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
17940 * dice 6 [1-6] 17940 * dice 6 [1-6]
17941 * decimal [0-9] 17941 * decimal [0-9]
17942 * hexadecimal [0-9A-F] 17942 * hexadecimal [0-9A-F]
17943 * card [A2-9TJQK][CDHS]
17943 * 17944 *
17944 * Automatically uses lowest entropy to avoid issues such as interpretting 0101 17945 * Automatically uses lowest entropy to avoid issues such as interpretting 0101
17945 * as hexadecimal which would be 16 bits when really it's only 4 bits of binary 17946 * as hexadecimal which would be 16 bits when really it's only 4 bits of binary
@@ -18050,6 +18051,40 @@ window.Entropy = new (function() {
18050 while (entropyBin.length < expectedBits) { 18051 while (entropyBin.length < expectedBits) {
18051 entropyBin = "0" + entropyBin; 18052 entropyBin = "0" + entropyBin;
18052 } 18053 }
18054 // Assume cards are NOT replaced.
18055 // Additional entropy decreases as more cards are used. This means
18056 // total possible entropy is measured using n!, not base^n.
18057 // eg the second last card can be only one of two, not one of fifty two
18058 // so the added entropy for that card is only one bit at most
18059 if (base.asInt == 52) {
18060 // Get the maximum value WITHOUT replacement
18061 var totalDecks = Math.ceil(base.parts.length / 52);
18062 var totalCards = totalDecks * 52;
18063 var totalCombos = factorial(52).pow(totalDecks);
18064 var totalRemainingCards = totalCards - base.parts.length;
18065 var remainingDecks = Math.floor(totalRemainingCards / 52);
18066 var remainingCards = totalRemainingCards % 52;
18067 var remainingCombos = factorial(52).pow(remainingDecks).multiply(factorial(remainingCards));
18068 var currentCombos = totalCombos.divide(remainingCombos);
18069 var numberOfBits = Math.log2(currentCombos);
18070 var maxWithoutReplace = BigInteger.pow(2, numberOfBits);
18071 // aggresive flooring of numberOfBits by BigInteger.pow means a
18072 // more accurate result can be had for small numbers using the
18073 // built-in Math.pow function.
18074 if (numberOfBits < 32) {
18075 maxWithoutReplace = BigInteger(Math.round(Math.pow(2, numberOfBits)));
18076 }
18077 // Get the maximum value WITH replacement
18078 var maxWithReplace = BigInteger.pow(52, base.parts.length);
18079 // Calculate the new value by scaling the original value down
18080 var withoutReplace = entropyInt.multiply(maxWithoutReplace).divide(maxWithReplace);
18081 // Left pad with zeros based on number of bits
18082 var entropyBin = withoutReplace.toString(2);
18083 var numberOfBitsInt = Math.floor(numberOfBits);
18084 while (entropyBin.length < numberOfBitsInt) {
18085 entropyBin = "0" + entropyBin;
18086 }
18087 }
18053 // Supply a 'filtered' entropy string for display purposes 18088 // Supply a 'filtered' entropy string for display purposes
18054 var entropyClean = base.parts.join(""); 18089 var entropyClean = base.parts.join("");
18055 var entropyHtml = base.parts.join(""); 18090 var entropyHtml = base.parts.join("");
@@ -18065,6 +18100,7 @@ window.Entropy = new (function() {
18065 entropyHtml = entropyHtml.replace(/H/g, "<span class='card-suit heart'>\u2665</span>"); 18100 entropyHtml = entropyHtml.replace(/H/g, "<span class='card-suit heart'>\u2665</span>");
18066 entropyHtml = entropyHtml.replace(/S/g, "<span class='card-suit spade'>\u2660</span>"); 18101 entropyHtml = entropyHtml.replace(/S/g, "<span class='card-suit spade'>\u2660</span>");
18067 } 18102 }
18103 // Return the result
18068 var e = { 18104 var e = {
18069 binaryStr: entropyBin, 18105 binaryStr: entropyBin,
18070 cleanStr: entropyClean, 18106 cleanStr: entropyClean,
@@ -18154,6 +18190,18 @@ window.Entropy = new (function() {
18154 return BigInteger.log(x) / BigInteger.log(2); 18190 return BigInteger.log(x) / BigInteger.log(2);
18155 }; 18191 };
18156 18192
18193 // Depends on BigInteger
18194 function factorial(n) {
18195 if (n == 0) {
18196 return 1;
18197 }
18198 f = BigInteger.ONE;
18199 for (var i=1; i<=n; i++) {
18200 f = f.multiply(new BigInteger(i));
18201 }
18202 return f;
18203 }
18204
18157})(); 18205})();
18158</script> 18206</script>
18159 <script>(function() { 18207 <script>(function() {
@@ -18949,20 +18997,21 @@ window.Entropy = new (function() {
18949 } 18997 }
18950 18998
18951 function showEntropyFeedback(entropy) { 18999 function showEntropyFeedback(entropy) {
19000 var numberOfBits = entropy.binaryStr.length;
18952 var strength = "extremely weak"; 19001 var strength = "extremely weak";
18953 if (entropy.binaryStr.length >= 64) { 19002 if (numberOfBits >= 64) {
18954 strength = "very weak"; 19003 strength = "very weak";
18955 } 19004 }
18956 if (entropy.binaryStr.length >= 96) { 19005 if (numberOfBits >= 96) {
18957 strength = "weak"; 19006 strength = "weak";
18958 } 19007 }
18959 if (entropy.binaryStr.length >= 128) { 19008 if (numberOfBits >= 128) {
18960 strength = "strong"; 19009 strength = "strong";
18961 } 19010 }
18962 if (entropy.binaryStr.length >= 160) { 19011 if (numberOfBits >= 160) {
18963 strength = "very strong"; 19012 strength = "very strong";
18964 } 19013 }
18965 if (entropy.binaryStr.length >= 192) { 19014 if (numberOfBits >= 192) {
18966 strength = "extremely strong"; 19015 strength = "extremely strong";
18967 } 19016 }
18968 // If time to crack is less than one day, and password is considered 19017 // If time to crack is less than one day, and password is considered
@@ -18983,38 +19032,20 @@ window.Entropy = new (function() {
18983 console.log("Error detecting entropy strength with zxcvbn:"); 19032 console.log("Error detecting entropy strength with zxcvbn:");
18984 console.log(e); 19033 console.log(e);
18985 } 19034 }
18986 var bitsStr = getNumberOfEntropyBits(entropy);
18987 var wordCount = Math.floor(entropy.binaryStr.length / 32) * 3;
18988 var entropyTypeStr = getEntropyTypeStr(entropy); 19035 var entropyTypeStr = getEntropyTypeStr(entropy);
19036 var wordCount = Math.floor(numberOfBits / 32) * 3;
19037 var bitsPerEvent = Math.log2(entropy.base.asInt).toFixed(2);
19038 if (entropy.base.asInt == 52) {
19039 bitsPerEvent = bitsPerEvent + " (or less)";
19040 }
18989 DOM.entropyFiltered.html(entropy.cleanHtml); 19041 DOM.entropyFiltered.html(entropy.cleanHtml);
18990 DOM.entropyType.text(entropyTypeStr); 19042 DOM.entropyType.text(entropyTypeStr);
18991 DOM.entropyStrength.text(strength); 19043 DOM.entropyStrength.text(strength);
18992 DOM.entropyEventCount.text(entropy.base.ints.length); 19044 DOM.entropyEventCount.text(entropy.base.ints.length);
18993 DOM.entropyBits.text(bitsStr); 19045 DOM.entropyBits.text(numberOfBits);
18994 DOM.entropyWordCount.text(wordCount); 19046 DOM.entropyWordCount.text(wordCount);
18995 DOM.entropyBinary.text(entropy.binaryStr); 19047 DOM.entropyBinary.text(entropy.binaryStr);
18996 DOM.entropyBitsPerEvent.text(Math.log2(entropy.base.asInt).toFixed(2)); 19048 DOM.entropyBitsPerEvent.text(bitsPerEvent);
18997 }
18998
18999 function getNumberOfEntropyBits(entropy) {
19000 var bitsStr = entropy.binaryStr.length.toString();
19001 // If using cards, assume they are not reused, thus additional entropy
19002 // decreases as more cards are used. This means entropy is measured
19003 // using n!, not base^n.
19004 // eg the second last card can be only one of two, not one of fifty two
19005 // so the added entropy for that card is only one bit at most
19006 if (entropy.base.asInt == 52) {
19007 var totalDecks = Math.ceil(entropy.base.parts.length / 52);
19008 var totalCards = totalDecks * 52;
19009 var totalCombos = factorial(52).pow(totalDecks);
19010 var totalRemainingCards = totalCards - entropy.base.parts.length;
19011 var remainingDecks = Math.floor(totalRemainingCards / 52);
19012 var remainingCards = totalRemainingCards % 52;
19013 var remainingCombos = factorial(52).pow(remainingDecks) * factorial(remainingCards);
19014 var currentCombos = totalCombos.divide(remainingCombos);
19015 bitsStr = currentCombos.toString(2).length.toString();
19016 }
19017 return bitsStr
19018 } 19049 }
19019 19050
19020 function getEntropyTypeStr(entropy) { 19051 function getEntropyTypeStr(entropy) {
@@ -19027,10 +19058,11 @@ window.Entropy = new (function() {
19027 var dupeTracker = {}; 19058 var dupeTracker = {};
19028 for (var i=0; i<entropy.base.parts.length; i++) { 19059 for (var i=0; i<entropy.base.parts.length; i++) {
19029 var card = entropy.base.parts[i]; 19060 var card = entropy.base.parts[i];
19030 if (card in dupeTracker) { 19061 var cardUpper = card.toUpperCase();
19062 if (cardUpper in dupeTracker) {
19031 dupes.push(card); 19063 dupes.push(card);
19032 } 19064 }
19033 dupeTracker[card] = true; 19065 dupeTracker[cardUpper] = true;
19034 } 19066 }
19035 if (dupes.length > 0) { 19067 if (dupes.length > 0) {
19036 var dupeWord = "duplicates"; 19068 var dupeWord = "duplicates";
@@ -19051,6 +19083,26 @@ window.Entropy = new (function() {
19051 if (uniqueCards.length == 52) { 19083 if (uniqueCards.length == 52) {
19052 cardDetail.unshift("full deck"); 19084 cardDetail.unshift("full deck");
19053 } 19085 }
19086 // Detect missing cards
19087 var values = "A23456789TJQK";
19088 var suits = "CDHS";
19089 var missingCards = [];
19090 for (var i=0; i<suits.length; i++) {
19091 for (var j=0; j<values.length; j++) {
19092 var card = values[j] + suits[i];
19093 if (!(card in dupeTracker)) {
19094 missingCards.push(card);
19095 }
19096 }
19097 }
19098 // Display missing cards if six or less, ie clearly going for full deck
19099 if (missingCards.length > 0 && missingCards.length <= 6) {
19100 var msg = missingCards.length + " missing: " + missingCards.slice(0,3).join(" ");
19101 if (missingCards.length > 3) {
19102 msg += "...";
19103 }
19104 cardDetail.push(msg);
19105 }
19054 // Add card details to typeStr 19106 // Add card details to typeStr
19055 if (cardDetail.length > 0) { 19107 if (cardDetail.length > 0) {
19056 typeStr += " (" + cardDetail.join(", ") + ")"; 19108 typeStr += " (" + cardDetail.join(", ") + ")";
@@ -19059,18 +19111,6 @@ window.Entropy = new (function() {
19059 return typeStr; 19111 return typeStr;
19060 } 19112 }
19061 19113
19062 // Depends on BigInteger
19063 function factorial(n) {
19064 if (n == 0) {
19065 return 1;
19066 }
19067 f = BigInteger.ONE;
19068 for (var i=1; i<=n; i++) {
19069 f = f.multiply(new BigInteger(i));
19070 }
19071 return f;
19072 }
19073
19074 var networks = [ 19114 var networks = [
19075 { 19115 {
19076 name: "Bitcoin", 19116 name: "Bitcoin",