diff --git a/src/core/commitment_scheme/mod.rs b/src/core/commitment_scheme/mod.rs index 1459e27bd..20f933792 100644 --- a/src/core/commitment_scheme/mod.rs +++ b/src/core/commitment_scheme/mod.rs @@ -1,14 +1,34 @@ -use std::collections::BTreeMap; +//! Implements a FRI polynomial commitment scheme. +//! This is a protocol where the prover can commit on a set of polynomials and then prove their +//! opening on a set of points. +//! Note: This implementation is not really a polynomial commitment scheme, because we are not in +//! the unique decoding regime. This is enough for a STARK proof though, where we onyl want to imply +//! the existence of such polynomials, and re ok with having a small decoding list. + +pub mod utils; + use std::iter::zip; use std::ops::Deref; use itertools::Itertools; +pub use self::utils::TreeVec; use super::backend::cpu::{CPUCircleEvaluation, CPUCirclePoly}; +use super::backend::CPUBackend; use super::channel::Blake2sChannel; +use super::circle::CirclePoint; use super::fields::m31::BaseField; -use super::poly::circle::CanonicCoset; +use super::fields::qm31::SecureField; +use super::fri::{ + CirclePolyDegreeBound, FriConfig, FriProof, FriProver, FriVerifier, SparseCircleEvaluation, +}; +use super::oods::get_pair_oods_quotient; +use super::poly::circle::{CanonicCoset, CircleDomain, CircleEvaluation}; use super::poly::BitReversedOrder; +use super::proof_of_work::{ProofOfWork, ProofOfWorkProof}; +use super::prover::{ + LOG_BLOWUP_FACTOR, LOG_LAST_LAYER_DEGREE_BOUND, N_QUERIES, PROOF_OF_WORK_BITS, +}; use super::queries::SparseSubCircleDomain; use super::ColumnVec; use crate::commitment_scheme::blake2_hash::{Blake2sHash, Blake2sHasher}; @@ -16,90 +36,142 @@ use crate::commitment_scheme::merkle_decommitment::MerkleDecommitment; use crate::commitment_scheme::merkle_tree::MerkleTree; use crate::core::channel::Channel; -pub mod utils; - -/// Holds a vector for each tree, which holds a vector for each column, which holds its respective -/// opened values. -pub struct OpenedValues(pub Vec>>); - -impl Deref for OpenedValues { - type Target = Vec>>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -pub struct Decommitments(Vec>); - -impl Deref for Decommitments { - type Target = Vec>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +type MerkleHasher = Blake2sHasher; +type ProofChannel = Blake2sChannel; +/// The prover size of a FRI polynomial commitment scheme. See [self]. pub struct CommitmentSchemeProver { - pub trees: Vec, + pub trees: TreeVec, pub log_blowup_factor: u32, } impl CommitmentSchemeProver { pub fn new(log_blowup_factor: u32) -> Self { CommitmentSchemeProver { - trees: Vec::new(), + trees: TreeVec::::default(), log_blowup_factor, } } - pub fn commit(&mut self, polynomials: ColumnVec, channel: &mut Blake2sChannel) { + pub fn commit(&mut self, polynomials: ColumnVec, channel: &mut ProofChannel) { let tree = CommitmentTreeProver::new(polynomials, self.log_blowup_factor, channel); self.trees.push(tree); } - pub fn roots(&self) -> Vec { - self.trees.iter().map(|tree| tree.root()).collect() + pub fn roots(&self) -> TreeVec { + self.trees.as_ref().map(|tree| tree.root()) } - pub fn decommit( + pub fn polys(&self) -> TreeVec> { + self.trees + .as_ref() + .map(|tree| tree.polynomials.iter().collect()) + } + + fn evaluations(&self) -> TreeVec>> { + self.trees + .as_ref() + .map(|tree| tree.evaluations.iter().collect()) + } + + pub fn open_values( &self, - positions: BTreeMap, - ) -> (OpenedValues, Decommitments) { - let (values, decommitments) = self - .trees - .iter() - .map(|tree| { - tree.decommit( - positions[&(tree.polynomials[0].log_size() + self.log_blowup_factor)].flatten(), - ) - }) - .unzip(); - (OpenedValues(values), Decommitments(decommitments)) + open_points: TreeVec>>>, + channel: &mut ProofChannel, + ) -> CommitmentSchemeProof { + // Evaluate polynomials on open points. + let opened_values = self + .polys() + .zip_cols(&open_points) + .map_cols(|(poly, points)| { + points + .iter() + .map(|point| poly.eval_at_point(*point)) + .collect_vec() + }); + channel.mix_felts(&opened_values.clone().flatten_all()); + + // Compute oods quotients for boundary constraints on open_points. + let quotients = self + .evaluations() + .zip_cols(&opened_values) + .zip_cols(&open_points) + .map_cols(|((evaluation, values), points)| { + zip(points, values) + .map(|(&point, &value)| { + get_pair_oods_quotient(point, value, evaluation).bit_reverse() + }) + .collect_vec() + }); + + // Run FRI commitment phase on the oods quotients. + let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES); + // TODO(spapini): Remove rev() when we start accumulating by size. + // This is only done because fri demands descending sizes. + let fri_prover = FriProver::::commit( + channel, + fri_config, + "ients.flatten_all_rev(), + ); + + // Proof of work. + let proof_of_work = ProofOfWork::new(PROOF_OF_WORK_BITS).prove(channel); + + // FRI decommitment phase. + let (fri_proof, fri_query_domains) = fri_prover.decommit(channel); + + // Decommit the FRI queries on the merkle trees. + let decommitment_results = self.trees.as_ref().map(|tree| { + tree.decommit( + fri_query_domains[&(tree.polynomials[0].log_size() + self.log_blowup_factor)] + .flatten(), + ) + }); + let queried_values = decommitment_results.as_ref().map(|(v, _)| v.clone()); + let decommitments = decommitment_results.map(|(_, d)| d); + + CommitmentSchemeProof { + opened_values, + decommitments, + queried_values, + proof_of_work, + fri_proof, + } } } +pub struct CommitmentSchemeProof { + pub opened_values: TreeVec>>, + pub decommitments: TreeVec>, + pub queried_values: TreeVec>>, + pub proof_of_work: ProofOfWorkProof, + pub fri_proof: FriProof, +} + +/// Prover data for a single commitment tree in a commitment scheme. The commitment scheme allows to +/// commit on a set polynomials at a time. This corresponds to such a set. pub struct CommitmentTreeProver { pub polynomials: ColumnVec, pub evaluations: ColumnVec>, // TODO(AlonH): Change to mixed degree merkle and remove values clone. - pub commitment: MerkleTree, + commitment: MerkleTree, } impl CommitmentTreeProver { - pub fn new( - polynomials: Vec, + fn new( + polynomials: ColumnVec, log_blowup_factor: u32, - channel: &mut Blake2sChannel, + channel: &mut ProofChannel, ) -> Self { - let domains = polynomials + let evaluations = polynomials .iter() - .map(|poly| CanonicCoset::new(poly.log_size() + log_blowup_factor)) - .collect_vec(); - let evaluations = zip(&polynomials, domains) - .map(|(poly, domain)| poly.evaluate(domain.circle_domain())) + .map(|poly| { + poly.evaluate( + CanonicCoset::new(poly.log_size() + log_blowup_factor).circle_domain(), + ) + }) .collect_vec(); - let commitment = MerkleTree::::commit( + let commitment = MerkleTree::::commit( evaluations .iter() .map(|eval| eval.values.clone()) @@ -115,76 +187,179 @@ impl CommitmentTreeProver { } // TODO(AlonH): change interface after integrating mixed degree merkle. - pub fn decommit( + /// Decommits the merkle tree on the given query positions. + fn decommit( &self, - positions: Vec, + queries: Vec, ) -> ( ColumnVec>, - MerkleDecommitment, + MerkleDecommitment, ) { let values = self .evaluations .iter() - .map(|c| positions.iter().map(|p| c[*p]).collect()) + .map(|c| queries.iter().map(|p| c[*p]).collect()) .collect(); - let decommitment = self.commitment.generate_decommitment(positions); + let decommitment = self.commitment.generate_decommitment(queries); (values, decommitment) } } impl Deref for CommitmentTreeProver { - type Target = MerkleTree; + type Target = MerkleTree; fn deref(&self) -> &Self::Target { &self.commitment } } +/// The verifier side of a FRI polynomial commitment scheme. See [self]. #[derive(Default)] pub struct CommitmentSchemeVerifier { - pub commitments: Vec, + pub trees: TreeVec, } impl CommitmentSchemeVerifier { pub fn new() -> Self { - CommitmentSchemeVerifier { - commitments: Vec::new(), - } + Self::default() } - pub fn commit(&mut self, commitment: Blake2sHash, channel: &mut Blake2sChannel) { - let verifier = CommitmentTreeVerifier::new(commitment, channel); - self.commitments.push(verifier); + /// A [TreeVec TreeVec> { + self.trees.as_ref().map(|tree| tree.log_sizes.to_vec()) } - pub fn verify( + /// Reads a commitment from the prover. + pub fn commit( + &mut self, + commitment: Blake2sHash, + log_sizes: Vec, + channel: &mut ProofChannel, + ) { + let verifier = CommitmentTreeVerifier::new(commitment, log_sizes, channel); + self.trees.push(verifier); + } + + pub fn verify_opening( &self, - decommitments: &[MerkleDecommitment], - positions: &[SparseSubCircleDomain], + open_points: TreeVec>>>, + proof: CommitmentSchemeProof, + channel: &mut ProofChannel, ) -> bool { - self.commitments - .iter() - .zip(decommitments) - .zip(positions) - .all(|((commitment, decommitment), positions)| { - commitment.verify(decommitment, &positions.flatten()) + channel.mix_felts(&proof.opened_values.clone().flatten_all()); + + // Compute degree bounds for oods quotients without looking at the proof. + let bounds = self + .column_log_sizes() + .zip_cols(&open_points) + .map_cols(|(log_size, open_points)| { + vec![CirclePolyDegreeBound::new(log_size); open_points.len()] + }) + .flatten_all_rev(); + + // FRI commitment phase on oods quotients. + let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES); + let mut fri_verifier = + FriVerifier::commit(channel, fri_config, proof.fri_proof, bounds).unwrap(); + + // Verify proof of work. + ProofOfWork::new(PROOF_OF_WORK_BITS).verify(channel, &proof.proof_of_work); + + // Get FRI query domains. + let fri_query_domains = fri_verifier.column_opening_positions(channel); + + // Verify merkle decommitments. + if !self + .trees + .as_ref() + .zip(&proof.decommitments) + .map(|(tree, decommitment)| { + // TODO(spapini): Also very opened_value here. + tree.verify( + decommitment, + &fri_query_domains[&(tree.log_sizes[0] + 1)].flatten(), + ) }) + .0 + .iter() + .all(|x| *x) + { + return false; + } + + // Answer FRI queries. + let mut fri_answers = self + .column_log_sizes() + .zip_cols(proof.opened_values) + .zip_cols(open_points) + .zip_cols(proof.queried_values) + .map_cols( + // For each column. + |(((log_size, opened_values), opened_points), queried_values)| { + zip(opened_points, opened_values) + .map(|(point, value)| { + // For each opening point of that column. + eval_quotients_on_sparse_domain( + queried_values.clone(), + &fri_query_domains[&(log_size + 1)], + CanonicCoset::new(log_size + 1).circle_domain(), + point, + value, + ) + }) + .collect_vec() + }, + ) + .flatten_all(); + + // TODO(spapini): Remove reverse. + fri_answers.reverse(); + fri_verifier.decommit(fri_answers).is_ok() } } +fn eval_quotients_on_sparse_domain( + queried_values: Vec, + query_domains: &SparseSubCircleDomain, + commitment_domain: CircleDomain, + point: CirclePoint, + value: SecureField, +) -> SparseCircleEvaluation { + let queried_values = &mut queried_values.clone().into_iter(); + let res = SparseCircleEvaluation::new( + query_domains + .iter() + .map(|subdomain| { + let subeval = CircleEvaluation::new( + subdomain.to_circle_domain(&commitment_domain), + queried_values.take(1 << subdomain.log_size).collect(), + ); + get_pair_oods_quotient(point, value, &subeval).bit_reverse() + }) + .collect(), + ); + assert!(queried_values.is_empty()); + res +} + +/// Verifier data for a single commitment tree in a commitment scheme. pub struct CommitmentTreeVerifier { pub commitment: Blake2sHash, + pub log_sizes: Vec, } impl CommitmentTreeVerifier { - pub fn new(commitment: Blake2sHash, channel: &mut Blake2sChannel) -> Self { + pub fn new(commitment: Blake2sHash, log_sizes: Vec, channel: &mut ProofChannel) -> Self { channel.mix_digest(commitment); - CommitmentTreeVerifier { commitment } + CommitmentTreeVerifier { + commitment, + log_sizes, + } } pub fn verify( &self, - decommitment: &MerkleDecommitment, + decommitment: &MerkleDecommitment, positions: &[usize], ) -> bool { decommitment.verify(self.commitment, positions) diff --git a/src/core/commitment_scheme/utils.rs b/src/core/commitment_scheme/utils.rs index 87f98f5fe..7e0fdb1e4 100644 --- a/src/core/commitment_scheme/utils.rs +++ b/src/core/commitment_scheme/utils.rs @@ -9,8 +9,8 @@ use crate::core::ColumnVec; #[derive(Debug, Clone)] pub struct TreeVec(pub Vec); impl TreeVec { - pub fn new() -> TreeVec { - TreeVec(Vec::new()) + pub fn new(vec: Vec) -> TreeVec { + TreeVec(vec) } pub fn map U>(self, f: F) -> TreeVec { TreeVec(self.0.into_iter().map(f).collect()) diff --git a/src/core/mod.rs b/src/core/mod.rs index 6bf765838..693dd6b97 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -22,9 +22,15 @@ pub type ColumnVec = Vec; /// A vector of [ColumnVec]s. Each [ColumnVec] relates (by index) to a component in the air. pub struct ComponentVec(pub Vec>); -impl ComponentVec> { - pub fn flatten(&self) -> Vec { - self.iter().flatten().flatten().copied().collect() +impl ComponentVec { + pub fn flatten(&self) -> ColumnVec { + self.iter().flatten().cloned().collect() + } +} + +impl ComponentVec> { + pub fn flatten_all(&self) -> Vec { + self.iter().flatten().flatten().cloned().collect() } } diff --git a/src/core/prover/mod.rs b/src/core/prover/mod.rs index 9c0332a54..497f12079 100644 --- a/src/core/prover/mod.rs +++ b/src/core/prover/mod.rs @@ -1,28 +1,19 @@ -use std::iter::zip; +use itertools::Itertools; -use itertools::{enumerate, Itertools}; - -use super::poly::circle::CanonicCoset; -use super::queries::SparseSubCircleDomain; +use super::commitment_scheme::{CommitmentSchemeProof, TreeVec}; use super::ColumnVec; use crate::commitment_scheme::blake2_hash::Blake2sHasher; use crate::commitment_scheme::hasher::Hasher; -use crate::core::air::evaluation::SECURE_EXTENSION_DEGREE; use crate::core::air::{Air, AirExt}; use crate::core::backend::cpu::CPUCircleEvaluation; use crate::core::backend::CPUBackend; use crate::core::channel::{Blake2sChannel, Channel as ChannelTrait}; use crate::core::circle::CirclePoint; -use crate::core::commitment_scheme::{ - CommitmentSchemeProver, CommitmentSchemeVerifier, Decommitments, OpenedValues, -}; +use crate::core::commitment_scheme::{CommitmentSchemeProver, CommitmentSchemeVerifier}; use crate::core::fields::m31::BaseField; use crate::core::fields::qm31::SecureField; -use crate::core::fri::{FriConfig, FriProof, FriProver, FriVerifier, SparseCircleEvaluation}; -use crate::core::oods::get_pair_oods_quotient; use crate::core::poly::circle::{combine_secure_value, CircleEvaluation}; use crate::core::poly::BitReversedOrder; -use crate::core::proof_of_work::{ProofOfWork, ProofOfWorkProof}; use crate::core::ComponentVec; type Channel = Blake2sChannel; @@ -34,14 +25,8 @@ pub const PROOF_OF_WORK_BITS: u32 = 12; pub const N_QUERIES: usize = 3; pub struct StarkProof { - pub commitments: Vec<::Hash>, - pub decommitments: Decommitments, - pub trace_oods_values: ComponentVec>, - pub composition_polynomial_column_oods_values: [SecureField; SECURE_EXTENSION_DEGREE], - pub opened_values: OpenedValues, - pub proof_of_work: ProofOfWorkProof, - pub fri_proof: FriProof, - pub additional_proof_data: AdditionalProofData, + pub commitments: TreeVec<::Hash>, + pub commitment_scheme_proof: CommitmentSchemeProof, } pub struct AdditionalProofData { @@ -57,6 +42,7 @@ pub fn prove( trace: ColumnVec>, ) -> StarkProof { // Evaluate and commit on trace. + // TODO(spapini): Commit on trace outside. let trace_polys = trace.into_iter().map(|poly| poly.interpolate()).collect(); let mut commitment_scheme = CommitmentSchemeProver::new(LOG_BLOWUP_FACTOR); commitment_scheme.commit(trace_polys, channel); @@ -69,190 +55,78 @@ pub fn prove( ); commitment_scheme.commit(composition_polynomial_poly.to_vec(), channel); - // Evaluate the trace mask and the composition polynomial on the OODS point. + // Draw OODS point. let oods_point = CirclePoint::::get_random_point(channel); - let (trace_oods_points, trace_oods_values) = air.mask_points_and_values( - oods_point, - &air.component_traces(&commitment_scheme.trees[0].polynomials), - ); - let composition_polynomial_oods_value = composition_polynomial_poly.eval_at_point(oods_point); - - // Calculate a quotient polynomial for each trace mask item and one for the composition - // polynomial. - let mut oods_quotients = Vec::with_capacity(trace_oods_points.len() + SECURE_EXTENSION_DEGREE); - let composition_polynomial_column_oods_values = - composition_polynomial_poly.eval_columns_at_point(oods_point); - channel.mix_felts(&trace_oods_values.flatten()); - channel.mix_felts(&composition_polynomial_column_oods_values); - for (evaluation, value) in zip( - &commitment_scheme.trees[1].evaluations, - composition_polynomial_column_oods_values, - ) { - oods_quotients.push(get_pair_oods_quotient(oods_point, value, evaluation).bit_reverse()); - } - for (component_points, component_values) in zip(&trace_oods_points.0, &trace_oods_values.0) { - for (i, (column_points, column_values)) in - enumerate(zip(component_points, component_values)) - { - for (point, value) in zip(column_points, column_values) { - oods_quotients.push( - get_pair_oods_quotient( - *point, - *value, - &commitment_scheme.trees[0].evaluations[i], - ) - .bit_reverse(), - ); - } - } - } - let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES); - let fri_prover = FriProver::commit(channel, fri_config, &oods_quotients); + // Open mask values at oods points. + let open_points = air.mask_points(oods_point); - let proof_of_work = ProofOfWork::new(PROOF_OF_WORK_BITS).prove(channel); - let (fri_proof, fri_opening_positions) = fri_prover.decommit(channel); + // TODO(spapini): Change when we support multiple interactions. + // First tree - trace. + let mut open_points = TreeVec::new(vec![open_points.flatten()]); + // Second tree - composition polynomial. + open_points.0.push(vec![vec![oods_point]; 4]); - let (opened_values, decommitments) = commitment_scheme.decommit(fri_opening_positions); + let commitment_scheme_proof = commitment_scheme.open_values(open_points, channel); StarkProof { commitments: commitment_scheme.roots(), - decommitments, - trace_oods_values, - composition_polynomial_column_oods_values, - opened_values, - proof_of_work, - fri_proof, - additional_proof_data: AdditionalProofData { - composition_polynomial_oods_value, - composition_polynomial_random_coeff: random_coeff, - oods_point, - oods_quotients, - }, + commitment_scheme_proof, } } pub fn verify(proof: StarkProof, air: &impl Air, channel: &mut Channel) -> bool { // Read trace commitment. let mut commitment_scheme = CommitmentSchemeVerifier::new(); - commitment_scheme.commit(proof.commitments[0], channel); + commitment_scheme.commit(proof.commitments[0], air.column_log_sizes(), channel); let random_coeff = channel.draw_felt(); // Read composition polynomial commitment. - commitment_scheme.commit(proof.commitments[1], channel); + commitment_scheme.commit( + proof.commitments[1], + vec![air.composition_log_degree_bound(); 4], + channel, + ); - // Calculate the composition polynomial value on the OODS point using the trace values sent and - // verify it is equal to the composition polynomial value sent. + // Draw OODS point. let oods_point = CirclePoint::::get_random_point(channel); - let trace_oods_points = air.mask_points(oods_point); - let composition_polynomial_oods_value = air.eval_composition_polynomial_at_point( - oods_point, - &proof.trace_oods_values, - random_coeff, + + // Open mask values at oods points. + let open_points = air.mask_points(oods_point); + + // TODO(spapini): Change when we support multiple interactions. + // First tree - trace. + let mut open_points = TreeVec::new(vec![open_points.flatten()]); + // Second tree - composition polynomial. + open_points.0.push(vec![vec![oods_point]; 4]); + + // TODO(spapini): Save clone. + let mut opened_values = proof.commitment_scheme_proof.opened_values.clone(); + let composition_oods_values = opened_values.0.pop().unwrap(); + + // Retrieved open mask values for each component. + let flat_trace_values = &mut opened_values.0.pop().unwrap().into_iter(); + let trace_oods_values = ComponentVec( + air.components() + .iter() + .map(|c| flat_trace_values.take(c.mask().len()).collect_vec()) + .collect(), ); + + let composition_polynomial_oods_value = + air.eval_composition_polynomial_at_point(oods_point, &trace_oods_values, random_coeff); assert_eq!( composition_polynomial_oods_value, - combine_secure_value(proof.composition_polynomial_column_oods_values) + combine_secure_value( + composition_oods_values + .iter() + .flatten() + .cloned() + .collect_vec() + .try_into() + .unwrap() + ) ); - channel.mix_felts(&proof.trace_oods_values.flatten()); - channel.mix_felts(&proof.composition_polynomial_column_oods_values); - let bounds = air.quotient_log_bounds(); - let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES); - let mut fri_verifier = - FriVerifier::commit(channel, fri_config, proof.fri_proof, bounds).unwrap(); - - ProofOfWork::new(PROOF_OF_WORK_BITS).verify(channel, &proof.proof_of_work); - let opening_positions = fri_verifier - .column_opening_positions(channel) - .into_values() - .collect_vec(); - commitment_scheme.verify(&proof.decommitments, &opening_positions); - - let mut commitment_domains = air.trace_commitment_domains(); - commitment_domains.push(CanonicCoset::new( - air.composition_log_degree_bound() + LOG_BLOWUP_FACTOR, - )); - // Prepare the quotient evaluations needed for the FRI verifier. - let sparse_circle_evaluations = prepare_fri_evaluations( - opening_positions, - proof.opened_values, - trace_oods_points, - proof.trace_oods_values, - proof.composition_polynomial_column_oods_values, - commitment_domains, - oods_point, - ); - - fri_verifier.decommit(sparse_circle_evaluations).unwrap(); - - true -} - -fn prepare_fri_evaluations( - opening_positions: Vec, - opened_values: OpenedValues, - trace_oods_points: ComponentVec>>, - trace_oods_values: ComponentVec>, - composition_polynomial_column_oods_values: [SecureField; SECURE_EXTENSION_DEGREE], - commitment_domains: Vec, - oods_point: CirclePoint, -) -> Vec> { - // TODO(AlonH): Generalize when introducing mixed degree. - let trace_commitment_domain = commitment_domains[0]; - let composition_polynomial_commitment_domain = commitment_domains.last().unwrap(); - let mut sparse_circle_evaluations = Vec::new(); - for (opened_values, oods_value) in - zip(&opened_values[1], composition_polynomial_column_oods_values) - { - let mut evaluation = Vec::new(); - let mut opened_values_iter = opened_values.iter(); - for sub_circle_domain in opening_positions[1].iter() { - let values = (&mut opened_values_iter) - .take(1 << sub_circle_domain.log_size) - .copied() - .collect(); - let sub_circle_evaluation = CircleEvaluation::new( - sub_circle_domain - .to_circle_domain(&composition_polynomial_commitment_domain.circle_domain()), - values, - ); - evaluation.push( - get_pair_oods_quotient(oods_point, oods_value, &sub_circle_evaluation) - .bit_reverse(), - ); - } - assert!( - opened_values_iter.next().is_none(), - "Not all values were used." - ); - sparse_circle_evaluations.push(SparseCircleEvaluation::new(evaluation)); - } - for (component_points, component_values) in zip(&trace_oods_points.0, &trace_oods_values.0) { - for (i, (column_points, column_values)) in - enumerate(zip(component_points, component_values)) - { - for (oods_point, oods_value) in zip(column_points, column_values) { - let mut evaluation = Vec::new(); - let mut opened_values = opened_values[0][i].iter().copied(); - for sub_circle_domain in opening_positions[0].iter() { - let values = (&mut opened_values) - .take(1 << sub_circle_domain.log_size) - .collect(); - let sub_circle_evaluation = CircleEvaluation::new( - sub_circle_domain - .to_circle_domain(&trace_commitment_domain.circle_domain()), - values, - ); - evaluation.push( - get_pair_oods_quotient(*oods_point, *oods_value, &sub_circle_evaluation) - .bit_reverse(), - ); - } - assert!(opened_values.next().is_none(), "Not all values were used."); - sparse_circle_evaluations.push(SparseCircleEvaluation::new(evaluation)); - } - } - } - sparse_circle_evaluations + commitment_scheme.verify_opening(open_points, proof.commitment_scheme_proof, channel) } diff --git a/src/fibonacci/mod.rs b/src/fibonacci/mod.rs index cbad21169..b9ad89fdc 100644 --- a/src/fibonacci/mod.rs +++ b/src/fibonacci/mod.rs @@ -82,7 +82,7 @@ mod tests { use crate::core::poly::circle::CanonicCoset; use crate::core::prover::{prove, verify}; use crate::core::queries::Queries; - use crate::core::utils::{bit_reverse, secure_eval_to_base_eval}; + use crate::core::utils::bit_reverse; use crate::fibonacci::air::MultiFibonacciAir; use crate::fibonacci::verify_proof; use crate::{m31, qm31}; @@ -125,24 +125,22 @@ mod tests { fn test_oods_quotients_are_low_degree() { const FIB_LOG_SIZE: u32 = 5; let fib = Fibonacci::new(FIB_LOG_SIZE, m31!(443693538)); + let poly = fib.get_trace().interpolate(); + let trace = [ComponentTrace::new(vec![&poly])]; + let channel = &mut Blake2sChannel::new(Blake2sHasher::hash(BaseField::into_slice(&[]))); + let coeff = channel.draw_felt(); + let point = CirclePoint::::get_random_point(channel); - let proof = fib.prove(); - let (composition_polynomial_quotient, trace_quotients) = proof - .additional_proof_data - .oods_quotients - .split_first() - .unwrap(); - - // Assert that the trace quotients are low degree. - for quotient in trace_quotients.iter() { - let interpolated_quotient_poly = secure_eval_to_base_eval(quotient).interpolate(); - assert!(interpolated_quotient_poly.is_in_fft_space(FIB_LOG_SIZE)); - } - - // Assert that the composition polynomial quotient is low degree. - let interpolated_quotient_poly = - secure_eval_to_base_eval(composition_polynomial_quotient).interpolate(); - assert!(interpolated_quotient_poly.is_in_fft_space(FIB_LOG_SIZE + 1)); + assert_eq!( + fib.air + .compute_composition_polynomial(coeff, &trace) + .eval_at_point(point), + fib.air.eval_composition_polynomial_at_point( + point, + &fib.air.mask_points_and_values(point, &trace).1, + coeff + ) + ); } #[test] @@ -185,46 +183,21 @@ mod tests { let fib = Fibonacci::new(FIB_LOG_SIZE, m31!(443693538)); let trace = fib.get_trace(); let trace_poly = trace.interpolate(); - let trace = ComponentTrace::new(vec![&trace_poly]); + let _trace = ComponentTrace::new(vec![&trace_poly]); let proof = fib.prove(); - let oods_point = proof.additional_proof_data.oods_point; - - let (_, mask_values) = fib.air.component.mask_points_and_values(oods_point, &trace); - let mut evaluation_accumulator = PointEvaluationAccumulator::new( - proof - .additional_proof_data - .composition_polynomial_random_coeff, - fib.air.composition_log_degree_bound(), - ); - fib.air.component.evaluate_constraint_quotients_at_point( - oods_point, - &mask_values, - &mut evaluation_accumulator, - ); - let hz = evaluation_accumulator.finalize(); - - assert_eq!( - proof - .additional_proof_data - .composition_polynomial_oods_value, - hz - ); assert!(verify_proof::(proof, fib.claim)); } - // TODO(AlonH): Check the correct error occurs after introducing errors instead of - // #[should_panic]. #[test] - #[should_panic] fn test_prove_invalid_trace_value() { const FIB_LOG_SIZE: u32 = 5; let fib = Fibonacci::new(FIB_LOG_SIZE, m31!(443693538)); let mut invalid_proof = fib.prove(); - invalid_proof.opened_values.0[0][0][4] += BaseField::one(); + invalid_proof.commitment_scheme_proof.queried_values.0[0][0][4] += BaseField::one(); - verify_proof::(invalid_proof, fib.claim); + assert!(!verify_proof::(invalid_proof, fib.claim)); } // TODO(AlonH): Check the correct error occurs after introducing errors instead of @@ -236,7 +209,11 @@ mod tests { let fib = Fibonacci::new(FIB_LOG_SIZE, m31!(443693538)); let mut invalid_proof = fib.prove(); - invalid_proof.trace_oods_values.swap(0, 1); + invalid_proof + .commitment_scheme_proof + .opened_values + .0 + .swap(0, 1); verify_proof::(invalid_proof, fib.claim); } @@ -250,7 +227,7 @@ mod tests { let fib = Fibonacci::new(FIB_LOG_SIZE, m31!(443693538)); let mut invalid_proof = fib.prove(); - invalid_proof.opened_values.0[0][0].pop(); + invalid_proof.commitment_scheme_proof.queried_values.0[0][0].pop(); verify_proof::(invalid_proof, fib.claim); }