Skip to content

Instantly share code, notes, and snippets.

@ckhung
Last active January 26, 2022 10:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ckhung/dadda37930068227e4b11825869c30d6 to your computer and use it in GitHub Desktop.
Save ckhung/dadda37930068227e4b11825869c30d6 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
# https://medium.com/mycrypto/the-journey-from-mnemonic-phrase-to-address-6c5e86e11e14
# pip3 install bip_utils
# python3 bip_demo.py
# For the 1st example, private key and address of path0
# have been verified using exodus wallet.
# For the 2nd example, the computed master key does not match the article...?
# If you have a private key stored in a file named priv_key_file.txt
# this program will also create a derived pair of keys from it
# as a 3rd example.
# DO NOT use the addresses generated from this sample comination
# of phrases to store your coins!
# import argparse
from bip_utils import (
Bip39Mnemonic, Bip39MnemonicDecoder, Bip39MnemonicEncoder,
Bip39Languages, Bip39SeedGenerator, Bip32Secp256k1, EthAddr
)
def print_master(master):
print(f'master: {master.PrivateKey().Raw().ToHex()}')
priv_key = master.PrivateKey().KeyObject()
print(f'private: {priv_key.Raw().ToHex()}')
print(f'public: {master.PrivateKey().PublicKey().ToExtended()}')
print(f'public: {master.PublicKey().ToExtended()}') # same as above
master2 = Bip32Secp256k1.FromPrivateKey(priv_key)
print(f'master2: {master2.PrivateKey().Raw().ToHex()}') # same as original master key
print('')
def path_demo(parent, path):
print(f'path: {path}')
pathobj = parent.DerivePath(path)
print(type(pathobj))
print(f'private: {pathobj.PrivateKey().Raw().ToHex()}')
eth_pubkey = pathobj.PrivateKey().PublicKey().KeyObject()
print(f'public: {eth_pubkey.RawCompressed().ToHex()}')
eth_pubkey = pathobj.PublicKey().KeyObject()
print(f'public: {eth_pubkey.RawCompressed().ToHex()}') # same as above
eth_addr = EthAddr.EncodeKey(eth_pubkey)
print(f'addr: {eth_addr}')
msg = b'pay 0.01 eth to some addr'
# print(type(pathobj.PrivateKey()))
sig = pathobj.PrivateKey().KeyObject().UnderlyingObject().sign(msg)
# print(type(sig))
print(f'sig: {sig.hex()}')
verify = eth_pubkey.UnderlyingObject().verify(sig, msg)
print(f'verify: {verify}')
fakesig = bytearray(sig)
fakesig[-1] = (fakesig[-1]+1)%256
fakesig = bytes(fakesig)
print(f'fakesig: {fakesig.hex()}')
verify = eth_pubkey.UnderlyingObject().verify(fakesig, msg)
print(f'fakevfy: {verify}')
print()
# parser = argparse.ArgumentParser(
# description='generate information from 12 phrase mnemonic',
# formatter_class=argparse.ArgumentDefaultsHelpFormatter)
# parser.add_argument('phrases', nargs='*', help='hello world ...')
# args = parser.parse_args()
sep_string = '=' * 10
print(f'\n{sep_string} "Journey" article, Part 1 {sep_string}\n')
phrases = 'wild quiz always market robust board \
acid enough twist divert margin route'
mns_eng = Bip39Mnemonic(phrases.split())
entropy = Bip39MnemonicDecoder(Bip39Languages.ENGLISH).Decode(mns_eng)
print(f'mne(eng): {mns_eng}')
print(f'entropy: {entropy.hex()}')
mns_cht = Bip39MnemonicEncoder(Bip39Languages.CHINESE_TRADITIONAL).Encode(entropy)
entropy = Bip39MnemonicDecoder(Bip39Languages.CHINESE_TRADITIONAL).Decode(mns_cht)
print(f'mne(cht): {mns_cht}')
print(f'entropy: {entropy.hex()}')
seed = Bip39SeedGenerator(mns_eng).Generate()
print(f'seed: {seed.hex()} [<= we will use this]')
seed_cht = Bip39SeedGenerator(mns_cht, Bip39Languages.CHINESE_TRADITIONAL).Generate()
print(f'seed_cht: {seed_cht.hex()} [discarded]')
print(f'[ seed gen. is lang-dependent! https://bitcoin.stackexchange.com/q/88115 ]')
master = Bip32Secp256k1.FromSeed(seed)
print_master(master)
path0 = "m/44'/60'/0'/0/0"
path_demo(master, path0)
pathobj0 = master.DerivePath(path0)
path_demo(pathobj0, '3')
path_demo(master, path0 + '/3')
print(f'\n{sep_string} "Journey" article, Part 2 {sep_string}\n')
seed = '77cdf1d92225adc0e67b1b4f5a31820251d518b3af074df25a07b751947fd07ebd29a4d0e57b84ea9de03a9123e2a6ea1e3ed739d4c562efec21f1bb0a54a879'
print(f'seed: {seed}')
master = Bip32Secp256k1.FromSeed(bytes.fromhex(seed))
print_master(master)
path_demo(master, path0)
from os import access, R_OK
from os.path import isfile
import binascii
priv_key_file = 'priv_key_file.txt'
if isfile(priv_key_file) and access(priv_key_file, R_OK):
print(f'\n{sep_string} priv key from file: {priv_key_file} {sep_string}\n')
with open(priv_key_file) as F:
priv_key = F.read().rstrip()
priv_key = binascii.unhexlify(priv_key)
master = Bip32Secp256k1.FromPrivateKey(priv_key)
print_master(master)
path0 = "17"
path_demo(master, path0)
# hierarchical deterministic wallet
# dot -Tsvg hdwallet.dot > hdwallet.svg
# The generated hdwallet.svg file was then manually edited using inkscape
digraph "hdwallet" {
rankdir = LR;
overlap = scale;
node [shape=rectangle];
mne [ label="mnemonics (en_US)\nwild ... route" ];
entropy [ label="entropy\nfb15...1fde" ];
mne_cht [ label="mnemonics (zh_TW)\n辨 縫 ... 亦 齡" ];
seed [ label="seed\nfd0e...3dbf" ];
master [ label="master\n329a...8208" ];
entropy -> mne:ne [ label="Bip39MnemonicEncoder()" ];
mne -> entropy:sw [ label="Bip39MnemonicDecoder()" ];
entropy -> mne_cht [ label="Bip39MnemonicEncoder()"; style="dashed" ];
mne_cht:sw -> entropy:se [ label="Bip39MnemonicDecoder()"; style="dashed" ];
mne:se -> seed [ label="Bip39SeedGenerator()"; ];
seed:se -> master:sw [ label="Bip32Secp256k1.FromSeed()" ];
master -> { rank = same; public; private }
private -> { public; master }
public -> address;
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@ckhung
Copy link
Author

ckhung commented Jan 1, 2022

wild-quiz-*-route

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment