Trustless ADA ↔ shielded ZEC atomic swaps: open-source research, looking for someone to pick it up

Open for pickup: an Aiken escrow (v0.7) for trustless ADA ↔ shielded ZEC swaps (simulator-tested, never tested on chain)

Hi Cardano devs,

I’ve been researching zeUTXO, a trustless atomic swap between ADA and shielded Zcash. I’m stepping back now and opening the repo for anyone who wants to continue it or reuse parts.

Repo: GitHub - maybejb200/zeUTXO-zcash-cardano-atomic-swap: Research prototype: trustless private atomic swap between shielded Zcash and Cardano using adaptor signatures, cross-group DLEQ and an Aiken escrow (simulator only, paused) · GitHub (MIT OR Apache-2.0). Start with HANDOFF.md.

The hook: one PlutusV3 escrow that holds all the clocks

The Cardano side is a single Aiken escrow, v0.7 (PlutusV3, about 2.4 KB, script hash 0ed9e0540ff4f40ccf3ccad91efaf9663d0feb4a6b5cad63700087e0). The Zcash side has no timelocks. Alice locks ADA; Bob funds a shielded note to a 2-of-2 joint key. Whoever learns the other’s share takes the ZEC, so Cardano never verifies Zcash: no light client, relay or oracle.

The escrow’s state machine:

  • Two-step claim: Commit{go_sig} moves Open → Claimed. It checks Alice’s Ed25519 “go” signature (bound to swap id, script hash, outref, amount and T1) and carries no secret. Then Reveal{b} checks b·G1 == b_c on BLS12-381 and pays Bob. If Bob commits and stalls, Escape after T3 returns the ADA to Alice.
  • Two-step refund: Notice moves Open → Refunding and writes t4 into the datum. It carries no secret. Then RefundReveal{a} returns the ADA to Alice. If she never reveals, Forfeit after t4 pays Bob.
  • The invariant: no secret-carrying redeemer has a deadline, and no deadline-bound redeemer carries a secret. That’s what defeats the “censor the reveal until the timeout” attacks.
  • Each spend has exactly one escrow input. Continuing outputs keep the same address and value, a byte-equal inline datum, and no reference script.

A cross-group DLEQ proof (Pallas ↔ BLS12-381 G1) ties the shares committed in the datum to the Zcash key.

Honest status

This is simulator-only. Local tests suggest it might be possible, but it has never been tested on chain. No preprod or testnet swap has run.

  • aiken check: 71/71 (76 with extra review tests). The included CI workflow rebuilds the escrow with Aiken v1.1.24 and checks that it’s byte-identical to the committed plutus.json and its pinned hash.
  • The end-to-end simulator (Lucid Evolution emulator plus a stricter ledger wrapper) passes 727/727 checks in two parameter profiles.
  • Seven internal adversarial reviews; none is an independent audit.
  • A testnet rehearsal on preprod + Zcash testnet was started on Nov 9–11 but never reached a swap. The Zcash node I was running kept stalling and never finished syncing.

Where Cardano folks could help

  • Running the rehearsal on preprod and checking things the emulator can’t: validity-interval and slot rounding on the Notice (fixed in code, emulator-tested only), and map-encoded redeemers in Conway transactions.
  • Writing a small live-run driver around the existing Lucid Evolution / Koios off-chain code.
  • Reviewing the escrow itself. An independent review of escrow.ak would be very welcome.
  • Review 6 suggested an in-escrow refundable deposit, which would change the script.

If this is at all interesting, I’d love to hear about it.

— John (maybejb200)

1 Like