Basic FRI Concepts

from polynomials and evaluation domains to low-degree testing, Merkle commitments, folding, queries, soundness, and the STARK proving pipeline

Start with the actual problem

FRI is easier to understand if we first ask what a STARK prover needs to prove.

Suppose a prover claims that some huge computation is valid. After converting the computation into algebraic constraints, the prover eventually needs to convince the verifier about properties of one or more polynomials.

“This huge collection of evaluations comes from a low-degree polynomial.”

The verifier cannot simply download every evaluation and reconstruct the polynomial. There may be millions of values.

FRI provides a scalable way to test this claim through:

commitments

The prover commits to large evaluation vectors using Merkle trees.

random queries

The verifier checks only a small number of positions.

folding

The prover repeatedly transforms a polynomial into a lower-degree polynomial.

At the end, the verifier has evidence that the original function was close to the claimed low-degree structure.

What does FRI stand for?

F — Fast
R — Reed–Solomon
I — Interactive Oracle
P — Proximity

The full name is Fast Reed–Solomon Interactive Oracle of Proximity.

Each word tells us something important.

Fast

The protocol is designed to handle very large evaluation domains efficiently.

Reed–Solomon

The underlying object is a polynomial evaluation code: values generated by evaluating a low-degree polynomial over a domain.

Interactive Oracle

The verifier accesses selected locations of a committed function rather than receiving the entire function.

Proximity

The goal is not merely to ask whether a function is exactly a codeword, but whether it is sufficiently close to one.

First principle: what is a polynomial?

A polynomial over a field can be written as:

f(X) = a₀ + a₁X + a₂X² + … + a_dX^d

The largest exponent with a non-zero coefficient is the degree.

deg(f) ≤ d

For example:

f(X) = 3 + 2X + 7X²
deg(f) = 2

FRI is fundamentally interested in whether a function behaves like a polynomial whose degree is below a specified bound.

The polynomial lives over a finite field

STARK systems do not normally evaluate polynomials over the real numbers.

They work over a finite field.

F = {0, 1, 2, …, p−1}
all arithmetic is performed modulo p

For example, over the field modulo 17:

15 + 5 = 3 mod 17
4 · 5 = 3 mod 17

Therefore a polynomial such as:

f(X) = 2 + 3X + 5X²

can be evaluated at field elements using finite-field arithmetic.

From coefficients to evaluations

A polynomial can be represented by its coefficients:

[a₀, a₁, a₂, …, a_d]

Or we can evaluate it at a collection of points:

[f(x₀), f(x₁), f(x₂), …, f(xₙ)]

FRI works primarily with this evaluation representation.

This is important because the prover can commit to a large vector of evaluations without revealing the entire polynomial's coefficients.

What is an evaluation domain?

An evaluation domain is a chosen set of field elements where the polynomial will be evaluated.

D = {x₀, x₁, x₂, …, x_{n−1}}

In STARK systems, the domain is often chosen with strong algebraic structure, commonly using a multiplicative subgroup or a related structured domain.

A structured domain makes polynomial operations and FFT-style transformations efficient.

Example

Suppose:

D = {1, ω, ω², …, ω^{n−1}}

where ω is an element with the required multiplicative order.

Reed–Solomon code: the key connection

A Reed–Solomon code can be understood as taking a low-degree polynomial and encoding it by evaluating it at many points.

polynomial f
↓ evaluate on D
codeword = [f(x₀), f(x₁), …, f(xₙ₋₁)]

So a low-degree polynomial corresponds to a highly structured evaluation vector.

FRI exploits this structure.

Mental model: instead of asking “is this list of numbers a polynomial?”, think “is this evaluation vector close to the evaluation vector of a sufficiently low-degree polynomial?”

What is an oracle?

An oracle is an abstraction for a function that the verifier can query at selected positions.

Imagine the prover has a huge vector:

v = [v₀, v₁, v₂, …, vₙ₋₁]

The verifier does not receive the whole vector.

Instead, it asks:

“Give me v₁₂₇.”
“Give me v₈₄₂.”
“Give me v₁₀₂₄.”

FRI is an oracle proof because the verifier reasons about a huge function through a relatively small number of queries.

What does “proximity” mean?

This is one of the most important words in FRI.

Suppose the verifier expects a function that comes from a polynomial of degree at most d.

A function may not be exactly such a polynomial, but it might differ at only a small fraction of its positions.

f_actual ≈ f_low_degree

FRI is designed to distinguish between:

close to low degree

The oracle differs from some valid low-degree polynomial only on a small fraction of the domain.

far from low degree

The oracle is not close to any polynomial within the claimed degree bound.

Why does the prover need to commit first?

If the prover could wait until seeing the verifier's queries before choosing values, it could answer each query dishonestly in a coordinated way.

Therefore the prover first commits to the evaluation vector.

evaluation vector Merkle tree root verifier

The Merkle root acts as a compact commitment to the complete vector.

Merkle commitments in FRI

Suppose the prover has evaluations:

v₀, v₁, v₂, …, v₇

Hash the leaves:

hᵢ = H(vᵢ)

Then repeatedly hash pairs:

h₀₁ = H(h₀ || h₁)
h₂₃ = H(h₂ || h₃)
root = H(h₀₁ || h₂₃ || …)

Later, the prover gives a queried value together with its authentication path.

The verifier can reconstruct the root and check that the value was part of the committed vector.

The central idea: folding

FRI repeatedly reduces the size and degree of the polynomial problem.

The easiest intuition is to split evaluations into two halves:

f₀(x), f₁(x)

and combine them using a random verifier challenge.

A common conceptual form is:

g(x²) = (f(x) + α f(−x)) / 2

where α is a random challenge derived from the transcript.

The exact implementation can be expressed in several equivalent forms depending on the domain and indexing convention.

Key intuition: folding combines information from two related points into one new point while reducing the effective degree of the object being tested.

Why does pairing x and −x help?

Write a polynomial as its even and odd parts:

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

Then:

f(x) + f(−x) = 2 f_even(x²)
f(x) − f(−x) = 2x f_odd(x²)

This decomposition is the algebraic reason folding can reduce the degree problem.

FRI uses a random linear combination of these pieces so that a cheating function is unlikely to continue looking low-degree after repeated folds.

What is the random challenge α?

At each folding round, the verifier contributes a random field element.

α₀ → first fold
α₁ → second fold
α₂ → third fold

These challenges prevent the prover from preparing a malicious function specifically for a known folding rule.

In a non-interactive STARK, the challenges are typically derived using Fiat–Shamir:

αᵢ = H(previous transcript)

FRI rounds

A simplified FRI protocol repeatedly performs:

commit challenge fold commit challenge fold

After each fold, the domain becomes smaller and the degree bound decreases.

Conceptually:

D₀ → D₁ → D₂ → D₃ → …
size: N → N/2 → N/4 → N/8 → …
degree bound: d → roughly d/2 → roughly d/4 → …

The precise degree relationship depends on the protocol variant and how the folding is defined.

A tiny conceptual example

Suppose the prover claims a polynomial has degree at most 3:

deg(f) ≤ 3

Evaluate it over a domain of eight points:

[f(x₀), f(x₁), …, f(x₇)]

FRI can fold the eight evaluations into four:

8 evaluations → 4 folded evaluations

Then:

4 → 2 → 1

The point is not that “one value proves the polynomial.” The point is that repeated algebraic reductions make the low-degree claim progressively easier to test, while random challenges preserve soundness.

What happens at the end?

Eventually the polynomial is reduced to a very small object.

The verifier can directly check the final representation against the expected low-degree structure.

large polynomial → folds → small polynomial → direct check

The prover cannot simply choose arbitrary final values because every folding step is tied to previous committed evaluations and transcript challenges.

Why are random queries necessary?

The verifier cannot inspect every position in every FRI layer.

Instead, it samples a small number of random positions.

huge domain → random query i → local consistency checks

For each query, the verifier checks the values needed to reconstruct the corresponding fold relation.

If the prover's function is far from low degree, random sampling gives the verifier a significant chance of detecting inconsistency.

Soundness intuition: a cheating prover may hide bad locations, but it cannot know which locations the verifier will query after it has committed.

What does a query look like?

Suppose the verifier chooses an index i.

The prover must provide enough information to verify the fold relationship involving the corresponding pair of locations.

query i related index field values fold equation Merkle paths

Repeated queries make it increasingly unlikely that a significantly corrupted oracle passes all checks.

FRI and Fiat–Shamir

The original FRI description is interactive: the verifier sends random challenges.

A STARK prover generally needs a non-interactive proof.

Fiat–Shamir derives each challenge from the transcript:

commit₀
α₀ = H(statement || commit₀)
fold₀
commit₁
α₁ = H(statement || commit₀ || commit₁)
fold₁

This creates a deterministic transcript that both prover and verifier can reproduce.

Careful transcript design and domain separation are essential for security.

Why the order matters

The protocol must preserve the causal order:

commit → challenge → respond

not:

challenge → choose commitment

If the prover can adapt its committed function after learning the challenge, the soundness argument can fail.

How FRI gets soundness

Suppose the prover's oracle is far from every polynomial of the claimed degree.

The prover commits to this oracle before seeing the random challenges.

FRI's folding transformation and random challenges make it difficult for a far-from-low-degree function to remain consistent through every round.

bad oracle
↓ random fold
still unlikely to look low-degree
↓ random fold
still unlikely
↓ queries
detected with high probability

The formal soundness analysis is more involved and depends on the field, degree bound, rate, number of rounds, and number of queries.

Soundness error intuition

If a cheating oracle has only a small chance of passing one random test, repeating independent or appropriately structured tests reduces the overall cheating probability.

one test → failure probability ε
q effective tests → roughly ε^q

The exact bound is protocol-specific, so this should be treated as intuition rather than a universal FRI formula.

What is the code rate?

The evaluation domain is usually larger than the polynomial's degree bound.

domain size = N
degree bound = d

The ratio between the amount of information represented and the size of the encoded domain is related to the code rate.

In simple intuition:

more evaluation points relative to degree → more redundancy → more error-detection capability

FRI relies on this redundancy to test whether the oracle is consistent with a low-degree polynomial.

FRI and low-degree extension

In STARKs, a polynomial is often first evaluated over a larger domain than the original execution trace domain.

This is called a low-degree extension (LDE).

trace values
↓ interpolate
trace polynomial
↓ evaluate on larger domain
LDE evaluations

The enlarged domain provides redundancy that is useful for proximity testing and soundness.

Where does the composition polynomial fit?

In a STARK, the prover does not usually ask FRI to prove every individual AIR constraint independently.

Constraint violations can be combined into a composition polynomial or related algebraic object.

execution trace
AIR constraints
composition polynomial
FRI low-degree proof

FRI then helps prove that the relevant composition object has the required low-degree structure.

FRI is not automatically zero knowledge

This distinction is important.

FRI is fundamentally a low-degree testing / proximity protocol. Zero knowledge is a separate security property.

FRI → low-degree soundness
ZK mechanisms → hide witness-dependent information

A complete zero-knowledge STARK adds appropriate masking, randomization, and protocol techniques so that the proof does not reveal the private execution data that should remain hidden.

FRI inside a STARK

A simplified STARK pipeline is:

program execution trace AIR polynomials Merkle commitments FRI proof

FRI is therefore not the entire STARK. It is one of the central components used to establish low-degree proximity.

Rust: the core folding idea

Educational FRI-style folding
rust
// Educational illustration only.
// Real FRI implementations must use field elements,
// a carefully chosen domain, transcript challenges,
// commitments, and exact protocol indexing.

fn fold(
    f_x: FieldElement,
    f_minus_x: FieldElement,
    alpha: FieldElement,
) -> FieldElement {
    // Conceptual form:
    // g(x²) = (f(x) + alpha * f(-x)) / 2
    let two_inv = FieldElement::from(2).inverse();
    (f_x + alpha * f_minus_x) * two_inv
}

// A real prover would:
// 1. evaluate a polynomial over a domain
// 2. commit to the evaluations
// 3. derive alpha from the transcript
// 4. fold the evaluations
// 5. commit to the next layer
// 6. repeat until the final layer

The important part is not the syntax. The important part is the repeated transformation:

large evaluation vector → smaller evaluation vector → smaller → …

What a real FRI implementation must handle

field arithmetic

Every value must be a valid element of the selected finite field.

domain indexing

Paired points must be mapped consistently across every folding round.

transcript

Challenges must be derived in the exact order expected by prover and verifier.

Merkle commitments

Every FRI layer must be committed before its challenge is known.

query paths

The verifier must request all sibling values needed to validate folding relationships.

final polynomial

The final reduced object must be checked against the claimed degree bound.

FRI vs FFT

These are easy to confuse because both appear together in STARK implementations.

FFT / IFFT

Efficiently moves between polynomial coefficients and evaluations over a structured domain.

FRI

Provides a protocol for testing that an evaluation oracle is close to a low-degree polynomial.

A STARK prover may use FFTs to construct polynomial evaluations and FRI to prove the resulting low-degree claims.

FRI vs Merkle trees

A Merkle tree by itself does not prove that a vector comes from a low-degree polynomial.

Merkle tree → commitment to data
FRI → low-degree proximity protocol

They work together:

FRI layer Merkle root random query authentication path

FRI vs KZG

Both can be used as polynomial-proof machinery, but their cryptographic approaches are very different.

Property FRI KZG
Core idea Low-degree testing through recursive folding Algebraic polynomial commitment with evaluation proofs
Commitment style Hash / Merkle commitments Elliptic-curve group commitment
Pairings Not required by core FRI Used for common KZG verification
Trusted setup Transparent Traditional KZG requires an SRS generated from secret setup randomness
Proof size Generally larger Very compact evaluation proofs
Typical STARK role Core low-degree testing component Not the usual commitment scheme

Why does folding actually help?

Suppose the initial domain contains N evaluations.

After one fold:

N → N/2

After another:

N/2 → N/4

After r rounds:

N / 2^r

This logarithmic number of rounds is what makes recursive reduction practical for very large domains.

The simplest mental model

1. Start with a huge evaluation vector.
2. Commit to it.
3. Receive a random challenge.
4. Fold paired evaluations into a smaller vector.
5. Commit to the smaller vector.
6. Repeat.
7. Randomly query the layers.
8. Verify Merkle paths and fold equations.
9. Check the final low-degree object.

The prover cannot freely change old layers because every layer was committed before the corresponding challenge was derived.

Interview-level questions

Q1
What does FRI stand for?

Fast Reed–Solomon Interactive Oracle of Proximity.

Q2
What problem does FRI solve?

It provides a scalable protocol for testing whether an oracle is close to the evaluation of a low-degree polynomial.

Q3
Why is it called “proximity”?

The verifier tests whether the function is close to a valid low-degree Reed–Solomon codeword, rather than requiring direct reconstruction of the whole polynomial.

Q4
What is folding?

Folding combines evaluations at related domain points using a random challenge to produce a new function on a smaller domain with a lower effective degree bound.

Q5
Why are Merkle trees used?

They commit to large evaluation vectors while allowing the verifier to authenticate only the values needed for random queries.

Q6
Why must the prover commit before the challenge?

Otherwise the prover could adapt the evaluation vector after learning which folding or query choices will be tested.

Q7
What does Fiat–Shamir do in FRI?

It derives verifier challenges from the transcript, allowing an interactive-style FRI protocol to be represented as a non-interactive proof.

Q8
Is FRI the same thing as a STARK?

No. FRI is a central low-degree testing component used by common STARK constructions, but a STARK includes the complete proving system around it.

Q9
Is FRI zero knowledge?

FRI itself is primarily a low-degree proximity protocol. A zero-knowledge STARK needs additional mechanisms to hide witness-dependent information.

Q10
Why is FRI useful for zkVMs?

A zkVM produces huge algebraic traces and polynomial representations. FRI lets the verifier test the required low-degree claims without downloading every evaluation.

The whole idea in one map

first-principles map
1. A polynomial can be represented by its evaluations over a domain.
2. Evaluations of a low-degree polynomial form a Reed–Solomon codeword.
3. A STARK needs to prove that huge evaluation vectors have this low-degree structure.
4. The prover commits to each evaluation layer using a Merkle tree.
5. The verifier supplies random challenges.
6. FRI folds related evaluations using those challenges.
7. Each fold reduces the domain and the effective degree bound.
8. The verifier checks a small number of random query paths.
9. Repeated random checks make far-from-low-degree cheating difficult.
10. The final reduced object is checked directly.
11. Fiat–Shamir turns transcript challenges into deterministic hash-derived challenges.
12. FRI provides low-degree proximity testing; it is not the entire STARK.

If you remember only one sentence, remember this: FRI lets a verifier test, using commitments, random queries, and recursive folding, whether a huge evaluation oracle is consistent with a low-degree polynomial without downloading the entire polynomial.