Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
a8d463a
coq: scaffolding for Cairo↔Coq circuit model + drift detection
May 1, 2026
61f5cd5
coq: extract xmss_chain_step to OCaml end-to-end
May 1, 2026
3df59f5
coq: restructure to Spec/Common/Impl per expert recommendation; STATU…
May 1, 2026
b570e47
coq: prove iter_succ + iter_compose in Spec.Wots; add Impl.Wots refin…
May 1, 2026
838ec1e
Merge branch 'main' into coq-model
May 2, 2026
561ad7c
coq: re-port Rocq -> OCaml extraction onto Spec/Impl/Common layout
May 3, 2026
8bf71cf
coq: fix Spec.Wots iter proofs for Rocq 9, switch to From Stdlib
May 3, 2026
5fa903c
coq: set extraction output dir to Impl/ explicitly
May 3, 2026
5dbd94f
coq: wire Hash3/pack_adrs_chain to real OCaml port via dune driver
May 4, 2026
ce19f59
coq: add HANDOFF.md — narrative companion to STATUS.md
May 4, 2026
9f9a578
coq: Merkle verification, L-tree, WOTS recovery, XMSS verifier skeleton
May 4, 2026
67dceba
coq: L-tree totality, auth-tree walk bridge, idx range check
May 4, 2026
82ca4df
coq: WOTS+ completeness and full XMSS completeness theorem
May 4, 2026
2eaa2c8
coq: sighash fold, nullifier spec, WOTS completeness
May 4, 2026
cd8647f
coq: soundness — CR axioms, Merkle binding, unique-leaf theorem
May 4, 2026
93b8225
coq: update STATUS.md with soundness and completeness work
May 4, 2026
8b810bb
coq: XMSS soundness reduction — verified signatures imply same endpoints
May 4, 2026
2070a8a
coq: chain injectivity, per-chain binding, transfer safety predicate
May 4, 2026
9c176eb
coq: Cairo-faithful verification predicates with all three assertions
May 4, 2026
ff5c190
coq: add QCheck2 differential fuzzer for extracted chain_step
May 4, 2026
d8e25ad
coq: WOTS+ unforgeability — checksum argument mechanized
May 4, 2026
a494099
coq: formalize safety predicates for all three circuits
May 4, 2026
e1816e0
coq: gitignore .Makefile.d build artifact
May 5, 2026
1a5da5a
multiasset: spec — H_commit gains asset arg, N→4 transfer, per-asset …
May 27, 2026
d4f4ba9
multiasset spec: add phi_input_wellformed and phi_output_lists_parallel
May 27, 2026
771c318
multiasset spec: assemble Phi_{transfer,shield,unshield} + sanity lemmas
May 27, 2026
72a1993
multiasset Phase A: thread asset arg through commit() (Cairo + Rust)
May 27, 2026
cf5147b
multiasset Phase A: regenerate fixtures for new commit() arity
May 27, 2026
91bb10a
multiasset Phase B: per-asset balance + asset witness fields (transfer)
May 27, 2026
0d98cb0
multiasset Phase B: per-asset balance + asset witness fields (shield)
May 27, 2026
e085cee
multiasset Phase B: per-asset balance + asset witness fields (unshield)
May 27, 2026
907cb8b
multiasset Phase D: whitepaper §Multiasset + per-section updates
May 27, 2026
dc64b77
multiasset Phase C: N→4 transfer layout (Cairo + Rust sighash)
May 27, 2026
84d13b9
multiasset Phase C: 2 change slots in unshield (Cairo + Rust sighash)
May 27, 2026
a01bdf6
multiasset Phase C: wire cm_4 / change_2 through TransferReq, Unshiel…
May 27, 2026
557a5c4
multiasset Phase C: get all tests green — verifier path + fixture regen
May 28, 2026
3d480e1
multiasset Phase C: gen_rollup_verified_bridge_fixture refactor for N…
May 28, 2026
6ddcc49
multiasset: 15 new Cairo mutation tests for Phase B/C invariants
May 28, 2026
6614591
multiasset Phase C complete: bridge fixture regenerated, all tests pass
May 28, 2026
70c317e
multiasset Phase C: wallet emits real cm_3 / cm_4 / enc_3 / enc_4
May 29, 2026
be1b73b
multiasset Phase C: wallet's unshield emits Phase B+C wire layout
May 29, 2026
2f732e0
multiasset Phase B: wallet's shield emits asset_new + asset_producer
May 29, 2026
416d72b
multiasset Phase C: align proof bench witnesses with 4-output transfe…
May 29, 2026
0f448fc
multiasset Phase B: positive non-tez coverage (14 Cairo + 6 Rust tests)
May 30, 2026
3ab6f92
multiasset Phase E.1: AssetEntry / derive_asset_id primitives
May 30, 2026
784e768
multiasset Phase E.2: per-(asset, pubkey) deposit pools + per-asset w…
May 30, 2026
658e617
multiasset Phase E.3 + E.4: lift Cairo v1 pins, add kernel registry, …
May 30, 2026
4bd90ec
multiasset Phase E.5: FA2 ticketer scaffold + asset routing tests
May 30, 2026
b2203e1
multiasset Phase E.6: wallet --asset selection for shield
May 30, 2026
6f31ab7
fa2_bridge_ticketer.tz: replace sketch with real annotated Michelson
May 31, 2026
fc49720
multiasset Phase E.7a: Note.asset_id + per-asset cmd_balance
Jun 8, 2026
602f43c
multiasset Phase E.7b: wallet transfer + unshield --asset selection
Jun 8, 2026
b6944f9
multiasset Phase E.8: per-asset deposit-recovery scan + pool tracking
Jun 8, 2026
6dbeefb
bridge: thorough test suite — Michelson structural + kernel routing +…
Jun 8, 2026
ec09174
fa2_bridge_ticketer.tz: typechecks under octez-client v24.4
Jun 8, 2026
1cd8ec6
multiasset: address all five FA2 deployment blockers
Jun 8, 2026
3d965f2
multiasset: thorough property + edge-case coverage
Jun 8, 2026
378df0f
multiasset: live-network FA2 bridge deployed + registered
Jun 8, 2026
affd06c
multiasset: real shadownet round-trip of fa2_bridge_ticketer's %mint
Jun 8, 2026
44ec17a
multiasset: full FA2 mint→burn round-trip on shadownet with balance v…
Jun 8, 2026
ad78800
gitignore: ignore .gh_token / gh_token
Jun 8, 2026
2003bf5
multiasset: CRITICAL fix — unshield asset_pub balance bypass
Jun 8, 2026
aff523a
multiasset: CRITICAL fix — FA2 shield mints producer-fee tez out of t…
Jun 8, 2026
73ad6fb
multiasset: CRITICAL fix — FA2 bridge bricked for any non-zero token_id
Jun 8, 2026
6973d82
multiasset: fix — watch-only wallets blind to FA2 notes (W1, W2)
Jun 8, 2026
cb947d1
multiasset: harden remaining audit findings (W3, W4, X4, Michelson nit)
Jun 8, 2026
c9953e0
multiasset: second-pass audit fixes (operator liveness, wire-v4 bump,…
Jun 9, 2026
a214260
multiasset: third-pass audit fixes (HTTP OOM cap, watcher silent-fail…
Jun 9, 2026
d2fada2
multiasset: address remaining audit hardening items (1, 3-8, 10-13)
Jun 9, 2026
05c4067
multiasset: sync specs, docs, and whitepaper with the multiasset impl…
Jun 9, 2026
19b4a2a
multiasset: final-sweep inconsistency fixes (Coq spec, stale docstrin…
Jun 9, 2026
9a4d224
multiasset: comprehensive end-to-end verification + final docstring sync
Jun 9, 2026
744fedf
multiasset: wire validate_l1_ticketer_canonical into the CLI + regene…
Jun 9, 2026
ce399d1
multiasset: sync OCaml port with 5-ary commit() + restore outgoing_ct…
Jun 9, 2026
f697470
fix(wallet): report producer note commitment in transfer producer_cm …
denver-s Jun 10, 2026
e2fbf1f
Merge origin/main into multiasset
Jun 10, 2026
7a74b0a
fix(ocaml): sync the OCaml port's transaction layer with multiasset (…
Jun 11, 2026
8f7d203
test: add per-flow sighash conformance test (OCaml <-> Rust core), th…
Jun 11, 2026
f578b02
multiasset: make the OCaml port actually implement multiasset (FA2), …
Jun 11, 2026
330bb5c
multiasset: extend the interop scenario with an end-to-end FA2 round-…
Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions .github/workflows/coq.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: rocq model

# Drift-checks the Cairo↔Impl manifest and builds the Rocq theory under
# coq/. The build job uses Rocq 9 via opam (same opam-via-setup-ocaml
# pattern as the OCaml unit tests workflow) so the dependency surface
# stays inside actions/* + opam packages, no third-party Docker
# images.
#
# Triggers:
# - any push to main affecting coq/** or cairo/src/**.cairo (Cairo
# edits drive drift detection)
# - same-paths PRs
# - the coq-model branch (so the model can iterate independently of
# main while it's under development)
# - workflow_dispatch
#
# Extraction wires through ocaml/coq_driver/ — `make` builds the
# theory and side-effects writing tzel_wots.{ml,mli} into coq/Impl/.
# coq/Extracted/build.sh copies those into ocaml/coq_driver/ and runs
# `dune build` against the OCaml workspace, so the realizations for
# Hash3 and pack_adrs_chain in Impl/Extraction.v resolve to the real
# Tzel.Hash.hash3 / Tzel.Wots.pack_adrs from the protocol port. The
# smoke step asserts a known reference vector (the all-zero input
# hashes to a fixed felt under the OCaml port; the extracted driver
# must produce the same byte-for-byte). Cairo-side run_chain_step
# runner + QCheck2 differential land next — see coq/STATUS.md.

on:
push:
branches: [main, coq-model]
paths:
- "coq/**"
- "cairo/src/**.cairo"
- "ocaml/coq_driver/**"
- ".github/workflows/coq.yml"
pull_request:
paths:
- "coq/**"
- "cairo/src/**.cairo"
- "ocaml/coq_driver/**"
- ".github/workflows/coq.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: rocq-${{ github.ref }}
cancel-in-progress: true

jobs:
drift:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Drift check (Cairo SHAs vs MANIFEST.toml)
run: ./coq/Drift/check.sh

build:
runs-on: ubuntu-latest
needs: drift
env:
LIBRARY_PATH: ${{ github.workspace }}/ocaml/vendor/mlkem-native/test/build
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install OCaml system prerequisites
run: |
sudo apt-get update
sudo apt-get install -y libgmp-dev pkg-config

- name: Set up OCaml + opam
uses: ocaml/setup-ocaml@e32b06a3e831ff2fbc6f08cf35be2085e3918014 # v3
with:
ocaml-compiler: "5.2.0"

- name: Install OCaml dependencies (tzel library + Rocq prover)
# Same opam package list as the unit-tests workflow's ocaml
# job — tzel links against these and the extracted driver
# links tzel. rocq-prover provides Rocq 9 and the extraction
# plugin.
run: |
opam install -y dune alcotest cstruct ctypes ctypes-foreign hex \
mirage-crypto yojson digestif rocq-prover

- name: Build ML-KEM native library
# tzel transitively links libmlkem768 via foreign stubs.
run: make -C ocaml/vendor/mlkem-native lib

- name: Build Rocq theory (compiles modules and extracts to OCaml)
working-directory: coq
run: |
opam exec -- rocq makefile -f _CoqProject -o Makefile
opam exec -- make -j2

- name: Build extracted-Rocq OCaml driver
run: opam exec -- ./coq/Extracted/build.sh

- name: Smoke run extracted driver (zero-input reference vector)
# With the real Tzel.Hash.hash3 / Tzel.Wots.pack_adrs
# realizations, hashing 96 zero bytes (x || pack_adrs(...) ||
# pub_seed where pack_adrs of all-zero indices is just the
# 8-byte little-endian TAG_XMSS_CHAIN followed by zeros) under
# BLAKE2s-251 produces this fixed felt. Computed once via the
# OCaml port; the extracted driver must match byte-for-byte.
run: |
out=$(./coq/Extracted/chain_step \
"0000000000000000000000000000000000000000000000000000000000000000" \
"0000000000000000000000000000000000000000000000000000000000000000" \
0 0 0)
echo "extracted xmss_chain_step output: $out"
expected="5ca134c7d8b26856b4dc9c748905318c23da49cac0fd56cc26c7885155466807"
if [[ "$out" != "$expected" ]]; then
echo "::error::expected $expected, got $out"
exit 1
fi
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ target/
.codex
.codex/
ocaml/_build/
# Extracted Rocq sources copied into the dune driver dir by
# coq/Extracted/build.sh; the canonical copy lives in coq/Impl/.
ocaml/coq_driver/tzel_wots.ml
ocaml/coq_driver/tzel_wots.mli
ocaml/vendor/mlkem-native/_build/
ocaml/vendor/mlkem-native/test/build/config.mk
ocaml/vendor/mlkem-native/test/build/libmlkem.a
Expand All @@ -15,6 +19,8 @@ bob.json
mutants.out*/
aws_creds
.env
.gh_token
gh_token
third_party/patched-git/

# Generated LaTeX artifacts
Expand Down
54 changes: 49 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@ Privacy on blockchains today relies on elliptic curve cryptography that quantum
- **Fuzzy message detection.** ML-KEM-based detection keys let a lightweight indexer flag likely-incoming transactions without being able to read them.
- **Diversified addresses.** Generate unlimited unlinkable addresses from a single master key.
- **1 KB encrypted memos.** End-to-end encrypted with ML-KEM-768 + ChaCha20-Poly1305.
- **Flexible N->3 transfers.** Spend up to 7 notes in a single proof and produce recipient, change, and DAL-producer fee notes without dummy notes.
- **Flexible N->4 transfers.** Spend up to 7 notes in a single proof and produce a recipient, up to two change notes (one per asset under the multiasset 2-accumulator design), and a DAL-producer fee note without dummy notes.
- **Multiasset.** Tez and FA2 tokens are both bridgeable; each FA2 ticketer KT1 deterministically maps to an L2 `asset_id = H("tzel:asset:" || ticketer_kt1)`. The on-chain commitment hides which asset a note carries, so rare-asset transactions blend with the common-asset crowd. See [docs/multiasset_deployment.md](./docs/multiasset_deployment.md).

### How it works

A UTXO-based private transaction system where:
- **Deposits** credit an aggregated rollup pool keyed by `pubkey_hash = H(auth_domain, auth_root, auth_pub_seed, blind)`. Multiple L1 tickets to `deposit:<hex(pubkey_hash)>` add to the same balance. `shield` debits the pool by `v + fee + producer_fee` and mints recipient + producer-fee notes; the proof's in-circuit WOTS+ signature, verified under the recipient's auth tree, binds the entire request payload so a delegated prover cannot redirect funds.
- **Transfers** spend 1-7 private notes and create recipient, change, and DAL-producer fee notes
- **Withdrawals** (unshield) destroy private notes, emit an L1 outbox transfer to a tz/KT1 recipient, and create a DAL-producer fee note plus optional change
- **Deposits** credit an aggregated rollup pool keyed by `(asset_id, pubkey_hash)` where `pubkey_hash = H(auth_domain, auth_root, auth_pub_seed, blind)` and `asset_id` is determined by the L1 ticketer that emitted the deposit (tez or any registered FA2). Multiple L1 tickets from the same ticketer to `deposit:<hex(pubkey_hash)>` add to the same balance. `shield` debits the asset pool by `v + fee` (or `v + fee + producer_fee` for tez shields) and mints recipient + producer-fee notes (the producer fee is always tez; for FA2 shields the kernel separately debits `producer_fee` from the user's tez pool at the same `pubkey_hash`). The proof's in-circuit WOTS+ signature, verified under the recipient's auth tree, binds the entire request payload — including the chosen asset — so a delegated prover cannot redirect funds.
- **Transfers** spend 1-7 private notes and create a recipient, up to two change notes, and a DAL-producer fee note (always tez)
- **Withdrawals** (unshield) destroy private notes, emit an L1 outbox transfer through the bridge ticketer registered for the unshielded asset (`tz1/tz2/tz3` or `KT1` recipient), and create a DAL-producer fee note plus optional change notes
- **Every shield / transfer / unshield burns at least 100000 mutez (0.1 tez)**, with a simple per-level stepped fee under congestion in the current rollup deployment
- **Every shield / transfer / unshield also creates a separate private DAL-producer fee note**
- **Every shield / transfer / unshield also creates a separate private DAL-producer fee note** (permanently tez, regardless of the transaction's primary asset)
- Every spend is proven with a **zero-knowledge STARK** that verifies the **WOTS+ signature inside the circuit** — the proof itself proves spend authorization

## Quick start
Expand Down
2 changes: 1 addition & 1 deletion apps/demo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ blake2s_simd = "1.0"
rand = "0.9"
hex = "0.4"
chacha20poly1305 = "0.10"
ml-kem = { version = "=0.3.0-rc.2", features = ["getrandom"] }
ml-kem = { version = "=0.3.2", features = ["getrandom"] }
Loading
Loading