Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the alpha used when folding columns into fri layers. #972

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading