Skip to content

Instantly share code, notes, and snippets.

@lord-max
Last active January 24, 2023 21:00
Show Gist options
  • Save lord-max/74190d1a211720671e68d4789227b43f to your computer and use it in GitHub Desktop.
Save lord-max/74190d1a211720671e68d4789227b43f to your computer and use it in GitHub Desktop.
When generating BIP39 seed by hand, you will need this script to fix last 4 bits (12th word) with a correct checksum.
// We expect array of 12 words as human readable indexes (1-2048)
function checksum_12_words(data) {
if (data.length != 12) return console.log("ERROR: Need 12 words numbers as input")
let binstr = (s,l =8) => s.toString(2).padStart(l,'0') // convert to binary `0011...` string
let tohex = (bytes) => bytes.map( x => x.toString(16).padStart(2,0) ).join('')
let bytes = data.map( x => binstr(x - 1, 11)) // convert to 0-index, then to binary `0011...`
.join('').match(/.{1,8}/g) // split 8 bits
.map( x => parseInt(x, 2)) // convert to UInt8
// Now we got 17 UInt8 bytes. Last 4 bits (the 17th byte) are wrong and need to be fixed
if (bytes.length != 17) return console.log("ERROR: Something is wrong, check your input")
bytes.pop() // remove wrong 17th byte of checksum
// You can comment out next line if you dont want to print the entropy
console.log("Entropy is :",tohex(bytes))
// This function works only if your browser is pointing to TLS website or
// on Firefox and Safari you can use http://localhost/. On Chrome you can
// use raw view of any gist since it has no running scripts: https://bit.ly/2YJILYN
window.crypto.subtle.digest("SHA-256", new Uint8Array(bytes).buffer).then( x => {
if (x.byteLength != 32) return console.log("ERROR: Wrong SHA256")
let hash = new Uint8Array(x)
let cs = binstr(hash[0]).match(/.{1,4}/g)[0] // Thats our checksum
// Take byte 15 for first 7 bits our final word and we add checksum bits
let bits = [binstr(bytes[15]),cs].join('')
if (bits.length != 12) return console.log("ERROR: Wrong final word bits")
//console.log(bits)
console.log("Your 12th word index is: " + (1+parseInt(bits.substr(1),2)))
})
return "OK"
}
// Test vector of human readable 1-index words: arrive, dirt, join, ...
// https://vault12.s3-us-west-1.amazonaws.com/bip39-words.pdf
// Try your own!
data = [101, 502, 962, 1400, 1607, 1817, 1090, 1827, 820, 1334, 156, 1073]
checksum_12_words(data)
// Entropy is : 0c87d5e0d77c8dc6220f226674d44dc3
// "OK"
// Your 12th word index is: 1078
// This is human readable 1-index of word `mammal`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment