<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: zemse</title>
    <description>The latest articles on Forem by zemse (@zemse).</description>
    <link>https://forem.com/zemse</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F240324%2F5e0dde93-5230-4fec-9f48-ee6094b8dc18.png</url>
      <title>Forem: zemse</title>
      <link>https://forem.com/zemse</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zemse"/>
    <language>en</language>
    <item>
      <title>Understanding EIP-7864's Unified Binary Tree</title>
      <dc:creator>zemse</dc:creator>
      <pubDate>Mon, 17 Feb 2025 10:18:15 +0000</pubDate>
      <link>https://forem.com/zemse/understanding-eip-7864s-unified-binary-tree-36m4</link>
      <guid>https://forem.com/zemse/understanding-eip-7864s-unified-binary-tree-36m4</guid>
      <description>&lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://github.com/jsign" rel="noopener noreferrer"&gt;Ignacio Hagopian&lt;/a&gt; (EIP-7864 author) for a quick review of this article and the cover image features a tree from the Goerli Park.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Unlike Bitcoin, Ethereum includes something called "state root" in its current block's header. For being functional, it's not necessary to have a state root, since any new full node joining the network can sync and execute all blocks to arrive at the current state. However, running full-node is time and resource-consuming. As of Feb 2025, the Ethereum's current blockchain size is ~1500 GiB. Forget about mobile phones, even most laptops don't have that much space capacity. To make things worse, we also have many L2s. It's not practical for users to run full nodes for every network they use. Hence, almost every Ethereum or L2 user knowingly or unknowingly trusts a full-node RPC provider. If these providers give malicious responses, the user won't realize until money is lost.&lt;/p&gt;

&lt;p&gt;That's why Ethereum, since its inception in mid-2015, came with a state root, a 32-byte value that is calculated by encoding the entire state using the Merkle Patricia Trie structure. This enables devices with limited storage/computation to still use Ethereum in a safe and trustless way.&lt;/p&gt;

&lt;p&gt;However, MPT has many complexities like RLP and Extension Nodes which make writing zk constraints extremely challenging (was in development for about &lt;a href="https://github.com/privacy-scaling-explorations/zkevm-circuits/commits/main/zkevm-circuits/src/mpt_circuit.rs" rel="noopener noreferrer"&gt;2 years&lt;/a&gt;). Being a hex-ary trie, its proof size is quite huge, especially when required to supply multiple state proofs. Light clients also face an &lt;a href="https://github.com/chainbound/bolt/discussions/59#discussioncomment-9871043" rel="noopener noreferrer"&gt;edge case&lt;/a&gt; while operating on a partial MPT.&lt;/p&gt;

&lt;p&gt;Verkle tree solution was studied for the last few years and attempted to solve the above problems, however, it's not post-quantum safe. The security of hash functions is not proven to be affected by quantum computers. Hence, the hash-based Binary tree can be a promising solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unified Binary Tree (UBT)
&lt;/h2&gt;

&lt;p&gt;There are many technical details specified in the &lt;a href="https://eips.ethereum.org/EIPS/eip-7864#notable-changes-from-the-hexary-structure" rel="noopener noreferrer"&gt;EIP-7864&lt;/a&gt;. This post is an informal attempt to specify the details one by one, such that it can be easy for an engineer to digest quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 - Sparse Tree
&lt;/h3&gt;

&lt;p&gt;Let's imagine a sparse merkle tree structure with 256 depth, meaning the number of leaves is 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;22562^{256} &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;256&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. Each leaf stores a 256-bit value. This makes it like a mapping of uint256 to uint256, where we traverse down the tree by consuming a bit from the key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6lmb9tv7qqhdh9rfb1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6lmb9tv7qqhdh9rfb1n.png" alt="Basic sparse tree" width="570" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the following steps, we will make some modifications to the tree to arrive at the Binary Tree specified in EIP-7864.&lt;/p&gt;

&lt;p&gt;Spoiler alert: the UBT is not sparse, it will be discussed later in Step 8.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2 - Group every 256 leaves
&lt;/h3&gt;

&lt;p&gt;In the MPT's Account trie, the leaf was an RLP byte string of tuple of the nonce, balance, code hash, and storage root. It's convenient to have these details together.&lt;/p&gt;

&lt;p&gt;In our binary tree, how can we keep these related values together?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We can hash their RLP string and store it as the leaf value.&lt;/li&gt;
&lt;li&gt;We can store related values in adjacent leaves in the merkle tree.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first option adds an extra layer of hashing and increases complexity. The second option is simpler. Let's go!&lt;/p&gt;

&lt;p&gt;To be able to store related items in adjacent leaves in a neat way, we can allocate adjacent groups of 256 leaves and call it "sub-tree". This means our original 256-bit key of the huge tree is split into two parts: 248-bit stem-key + 8-bit sub-key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwz8j2qfsets6dtlo2f4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwz8j2qfsets6dtlo2f4f.png" alt="Tree with 248 depth and subtrees" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that from a structural perspective, there's no difference from our original 256-depth sparse merkle tree. We have simply grouped all the leaves of our massive tree into groups of 256 leaves. So it looks like we have a tree of 248-depth, and each of its leaves is an 8-depth sub-tree.&lt;/p&gt;
&lt;h4&gt;
  
  
  There are three types of sub-trees:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Account sub-tree&lt;/li&gt;
&lt;li&gt;Storage sub-tree&lt;/li&gt;
&lt;li&gt;Code chunks sub-tree&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these sub-trees are 8-depth, so they look the same. The only difference is the kind of data that is stored in the leaves.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3 - Account sub-tree
&lt;/h3&gt;

&lt;p&gt;Details of an account will be stored in a subtree. To reach that sub-tree for an account we need to convert a 20-byte address into a 31-byte key using the following logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;address_to_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_bytes_32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tree_idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// use first 31 bytes result of the hash&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tree_idx&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a sub-tree there are 256 leaves. Every account has the following details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nonce (8 bytes)&lt;/li&gt;
&lt;li&gt;Balance (16 bytes)&lt;/li&gt;
&lt;li&gt;Bytecode (dynamic, max length 24kb)&lt;/li&gt;
&lt;li&gt;Storage (dynamic, max count is very high)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our goal is to somehow store it. Now &lt;code&gt;nonce&lt;/code&gt; and &lt;code&gt;balance&lt;/code&gt; could each take a leaf but each leaf size is 32 bytes. So to save proof cost, we can combine these details in a single leaf.&lt;/p&gt;

&lt;h4&gt;
  
  
  First leaf data layout
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;1 byte: Version byte&lt;/li&gt;
&lt;li&gt;4 bytes: Reserved for future usage&lt;/li&gt;
&lt;li&gt;3 bytes: code size&lt;/li&gt;
&lt;li&gt;8 bytes: nonce&lt;/li&gt;
&lt;li&gt;16 bytes: balance&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Second leaf
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;32 bytes: Codehash&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Rest of the leaves
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Third leaf to 64th leaf: Reserved for future usage.&lt;/li&gt;
&lt;li&gt;65th leaf to 128th leaf: Reserved for Storage.&lt;/li&gt;
&lt;li&gt;129th leaf to 256th leaf: Reserved for Bytecode chunks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70qpsz3rg9etd85n9ufa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70qpsz3rg9etd85n9ufa.png" alt="Tree with 248 depth and subtrees and expand one subtree to show details" width="800" height="790"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 - Storage sub-tree
&lt;/h3&gt;

&lt;p&gt;Previously, there were MPTs inside MPTs (account trie contained storage trie). To open a storage slot, we had to open the account's storage root first, which adds proof size as well as extra work. In the Binary tree, we could avoid this by combining all key-value pairs in the single tree.&lt;/p&gt;

&lt;p&gt;The first 64 storage slots are stored in the Account's sub-tree. The 65th leaf to 128th leaf is reserved for this purpose. The rest of the storage slots in groups of 256 are stored together in a deterministically random sub-tree calculated using the following logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_tree_key_for_storage_slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Address32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;storage_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;storage_key&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CODE_OFFSET&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;HEADER_STORAGE_OFFSET&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HEADER_STORAGE_OFFSET&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;storage_key&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MAIN_STORAGE_OFFSET&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;storage_key&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get_tree_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;STEM_SUBTREE_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;STEM_SUBTREE_WIDTH&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps with giving state proof for Solidity arrays which start at a deterministically random slot and then all array elements are sequential. In the case of solidity mappings, it will store things in random leaves in our UBT, but if the solidity mapping points to a structure (e.g. &lt;code&gt;mapping(address =&amp;gt; Person)&lt;/code&gt;) then solidity lays out the structure contents sequentially, so we can make easy state proofs for that too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 - Bytecode chunk sub-tree
&lt;/h3&gt;

&lt;p&gt;Previously in MPT only codehash was present in the state. Opening a small part of bytecode through state proof meant providing an entire preimage of codehash which is lengthy. This is troublesome especially when we want to create block execution proof, a worse-case block would touch as many Ethereum accounts and we have to witness all bytecode when only a small portion of it is used, this causes a lot of hashing, creating a DoS vector for zk light clients.&lt;/p&gt;

&lt;p&gt;In the new UBT, we want to improve this situation by placing the bytecode in the merkle tree, chunk by chunk in the leaves. So that zk light clients can expose sufficiently required code slices. The costs of CALL opcodes can also be updated to incentivize usage of less bytecode.&lt;/p&gt;

&lt;p&gt;Bytecode in the worst case (24kb) will require 750+ leaves. So we need to allocate other sub-trees to be able to fill all the bytecode. &lt;/p&gt;

&lt;p&gt;A naive approach can be to simply break bytecode into 32-byte chunks and place them in the merkle tree. However, note that bytecode can also contain push opcodes. So when you are given a 32-byte chunk from a huge bytecode, you are not sure if the first byte is an executable opcode or part of a push opcode.&lt;/p&gt;

&lt;p&gt;To resolve this issue, we can simply allocate 1 byte in every chunk to store the number of bytes that are non-executable (part of the push opcode in the previous chunk).&lt;/p&gt;

&lt;h4&gt;
  
  
  Layout of chunk
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;1 byte: number of non-executable/push bytes at the begining of this chunk&lt;/li&gt;
&lt;li&gt;31 bytes: raw bytecode&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example 1 - short bytecode
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# raw bytecode len 3 bytes&lt;/span&gt;
345f55

&lt;span class="c"&gt;# 1-byte num of non-exec bytes + 31-byte chunks&lt;/span&gt;
- 00345f5500000000000000000000000000000000000000000000000000000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 2 - long bytecode
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# raw bytecode len 64 bytes&lt;/span&gt;
5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b
5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b

&lt;span class="c"&gt;# 1-byte num of non-exec bytes + 31-byte chunks&lt;/span&gt;
- 005b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b
- 005b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b
- 005b5b0000000000000000000000000000000000000000000000000000000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 3 - long bytecode with push opcode
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# raw bytecode len 64 bytes&lt;/span&gt;
5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b6911223344
5566778899aa5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b

&lt;span class="c"&gt;# 1-byte num of non-exec bytes + 31-byte chunks&lt;/span&gt;
- 005b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b69112233
- 07445566778899aa5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b
- 005b5b0000000000000000000000000000000000000000000000000000000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we have a PUSH10 (0x69) in the first chunk whose push data is also going into the second chunk. The complete instruction looks like &lt;code&gt;69112233445566778899aa&lt;/code&gt;, however when we break it into 31-byte chunks we have &lt;code&gt;445566778899aa&lt;/code&gt; push bytes, hence we store 7 in the num of non-exec bytes.&lt;/p&gt;

&lt;p&gt;The first 128 bytecode chunks are stored in the account sub-tree. The rest of the chunks in groups of 256 chunks are stored somewhere in the UBT.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_tree_key_for_code_chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Address32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get_tree_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CODE_OFFSET&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunk_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;STEM_SUBTREE_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CODE_OFFSET&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunk_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;STEM_SUBTREE_WIDTH&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6 - Simplify the tree by hash function special case
&lt;/h3&gt;

&lt;p&gt;Usually in a Merkle tree, the hash value of a node is the hash of the concatenation of its children.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hl1cy25saq92ush4e78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hl1cy25saq92ush4e78.png" alt="Top node with children A and B" width="201" height="201"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;top = hash(concat(A, B))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see the scale of our tree, most of it is going to be empty even after 100 years of production usage.&lt;/p&gt;

&lt;p&gt;There will be a lot of hashing involved, we can add a special case - if both A and B are &lt;code&gt;0&lt;/code&gt;, then &lt;code&gt;hash(concat(0, 0))&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means if our tree is empty, its root is &lt;code&gt;0&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Similarly, if a leaf is non-zero, we can compute the hash of that section easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5bym3w7rxm9jzmyl8qfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5bym3w7rxm9jzmyl8qfu.png" alt="Simplify the hash rules" width="360" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, note that the hash function is not yet finalized. People are waiting for the security analysis of poseidon2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7 - Empty node to further simplify tree
&lt;/h3&gt;

&lt;p&gt;A naive approach for creating such a tree in memory will require about 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;106810^{68} &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;0&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;68&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 GB of memory.&lt;/p&gt;

&lt;p&gt;To ghost the unused portions of the tree, we can introduce "Empty Node".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpauc3g8kxp6p11fa0q2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpauc3g8kxp6p11fa0q2u.png" alt="Adding empty node" width="360" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Interestingly, the usage of empty nodes to hide the section or actual full sections does not affect the state root.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 8 - Convert into a non-sparse tree to further simplify the tree
&lt;/h3&gt;

&lt;p&gt;In a sparse merkle tree, the proof size is 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(logb(leavesmax))O(logb(leaves_{max})) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;l&lt;/span&gt;&lt;span class="mord mathnormal"&gt;o&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;l&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;v&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;s&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;ma&lt;/span&gt;&lt;span class="mord mathnormal mtight"&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. In our tree where we have 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;22562^{256} &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;256&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 depth, we will have a very huge proof size i.e. 32 bytes x 256 = 8192 bytes. &lt;/p&gt;

&lt;p&gt;Especially, when most of the leaves in our tree are going to be empty even after 1000 years of production usage. The ideal case would be to have the proof in 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(logb(leavescount))O(logb(leaves_{count})) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;l&lt;/span&gt;&lt;span class="mord mathnormal"&gt;o&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;l&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;v&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;s&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;co&lt;/span&gt;&lt;span class="mord mathnormal mtight"&gt;u&lt;/span&gt;&lt;span class="mord mathnormal mtight"&gt;n&lt;/span&gt;&lt;span class="mord mathnormal mtight"&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;We introduce a structure something called &lt;code&gt;StemNode&lt;/code&gt; which is supposed to represent the 256 leaves of the sub-tree. It also stores the 31 bytes of the stem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;StemNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;stem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="n"&gt;leaves&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is to have a minimal amount of internal branching nodes. If there's just a single &lt;code&gt;StemNode&lt;/code&gt; then we can place it directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tree examples
&lt;/h3&gt;

&lt;p&gt;Following is an empty tree:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtxhsl5ixqslya48fj7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtxhsl5ixqslya48fj7b.png" alt="An empty tree is just an empty node" width="200" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since there's nothing, the root node is EmptyNode and root hash is 0.&lt;/p&gt;

&lt;h4&gt;
  
  
  First insertion
&lt;/h4&gt;

&lt;p&gt;Now we insert one element &lt;code&gt;key=bytes32(1)&lt;/code&gt; and &lt;code&gt;value=1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sqpndtsejta29syioa4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sqpndtsejta29syioa4.png" alt="Tree after first insertion" width="270" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we have one insertion, it creates a stem node with the stem as the first 31 bytes from the key, last 1 byte is used as the id in the stem node. In this case, our &lt;code&gt;key=1&lt;/code&gt; is broken down into &lt;code&gt;stem=0&lt;/code&gt; and &lt;code&gt;id=1&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Second insertion
&lt;/h4&gt;

&lt;p&gt;Now we insert one more element &lt;code&gt;key = 1&amp;lt;&amp;lt;255&lt;/code&gt; and &lt;code&gt;value=1&lt;/code&gt;. This key is broken down into &lt;code&gt;stem=1&amp;lt;&amp;lt;247&lt;/code&gt; and &lt;code&gt;id=0&lt;/code&gt;. We will now update the tree.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedq0yhbgsh3s0isrb6al.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedq0yhbgsh3s0isrb6al.png" alt="Tree after second insertion" width="560" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Third insertion
&lt;/h4&gt;

&lt;p&gt;To show an insertion in existing stem node, let us insert key=0 value=4. Here key is broken down into &lt;code&gt;stem=0&lt;/code&gt; and &lt;code&gt;id=0&lt;/code&gt;. As we walk down the tree, we arrive at a StemNode where stem is &lt;code&gt;0&lt;/code&gt;. So we update the value at &lt;code&gt;id=0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28y3k5fhr4ksfmml8sw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28y3k5fhr4ksfmml8sw5.png" alt="Tree after third insertion" width="560" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Fourth insertion
&lt;/h4&gt;

&lt;p&gt;We can do additional insertion at &lt;code&gt;key = 1&amp;lt;&amp;lt;253&lt;/code&gt; and &lt;code&gt;value=1&lt;/code&gt; to see how internal nodes are created. This key is broken down into &lt;code&gt;stem=1&amp;lt;&amp;lt;245&lt;/code&gt; and &lt;code&gt;id=0&lt;/code&gt;. We create minimum internal nodes as needed.&lt;/p&gt;

&lt;p&gt;As we walk down the stem path, we arrive at a StemNode whose stem is 0 instead of &lt;code&gt;1&amp;lt;&amp;lt;245&lt;/code&gt;. So we refactor that section by adding some internal nodes and creating a new StemNode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsreuuhig6q2ot6nw2xt8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsreuuhig6q2ot6nw2xt8.png" alt="Tree after fourth insertion" width="740" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see a node existed already on the left leg of the root. It was refactored down as needed using a minimal amount of internal branch nodes.&lt;/p&gt;

&lt;p&gt;In the previous MPT specification, a field similar to &lt;code&gt;stem&lt;/code&gt; existed called &lt;code&gt;path&lt;/code&gt; in the branch, extension, and leaf nodes in MPT, however, it excluded the already consumed nibbles down in the path. So in the process when we have to refactor the tree, it changes the &lt;code&gt;path&lt;/code&gt;, hereby changing the hash of the node, giving rise to some edge cases. It is great to see that in the UBT specification, the &lt;code&gt;stem&lt;/code&gt; value is not affected by refactoring in placement as it's the full 31-byte key value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;As of Feb 2025, this proposal is in draft status. Unified Binary Tree is a step towards a quantum-safe and snarkified Ethereum. It also makes Ethereum's spec simpler and can work together with state-expiry EIP. It overall sounds beneficial to Ethereum, however making changes to Ethereum is not easy and we have to explore the challenges too.&lt;/p&gt;

&lt;p&gt;To participate in the UBT discussion, you can use the thread at &lt;a href="https://ethereum-magicians.org/t/eip-7864-ethereum-state-using-a-unified-binary-tree/22611/6" rel="noopener noreferrer"&gt;https://ethereum-magicians.org/t/eip-7864-ethereum-state-using-a-unified-binary-tree/22611/6&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>datastructures</category>
      <category>eip7864</category>
      <category>ubt</category>
    </item>
    <item>
      <title>Setup GPG on macOS</title>
      <dc:creator>zemse</dc:creator>
      <pubDate>Sun, 12 Mar 2023 14:07:08 +0000</pubDate>
      <link>https://forem.com/zemse/setup-gpg-on-macos-2iib</link>
      <guid>https://forem.com/zemse/setup-gpg-on-macos-2iib</guid>
      <description>&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install gpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create new key
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# generate key
gpg --full-generate-key

# get the public key using key ID
gpg --armor --export XXXXXX

# set the key ID in git
git config --global user.signingkey XXXXXXX

# always sign commits
git config commit.gpgsign true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup keychain
&lt;/h2&gt;

&lt;p&gt;gpg collects password from cli. This causes issues if using vscode to create a commit. So input can be taken from a popup or keychain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install pinentry-mac
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The brew installation will print these caveats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==&amp;gt; Caveats
You can now set this as your pinentry program like

~/.gnupg/gpg-agent.conf
    pinentry-program /opt/homebrew/bin/pinentry-mac
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So just create a &lt;code&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt; file if it doesn't exist and put the line &lt;code&gt;pinentry-program /opt/homebrew/bin/pinentry-mac&lt;/code&gt; in it.&lt;/p&gt;

&lt;p&gt;Now, to check if it works.&lt;/p&gt;

&lt;p&gt;1.&lt;code&gt;gpg --list-keys&lt;/code&gt; to print the existing keys.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;pkill -TERM gpg-agent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Restart the terminal.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo test | gpg -e -r &amp;lt;PUT THE KEY ID HERE&amp;gt; | gpg -d&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should open a pin entry popup and make sure "save in keychain" option is selected.&lt;/p&gt;

&lt;h2&gt;
  
  
  More links
&lt;/h2&gt;

&lt;p&gt;Documentation on GitHub for setup: &lt;a href="https://docs.github.com/en/authentication/managing-commit-signature-verification"&gt;https://docs.github.com/en/authentication/managing-commit-signature-verification&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Unlocking the Lockbox2 | ParadigmCTF’22</title>
      <dc:creator>zemse</dc:creator>
      <pubDate>Wed, 24 Aug 2022 05:50:00 +0000</pubDate>
      <link>https://forem.com/zemse/unlocking-the-lockbox2-paradigmctf22-10pn</link>
      <guid>https://forem.com/zemse/unlocking-the-lockbox2-paradigmctf22-10pn</guid>
      <description>&lt;p&gt;This weekend was fun, thanks to &lt;a href="https://twitter.com/paradigm" rel="noopener noreferrer"&gt;Paradigm&lt;/a&gt; for organising a great &lt;a href="https://twitter.com/paradigm_ctf" rel="noopener noreferrer"&gt;CTF&lt;/a&gt; again, that has very original and really tough challenges. Got to learn a lot while attempting/solving some of them. This CTF sometimes reminds me of IITJEE exam (a not-for-noobs high school/10+2 level exam in India).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/paradigmxyz/paradigm-ctf-2021/tree/master/lockbox/public/contracts" rel="noopener noreferrer"&gt;Lockbox (the first)&lt;/a&gt; was very interesting challenge. I attempted it last year during the CTF, found it very tough. This year’s challenge isn’t any less. From seeming like you can do it, then making you feel like it’s literally impossible, Lockbox kept the reputation with it's 2nd iteration.&lt;/p&gt;

&lt;p&gt;The Lockbox2 challenge is available &lt;a href="https://github.com/zemse/lockbox2-rocks/tree/main/contracts" rel="noopener noreferrer"&gt;here&lt;/a&gt;. In this post, we'll understand the challenge and solve it (based on how I approached it during the CTF). I've posted links wherever necessary. As a heads up, this is a quite long post, it's intended for beginners/intermediates to be able to follow. For experts, feel free to skim through the post or directly skip to the final solution &lt;a href="https://github.com/zemse/lockbox2-rocks/blob/main/test/Lockbox2.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd like to thank &lt;a href="https://twitter.com/rileyholterhus" rel="noopener noreferrer"&gt;@rileyholterhus&lt;/a&gt;, the Lockbox2 puzzle creator, to do a quick review of this post and provide valuable suggestions 🙏.&lt;/p&gt;

&lt;p&gt;The Setup contract deploys a Lockbox2 contract, that contains a variable called &lt;code&gt;locked&lt;/code&gt;, which is instantiated as &lt;code&gt;true&lt;/code&gt;. The challenge requires this locked to be set as &lt;code&gt;false&lt;/code&gt;. We can see that if get the &lt;code&gt;solve()&lt;/code&gt; method to execute successfully, it’d set locked variable as &lt;code&gt;false&lt;/code&gt;. But there are some preceding conditions which depend on input, which if not met, the &lt;code&gt;solve()&lt;/code&gt; tx would fail. The challenge is all about crafting an input that passes the combination of conditions, similar to cracking &lt;a href="https://en.wikipedia.org/wiki/Rotary_combination_lock" rel="noopener noreferrer"&gt;combination locks&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqbfiattq8ukedtujw9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqbfiattq8ukedtujw9h.png" alt="A scene from Bollywood movie Happy New Year, Boman Irani attempting to crack a rotary combination lock of the vault"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crafting inputs and improving it sounds fun. However, interestingly, the solidity &lt;code&gt;solve()&lt;/code&gt; method does not take any input!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function solve() external {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the solve method doesn't accept any input, how are we supposed to insert the crafted input?!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5jist9i81gl23f29osn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5jist9i81gl23f29osn.png" alt="Meme expressing this is just the first of all problems we will face"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The thing here is, you can basically pass more calldata than needed, solidity does not really care about it (ik this is pretty obvious now, if I’d show this to myself of two years ago I'd have no clue). &lt;/p&gt;

&lt;p&gt;So if we use the usual libs that rely on ABI, the generated calldata will be just the 4 bytes selector and we won’t be able to able to have them encode it for us. So we have to get our hands dirty and do it ourselves. Check out the Contract ABI Spec in the &lt;a href="https://docs.soliditylang.org/en/latest/abi-spec.html" rel="noopener noreferrer"&gt;Solidity docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we will go through the challenge just to get it’s overview and understand it. Then we can get started into crafting the calldata all together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of solve method
&lt;/h2&gt;

&lt;p&gt;The solve method makes 5 delegate calls to the self contract, to invoke the logic for those 5 stages.&lt;/p&gt;

&lt;p&gt;It’s easily visible that calldata beyond the 4 bytes &lt;code&gt;msg.data[4:]&lt;/code&gt; is passed to the particular stage method.&lt;/p&gt;

&lt;p&gt;Here, delegatecall preserves the &lt;code&gt;msg.sender&lt;/code&gt;. The intention could be to just add some friction for those who have not played enough with delegatecall. Or if not, we'll get to know shortly ;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 1
&lt;/h3&gt;

&lt;p&gt;Quite straight forward, the calldata must be under 500 bytes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 2
&lt;/h3&gt;

&lt;p&gt;Looks at first 4 words and expects them to either be a prime number or simply 1. Each of those 4 numbers should small enough (like up to 1000), so that the for-loop can iterate within tx gas limit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 3
&lt;/h3&gt;

&lt;p&gt;Looks at first 3 words as &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt;. Makes a staticcall to &lt;code&gt;address(a + b)&lt;/code&gt;. Note that from previous stage, the words are quite small numbers (~1000) and hence their sum would also be small. This means we can’t target this staticcall to a contract that we could practically deploy. This has to either be a precompile address or empty account. &lt;/p&gt;

&lt;p&gt;If it is a precompile, then we have just a handful of &lt;a href="https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/evm/src/precompiles/index.ts" rel="noopener noreferrer"&gt;choices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A staticcall to empty account would be successful and return empty data (you can verify this by doing a simple eth_call to random address, it won’t give json rpc error response).&lt;/p&gt;

&lt;p&gt;Btw, this one has an interesting &lt;code&gt;mstore(a, b)&lt;/code&gt; over there. This logic basically stores value &lt;code&gt;b&lt;/code&gt; at memory location &lt;code&gt;a&lt;/code&gt;. By initial thought, memory location cannot be very huge and maybe it just want's to restrict &lt;code&gt;a&lt;/code&gt; to be sufficiently small, but isn't that implied from stage2? Can't make sense of it so far, let's move on for now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 4
&lt;/h3&gt;

&lt;p&gt;Things get nasty here since now it involves dynamic types. It is important to understand how solidity handles dynamic types, specifically bytes in calldata for this case. Check out dynamic types section in the Contract ABI spec &lt;a href="https://docs.soliditylang.org/en/latest/abi-spec.html#use-of-dynamic-types" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For simplicity, let’s ignore previous stages, just look at this in order to understand what this stage needs in order to pass through.&lt;/p&gt;

&lt;p&gt;The gist of the conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It takes two byte strings, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Deploys a contract using &lt;code&gt;a&lt;/code&gt; as the creation code. The bytecode should be a ECDSA public key (length 64) of the &lt;code&gt;tx.origin&lt;/code&gt; (the EOA wallet that we will use to interact). Note that ECDSA of ecdsa public key gives ethereum address (after chopping of the upper 12 bytes).&lt;/li&gt;
&lt;li&gt;Makes a staticcall to the contract just deployed, using &lt;code&gt;b&lt;/code&gt; as the calldata, this call should be successful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can easily deploy a contract containing any code we want. Here, we want to have the &lt;code&gt;tx.origin&lt;/code&gt;’s public key as the bytecode. So one thing is we should fix a EOA wallet. And then the challenge is getting the static call to succeed. Easiest approach I could think of is having first byte as zero (STOP opcode), so that it halts execution and staticcall passes.&lt;/p&gt;

&lt;p&gt;If you notice, this does not involve &lt;code&gt;b&lt;/code&gt; at all. So basically &lt;code&gt;b&lt;/code&gt; taking any value can work, which is one less headache.&lt;/p&gt;

&lt;p&gt;Making this stage pass individually is straight forward. It will be challenging to make combination of all stages pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 5
&lt;/h3&gt;

&lt;p&gt;It internally makes a msg call to solve function which should fail somehow. Though there’s a difference of &lt;code&gt;msg.sender&lt;/code&gt; in both &lt;code&gt;solve()&lt;/code&gt; invocation, &lt;code&gt;msg.sender&lt;/code&gt; is really not consumed anywhere to make a difference. At first it might seem strange, how it is possible for one thing to work first and then not work in the same env conditions? &lt;/p&gt;

&lt;p&gt;The key to this stage, is the fact that in a CALL only 63/64 of the available gas is passed (source &lt;a href="https://www.evm.codes" rel="noopener noreferrer"&gt;evm.codes&lt;/a&gt;). If we pass just enough gas limit, slightly less gas would be passed such that internal message call fails due to out of gas, passing the check in stage 5. Also it is important to note that 1/64 gas should be enough to perform later operations, else it will not work. It also makes sense why there's &lt;code&gt;locked&lt;/code&gt; variable is set to &lt;code&gt;false&lt;/code&gt;, instead of having a &lt;code&gt;solved&lt;/code&gt; variable which is set to &lt;code&gt;true&lt;/code&gt; like in other challenges, since it'd cost less gas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the challenge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 - Solve Stage 4
&lt;/h3&gt;

&lt;p&gt;I started from this stage because it has the most complex calldata, and getting other stage passed could look like minor tweaking in the calldata (this is what I expected, I believe it was a right decision).&lt;/p&gt;

&lt;p&gt;In stage4, we need to write a bytecode that returns public key which has first byte as zero.&lt;/p&gt;

&lt;p&gt;Okay, but for that we need a public key, and for that we need a wallet/private key in order to be the tx.origin.&lt;/p&gt;

&lt;p&gt;I’ll just use ethers.js in my terminal (using &lt;a href="https://github.com/zemse/ethers-repl" rel="noopener noreferrer"&gt;ethers-repl&lt;/a&gt;) to get a wallet real quick. You can use anything which gets the job done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sohamzemse&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;MacBook&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Pro&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRandom&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x9b067b56552d3369e7762f0f92051db20a2db034e8e9fc803a71e64ae5b163b4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x0400a86410b6215c11e36c6a60d02277415f69393b692b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a68452a4311cc7238d7431fa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the public key here has a &lt;code&gt;0x04&lt;/code&gt; prefix byte, which is to signify that this is an uncompressed ECDSA public key. The actual public key follows after the prefix byte.&lt;/p&gt;

&lt;p&gt;Now we need a code that creates contract with the public key as the bytecode. It's pretty opinionated, you can use solidity/yul/vyper/huff/etk/whatever. I happen to be an evm nerd and I was in a hurry, so couldn't stop myself from writing down the following raw evm code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vim lockbox_stage4.evm
=========lockbox_stage4.evm========================
push1 0x40 // 64 bytes
dup1
push1 0xb // offset in this code
push1 0 // offset in memory
codecopy
push1 0
return
// public key
00a86410b6215c11e36c6a60d02277415f69393b692b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a68452a4311cc7238d7431fa
===================================================

$ evm-run lockbox_stage4.evm
code 604080600B6000396000f300A86410B6215C11E36C6A60D02277415F69393B692B6799805EE75969DF78D25398733FC3E0438BBCBB9E37FA1FF5DA79660324A68452A4311CC7238D7431FA
Returned: 00a86410b6215c11e36c6a60d02277415f69393b692b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a68452a4311cc7238d7431fa
gasUsed: 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm using &lt;a href="https://github.com/zemse/evm-run" rel="noopener noreferrer"&gt;evm-run&lt;/a&gt; for assembling + running evm code. (Sidenote: you can checkout &lt;a href="https://github.com/quilt/etk" rel="noopener noreferrer"&gt;ETK&lt;/a&gt; which helps with labels as well). &lt;/p&gt;

&lt;p&gt;We can see that the bytecode on execution spits out the public key in the returndata (so that it becomes the contract bytecode). Okay, so we got the code that should be passed as to the first input &lt;code&gt;a&lt;/code&gt;. And in case of &lt;code&gt;b&lt;/code&gt; we can pass anything, we can just use empty bytes for now i.e. &lt;code&gt;0x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now it's time to encode the calldata that should work with stage4. Notice that ethers.js strictly requires &lt;code&gt;"0x"&lt;/code&gt; prefix, so we have to add that at the start of the bytecode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaultAbiCoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bytes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bytes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x604080600B6000396000f300A86410B6215C11E36C6A60D02277415F69393B692B6799805EE75969DF78D25398733FC3E0438BBCBB9E37FA1FF5DA79660324A68452A4311CC7238D7431FA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004b604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b692b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a68452a4311cc7238d7431fa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;wordify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000040&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00000000000000000000000000000000000000000000000000000000000000c0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;solve()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting all of this together, I'm locally using hardhat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// use the private key we generated earlier (for public key to have first byte zero)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x9b067b56552d3369e7762f0f92051db20a2db034e8e9fc803a71e64ae5b163b4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// fund this wallet with some eth to pay for tx fees&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hardhatAccount0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigners&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hardhatAccount0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseEther&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// we are not using the usual abi encoding tools, because this challenge involves manipulating the calldata to make the all stages passed&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;gasLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// pass some huge gas limit, bcz estimate has some issues&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000040&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00000000000000000000000000000000000000000000000000000000000000c0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now execute the tx, and you should see stage4 pass. I’m using Hardhat framework to view the execution trace, using the &lt;a href="https://github.com/zemse/hardhat-tracer" rel="noopener noreferrer"&gt;hardhat-tracer&lt;/a&gt; plugin. (Sidenote: A great alternative is using &lt;a href="https://github.com/foundry-rs/foundry" rel="noopener noreferrer"&gt;Foundry&lt;/a&gt; and it also has tracing built-in).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqy97yq9n2cxk6fob32p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqy97yq9n2cxk6fob32p.png" alt="Screenshot of execution trace generated using hardhat-tracer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The stage4 is highlighted in the screenshot above, you can see that rest of the stages fail with empty revert data as &lt;code&gt;UnknownError&lt;/code&gt;, while there is no error in case of stage4.&lt;/p&gt;

&lt;p&gt;Stage4 done, now lets get others!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Solve Stage 2
&lt;/h2&gt;

&lt;p&gt;The actual condition in the code first checks if the value is greater than or equal to one and then goes into a for-loop that requires &lt;code&gt;word % j != 0&lt;/code&gt; for all &lt;code&gt;2 &amp;lt;= j &amp;lt; word&lt;/code&gt;. This step basically translates to the requirement of the first 4 words to be a prime number or 1 and the number cannot be huge, otherwise the for loop will go out of gas.&lt;/p&gt;

&lt;p&gt;Okay, lets look at our calldata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000040&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[0]&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000000000000000000000000000000000000000000000000000000000c0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[1]&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[2]&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[3]&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can clearly see that arr[3] is huge. Also note that the first three words are not prime numbers either. We need to fix this. &lt;/p&gt;

&lt;p&gt;Let’s see how dynamic types are encoded in the case of &lt;code&gt;(bytes a, bytes b)&lt;/code&gt;. The first word contains the location where content of &lt;code&gt;a&lt;/code&gt; starts. And second word contains the location where content of &lt;code&gt;b&lt;/code&gt; starts. This means we can move the content of &lt;code&gt;a&lt;/code&gt; anywhere we want.&lt;/p&gt;

&lt;p&gt;One easy idea is to simply move the data bit forward, by two words, in order to have arr[3] to take a value that’s within iterative limits as well as making arr[2] and arr[3] independent of the byte strings. So basically we can put any kind of stuff we want over there, the contract be won’t bothered about it at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000080&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[0], changed from 0x40 to 0x80 (+0x40)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000100&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[1], changed from 0xc0 to 0x100 (+0x40)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[2] (just inserted)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[3] (just inserted)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have inserted two words just after the first two words. We can put anything there, but having &lt;code&gt;1&lt;/code&gt; in there, simply works for now.&lt;/p&gt;

&lt;p&gt;Also we need the first two words to be a prime number. So the first two words are &lt;code&gt;0x80&lt;/code&gt; (128) and &lt;code&gt;0x100&lt;/code&gt; (256). Let's see some prime numbers just after them (so we can push them bit further). We know 131 and 257 are primes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000083&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[0], changed from 0x80 to 0x83 (+0x03)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000101&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[1], changed from 0x100 to 0x101 (+0x01)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[2]&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// arr[3]&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// a is moved further by 3 bytes&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// b is moved further by 1 byte&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now with this, we can see Stage2 passes! Following is a screenshot of trace generated on hardhat using hardhat-tracer, and the delegate call to stage2 is highlighted for visibility, we can see it does not revert.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmb7dkzgbxxt5hvhan4q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmb7dkzgbxxt5hvhan4q.png" alt="Terminal screenshot of stage2 passing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ah, finally stage2 passed! Actually, we've done a lot so far. Pads on the back!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Solve Stage3
&lt;/h2&gt;

&lt;p&gt;Here, a static call is made to &lt;code&gt;a + b&lt;/code&gt;, which in our case currently it's &lt;code&gt;0x83 + 0x101 = 0x184&lt;/code&gt;. That's definitely not a precompile address atm, can be checked by making an eth_call.&lt;/p&gt;

&lt;p&gt;If it's not a precompile, then the static call would still success, however result would be empty data. And this stage requires that the third word should equal to the length of the return data. &lt;/p&gt;

&lt;p&gt;The third word can be anything only that stage2 restricts the third word to a non-zero value (1 or prime). It means there should be some return data. But how? We definitely cannot deploy a contract at an address with so many zeros! So it means the &lt;code&gt;a + b&lt;/code&gt; needs to be a precompile for this to work.&lt;/p&gt;

&lt;p&gt;I couldn't find an up-to-date list of precompiles, had to look into client implementations. Here is the list in &lt;a href="https://github.com/ethereumjs/ethereumjs-monorepo/blob/ffe3402a69e04f48654f13127becf86a8a46485a/packages/evm/src/precompiles/index.ts" rel="noopener noreferrer"&gt;EthereumJS/EVM&lt;/a&gt;. We can clearly see precompiles are only upto 0x12. Also the return data length should be a prime number, when called with empty data. We can just try this using &lt;code&gt;eth_call&lt;/code&gt;. For that, I'm quickly jumping into ethers-repl on my terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x0000000000000000000000000000000000000012&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// {"jsonrpc":"2.0","id":44,"error":{"code":-32602,"message":"invalid 1st argument: transaction 'data': value was too short"}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Couldn't really find any precompile that works with empty calldata and gives a return data with prime length. It means we cannot use a precompile. After playing around a bit, it was fairly convincing that forget prime length return data, there is no way this static call could return a non-zero length return data.&lt;/p&gt;

&lt;p&gt;But wait, didn't we just eliminated all the possibilities? Is this challenge even solvable? &lt;/p&gt;

&lt;p&gt;&lt;em&gt;*Looks at the scoreboard, single integer number of people have solved it*&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Okay, means definitely there's some advanced stuff going on here and something is missing in my observations.&lt;/p&gt;

&lt;p&gt;Oh! could it be related to that weird &lt;code&gt;mstore(a, b)&lt;/code&gt; which I believed it was there for no reason. Hmm, after a careful observation, I could see that we do not need to have the static call return a data with prime length, the check is &lt;code&gt;data.length == c&lt;/code&gt;, where &lt;code&gt;data.length&lt;/code&gt; is taken from memory. So we have to use the &lt;code&gt;mstore(a, b)&lt;/code&gt; to write at a location and manipulate the value of &lt;code&gt;data.length&lt;/code&gt;. To know where in the memory &lt;code&gt;data.length&lt;/code&gt; is, I'm just using hardhat-tracer to print MLOAD operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx hardhat &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--trace&lt;/span&gt; &lt;span class="nt"&gt;--opcodes&lt;/span&gt; MLOAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12h46gbvl0hb77t60orj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12h46gbvl0hb77t60orj.png" alt="Terminal screenshot of display of MLOAD opcodes during the execution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we can see after the static call to the &lt;code&gt;0x00..184&lt;/code&gt; address, there is an MLOAD at location 0x60 for reading &lt;code&gt;data.length&lt;/code&gt;. Memory location 0x60 is a special one because it always points to zero, it's used as the initial value for dynamic memory arrays when they are empty (&lt;a href="https://docs.soliditylang.org/en/latest/internals/layout_in_memory.html#layout-in-memory" rel="noopener noreferrer"&gt;source&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;mstore(a, b)&lt;/code&gt; is done before the declaration of &lt;code&gt;bytes memory data&lt;/code&gt;. And since the return data is empty, solidity uses 0x60 as the location for the &lt;code&gt;data&lt;/code&gt; variable. Solidity docs mention that this memory slot should not be written to, since it'd cause empty arrays to assume non-zero length. This helps us!&lt;/p&gt;

&lt;p&gt;Now comes another tricky part, we have to figure out how to rearrange our calldata. I'm reverting our calldata changes back to step3 initial, and then moving it further by one word (instead of two words as we previously did). We have to do this because the &lt;code&gt;mstore(a, b)&lt;/code&gt; writes at memory slot &lt;code&gt;a&lt;/code&gt;, and we want it to be &lt;code&gt;0x60&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000060&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 0x40 to 0x60&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000000000000000000000000000000000000000000000000000000000e0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 0xc0 to 0xe0&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// inserted here&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, but what about previous stage where these first 4 words need to be primes? We might slightly change them. We know that 0x61 and 0xe3 is a prime. So let's change the first two words to ensure they are prime. That will require shifting the content of towards right by one byte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000061&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 0x60 to 0x61&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000000000000000000000000000000000000000000000000000000000e3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 0xe0 to 0xe3&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// keeping this 1&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000000000000000000000000000000000000000000000000000000000004b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// one byte extra here&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// three bytes extra here&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, you can see that 4th word is zero. Previously it was length of the byte string &lt;code&gt;a&lt;/code&gt; in stage4. Since the length was under 1 byte, the 4th word became zero. Just to recall, byte string &lt;code&gt;a&lt;/code&gt; is the creation code of a contract that gets deployed in stage4. Is there a way we can increase the length, by adding some redundant code without affecting behaviour?&lt;/p&gt;

&lt;p&gt;Turns out that the answer is yes, we can! This is the evm code we previously used. The current code length is 0x4b, and we want it to exceed 0x100, so that the "1" gets in the 4th word.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;wordify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mh"&gt;0x4b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can just put the above zeros after our bytecode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push1 0x40 // 64 bytes
dup1
push1 0xb // offset in this code
push1 0 // offset in memory
codecopy
push1 0
return
// public key
00a86410b6215c11e36c6a60d02277415f69393b692b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a68452a4311cc7238d7431fa
// add any code after this, it is not used
// redundant code which makes bytecode length 0x100
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000

===================================================

$ evm-run lockbox_stage4.evm
code 604080600B6000396000f300A86410B6215C11E36C6A60D02277415F69393B692B6799805EE75969DF78D25398733FC3E0438BBCBB9E37FA1FF5DA79660324A68452A4311CC7238D7431FA00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Returned: 00a86410b6215c11e36c6a60d02277415f69393b692b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a68452a4311cc7238d7431fa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have to repeat the steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bytecode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;604080600B......00000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// paste here&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;hexDataLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytecode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="c1"&gt;// this is 0x100&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaultAbiCoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bytes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bytes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bytecode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;wordify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000040&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000160&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have to now repeat the steps similar to previous. I'll just paste the updated calldata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x890d6908&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 4 byte selector for solve() method&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000061&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 0x60 to 0x61&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000161&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 0x160 to 0x161&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// keeping this 1&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000000000000000000000000000000000000000000000000000000000000100&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// one byte extra here&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;604080600b6000396000f300a86410b6215c11e36c6a60d02277415f69393b69&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2b6799805ee75969df78d25398733fc3e0438bbcbb9e37fa1ff5da79660324a6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8452a4311cc7238d7431fa000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000000000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that here, 0x161 is written to memory location 0x61, which basically writes 1 to the 0x60 word (data.length memory slot), the rest 61 is written to next slot and it does not matter.&lt;/p&gt;

&lt;p&gt;Now we've got stage1, stage2, stage3, stage4 passing, only stage5 is failing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tmxljmg8p2pw2ly97fe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tmxljmg8p2pw2ly97fe.png" alt="Terminal screenshot of first 4 stages passing, while stage 5 failing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Solve Stage 5
&lt;/h2&gt;

&lt;p&gt;This stage makes a call to the solve() method again, and in the trace above, we can see everything passes but only the stage5 check, which wants the solve() invocation from stage5 to fail.&lt;/p&gt;

&lt;p&gt;It's based on the fact that when an execution context makes a CALL, it can at max give 63/64 of the gas available. We have to carefully pass a value of &lt;code&gt;gasLimit&lt;/code&gt; such that when 63/64 of the gas available is passed to the solve() internal message call, it's not enough for it and it goes out of gas. That only fails the internal msg call, and 1/64 gas is available for the stage5's execution context to proceed. After trying for some values, I found &lt;code&gt;560_000&lt;/code&gt; to be just enough to work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslq23oxyd6vsjruxorso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslq23oxyd6vsjruxorso.png" alt="Terminal screenshot of all stages of challenge solved"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yay! The challenge is solved! &lt;/p&gt;

&lt;p&gt;Se* is cool but have you ever tried catching a flag :P&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgfpjqgalusrkwx078iw1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgfpjqgalusrkwx078iw1.jpg" alt="The feeling when you catch the flag"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned to &lt;a href="https://twitter.com/paradigm_ctf" rel="noopener noreferrer"&gt;@paradigm_ctf&lt;/a&gt; for the future editions. Hopefully, we’ll see Lockbox3!&lt;/p&gt;

&lt;p&gt;Also, if you made this far, thanks! Btw I’m Soham, and I mostly do open-source contributions to some ethereum dev tools. As a disclosure: hardhat-tracer, evm-run, ethers-repl mentioned above are some of my github projects. Oh yeah, also I'm attending my first Devcon this year as a Devcon Scholar, would love to meet if you are coming too! Looking forward to buidl more stuff. My social links: &lt;a href="https://github.com/zemse" rel="noopener noreferrer"&gt;github&lt;/a&gt;, &lt;a href="https://twitter.com/0xZemse" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>EthersJS - Signing EIP712 Typed Structs</title>
      <dc:creator>zemse</dc:creator>
      <pubDate>Fri, 18 Jun 2021 05:13:23 +0000</pubDate>
      <link>https://forem.com/zemse/ethersjs-signing-eip712-typed-structs-2ph8</link>
      <guid>https://forem.com/zemse/ethersjs-signing-eip712-typed-structs-2ph8</guid>
      <description>&lt;p&gt;Heya! In this post we're going to go a quick look into using EthersJS API for the &lt;a href="https://eips.ethereum.org/EIPS/eip-712"&gt;EIP712 standard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, before we dive in, I would like to point out that if your use case is simple as a single message, you likely do not need to complicate it with EIP712. You can simply use &lt;code&gt;signer.signMessage("hello")&lt;/code&gt; API (EIP191). While if you have multiple values (like complex structs) to sign, then EIP712 can be useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up signer
&lt;/h2&gt;

&lt;p&gt;Consider a use case where a user want to sign a complex struct. They also need to include a signature to prove that they own the private keys of an account containing some funds.&lt;/p&gt;

&lt;p&gt;You can use Metamask. But if you're just trying for demo, you can just generate a random wallet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metamaskProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;metamaskProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSigner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// or&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Defining Domain Separator
&lt;/h2&gt;

&lt;p&gt;Now we define our domain separator. This is useful for the case when there is a fork/clone of your app on your chain or even a different one, and some user using both the apps. The domain separator ensures different signatures for same messages by same user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;verifyingContract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x1111111111111111111111111111111111111111&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Defining Struct Types
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Mail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;from&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Signing struct objects
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x2111111111111111111111111111111111111111&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x3111111111111111111111111111111111111111&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To sign the above struct, we use &lt;code&gt;_signTypedData&lt;/code&gt; method on the signer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_signTypedData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 0x74ff2b1850dfa49f825a29760cf7f8194465190481afb49dd81f0ef7783d7b9638180110bdbf5d85ab8d9f39d2d4f4bc63f017c5b53e90bf915cf22c2b7125901b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This contains an underscore prepend because of the fact that it's recently introduced and is is in public beta. Once enough confidence in it, it will be moved out of beta by renaming to &lt;code&gt;signTypedData&lt;/code&gt; (don't worry the underscore alias will also exist for backwards compatibility).&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying signatures
&lt;/h2&gt;

&lt;p&gt;You can use the &lt;code&gt;verifyTypedData&lt;/code&gt; util to verify if a given signature is valid.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedSignerAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recoveredAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verifyTypedData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recoveredAddress&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;expectedSignerAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;That's pretty much it for this post. To summarise, we saw &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to define a domain separator&lt;/li&gt;
&lt;li&gt;struct types&lt;/li&gt;
&lt;li&gt;signing our struct object&lt;/li&gt;
&lt;li&gt;verifying a given signature&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ethers</category>
      <category>eip712</category>
      <category>signature</category>
      <category>ethereum</category>
    </item>
  </channel>
</rss>
