From f56de3a75fb2a689ba9030e83e0cd3a7c3f49a7d Mon Sep 17 00:00:00 2001 From: Shahar Papini Date: Fri, 22 Mar 2024 20:36:33 +0200 Subject: [PATCH] FRI using simple merkle --- benches/fri.rs | 4 +- src/commitment_scheme/prover.rs | 7 +++ src/core/fri.rs | 83 +++++++++++++++------------------ 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/benches/fri.rs b/benches/fri.rs index 06527d2a1..ce747dd6b 100644 --- a/benches/fri.rs +++ b/benches/fri.rs @@ -10,7 +10,9 @@ fn folding_benchmark(c: &mut Criterion) { let domain = LineDomain::new(CanonicCoset::new(LOG_SIZE + 1).half_coset()); let evals = LineEvaluation::new( domain, - vec![BaseField::from_u32_unchecked(712837213).into(); 1 << LOG_SIZE], + vec![BaseField::from_u32_unchecked(712837213).into(); 1 << LOG_SIZE] + .into_iter() + .collect(), ); let alpha = BaseField::from_u32_unchecked(12389).into(); c.bench_function("fold_line", |b| { diff --git a/src/commitment_scheme/prover.rs b/src/commitment_scheme/prover.rs index e9a28fe53..157ffccbe 100644 --- a/src/commitment_scheme/prover.rs +++ b/src/commitment_scheme/prover.rs @@ -64,3 +64,10 @@ impl, H: MerkleHasher> MerkleProver { pub struct Decommitment { pub witness: Vec, } +impl Clone for Decommitment { + fn clone(&self) -> Self { + Self { + witness: self.witness.clone(), + } + } +} diff --git a/src/core/fri.rs b/src/core/fri.rs index 0aa37443a..748674854 100644 --- a/src/core/fri.rs +++ b/src/core/fri.rs @@ -10,16 +10,16 @@ use thiserror::Error; use super::backend::{Backend, CPUBackend}; use super::channel::Channel; -use super::fields::m31::BaseField; use super::fields::qm31::SecureField; +use super::fields::secure_column::SecureColumn; use super::poly::circle::{CircleEvaluation, SecureEvaluation}; use super::poly::line::{LineEvaluation, LinePoly}; use super::poly::BitReversedOrder; // TODO(andrew): Create fri/ directory, move queries.rs there and split this file up. use super::queries::{Queries, SparseSubCircleDomain}; -use crate::commitment_scheme::hasher::Hasher; -use crate::commitment_scheme::merkle_decommitment::MerkleDecommitment; -use crate::commitment_scheme::merkle_tree::MerkleTree; +use crate::commitment_scheme::ops::{MerkleHasher, MerkleOps}; +use crate::commitment_scheme::prover::{Decommitment, MerkleProver}; +use crate::commitment_scheme::verifier::MerkleTreeVerifier; use crate::core::circle::Coset; use crate::core::poly::line::LineDomain; use crate::core::utils::bit_reverse_index; @@ -101,7 +101,7 @@ pub trait FriOps: Backend + Sized { } /// A FRI prover that applies the FRI protocol to prove a set of polynomials are of low degree. -pub struct FriProver { +pub struct FriProver, H: MerkleHasher> { config: FriConfig, inner_layers: Vec>, last_layer_poly: LinePoly, @@ -109,7 +109,7 @@ pub struct FriProver { column_log_sizes: Vec, } -impl> FriProver { +impl, H: MerkleHasher> FriProver { /// Commits to multiple [CircleEvaluation]s. /// /// `columns` must be provided in descending order by size. @@ -268,7 +268,7 @@ impl> FriProver { } } -pub struct FriVerifier { +pub struct FriVerifier { config: FriConfig, /// Alpha used to fold all circle polynomials to univariate polynomials. circle_poly_alpha: SecureField, @@ -284,7 +284,7 @@ pub struct FriVerifier { queries: Option, } -impl> FriVerifier { +impl> FriVerifier { /// Verifies the commitment stage of FRI. /// /// `column_bounds` should be the committed circle polynomial degree bounds in descending order. @@ -586,7 +586,7 @@ impl LinePolyDegreeBound { /// A FRI proof. #[derive(Debug)] -pub struct FriProof { +pub struct FriProof { pub inner_layers: Vec>, pub last_layer_poly: LinePoly, } @@ -602,15 +602,15 @@ pub const CIRCLE_TO_LINE_FOLD_STEP: u32 = 1; /// /// The subset corresponds to the set of evaluations needed by a FRI verifier. #[derive(Debug)] -pub struct FriLayerProof { +pub struct FriLayerProof { /// The subset stored corresponds to the set of evaluations the verifier doesn't have but needs /// to fold and verify the merkle decommitment. pub evals_subset: Vec, - pub decommitment: MerkleDecommitment, + pub decommitment: Decommitment, pub commitment: H::Hash, } -struct FriLayerVerifier { +struct FriLayerVerifier { degree_bound: LinePolyDegreeBound, domain: LineDomain, folding_alpha: SecureField, @@ -618,7 +618,7 @@ struct FriLayerVerifier { proof: FriLayerProof, } -impl> FriLayerVerifier { +impl> FriLayerVerifier { /// Verifies the layer's merkle decommitment and returns the the folded queries and query evals. /// /// # Errors @@ -635,38 +635,18 @@ impl> FriLayerVerifier { queries: Queries, evals_at_queries: Vec, ) -> Result<(Queries, Vec), FriVerificationError> { - let decommitment = &self.proof.decommitment; + let decommitment = self.proof.decommitment.clone(); let commitment = self.proof.commitment; // Extract the evals needed for decommitment and folding. let sparse_evaluation = self.extract_evaluation(&queries, &evals_at_queries)?; // TODO: When leaf values are removed from the decommitment, also remove this block. - { - let mut expected_decommitment_evals = Vec::new(); - - for leaf in decommitment.values() { - // Ensure each leaf is a single value. - if let Ok(evals) = leaf.try_into() { - expected_decommitment_evals.push(SecureField::from_m31_array(evals)); - } else { - return Err(FriVerificationError::InnerLayerCommitmentInvalid { - layer: self.layer_index, - }); - } - } - - let actual_decommitment_evals = sparse_evaluation - .subline_evals - .iter() - .flat_map(|e| e.values.into_iter()); - - if !actual_decommitment_evals.eq(expected_decommitment_evals) { - return Err(FriVerificationError::InnerLayerCommitmentInvalid { - layer: self.layer_index, - }); - } - } + let actual_decommitment_evals: SecureColumn = sparse_evaluation + .subline_evals + .iter() + .flat_map(|e| e.values.into_iter()) + .collect(); let folded_queries = queries.fold(FOLD_STEP); @@ -680,7 +660,20 @@ impl> FriLayerVerifier { }) .collect::>(); - if !decommitment.verify(commitment, &decommitment_positions) { + let verifier = MerkleTreeVerifier { root: commitment }; + // TODO(spapini): Propagate error. + if verifier + .verify( + decommitment_positions, + actual_decommitment_evals + .columns + .into_iter() + .map(|e| (self.domain.log_size(), e)) + .collect_vec(), + decommitment, + ) + .is_err() + { return Err(FriVerificationError::InnerLayerCommitmentInvalid { layer: self.layer_index, }); @@ -763,16 +756,16 @@ impl> FriLayerVerifier { /// The polynomial evaluations are viewed as evaluation of a polynomial on multiple distinct cosets /// of size two. Each leaf of the merkle tree commits to a single coset evaluation. // TODO(andrew): Support different step sizes. -struct FriLayerProver { +struct FriLayerProver, H: MerkleHasher> { evaluation: LineEvaluation, - merkle_tree: MerkleTree, + merkle_tree: MerkleProver, } -impl> FriLayerProver { +impl, H: MerkleHasher> FriLayerProver { fn new(evaluation: LineEvaluation) -> Self { // TODO(spapini): Commit on slice. // TODO(spapini): Merkle tree in backend. - let merkle_tree = MerkleTree::commit(evaluation.values.to_cpu().columns.into()); + let merkle_tree = MerkleProver::commit(evaluation.values.columns.iter().collect_vec()); #[allow(unreachable_code)] FriLayerProver { evaluation, @@ -808,7 +801,7 @@ impl> FriLayerProver { } let commitment = self.merkle_tree.root(); - let decommitment = self.merkle_tree.generate_decommitment(decommit_positions); + let decommitment = self.merkle_tree.decommit(decommit_positions); FriLayerProof { evals_subset,