.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/crypto/signatures/plot_04_nonce_reuse.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_crypto_signatures_plot_04_nonce_reuse.py: Nonce reuse in practice, and deterministic nonces (2010-2013) ============================================================= A Schnorr or ECDSA signature hides the private key behind a one-time nonce. Reuse the nonce for two messages and two equations in one unknown give the key away. In 2010 the fail0verflow team recovered Sony's PlayStation 3 signing key this way: the console's ECDSA used a constant nonce. RFC 6979 (2013) removed the random number generator from signing: derive the nonce deterministically from the key and the message with HMAC. What to look for ---------------- Two signatures with the same nonce reveal x = (s1 - s2)/(c1 - c2). With RFC 6979 nonces, each message gets its own nonce automatically, and the derivation reproduces the RFC's published test vector. The history behind this experiment: :doc:`/history/crypto_breakthroughs`. See :doc:`/exercises/crypto` for a worked solution to the exercise. .. GENERATED FROM PYTHON SOURCE LINES 24-26 Two signatures, one nonce: the key falls out -------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 26-42 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk c = bk.crypto private, nonce = 42, 17 public = c.public_key(private) first = c.sign(b"pay Bob", private, nonce=nonce) second = c.sign(b"pay Carol", private, nonce=nonce) assert first.commitment == second.commitment # The tell-tale sign: identical R. c1 = c.challenge(b"pay Bob", first.commitment, public) c2 = c.challenge(b"pay Carol", second.commitment, public) recovered = c.recover_reused_nonce_key(first, second, c1, c2) assert recovered == private print("Reused nonce exposes private key:", recovered) .. rst-class:: sphx-glr-script-out .. code-block:: none Reused nonce exposes private key: 42 .. GENERATED FROM PYTHON SOURCE LINES 43-46 Deterministic nonces (RFC 6979) ------------------------------- The RFC's own example: NIST P-256's group order, its private key, "sample". .. GENERATED FROM PYTHON SOURCE LINES 46-55 .. code-block:: Python p256_order = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 p256_key = 0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721 k = c.deterministic_nonce(p256_key, b"sample", p256_order) assert k == 0xA6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60 print("RFC 6979 test vector reproduced") nonces = [c.deterministic_nonce(private, f"payment {i}".encode()) for i in range(200)] assert len(set(nonces)) == 200 # A fresh nonce for every message, no RNG involved. .. rst-class:: sphx-glr-script-out .. code-block:: none RFC 6979 test vector reproduced .. GENERATED FROM PYTHON SOURCE LINES 56-58 Nonces spread over the whole range ---------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 58-63 .. code-block:: Python fig, ax = plt.subplots(figsize=(7, 3.5)) ax.hist([n / c.SECP256K1.order for n in nonces], bins=20, color="#2563eb", edgecolor="white") ax.set(xlabel="nonce / group order", ylabel="messages", title="RFC 6979 nonces for 200 messages") fig.tight_layout() .. image-sg:: /api/gallery/crypto/signatures/images/sphx_glr_plot_04_nonce_reuse_001.png :alt: RFC 6979 nonces for 200 messages :srcset: /api/gallery/crypto/signatures/images/sphx_glr_plot_04_nonce_reuse_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 64-69 Exercise -------- Derive x = (s1 - s2)/(c1 - c2) modulo n from s_i = k + c_i x. Why must the challenges differ? Why does a deterministic nonce stay safe even when the same message is signed twice? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.135 seconds) .. _sphx_glr_download_api_gallery_crypto_signatures_plot_04_nonce_reuse.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/crypto/signatures/plot_04_nonce_reuse.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_04_nonce_reuse.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_04_nonce_reuse.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_04_nonce_reuse.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_