Skip to content

Commit

Permalink
FRI using simple merkle
Browse files Browse the repository at this point in the history
  • Loading branch information
spapinistarkware committed Apr 3, 2024
1 parent 4559157 commit a3f9dca
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 52 deletions.
9 changes: 9 additions & 0 deletions src/commitment_scheme/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,12 @@ impl<H: MerkleHasher> MerkleDecommitment<H> {
}
}
}
// TODO(andreW): Remove these in favor of the `derivative` crate.
impl<H: MerkleHasher> Clone for MerkleDecommitment<H> {
fn clone(&self) -> Self {
Self {
hash_witness: self.hash_witness.clone(),
column_witness: self.column_witness.clone(),
}
}
}
6 changes: 3 additions & 3 deletions src/core/commitment_scheme/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use super::super::prover::{
use super::super::ColumnVec;
use super::quotients::{compute_fri_quotients, PointSample};
use super::utils::TreeVec;
use crate::commitment_scheme::blake2_hash::{Blake2sHash, Blake2sHasher};
use crate::commitment_scheme::blake2_hash::Blake2sHash;
use crate::commitment_scheme::blake2_merkle::Blake2sMerkleHasher;
use crate::commitment_scheme::prover::{MerkleDecommitment, MerkleProver};
use crate::core::channel::Channel;
Expand Down Expand Up @@ -91,7 +91,7 @@ impl CommitmentSchemeProver {
// Run FRI commitment phase on the oods quotients.
let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES);
let fri_prover =
FriProver::<CPUBackend, Blake2sHasher>::commit(channel, fri_config, &quotients);
FriProver::<CPUBackend, Blake2sMerkleHasher>::commit(channel, fri_config, &quotients);

// Proof of work.
let proof_of_work = ProofOfWork::new(PROOF_OF_WORK_BITS).prove(channel);
Expand Down Expand Up @@ -127,7 +127,7 @@ pub struct CommitmentSchemeProof {
pub decommitments: TreeVec<MerkleDecommitment<MerkleHasher>>,
pub queried_values: TreeVec<ColumnVec<Vec<BaseField>>>,
pub proof_of_work: ProofOfWorkProof,
pub fri_proof: FriProof<Blake2sHasher>,
pub fri_proof: FriProof<Blake2sMerkleHasher>,
}

/// Prover data for a single commitment tree in a commitment scheme. The commitment scheme allows to
Expand Down
97 changes: 48 additions & 49 deletions src/core/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{MerkleDecommitment, MerkleProver};
use crate::commitment_scheme::verifier::MerkleVerifier;
use crate::core::circle::Coset;
use crate::core::poly::line::LineDomain;
use crate::core::utils::bit_reverse_index;
Expand Down Expand Up @@ -104,15 +104,15 @@ 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<B: FriOps, H: Hasher> {
pub struct FriProver<B: FriOps + MerkleOps<H>, H: MerkleHasher> {
config: FriConfig,
inner_layers: Vec<FriLayerProver<B, H>>,
last_layer_poly: LinePoly,
/// Unique sizes of committed columns sorted in descending order.
column_log_sizes: Vec<u32>,
}

impl<B: FriOps, H: Hasher<NativeType = u8>> FriProver<B, H> {
impl<B: FriOps + MerkleOps<H>, H: MerkleHasher> FriProver<B, H> {
/// Commits to multiple [CircleEvaluation]s.
///
/// `columns` must be provided in descending order by size.
Expand Down Expand Up @@ -273,7 +273,7 @@ impl<B: FriOps, H: Hasher<NativeType = u8>> FriProver<B, H> {
}
}

pub struct FriVerifier<H: Hasher> {
pub struct FriVerifier<H: MerkleHasher> {
config: FriConfig,
/// Alpha used to fold all circle polynomials to univariate polynomials.
circle_poly_alpha: SecureField,
Expand All @@ -289,7 +289,7 @@ pub struct FriVerifier<H: Hasher> {
queries: Option<Queries>,
}

impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
impl<H: MerkleHasher> FriVerifier<H> {
/// Verifies the commitment stage of FRI.
///
/// `column_bounds` should be the committed circle polynomial degree bounds in descending order.
Expand Down Expand Up @@ -328,7 +328,7 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
));

for (layer_index, proof) in proof.inner_layers.into_iter().enumerate() {
channel.mix_digest(proof.commitment);
channel.mix_digest(proof.commitment.clone());

let folding_alpha = channel.draw_felt();

Expand Down Expand Up @@ -591,7 +591,7 @@ impl LinePolyDegreeBound {

/// A FRI proof.
#[derive(Debug)]
pub struct FriProof<H: Hasher> {
pub struct FriProof<H: MerkleHasher> {
pub inner_layers: Vec<FriLayerProof<H>>,
pub last_layer_poly: LinePoly,
}
Expand All @@ -607,23 +607,23 @@ 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<H: Hasher> {
pub struct FriLayerProof<H: MerkleHasher> {
/// 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<SecureField>,
pub decommitment: MerkleDecommitment<BaseField, H>,
pub decommitment: MerkleDecommitment<H>,
pub commitment: H::Hash,
}

struct FriLayerVerifier<H: Hasher> {
struct FriLayerVerifier<H: MerkleHasher> {
degree_bound: LinePolyDegreeBound,
domain: LineDomain,
folding_alpha: SecureField,
layer_index: usize,
proof: FriLayerProof<H>,
}

impl<H: Hasher<NativeType = u8>> FriLayerVerifier<H> {
impl<H: MerkleHasher> FriLayerVerifier<H> {
/// Verifies the layer's merkle decommitment and returns the the folded queries and query evals.
///
/// # Errors
Expand All @@ -640,38 +640,18 @@ impl<H: Hasher<NativeType = u8>> FriLayerVerifier<H> {
queries: Queries,
evals_at_queries: Vec<SecureField>,
) -> Result<(Queries, Vec<SecureField>), FriVerificationError> {
let decommitment = &self.proof.decommitment;
let commitment = self.proof.commitment;
let decommitment = self.proof.decommitment.clone();
let commitment = self.proof.commitment.clone();

// 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<CPUBackend> = sparse_evaluation
.subline_evals
.iter()
.flat_map(|e| e.values.into_iter())
.collect();

let folded_queries = queries.fold(FOLD_STEP);

Expand All @@ -685,7 +665,21 @@ impl<H: Hasher<NativeType = u8>> FriLayerVerifier<H> {
})
.collect::<Vec<usize>>();

if !decommitment.verify(commitment, &decommitment_positions) {
let merkle_verifier = MerkleVerifier {
root: commitment,
column_log_sizes: vec![self.domain.log_size(); 4],
};
// TODO(spapini): Propagate error.
if merkle_verifier
.verify(
[(self.domain.log_size(), decommitment_positions)]
.into_iter()
.collect(),
actual_decommitment_evals.columns.into_iter().collect_vec(),
decommitment,
)
.is_err()
{
return Err(FriVerificationError::InnerLayerCommitmentInvalid {
layer: self.layer_index,
});
Expand Down Expand Up @@ -768,16 +762,16 @@ impl<H: Hasher<NativeType = u8>> FriLayerVerifier<H> {
/// 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<B: FriOps, H: Hasher> {
struct FriLayerProver<B: FriOps + MerkleOps<H>, H: MerkleHasher> {
evaluation: LineEvaluation<B>,
merkle_tree: MerkleTree<BaseField, H>,
merkle_tree: MerkleProver<B, H>,
}

impl<B: FriOps, H: Hasher<NativeType = u8>> FriLayerProver<B, H> {
impl<B: FriOps + MerkleOps<H>, H: MerkleHasher> FriLayerProver<B, H> {
fn new(evaluation: LineEvaluation<B>) -> 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,
Expand Down Expand Up @@ -813,7 +807,12 @@ impl<B: FriOps, H: Hasher<NativeType = u8>> FriLayerProver<B, H> {
}

let commitment = self.merkle_tree.root();
let decommitment = self.merkle_tree.generate_decommitment(decommit_positions);
let (_, decommitment) = self.merkle_tree.decommit(
[(self.evaluation.domain().log_size(), decommit_positions)]
.into_iter()
.collect(),
self.evaluation.values.columns.iter().collect_vec(),
);

FriLayerProof {
evals_subset,
Expand Down Expand Up @@ -904,7 +903,7 @@ mod tests {
use num_traits::{One, Zero};

use super::{get_opening_positions, FriVerificationError, SparseCircleEvaluation};
use crate::commitment_scheme::blake2_hash::Blake2sHasher;
use crate::commitment_scheme::blake2_merkle::Blake2sMerkleHasher;
use crate::core::backend::cpu::{CPUCircleEvaluation, CPUCirclePoly};
use crate::core::backend::{CPUBackend, Col, Column, ColumnOps};
use crate::core::circle::{CirclePointIndex, Coset};
Expand All @@ -925,7 +924,7 @@ mod tests {
/// Default blowup factor used for tests.
const LOG_BLOWUP_FACTOR: u32 = 2;

type FriProver = super::FriProver<CPUBackend, Blake2sHasher>;
type FriProver = super::FriProver<CPUBackend, Blake2sMerkleHasher>;

#[test]
fn fold_line_works() {
Expand Down

0 comments on commit a3f9dca

Please sign in to comment.