An Introduction to Webb’s Systems 1: v0.1 Privacy-Preserving Cross-Chain Asset Transfers

Welcome to Part 1 of a three-part introduction series to Webb’s systems. In this article, we'll explore Webb’s system for cross-chain asset transfers.

An Introduction to Webb’s Systems 1: v0.1 Privacy-Preserving Cross-Chain Asset Transfers

The Webb UTXO System:
A Privacy-Preserving Cross-Chain Asset Transfer System

Welcome to Part 1 of a three-part introduction series to Webb’s systems. In this article, we'll explore Webb’s system for cross-chain asset transfers. Part 2 will delve into Webb’s cross-chain identity systems, and Part 3 will combine the knowledge from the previous parts to describe an identity-based cross-chain asset transfer system.

To understand Webb’s UTXO system, you should be familiar with Merkle trees and the UTXO model. A 'transaction' refers to depositing into, withdrawing out of, and transferring funds within the Webb system. The UTXO model is employed to track user balances. The invariant that any transaction must maintain is:

sum of input UTXO amounts + public amount = sum of output UTXO amounts

The public amount is positive when a deposit occurs and negative when a withdrawal occurs. When the public amount is zero, the total funds locked in the Webb system remain unchanged, although the funds may change owners.

Unpacking the Webb UTXO Data Structure

A UTXO typically consists of a pair (public key, amount), indicating that the person possessing the private key corresponding to the public key has the right to spend the specified number of coins amount. In the Webb system, a destination chain Id is added to the UTXO data structure, representing the chain Id where the UTXO will be spent. For added security, a randomly generated secret blinding value is included in the UTXO. The Webb UTXO looks like this:

webb_utxo = {public key, amount, destination chain Id, blinding}

Privacy-Preserving Cross-Chain Asset Transfers via Sets of Linked Merkle Trees and Zero-Knowledge Proofs

Webb’s systems function through sets of linked Merkle trees. A set of linked Merkle trees is a collection of Merkle trees, each maintaining a list of the Merkle roots of the other trees in the set.


Suppose we have a set of three linked Merkle trees, each located on a separate blockchain (say blockchains A, B, C, and D). We will demonstrate how to use these linked Merkle trees to perform privacy-preserving cross-chain asset transfers. If a user wants to transfer assets from chain A to chain B, they will:

  • Conduct a deposit transaction on chain A. This locks the deposited funds in chain A and creates a corresponding webb_utxo. To preserve privacy, only a commitment Poseidon(webb_utxo) is publicly revealed, where Poseidonis a zero-knowledge friendly hash function. The commitment is added to the linked Merkle tree on chain A.
  • The user then proves in zero-knowledge on chain B that they know a webb_utxo and a Merkle proof, such that Poseidon(webb_utxo) is a commitment in one of a set of linked Merkle trees. Upon verification of this proof, chain B releases funds to the user and generates the corresponding webb_utxos. Importantly, the zero-knowledge proof does NOT reveal:
  • The webb_utxo.
  • The exact Merkle tree/root/path corresponding to the commitment.
  • Whether the deposit occurred on chain A, B, C, or D.

Preventing Double Spending via Nullifiers

What prevents a user from spending the same webb_utxo twice? The answer is nullifiers. Each UTXO has a nullifier associated with it, given by:

Poseidon(commitment, merklePath, Poseidon(privKey, commitment, merklePath))

When a webb_utxo is spent, the user has to provide this nullifier, which is then publicly stored on-chain. The chain where the withdrawal is occurring also verifies in zero-knowledge that the nullifier truly is what it’s supposed to be and not some bogus value. If a user tries to spend the same webb_utxo , they will have to submit the same nullifier. Since the chain publicly stores used nullifiers, it will easily detect that the user is trying to double spend.

Relaying Merkle Root Information and Decentralizing Trust

One question the curious reader may be wondering about is how Merkle trees on different blockchains maintain Merkle root information about each other. Currently, this is done via a system of relayers that listen for Merkle root updates and relay them across chains. However, the major flaw in the current system is that malicious relayers can submit and approve invalid Merkle roots. This is a problem because it may allow people to withdraw money that they never deposited.

To decentralize trust away from the relayers, a light client system is currently being implemented for validating block headers and verifying storage/account/receipt proofs about updated Merkle roots against these block headers. This is more trustless than the previous system and follows from the security of light clients.

Building Applications on Top of Webb’s Cross-Chain Asset Transfer System

Webb’s work is open source and permissionless, so anyone can build on top of it. Developers can create powerful applications that enhance privacy and security by building on top of Webb's cross-chain asset transfer system. Relevant links for their repos are:


In this article, we introduced Webb's system for privacy-preserving cross-chain asset transfers. This system uses sets of linked Merkle trees and zero-knowledge proofs to enable users to conduct cross-chain asset transfers while preserving their privacy. We also discussed how nullifiers prevent double spending and how the system relays Merkle root information across blockchains. Webb's vision is to enable trustless, decentralized, and private cross-chain communication. In the next part of this series, we will discuss Webb's system for cross-chain identity systems, and in part 3, we will combine parts 1 and 2 to describe an identity-based cross-chain asset transfer system.