Appendix A: Cryptographic primitives
This appendix collects cryptographic building blocks used throughout the book but not central to the SNARK narrative. These primitives appear in trusted setups, commitment schemes, and protocol constructions.
Mathematical background
Finite fields
A finite field (for prime ) is the set with addition and multiplication modulo . Every nonzero element has a multiplicative inverse.
- The multiplicative group has order
- Fermat's Little Theorem: For , . Thus .
- Primitive roots: There exists such that
Extension fields arise by adjoining roots of irreducible polynomials. Elements are degree- polynomials over , with multiplication modulo the irreducible polynomial. SNARK-friendly fields often have for 128-bit security.
Roots of unity: If , there exist -th roots of unity satisfying . These enable FFT-based polynomial multiplication.
Elliptic curves
An elliptic curve over is the set of points satisfying plus a "point at infinity" serving as identity.
Points form an abelian group under a geometric addition rule. For distinct points and :
The group order is approximately (Hasse's theorem: ).
Given and , finding is the discrete log problem, believed hard for well-chosen curves. Computing for scalar uses double-and-add, taking group operations.
The Weierstrass form is standard, but other forms offer advantages. Montgomery curves () enable constant-time scalar multiplication via the Montgomery ladder. Twisted Edwards curves () have unified addition formulas (the same formula works for doubling), making them efficient and resistant to side-channel attacks. BabyJubjub and Jubjub are twisted Edwards curves.
Bilinear pairings
A pairing is a map between elliptic curve groups satisfying:
- Bilinearity:
- Non-degeneracy: If and are generators, generates
- Efficiency: Computable in polynomial time
Pairings enable "multiplication in the exponent": given and , you can't compute directly, but moves the product to a different group. KZG commitments use pairings to verify polynomial evaluations: the verifier checks without knowing .
Not all curves support efficient pairings. BN254 and BLS12-381 are specifically designed for this purpose.
Discrete log assumptions
The security of elliptic curve cryptography rests on a hierarchy of assumptions:
- Discrete Log Problem (DLP): Given and , find .
- Computational Diffie-Hellman (CDH): Given , , and , compute .
- Decisional Diffie-Hellman (DDH): Distinguish from for random .
In pairing groups, DDH is easy (check via pairing), but CDH is still believed hard. This is the gap Diffie-Hellman setting that KZG exploits.
Secure random sampling
Many protocols require random field elements sampled uniformly from .
Modulo bias
A common implementation generates random bytes, interprets them as an integer, and takes the result modulo .
x = random_bytes(32) # 256 bits
r = int(x) mod p
This introduces bias. If , some residues are more likely than others. To sample from using a random byte (0-255): values 0-5 appear with probability (26 preimages each) while values 6-9 appear with probability (25 preimages each). The bias is small but potentially exploitable over many samples.
Rejection sampling
Generate candidates and reject those outside an unbiased range.
repeat:
x = random_bytes(32)
if x < p * floor(2^256 / p):
return x mod p
This ensures each residue has equal probability. Expected iterations: when is close to a power of 2.
Hashing to field elements
When deriving field elements from structured data (Fiat-Shamir challenges, randomness beacons):
- Hash the input:
- Interpret as integer and reduce modulo
- Or use a domain-specific "hash-to-field" function (RFC 9380)
The hash output should be larger than (e.g., 512 bits for a 256-bit field) to minimize bias.
Nothing-up-my-sleeve (NUMS) constructions
Sometimes protocols require public constants that "couldn't have been chosen maliciously." If a constant is needed (e.g., a generator, a hash input), how do we convince others it wasn't chosen to create a trapdoor?
The NUMS technique derives the constant from a public, unpredictable source: digits of , , or ; hashes of fixed strings like ; or sequential integers ("Point number 1", "Point number 2", etc.).
In a Powers of Tau ceremony, the initial toxic waste should be derived via NUMS:
Each participant then randomizes: where is their secret randomness.
Shamir's secret sharing
Distribute a secret among parties such that any can reconstruct but learn nothing.
Construction
Work over a finite field with .
Sharing (by dealer):
- Choose random polynomial
- The secret is
- Give party the share
Reconstruction (by any parties):
- Collect shares:
- Use Lagrange interpolation to find :
Security
Any shares are consistent with every possible secret. The polynomial through points can have any value at 0. This is information-theoretic: even computationally unbounded adversaries learn nothing.
The threshold exhibits a sharp discontinuity. With shares, the entropy of the secret is bits (maximum uncertainty). With shares, the entropy drops to zero (the secret is uniquely determined). There is no intermediate state where information leaks gradually as shares accumulate.
Worked example
Secret , threshold , parties , field .
Polynomial: (random coefficient ).
Shares:
- Party 1:
- Party 2:
- Party 3:
Reconstruction from parties 1 and 3:
In : , .
Feldman's verifiable secret sharing
Standard Shamir assumes an honest dealer. A malicious dealer could distribute inconsistent shares that don't reconstruct to any secret, or that reconstruct to different secrets for different groups. Feldman's VSS solves this by broadcasting commitments to the polynomial coefficients.
Setup: Group of prime order , generator .
Sharing:
- Dealer chooses
- Dealer broadcasts commitments:
- Dealer sends share to party
Verification: Party checks:
This holds because:
If verification fails, party broadcasts a complaint. Honest parties can detect malicious dealers.
Feldman VSS reveals (the "encrypted" secret). This may leak partial information (e.g., equality with other secrets). Pedersen VSS adds blinding for perfect hiding.
Hash functions in zero-knowledge
SNARKs use hash functions for Fiat-Shamir challenges, Merkle tree commitments (FRI, STARKs), and random oracle instantiation.
The circuit cost problem
Standard hashes (SHA-256, BLAKE3) are expensive in circuits. SHA-256 uses operations that CPUs handle efficiently (32-bit XOR, bit rotations, boolean operations), but these are catastrophic inside arithmetic circuits over prime fields.
A single XOR in an arithmetic circuit requires decomposing each input into bits (one constraint per bit to enforce booleanity: ), then computing the XOR bit-by-bit as . A 256-bit XOR that takes one CPU cycle becomes hundreds of constraints. SHA-256 costs roughly 25,000-30,000 constraints per invocation. A depth-20 Merkle tree (about 1 million leaves) requires 20 hashes, totaling 500,000-600,000 constraints just for hashing.
Algebraic hashes
Algebraically-friendly hashes use only native field operations: addition and multiplication. No bit operations at all.
Poseidon is the dominant choice. It uses a sponge construction with a permutation built from three layers per round:
- Add round constants: Breaks symmetry. Cost: 0 constraints (additions are linear).
- S-box: Apply (typically ) for nonlinearity. Cost: 2 constraints per S-box.
- MDS matrix: Multiply state by a maximum-distance-separable matrix for diffusion. Cost: 0 constraints (linear operations absorbed into next nonlinear step).
The HADES design uses full rounds (S-box on all state elements) at the beginning and end for statistical security, and partial rounds (S-box on only one element) in the middle for algebraic security. A typical configuration of 8 full rounds and 56 partial rounds totals ~160 constraints per hash, compared to ~25,000 for SHA-256.
Other algebraic hashes include MiMC (2016, simpler but higher multiplicative depth, largely superseded), Rescue (alternates S-box and inverse S-box), and Poseidon2 (2023, same constraints as Poseidon but 3× faster witness generation).
Security considerations
Algebraic hashes have less cryptanalytic history than SHA-256. Poseidon has received sustained analysis (Grassi et al. 2019, subsequent Gröbner basis attacks), and current parameters include security margins. Conservative applications may use more rounds than the minimum recommended or fall back to SHA-256 for security-critical operations outside circuits.
Poseidon is not for general-purpose hashing. For files, passwords, or data at rest, use SHA-256 or BLAKE3. Poseidon is a specialized tool for proving hash computations inside ZK circuits.
Modular arithmetic implementation
SNARK provers spend most time in modular arithmetic. Implementation details matter enormously.
Montgomery multiplication
Standard modular multiplication computes , then divides by and takes the remainder. Montgomery representation avoids the expensive division by storing where for convenient . The Montgomery product replaces division by with division by , which is a bit shift (essentially free in hardware). The conversion overhead is amortized over many operations.
SIMD and parallelism
Modern CPUs have vector instructions (AVX-256, AVX-512) that parallelize field arithmetic: four 64-bit multiplications simultaneously, or eight 32-bit multiplications simultaneously. GPU arithmetic parallelizes across thousands of threads. SNARK provers achieve 10-100× speedup from GPU acceleration.
Random beacons
Some applications require public randomness that cannot be predicted before a deadline, cannot be biased by any party, and is verifiable by all.
Blockchain-based beacons use the hash of a future block as randomness. The block hash is unpredictable until mined, but miners can withhold blocks to manipulate the beacon (at cost of block rewards).
VDF-based beacons use a Verifiable Delay Function that requires sequential time to compute but is fast to verify. A beacon seeds a VDF; by the time the output is known, manipulation is impossible.
Multi-party beacons have multiple parties contribute randomness. If any one is honest, the result is unbiased. The simple protocol has each party commit to a random value, then all reveal; the beacon is the hash of all revealed values. The risk is that the last revealer sees the beacon before revealing; commit-then-reveal with timeouts mitigates this.
Elliptic curves in zero-knowledge
Not all elliptic curves work for SNARKs. Pairing-based systems (Groth16, KZG commitments) require curves with efficiently computable bilinear pairings. The choice of curve determines the scalar field, which in turn determines what field elements your circuit operates over.
BN254 (alt_bn128)
A Barreto-Naehrig curve with embedding degree 12 and the workhorse of practical SNARKs.
- Scalar field: (254 bits)
- Security: Originally claimed ~128 bits, now estimated at ~100 bits due to advances in discrete log attacks on extension fields
- Status: Still widely used (Ethereum precompiles, most zkEVMs, Groth16 deployments)
BN254's scalar field prime:
Ethereum has native precompiles for BN254 operations (ecAdd, ecMul, ecPairing), making it the default for on-chain verification.
BLS12-381
A Barreto-Lynn-Scott curve with embedding degree 12. Designed to provide ~128-bit security even with improved attacks.
- Scalar field: (255 bits)
- Security: Solid 128-bit security margin
- Status: Used in newer systems (Zcash Sapling, Ethereum 2.0 signatures, PLONK implementations)
BLS12-381 is larger than BN254 (larger field, more expensive operations) but future-proof against known attack improvements.
Embedded curves
Pairing curves have large coordinates. Computing BN254 point addition inside a BN254 circuit is expensive because the base field is ~254 bits, requiring big-integer arithmetic in constraints. The solution is to use a different curve whose base field matches the SNARK's scalar field.
BabyJubjub is a twisted Edwards curve defined over BN254's scalar field. Points on BabyJubjub have coordinates in where is BN254's scalar field order. BabyJubjub operations are native arithmetic in BN254 circuits, with point addition costing ~6 constraints instead of thousands. EdDSA signature verification becomes practical inside circuits.
Jubjub plays the same role for BLS12-381: a twisted Edwards curve over BLS12-381's scalar field.
The pattern: an "embedded" or "inner" curve lives over the outer curve's scalar field, enabling efficient in-circuit elliptic curve operations.
Curve cycles
For recursive SNARKs, you need to verify a proof inside a circuit. If both the proof system and the circuit use the same field, the verifier does arithmetic in the scalar field while the proof's group operations are over the base field.
A curve cycle pairs two curves where each curve's base field equals the other's scalar field. Pasta curves (Pallas and Vesta) form such a cycle, enabling efficient recursion in systems like Halo 2.
| Curve | Base Field | Scalar Field |
|---|---|---|
| Pallas | ||
| Vesta |
Prove over Pallas, verify in a Vesta circuit; prove over Vesta, verify in a Pallas circuit. The cycle enables indefinite recursion. The BN254/Grumpkin cycle matters for Ethereum developers: since BN254 is precompiled on Ethereum, systems like Aztec use this cycle to verify recursive proofs on-chain cheaply.
Group operations
Elliptic curve SNARKs rely on fast group operations.
Point addition (affine)
Given points and on curve :
Affine coordinates require field inversion (expensive).
Projective coordinates
Represent as where , . Point addition and doubling use only multiplication, avoiding inversion until final conversion back to affine. Jacobian coordinates with , are optimized for repeated doubling.
Multi-scalar multiplication (MSM)
Compute for scalars and points .
Pippenger's algorithm groups scalars by their bit patterns, reducing work from to .
MSM dominates KZG commitment time. Parallelization and GPU implementation are necessary for practical SNARKs.