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 2 commits 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
108 changes: 57 additions & 51 deletions crates/prover/src/core/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use num_traits::Zero;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tracing::instrument;
use tracing_subscriber::layer;

use super::backend::{Col, CpuBackend};
use super::channel::{Channel, MerkleChannel};
Expand Down Expand Up @@ -208,29 +209,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 +443,10 @@ 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 (last_layer_queries, last_layer_query_evals) =
self.decommit_inner_layers(&inner_layer_queries, first_layer_folded_evals)?;
self.decommit_inner_layers(queries, first_layer_sparse_evals)?;
self.decommit_last_layer(last_layer_queries, last_layer_query_evals)
}

Expand All @@ -462,7 +458,7 @@ impl<MC: MerkleChannel> FriVerifier<MC> {
&self,
queries: &Queries,
first_layer_query_evals: ColumnVec<Vec<SecureField>>,
) -> Result<(Queries, ColumnVec<Vec<SecureField>>), FriVerificationError> {
) -> Result<ColumnVec<SparseEvaluation>, FriVerificationError> {
self.first_layer
.verify_and_fold(queries, first_layer_query_evals)
}
Expand All @@ -473,41 +469,45 @@ 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_queries = queries.clone().fold(FOLD_STEP);
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 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 column's circle into the
// current layer.
// let column_domain = first_layer_column_domains.next().unwrap();
let folded_column_evals = first_layer_sparse_evals
.next()
.unwrap()
.fold_circle(folding_alpha, *column_domain);

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

(layer_queries, layer_query_evals) =
layer.verify_and_fold(layer_queries, layer_query_evals)?;
let sparse_evaluation;
sparse_evaluation = layer.verify_and_fold(&layer_queries, layer_query_evals)?;
layer_queries = layer_queries.fold(FOLD_STEP);
// Fold the line using the current layer's folding alpha.
folding_alpha = layer.folding_alpha;
layer_query_evals = sparse_evaluation.fold_line(folding_alpha, layer.domain);
}

// 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,17 @@ impl<MC: MerkleChannel> FriVerifier<MC> {
}
}


fn accumulate_line(layer_query_evals: &mut Vec<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(&mut 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 +685,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 layer's merkle decommitment and returns the the folded queries and sparse
/// evals.
///
/// # Errors
///
Expand All @@ -691,14 +703,14 @@ impl<H: MerkleHasher> FriFirstLayerVerifier<H> {
&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 +740,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 +764,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 All @@ -769,7 +777,8 @@ struct FriInnerLayerVerifier<H: MerkleHasher> {
}

impl<H: MerkleHasher> FriInnerLayerVerifier<H> {
/// Verifies the layer's merkle decommitment and returns the the folded queries and query evals.
/// Verifies the layer's merkle decommitment and returns the the folded queries and sparse
/// evals.
///
/// # Errors
///
Expand All @@ -784,9 +793,9 @@ impl<H: MerkleHasher> FriInnerLayerVerifier<H> {
/// * The queries are sampled on the wrong domain.
fn verify_and_fold(
&self,
queries: Queries,
queries: &Queries,
evals_at_queries: Vec<SecureField>,
) -> Result<(Queries, Vec<SecureField>), FriVerificationError> {
) -> Result<SparseEvaluation, FriVerificationError> {
assert_eq!(queries.log_domain_size, self.domain.log_size());

let mut fri_witness = self.proof.fri_witness.iter().copied();
Expand Down Expand Up @@ -834,10 +843,7 @@ impl<H: MerkleHasher> FriInnerLayerVerifier<H> {
error: e,
})?;

let folded_queries = queries.fold(FOLD_STEP);
let folded_evals = sparse_evaluation.fold_line(self.folding_alpha, self.domain);

Ok((folded_queries, folded_evals))
Ok(sparse_evaluation)
}
}

Expand Down
Loading