SPST: a self-paying shielded transaction model
Sections
- The setting
- Definitions
- The SPST relation
- The self-paying property (Theorem 3.1)
- Theorem 3.2 — Balance / value conservation
- Argument 1 (SNARK soundness)
- Argument 2 (Pedersen cross-check)
- Theorem 3.3 — Double-spend resistance
- Theorem 3.4 — Transaction unlinkability
- Theorem 3.5 — Non-malleability
- Circuit complexity
- What SPST is not
- Bibliography
In the previous post I argued that on account-model chains the fee paradox is what forces relayer dependence. The cleanest resolution — Approach A — extracts the transaction fee from inside the ZK proof itself. This post specifies that resolution.
The construction is called SPST (Self-Paying Shielded Transactions). It is the foundation that PPST, TAB, and UPEE build on. It also stands alone as a complete protocol for private value transfer with self-paying fees — the Solana analogue to Zcash’s Sapling spend description, but adapted to a smart-contract environment.
The setting
Work over a prime-order elliptic curve group of order with two independent generators for which no party knows . Let denote the scalar field. We use:
- Poseidon as the SNARK-friendly hash (width , HADES rounds full + partial, S-box , ~324 R1CS constraints per 2-to-1 compression).
- PRF keyed by , instantiated as a domain-separated Poseidon evaluation.
- Groth16 over BN254 as the on-chain verifier (alt_bn128 syscalls on Solana).
- Indexed Merkle Trees for nullifier non-membership (depth-32 over 254-bit values; ~10,948 R1CS constraints per non-membership proof, vs 82,296 for naive sparse Merkle).
Definitions
Definition 3.1 (Shielded Note). A shielded note is a tuple
where is the owner’s public spending key, is the note value, is unique per-note serial randomness, and is the commitment trapdoor.
Definition 3.2 (Note Commitment).
Note commitments are appended as leaves to a global Merkle tree of depth (capacity notes). The Merkle root at any epoch is .
Definition 3.3 (Nullifier).
Upon spending, is published to a global nullifier set . Double-spending is prevented by rejecting any transaction whose already lives in .
Definition 3.4 (SPST Transaction). With inputs and outputs:
where is the public fee and is a Groth16 proof of the SPST relation.
The validator accepts iff (i) verifies, (ii) is a recent root, (iii) every , and (iv) .
The SPST relation
The relation is the set of pairs:
Public instance .
Private witness .
Eight constraints, all enforced by the circuit:
| # | Name | Constraint |
|---|---|---|
| C1 | Spending key validity | |
| C2 | Nullifier correctness | |
| C3 | Input commitment well-formedness | |
| C4 | Merkle membership | |
| C5 | Output commitment well-formedness | |
| C6 | Value conservation with fee | |
| C7 | Non-negative output values | (bit decomposition) |
| C8 | Non-negative fee |
C6 is the load-bearing constraint. It is what makes the transaction self-paying: the prover can only produce a valid proof if the input notes’ values sum to exactly the output values plus the fee.
The self-paying property (Theorem 3.1)
Theorem. Let be a valid SPST transaction. Then:
- The fee is funded entirely from consumed shielded notes.
- No external account, relayer, or gas sponsor is required.
- Validators extract as inclusion compensation without learning the private inputs/outputs beyond itself and the validity of .
Proof sketch. (1) follows directly from C6. (2) follows because is a self-contained data structure that any party can broadcast; the on-chain verifier decrements the privacy program’s lamport reserve by and credits the validator. (3) is the perfect zero-knowledge property of Groth16: the validator sees as a public input but learns nothing about or .
The full proof is in §3.1.3 of the paper. The takeaway: on Solana, the privacy program’s PDA holds a reserve. Each shield deposit increments it. Each SPST transaction’s proof authorises the validator to take from it. Replenishment is automatic.
Theorem 3.2 — Balance / value conservation
Statement. No PPT adversary can produce a valid SPST transaction that creates value (i.e., one for which ) except with negligible probability.
The proof gives two complementary arguments — one from the SNARK’s knowledge soundness, one from an independent Pedersen commitment cross-check that provides defense in depth.
Argument 1 (SNARK soundness)
C6 enforces over . C7 and C8 enforce . With at most inputs each bounded by , — so field arithmetic faithfully represents integer arithmetic and no modular wraparound is possible.
By Groth16 knowledge soundness in the AGM, an extractor can recover the witness satisfying all constraints C1–C8. C6 in the extracted witness gives as an integer equation. Contradiction with the assumed inflation.
Argument 2 (Pedersen cross-check)
As defense in depth, attach Pedersen value commitments to each note. With and , the verifier checks
where .
Suppose an adversary passes this check but with . Let . Then for some , which yields — contradicting DLOG. ∎
Theorem 3.3 — Double-spend resistance
Game. may adaptively deposit and spend; wins if it produces two accepted transactions consuming the same note .
Cases.
- Case 1: The two transactions publish the same nullifier. Rejected by the protocol’s nullifier-set check.
- Case 2: They publish different nullifiers but consume the same note. By C4 both proofs authenticate the same commitment . By C1 we have .
- If , then . Contradiction.
- If , then — a collision in Poseidon. Reduces to collision resistance.
Both cases reach a contradiction. ∎
Theorem 3.4 — Transaction unlinkability
Statement. Under perfect zero-knowledge of Groth16 and computational hiding of Pedersen commitments under DDH, the SPST scheme satisfies transaction unlinkability: no PPT adversary can determine which input notes fund which output notes with non-negligible advantage.
Proof structure. Hybrid argument:
- Hybrid 0: real game.
- Hybrid 1: replace all Groth16 proofs with simulated proofs. By perfect ZK of Groth16, indistinguishable.
- Hybrid 2: in the simulated view, the multisets of nullifiers, commitments, roots, fees are identical for both branchings of the challenge. The fee is identical by construction. Each with fresh random is computationally indistinguishable from a uniform field element. Each nullifier with unique is pseudorandom. The Pedersen value commitments are computationally hiding under DDH.
Result: . ∎
Theorem 3.5 — Non-malleability
Statement. No PPT adversary can take a valid SPST transaction and produce a distinct valid transaction with altered public inputs (e.g., a different fee), except with negligible probability.
Proof. Relies on the simulation-extractability of Groth16 in the Random Oracle Model — the Bowe-Gabizon construction (2019), refined by Ràfols-Baghery-Pindado (2023). An adversary mauling the proof to alter would need to extract a witness with a different satisfying C6, but C6 plus the unchanged input commitments and output commitments uniquely determines . Contradiction.
Circuit complexity
For an SPST circuit with inputs and outputs:
A canonical 2-in / 2-out transaction:
| Component | Per-input | Per-output | Subtotal |
|---|---|---|---|
| Note commitment (input) | 388 | — | |
| Merkle path (depth 32) | 10,400 | — | |
| PRF evaluations (pk + nf) | 648 | — | |
| Range proof (input value) | 64 | — | |
| Note commitment (output) | — | 388 | |
| Range proof (output value) | — | 64 | |
| Fee range proof | — | — | 64 |
On commodity hardware (Apple M2, 8-core), Groth16 proving for ~24,000 constraints takes 0.5–1.5 seconds with arkworks or snarkjs. Proof size is 128 bytes compressed (BN254 G1/G2 compression on Solana). Verification is ~150,000–200,000 CU via sol_alt_bn128_* syscalls.
| Aspect | Pros | Cons |
|---|---|---|
| Proof size | 128 bytes (BN254 compressed) | Fits the 1,232-byte Solana limit with 1,100+ bytes for other tx data |
| Verification cost | < 200,000 CU (≈ $0.02 USD) | ~14% of the 1.4M CU per-tx budget; leaves room for nullifier checks + state updates |
| Prover time (M2 laptop) | 0.5–1.5 s for 2-in / 2-out | Linear in circuit size; recursive proofs amplify this |
| Trusted setup | Per-circuit Groth16 MPC (Powers of Tau-style) | Separate ceremony per circuit shape; PLONK alternative awaits SIMD-0302 G2 syscall |
What SPST is not
SPST handles private value transfer — the Solana analogue of Zcash’s Sapling. It does not:
- Handle private computation. The next post (PPST) extends the relation to arbitrary arithmetic circuits over private state.
- Hide the submitter. The transaction submitter is still publicly identified by their Ed25519 signature on the wrapping Solana transaction. TAB addresses that.
- Hide the fee amount. is necessarily public for validator compensation.
But it does the load-bearing thing: the user becomes self-sovereign with respect to fee payment. Combined with TAB and PPST, that’s the whole framework.
Bibliography
- Ben-Sasson, E. et al. (2014). Zerocash. IEEE S&P 2014. https://eprint.iacr.org/2014/349
- Hopwood, D. et al. (2016–2026). Zcash Protocol Specification. https://zips.z.cash/protocol/protocol.pdf
- Groth, J. (2016). On the Size of Pairing-based Non-interactive Arguments. EUROCRYPT 2016. https://eprint.iacr.org/2016/260
- Bowe, S., Gabizon, A. (2019). Making Groth’s zk-SNARK Simulation Extractable. https://eprint.iacr.org/2019/197
- Ràfols, C., Baghery, K., Pindado, Z. (2023). Simulation Extractable versions of Groth’s zk-SNARK Revisited. https://doi.org/10.1007/s10207-023-00750-7
- Pedersen, T. P. (1991). Non-Interactive and Information-Theoretic Secure Verifiable Secret Sharing. CRYPTO 1991.
- Grassi, L. et al. (2021). Poseidon: A New Hash Function for Zero-Knowledge Proof Systems. USENIX Security 2021. https://eprint.iacr.org/2019/458
- Aztec Documentation. Indexed Merkle Tree (Nullifier Tree). https://docs.aztec.network/
Previous: The fee paradox ← · Next: PPST: private programmable state →