Last active
February 18, 2021 01:40
-
-
Save atoponce/de92adafbde810eb9d3f63a217885ab4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset='utf-8'></meta> | |
<title>Lehmer Code</title> | |
<style> | |
input[type=text] { | |
font-family: monospace; | |
width: 450px; | |
} | |
</style> | |
</head> | |
<body> | |
<label for='chars'>Characters (A-Z):</label> | |
<br/> | |
<input type='text' id='chars' name='chars' /> | |
<br/> | |
<label for='faces'>Digits (1-6):</label> | |
<br/> | |
<input type='text' id='faces' name='faces' /> | |
<br/> | |
<label for='orien'>Orientations (1-4):</label> | |
<br/> | |
<input type='text' id='orien' name='orien' /> | |
<br/> | |
<input type='submit' value='Submit' onclick='buildHex()'/> | |
<br/> | |
<br/> | |
<label for='result'>Result:</label> | |
<br/> | |
<input readonly type='text' id='result' name='result' /> | |
<br/> | |
<p>Give this result to <a href='https://github.com/diracdeltas/niceware'>Niceware</a> for a fun 192-bit 12-word passphrase.</a> | |
<script> | |
function factorial(n) { | |
let result = BigInt(1) | |
while (n > 0) { | |
result *= BigInt(n) | |
n-- | |
} | |
return result | |
} | |
function calculateLehmer(chars) { | |
const arr = chars.split('') | |
let lehmer = [] | |
let counter = 0 | |
let result = BigInt(0) | |
for (let i = 0; i < arr.length; i++) { | |
for (let j = i + 1; j < arr.length; j++) { | |
if (arr[i] > arr[j]) counter++ | |
} | |
lehmer[i] = counter | |
counter = 0 | |
} | |
counter = lehmer.length | |
for (let i = 0; i < lehmer.length; i++) { | |
counter-- | |
result += (BigInt(lehmer[i]) * factorial(counter)) | |
} | |
return result | |
} | |
function calculateDecimal(outcome, possible) { | |
const arr = outcome.split('') | |
let counter = arr.length | |
let result = BigInt(0) | |
for (let i = 0; i < arr.length; i++) { | |
counter-- | |
result += BigInt((arr[i] % possible) * possible**counter) | |
} | |
return result | |
} | |
function buildHex() { | |
const result = document.getElementById('result') | |
// The three DiceKeys inputs | |
const chars = document.getElementById('chars').value | |
const faces = document.getElementById('faces').value | |
const orien = document.getElementById('orien').value | |
// The calculated results of each set | |
const charsDec = calculateLehmer(chars) | |
const facesDec = calculateDecimal(faces, 6) | |
const orienDec = calculateDecimal(orien, 4) | |
// The maxes each set can be | |
const charsMax = BigInt(factorial(25)) - 1n | |
const facesMax = BigInt(6**25) - 1n | |
const orienMax = BigInt(4**25) - 1n | |
// The calculated ID of that specific DiceKeys toss | |
let permutation = (orienDec * facesMax * charsMax) + (facesDec * charsMax) + charsDec | |
// We must keep a uniform distribution. Some tosses must be discarded. | |
// 2^198 is about 80% of 2^198.30557612690..., so we lose ~20% tosses. | |
if (permutation >= BigInt(2**198)) { | |
result.value = 'Result will be biased. Reroll.' | |
result.style.color = 'red' | |
} | |
else { | |
permutation = permutation & (BigInt(2**192) - 1n) | |
const hex = permutation.toString(16).padStart(48, '0') | |
result.value = hex | |
result.style.color = 'black' | |
} | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment