Skip to content

Commit

Permalink
Change the alpha used when folding columns into fri layers.
Browse files Browse the repository at this point in the history
  • Loading branch information
alon-f committed Jan 13, 2025
1 parent c5af676 commit 6cee79f
Showing 1 changed file with 53 additions and 44 deletions.
97 changes: 53 additions & 44 deletions crates/prover/src/core/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,29 +208,24 @@ impl<'a, B: FriOps + MerkleOps<MC::H>, MC: MerkleChannel> FriProver<'a, B, MC> {
v.len() >> CIRCLE_TO_LINE_FOLD_STEP
}

let circle_poly_folding_alpha = channel.draw_felt();
let first_inner_layer_log_size = folded_size(&columns[0]).ilog2();
let first_inner_layer_domain =
LineDomain::new(Coset::half_odds(first_inner_layer_log_size));

let mut layer_evaluation = LineEvaluation::new_zero(first_inner_layer_domain);
let mut columns = columns.iter().peekable();
let mut layers = Vec::new();
let mut folding_alpha = channel.draw_felt();

while layer_evaluation.len() > config.last_layer_domain_size() {
// Check for circle polys in the first layer that should be combined in this layer.
while let Some(column) = columns.next_if(|c| folded_size(c) == layer_evaluation.len()) {
B::fold_circle_into_line(
&mut layer_evaluation,
column,
circle_poly_folding_alpha,
twiddles,
);
B::fold_circle_into_line(&mut layer_evaluation, column, folding_alpha, twiddles);
}

let layer = FriInnerLayerProver::new(layer_evaluation);
MC::mix_root(channel, layer.merkle_tree.root());
let folding_alpha = channel.draw_felt();
folding_alpha = channel.draw_felt();
let folded_layer_evaluation = B::fold_line(&layer.evaluation, folding_alpha, twiddles);

layer_evaluation = folded_layer_evaluation;
Expand Down Expand Up @@ -447,10 +442,11 @@ impl<MC: MerkleChannel> FriVerifier<MC> {
queries: &Queries,
first_layer_query_evals: ColumnVec<Vec<SecureField>>,
) -> Result<(), FriVerificationError> {
let (inner_layer_queries, first_layer_folded_evals) =
let first_layer_sparse_evals =
self.decommit_first_layer(queries, first_layer_query_evals)?;
let inner_layer_queries = queries.fold(CIRCLE_TO_LINE_FOLD_STEP);
let (last_layer_queries, last_layer_query_evals) =
self.decommit_inner_layers(&inner_layer_queries, first_layer_folded_evals)?;
self.decommit_inner_layers(&inner_layer_queries, first_layer_sparse_evals)?;
self.decommit_last_layer(last_layer_queries, last_layer_query_evals)
}

Expand All @@ -462,9 +458,8 @@ impl<MC: MerkleChannel> FriVerifier<MC> {
&self,
queries: &Queries,
first_layer_query_evals: ColumnVec<Vec<SecureField>>,
) -> Result<(Queries, ColumnVec<Vec<SecureField>>), FriVerificationError> {
self.first_layer
.verify_and_fold(queries, first_layer_query_evals)
) -> Result<ColumnVec<SparseEvaluation>, FriVerificationError> {
self.first_layer.verify(queries, first_layer_query_evals)
}

/// Verifies all inner layer decommitments.
Expand All @@ -473,41 +468,46 @@ impl<MC: MerkleChannel> FriVerifier<MC> {
fn decommit_inner_layers(
&self,
queries: &Queries,
first_layer_folded_evals: ColumnVec<Vec<SecureField>>,
first_layer_sparse_evals: ColumnVec<SparseEvaluation>,
) -> Result<(Queries, Vec<SecureField>), FriVerificationError> {
let first_layer_fold_alpha = self.first_layer.folding_alpha;
let first_layer_fold_alpha_pow_fold_factor = first_layer_fold_alpha.square();

let mut layer_queries = queries.clone();
let mut layer_query_evals = vec![SecureField::zero(); layer_queries.len()];
let mut first_layer_folded_evals = first_layer_folded_evals.into_iter();
let mut first_layer_column_bounds = self.first_layer.column_bounds.iter().peekable();
let mut first_layer_sparse_evals = first_layer_sparse_evals.into_iter();
let first_layer_column_bounds = self.first_layer.column_bounds.iter();
let first_layer_column_domains = self.first_layer.column_commitment_domains.iter();
let mut first_layer_columns = first_layer_column_bounds
.zip_eq(first_layer_column_domains)
.peekable();
let mut previous_folding_alpha = self.first_layer.folding_alpha;

for layer in self.inner_layers.iter() {
// Check for evals committed in the first layer that need to be folded into this layer.
while first_layer_column_bounds
.next_if(|b| b.fold_to_line() == layer.degree_bound)
.is_some()
while let Some((_, column_domain)) =
first_layer_columns.next_if(|(b, _)| b.fold_to_line() == layer.degree_bound)
{
let folded_column_evals = first_layer_folded_evals.next().unwrap();

for (curr_layer_eval, folded_column_eval) in
zip_eq(&mut layer_query_evals, folded_column_evals)
{
// TODO(andrew): As Ilya pointed out using the first layer's folding
// alpha here might not be sound. Investigate.
*curr_layer_eval *= first_layer_fold_alpha_pow_fold_factor;
*curr_layer_eval += folded_column_eval;
}
// Use the previous layer's folding alpha to fold the circle's sparse evals into
// the current layer.
let folded_column_evals = first_layer_sparse_evals
.next()
.unwrap()
.fold_circle(previous_folding_alpha, *column_domain);

accumulate_line(
&mut layer_query_evals,
&folded_column_evals,
previous_folding_alpha,
);
}

// Verify the layer and fold it using the current layer's folding alpha.
(layer_queries, layer_query_evals) =
layer.verify_and_fold(layer_queries, layer_query_evals)?;
previous_folding_alpha = layer.folding_alpha;
}

// Check all values have been consumed.
assert!(first_layer_column_bounds.is_empty());
assert!(first_layer_folded_evals.is_empty());
assert!(first_layer_columns.is_empty());
assert!(first_layer_sparse_evals.is_empty());

Ok((layer_queries, layer_query_evals))
}
Expand Down Expand Up @@ -552,6 +552,18 @@ impl<MC: MerkleChannel> FriVerifier<MC> {
}
}

fn accumulate_line(
layer_query_evals: &mut [SecureField],
column_query_evals: &[SecureField],
folding_alpha: SecureField,
) {
let folding_alpha_squared = folding_alpha.square();
for (curr_layer_eval, folded_column_eval) in zip_eq(layer_query_evals, column_query_evals) {
*curr_layer_eval *= folding_alpha_squared;
*curr_layer_eval += *folded_column_eval;
}
}

/// Returns the column query positions mapped by sample domain log size.
///
/// The column log sizes must be unique and in descending order.
Expand Down Expand Up @@ -674,7 +686,8 @@ struct FriFirstLayerVerifier<H: MerkleHasher> {
}

impl<H: MerkleHasher> FriFirstLayerVerifier<H> {
/// Verifies the layer's merkle decommitment and returns the the folded queries and query evals.
/// Verifies the first layer's merkle decommitment, and returns the evaluations needed for
/// folding the columns to their corresponding layer.
///
/// # Errors
///
Expand All @@ -687,18 +700,18 @@ impl<H: MerkleHasher> FriFirstLayerVerifier<H> {
/// Panics if:
/// * The queries are sampled on the wrong domain.
/// * There are an invalid number of provided column evals.
fn verify_and_fold(
fn verify(
&self,
queries: &Queries,
query_evals_by_column: ColumnVec<Vec<SecureField>>,
) -> Result<(Queries, ColumnVec<Vec<SecureField>>), FriVerificationError> {
) -> Result<ColumnVec<SparseEvaluation>, FriVerificationError> {
// Columns are provided in descending order by size.
let max_column_log_size = self.column_commitment_domains[0].log_size();
assert_eq!(queries.log_domain_size, max_column_log_size);

let mut fri_witness = self.proof.fri_witness.iter().copied();
let mut decommitment_positions_by_log_size = BTreeMap::new();
let mut folded_evals_by_column = Vec::new();
let mut sparse_evals_by_column = Vec::new();

let mut decommitmented_values = vec![];
for (&column_domain, column_query_evals) in
Expand Down Expand Up @@ -728,9 +741,7 @@ impl<H: MerkleHasher> FriFirstLayerVerifier<H> {
.flatten()
.flat_map(|qm31| qm31.to_m31_array()),
);

let folded_evals = sparse_evaluation.fold_circle(self.folding_alpha, column_domain);
folded_evals_by_column.push(folded_evals);
sparse_evals_by_column.push(sparse_evaluation);
}

// Check all proof evals have been consumed.
Expand All @@ -754,9 +765,7 @@ impl<H: MerkleHasher> FriFirstLayerVerifier<H> {
)
.map_err(|error| FriVerificationError::FirstLayerCommitmentInvalid { error })?;

let folded_queries = queries.fold(CIRCLE_TO_LINE_FOLD_STEP);

Ok((folded_queries, folded_evals_by_column))
Ok(sparse_evals_by_column)
}
}

Expand Down

0 comments on commit 6cee79f

Please sign in to comment.