Skip to content

Commit

Permalink
Contain queries in FRI.
Browse files Browse the repository at this point in the history
  • Loading branch information
alonh5 committed Feb 20, 2024
1 parent c485aef commit 724f03a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 62 deletions.
112 changes: 80 additions & 32 deletions src/core/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ impl<H: Hasher<NativeType = u8>> FriProver<H> {
}

pub struct FriVerifier<H: Hasher> {
config: FriConfig,
/// Alpha used to fold all circle polynomials to univariate polynomials.
circle_poly_alpha: SecureField,
/// Domain size queries should be sampled from.
Expand All @@ -255,6 +256,9 @@ pub struct FriVerifier<H: Hasher> {
inner_layers: Vec<FriLayerVerifier<H>>,
last_layer_domain: LineDomain,
last_layer_poly: LinePoly<SecureField>,
/// The queries used for decommitment. Initialized when calling
/// [`FriVerifier::column_opening_positions`].
queries: Option<Queries>,
}

impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
Expand Down Expand Up @@ -328,12 +332,14 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
channel.mix_felts(&last_layer_poly);

Ok(Self {
config,
circle_poly_alpha,
column_bounds,
expected_query_log_domain_size,
inner_layers,
last_layer_domain,
last_layer_poly,
queries: None,
})
}

Expand All @@ -344,23 +350,36 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
/// # Panics
///
/// Panics if:
/// * The queries were not yet sampled.
/// * The queries were sampled on the wrong domain size.
/// * There aren't the same number of decommited values as degree bounds.
/// * There aren't the same number of decommitted values as degree bounds.
// TODO(andrew): Finish docs.
pub fn decommit<F>(
mut self,
decommitted_values: Vec<SparseCircleEvaluation<F>>,
) -> Result<(), VerificationError>
where
F: ExtensionOf<BaseField>,
SecureField: ExtensionOf<F>,
{
let queries = self.queries.take().expect("queries not sampled");
self.decommit_on_queries(&queries, decommitted_values)
}

fn decommit_on_queries<F>(
self,
queries: &Queries,
decommited_values: Vec<SparseCircleEvaluation<F>>,
decommitted_values: Vec<SparseCircleEvaluation<F>>,
) -> Result<(), VerificationError>
where
F: ExtensionOf<BaseField>,
SecureField: ExtensionOf<F>,
{
assert_eq!(queries.log_domain_size, self.expected_query_log_domain_size);
assert_eq!(decommited_values.len(), self.column_bounds.len());
assert_eq!(decommitted_values.len(), self.column_bounds.len());

let (last_layer_queries, last_layer_query_evals) =
self.decommit_inner_layers(queries, decommited_values)?;
self.decommit_inner_layers(queries, decommitted_values)?;

self.decommit_last_layer(last_layer_queries, last_layer_query_evals)
}
Expand All @@ -371,7 +390,7 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
fn decommit_inner_layers<F>(
&self,
queries: &Queries,
decommited_values: Vec<SparseCircleEvaluation<F>>,
decommitted_values: Vec<SparseCircleEvaluation<F>>,
) -> Result<(Queries, Vec<SecureField>), VerificationError>
where
F: ExtensionOf<BaseField>,
Expand All @@ -380,7 +399,7 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
let circle_poly_alpha = self.circle_poly_alpha;
let circle_poly_alpha_sq = circle_poly_alpha * circle_poly_alpha;

let mut decommited_values = decommited_values.into_iter();
let mut decommitted_values = decommitted_values.into_iter();
let mut column_bounds = self.column_bounds.iter().copied().peekable();
let mut layer_queries = queries.fold(CIRCLE_TO_LINE_FOLD_STEP);
let mut layer_query_evals = vec![SecureField::zero(); layer_queries.len()];
Expand All @@ -391,7 +410,7 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
.next_if(|b| b.fold_to_line() == layer.degree_bound)
.is_some()
{
let sparse_evaluation = decommited_values.next().unwrap();
let sparse_evaluation = decommitted_values.next().unwrap();
let folded_evals = sparse_evaluation.fold(circle_poly_alpha);
assert_eq!(folded_evals.len(), layer_query_evals.len());

Expand All @@ -406,7 +425,7 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {

// Check all values have been consumed.
assert!(column_bounds.is_empty());
assert!(decommited_values.is_empty());
assert!(decommitted_values.is_empty());

Ok((layer_queries, layer_query_evals))
}
Expand All @@ -433,9 +452,31 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {

Ok(())
}

/// Samples queries and returns the opening positions for each unique column size.
///
/// The order of the opening positions corresponds to the order of the column commitment.
pub fn column_opening_positions(
&mut self,
channel: &mut impl Channel<Digest = H::Hash>,
) -> Vec<SparseSubCircleDomain> {
let column_log_sizes = self
.column_bounds
.iter()
.dedup()
.map(|b| b.log_degree_bound + self.config.log_blowup_factor)
.collect_vec();
let queries = Queries::generate(channel, column_log_sizes[0], self.config.n_queries);
let positions = get_opening_positions(&queries, &column_log_sizes);
self.queries = Some(queries);
positions
}
}

/// Returns the column opening positions needed for verification.
///
/// The domain log sizes must be unique and in descending order.
// TODO(AlonH): Consider returning a mapping instead of a vector.
fn get_opening_positions(
queries: &Queries,
domain_log_sizes: &[u32],
Expand Down Expand Up @@ -897,7 +938,7 @@ mod tests {

use num_traits::{One, Zero};

use super::{SparseCircleEvaluation, VerificationError};
use super::{get_opening_positions, SparseCircleEvaluation, VerificationError};
use crate::commitment_scheme::blake2_hash::{Blake2sHash, Blake2sHasher};
use crate::core::channel::{Blake2sChannel, Channel};
use crate::core::circle::{CirclePointIndex, Coset};
Expand All @@ -912,8 +953,7 @@ mod tests {
use crate::core::poly::circle::{CircleDomain, CircleEvaluation, CirclePoly};
use crate::core::poly::line::{LineDomain, LineEvaluation, LinePoly};
use crate::core::poly::{BitReversedOrder, NaturalOrder};
use crate::core::queries::Queries;
use crate::core::utils::bit_reverse_index;
use crate::core::queries::{Queries, SparseSubCircleDomain};

/// Default blowup factor used for tests.
const LOG_BLOWUP_FACTOR: u32 = 2;
Expand Down Expand Up @@ -997,7 +1037,7 @@ mod tests {
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();

verifier.decommit(&queries, vec![decommitment_value])
verifier.decommit_on_queries(&queries, vec![decommitment_value])
}

#[test]
Expand All @@ -1014,24 +1054,27 @@ mod tests {
let bounds = LOG_DEGREES.map(CirclePolyDegreeBound::new).to_vec();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bounds).unwrap();

verifier.decommit(&queries, decommitment_values)
verifier.decommit_on_queries(&queries, decommitment_values)
}

#[test]
fn valid_mixed_degree_end_to_end_proof_passes_verification() -> Result<(), VerificationError> {
const LOG_DEGREES: [u32; 3] = [6, 5, 4];
let polynomials =
LOG_DEGREES.map(|log_d| polynomial_evaluation::<BaseField>(log_d, LOG_BLOWUP_FACTOR));
let max_column_log_size = polynomials[0].domain.log_size();
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let queries = Queries::generate(&mut test_channel(), max_column_log_size, config.n_queries);
let prover = FriProver::commit(&mut test_channel(), config, &polynomials);
let decommitment_values = polynomials.map(|p| query_polynomial(&p, &queries)).to_vec();
let (proof, _) = prover.decommit(&mut test_channel());
let (proof, prover_opening_positions) = prover.decommit(&mut test_channel());
let decommitment_values = zip(&polynomials, &prover_opening_positions)
.map(|(poly, positions)| open_polynomial(poly, positions))
.collect();
let bounds = LOG_DEGREES.map(CirclePolyDegreeBound::new).to_vec();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bounds).unwrap();

verifier.decommit(&queries, decommitment_values)
let mut verifier = FriVerifier::commit(&mut test_channel(), config, proof, bounds).unwrap();
let verifier_opening_positions = verifier.column_opening_positions(&mut test_channel());

assert_eq!(prover_opening_positions, verifier_opening_positions);
verifier.decommit(decommitment_values)
}

#[test]
Expand Down Expand Up @@ -1093,7 +1136,7 @@ mod tests {
proof.inner_layers[1].evals_subset.pop();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();

let verification_result = verifier.decommit(&queries, vec![decommitment_value]);
let verification_result = verifier.decommit_on_queries(&queries, vec![decommitment_value]);

assert!(matches!(
verification_result,
Expand All @@ -1116,7 +1159,7 @@ mod tests {
proof.inner_layers[1].evals_subset[0] += BaseField::one();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();

let verification_result = verifier.decommit(&queries, vec![decommitment_value]);
let verification_result = verifier.decommit_on_queries(&queries, vec![decommitment_value]);

assert!(matches!(
verification_result,
Expand Down Expand Up @@ -1161,7 +1204,7 @@ mod tests {
proof.last_layer_poly[0] += BaseField::one();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();

let verification_result = verifier.decommit(&queries, vec![decommitment_value]);
let verification_result = verifier.decommit_on_queries(&queries, vec![decommitment_value]);

assert!(matches!(
verification_result,
Expand All @@ -1186,7 +1229,7 @@ mod tests {
let mut invalid_queries = queries.clone();
invalid_queries.log_domain_size -= 1;

let _ = verifier.decommit(&invalid_queries, vec![decommitment_value]);
let _ = verifier.decommit_on_queries(&invalid_queries, vec![decommitment_value]);
}

/// Returns an evaluation of a random polynomial with degree `2^log_degree`.
Expand Down Expand Up @@ -1217,19 +1260,24 @@ mod tests {
polynomial: &CircleEvaluation<F, BitReversedOrder>,
queries: &Queries,
) -> SparseCircleEvaluation<F> {
let domain = polynomial.domain;
let positions = get_opening_positions(
queries,
&[queries.log_domain_size, polynomial.domain.log_size()],
);
open_polynomial(polynomial, &positions[1])
}

fn open_polynomial<F: ExtensionOf<BaseField>>(
polynomial: &CircleEvaluation<F, BitReversedOrder>,
positions: &SparseSubCircleDomain,
) -> SparseCircleEvaluation<F> {
let polynomial = polynomial.clone().bit_reverse();
let oracle = EvalByEvaluation::new(CirclePointIndex::zero(), &polynomial);

// Get queries on the polynomial
let polynomial_queries = queries.fold(queries.log_domain_size - domain.log_size());

let coset_evals = polynomial_queries
let coset_evals = positions
.iter()
.map(|&query| {
let position = bit_reverse_index(query, domain.log_size());
let p = domain.index_at(position);
let coset_domain = CircleDomain::new(Coset::new(p, 0));
.map(|position| {
let coset_domain = position.to_circle_domain(&polynomial.domain);
let evals = coset_domain
.iter_indices()
.map(|p| oracle.get_at(p))
Expand Down
7 changes: 4 additions & 3 deletions src/core/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Queries {
})
.dedup()
.collect(),
large_domain_size: self.log_domain_size,
large_domain_log_size: self.log_domain_size,
}
}
}
Expand All @@ -87,9 +87,10 @@ impl Deref for Queries {
}
}

#[derive(Debug, Eq, PartialEq)]
pub struct SparseSubCircleDomain {
pub domains: Vec<SubCircleDomain>,
pub large_domain_size: u32,
pub large_domain_log_size: u32,
}

impl SparseSubCircleDomain {
Expand All @@ -110,7 +111,7 @@ impl Deref for SparseSubCircleDomain {

/// Represents a circle domain relative to a larger circle domain. The `initial_index` is the bit
/// reversed query index in the larger domain.
#[derive(PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct SubCircleDomain {
pub coset_index: usize,
pub log_size: u32,
Expand Down
33 changes: 6 additions & 27 deletions src/fibonacci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::core::oods::{get_oods_quotient, get_pair_oods_quotient, quotient_log_
use crate::core::poly::circle::{CanonicCoset, CircleEvaluation, CirclePoly};
use crate::core::poly::BitReversedOrder;
use crate::core::proof_of_work::{ProofOfWork, ProofOfWorkProof};
use crate::core::queries::Queries;

type Channel = Blake2sChannel;
type MerkleHasher = Blake2sHasher;
Expand Down Expand Up @@ -237,31 +236,13 @@ pub fn verify_proof<const N_BITS: u32>(proof: FibonacciProof) -> bool {
)];
bounds.append(&mut quotient_log_bounds(fib.component));
let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES);
let fri_verifier = FriVerifier::commit(channel, fri_config, proof.fri_proof, bounds).unwrap();
let mut fri_verifier =
FriVerifier::commit(channel, fri_config, proof.fri_proof, bounds).unwrap();

ProofOfWork::new(PROOF_OF_WORK_BITS).verify(channel, &proof.proof_of_work);
let composition_polynomial_queries = Queries::generate(
channel,
fib.composition_polynomial_commitment_domain.log_size(),
N_QUERIES,
);
let trace_queries = composition_polynomial_queries.fold(
fib.composition_polynomial_commitment_domain.log_size()
- fib.trace_commitment_domain.log_size(),
);
// TODO(AlonH): Get sub circle domains from FRI.
const FRI_STEP_SIZE: u32 = 1;
let composition_polynomial_opening_positions =
composition_polynomial_queries.opening_positions(FRI_STEP_SIZE);
let trace_opening_positions = trace_queries.opening_positions(FRI_STEP_SIZE);
assert_eq!(
trace_opening_positions.len(),
proof.trace_opened_values.len() >> FRI_STEP_SIZE
);
assert_eq!(
composition_polynomial_opening_positions.len(),
proof.composition_polynomial_opened_values.len() >> FRI_STEP_SIZE
);
let opening_positions = fri_verifier.column_opening_positions(channel);
let composition_polynomial_opening_positions = &opening_positions[0];
let trace_opening_positions = &opening_positions[1];
assert!(trace_commitment_scheme.verify(
&proof.trace_decommitments[0],
&trace_opening_positions.flatten()
Expand Down Expand Up @@ -315,9 +296,7 @@ pub fn verify_proof<const N_BITS: u32>(proof: FibonacciProof) -> bool {
sparse_circle_evaluations.push(SparseCircleEvaluation::new(evaluation));
}

fri_verifier
.decommit(&composition_polynomial_queries, sparse_circle_evaluations)
.unwrap();
fri_verifier.decommit(sparse_circle_evaluations).unwrap();

true
}
Expand Down

0 comments on commit 724f03a

Please sign in to comment.