Skip to content

Commit

Permalink
perf!: Include last FRI polynomial into proof
Browse files Browse the repository at this point in the history
No performance change was observed on my laptop using benchmark
`prove_verify_halt` (11ms in both cases) but the main selling
point comes from the smaller anticipated clock cycle count in the
recursive verifier.

BREAKING CHANGE: Now the prover sends the last polynomial in addition to
the last codeword in FRI. The verifier verifies that the polynomial is
of low degree directly (without iNTTs!) and checks that it matches with
the codeword using the barycentric evaluation function and randomness
sampled from the proof stream's sponge state.

Closes #156
  • Loading branch information
aszepieniec authored and jan-ferdinand committed Apr 23, 2024
1 parent cff63b2 commit f8a59c5
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 11 deletions.
35 changes: 24 additions & 11 deletions triton-vm/src/fri.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::marker::PhantomData;

use itertools::Itertools;
use num_traits::Zero;
use rayon::iter::*;
use twenty_first::math::traits::FiniteField;
use twenty_first::math::traits::PrimitiveRootOfUnity;
Expand Down Expand Up @@ -54,6 +55,7 @@ impl<'stream, H: AlgebraicHasher> FriProver<'stream, H> {
self.commit_to_next_round()?;
}
self.send_last_codeword();
self.send_last_polynomial();
Ok(())
}

Expand Down Expand Up @@ -95,6 +97,15 @@ impl<'stream, H: AlgebraicHasher> FriProver<'stream, H> {
self.proof_stream.enqueue(proof_item);
}

fn send_last_polynomial(&mut self) {
let last_codeword = &self.rounds.last().unwrap().codeword;
let last_polynomial = ArithmeticDomain::of_length(last_codeword.len())
.unwrap()
.interpolate(last_codeword);
let proof_item = ProofItem::FriPolynomial(last_polynomial.coefficients);
self.proof_stream.enqueue(proof_item);
}

fn query(&mut self) -> ProverResult<()> {
self.sample_first_round_collinearity_check_indices();

Expand Down Expand Up @@ -194,6 +205,7 @@ struct FriVerifier<'stream, H: AlgebraicHasher> {
rounds: Vec<VerifierRound>,
first_round_domain: ArithmeticDomain,
last_round_codeword: Vec<XFieldElement>,
last_round_polynomial: Polynomial<XFieldElement>,
last_round_max_degree: usize,
num_rounds: usize,
num_collinearity_checks: usize,
Expand All @@ -212,7 +224,8 @@ struct VerifierRound {
impl<'stream, H: AlgebraicHasher> FriVerifier<'stream, H> {
fn initialize(&mut self) -> VerifierResult<()> {
self.initialize_verification_rounds()?;
self.receive_last_round_codeword()
self.receive_last_round_codeword()?;
self.receive_last_round_polynomial()
}

fn initialize_verification_rounds(&mut self) -> VerifierResult<()> {
Expand Down Expand Up @@ -289,6 +302,12 @@ impl<'stream, H: AlgebraicHasher> FriVerifier<'stream, H> {
Ok(())
}

fn receive_last_round_polynomial(&mut self) -> VerifierResult<()> {
let coefficients = self.proof_stream.dequeue()?.try_into_fri_polynomial()?;
self.last_round_polynomial = Polynomial::new(coefficients);
Ok(())
}

fn compute_last_round_folded_partial_codeword(&mut self) -> VerifierResult<()> {
self.sample_first_round_collinearity_check_indices();
self.receive_authentic_partially_revealed_codewords()?;
Expand Down Expand Up @@ -504,25 +523,17 @@ impl<'stream, H: AlgebraicHasher> FriVerifier<'stream, H> {
&mut self,
) -> VerifierResult<()> {
let indeterminate = self.proof_stream.sample_scalars(1)[0];
let last_round_polynomial = self.last_round_polynomial();
let horner_evaluation = last_round_polynomial.evaluate(indeterminate);
let horner_evaluation = self.last_round_polynomial.evaluate(indeterminate);
let barycentric_evaluation = barycentric_evaluate(&self.last_round_codeword, indeterminate);
if horner_evaluation != barycentric_evaluation {
return Err(LastRoundPolynomialEvaluationMismatch);
}
if last_round_polynomial.degree() > self.last_round_max_degree.try_into().unwrap() {
if self.last_round_polynomial.degree() > self.last_round_max_degree.try_into().unwrap() {
return Err(LastRoundPolynomialHasTooHighDegree);
}
Ok(())
}

fn last_round_polynomial(&self) -> Polynomial<XFieldElement> {
let domain = self.rounds.last().unwrap().domain;
domain
.with_offset(bfe!(1))
.interpolate(&self.last_round_codeword)
}

fn first_round_partially_revealed_codeword(&self) -> Vec<(usize, XFieldElement)> {
let partial_codeword_a = self.rounds[0].partial_codeword_a.clone();
let partial_codeword_b = self.rounds[0].partial_codeword_b.clone();
Expand Down Expand Up @@ -631,6 +642,7 @@ impl<H: AlgebraicHasher> Fri<H> {
rounds: vec![],
first_round_domain: self.domain,
last_round_codeword: vec![],
last_round_polynomial: Polynomial::zero(),
last_round_max_degree: self.last_round_max_degree(),
num_rounds: self.num_rounds(),
num_collinearity_checks: self.num_collinearity_checks,
Expand Down Expand Up @@ -913,6 +925,7 @@ mod tests {
(MerkleRoot(p), MerkleRoot(v)) => prop_assert_eq!(p, v),
(FriResponse(p), FriResponse(v)) => prop_assert_eq!(p, v),
(FriCodeword(p), FriCodeword(v)) => prop_assert_eq!(p, v),
(FriPolynomial(p), FriPolynomial(v)) => prop_assert_eq!(p, v),
_ => panic!("Unknown items.\nProver: {prover_item:?}\nVerifier: {verifier_item:?}"),
}
}
Expand Down
2 changes: 2 additions & 0 deletions triton-vm/src/proof_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ proof_items!(
Log2PaddedHeight(u32) => false, try_into_log2_padded_height,
QuotientSegmentsElements(Vec<QuotientSegments>) => false, try_into_quot_segments_elements,
FriCodeword(Vec<XFieldElement>) => false, try_into_fri_codeword,
FriPolynomial(Vec<XFieldElement>) => false, try_into_fri_polynomial,
FriResponse(FriResponse) => false, try_into_fri_response,
);

Expand Down Expand Up @@ -189,6 +190,7 @@ pub(crate) mod tests {
assert!(let Err(UnexpectedItem{..}) = item.clone().try_into_log2_padded_height());
assert!(let Err(UnexpectedItem{..}) = item.clone().try_into_quot_segments_elements());
assert!(let Err(UnexpectedItem{..}) = item.clone().try_into_fri_codeword());
assert!(let Err(UnexpectedItem{..}) = item.clone().try_into_fri_polynomial());
assert!(let Err(UnexpectedItem{..}) = item.try_into_fri_response());
}

Expand Down

0 comments on commit f8a59c5

Please sign in to comment.