Verkle trees are commitment schemes that work similarly to Merkle trees, but with much fewer witnesses. It works by replacing the hashes of the Merkle tree with vector commits, which makes wider branch elements more efficient.
Thanks to Kevaundray Wedderburn for his feedback on the post.
outline
For more information about how buckle trees work, see:
The purpose of this post is to describe the specific layout. Draft Buckle Tree EIP. It is aimed at client developers who have implemented Verkle Tree and want an introduction before delving deeper into EIP.
Verkle trees bring many changes to the tree structure. The most important changes are:
- Converting from 20-byte keys to 32-byte keys (not to be confused with 32-byte addresses, which is a separate change)
- Attempting to merge accounts and repositories; And finally
- Verkle Trie itself is introduced, which uses vector commits instead of hashes.
As a vector commit approach for Verkle trees we use: Pedersen’s promise. Pedersen’s promise is based on elliptic curves. For an introduction to the Pedersen commitment and how to use it as a polynomial or vector commitment using the dot product argument, see: here.
The curve we use is Bandersnatch. This curve was chosen because it performs well and allows efficient SNARKs in BLS12_381 to infer about future buckle trees. This can be useful for rollups as well as allowing upgrades where all witnesses can be compressed into one SNARK without additional commit updates.
Bandersnatch’s curve order/scalar field size is: p = 13108968793781547619861935127046491459309155893440570251786403306729687672801, which is a 253-bit prime number. As a result, only bit strings of up to 252 bits can be safely committed. Otherwise the field will overflow. We chose a branch factor (width) of 256 for the verkle tree. This means that each commit can commit up to 256 values of 252 bits each (up to 256 integers, to be exact). blood – 1). We write this as: commit(v₀, v₁, …, v₂₅₅) To commit to a list V The length is 256.
Layout of Buckle Tree
One of the design goals of buckle tree EIPs is to make access to adjacent locations (e.g. repositories or adjacent code chunks with nearly identical addresses) inexpensive. For this, the key consists of: stem 31 bytes and suffix 1 byte is a total of 32 bytes. The key scheme is designed so that “close” storage locations map to the same stem and different suffixes. For more information, see: EIP draft.
The Verkle tree itself consists of two types of nodes:
- expansion nodeIt represents 256 values with the same stem but different suffixes.
- internal nodeIt has a maximum of 256 child nodes and can be other internal nodes or extension nodes.
A promise to an expansion node is a promise to a four-element vector. The remaining positions will be 0. This is as follows:
C₁ and C₂ are two additional promises that promise any value with the following stems: stem. The reason we need two promises is because the value is 32 bytes, but we can only store 252 bits per field element. Therefore, a single commitment is not enough to store 256 values. So instead, C₁ stores values from the suffixes 0 through 127, and C₂ stores values from 128 through 255. Here the value is split in two to fit the field size (we’ll explain later).
The extension along with the C₁ and C₂ promises is called “Extension and Suffix Tree” (EaS for short).
Figure 1 It represents the process of going through the buckle tree to find the key. 0xfe0002abcd..ff04: The path passes through three internal nodes, each with 256 children (254, 0, 2), with one extended node representing: abcd..ff Two suffix tree promises containing values for 04, v₄. please refer to this stem This is actually the first 31 bytes of the key, including the path through internal nodes.
Commitment to Value Leaf Nodes
Each expansion and suffix tree node contains 256 values. The value is 256 bits wide, and only 252 bits can be safely stored in one field element, so if you simply try to store one value in one field element, you will lose 4 bits.
To circumvent this problem, we decided to split the group of 256 values into two groups of 128 values each. Each 32-byte value in the group is split into two 16-byte values. Therefore, the value of vᵢ∈ 𝔹₃₂ changes to v⁽ˡᵒʷᵉʳ⁾ᵢ ∈ 𝔹₁₆ and v⁽ᵘᵖᵖᵉʳ⁾ᵢ∈ 𝔹₁₆, making v⁽ˡᵒʷᵉʳ⁾ᵢ ++ v⁽ ᵘᵖᵖᵉʳ⁾ᵢ=vᵢ.
A “leaf marker” is added to v⁽ˡᵒʷᵉʳ⁾ᵢ to distinguish between leaves that have never been accessed and those that have been overwritten with zeros. No values are deleted from the buckle tree.. This is required for future status expiration planning. The marker is set at the 129th bit. That is, v⁽ˡᵒʷᵉʳ ᵐᵒᵈⁱᶠⁱᵉᵈ⁾ᵢ = v⁽ˡᵒʷᵉʳ⁾ᵢ + 21²⁸ If vᵢ has been previously accessed, then v⁽ˡᵒʷᵉʳ ᵐ ᵒᵈⁱᶠ ⁱᵉᵈ⁾ᵢ = 0 if vᵢ has never been accessed.
The two promises C₁ and C₂ are defined as follows:
The Promise of Expansion Nodes
Commitments to an expansion node require an “expansion marker” with the number 1, two subtree commitments C₁ and C2, stem This is the key that leads to this expansion node.
Unlike the extended nodes of a Merkle-Patricia tree, which contain only key sections connecting parent internal nodes to child internal nodes, the stem contains the entire key up to that point. This is because Buckle Tree was designed with stateless proofs in mind. When a new key is inserted that “splits” the extension in two, its older siblings do not need to be updated, allowing for smaller proofs.
Internal Node Promises
Internal nodes have a simpler computational method for promises. A node is represented as a vector of 256 values, which are the root appointments (field representations) of each of the 256 subtrees. Commitment to empty subtrees is 0. If the subtree is not empty, the commitments for internal nodes are:
Here Cᵢ is the child of the internal node, and is 0 if the child is empty.
insert into tree
Figure 2 shows the process of inserting a new value into the tree. This gets interesting when stems collide on multiple initial bytes.
Figure 2 The v₁₉₂ value is inserted at the location. 0000010000…0000 Buckle tree containing only v₁₂₇ values at position 0000000000…0000. Since the stem is different in the third byte, two internal nodes are added until another byte is reached. Then another “expand and suffix” tree is inserted, with a full 31-byte stem. The initial node remains intact and C²₀ has the same value as C⁰₀ before the insertion.
Shallower trees, less evidence.
The buckle tree structure creates a shallower tree, reducing the amount of data stored. But its true power comes from its ability to generate smaller pieces of evidence: witnesses. This will be explained in the next article.