aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/js/entropy.js76
1 files changed, 55 insertions, 21 deletions
diff --git a/src/js/entropy.js b/src/js/entropy.js
index 1e556ce..5b687d8 100644
--- a/src/js/entropy.js
+++ b/src/js/entropy.js
@@ -1,11 +1,41 @@
1/*
2 * Detects entropy from a string.
3 *
4 * Formats include:
5 * binary [0-1]
6 * base 6 [0-5]
7 * dice 6 [1-6]
8 * decimal [0-9]
9 * hexadecimal [0-9A-F]
10 *
11 * Automatically uses lowest entropy to avoid issues such as interpretting 0101
12 * as hexadecimal which would be 16 bits when really it's only 4 bits of binary
13 * entropy.
14 */
15
1window.Entropy = new (function() { 16window.Entropy = new (function() {
2 17
18 // matchers returns an array of the matched events for each type of entropy.
19 // eg
20 // matchers.binary("010") returns ["0", "1", "0"]
21 // matchers.binary("a10") returns ["1", "0"]
22 // matchers.hex("a10") returns ["a", "1", "0"]
3 var matchers = { 23 var matchers = {
4 binary: /[0-1]/gi, 24 binary: function(str) {
5 base6: /[0-5]/gi, 25 return str.match(/[0-1]/gi) || [];
6 dice: /[1-6]/gi, // ie dice numbers 26 },
7 base10: /[0-9]/gi, 27 base6: function(str) {
8 hex: /[0-9A-F]/gi, 28 return str.match(/[0-5]/gi) || [];
29 },
30 dice: function(str) {
31 return str.match(/[1-6]/gi) || []; // ie dice numbers
32 },
33 base10: function(str) {
34 return str.match(/[0-9]/gi) || [];
35 },
36 hex: function(str) {
37 return str.match(/[0-9A-F]/gi) || [];
38 },
9 } 39 }
10 40
11 this.fromString = function(rawEntropyStr) { 41 this.fromString = function(rawEntropyStr) {
@@ -25,12 +55,11 @@ window.Entropy = new (function() {
25 } 55 }
26 rawEntropyStr = newRawEntropyStr; 56 rawEntropyStr = newRawEntropyStr;
27 base.str = "base 6 (dice)"; 57 base.str = "base 6 (dice)";
58 base.parts = matchers.base6(rawEntropyStr);
28 base.matcher = matchers.base6; 59 base.matcher = matchers.base6;
29 } 60 }
30 var entropyParts = rawEntropyStr.match(base.matcher) || [];
31 var entropyStr = entropyParts.join("");
32 // Detect empty entropy 61 // Detect empty entropy
33 if (entropyStr.length == 0) { 62 if (base.parts.length == 0) {
34 return { 63 return {
35 binaryStr: "", 64 binaryStr: "",
36 hexStr: "", 65 hexStr: "",
@@ -39,10 +68,10 @@ window.Entropy = new (function() {
39 }; 68 };
40 } 69 }
41 // Pull leading zeros off 70 // Pull leading zeros off
42 var leadingZeros = ""; 71 var leadingZeros = [];
43 while (entropyStr[0] == "0") { 72 while (base.parts[0] == "0") {
44 leadingZeros += "0"; 73 leadingZeros.push("0");
45 entropyStr = entropyStr.substring(1); 74 base.parts.shift();
46 } 75 }
47 // Convert leading zeros to binary equivalent 76 // Convert leading zeros to binary equivalent
48 var numBinLeadingZeros = Math.ceil(Math.log2(base.asInt) * leadingZeros.length); 77 var numBinLeadingZeros = Math.ceil(Math.log2(base.asInt) * leadingZeros.length);
@@ -57,7 +86,7 @@ window.Entropy = new (function() {
57 hexLeadingZeros += "0"; 86 hexLeadingZeros += "0";
58 } 87 }
59 // Handle entropy of zero 88 // Handle entropy of zero
60 if (entropyStr == "") { 89 if (base.parts.length == 0) {
61 return { 90 return {
62 binaryStr: binLeadingZeros, 91 binaryStr: binLeadingZeros,
63 hexStr: hexLeadingZeros || "0", 92 hexStr: hexLeadingZeros || "0",
@@ -69,7 +98,7 @@ window.Entropy = new (function() {
69 // out of sync if first number has leading 0 bits, eg 2 in hex is 0010 98 // out of sync if first number has leading 0 bits, eg 2 in hex is 0010
70 // which would show up as 10, thus missing 2 bits it should have. 99 // which would show up as 10, thus missing 2 bits it should have.
71 if (base.asInt == 16) { 100 if (base.asInt == 16) {
72 var firstDigit = parseInt(entropyStr[0], 16); 101 var firstDigit = parseInt(base.parts[0], 16);
73 if (firstDigit >= 4 && firstDigit < 8) { 102 if (firstDigit >= 4 && firstDigit < 8) {
74 binLeadingZeros += "0"; 103 binLeadingZeros += "0";
75 } 104 }
@@ -81,10 +110,10 @@ window.Entropy = new (function() {
81 } 110 }
82 } 111 }
83 // Convert entropy to different foramts 112 // Convert entropy to different foramts
84 var entropyInt = BigInteger.parse(entropyStr, base.asInt); 113 var entropyInt = BigInteger.parse(base.parts.join(""), base.asInt);
85 var entropyBin = binLeadingZeros + entropyInt.toString(2); 114 var entropyBin = binLeadingZeros + entropyInt.toString(2);
86 var entropyHex = hexLeadingZeros + entropyInt.toString(16); 115 var entropyHex = hexLeadingZeros + entropyInt.toString(16);
87 var entropyClean = leadingZeros + entropyStr; 116 var entropyClean = leadingZeros.join("") + base.parts.join("");
88 var e = { 117 var e = {
89 binaryStr: entropyBin, 118 binaryStr: entropyBin,
90 hexStr: entropyHex, 119 hexStr: entropyHex,
@@ -97,41 +126,46 @@ window.Entropy = new (function() {
97 function getBase(str) { 126 function getBase(str) {
98 // Need to get the lowest base for the supplied entropy. 127 // Need to get the lowest base for the supplied entropy.
99 // This prevents interpreting, say, dice rolls as hexadecimal. 128 // This prevents interpreting, say, dice rolls as hexadecimal.
100 var binaryMatches = str.match(matchers.binary) || []; 129 var binaryMatches = matchers.binary(str);
101 var base6Matches = str.match(matchers.base6) || []; 130 var hexMatches = matchers.hex(str);
102 var diceMatches = str.match(matchers.dice) || [];
103 var base10Matches = str.match(matchers.base10) || [];
104 var hexMatches = str.match(matchers.hex) || [];
105 // Find the lowest base that can be used, whilst ignoring any irrelevant chars 131 // Find the lowest base that can be used, whilst ignoring any irrelevant chars
106 if (binaryMatches.length == hexMatches.length) { 132 if (binaryMatches.length == hexMatches.length) {
107 return { 133 return {
134 parts: binaryMatches,
108 matcher: matchers.binary, 135 matcher: matchers.binary,
109 asInt: 2, 136 asInt: 2,
110 str: "binary", 137 str: "binary",
111 } 138 }
112 } 139 }
140 var diceMatches = matchers.dice(str);
113 if (diceMatches.length == hexMatches.length) { 141 if (diceMatches.length == hexMatches.length) {
114 return { 142 return {
143 parts: diceMatches,
115 matcher: matchers.dice, 144 matcher: matchers.dice,
116 asInt: 6, 145 asInt: 6,
117 str: "dice", 146 str: "dice",
118 } 147 }
119 } 148 }
149 var base6Matches = matchers.base6(str);
120 if (base6Matches.length == hexMatches.length) { 150 if (base6Matches.length == hexMatches.length) {
121 return { 151 return {
152 parts: base6Matches,
122 matcher: matchers.base6, 153 matcher: matchers.base6,
123 asInt: 6, 154 asInt: 6,
124 str: "base 6", 155 str: "base 6",
125 } 156 }
126 } 157 }
158 var base10Matches = matchers.base10(str);
127 if (base10Matches.length == hexMatches.length) { 159 if (base10Matches.length == hexMatches.length) {
128 return { 160 return {
161 parts: base10Matches,
129 matcher: matchers.base10, 162 matcher: matchers.base10,
130 asInt: 10, 163 asInt: 10,
131 str: "base 10", 164 str: "base 10",
132 } 165 }
133 } 166 }
134 return { 167 return {
168 parts: hexMatches,
135 matcher: matchers.hex, 169 matcher: matchers.hex,
136 asInt: 16, 170 asInt: 16,
137 str: "hexadecimal", 171 str: "hexadecimal",