Private signature · Halo2 · Orchard
Research preview · Circuit in developmentSign on behalf of the group, without revealing who signed.
ZK Sign proves you belong to an authorized set (Merkle root published by the issuer) and that your signature is unique for that document. Your key stays with you, your identity stays private, the nullifier blocks double-signing.
RFC published 2026-04-21. MVP ships SignCircuit with Merkle depth 16 (65k members). Revoke, threshold, and ring mode land in phases S.7+.
Capabilities
Four guarantees in one signature
A single proof covers membership, anti-replay, document binding, and composition with timestamp. Revoke and threshold ship in phase 2.
Private membership
MVPProves you are one of the authorized members (published Merkle root) without revealing which leaf is yours. Rotation becomes a new root.
Private: sk_sign, merkle_path, merkle_indices. Public: merkle_root.Anti-replay via nullifier
MVPnullifier = Poseidon(sk_sign, doc_hash) binds signer to document. Two signatures on the same doc produce the same nullifier and get rejected.
Private: sk_sign, doc_hash. Public: nullifier.Traceable revocation
Phase 2Issuer publishes a new Merkle root excluding compromised keys. Old signatures stay valid; new ones from the banned key fail.
Private: old_pk, old_path. Public: old_root, new_root, revocation_nullifier.Threshold t-of-n
Phase 2Aggregates N signers of the same Merkle into one proof. Shows that at least t distinct keys endorsed without revealing identities.
Private: sk_sign[t], merkle_path[t]. Public: merkle_root, threshold t, nullifier[t].
How it works
From document upload to the Orchard memo
Seven steps across issuer, signer, and verifier. Everything runs client-side; the server only relays the Zcash transaction.
- Issuer
Builds and publishes Merkle root
Collects members' public keys, computes a Poseidon Merkle tree of depth 16, and publishes the root (on-chain or via issuer-state.json).
- Signer
Local hash of the document
SHA-256 runs in the browser via crypto.subtle. The document never leaves the device; the prover only sees doc_hash.
- Prover
Derives pk_sign and nullifier
pk_sign = Poseidon(sk_sign) and nullifier = Poseidon(sk_sign, doc_hash_lo, doc_hash_hi). All in WASM, zero key exposure.
- Prover
Halo2 proof with Merkle verify
SignCircuit checks the merkle_path up to the public root and binds the nullifier to doc_hash. Output is the compact proof.
- Zcash
Anchors via Orchard memo
512B memo with ZKSG magic + merkle_root_hint + 32B nullifier + optional doc_commit. Regular shielded transaction.
- Signer
Delivers receipt
receipt.json carries proof + nullifier + tx_hash + block height. Verifier receives it offline, no need to reopen the document.
- Verifier
Checks proof + fresh nullifier
Validates the Halo2 proof, confirms the known Merkle root, and looks up the nullifier in earlier blocks. Double-use triggers reject.
Stack
Same base as the other ZK on Zcash products
Full reuse with ZK Credit, ZK ID, and ZK Timestamp: same zkcgz binary, same pasta_curves primitives, same Orchard anchor. No trusted setup.
- Proving systemHalo2 + IPA
pasta_curves, trustless. SignCircuit reuses the Poseidon chip (width=3, rate=2) already used by CredentialCircuit.
- Member structurePoseidon Merkle (depth 16)
Each node is Poseidon(left, right). Depth 16 covers 65,536 signers. Rotation publishes a new root.
- On-chain anchorOrchard memo (512B)
ZKSG magic + version + merkle_root_hint + nullifier + optional doc_commit. Coexists with ZKT0 and ZKID.
- Where it runs100% client (WASM)
sk_sign never leaves the device. Server only relays the Zcash tx. Hosted mode with HSM ships in phase S.6+.
Roadmap
From RFC to E2E demo
Seven MVP phases + S.7 for revocation. Each phase ships something runnable; threshold and ring mode are post-MVP.
- S.1
RFC approved + /sign route
- S.2
SignCircuit in Rust (halo2_proofs + Merkle Poseidon)
- S.3
CLI zkcgz sign issue/sign/verify
- S.4
Orchard memo encoder/decoder with ZKSG magic
- S.5
Surfaces /sign/issue, /sign/sign, /sign/verify
- S.6
Testnet E2E: issue, sign, anchor, verify
- S.7
SignRevokeCircuit + /sign/revoke surface
Out of scope
What ZK Sign is not
Explicit decisions to keep the MVP viable and the pitch crisp.
- Legal non-repudiation: this is technical evidence, not a substitute for a notary or lawyer.
- Threshold t-of-n in the MVP: single-signer first, threshold in phase 2.
- Replacement for ECDSA/Ed25519 where law demands identity: still out of scope.
- Issuing X.509 certificates from the nullifier: optional future bridge.