DOC# SPSTSE SLUG spst_self_paying_shielded_transactions PRINTED 2026-05-06 03:47 UTC

SPST: a self-paying shielded transaction model

First construction in F_RP. The SPST relation, balance conservation under DLOG, double-spend resistance under collision-resistant PRF, unlinkability under DDH, simulation-extractable non-malleability.

FROM
Dax the Dev <[email protected]>
SOURCE
https://blog.skill-issue.dev/blog/spst_self_paying_shielded_transactions/
FILED
2026-04-30 17:30 UTC
REVISED
2026-04-30 17:30 UTC
TIME
8 min read
SERIES
relayerless-privacy
TAGS
#zk #cryptography #pedersen #groth16 #zcash #solana #phd

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 G\mathbb{G} of order pp with two independent generators g,hGg, h \in \mathbb{G} for which no party knows loggh\log_g h. Let Fp\mathbb{F}_p denote the scalar field. We use:

Definitions

Definition 3.1 (Shielded Note). A shielded note is a tuple

note=(pk,v,ρ,r) \mathsf{note} = (\mathsf{pk}, v, \rho, r)

where pk=PRFsk(0)\mathsf{pk} = \mathsf{PRF}_{sk}(0) is the owner’s public spending key, v{0,,2641}v \in \{0, \ldots, 2^{64}-1\} is the note value, ρFp\rho \in \mathbb{F}_p is unique per-note serial randomness, and rFpr \in \mathbb{F}_p is the commitment trapdoor.

Definition 3.2 (Note Commitment).

cm  =  Poseidon(pk,v,ρ,r)    Fp. \mathsf{cm} \;=\; \mathsf{Poseidon}(\mathsf{pk},\, v,\, \rho,\, r) \;\in\; \mathbb{F}_p.

Note commitments are appended as leaves to a global Merkle tree T\mathcal{T} of depth d=32d = 32 (capacity 2322^{32} notes). The Merkle root at any epoch is rt\mathsf{rt}.

Definition 3.3 (Nullifier).

nf  =  PRFsk(ρ)  =  Poseidon(sk,ρ). \mathsf{nf} \;=\; \mathsf{PRF}_{sk}(\rho) \;=\; \mathsf{Poseidon}(sk, \rho).

Upon spending, nf\mathsf{nf} is published to a global nullifier set N\mathcal{N}. Double-spending is prevented by rejecting any transaction whose nf\mathsf{nf} already lives in N\mathcal{N}.

Definition 3.4 (SPST Transaction). With nn inputs and mm outputs:

tx  =  ({nfi}i=1n,  {cmj}j=1m,  rt,  f,  π) \mathsf{tx} \;=\; \bigl(\, \{\mathsf{nf}_i\}_{i=1}^{n},\; \{\mathsf{cm}_j\}_{j=1}^{m},\; \mathsf{rt},\; f,\; \pi \,\bigr)

where f{0,,2641}f \in \{0, \ldots, 2^{64}-1\} is the public fee and π\pi is a Groth16 proof of the SPST relation.

The validator accepts iff (i) π\pi verifies, (ii) rt\mathsf{rt} is a recent root, (iii) every nfiN\mathsf{nf}_i \notin \mathcal{N}, and (iv) ffminf \geq f_{\min}.

The SPST relation

The relation RSPST\mathcal{R}_{\mathsf{SPST}} is the set of (x,w)(x, w) pairs:

Public instance x=({nfi},{cmj},rt,f)x = \bigl(\{\mathsf{nf}_i\}, \{\mathsf{cm}_j\}, \mathsf{rt}, f\bigr).

Private witness w=({(notei,pathi,ski)},{notej})w = \bigl(\{(\mathsf{note}_i, \mathsf{path}_i, sk_i)\}, \{\mathsf{note}'_j\}\bigr).

Eight constraints, all enforced by the circuit:

#NameConstraint
C1Spending key validitypki=PRFski(0)\mathsf{pk}_i = \mathsf{PRF}_{sk_i}(0)
C2Nullifier correctnessnfi=PRFski(ρi)\mathsf{nf}_i = \mathsf{PRF}_{sk_i}(\rho_i)
C3Input commitment well-formednesscmi(in)=Poseidon(pki,vi,ρi,ri)\mathsf{cm}^{(\mathsf{in})}_i = \mathsf{Poseidon}(\mathsf{pk}_i, v_i, \rho_i, r_i)
C4Merkle membershipMerkleVerify(rt,cmi(in),pathi)=1\mathsf{MerkleVerify}(\mathsf{rt}, \mathsf{cm}^{(\mathsf{in})}_i, \mathsf{path}_i) = 1
C5Output commitment well-formednesscmj=Poseidon(pkj,vj,ρj,rj)\mathsf{cm}_j = \mathsf{Poseidon}(\mathsf{pk}'_j, v'_j, \rho'_j, r'_j)
C6Value conservation with feeivi=jvj+f\sum_i v_i = \sum_j v'_j + f
C7Non-negative output valuesvj{0,,2641}v'_j \in \{0, \ldots, 2^{64}-1\} (bit decomposition)
C8Non-negative feef{0,,2641}f \in \{0, \ldots, 2^{64}-1\}

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 tx=({nfi},{cmj},rt,f,π)\mathsf{tx} = (\{\mathsf{nf}_i\}, \{\mathsf{cm}_j\}, \mathsf{rt}, f, \pi) be a valid SPST transaction. Then:

  1. The fee ff is funded entirely from consumed shielded notes.
  2. No external account, relayer, or gas sponsor is required.
  3. Validators extract ff as inclusion compensation without learning the private inputs/outputs beyond ff itself and the validity of π\pi.

Proof sketch. (1) follows directly from C6. (2) follows because tx\mathsf{tx} is a self-contained data structure that any party can broadcast; the on-chain verifier decrements the privacy program’s lamport reserve by ff and credits the validator. (3) is the perfect zero-knowledge property of Groth16: the validator sees ff as a public input but learns nothing about viv_i or vjv'_j.

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 ff 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 jvj+f>ivi\sum_j v'_j + f > \sum_i v_i) 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 ivi=jvj+f\sum_i v_i = \sum_j v'_j + f over Fp\mathbb{F}_p. C7 and C8 enforce vj,f[0,264)v'_j, f \in [0, 2^{64}). With at most n216n \leq 2^{16} inputs each bounded by 2642^{64}, ivi<280p2254\sum_i v_i < 2^{80} \ll p \approx 2^{254} — so field arithmetic faithfully represents integer arithmetic and no modular wraparound is possible.

By Groth16 knowledge soundness in the AGM, an extractor E\mathcal{E} can recover the witness ww^* satisfying all constraints C1–C8. C6 in the extracted witness gives ivi=jvj+f\sum_i v_i = \sum_j v'_j + f 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 Cin,i=vig+ri(vc)hC_{\mathsf{in},i} = v_i \cdot g + r^{(\mathsf{vc})}_i \cdot h and Cout,j=vjg+rj(vc)hC_{\mathsf{out},j} = v'_j \cdot g + r^{(\mathsf{vc})}_j \cdot h, the verifier checks

iCin,i  =  jCout,j  +  fg  +  rΔh\sum_i C_{\mathsf{in},i} \;=\; \sum_j C_{\mathsf{out},j} \;+\; f \cdot g \;+\; r_\Delta \cdot h

where rΔ=iri(vc)jrj(vc)r_\Delta = \sum_i r^{(\mathsf{vc})}_i - \sum_j r^{(\mathsf{vc})}_j.

Suppose an adversary passes this check but with jvj+fivi\sum_j v'_j + f \neq \sum_i v_i. Let δ=ivijvjf0\delta = \sum_i v_i - \sum_j v'_j - f \neq 0. Then δg=rΔh\delta \cdot g = r'_\Delta \cdot h for some rΔr'_\Delta, which yields loggh=δ/rΔ\log_g h = \delta / r'_\Delta — contradicting DLOG. ∎

Theorem 3.3 — Double-spend resistance

Game. A\mathcal{A} may adaptively deposit and spend; wins if it produces two accepted transactions consuming the same note note\mathsf{note}^*.

Cases.

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:

Result: AdvAnegl(λ)\mathsf{Adv}_{\mathcal{A}} \leq \mathsf{negl}(\lambda). ∎

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 ff would need to extract a witness with a different ff' satisfying C6, but C6 plus the unchanged input commitments and output commitments uniquely determines ff. Contradiction.

Circuit complexity

For an SPST circuit with nn inputs and mm outputs:

Ctotal    11,500n  +  452m  +  64.C_{\mathsf{total}} \;\approx\; 11{,}500 \cdot n \;+\; 452 \cdot m \;+\; 64.

A canonical 2-in / 2-out transaction:

C2,2  =  23,000+904+64    24,000 constraints.C_{2,2} \;=\; 23{,}000 + 904 + 64 \;\approx\; 24{,}000 \text{ constraints}.
ComponentPer-inputPer-outputSubtotal
Note commitment (input)388388n388n
Merkle path (depth 32)10,40010,400n10{,}400n
PRF evaluations (pk + nf)648648n648n
Range proof (input value)6464n64n
Note commitment (output)388388m388m
Range proof (output value)6464m64m
Fee range proof64

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.

AspectProsCons
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:

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

Previous: The fee paradox ← · Next: PPST: private programmable state →

← Back to article