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
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: hdwallet Pages: 1 -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1103pt"
height="210pt"
viewBox="0.00 0.00 1103.00 210.00"
version="1.1"
id="svg162"
sodipodi:docname="hdwallet.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata168">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs166">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path1016"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path1004"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker1279"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path1277"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path998"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-7"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1016-5"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1023"
id="namedview164"
showgrid="false"
inkscape:snap-global="false"
inkscape:zoom="0.91523119"
inkscape:cx="735.33333"
inkscape:cy="140"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="edge2" />
<g
id="graph0"
class="graph"
transform="scale(1 1) rotate(0) translate(4 206)">
<title
id="title2">hdwallet</title>
<polygon
stroke="transparent"
points="-4,4 -4,-206 1099,-206 1099,4 -4,4"
id="polygon4"
fill="white" />
<!-- mne -->
<g
id="node1"
class="node">
<title
id="title6">mne</title>
<polygon
points="158,-147 0,-147 0,-109 158,-109 158,-147"
id="polygon8"
stroke="black"
fill="none" />
<text
x="79"
y="-131.8"
font-size="14.00"
id="text10"
text-anchor="middle"
font-family="Times,serif">mnemonics (en_US)</text>
<text
x="79"
y="-116.8"
font-size="14.00"
id="text12"
text-anchor="middle"
font-family="Times,serif">wild ... route</text>
</g>
<!-- entropy -->
<g
id="node2"
class="node">
<title
id="title15">entropy</title>
<polygon
points="475,-176 381,-176 381,-138 475,-138 475,-176"
id="polygon17"
stroke="black"
fill="none" />
<text
x="428"
y="-160.8"
font-size="14.00"
id="text19"
text-anchor="middle"
font-family="Times,serif">entropy</text>
<text
x="428"
y="-145.8"
font-size="14.00"
id="text21"
text-anchor="middle"
font-family="Times,serif">fb15...1fde</text>
</g>
<!-- mne&#45;&gt;entropy -->
<g
id="edge2"
class="edge">
<title
id="title24">mne-&gt;entropy:sw</title>
<path
d="M158.28,-119.06C231.39,-112.52 334.93,-108.37 373.92,-131.82"
id="path26"
stroke="black"
fill="none" />
<polygon
points="371.93,-134.7 382,-138 376.18,-129.14 371.93,-134.7"
id="polygon28"
stroke="black"
fill="black" />
<text
x="262.94427"
y="-121.60535"
font-size="14.00"
id="text30"
style="font-size:14px;font-family:Times, serif;text-anchor:middle">Bip39MnemonicDecoder()</text>
</g>
<!-- seed -->
<g
id="node4"
class="node">
<title
id="title33">seed</title>
<polygon
points="475,-109 381,-109 381,-71 475,-71 475,-109"
id="polygon35"
stroke="black"
fill="none" />
<text
x="428"
y="-93.8"
font-size="14.00"
id="text37"
text-anchor="middle"
font-family="Times,serif">seed</text>
<text
x="428"
y="-78.8"
font-size="14.00"
id="text39"
text-anchor="middle"
font-family="Times,serif">fd0e...3dbf</text>
</g>
<!-- mne&#45;&gt;seed -->
<g
id="edge5"
class="edge">
<title
id="title42">mne:se-&gt;seed</title>
<path
d="M158,-109C165.36,-101.64 166.24,-97.62 176,-94 239.59,-70.4 318.62,-74.02 370.82,-80.48"
id="path44"
stroke="black"
fill="none" />
<polygon
points="370.52,-83.97 380.89,-81.8 371.44,-77.03 370.52,-83.97"
id="polygon46"
stroke="black"
fill="black" />
<text
x="265.40268"
y="-55.187817"
font-size="14.00"
id="text48"
style="font-size:14px;font-family:Times, serif;text-anchor:middle">Bip39SeedGenerator()</text>
</g>
<!-- entropy&#45;&gt;mne -->
<g
id="edge1"
class="edge">
<title
id="title51">entropy-&gt;mne:ne</title>
<path
d="M380.96,-171.92C322.98,-187.64 223.77,-203.82 164.39,-153.79"
id="path53"
stroke="black"
fill="none" />
<polygon
points="166.73,-151.19 157,-147 162,-156.34 166.73,-151.19"
id="polygon55"
stroke="black"
fill="black" />
<text
x="273.59732"
y="-163.75766"
font-size="14.00"
id="text57"
style="font-size:14px;font-family:Times, serif;text-anchor:middle">Bip39MnemonicEncoder()</text>
</g>
<!-- mne_cht -->
<g
id="node3"
class="node">
<title
id="title60">mne_cht</title>
<polygon
points="880,-175 721,-175 721,-137 880,-137 880,-175"
id="polygon62"
stroke="black"
fill="none" />
<text
x="800.5"
y="-159.8"
font-size="14.00"
id="text64"
text-anchor="middle"
font-family="Times,serif">mnemonics (zh_TW)</text>
<text
x="800.5"
y="-144.8"
font-size="14.00"
id="text66"
text-anchor="middle"
font-family="Times,serif">辨 縫 ... 亦 齡</text>
</g>
<!-- entropy&#45;&gt;mne_cht -->
<g
id="edge3"
class="edge"
transform="translate(0,-11.472511)">
<title
id="title69">entropy-&gt;mne_cht</title>
<path
d="m 475.17,-156.88 c 58.74,0.16 161.41,0.44 235.53,0.64"
id="path71"
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-dasharray:5, 2" />
<polygon
points="720.96,-156.21 710.95,-152.74 710.97,-159.74 "
id="polygon73"
style="fill:#000000;stroke:#000000" />
<text
x="598"
y="-159.8"
font-size="14.00"
id="text75"
style="font-size:14px;font-family:Times, serif;text-anchor:middle">Bip39MnemonicEncoder()</text>
</g>
<!-- mne_cht&#45;&gt;entropy -->
<g
id="edge4"
class="edge">
<title
id="title78">mne_cht:sw-&gt;entropy:se</title>
<text
x="598"
y="-132.8"
font-size="14.00"
id="text84"
text-anchor="middle"
font-family="Times,serif">Bip39MnemonicDecoder()</text>
<path
d="m 721.95794,-151.51737 c -58.74,0.16 -161.41,0.44 -235.52999,0.64"
id="path71-3"
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:0.99999994;stroke-dasharray:4.99999994, 1.99999998" />
<polygon
transform="matrix(-1,0,0,1,1197.1279,5.3626241)"
points="720.96,-156.21 710.95,-152.74 710.97,-159.74 "
id="polygon73-6"
style="fill:#000000;stroke:#000000" />
</g>
<!-- master -->
<g
id="node5"
class="node">
<title
id="title87">master</title>
<polygon
points="851,-109 750,-109 750,-71 851,-71 851,-109"
id="polygon89"
stroke="black"
fill="none" />
<text
x="800.5"
y="-93.8"
font-size="14.00"
id="text91"
text-anchor="middle"
font-family="Times,serif">master</text>
<text
x="800.5"
y="-78.8"
font-size="14.00"
id="text93"
text-anchor="middle"
font-family="Times,serif">329a...8208</text>
</g>
<!-- seed&#45;&gt;master -->
<g
id="edge6"
class="edge">
<title
id="title96">seed:se-&gt;master:sw</title>
<text
x="599.63892"
y="-68.911438"
font-size="14.00"
id="text102"
style="font-size:14px;font-family:Times, serif;text-anchor:middle">Bip32Secp256k1.FromSeed()</text>
<path
style="fill:none;stroke:#000000;stroke-width:1.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Lend-7)"
d="M 475.67593,-91.03813 H 748.55784"
id="path993"
inkscape:connector-curvature="0" />
</g>
<!-- public -->
<g
id="node6"
class="node">
<title
id="title105">public</title>
<polygon
points="981,-36 921,-36 921,0 981,0 981,-36"
id="polygon107"
stroke="black"
fill="none" />
<text
x="951"
y="-14.3"
font-size="14.00"
id="text109"
text-anchor="middle"
font-family="Times,serif">public</text>
</g>
<!-- master&#45;&gt;public -->
<g
id="edge7"
class="edge">
<title
id="title112">master-&gt;public</title>
<path
d="M840.91,-70.89C862.76,-60.3 889.83,-47.17 911.53,-36.65"
id="path114"
stroke="black"
fill="none" />
<polygon
points="913.31,-39.68 920.78,-32.17 910.26,-33.38 913.31,-39.68"
id="polygon116"
stroke="black"
fill="black" />
</g>
<!-- private -->
<g
id="node7"
class="node">
<title
id="title119">private</title>
<polygon
points="985,-108 917,-108 917,-72 985,-72 985,-108"
id="polygon121"
stroke="black"
fill="none" />
<text
x="951"
y="-86.3"
font-size="14.00"
id="text123"
text-anchor="middle"
font-family="Times,serif">private</text>
</g>
<!-- master&#45;&gt;private -->
<g
id="edge8"
class="edge">
<title
id="title126">master-&gt;private</title>
<path
d="M851.36,-83.58C869.22,-83.08 889.21,-83.15 906.49,-83.79"
id="path128"
stroke="black"
fill="none" />
<polygon
points="906.71,-87.31 916.86,-84.27 907.03,-80.31 906.71,-87.31"
id="polygon130"
stroke="black"
fill="black" />
</g>
<!-- address -->
<g
id="node8"
class="node">
<title
id="title133">address</title>
<polygon
points="1095,-36 1022,-36 1022,0 1095,0 1095,-36"
id="polygon135"
stroke="black"
fill="none" />
<text
x="1058.5"
y="-14.3"
font-size="14.00"
id="text137"
text-anchor="middle"
font-family="Times,serif">address</text>
</g>
<!-- public&#45;&gt;address -->
<g
id="edge11"
class="edge">
<title
id="title140">public-&gt;address</title>
<path
d="M981.11,-18C990.53,-18 1001.22,-18 1011.56,-18"
id="path142"
stroke="black"
fill="none" />
<polygon
points="1011.72,-21.5 1021.72,-18 1011.72,-14.5 1011.72,-21.5"
id="polygon144"
stroke="black"
fill="black" />
</g>
<!-- private&#45;&gt;master -->
<g
id="edge9"
class="edge">
<title
id="title147">private-&gt;master</title>
<path
d="M916.86,-95.73C900.53,-96.64 880.32,-96.94 861.4,-96.64"
id="path149"
stroke="black"
fill="none" />
<polygon
points="861.44,-93.14 851.36,-96.42 861.28,-100.13 861.44,-93.14"
id="polygon151"
stroke="black"
fill="black" />
</g>
<!-- private&#45;&gt;public -->
<g
id="edge10"
class="edge">
<title
id="title154">private-&gt;public</title>
<path
d="M951,-71.95C951,-63.41 951,-54.86 951,-46.31"
id="path156"
stroke="black"
fill="none" />
<polygon
points="954.5,-46.28 951,-36.28 947.5,-46.28 954.5,-46.28"
id="polygon158"
stroke="black"
fill="black" />
</g>
</g>
</svg>
@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