# Canonical MPC trusted setup — deployed + redeemed on Preview The Groth16 proving/verifying keys for the deployed `drv.Recovery` circuit were produced by a real **MPC Powers-of-Tau ceremony** (not a throwaway `groth16.Setup`), the resulting verifying key was baked into the `RedemptionValidator` and deployed to Cardano **Preview**, and the live node ran the **entire** validator — `groth16VerifyCommitted` (against the MPC VK) + entitlement + destination + no-self-pay — releasing exactly 5 tADA. This makes the MPC-produced VK the canonical on-chain setup. Date 2026-06-30. Network Preview (testnet-magic 2). Branch `feat/mpc-ceremony-framework`. ## The ceremony - Circuit `drv.Recovery`: **3,450,403 constraints, domain 2²² (4,194,304), power 22**, `nbPublic=1 nbSecret=1239`, `PublicAndCommitmentCommitted == [[]]`. - Tooling: `C:\proof-deps\realceremony` over `proto/ceremony/core` (commitment-aware `bgm17` wrapper) on the patched gnark fork (`fix/1428-phase2-init-memory`). - Phase-1 Powers of Tau + fixed-beacon Seal, Phase-2 circuit-specific contribute + Seal → `recovery.pk` (**2.42 GB**) + `recovery.vk` (**784 B**) in `proto/vending/prover/work/keys/` (gitignored). The keys are NOT reproducible (fixed beacon + `crypto/rand` contribution); re-running gives a fresh, equally valid canonical setup. - **Ceremony wall-clock: 2528 s (~42 min)** — Phase-1 contribute 137 s, Phase-1 seal +134 s, Phase-2 ~36 min, key write ~6 s. (Accelerated by the parallel `SrsCommons.update` patch — Phase-1 ~9.5× — and buffered pk I/O — write ~1700× — see `docs/superpowers/{specs,plans}/2026-06-30-phase1-*`.) ## Prove (binds the on-chain artifacts to the ceremony keys) `realprove` loaded `work/keys/recovery.{pk,vk}` and **skipped trusted setup** (load 24.6 s, prove 8.5 s, off-chain `VerifyProof: OK`), regenerating the fixtures in `testdata-recovery/`: `vk_c.hex` **672 B**, `proof_c.hex` **336 B**, `dom.hex` 722 B, `pub.hex` 32 B. ## Validator (deployed with the MPC VK) | Item | Value | |------|-------| | Validator | Plutus V3, **5960 bytes** (CBOR(flat)), inline | | **Script address (canonical, MPC VK)** | `addr_test1wrgkz5sdkqjy8qzyqu96dl5clx0ljlfj46ey5g8f0394dgqv86qr5` | | Claimant credential `C` | `19e07fbcc7577359d6c51f1e49cf1b0bf4c943b48ba4e4905a8702e4` | | Entitlement | 5 tADA, ADA-only (`encodeEntitlement` = `404b4c00…`) | | Snapshot root R | `4a87ca7f53f5467c06086021b956b1548916668c67da698e52e9b913eb98a0e5` | | Destination `D` (57 B) | `00483df46f0e8772d5ac6799f33f4f94685db069d93245644ea8aedbe587fd0b53ef4ecdfca456f16a542fe784010317e5fbdbec4f29671641` | | Destination address | `addr_test1qpyrmar0p6rh94dvv7vlx060j359mvrfmyey2ezw4zhdhev8l5948m6weh72g4h3df2zleuyqyp30e0mm0ky72t8zeqsm0yae5` | | Funded wallet | `addr_test1vpw0dhd0k6rq0qrpeul0km0xtl5tguqk8f9q8v5p5rzghdq05nhzv` | ## Off-chain gate (CEK) before going live Full validator on a synthetic V3 ScriptContext with the real ceremony proof **ACCEPTs**; ExBudget **3,914,957,868 CPU / 2,826,629 mem** (fits 10e9 / 16.5e6). `encodeAddr(destAddr)==D` and `encodeEntitlement(5 tADA)==cdEntitlement` both True. Negatives reject: tampered proof (`bls12_381_G1_uncompress` fails), wrong value, wrong `D`. ## Transactions (live Preview) | # | Tx hash | Action | Status | |---|---------|--------|--------| | 1 | `af00155008b74408c34f81722f3f7cbc935a8c0474d93f2ad2de89e362f93e2e` | Lock 5 tADA in custody (inline `CustodyDatum(C, ent)`) | confirmed | | 2 | `92738a5d5b7603f056c822bd15b309c29c967dc91ef3325137d236966910f896` | Claim — full validator runs (MPC VK), 5 tADA released to `D` | confirmed | Explorer: - Lock: https://preview.cexplorer.io/tx/af00155008b74408c34f81722f3f7cbc935a8c0474d93f2ad2de89e362f93e2e - Claim: https://preview.cexplorer.io/tx/92738a5d5b7603f056c822bd15b309c29c967dc91ef3325137d236966910f896 ## Result The destination wallet `addr_test1qpyrmar…` holds a UTxO `92738a5d5b7603f056c822bd15b309c29c967dc91ef3325137d236966910f896#0` of **5,000,000 lovelace (5 tADA)** from the claim tx (confirmed on-chain). A real client ZK proof, verified against the **MPC-ceremony-produced verifying key**, recovered the custody balance through the live node running the complete `RedemptionValidator`. Claim declared ex-units `(6,000,000,000, 4,000,000)`; the off-chain CEK measured `3,914,957,868 / 2,826,629` — both within the per-tx budget. The MPC trusted setup is now canonical. ## Trust scope (testnet) — and what production requires VibeSec audit of this work (S9 + artifact integrity) surfaced two P1s that bound what "canonical" means here. Both are scope/labeling matters for a **Preview testnet** deployment, not live exploits on it, but they are **mandatory pre-conditions before any mainnet/production use** and are tracked here so the claim is not overstated: - **Single-operator setup, not a multi-party ceremony.** The deployed keys come from one `Contribute` per phase on the operator's machine — the `realceremony` binary calls `InitPhase1→Contribute→SealPhase1→InitPhase2→Contribute→SealPhase2` directly and **bypasses** the ceremony framework's transcript/`VerifyAll`/coordinator path. The operator transiently holds the toxic waste (τ,α,β) and could, in principle, forge proofs — acceptable for a value-less testnet pipeline validation, **not** for production. The beacon is a fixed ASCII literal (no external entropy). **For mainnet:** run the multi-party path (`proto/ceremony/coord`+`contributor`, ≥3 independent contributors, each replayable via `VerifyAll`) and seal with a real public randomness beacon (drand / Cardano epoch hash) fetched *after* the last contribution is locked. - **No in-branch byte-identical guard for the regenerated `redemption.plutus`.** This branch carries no `scripts/ci` byte-identical pin for the new artifact. Nothing was deleted/weakened — the guard infra simply isn't in this branch — and the artifact is independently verified (VK `vk_c.hex` embedded verbatim at cborHex offset 10348; validator logic byte-unchanged; claim tx confirmed on-chain). **Before merging to any guard-carrying branch:** add the pin and confirm it. Reference hashes for the committed `redemption.plutus`: file sha256 `4942b869108599b337514de60832aaa0edf080eac18f12be72a646dbe3865d89`; `sha256(cborHex-ascii)` `1b4fb0ce019cf789df742a0d4c862a7200f7c35b1abd96b6a82e1940855bd7d4`. Lower-severity (tracked, non-blocking): fixed-text beacon (P2; subsumed by the single-operator point), gnark fork pinned by local-path replace with no commit-SHA (P3, backlog), prover provenance manifest absent (P3, deferred). The parallelized `update` and buffered pk I/O drew **no** security finding (byte-identical golden gate, `-race` clean, VK still loaded with the checked reader).