.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/vm/ethereum/plot_04_integer_overflow.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_vm_ethereum_plot_04_integer_overflow.py: Integer overflow: minting tokens from nothing (BeautyChain, 2018) ================================================================= EVM words wrap modulo 2**256. In April 2018 an attacker called the BeautyChain (BEC) token's ``batchTransfer`` with two recipients and a value of 2**255. The contract computed the total as ``2 * 2**255``, which wraps to 0, checked that the sender had at least 0 tokens, and credited each recipient 2**255 tokens. Exchanges suspended the token (CVE-2018-10299). The SafeMath library's checked arithmetic, and later Solidity 0.8's default overflow checks, close the hole. What to look for ---------------- The unchecked contract accepts the call from a sender with no tokens, and the total supply jumps by 2**256: tokens appear from nowhere. The checked version reverts, and both versions agree on every ordinary transfer. The history behind this experiment: :doc:`/history/vm_breakthroughs`. See :doc:`/exercises/vm` for a worked solution to the exercise. .. GENERATED FROM PYTHON SOURCE LINES 26-28 The attack ---------- .. GENERATED FROM PYTHON SOURCE LINES 28-46 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk ATTACKER, RECIPIENT_A, RECIPIENT_B = 1, 2, 3 balances = {ATTACKER: 0, 4: 1_000_000} unchecked = bk.vm.batch_transfer(ATTACKER, [RECIPIENT_A, RECIPIENT_B]) checked = bk.vm.batch_transfer(ATTACKER, [RECIPIENT_A, RECIPIENT_B], checked=True) value = 2**255 assert 2 * value % 2**256 == 0 after = bk.vm.execute(unchecked, arguments=(value,), storage=balances).storage print("recipient A now holds", after[RECIPIENT_A]) assert after[RECIPIENT_A] == after[RECIPIENT_B] == value and after[ATTACKER] == 0 try: bk.vm.execute(checked, arguments=(value,), storage=balances) except bk.vm.VMError as error: print("checked version:", error) .. rst-class:: sphx-glr-script-out .. code-block:: none recipient A now holds 57896044618658097711785492504343953926634992332820282019728792003956564819968 checked version: reverted .. GENERATED FROM PYTHON SOURCE LINES 47-49 Ordinary transfers are unaffected --------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 49-61 .. code-block:: Python funded = {ATTACKER: 500} for v in (1, 10, 100, 250): a = bk.vm.execute(unchecked, arguments=(v,), storage=funded).storage b = bk.vm.execute(checked, arguments=(v,), storage=funded).storage assert a == b and sum(a.values()) == 500 supply = {"before": sum(balances.values()), "after attack": sum(after.values())} fig, ax = plt.subplots(figsize=(6, 3.5)) ax.bar(supply.keys(), [s / 2**255 for s in supply.values()], color=["#64748b", "#dc2626"]) ax.set(ylabel="total supply / 2**255", title="Tokens from a wrapped multiplication") fig.tight_layout() .. image-sg:: /api/gallery/vm/ethereum/images/sphx_glr_plot_04_integer_overflow_001.png :alt: Tokens from a wrapped multiplication :srcset: /api/gallery/vm/ethereum/images/sphx_glr_plot_04_integer_overflow_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 62-67 Exercise -------- The checked version tests ``amount / count == value``. Why does that detect every overflow of ``count * value`` for ``count >= 1``? Could the check ``amount >= value`` replace it? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.091 seconds) .. _sphx_glr_download_api_gallery_vm_ethereum_plot_04_integer_overflow.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/vm/ethereum/plot_04_integer_overflow.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_04_integer_overflow.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_04_integer_overflow.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_04_integer_overflow.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_