- // 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 entropy to binary
- var entropyBin = entropyInt.toString(2);
- // If the first integer is small, it must be padded with zeros.
- // Otherwise the chance of the first bit being 1 is 100%, which is
- // obviously incorrect.
- // This is not perfect for non-2^n bases.
- var expectedBits = Math.floor(base.parts.length * Math.log2(base.asInt));
- while (entropyBin.length < expectedBits) {
- entropyBin = "0" + entropyBin;
- }
- // Assume cards are NOT replaced.
- // Additional entropy decreases as more cards are used. This means
- // 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;
- }
- }