Skip to content

Commit

Permalink
Get opening positions from FRI.
Browse files Browse the repository at this point in the history
  • Loading branch information
alonh5 committed Feb 18, 2024
1 parent 18ed839 commit bccbf21
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 44 deletions.
86 changes: 60 additions & 26 deletions src/core/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fmt::Debug;
use std::iter::zip;
use std::ops::RangeInclusive;

use itertools::Itertools;
use num_traits::Zero;
use thiserror::Error;

Expand All @@ -14,7 +15,7 @@ use super::poly::circle::CircleEvaluation;
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;
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;
Expand All @@ -29,7 +30,8 @@ use crate::core::utils::bit_reverse_index;
pub struct FriConfig {
log_blowup_factor: u32,
log_last_layer_degree_bound: u32,
// TODO(andrew): Add num_queries, fold_steps.
pub n_queries: usize,
// TODO(andrew): fold_steps.
}

impl FriConfig {
Expand All @@ -50,12 +52,13 @@ impl FriConfig {
/// Panics if:
/// * `log_last_layer_degree_bound` is greater than 10.
/// * `log_blowup_factor` is equal to zero or greater than 16.
pub fn new(log_last_layer_degree_bound: u32, log_blowup_factor: u32) -> Self {
pub fn new(log_last_layer_degree_bound: u32, log_blowup_factor: u32, n_queries: usize) -> Self {
assert!(Self::LOG_LAST_LAYER_DEGREE_BOUND_RANGE.contains(&log_last_layer_degree_bound));
assert!(Self::LOG_BLOWUP_FACTOR_RANGE.contains(&log_blowup_factor));
Self {
log_blowup_factor,
log_last_layer_degree_bound,
n_queries,
}
}

Expand All @@ -66,14 +69,16 @@ impl FriConfig {

/// A FRI prover that applies the FRI protocol to prove a set of polynomials are of low degree.
pub struct FriProver<H: Hasher> {
config: FriConfig,
inner_layers: Vec<FriLayerProver<H>>,
last_layer_poly: LinePoly<SecureField>,
column_log_sizes: Vec<u32>,
}

impl<H: Hasher<NativeType = u8>> FriProver<H> {
/// Commits to multiple [CircleEvaluation]s.
///
/// `evals` must be provided in descending order by size.
/// `columns` must be provided in descending order by size.
///
/// Mixed degree STARKs involve polynomials evaluated on multiple domains of different size.
/// Combining evaluations on different sized domains into an evaluation of a single polynomial
Expand All @@ -84,7 +89,7 @@ impl<H: Hasher<NativeType = u8>> FriProver<H> {
/// # Panics
///
/// Panics if:
/// * `evals` is empty or not sorted in ascending order by domain size.
/// * `columns` is empty or not sorted in ascending order by domain size.
/// * An evaluation is not from a sufficiently low degree circle polynomial.
/// * An evaluation's domain is smaller than the last layer.
/// * An evaluation's domain is not a canonic circle domain.
Expand All @@ -98,14 +103,19 @@ impl<H: Hasher<NativeType = u8>> FriProver<H> {
F: ExtensionOf<BaseField>,
SecureField: ExtensionOf<F>,
{
assert!(!columns.is_empty(), "no columns");
assert!(columns.is_sorted_by_key(|e| Reverse(e.len())), "not sorted");
assert!(columns.iter().all(|e| e.domain.is_canonic()), "not canonic");
let (inner_layers, last_layer_evaluation) =
Self::commit_inner_layers(channel, config, columns);
let last_layer_poly = Self::commit_last_layer(channel, config, last_layer_evaluation);

let column_log_sizes = columns.iter().map(|e| e.domain.log_size()).collect_vec();
Self {
config,
inner_layers,
last_layer_poly,
column_log_sizes,
}
}

Expand Down Expand Up @@ -191,10 +201,20 @@ impl<H: Hasher<NativeType = u8>> FriProver<H> {
last_layer_poly
}

pub fn decommit(
self,
channel: &mut impl Channel<Digest = H::Hash>,
) -> (FriProof<H>, Vec<SparseSubCircleDomain>) {
let queries = Queries::generate(channel, self.column_log_sizes[0], self.config.n_queries);
let positions = opening_positions(&queries, &self.column_log_sizes);
let proof = self.decommit_on_queries(&queries);
(proof, positions)
}

/// # Panics
///
/// Panics if the queries were sampled on the wrong domain size.
pub fn decommit(self, queries: &Queries) -> FriProof<H> {
fn decommit_on_queries(self, queries: &Queries) -> FriProof<H> {
let first_layer_queries = queries.fold(CIRCLE_TO_LINE_FOLD_STEP);
let inner_layers = self
.inner_layers
Expand Down Expand Up @@ -405,6 +425,20 @@ impl<H: Hasher<NativeType = u8>> FriVerifier<H> {
}
}

fn opening_positions(queries: &Queries, domain_log_sizes: &[u32]) -> Vec<SparseSubCircleDomain> {
let mut prev_log_size = domain_log_sizes[0];
let mut prev_queries = queries.clone();
let mut positions = vec![prev_queries.opening_positions(FOLD_STEP)];
for log_size in domain_log_sizes.iter().skip(1) {
let n_folds = prev_log_size - log_size;
let queries = prev_queries.fold(n_folds);
positions.push(queries.opening_positions(FOLD_STEP));
prev_log_size = *log_size;
prev_queries = queries;
}
positions
}

pub trait FriChannel {
type Digest;

Expand Down Expand Up @@ -919,7 +953,7 @@ mod tests {
fn committing_high_degree_polynomial_fails() {
const LOG_EXPECTED_BLOWUP_FACTOR: u32 = LOG_BLOWUP_FACTOR;
const LOG_INVALID_BLOWUP_FACTOR: u32 = LOG_BLOWUP_FACTOR - 1;
let config = FriConfig::new(2, LOG_EXPECTED_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_EXPECTED_BLOWUP_FACTOR, 3);
let evaluation = polynomial_evaluation::<BaseField>(6, LOG_INVALID_BLOWUP_FACTOR);

FriProver::commit(&mut test_channel(), config, &[evaluation]);
Expand All @@ -932,19 +966,19 @@ mod tests {
assert!(!invalid_domain.is_canonic(), "must be an invalid domain");
let evaluation = CircleEvaluation::new(invalid_domain, vec![BaseField::one(); 1 << 4]);

FriProver::commit(&mut test_channel(), FriConfig::new(2, 2), &[evaluation]);
FriProver::commit(&mut test_channel(), FriConfig::new(2, 2, 3), &[evaluation]);
}

#[test]
fn valid_proof_passes_verification() -> Result<(), VerificationError> {
const LOG_DEGREE: u32 = 3;
let config = FriConfig::new(1, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(1, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![5], log_domain_size);
let decommitment_value = query_polynomial(&polynomial, &queries);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let proof = prover.decommit(&queries);
let proof = prover.decommit_on_queries(&queries);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();

Expand All @@ -954,14 +988,14 @@ mod tests {
#[test]
fn valid_mixed_degree_proof_passes_verification() -> Result<(), VerificationError> {
const LOG_DEGREES: [u32; 3] = [6, 5, 4];
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let polynomials =
LOG_DEGREES.map(|log_d| polynomial_evaluation::<BaseField>(log_d, LOG_BLOWUP_FACTOR));
let log_domain_size = polynomials[0].domain.log_size();
let queries = Queries::from_positions(vec![7, 70], log_domain_size);
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(&queries);
let proof = prover.decommit_on_queries(&queries);
let bounds = LOG_DEGREES.map(CirclePolyDegreeBound::new).to_vec();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bounds).unwrap();

Expand All @@ -971,12 +1005,12 @@ mod tests {
#[test]
fn proof_with_removed_layer_fails_verification() {
const LOG_DEGREE: u32 = 6;
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(6, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![1], log_domain_size);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let proof = prover.decommit(&queries);
let proof = prover.decommit_on_queries(&queries);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
// Set verifier's config to expect one extra layer than prover config.
let mut invalid_config = config;
Expand All @@ -993,12 +1027,12 @@ mod tests {
#[test]
fn proof_with_added_layer_fails_verification() {
const LOG_DEGREE: u32 = 6;
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![1], log_domain_size);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let proof = prover.decommit(&queries);
let proof = prover.decommit_on_queries(&queries);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
// Set verifier's config to expect one less layer than prover config.
let mut invalid_config = config;
Expand All @@ -1015,14 +1049,14 @@ mod tests {
#[test]
fn proof_with_invalid_inner_layer_evaluation_fails_verification() {
const LOG_DEGREE: u32 = 6;
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![5], log_domain_size);
let decommitment_value = query_polynomial(&polynomial, &queries);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let mut proof = prover.decommit(&queries);
let mut proof = prover.decommit_on_queries(&queries);
// Remove an evaluation from the second layer's proof.
proof.inner_layers[1].evals_subset.pop();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();
Expand All @@ -1038,14 +1072,14 @@ mod tests {
#[test]
fn proof_with_invalid_inner_layer_decommitment_fails_verification() {
const LOG_DEGREE: u32 = 6;
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![5], log_domain_size);
let decommitment_value = query_polynomial(&polynomial, &queries);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let mut proof = prover.decommit(&queries);
let mut proof = prover.decommit_on_queries(&queries);
// Modify the committed values in the second layer.
proof.inner_layers[1].evals_subset[0] += BaseField::one();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();
Expand All @@ -1062,13 +1096,13 @@ mod tests {
fn proof_with_invalid_last_layer_degree_fails_verification() {
const LOG_DEGREE: u32 = 6;
const LOG_MAX_LAST_LAYER_DEGREE: u32 = 2;
let config = FriConfig::new(LOG_MAX_LAST_LAYER_DEGREE, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(LOG_MAX_LAST_LAYER_DEGREE, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![1, 7, 8], log_domain_size);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let mut proof = prover.decommit(&queries);
let mut proof = prover.decommit_on_queries(&queries);
let bad_last_layer_coeffs = vec![One::one(); 1 << (LOG_MAX_LAST_LAYER_DEGREE + 1)];
proof.last_layer_poly = LinePoly::new(bad_last_layer_coeffs);

Expand All @@ -1083,14 +1117,14 @@ mod tests {
#[test]
fn proof_with_invalid_last_layer_fails_verification() {
const LOG_DEGREE: u32 = 6;
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(2, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![1, 7, 8], log_domain_size);
let decommitment_value = query_polynomial(&polynomial, &queries);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let mut proof = prover.decommit(&queries);
let mut proof = prover.decommit_on_queries(&queries);
// Compromise the last layer polynomial's first coefficient.
proof.last_layer_poly[0] += BaseField::one();
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();
Expand All @@ -1107,13 +1141,13 @@ mod tests {
#[should_panic]
fn decommit_queries_on_invalid_domain_fails_verification() {
const LOG_DEGREE: u32 = 3;
let config = FriConfig::new(1, LOG_BLOWUP_FACTOR);
let config = FriConfig::new(1, LOG_BLOWUP_FACTOR, 3);
let polynomial = polynomial_evaluation::<BaseField>(LOG_DEGREE, LOG_BLOWUP_FACTOR);
let log_domain_size = polynomial.domain.log_size();
let queries = Queries::from_positions(vec![5], log_domain_size);
let decommitment_value = query_polynomial(&polynomial, &queries);
let prover = FriProver::commit(&mut test_channel(), config, &[polynomial]);
let proof = prover.decommit(&queries);
let proof = prover.decommit_on_queries(&queries);
let bound = vec![CirclePolyDegreeBound::new(LOG_DEGREE)];
let verifier = FriVerifier::commit(&mut test_channel(), config, proof, bound).unwrap();
// Simulate the verifier sampling queries on a smaller domain.
Expand Down
23 changes: 5 additions & 18 deletions src/fibonacci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,27 +157,14 @@ impl Fibonacci {
);
}

let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR);
let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES);
let fri_prover = FriProver::commit(channel, fri_config, &oods_quotients);

let proof_of_work = ProofOfWork::new(PROOF_OF_WORK_BITS).prove(channel);
// TODO(AlonH): Get opening positions from FRI.
let composition_polynomial_queries = Queries::generate(
channel,
self.composition_polynomial_commitment_domain.log_size(),
N_QUERIES,
);
let trace_queries = composition_polynomial_queries.fold(
self.composition_polynomial_commitment_domain.log_size()
- self.trace_commitment_domain.log_size(),
);
let fri_proof = fri_prover.decommit(&composition_polynomial_queries);
let (fri_proof, fri_opening_positions) = fri_prover.decommit(channel);

const FRI_STEP_SIZE: u32 = 1;
let composition_polynomial_decommitment_positions = composition_polynomial_queries
.opening_positions(FRI_STEP_SIZE)
.flatten();
let trace_decommitment_positions = trace_queries.opening_positions(FRI_STEP_SIZE).flatten();
let composition_polynomial_decommitment_positions = fri_opening_positions[0].flatten();
let trace_decommitment_positions = fri_opening_positions[1].flatten();

// Decommit and get the values in the opening positions.
let composition_polynomial_opened_values = composition_polynomial_decommitment_positions
Expand Down Expand Up @@ -238,7 +225,7 @@ pub fn verify_proof<const N_BITS: u32>(proof: FibonacciProof) -> bool {
);
let composition_polynomial_oods_value = evaluation_accumulator.finalize();

let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR);
let fri_config = FriConfig::new(LOG_LAST_LAYER_DEGREE_BOUND, LOG_BLOWUP_FACTOR, N_QUERIES);
let bounds = fib.component.log_degree_bounds();
let fri_verifier = FriVerifier::commit(channel, fri_config, proof.fri_proof, bounds).unwrap();

Expand Down

0 comments on commit bccbf21

Please sign in to comment.