Circle FRI Protocol
FRI verification adapted for circle-group domains — the folding scheme at the heart of the STARK verifier.
Overview
FRI (Fast Reed-Solomon Interactive Oracle Proof of Proximity) is the core mechanism by which the STARK verifier confirms that committed polynomials have bounded degree. Circle FRI adapts the standard FRI protocol to the circle-group evaluation domain used by Stwo.
All FRI logic is implemented in FriVerifier.sol (222 lines).
1. FRI in a Nutshell
The prover claims to have committed a polynomial of degree evaluated on a domain of size . The verifier checks this by:
- Folding: Combine pairs of evaluations using a random challenge to produce a new polynomial of half the degree on a domain of half the size
- Committing: The prover commits (Merkle tree) to each folded polynomial
- Repeating: Continue folding until the polynomial is small enough to send explicitly
- Checking: Verify the final polynomial against the committed constant, and spot-check random queries through all layers
2. Circle FRI vs Standard FRI
Standard FRI operates on multiplicative subgroups. Circle FRI replaces the multiplicative group with the circle group. The first fold is special:
- Circle → Line: Points and (conjugate pairs) are folded using the y-coordinate as the twiddle factor. Result lives on a line domain.
- Subsequent folds: Standard FRI on the line domain.
3. Our Parameters
| Parameter | Value | Description |
|---|---|---|
LIFTING_LOG_SIZE | 7 | Initial evaluation domain size: |
LOG_BLOWUP_FACTOR | 1 | Blowup factor: |
N_QUERIES | 3 | Number of spot-check queries |
N_FRI_INNER_LAYERS | 5 | Number of line-to-line fold layers |
The full sequence:
| Step | Layer Type | Log Size |
|---|---|---|
| 0 | Circle → Line | 7 → 6 |
| 1–5 | Line → Line | 6 → 1 |
| 6 | Last layer | 1 |
4. The Fold Operation
function _fold(uint128 fP, uint128 fNegP, uint32 twiddleInv, uint128 alpha)
internal pure returns (uint128)
{
uint128 f0 = qm31Add(fP, fNegP);
uint128 f1 = qm31MulM31(qm31Sub(fP, fNegP), twiddleInv);
return qm31Add(f0, qm31Mul(alpha, f1));
}Circle Fold Twiddle
For the first layer, pairs are and . Twiddle: .
Line Fold Twiddle
For inner layers, pairs are and . Twiddle: .
5. Domain Construction
Circle Domain (First Layer)
The evaluation domain is the canonical coset circle domain of log-size LIFTING_LOG_SIZE = 7. It has 128 points: 64 "positive" points and their conjugates.
Points are accessed in bit-reversed order.
Common Bug: Domain Index Arithmetic
The initial/step indices use liftingLogSize + 1 and liftingLogSize - 1 (with layer offset), NOT liftingLogSize. Getting this wrong by one produces valid-looking domain points that fail the Merkle check at a specific FRI layer.
6. Pair Reconstruction
At each FRI layer, the verifier needs evaluations at pairs of conjugate positions:
- If both positions are queried — use them directly
- If only one position is queried — the partner comes from the FRI witness array
- After reconstruction, both siblings are verified against the layer's Merkle tree
7. Last Layer Verification
After all folds, the verifier receives the last-layer polynomial explicitly. For each query position, it evaluates the polynomial at the corresponding domain point using Horner's method and checks against the folded evaluation.
8. Gas Impact
FRI verification dominates the overall gas cost (~41% of total ~20M gas):
| Operation | Total Gas |
|---|---|
| Merkle verification (7 trees) | ~3.5M |
| Circle/line point computation | ~700K |
| QM31 fold operations | ~40K |
The dominant cost is Merkle verification across all FRI layers.