Last active
August 29, 2015 14:19
-
-
Save wizardofozzie/0b85c1c64bbd430e11ef to your computer and use it in GitHub Desktop.
BIP39 code
This file contains 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
#!/usr/bin/python | |
import binascii, re, json, copy, sys | |
from binascii import hexlify, unhexlify | |
from bitcoin.main import * | |
# SEE https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki | |
# https://gist.github.com/simcity4242/0b85c1c64bbd430e11ef/edit | |
def bip39_seed_to_mnemonic(hexseed): | |
""">>>bip39_seed_to_mnemonic('eaebabb2383351fd31d703840b32e9e2') | |
'turtle front uncle idea crush write shrug there lottery flower risk shell'""" | |
if isinstance(hexseed, string_types) and re.match('^[0-9a-fA-F]*$', hexseed): | |
hexseed = from_string_to_bytes(str(hexseed)) | |
else: | |
raise TypeError("Enter a hex seed!") | |
hexseed = unhexlify(str(hexseed)) | |
if len(hexseed) % 4: | |
raise Exception("Seed not a multiple of 4 bytes!") | |
elif len(hexseed) < 4: | |
raise Exception("Seed must be at least 32 bits of entropy") | |
elif len(hexseed) > 124: | |
raise Exception("Seed cannot exceed 992 bits of entropy") | |
checksum_length = int((len(hexseed) * 8) // 32) | |
checksum = sha256(hexseed) | |
hexbin = changebase( hexlify(hexseed), 16, 2, len(hexseed)*8) | |
checksum_bin = changebase( checksum, 16, 2, len(unhexlify(checksum))*8) | |
binstr_final = from_string_to_bytes(str(hexbin) + str(checksum_bin)[:checksum_length]) | |
binlist_words = [binstr_final[i:i+11] for i in range(0,len(binstr_final),11)] | |
return " ".join( [BIP0039_ENG_WORDLIST[int(x,2)] for x in binlist_words ] ) | |
def bip39_mnemonic_to_seed(mnemonic): | |
""">>>bip39_mnemonic_to_seed('board flee heavy tunnel powder denial science ski answer betray cargo cat') | |
'18ab19a9f54a9274f03e5209a2ac8a91'""" | |
if isinstance(mnemonic, string_types): | |
mnemonic = str(from_string_to_bytes(mnemonic)).lower().strip() | |
elif isinstance(mnemonic, list): | |
mnemonic = " ".join(str(from_string_to_bytes(mnemonic))).lower() | |
else: | |
raise TypeError("Enter a lower case, single-spaced mnemonic!") | |
try: | |
mnemonic_array = str(mnemonic).split(" ") | |
if mnemonic_array[0] is '': mnemonic_array.pop(0) | |
except: | |
raise TypeError("Enter a lower case, single-spaced mnemonic!") | |
if not (93 > len(mnemonic_array) > 3): | |
raise TypeError("32 < entropy < 992 bits; Input too big or too small") | |
if len(mnemonic_array) % 3: | |
raise TypeError("Too many or too few words") | |
assert all(map(lambda x: x in BIP0039_ENG_WORDLIST, mnemonic_array)) | |
binstr = ''.join([ changebase(str(BIP0039_ENG_WORDLIST.index(x)), 10, 2, 11) for x in mnemonic_array]) | |
num_checksum_digits = len(binstr) % 32 | |
binary_checksum = binstr[(len(binstr) - num_checksum_digits):] | |
binary_no_checksum = binstr[ : (-1*num_checksum_digits)] | |
hexoutput = hexlify(changebase(binary_no_checksum, 2, 16, len(binary_checksum) * 8)) | |
assert not (len(hexoutput) % 2) | |
checksum_bin = changebase(sha256(unhexlify(hexoutput)), 16, 2, 256) | |
assert checksum_bin[:num_checksum_digits] != binary_checksum | |
return unhexlify(hexoutput) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment