Back to projects
Z.U.L.U icon

Z.U.L.U

The first trustless Zcash relay on Starknet

$6,500
Total awarded
Shreyansh
Builder
Python React.js Cairo StarkNet Zcash RPC

Awards

The problem it solves

Z.U.L.U. (Zcash Unified Ledger on Starknet) - a trustless Zcash relay on Starknet

[1] the trust problem with bridges right now, if you want to bridge Zcash to any chain, you have to trust some centralized entity (multisig, MPC, whatever). they hold your funds and you just… hope they don’t rug.

solution: i built a relay that cryptographically verifies Zcash block headers directly on Starknet. no trust needed - the math proves the block is valid.

[2] zcash → starknet interoperability didn’t exist there was literally no way for a Starknet contract to know what’s happening on Zcash. zero connection between these two ecosystems.

solution: now any Starknet contract can query verified Zcash blocks. this opens up:

  • trustless bridges (verify a tx was included in a block via merkle proof)
  • cross-chain dApps that react to Zcash events
  • SPV-style payment verification

[3] equihash verification was “impossible” on-chain verifying Zcash’s proof-of-work (Equihash) on-chain is too expensive. 512 blake2b hashes per block

solution: heavily optimized the blake2b and equihash implementation in Cairo to make it actually feasible. ~15 STRK per block, ~3 minutes, fully on-chain verification.

tldr: i built the infrastructure to connect Zcash’s privacy chain to Starknet’s scaling chain - trustlessly.

Challenges we ran into

[1] the blake2b bottleneck [biggest hurdle & thanks to Starkware ecosystem team to guide and help me out]

problem : equihash requires verifying 512 indices, each needing blake2b hash & standard implementation was far too expensive (gas wise) and slow

solution : i optimized blake2b and equihash a. unrolls all 12 rounds of compression function to eliminate loop overhead

b. precomputes the equihash init state constants to skips param block construction

c. first -block caching : [biggest optimization] the first 128 bytes of the header are identical for all 512 hashes, i made a the verifier to compress this chunk once , cache the state and then reuse it. this cut compression calls by ~50%

[2] the endian-ness : little and big endian conversion this was the most annoying problem, the internal state of the block is in little endian but my program was for big endian and since there were many functions with different endian-ness expectation - it was really exhausting but i finally made all of it consistent

[3] frontend synchronization : so to showcase the inner working of this project , i had to show the backend’s step by step logs of the multi-tx

solution : i used websockets to the frontend, giving users real time visibility to the 11 tx

Gallery