A Central Bank Digital Currency with Offline Payment and Post-Hoc Auditability
Go prototype of an account-based CBDC with cash-like offline payments and lawful post-hoc audit, in pure cryptography (no TEE). Everyday verification is split from exceptional audit: the Central Bank sees no private data; any 3 of 5 maintainers can open a transaction only under a lawful order.
Built with gnark (Groth16) and gnark-crypto (BN254 / twisted Edwards). Circuit style follows the gnark Groth16 examples. Spec: docs/protocol.pdf.
| Spec | Code |
|---|---|
Setup, pkThEnc |
CompileCircuits, Setup.PkTh |
Enrollment π_enroll, scm0 |
CircuitEnroll, NewState |
RequestPayment rcm |
PaymentRequest |
| CreatePayment | CreatePayment / CreatePaymentInline |
| CompletePayment | AcceptPayment, CompletePayment |
π_state^create, π_pm, π_link, π_dep^create |
CircuitStateCreate, CircuitPm, ProvePaymentLink, CircuitDepCreate |
π_state^complete, π_dep^complete |
CircuitStateComplete, CircuitDepComplete |
T_S, ψ_S |
TracingTag, ElGamalEncrypt |
Not included: KYC directory, networked ledger, maintainer threshold-decryption service, or the reconnect/audit/trace control loops as a deployed system.
Commitment Comm is MiMC-BN254 (nativeCommit). D = 5t+1, prototype t = 2 so D = 5. Epoch slack Δ_sync = 5 (SyncTol).
CompileCircuits
CircuitEnroll, NewState
PaymentRequest
CreatePayment
In-circuit: π_state^create, π_pm. Out-of-circuit Schnorr π_link binds T_S, ψ_S to pcm, scm_S,new. Optional π_dep^create if the old state is signed.
AcceptPayment then CompletePayment
| Proof | Circuit / function |
|---|---|
π_enroll |
CircuitEnroll |
π_dep^create |
CircuitDepCreate |
π_pm |
CircuitPm |
π_state^create |
CircuitStateCreate |
π_dep^complete |
CircuitDepComplete |
π_state^complete |
CircuitStateComplete |
π_link (Schnorr) |
ProvePaymentLink / VerifyPaymentLink |
CreatePaymentInline / CircuitStateCreateInline move T_S, ψ_S into the Groth16 circuit (larger; used as the baseline in the circuit-size table).
| Actor | Role |
|---|---|
| Users (payer / payee) | Hold a committed wallet; pay offline |
| Central Bank (CB) | Verifies proofs and checks double-spending. Trusted to verify correctly, not trusted to protect privacy |
| Maintainers | Any 3 of 5 must cooperate to audit or trace |
| Scheme | Offline | Audit & Trace | Mechanism / limitation |
|---|---|---|---|
| PEReDi / Platypus | ✗ | ✓ | Threshold ElGamal audit; must be online during payment |
| PayOff | ✓ | ✗ | Offline chained settlement; no audit |
| PayAudit | ✓ | ✓ | Audit ciphertext ψ and traceable tag T |
A related public CBDC prototype (online, Circom/snarkjs) is applied-crypto/cbdc.
| Requirement | Mechanism | Meaning |
|---|---|---|
| Hide balance | Committed wallet state | Balance sits in a commitment on the ledger |
| Prevent overspending | Zero-knowledge proof | Prove a valid resulting balance without revealing values |
| Detect double-spending | Deterministic tag T = g^{a · ctr} |
Reusing an old state yields the same T |
| Hide identities | Threshold ElGamal ψ |
Amount and identities are locked; no single party can open them |
| Enable lawful audit | (t+1)-threshold decryption |
Only a quorum of maintainers unlocks ψ |
| Trace user history | Secret a reconstruction |
Regulator computes candidate T values and scans the ledger |
| Prevent tampering | Dependency chain | Each state links to the previous; a break is detectable |
Threat model. 5 maintainers; any 3 must cooperate to audit or trace. At most 2 may be malicious or unavailable (t = 2, D = 5t+1 = 5). Even if CB colludes with all malicious maintainers (up to 2), privacy remains intact.
Laptop: AMD Ryzen 7 4800H @ 2.90 GHz (Zen 2, 16 GB). Stack: gnark / Groth16 / BN254.
| Metric | Result |
|---|---|
| Single offline payment (create + accept + complete) | < 0.3 s |
| Settlement of a 100-payment chain | < 0.6 s |
| Message size for 100-payment history | ~105 KB (~1 KB per payment) |
| Circuit-size comparison (creation proof) | Constraints / cost |
|---|---|
| ElGamal & tag inside the ZK circuit | 33,714 |
| ElGamal & tag outside + Schnorr proof | 19,306 |
| Constraint reduction | ~43% |
| Schnorr generation / verification | 0.0006 s / 0.0012 s (negligible) |
PayOff similar creation ≈ 0.21 s on a Ryzen 7 PRO 7730U (arXiv:2408.06956, Table III); ours ≈ 0.12 s with added audit/trace.
Requires Go 1.24+.
git clone https://github.com/eddiewsh/PayAudit
cd PayAudit
go test ./...go test ./... -run TestPrintCircuitTable -count=1
go test ./... -run TestPrintEndToEndTable -count=1Table tests are skipped under -short.
| File | |
|---|---|
payaudit.go |
Circuits and create / accept / complete |
crypto.go |
MiMC, threshold ElGamal, tracing tag, Schnorr π_link |
payaudit_bench_test.go |
Circuit table and end-to-end latency |
docs/protocol.pdf |
Protocol / proof relations |
docs/PayAudit-poster.pdf |
Poster |
docs/figures/steps/ |
Setup, enroll, spend, settle, audit, proofs |
Consensys/gnarkConsensys/gnark-cryptoapplied-crypto/cbdcmatter-labs/awesome-zero-knowledge-proofs
- C. Beer et al., PayOff: A Regulated Central Bank Digital Currency with Private Offline Payments, AsiaCCS, 2026. arXiv:2408.06956
- A. Sarencheh et al., PEReDi: Privacy-Enhanced, Regulated and Distributed Central Bank Digital Currencies, ACM CCS, 2022.
- K. Wüst et al., Platypus: A Central Bank Digital Currency with Unlinkable Transactions and Privacy-Preserving Regulation, ACM CCS, 2022. ePrint 2021/1443
- G. Botrel et al., gnark, github.com/Consensys/gnark.
















