The simulator on production Orchard.
The Orchard Action relation is the production target. A valid
Action witness is a tuple
(SpendingKey, Note, MerklePath, OutputNote, α,
rcv) satisfying the on-chain constraints: the spent
note's commitment must be in the Merkle tree at the claimed
anchor, the nullifier must equal
ExtractP([PRFnfOrchardnk(ρ) +
ψ]·KOrchard + cm), the value
commitment must be a Pedersen commitment to
(spend − output) with trapdoor
rcv, and so on. The
Zcash protocol specification documents
the full relation in
section 4.18.4 ("Action Statement
(Orchard)").
The simulator below samples a uniformly random valid witness,
builds the production orchard::circuit::Circuit
from it, runs halo2_proofs::plonk::create_proof,
and presents the resulting 4992 bytes to the production
orchard::circuit::Proof::verify. The verifier
accepts. A small downstream patch on the upstream
orchard crate exposes six read-only accessors
(ProvingKey::{inner,params},
VerifyingKey::{inner,params},
Instance::to_halo2_instance,
SigningMetadata::{alpha,is_dummy}) so the same
path can also run with a programmable Fiat-Shamir transcript;
otherwise nothing in orchard or
halo2_proofs is modified.
Run it
First click pays for the proving-key build (around six seconds on a desktop, more in the browser, cached afterward). Each proof from then on takes roughly three seconds on the parallel WASM build, or thirty seconds on the single-threaded build. The seed is exposed in the URL hash so the run is reproducible.
Data flow
Each Run drives four stages of the production code path. The diagram below lights up live as the worker walks them.
SpendingKey::from_bytes,
Note::from_parts,
MerklePath::from_parts,
Rho::from_bytes
orchard::circuit::Circuit::from_action_context
halo2_proofs::plonk::create_proof
on Pasta vesta::Affine
halo2_proofs::plonk::verify_proof against
the public Instance
The public Instance
These nine field elements are the public statement; everything the prover used to build the proof (spending key, spent note, Merkle path, output note) is invisible to the verifier. The Reference page defines each term.
-
-
-
-
-
-
-
-
The proof bytes
First and last 64 bytes of the 4992-byte proof. The full hex is one click away; the anatomy section on the Reference page walks through what the byte ranges contain.
-
-
Show all 4992 bytes
click "load full hex" to populate (9984 hex characters)
Soundness: tamper with one byte
A PLONKish proof has no malleation slack; any single bit-flip
makes verify_proof reject. Three buttons below
flip a byte at head, middle, and tail of the cached proof
and re-run verification.
Zero-knowledge at the byte level
Same witness, same Instance, two independent calls to
Proof::create with different proving RNGs. Both
verify. The bytes share no information beyond their
structural format; if the proof bytes leaked anything about
the witness, the two sequences would correlate.
-
-
-
Strict ROM-programmable ZK
The runs above use Halo 2's default
Blake2bWrite transcript: the simulator samples a
uniform witness internally and the honest prover hashes the
transcript as usual. That already satisfies the textbook ZK
property under the witness-uniformity argument (see
Reference), but the
cryptographic move is more visible if we make the
Fiat-Shamir random oracle programmable. The button below
drives the same production prover with a
ProgrammableHalo2Write transcript instead: 256
Pasta-scalar challenges are picked uniformly at random in
advance, the prover reads them off the queue instead of
hashing, and the verifier accepts under the matching
ProgrammableHalo2Read while
Blake2bRead rejects. The acceptance under
programmable plus rejection under Blake2b is the
cryptographic signature of a strict ROM-ZK simulator.
-------The full bundle
The proof is one component of an Orchard bundle. A v5 Zcash
transaction also carries a binding signature over the value
commitments and a spend-auth signature per Action. The
button below builds a full
Bundle<Authorized, i64> through the
production
orchard::builder::Builder pipeline and verifies
every signature independently.
---------per-Action authorizing data
Verify arbitrary bytes
Paste a hex-encoded proof or the entire downloaded JSON. The
page parses out the bytes, reconstructs
orchard::Proof::new, and runs
verify_proof against the most recently cached
Instance.
Three independent runs
Three uniformly random witnesses, three independently
produced proofs, all verified by the same
verify_proof. The simulator does not depend on
one lucky seed.
What would happen on mainnet
Every cryptographic check on this page passes. A consensus node would still reject the transaction for non-cryptographic reasons:
-
The
anchoris uniformly random; mainnet nodes check it against historical roots of the on-chain Orchard note-commitment tree. - Even with a matching anchor, the spent note's commitment is not in any real block. The Merkle path proves membership in a tree the spent note was never in.
-
If the bundle were submitted alongside transparent or
Sapling components, the cross-bundle value balance check
would fail unless those components were constructed to net
to
(spend_orchard − output_orchard − fee). An Orchard-only transaction (as this simulator builds) doesn't hit this constraint internally, but a real wallet rarely sends one. - The 32-byte sighash here is uniformly random. In production it is derived from the entire v5 transaction body per ZIP 244. A node deriving the sighash from the actual submitted body computes a different value, and every signature in the bundle fails to verify against it.
The simulator therefore demonstrates the
Simulate algorithm without breaking any soundness
property. It cannot be used to forge a spend the network would
accept.