diff options
author | Ian Coleman <coleman.ian@gmail.com> | 2016-11-25 14:38:19 +1100 |
---|---|---|
committer | Ian Coleman <coleman.ian@gmail.com> | 2016-11-25 14:38:19 +1100 |
commit | 78b8d6048ab7fc56d2a2b389545f8314ad83e387 (patch) | |
tree | 43927f7635350d15e214d9ffe52497951c22316b /bip39-standalone.html | |
parent | 55b592b498a57465b91bd8402d0d91324cc34cf9 (diff) | |
download | BIP39-78b8d6048ab7fc56d2a2b389545f8314ad83e387.tar.gz BIP39-78b8d6048ab7fc56d2a2b389545f8314ad83e387.tar.zst BIP39-78b8d6048ab7fc56d2a2b389545f8314ad83e387.zip |
Card entropy fixes compiled into standalone
Diffstat (limited to 'bip39-standalone.html')
-rw-r--r-- | bip39-standalone.html | 98 |
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 | ||
17950 | window.Entropy = new (function() { | 17950 | window.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. |