.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/fraud/solvency/plot_03_provisions_proof_of_solvency.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_fraud_solvency_plot_03_provisions_proof_of_solvency.py: Provisions: privacy-preserving proofs of solvency (2015) ======================================================== Maxwell's proof reveals the exchange's total liabilities and, to show its reserves, which addresses it owns. Dagher, Bünz, Bonneau, Clark and Boneh hid both with Pedersen commitments :math:`C(v, r) = g^v h^r`, which multiply into a commitment to the sum. The exchange commits, for every address in a large public set, to that address's balance if it owns it and to 0 if not; it commits to every customer's balance; and .. math:: \frac{\prod_i C(s_i b_i, r_i)}{\prod_j C(\ell_j, t_j)} = C\Big(\sum_i s_i b_i - \sum_j \ell_j,\; \sum_i r_i - \sum_j t_j\Big) commits to its surplus. Zero-knowledge proofs show that each asset commitment holds 0 or the public balance, that each liability and the surplus are not negative, and nothing else: not the total, not which addresses, not any balance. Each customer, given its blinding factor, checks that its own balance is among the commitments. .. GENERATED FROM PYTHON SOURCE LINES 25-29 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 30-32 A solvent exchange proves it ---------------------------- .. GENERATED FROM PYTHON SOURCE LINES 32-44 .. code-block:: Python # Balances of twelve public addresses, four of them the exchange's. anonymity_set = [820, 40, 1_500, 310, 975, 60, 1_210, 400, 15, 1_830, 700, 95] owned = {2, 6, 9, 10} customers = [480, 1_200, 75, 960, 330, 610, 1_025, 290] prover = bk.fraud.SolvencyProver(anonymity_set, owned, customers, seed=1) print(f"assets {prover.assets}, liabilities {sum(customers)}, surplus {prover.surplus}") proof = prover.prove() assert bk.fraud.verify_solvency(anonymity_set, proof) assert bk.fraud.verify_liability(proof.liability_commitments[3], customers[3], prover.blinding(3)) print("each liability proof commits to", proof.liability_proofs[0].bits, "bits") .. rst-class:: sphx-glr-script-out .. code-block:: none assets 5240, liabilities 4970, surplus 270 each liability proof commits to 16 bits .. GENERATED FROM PYTHON SOURCE LINES 45-50 What the proof does not let the exchange do ------------------------------------------- Selling a large address leaves it insolvent: no surplus proof exists. Dropping a customer from the list breaks the arithmetic, and that customer finds its commitment missing. .. GENERATED FROM PYTHON SOURCE LINES 50-65 .. code-block:: Python poorer = bk.fraud.SolvencyProver(anonymity_set, {2, 6, 9}, customers, seed=1) try: poorer.prove() except ValueError as error: print("insolvent exchange:", error) hidden = bk.fraud.SolvencyProof( proof.asset_commitments, proof.asset_proofs, proof.liability_commitments[1:], proof.liability_proofs[1:], proof.surplus_proof, ) assert not bk.fraud.verify_solvency(anonymity_set, hidden) .. rst-class:: sphx-glr-script-out .. code-block:: none insolvent exchange: insolvent: no proof of a non-negative surplus exists .. GENERATED FROM PYTHON SOURCE LINES 66-69 Commitments reveal nothing -------------------------- Commitments to an owned address's balance and to 0 look alike. .. GENERATED FROM PYTHON SOURCE LINES 69-82 .. code-block:: Python owned_c = [c for i, c in enumerate(proof.asset_commitments) if i in owned] other_c = [c for i, c in enumerate(proof.asset_commitments) if i not in owned] p = bk.crypto.TEACHING_GROUP.p fig, ax = plt.subplots(figsize=(7, 3)) ax.scatter([c / p for c in owned_c], [1] * len(owned_c), color="#16a34a", label="owned") ax.scatter([c / p for c in other_c], [0] * len(other_c), color="#64748b", label="not owned") ax.set(xlabel="commitment / p", yticks=[0, 1], yticklabels=["not owned", "owned"], xlim=(0, 1)) ax.set_title("Which addresses the exchange owns is hidden") fig.tight_layout() plt.show() .. image-sg:: /api/gallery/fraud/solvency/images/sphx_glr_plot_03_provisions_proof_of_solvency_001.png :alt: Which addresses the exchange owns is hidden :srcset: /api/gallery/fraud/solvency/images/sphx_glr_plot_03_provisions_proof_of_solvency_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 83-89 Exercise -------- Two exchanges could each claim the same address in their own proofs. Why can't customers of either exchange detect it, and what did Provisions add to rule it out? A worked solution is in :doc:`/exercises/fraud`. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.042 seconds) .. _sphx_glr_download_api_gallery_fraud_solvency_plot_03_provisions_proof_of_solvency.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/fraud/solvency/plot_03_provisions_proof_of_solvency.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_03_provisions_proof_of_solvency.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_03_provisions_proof_of_solvency.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_03_provisions_proof_of_solvency.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_