The recipient controls the spend marker

Suppose Alice creates a private payment for Bob. Alice knows the amount, the output randomness and when she published it. If she also knows the secret used to calculate Bob's later public spend marker, she can connect that spend to her payment.

ZPS-1 separates spending authorization from nullifier generation. Bob supplies an authenticated, one-use descriptor containing an ML-DSA verification key, a commitment to his independent nullifier secret, an ML-KEM viewing public key and a descriptor identifier. His secret stays with him.

Note creation and a later spend are separate events. The recipient keeps the nullifier secret in both.
Note creation and a later spend are separate events. The recipient keeps the nullifier secret in both.

What a note commits to

A note is an immutable, concealed output. The sender constructs its commitment from canonical fields. The chain stores that commitment; an encrypted envelope carries the opening that the recipient needs to recover the note.

Field groupPurpose
Chain and versionPrevent interpretation under another chain or protocol.
Asset and integer valueBind the amount used in conservation checks.
Fresh note identifier and blinding randomnessSeparate outputs and support hiding.
Spending key and nullifier-secret commitmentBind spending authority and the independent spend-marker secret.
Full descriptor digest and policy digestBind the encryption key, descriptor identity and spending policy.

Bob decrypts the payload, recomputes the commitment and checks it against the published note. Bob's independently held nullifier secret is never part of data Alice constructs.

C = H_note(chainID, version, asset, value, rho, r, pk_sp, nu, d, policy)
N = H_null(chainID, version, s_nf, rho)

Here nu commits to Bob's secret s_nf; d is the complete descriptor digest. Final hashes, parameters and proving constraints are not selected.

Authorize the whole transaction

A signature covers the chain, version, accepted root, ordered nullifiers, output commitments, paired envelope hashes, queued public calls, fee and expiration. Changing a recipient envelope after authorization must change the signed digest.

The candidate proof checks the ML-DSA signature against the spending verification key committed in the input note. Neither that key nor its signature is separately published as transaction data.

A candidate STARK verifies the spending relation. The state machine and consensus have additional responsibilities.
A candidate STARK verifies the spending relation. The state machine and consensus have additional responsibilities.
PredicateRequired check
M · MembershipInputs belong to an accepted Merkle root.
B · Note bindingOpenings match commitments and descriptor digests.
E · Envelope bindingEach output pairs with its canonical ciphertext-envelope hash.
A · AuthorizationThe committed ML-DSA key verifies the complete digest.
N · Nullifier correctnessThe marker derives from the same secret and note used in the witness.
I · Integer boundsValues are in range; sums cannot wrap around the proof field.
V · ConservationAccount for each asset across inputs, outputs, fees and conversions.

These predicates define a candidate language, not a completed proving circuit or a security theorem.

Binding is not delivery

  • Integrity: envelope bytes match the authorized hash.
  • Availability: the recipient can retrieve those bytes.
  • Recoverability: decryption yields an opening matching the commitment.
ProfileTargetSeparate obligations
Baseline ZPS-1Envelope integrity; agreed byte availability is a validator policy.Correct recipient decryption is not proved.
Strict-delivery candidateA private witness links ML-KEM encapsulation, AEAD payload, descriptor, commitment and envelope.Proof cost and composition security are unestablished. Retrieval and key retention still matter.

A malicious sender can authorize a self-consistent but unusable envelope before signing. Baseline verification can accept it. A recipient acknowledgement is another policy option, but an attestation of receipt is not a proof of correct encryption.

From proof to accepted spend

  1. Reject malformed encoding, unknown versions, wrong chain IDs, stale anchors and expired statements.
  2. Check unique, sorted nullifiers against current scratch state. Reject duplicate output commitments across the transaction and existing history.
  3. Check output/envelope pairing, descriptor binding, supplied hashes and agreed availability.
  4. Verify the registered STARK relation, then run queued public effects in actual block order.
  5. Stage all effects only on success. Commit only when the entire proposed block and its roots are valid.

Mempool acceptance does not reserve a spend. Conflicting transactions can look valid against the same earlier state; canonical ordering decides which can commit.

input value = output values + fee

This is bounded integer accounting, not just equality in a finite proof field. Public deposits and withdrawals require separately validated terms.