.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/wallets/custody/plot_03_social_recovery_wallets.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_custody_plot_03_social_recovery_wallets.py: Social-recovery wallets (2021) ============================== Vitalik Buterin argued in January 2021 for wallets that need no seed-phrase backup. A social-recovery wallet is a contract with one signing key for daily use and n guardians, any m of whom can replace that key. Losing the key no longer loses the coins, and a thief with the key alone can be locked out. If each guardian is independently lost with probability :math:`p_l` or corrupt with probability :math:`p_c`, .. math:: P(\text{theft}) = \sum_{j \ge m} \binom{n}{j} p_c^{\,j} (1 - p_c)^{n-j}, and a lockout needs fewer than m honest guardians: the threshold trades one risk for the other. Changes to the guardians are delayed, so a thief cannot replace them before they recover the wallet. .. GENERATED FROM PYTHON SOURCE LINES 22-27 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk from blockchainkit.wallets.visualizers import plot_recovery_risk .. GENERATED FROM PYTHON SOURCE LINES 28-30 Losing a key, and getting the wallet back ----------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 30-50 .. code-block:: Python world = bk.contracts.World() world.fund("alice", 100) guardians = ["sister", "friend", "hardware", "lawyer", "colleague"] wallet = world.deploy("alice", bk.wallets.SocialRecoveryWallet, "alice", guardians, 3) world.transact("alice", wallet, value=100) # A thief copies alice's key and tries to make itself the only guardian. assert world.transact("alice", wallet, "propose_guardians", ["thief"], 1).success print(world.transact("alice", wallet, "apply_guardians").error) # Three guardians move the wallet to alice's new key first. for g in ("sister", "friend", "hardware"): receipt = world.transact(g, wallet, "support_recovery", "alice-new-key") print("recovered:", receipt.result, "owner:", world.view(wallet, "owner")) world.advance(bk.wallets.GUARDIAN_DELAY) print("thief applies:", world.transact("alice", wallet, "apply_guardians").error) assert world.transact("alice-new-key", wallet, "execute", "bob", 30).success assert world.balance("bob") == 30 .. rst-class:: sphx-glr-script-out .. code-block:: none the delay has not passed recovered: True owner: alice-new-key thief applies: only the owner .. GENERATED FROM PYTHON SOURCE LINES 51-53 Choosing the threshold ---------------------- .. GENERATED FROM PYTHON SOURCE LINES 53-64 .. code-block:: Python for m in range(1, 6): risk = bk.wallets.recovery_risk(5, m, lost=0.1, corrupt=0.05) print(f"{m} of 5: lockout {risk.lockout:.2e}, theft {risk.theft:.2e}") best = bk.wallets.recovery_risk(5, 3, lost=0.1, corrupt=0.05) assert best.lockout < 0.1 and best.theft < 0.05 # Better than one seed phrase on both counts. ax = plot_recovery_risk(5, lost=0.1, corrupt=0.05) ax.set_title("5 guardians against one seed phrase (lost 10%, stolen 5%)") plt.show() .. image-sg:: /api/gallery/wallets/custody/images/sphx_glr_plot_03_social_recovery_wallets_001.png :alt: 5 guardians against one seed phrase (lost 10%, stolen 5%) :srcset: /api/gallery/wallets/custody/images/sphx_glr_plot_03_social_recovery_wallets_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none 1 of 5: lockout 7.59e-05, theft 2.26e-01 2 of 5: lockout 2.23e-03, theft 2.26e-02 3 of 5: lockout 2.66e-02, theft 1.16e-03 4 of 5: lockout 1.65e-01, theft 3.00e-05 5 of 5: lockout 5.56e-01, theft 3.13e-07 .. GENERATED FROM PYTHON SOURCE LINES 65-70 Exercise -------- Which threshold minimizes the sum of the lockout and theft probabilities for 5 guardians, each lost with probability 0.1 and corrupt with 0.05? A worked solution is in :doc:`/exercises/wallets`. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.106 seconds) .. _sphx_glr_download_api_gallery_wallets_custody_plot_03_social_recovery_wallets.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/custody/plot_03_social_recovery_wallets.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_03_social_recovery_wallets.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_03_social_recovery_wallets.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_03_social_recovery_wallets.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_