Technical Notes · Zero Knowledge

FRI From Scratch

How low-degree testing works, why FRI repeatedly folds a polynomial, and how the commit–fold–query loop fits into a STARK proving pipeline.

Srishti Rathi · Technical Notes · May 2026

The problem FRI solves

In a STARK, the prover commits to large vectors of field elements that are supposed to be evaluations of low-degree polynomials. The verifier can't afford to download every value, interpolate the polynomial, and check its degree directly.

FRI — Fast Reed–Solomon Interactive Oracle Proof of Proximity — gives the verifier a cheaper way to test whether the committed evaluations are close to a polynomial below a required degree bound.

evaluations commit fold commit again repeat query

Why low degree matters

A STARK turns execution correctness into polynomial identities. Trace columns become polynomials, AIR constraints become algebraic relations, and the resulting polynomial claims come with degree bounds. If a prover could swap in arbitrary high-degree functions instead, the verifier's algebraic checks would no longer establish what they're supposed to.

FRI isn't the part that proves a program's transition constraints. Its job is to test the low-degree property of the polynomial data the earlier stages of the STARK produced.

Commit to the evaluation layer

Suppose f(X) has been evaluated over a multiplicative domain. The prover places those evaluations into a Merkle tree and sends only the root — fixing the entire layer before the verifier's next random challenge is even known.

f(x₀), f(x₁), …, f(xₙ₋₁) Merkle tree root

The folding idea

Write the polynomial by splitting its even and odd powers:

f(X) = f_even(X²) + X · f_odd(X²)

The verifier samples a random field element β. The prover then defines the next polynomial by mixing the two halves:

g(Y) = f_even(Y) + β · f_odd(Y)

If f has degree roughly d, its even and odd parts have degree roughly d/2. The new polynomial has a correspondingly smaller degree bound.

degree d fold with β₀ about d/2 fold with β₁ about d/4

Folding directly from evaluations

For opposite domain points x and -x, the even and odd pieces can be recovered directly from their evaluations, without ever interpolating a polynomial:

even = (f(x) + f(-x)) / 2
odd = (f(x) - f(-x)) / (2x)

So the next-layer evaluation becomes:

g(x²) = (f(x) + f(-x))/2 + β · (f(x) - f(-x))/(2x)

That's what makes folding practical to implement — the prover works directly with evaluation vectors, round after round, instead of reconstructing a new polynomial at every step.

Commit → challenge → fold

The order here is essential. The prover commits to the current layer first; only after that commitment is fixed does β get sampled. In a non-interactive STARK, Fiat–Shamir derives that challenge from the transcript instead of an actual verifier.

layer Merkle root transcript challenge β fold next layer

The process repeats, halving the layer in a binary FRI construction, until the remaining polynomial is small enough to check directly.

1024 512 256 128 final layer

Why queries are still needed

Merkle roots only show that the prover fixed each layer — they don't show that one layer was honestly obtained by folding the previous one. Once every commitment is fixed, the verifier chooses random query positions to check that.

For each query, the prover opens the required values from one layer along with their Merkle authentication paths. The verifier checks those paths, recomputes the fold using the round's challenge, and compares the result against the opened value in the next layer.

open pair verify Merkle paths recompute fold compare with next layer

Why random queries give confidence

If the original data is far from every low-degree polynomial, the prover generally can't make all the committed layers behave like honest folds at once. Random query paths exist to expose exactly that kind of inconsistency, and repeating the test across many independently sampled queries shrinks the chance that malformed data slips through undetected.

FRI's formal soundness is a Reed–Solomon proximity-testing statement. Concrete security depends on parameters like code rate, domain size, folding strategy, and number of queries — it's more subtle than saying one random query catches every bad polynomial.

Why low-degree extension comes first

Before FRI runs, a STARK normally evaluates its polynomial over a domain larger than the original trace domain — the low-degree extension. Those extra evaluations introduce redundancy: a genuinely low-degree polynomial can't take arbitrary values across the enlarged domain, which is exactly the structure FRI needs to test against.

trace interpolate evaluate on larger domain commit FRI

Where FRI fits in a STARK

By the time FRI runs, execution correctness has already been translated into algebraic constraints and polynomial claims. FRI supplies the low-degree-testing layer that makes those claims efficiently checkable.

execution trace AIR constraints polynomial claims LDE FRI

FRI and KZG solve related problems differently

Property FRI KZG
Core technique Folding + proximity testing Algebraic polynomial commitment
Commitments Typically hashes / Merkle trees Elliptic-curve group elements
Trusted setup No secret setup Requires an SRS
Proof data Queries and Merkle paths make proofs larger Very small opening proofs
Verification Random query and fold consistency checks Pairing-based check

Takeaway

FRI replaces the expensive instruction "reconstruct this huge polynomial and check its degree" with a sequence of smaller commitments and random consistency checks.

The prover repeatedly commits, receives a challenge, and folds. Once every layer is fixed, the verifier queries a handful of paths and checks that the folds were performed consistently.

The core mental model is: commit → challenge → fold → repeat → query. That's the heart of FRI, and the low-degree-testing machinery behind a STARK.