Technical Deep Dive

Architecture

Technical overview of RAIL20's components, ZK circuit, and data flow.

System Overview

Data Flow

text
User (browser)
  |
  +-- 1. Generate ZK proof locally
  v
Broadcaster (relayer)
  |
  +-- 2. Validate proof + nullifier status
  +-- 3. Submit tx (broadcaster pays ETH gas)
  v
RAIL20Vault (on-chain)
  |
  +-- 4. Verify PLONK proof
  +-- 5. Check nullifier not spent
  +-- 6. Mark nullifier spent
  +-- 7. Insert new commitments
  +-- 8. Transfer B20 tokens
  v
FeeRouter
  +-- 9. Split: 50% treasury, 30% broadcaster, 20% burn

ZK Circuit Design

Single unified circuit compiled with circom 2.x, verified via PLONK (universal setup).

ParameterValue
Proof systemPLONK (universal setup)
Trusted setupHermez PTAU 2^14 (54 contributors)
Constraints5,073 non-linear + 5,409 linear
Public inputs6 (root, nullifierHash, commitments, txHash, mode)
Private inputs39
Merkle depth16 (65,536 max commitments)
Hash functionPoseidon
CurveBN254
Proof size~450 bytes (24 uint256)
Verify gas~250,000

Why PLONK over Groth16?

PLONK uses a universal trusted setup. No Phase 2 ceremony, no new toxic waste when circuit changes. Tradeoff: ~450 byte proof (vs 96) and ~20K more gas — negligible on Base L2.

Merkle Tree

16-level Poseidon tree. Append-only — spent notes tracked via nullifier mapping.

javascript
commitment = Poseidon(nullifier, secret, amount)
nullifierHash = Poseidon(nullifier)
pathElements[16]  // sibling hashes
pathIndices[16]   // 0=left, 1=right

Security Model