Skip to content

Commit

Permalink
Add errors in prove. (#468)
Browse files Browse the repository at this point in the history
<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/starkware-libs/stwo/468)
<!-- Reviewable:end -->
  • Loading branch information
alonh5 committed Mar 20, 2024
1 parent b89a453 commit f0abe55
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/commitment_scheme/blake2_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl super::hasher::Name for Blake2sHash {
impl super::hasher::Hash<u8> for Blake2sHash {}

// Wrapper for the blake2s Hashing functionalities.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Blake2sHasher {
state: Blake2s256,
}
Expand Down
2 changes: 1 addition & 1 deletion src/commitment_scheme/merkle_decommitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::core::fields::IntoSlice;
/// queried path, or nodes with both children in the queried path are excluded.
/// * `n_rows_in_leaf_block` - The number of trace-rows packed in each leaf block.
// TODO(Ohad): derive Debug.
#[derive(Default)]
#[derive(Default, Debug)]
pub struct MerkleDecommitment<T: Sized + Display, H: Hasher> {
pub leaf_blocks: Vec<Vec<T>>,
pub layers: Vec<Vec<H::Hash>>,
Expand Down
2 changes: 2 additions & 0 deletions src/core/commitment_scheme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod utils;

/// Holds a vector for each tree, which holds a vector for each column, which holds its respective
/// opened values.
#[derive(Debug)]
pub struct OpenedValues(pub Vec<ColumnVec<Vec<BaseField>>>);

impl Deref for OpenedValues {
Expand All @@ -30,6 +31,7 @@ impl Deref for OpenedValues {
}
}

#[derive(Debug)]
pub struct Decommitments(Vec<MerkleDecommitment<BaseField, Blake2sHasher>>);

impl Deref for Decommitments {
Expand Down
2 changes: 1 addition & 1 deletion src/core/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ mod tests {
use crate::core::fields::{ComplexConjugate, FieldExpOps};
use crate::core::poly::circle::CanonicCoset;
use crate::core::poly::NaturalOrder;
use crate::core::utils::secure_eval_to_base_eval;
use crate::core::test_utils::secure_eval_to_base_eval;
use crate::m31;

#[test]
Expand Down
11 changes: 4 additions & 7 deletions src/core/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ impl LinePolyDegreeBound {
}

/// A FRI proof.
#[derive(Debug)]
pub struct FriProof<H: Hasher> {
pub inner_layers: Vec<FriLayerProof<H>>,
pub last_layer_poly: LinePoly<SecureField>,
Expand All @@ -634,6 +635,7 @@ pub const CIRCLE_TO_LINE_FOLD_STEP: u32 = 1;
/// Stores a subset of evaluations in a [FriLayer] with their corresponding merkle decommitments.
///
/// The subset corresponds to the set of evaluations needed by a FRI verifier.
#[derive(Debug)]
pub struct FriLayerProof<H: Hasher> {
/// The subset stored corresponds to the set of evaluations the verifier doesn't have but needs
/// to fold and verify the merkle decommitment.
Expand Down Expand Up @@ -911,10 +913,9 @@ mod tests {
use num_traits::{One, Zero};

use super::{get_opening_positions, SparseCircleEvaluation, VerificationError};
use crate::commitment_scheme::blake2_hash::{Blake2sHash, Blake2sHasher};
use crate::commitment_scheme::blake2_hash::Blake2sHasher;
use crate::core::backend::cpu::{CPUCircleEvaluation, CPUCirclePoly, CPULineEvaluation};
use crate::core::backend::CPUBackend;
use crate::core::channel::{Blake2sChannel, Channel};
use crate::core::circle::{CirclePointIndex, Coset};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
Expand All @@ -926,6 +927,7 @@ mod tests {
use crate::core::poly::line::{LineDomain, LineEvaluation, LinePoly};
use crate::core::poly::{BitReversedOrder, NaturalOrder};
use crate::core::queries::{Queries, SparseSubCircleDomain};
use crate::core::test_utils::test_channel;

/// Default blowup factor used for tests.
const LOG_BLOWUP_FACTOR: u32 = 2;
Expand Down Expand Up @@ -1278,9 +1280,4 @@ mod tests {

SparseCircleEvaluation::new(coset_evals)
}

fn test_channel() -> Blake2sChannel {
let seed = Blake2sHash::from(vec![0; 32]);
Blake2sChannel::new(seed)
}
}
3 changes: 3 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ pub mod poly;
pub mod proof_of_work;
pub mod prover;
pub mod queries;
#[cfg(test)]
pub mod test_utils;
pub mod utils;

/// A vector in which each element relates (by index) to a column in the trace.
pub type ColumnVec<T> = Vec<T>;

/// A vector of [ColumnVec]s. Each [ColumnVec] relates (by index) to a component in the air.
#[derive(Debug)]
pub struct ComponentVec<T>(pub Vec<ColumnVec<T>>);

impl<T: Copy> ComponentVec<ColumnVec<T>> {
Expand Down
6 changes: 5 additions & 1 deletion src/core/poly/circle/domain.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::iter::Chain;

use crate::core::circle::{CirclePoint, CirclePointIndex, Coset, CosetIterator};
use crate::core::circle::{
CirclePoint, CirclePointIndex, Coset, CosetIterator, M31_CIRCLE_LOG_ORDER,
};
use crate::core::fields::m31::BaseField;

pub const MAX_CIRCLE_DOMAIN_LOG_SIZE: u32 = M31_CIRCLE_LOG_ORDER - 1;

/// A valid domain for circle polynomial interpolation and evaluation.
/// Valid domains are a disjoint union of two conjugate cosets: +-C + <G_n>.
/// The ordering defined on this domain is C + iG_n, and then -C - iG_n.
Expand Down
2 changes: 1 addition & 1 deletion src/core/poly/circle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod poly;
mod secure_poly;

pub use canonic::CanonicCoset;
pub use domain::CircleDomain;
pub use domain::{CircleDomain, MAX_CIRCLE_DOMAIN_LOG_SIZE};
pub use evaluation::{CircleEvaluation, CosetSubEvaluation};
pub use ops::PolyOps;
pub use poly::CirclePoly;
Expand Down
150 changes: 146 additions & 4 deletions src/core/prover/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::iter::zip;

use itertools::{enumerate, Itertools};
use thiserror::Error;

use super::poly::circle::CanonicCoset;
use super::poly::circle::{CanonicCoset, MAX_CIRCLE_DOMAIN_LOG_SIZE};
use super::queries::SparseSubCircleDomain;
use super::ColumnVec;
use crate::commitment_scheme::blake2_hash::Blake2sHasher;
Expand Down Expand Up @@ -33,6 +34,7 @@ pub const LOG_LAST_LAYER_DEGREE_BOUND: u32 = 0;
pub const PROOF_OF_WORK_BITS: u32 = 12;
pub const N_QUERIES: usize = 3;

#[derive(Debug)]
pub struct StarkProof {
pub commitments: Vec<<MerkleHasher as Hasher>::Hash>,
pub decommitments: Decommitments,
Expand All @@ -44,6 +46,7 @@ pub struct StarkProof {
pub additional_proof_data: AdditionalProofData,
}

#[derive(Debug)]
pub struct AdditionalProofData {
pub composition_polynomial_oods_value: SecureField,
pub composition_polynomial_random_coeff: SecureField,
Expand All @@ -55,7 +58,25 @@ pub fn prove(
air: &impl Air<CPUBackend>,
channel: &mut Channel,
trace: ColumnVec<CPUCircleEvaluation<BaseField, BitReversedOrder>>,
) -> StarkProof {
) -> Result<StarkProof, ProvingError> {
// Check that traces are not too big.
for (i, trace) in trace.iter().enumerate() {
if trace.domain.log_size() + LOG_BLOWUP_FACTOR > MAX_CIRCLE_DOMAIN_LOG_SIZE {
return Err(ProvingError::MaxTraceDegreeExceeded {
trace_index: i,
degree: trace.domain.log_size(),
});
}
}

// Check that the composition polynomial is not too big.
let composition_polynomial_log_degree_bound = air.max_constraint_log_degree_bound();
if composition_polynomial_log_degree_bound + LOG_BLOWUP_FACTOR > MAX_CIRCLE_DOMAIN_LOG_SIZE {
return Err(ProvingError::MaxCompositionDegreeExceeded {
degree: composition_polynomial_log_degree_bound,
});
}

// Evaluate and commit on trace.
let trace_polys = trace.into_iter().map(|poly| poly.interpolate()).collect();
let mut commitment_scheme = CommitmentSchemeProver::new(LOG_BLOWUP_FACTOR);
Expand Down Expand Up @@ -115,7 +136,7 @@ pub fn prove(

let (opened_values, decommitments) = commitment_scheme.decommit(fri_opening_positions);

StarkProof {
Ok(StarkProof {
commitments: commitment_scheme.roots(),
decommitments,
trace_oods_values,
Expand All @@ -129,7 +150,7 @@ pub fn prove(
oods_point,
oods_quotients,
},
}
})
}

pub fn verify(proof: StarkProof, air: &impl Air<CPUBackend>, channel: &mut Channel) -> bool {
Expand Down Expand Up @@ -256,3 +277,124 @@ fn prepare_fri_evaluations(
}
sparse_circle_evaluations
}

#[derive(Clone, Copy, Debug, Error)]
pub enum ProvingError {
#[error(
"Trace column {trace_index} log degree bound ({degree}) exceeded max log degree ({}).",
MAX_CIRCLE_DOMAIN_LOG_SIZE - LOG_BLOWUP_FACTOR
)]
MaxTraceDegreeExceeded { trace_index: usize, degree: u32 },
#[error(
"Composition polynomial log degree bound ({degree}) exceeded max log degree ({}).",
MAX_CIRCLE_DOMAIN_LOG_SIZE - LOG_BLOWUP_FACTOR
)]
MaxCompositionDegreeExceeded { degree: u32 },
}

#[cfg(test)]
mod tests {
use num_traits::Zero;

use crate::core::air::evaluation::{DomainEvaluationAccumulator, PointEvaluationAccumulator};
use crate::core::air::{Air, Component, ComponentTrace, ComponentVisitor, Mask};
use crate::core::backend::cpu::CPUCircleEvaluation;
use crate::core::backend::CPUBackend;
use crate::core::circle::{CirclePoint, CirclePointIndex, Coset};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::poly::circle::{CircleDomain, MAX_CIRCLE_DOMAIN_LOG_SIZE};
use crate::core::prover::{prove, ProvingError};
use crate::core::test_utils::test_channel;

struct TestAir<C: Component<CPUBackend>>(C);

impl Air<CPUBackend> for TestAir<TestComponent> {
fn visit_components<V: ComponentVisitor<CPUBackend>>(&self, v: &mut V) {
v.visit(&self.0)
}
}

struct TestComponent {
max_constraint_log_degree_bound: u32,
}

impl Component<CPUBackend> for TestComponent {
fn max_constraint_log_degree_bound(&self) -> u32 {
self.max_constraint_log_degree_bound
}

fn trace_log_degree_bounds(&self) -> Vec<u32> {
todo!()
}

fn evaluate_constraint_quotients_on_domain(
&self,
_trace: &ComponentTrace<'_, CPUBackend>,
_evaluation_accumulator: &mut DomainEvaluationAccumulator<CPUBackend>,
) {
todo!()
}

fn mask(&self) -> Mask {
todo!()
}

fn evaluate_constraint_quotients_at_point(
&self,
_point: CirclePoint<SecureField>,
_mask: &crate::core::ColumnVec<Vec<SecureField>>,
_evaluation_accumulator: &mut PointEvaluationAccumulator,
) {
todo!()
}
}

// Ignored because it takes too long and too much memory (in the CI) to run.
#[test]
#[ignore]
fn test_trace_too_big() {
const LOG_DOMAIN_SIZE: u32 = MAX_CIRCLE_DOMAIN_LOG_SIZE;
let air = TestAir(TestComponent {
max_constraint_log_degree_bound: LOG_DOMAIN_SIZE,
});
let domain = CircleDomain::new(Coset::new(
CirclePointIndex::generator(),
LOG_DOMAIN_SIZE - 1,
));
let values = vec![BaseField::zero(); 1 << LOG_DOMAIN_SIZE];
let trace = vec![CPUCircleEvaluation::new(domain, values)];

let proof_error = prove(&air, &mut test_channel(), trace).unwrap_err();
assert!(matches!(
proof_error,
ProvingError::MaxTraceDegreeExceeded {
trace_index: 0,
degree: LOG_DOMAIN_SIZE
}
));
}

#[test]
fn test_composition_polynomial_too_big() {
const COMPOSITION_POLYNOMIAL_DEGREE: u32 = MAX_CIRCLE_DOMAIN_LOG_SIZE;
let air = TestAir(TestComponent {
max_constraint_log_degree_bound: COMPOSITION_POLYNOMIAL_DEGREE,
});
const LOG_DOMAIN_SIZE: u32 = 5;
let domain = CircleDomain::new(Coset::new(
CirclePointIndex::generator(),
LOG_DOMAIN_SIZE - 1,
));
let values = vec![BaseField::zero(); 1 << LOG_DOMAIN_SIZE];
let trace = vec![CPUCircleEvaluation::new(domain, values)];

let proof_error = prove(&air, &mut test_channel(), trace).unwrap_err();
assert!(matches!(
proof_error,
ProvingError::MaxCompositionDegreeExceeded {
degree: COMPOSITION_POLYNOMIAL_DEGREE
}
));
}
}
21 changes: 21 additions & 0 deletions src/core/test_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use super::backend::cpu::CPUCircleEvaluation;
use super::channel::Blake2sChannel;
use super::fields::m31::BaseField;
use super::fields::qm31::SecureField;
use crate::core::channel::Channel;

pub fn secure_eval_to_base_eval<EvalOrder>(
eval: &CPUCircleEvaluation<SecureField, EvalOrder>,
) -> CPUCircleEvaluation<BaseField, EvalOrder> {
CPUCircleEvaluation::new(
eval.domain,
eval.values.iter().map(|x| x.to_m31_array()[0]).collect(),
)
}

pub fn test_channel() -> Blake2sChannel {
use crate::commitment_scheme::blake2_hash::Blake2sHash;

let seed = Blake2sHash::from(vec![0; 32]);
Blake2sChannel::new(seed)
}
10 changes: 0 additions & 10 deletions src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,6 @@ pub fn bit_reverse<T>(v: &mut [T]) {
}
}

#[cfg(test)]
pub fn secure_eval_to_base_eval<EvalOrder>(
eval: &super::backend::cpu::CPUCircleEvaluation<super::fields::qm31::SecureField, EvalOrder>,
) -> super::backend::cpu::CPUCircleEvaluation<super::fields::m31::BaseField, EvalOrder> {
super::backend::cpu::CPUCircleEvaluation::new(
eval.domain,
eval.values.iter().map(|x| x.to_m31_array()[0]).collect(),
)
}

#[cfg(test)]
mod tests {
use crate::core::utils::bit_reverse;
Expand Down
Loading

0 comments on commit f0abe55

Please sign in to comment.