Merkle Library

Merkle trees allow for on-chain verification of off-chain data. With the merkle root posted on-chain, the generation of proofs off-chain can provide verifiably true data.

For implementation details on the Merkle Library please see the Sway Libs Docs.

Importing the Merkle Library

In order to use the Merkle Library, Sway Libs must be added to the Forc.toml file and then imported into your Sway project. To add Sway Libs as a dependency to the Forc.toml file in your project please see the Getting Started.

To import the Merkle Library to your Sway Smart Contract, add the following to your Sway file:

use sway_libs::merkle::binary_proof::*;

Using the Merkle Proof Library In Sway

Once imported, using the Merkle Proof library is as simple as calling the desired function. Here is a list of function definitions that you may use.

  • leaf_digest()
  • node_digest()
  • process_proof()
  • verify_proof()

Basic Functionality

Computing Leaves and Nodes

The Binary Proof currently allows for you to compute leaves and nodes of a merkle tree given the appropriate hash digest.

To compute a leaf use the leaf_digest() function:

fn compute_leaf(hashed_data: b256) {
    let leaf: b256 = leaf_digest(hashed_data);
}

To compute a node given two leaves, use the node_digest() function:

fn compute_node(leaf_a: b256, leaf_b: b256) {
    let node: b256 = node_digest(leaf_a, leaf_b);
}

NOTE Order matters when computing a node.

Computing the Merkle Root

To compute a Merkle root given a proof, use the process_proof() function.

fn process(key: u64, leaf: b256, num_leaves: u64, proof: Vec<b256>) {
    let merkle_root: b256 = process_proof(key, leaf, num_leaves, proof);
}

Verifying a Proof

To verify a proof against a merkle root, use the verify_proof() function.

fn verify(
    merkle_root: b256,
    key: u64,
    leaf: b256,
    num_leaves: u64,
    proof: Vec<b256>,
) {
    assert(verify_proof(key, leaf, merkle_root, num_leaves, proof));
}

Using the Merkle Proof Library with Fuels-rs

To generate a Merkle Tree and corresponding proof for your Sway Smart Contract, use the Fuel-Merkle crate.

Importing Into Your Project

The import the Fuel-Merkle crate, the following should be added to the project's Cargo.toml file under [dependencies]:

fuel-merkle = { version = "0.50.0" }

NOTE Make sure to use the latest version of the fuel-merkle crate.

Importing Into Your Rust File

The following should be added to your Rust file to use the Fuel-Merkle crate.

use fuel_merkle::binary::in_memory::MerkleTree;

Using Fuel-Merkle

Generating A Tree

To create a merkle tree using Fuel-Merkle is as simple as pushing your leaves in increasing order.

    // Create a new Merkle Tree and define leaves
    let mut tree = MerkleTree::new();
    let leaves = ["A".as_bytes(), "B".as_bytes(), "C".as_bytes()].to_vec();

    // Hash the leaves and then push to the merkle tree
    for datum in leaves.iter() {
        let mut hasher = Sha256::new();
        hasher.update(&datum);
        let hash = hasher.finalize();
        tree.push(&hash);
    }

Generating And Verifying A Proof

To generate a proof for a specific leaf, you must have the index or key of the leaf. Simply call the prove function:

    // Define the key or index of the leaf you want to prove and the number of leaves
    let key: u64 = 0;

    // Get the merkle root and proof set
    let (merkle_root, proof_set) = tree.prove(key).unwrap();

    // Convert the proof set from Vec<Bytes32> to Vec<Bits256>
    let mut bits256_proof: Vec<Bits256> = Vec::new();
    for itterator in proof_set {
        bits256_proof.push(Bits256(itterator.clone()));
    }

Once the proof has been generated, you may call the Sway Smart Contract's verify_proof function:

    // Create the merkle leaf
    let mut leaf_hasher = Sha256::new();
    leaf_hasher.update(&leaves[key as usize]);
    let hashed_leaf_data = leaf_hasher.finalize();
    let merkle_leaf = leaf_sum(&hashed_leaf_data);

    // Get the number of leaves or data points
    let num_leaves: u64 = leaves.len() as u64;

    // Call the Sway contract to verify the generated merkle proof
    let result: bool = contract_instance
        .methods()
        .verify(
            Bits256(merkle_root),
            key,
            Bits256(merkle_leaf),
            num_leaves,
            bits256_proof,
        )
        .call()
        .await
        .unwrap()
        .value;
    assert!(result);