aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Coleman <coleman.ian@gmail.com>2016-11-25 14:38:19 +1100
committerIan Coleman <coleman.ian@gmail.com>2016-11-25 14:38:19 +1100
commit78b8d6048ab7fc56d2a2b389545f8314ad83e387 (patch)
tree43927f7635350d15e214d9ffe52497951c22316b
parent55b592b498a57465b91bd8402d0d91324cc34cf9 (diff)
downloadBIP39-78b8d6048ab7fc56d2a2b389545f8314ad83e387.tar.gz
BIP39-78b8d6048ab7fc56d2a2b389545f8314ad83e387.tar.zst
BIP39-78b8d6048ab7fc56d2a2b389545f8314ad83e387.zip
Card entropy fixes compiled into standalone
-rw-r--r--bip39-standalone.html98
1 files changed, 85 insertions, 13 deletions
diff --git a/bip39-standalone.html b/bip39-standalone.html
index 8476014..e4c172c 100644
--- a/bip39-standalone.html
+++ b/bip39-standalone.html
@@ -161,7 +161,7 @@
161 <select class="mnemonic-length form-control"> 161 <select class="mnemonic-length form-control">
162 <option value="raw">From entropy length (3 words per 32 bits)</option> 162 <option value="raw">From entropy length (3 words per 32 bits)</option>
163 <option value="12">12 Words</option> 163 <option value="12">12 Words</option>
164 <option value="15">15 Words</option> 164 <option value="15" selected>15 Words</option>
165 <option value="18">18 Words</option> 165 <option value="18">18 Words</option>
166 <option value="21">21 Words</option> 166 <option value="21">21 Words</option>
167 <option value="24">24 Words</option> 167 <option value="24">24 Words</option>
@@ -17949,6 +17949,8 @@ var time_estimates;time_estimates={estimate_attack_times:function(e){var t,n,s,o
17949 17949
17950window.Entropy = new (function() { 17950window.Entropy = new (function() {
17951 17951
17952 var TWO = new BigInteger(2);
17953
17952 // matchers returns an array of the matched events for each type of entropy. 17954 // matchers returns an array of the matched events for each type of entropy.
17953 // eg 17955 // eg
17954 // matchers.binary("010") returns ["0", "1", "0"] 17956 // matchers.binary("010") returns ["0", "1", "0"]
@@ -18057,7 +18059,6 @@ window.Entropy = new (function() {
18057 // eg the second last card can be only one of two, not one of fifty two 18059 // 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 18060 // so the added entropy for that card is only one bit at most
18059 if (base.asInt == 52) { 18061 if (base.asInt == 52) {
18060 // Get the maximum value WITHOUT replacement
18061 var totalDecks = Math.ceil(base.parts.length / 52); 18062 var totalDecks = Math.ceil(base.parts.length / 52);
18062 var totalCards = totalDecks * 52; 18063 var totalCards = totalDecks * 52;
18063 var totalCombos = factorial(52).pow(totalDecks); 18064 var totalCombos = factorial(52).pow(totalDecks);
@@ -18068,18 +18069,77 @@ window.Entropy = new (function() {
18068 var currentCombos = totalCombos.divide(remainingCombos); 18069 var currentCombos = totalCombos.divide(remainingCombos);
18069 var numberOfBits = Math.log2(currentCombos); 18070 var numberOfBits = Math.log2(currentCombos);
18070 var maxWithoutReplace = BigInteger.pow(2, numberOfBits); 18071 var maxWithoutReplace = BigInteger.pow(2, numberOfBits);
18071 // aggresive flooring of numberOfBits by BigInteger.pow means a 18072 // Use a bunch of sorted decks to measure entropy from, populated
18072 // more accurate result can be had for small numbers using the 18073 // as needed.
18073 // built-in Math.pow function. 18074 var sortedDecks = [];
18074 if (numberOfBits < 32) { 18075 // Initialize the final entropy value for these cards
18075 maxWithoutReplace = BigInteger(Math.round(Math.pow(2, numberOfBits))); 18076 var entropyInt = BigInteger.ZERO;
18077 // Track how many instances of each card have been used, and thus
18078 // how many decks are in use.
18079 var cardCounts = {};
18080 // Track the total bits of entropy that remain, which diminishes as
18081 // each card is drawn.
18082 var totalBitsLeft = numberOfBits;
18083 // Work out entropy contribution of each card drawn
18084 for (var i=0; i<base.parts.length; i++) {
18085 // Get the card that was drawn
18086 var cardLower = base.parts[i];
18087 var card = cardLower.toUpperCase();
18088 // Initialize the deck for this card if needed, to track how
18089 // much entropy it adds.
18090 if (!(card in cardCounts)) {
18091 cardCounts[card] = 0;
18092 }
18093 // Get the deck this card is from
18094 var deckIndex = cardCounts[card];
18095 while (deckIndex > sortedDecks.length-1) {
18096 sortedDecks.push(getSortedDeck());
18097 }
18098 // See how many bits this card contributes (depends on how many
18099 // are left in the deck it's from)
18100 var deckForCard = sortedDecks[deckIndex];
18101 var cardsLeftInDeck = deckForCard.length;
18102 var additionalBits = Math.log2(cardsLeftInDeck);
18103 // Work out the min and max value for this card
18104 var nextTotalBitsLeft = totalBitsLeft - additionalBits;
18105 var minPossibleNewEntropy = TWO.pow(nextTotalBitsLeft).subtract(1);
18106 var maxPossibleNewEntropy = TWO.pow(totalBitsLeft).subtract(1);
18107 var diff = maxPossibleNewEntropy.subtract(minPossibleNewEntropy);
18108 // BigInteger aggresively floors numbers which greatly affects
18109 // the small numbers. In that case, use native Math library
18110 var useBigInt = totalBitsLeft >= 32;
18111 if (!useBigInt) {
18112 minPossibleNewEntropy = Math.round(Math.pow(2, nextTotalBitsLeft)-1);
18113 maxPossibleNewEntropy = Math.round(Math.pow(2, totalBitsLeft)-1);
18114 diff = maxPossibleNewEntropy - minPossibleNewEntropy;
18115 }
18116 // Scale the value between possible min and max depending on
18117 // this card value
18118 var thisCardIndex = deckForCard.indexOf(card);
18119 var toAdd = BigInteger.ZERO;
18120 if (cardsLeftInDeck > 1) {
18121 if (useBigInt) {
18122 toAdd = diff.multiply(thisCardIndex)
18123 .divide(deckForCard.length - 1)
18124 .add(minPossibleNewEntropy);
18125 }
18126 else {
18127 var ratio = thisCardIndex / (deckForCard.length -1);
18128 var f = diff * ratio;
18129 toAdd = new BigInteger(f).add(minPossibleNewEntropy);
18130 }
18131 }
18132 // Add this card entropy to existing entropy
18133 entropyInt = entropyInt.add(toAdd);
18134 // Remove this card from the deck it comes from
18135 deckForCard.splice(thisCardIndex,1);
18136 // Ensure the next insance of this card uses the next deck
18137 cardCounts[card] = cardCounts[card] + 1;
18138 // Next card drawn has less total remaining bits to work with
18139 totalBitsLeft = nextTotalBitsLeft;
18076 } 18140 }
18077 // Get the maximum value WITH replacement 18141 // Convert to binary
18078 var maxWithReplace = BigInteger.pow(52, base.parts.length); 18142 var entropyBin = entropyInt.toString(2);
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); 18143 var numberOfBitsInt = Math.floor(numberOfBits);
18084 while (entropyBin.length < numberOfBitsInt) { 18144 while (entropyBin.length < numberOfBitsInt) {
18085 entropyBin = "0" + entropyBin; 18145 entropyBin = "0" + entropyBin;
@@ -18110,6 +18170,18 @@ window.Entropy = new (function() {
18110 return e; 18170 return e;
18111 } 18171 }
18112 18172
18173 function getSortedDeck() {
18174 var s = [];
18175 var suits = "CDHS";
18176 var values = "A23456789TJQK";
18177 for (var i=0; i<suits.length; i++) {
18178 for (var j=0; j<values.length; j++) {
18179 s.push(values[j]+suits[i]);
18180 }
18181 }
18182 return s;
18183 }
18184
18113 function getBase(str) { 18185 function getBase(str) {
18114 // Need to get the lowest base for the supplied entropy. 18186 // Need to get the lowest base for the supplied entropy.
18115 // This prevents interpreting, say, dice rolls as hexadecimal. 18187 // This prevents interpreting, say, dice rolls as hexadecimal.