FRI
Last updated
Short for “Fast Reed-Solomon Interactive Oracle Proofs of Proximity”, the FRI Protocol is a designed for zkSTARKS. All Interactive Oracle Proofs of Proximity (IOPPs) are designed to verify that a large dataset or computation closely matches a specific structure using only a few queries. FRI, in particular, addresses the challenge of low-degree testing within this framework. But what is “Low Degree Testing,” you ask? Let’s talk about the “Reed-Solomon” portion in FRI’s title to explain.
We’ll pull from and Vitalik’s article “” to explain how Reed-Solomon Encoding works and introduce the idea of “low-degree testing.” Feel free to take an additional look at to understand more about the technicalities behind Reed-Solomon codes.
The goal of Reed-Solomon encoding is to securely pass a message successfully to another party. Let’s look at an example:
Say User A wants to send the message “ABC” to a User B with Reed-Solomon encoding…
First, User A converts this message into a polynomial of degree "." In our case, that’s .
Next, User A evaluates this polynomial on a larger domain of a coset and adds more values to hide the original message.
This set of evaluations is sent all together to User B and is named the “codeword.”
Let’s say User A was instead a malicious user and attempted to send a faulty codeword instead. We’ll change to instead to illustrate how User B could successfully catch this mistake.
But what does a rejection actually mean? If we look at figure 2, we can see that if the codeword was valid, all the values should belong to the same line or to the polynomial of the same degree 2. In comparison, in figure 3, we see that one faulty value would jeopardize the degree of the resulting total polynomial by increasing it to a degree higher than 2. This thus introduces the problem of low-degree testing. Low-degree testing tries to ensure a polynomial is of low-degree, which would insinuate that the original polynomial or codeword is valid.
As you can now see, low-degree testing refers to the process of ensuring a polynomial is of low-degree or smaller than a certain degree. But why is FRI needed specifically for low-degree testing? Well, this ties back to the original goal of IOPPs to use fewer queries or reduce the overall query load. In our example earlier we mentioned that if User B queries a value, a total of other values must be needed to interpolate the polynomial at the given value, with d being the degree of the original polynomial. This results in the naive complexity of each query equaling . However, as an IOPP, The FRI protocol manages to achieve low-degree testing with only queries, as instead of using expensive interpolation, FRI folds the polynomial into a constant to check the degree.
The input to the protocol is a polynomial linked with a bounding degree by which the polynomial’s degree should be at or less than.
As aforementioned, the commit phase follows the prover folding the polynomial to a digestible size. Going forward, we’ll refer to example-specific sections with “(EX)”.
(EX) The prover calculates
(EX) The prover creates a Merkle tree from and commits the root :
After receiving the Merkle Root, the verifier replies with a challenge in response.
With this , the prover calculates the folded polynomial. Let’s look at how this works:
First, is split into two different parts: the terms with a degree of an even number and the terms with a degree of an odd number.
Then the folded polynomial is created from these two parts along with the challenge:
Let’s check how this works with an example:
Our even and odd degree terms would then be split up as such:
From these two split polynomials we can now create our folded polynomial:
Finally, we can see that our polynomial of degree 4 has been successfully folded in half to polynomial of degree 2. Thus all polynomials of degree will be folded to a polynomial of degree .
Next, the prover is evaluated on the given sub-domain. Note that the domain size is reduced by half every fold, resulting in and . In other words, .
(EX) Let’s say our folded polynomial had the following evaluations and .
Finally, the evaluations are used to create a Merkle tree, and the root of the resulting Merkle tree is committed.
(EX) The prover creates a Merkle tree from and and commits the root :
This recursive folding process continues until the polynomial is reduced to a constant and committed as the final result. Note that the evaluations of the polynomials are seen as the codewords within Reed-Solomon encoding, hence, the title of FRI.
(EX) The prover folds the polynomial one more time and gets and commits .
In the query phase, the verifier ensures that the prover’s polynomial evaluations are valid through queries. The following explanations describe the process of running a single query.
The verifier queries a random challenge to the prover.
The prover sends where starts at and the individual Merkle tree proof for each evaluation back to the verifier.
The verifier verifies the Merkle tree proofs.
The verifier uses and to create themselves and checks with the prover’s given answer. How does the verifier do this? Let’s take a look:
Through solving the system of equations of and , we can get and .
Finally, with and , we can create or the next folded polynomial’s evaluations.
Thus with the received and and knowing and , the verifier can create .
The prover continues to send the and evaluations incrementing by each round, while the verifier continues calculating and verifying until the final evaluation is verified (i.e. recursively run steps 2-4).
This query process is repeated to the desired amount of queries.
User B first receives the codeword from User A, and tries to check a random value in the codeword, otherwise known as querying. By chance, let’s say, User B tries to check . User B uses User A’s codeword values excluding to create a Lagrange-based form of a polynomial through interpolation (See for more details on interpolation). In our case, this should be a polynomial of degree 2. Using this interpolated polynomial, User B can now calculate the value at themselves and find that should equal . Finally, they check this self-calculated value against User A’s previously asserted value of and reject the User A’s codeword since the values are not equal.
As Risc Zero explains in their video the FRI protocol is a process in which a polynomial is folded a number of times to reduce the problem size and then verified by a limited number of queries. The FRI protocol is split into two phases: the Commit Phase and the Query Phase. In the commit phase, the prover recursively folds the polynomial and commits their evaluations, while in the query phase, the verifier checks the folded evaluations through their own calculations. Note that while the concept of the FRI protocol mentions folding can by done at any constant scale k, we will explain the process of 2-folding for simplicity and for its prevalence in FRI in code.
The naive version of the FRI protocol consists of the implementation outlined below, with a simple difference of making it non-interactive by introducing a separate challenger. To see naive FRI in code, refer to implementation for Rust or implementation in C++.
With knowledge of the input polynomial , the prover evaluates the polynomial on a given domain (, where is a and n is the domain size). This evaluation is usually done with (Fast-Fourier Transformation). These evaluations all together act as a single Reed-Solomon codeword as if a single evaluation is wrong and is caught, the polynomial is guaranteed to be of high-degree.
These evaluations are then used to create the leaves of a , and the resulting Merkle root is committed to the verifier [MT root]. These evaluations can also be interpreted as the Reed Solomon codeword of the FRI protocol.
The FRI Protocol stands as a valuable IOPP protocol to reduce the number of queries in the case of low-degree testing. While the general scheme simply involves recursively folding a polynomial, the additionally complicates the protocol. If you choose to dive more into the FRI protocol, I recommend you look at the following references for more information.
by the Risc Zero Study Club — A good intro to RS Codes
by the Risc Zero Study Club — A good intro to FRI
by the Risc Zero Study Club — A good view into the process of FRI
by — A good starter overview on FRI
by Vitalik Buterin — Provides insight to the concept behind FRI
by Elliptic Hector — A good visual of the FRI Protocol
— A good hands-on example of FRI
by LambdaClass — Provides a code and computation viewpoint of FRI
— An extensive dive into FRI
— The original FRI paper
by the StarkWare Team — Provides some valuable sections outlining security features and optimizations to add to FRI
by Matter Labs — Section 8 and Section F provide an in-depth view of added security features and optimizations
by Polygon Labs — An extensive view into Two Adic FRI
Written by from