.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/wallets/derivation/plot_02_bip39_mnemonic_seed_phrases.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_wallets_derivation_plot_02_bip39_mnemonic_seed_phrases.py: Mnemonic seed phrases (BIP39, 2013) =================================== Marek Palatinus, Pavol Rusnak, Aaron Voisine and Sean Bowe proposed writing a wallet's seed as words. The entropy gets a checksum, the first ENT/32 bits of its SHA-256, and the bits are cut into 11-bit indices into a list of 2048 words, .. math:: \frac{ENT + ENT/32}{11} \text{ words}: \quad 128 \text{ bits} \to 12 \text{ words}. A miscopied word fails the 4-bit checksum of a 12-word phrase 15 times in 16. The phrase is then stretched by PBKDF2-HMAC-SHA512 over 2048 iterations into the 64-byte BIP32 seed, with an optional passphrase that gives every guess a different, valid wallet. The word list here is generated by a rule rather than BIP39's English list; the seed derivation is BIP39's own, and reproduces its test vectors. .. GENERATED FROM PYTHON SOURCE LINES 23-27 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 28-30 Entropy to words to seed ------------------------ .. GENERATED FROM PYTHON SOURCE LINES 30-43 .. code-block:: Python entropy = bytes.fromhex("0c1e24e5917779d297e14d45f14e1a1a") phrase = bk.wallets.entropy_to_mnemonic(entropy) print("phrase:", phrase) assert bk.wallets.mnemonic_to_entropy(phrase) == entropy seed = bk.wallets.mnemonic_to_seed(phrase, "") print("seed:", seed.hex()[:32], "...") master = bk.wallets.master_key(seed) print("master:", bk.wallets.serialize_extended_key(master)[:24], "...") english = " ".join(["abandon"] * 11 + ["about"]) # BIP39's first test vector. assert bk.wallets.mnemonic_to_seed(english, "TREZOR").hex().startswith("c55257c360c07c72") .. rst-class:: sphx-glr-script-out .. code-block:: none phrase: buda zale golo faro lita voli juta fome himo mono mira giko seed: fa6e9176d2205fdf040f71c20bf525da ... master: xprv9s21ZrQH143K43BHonUM ... .. GENERATED FROM PYTHON SOURCE LINES 44-46 How often a miscopied word is caught ------------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 46-62 .. code-block:: Python words = phrase.split() rates = {} for size in (16, 20, 24, 28, 32): sample = bk.wallets.entropy_to_mnemonic(bytes(range(size))).split() caught = sum( not bk.wallets.is_valid_mnemonic(" ".join([*sample[:3], w, *sample[4:]])) for w in bk.wallets.WORDLIST if w != sample[3] ) rates[len(sample)] = caught / 2047 print( f"{len(sample)} words: {caught} of 2047 replacements caught ({1 - 2 ** -(size // 4):.4f})" ) assert abs(rates[12] - 15 / 16) < 0.02 .. rst-class:: sphx-glr-script-out .. code-block:: none 12 words: 1904 of 2047 replacements caught (0.9375) 15 words: 1978 of 2047 replacements caught (0.9688) 18 words: 2017 of 2047 replacements caught (0.9844) 21 words: 2031 of 2047 replacements caught (0.9922) 24 words: 2040 of 2047 replacements caught (0.9961) .. GENERATED FROM PYTHON SOURCE LINES 63-65 Every passphrase is a valid, different wallet --------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 65-82 .. code-block:: Python for passphrase in ("", "correct", "Correct"): other = bk.wallets.master_key(bk.wallets.mnemonic_to_seed(phrase, passphrase)) print(f"{passphrase!r:10} -> {bk.wallets.p2pkh_address(other.public)}") fig, ax = plt.subplots(figsize=(6, 4)) ax.plot(list(rates), [1 - r for r in rates.values()], "o-", color="#dc2626", label="measured") ax.plot( list(rates), [2 ** -(n // 3) for n in rates], "--", color="black", label="2^-(checksum bits)" ) ax.set_yscale("log") ax.set(xlabel="words in the phrase", ylabel="miscopied word accepted", xticks=list(rates)) ax.set_title("Longer phrases carry longer checksums") ax.legend() fig.tight_layout() plt.show() .. image-sg:: /api/gallery/wallets/derivation/images/sphx_glr_plot_02_bip39_mnemonic_seed_phrases_001.png :alt: Longer phrases carry longer checksums :srcset: /api/gallery/wallets/derivation/images/sphx_glr_plot_02_bip39_mnemonic_seed_phrases_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none '' -> 1PfPeEV8N2TdomVtgD4EjTiGLXc4KD6vyt 'correct' -> 147F2jMLoJfFDzpCNxwCSBQtKkhoRvFC14 'Correct' -> 18tCMaoptY4QyMKg8rQAzYUb96pPRfUWXy .. GENERATED FROM PYTHON SOURCE LINES 83-87 Exercise -------- How many words, and how many checksum bits, encode 256 bits of entropy? A worked solution is in :doc:`/exercises/wallets`. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.174 seconds) .. _sphx_glr_download_api_gallery_wallets_derivation_plot_02_bip39_mnemonic_seed_phrases.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/wallets/derivation/plot_02_bip39_mnemonic_seed_phrases.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_bip39_mnemonic_seed_phrases.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_bip39_mnemonic_seed_phrases.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_bip39_mnemonic_seed_phrases.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_