From 1aae5f6c705e79198ce985565dc3f725aa782230 Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Sun, 28 Jul 2024 11:51:19 +0200 Subject: [PATCH 1/8] range check example prep --- crates/prover/src/examples/mod.rs | 1 + crates/prover/src/examples/range_check/air.rs | 115 ++++++++++ .../src/examples/range_check/component.rs | 196 ++++++++++++++++++ crates/prover/src/examples/range_check/mod.rs | 67 ++++++ 4 files changed, 379 insertions(+) create mode 100644 crates/prover/src/examples/range_check/air.rs create mode 100644 crates/prover/src/examples/range_check/component.rs create mode 100644 crates/prover/src/examples/range_check/mod.rs diff --git a/crates/prover/src/examples/mod.rs b/crates/prover/src/examples/mod.rs index 45e2f4186..7c9fa069c 100644 --- a/crates/prover/src/examples/mod.rs +++ b/crates/prover/src/examples/mod.rs @@ -1,4 +1,5 @@ pub mod fibonacci; pub mod poseidon; +pub mod range_check; pub mod wide_fibonacci; pub mod xor; diff --git a/crates/prover/src/examples/range_check/air.rs b/crates/prover/src/examples/range_check/air.rs new file mode 100644 index 000000000..6945c2dea --- /dev/null +++ b/crates/prover/src/examples/range_check/air.rs @@ -0,0 +1,115 @@ +use super::component::{RangeCheckComponent, RangeCheckInput, RangeCheckTraceGenerator}; +use crate::core::air::{Air, AirProver, Component, ComponentProver}; +use crate::core::backend::CpuBackend; +use crate::core::channel::Blake2sChannel; +use crate::core::fields::m31::BaseField; +use crate::core::poly::circle::CircleEvaluation; +use crate::core::poly::BitReversedOrder; +use crate::core::prover::VerificationError; +use crate::core::{ColumnVec, InteractionElements, LookupValues}; +use crate::trace_generation::registry::ComponentGenerationRegistry; +use crate::trace_generation::{AirTraceGenerator, AirTraceVerifier, ComponentTraceGenerator}; + +pub struct RangeCheckAirGenerator { + pub registry: ComponentGenerationRegistry, +} + +impl RangeCheckAirGenerator { + pub fn new(inputs: &RangeCheckInput) -> Self { + let mut component_generator = RangeCheckTraceGenerator::new(); + component_generator.add_inputs(inputs); + let mut registry = ComponentGenerationRegistry::default(); + registry.register("range_check", component_generator); + Self { registry } + } +} + +impl AirTraceVerifier for RangeCheckAirGenerator { + fn interaction_elements(&self, _channel: &mut Blake2sChannel) -> InteractionElements { + InteractionElements::default() + } +} + +impl AirTraceGenerator for RangeCheckAirGenerator { + fn write_trace(&mut self) -> Vec> { + RangeCheckTraceGenerator::write_trace("range_check", &mut self.registry) + } + + fn interact( + &self, + _trace: &ColumnVec>, + _elements: &InteractionElements, + ) -> Vec> { + vec![] + } + + fn to_air_prover(&self) -> impl AirProver { + let component_generator = self + .registry + .get_generator::("range_check"); + RangeCheckAir { + component: component_generator.component(), + } + } + + fn composition_log_degree_bound(&self) -> u32 { + let component_generator = self + .registry + .get_generator::("range_check"); + assert!(component_generator.inputs_set(), "Fibonacci input not set."); + component_generator + .component() + .max_constraint_log_degree_bound() + } +} + +#[derive(Clone)] +pub struct RangeCheckAir { + pub component: RangeCheckComponent, +} + +impl RangeCheckAir { + pub fn new(component: RangeCheckComponent) -> Self { + Self { component } + } +} + +impl Air for RangeCheckAir { + fn components(&self) -> Vec<&dyn Component> { + vec![&self.component] + } + + fn verify_lookups(&self, _lookup_values: &LookupValues) -> Result<(), VerificationError> { + Ok(()) + } +} + +impl AirTraceVerifier for RangeCheckAir { + fn interaction_elements(&self, _channel: &mut Blake2sChannel) -> InteractionElements { + InteractionElements::default() + } +} + +impl AirTraceGenerator for RangeCheckAir { + fn interact( + &self, + _trace: &ColumnVec>, + _elements: &InteractionElements, + ) -> Vec> { + vec![] + } + + fn to_air_prover(&self) -> impl AirProver { + self.clone() + } + + fn composition_log_degree_bound(&self) -> u32 { + self.component.max_constraint_log_degree_bound() + } +} + +impl AirProver for RangeCheckAir { + fn prover_components(&self) -> Vec<&dyn ComponentProver> { + vec![&self.component] + } +} diff --git a/crates/prover/src/examples/range_check/component.rs b/crates/prover/src/examples/range_check/component.rs new file mode 100644 index 000000000..a34329ada --- /dev/null +++ b/crates/prover/src/examples/range_check/component.rs @@ -0,0 +1,196 @@ +use std::ops::Div; + +use crate::core::air::accumulation::{DomainEvaluationAccumulator, PointEvaluationAccumulator}; +use crate::core::air::mask::shifted_mask_points; +use crate::core::air::{Component, ComponentProver, ComponentTrace}; +use crate::core::backend::CpuBackend; +use crate::core::circle::CirclePoint; +use crate::core::fields::m31::BaseField; +use crate::core::fields::qm31::SecureField; +use crate::core::fields::ExtensionOf; +use crate::core::pcs::TreeVec; +use crate::core::poly::circle::{CanonicCoset, CircleEvaluation}; +use crate::core::poly::BitReversedOrder; +use crate::core::utils::bit_reverse_index; +use crate::core::{ColumnVec, InteractionElements, LookupValues}; +use crate::trace_generation::registry::ComponentGenerationRegistry; +use crate::trace_generation::{ComponentGen, ComponentTraceGenerator, BASE_TRACE}; + +#[derive(Clone)] +pub struct RangeCheckComponent { + pub log_size: u32, + pub value: BaseField, +} + +impl RangeCheckComponent { + pub fn new(log_size: u32, value: BaseField) -> Self { + Self { log_size, value } + } + + /// Evaluates the step constraint quotient polynomial on a single point. + /// The step constraint is defined as: + /// mask[0]^2 + mask[1]^2 - mask[2] + fn step_constraint_eval_quotient_by_mask>( + &self, + _point: CirclePoint, + _mask: &[F; 3], + ) -> F { + todo!() + } + + /// Evaluates the boundary constraint quotient polynomial on a single point. + fn boundary_constraint_eval_quotient_by_mask>( + &self, + _point: CirclePoint, + _mask: &[F; 1], + ) -> F { + todo!() + } +} + +impl Component for RangeCheckComponent { + fn n_constraints(&self) -> usize { + 2 + } + + fn max_constraint_log_degree_bound(&self) -> u32 { + // Step constraint is of degree 2. + self.log_size + 1 + } + + fn trace_log_degree_bounds(&self) -> TreeVec> { + TreeVec::new(vec![vec![self.log_size]]) + } + + fn mask_points( + &self, + point: CirclePoint, + ) -> TreeVec>>> { + TreeVec::new(vec![shifted_mask_points( + &vec![vec![0, 1, 2]], + &[CanonicCoset::new(self.log_size)], + point, + )]) + } + + fn evaluate_constraint_quotients_at_point( + &self, + point: CirclePoint, + mask: &TreeVec>>, + evaluation_accumulator: &mut PointEvaluationAccumulator, + _interaction_elements: &InteractionElements, + _lookup_values: &LookupValues, + ) { + evaluation_accumulator.accumulate( + self.step_constraint_eval_quotient_by_mask(point, &mask[0][0][..].try_into().unwrap()), + ); + evaluation_accumulator.accumulate(self.boundary_constraint_eval_quotient_by_mask( + point, + &mask[0][0][..1].try_into().unwrap(), + )); + } +} + +#[derive(Copy, Clone)] +pub struct RangeCheckInput { + pub log_size: u32, + pub value: BaseField, +} + +#[derive(Clone)] +pub struct RangeCheckTraceGenerator { + input: Option, +} + +impl ComponentGen for RangeCheckTraceGenerator {} + +impl RangeCheckTraceGenerator { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { input: None } + } + + pub fn inputs_set(&self) -> bool { + self.input.is_some() + } +} + +impl ComponentTraceGenerator for RangeCheckTraceGenerator { + type Component = RangeCheckComponent; + type Inputs = RangeCheckInput; + + fn add_inputs(&mut self, inputs: &Self::Inputs) { + assert!(!self.inputs_set(), "Fibonacci input already set."); + self.input = Some(*inputs); + } + + fn write_trace( + component_id: &str, + registry: &mut ComponentGenerationRegistry, + ) -> ColumnVec> { + let trace_generator = registry.get_generator_mut::(component_id); + assert!(trace_generator.inputs_set(), "Fibonacci input not set."); + let trace_domain = CanonicCoset::new(trace_generator.input.unwrap().log_size); + let trace = Vec::with_capacity(trace_domain.size()); + + // Fill trace with fibonacci squared. + + // Returns as a CircleEvaluation. + vec![CircleEvaluation::new_canonical_ordered(trace_domain, trace)] + } + + fn write_interaction_trace( + &self, + _trace: &ColumnVec<&CircleEvaluation>, + _elements: &InteractionElements, + ) -> ColumnVec> { + vec![] + } + + fn component(&self) -> Self::Component { + assert!(self.inputs_set(), "Fibonacci input not set."); + RangeCheckComponent::new(self.input.unwrap().log_size, self.input.unwrap().value) + } +} + +impl ComponentProver for RangeCheckComponent { + fn evaluate_constraint_quotients_on_domain( + &self, + trace: &ComponentTrace<'_, CpuBackend>, + evaluation_accumulator: &mut DomainEvaluationAccumulator, + _interaction_elements: &InteractionElements, + _lookup_values: &LookupValues, + ) { + let poly = &trace.polys[BASE_TRACE][0]; + let trace_domain = CanonicCoset::new(self.log_size); + let trace_eval_domain = CanonicCoset::new(self.log_size + 1).circle_domain(); + let trace_eval = poly.evaluate(trace_eval_domain).bit_reverse(); + + // Step constraint. + let constraint_log_degree_bound = trace_domain.log_size() + 1; + let [mut accum] = evaluation_accumulator.columns([(constraint_log_degree_bound, 2)]); + let constraint_eval_domain = trace_eval_domain; + for (off, point_coset) in [ + (0, constraint_eval_domain.half_coset), + ( + constraint_eval_domain.half_coset.size(), + constraint_eval_domain.half_coset.conjugate(), + ), + ] { + let eval = trace_eval.fetch_eval_on_coset(point_coset.shift(trace_domain.index_at(0))); + let mul = trace_domain.step_size().div(point_coset.step_size); + for (i, point) in point_coset.iter().enumerate() { + let mask = [eval[i], eval[i as isize + mul], eval[i as isize + 2 * mul]]; + let mut res = self.boundary_constraint_eval_quotient_by_mask(point, &[mask[0]]) + * accum.random_coeff_powers[0]; + res += self.step_constraint_eval_quotient_by_mask(point, &mask) + * accum.random_coeff_powers[1]; + accum.accumulate(bit_reverse_index(i + off, constraint_log_degree_bound), res); + } + } + } + + fn lookup_values(&self, _trace: &ComponentTrace<'_, CpuBackend>) -> LookupValues { + LookupValues::default() + } +} diff --git a/crates/prover/src/examples/range_check/mod.rs b/crates/prover/src/examples/range_check/mod.rs new file mode 100644 index 000000000..0420559de --- /dev/null +++ b/crates/prover/src/examples/range_check/mod.rs @@ -0,0 +1,67 @@ +use air::RangeCheckAir; +use num_traits::One; + +use self::component::RangeCheckComponent; +use crate::core::backend::cpu::CpuCircleEvaluation; +use crate::core::channel::{Blake2sChannel, Channel}; +use crate::core::fields::m31::BaseField; +use crate::core::fields::{FieldExpOps, IntoSlice}; +use crate::core::poly::circle::{CanonicCoset, CircleEvaluation}; +use crate::core::poly::BitReversedOrder; +use crate::core::prover::{ProvingError, StarkProof, VerificationError}; +use crate::core::vcs::blake2_hash::Blake2sHasher; +use crate::core::vcs::hasher::Hasher; +use crate::trace_generation::{commit_and_prove, commit_and_verify}; + +pub mod air; +mod component; + +#[derive(Clone)] +pub struct RangeCheck { + pub air: RangeCheckAir, +} + +impl RangeCheck { + pub fn new(log_size: u32, value: BaseField) -> Self { + let component = RangeCheckComponent::new(log_size, value); + Self { + air: RangeCheckAir::new(component), + } + } + + pub fn get_trace(&self) -> CpuCircleEvaluation { + // Trace. + let trace_domain = CanonicCoset::new(self.air.component.log_size); + let mut trace = Vec::with_capacity(trace_domain.size()); + + // Fill trace with fibonacci squared. + let mut a = BaseField::one(); + let mut b = BaseField::one(); + for _ in 0..trace_domain.size() { + trace.push(a); + let tmp = a.square() + b.square(); + a = b; + b = tmp; + } + + // Returns as a CircleEvaluation. + CircleEvaluation::new_canonical_ordered(trace_domain, trace) + } + + pub fn prove(&self) -> Result { + let trace = self.get_trace(); + let channel = &mut Blake2sChannel::new(Blake2sHasher::hash(BaseField::into_slice(&[self + .air + .component + .value]))); + commit_and_prove(&self.air, channel, vec![trace]) + } + + pub fn verify(&self, proof: StarkProof) -> Result<(), VerificationError> { + let channel = &mut Blake2sChannel::new(Blake2sHasher::hash(BaseField::into_slice(&[self + .air + .component + .value]))); + commit_and_verify(proof, &self.air, channel) + } +} From 6f368007f43712bcdfb37f898c3fa3756134156f Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Sun, 28 Jul 2024 12:35:55 +0200 Subject: [PATCH 2/8] cleanup --- crates/prover/src/examples/range_check/air.rs | 2 +- .../prover/src/examples/range_check/component.rs | 8 ++++---- crates/prover/src/examples/range_check/mod.rs | 15 +++------------ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/crates/prover/src/examples/range_check/air.rs b/crates/prover/src/examples/range_check/air.rs index 6945c2dea..a710080d6 100644 --- a/crates/prover/src/examples/range_check/air.rs +++ b/crates/prover/src/examples/range_check/air.rs @@ -56,7 +56,7 @@ impl AirTraceGenerator for RangeCheckAirGenerator { let component_generator = self .registry .get_generator::("range_check"); - assert!(component_generator.inputs_set(), "Fibonacci input not set."); + assert!(component_generator.inputs_set(), "range_check input not set."); component_generator .component() .max_constraint_log_degree_bound() diff --git a/crates/prover/src/examples/range_check/component.rs b/crates/prover/src/examples/range_check/component.rs index a34329ada..5ca77d308 100644 --- a/crates/prover/src/examples/range_check/component.rs +++ b/crates/prover/src/examples/range_check/component.rs @@ -120,7 +120,7 @@ impl ComponentTraceGenerator for RangeCheckTraceGenerator { type Inputs = RangeCheckInput; fn add_inputs(&mut self, inputs: &Self::Inputs) { - assert!(!self.inputs_set(), "Fibonacci input already set."); + assert!(!self.inputs_set(), "range_check input already set."); self.input = Some(*inputs); } @@ -129,11 +129,11 @@ impl ComponentTraceGenerator for RangeCheckTraceGenerator { registry: &mut ComponentGenerationRegistry, ) -> ColumnVec> { let trace_generator = registry.get_generator_mut::(component_id); - assert!(trace_generator.inputs_set(), "Fibonacci input not set."); + assert!(trace_generator.inputs_set(), "range_check input not set."); let trace_domain = CanonicCoset::new(trace_generator.input.unwrap().log_size); let trace = Vec::with_capacity(trace_domain.size()); - // Fill trace with fibonacci squared. + // Fill trace with range_check. // Returns as a CircleEvaluation. vec![CircleEvaluation::new_canonical_ordered(trace_domain, trace)] @@ -148,7 +148,7 @@ impl ComponentTraceGenerator for RangeCheckTraceGenerator { } fn component(&self) -> Self::Component { - assert!(self.inputs_set(), "Fibonacci input not set."); + assert!(self.inputs_set(), "range_check input not set."); RangeCheckComponent::new(self.input.unwrap().log_size, self.input.unwrap().value) } } diff --git a/crates/prover/src/examples/range_check/mod.rs b/crates/prover/src/examples/range_check/mod.rs index 0420559de..1e28ac55e 100644 --- a/crates/prover/src/examples/range_check/mod.rs +++ b/crates/prover/src/examples/range_check/mod.rs @@ -1,11 +1,10 @@ use air::RangeCheckAir; -use num_traits::One; use self::component::RangeCheckComponent; use crate::core::backend::cpu::CpuCircleEvaluation; use crate::core::channel::{Blake2sChannel, Channel}; use crate::core::fields::m31::BaseField; -use crate::core::fields::{FieldExpOps, IntoSlice}; +use crate::core::fields::IntoSlice; use crate::core::poly::circle::{CanonicCoset, CircleEvaluation}; use crate::core::poly::BitReversedOrder; use crate::core::prover::{ProvingError, StarkProof, VerificationError}; @@ -32,17 +31,9 @@ impl RangeCheck { pub fn get_trace(&self) -> CpuCircleEvaluation { // Trace. let trace_domain = CanonicCoset::new(self.air.component.log_size); - let mut trace = Vec::with_capacity(trace_domain.size()); + let trace = Vec::with_capacity(trace_domain.size()); - // Fill trace with fibonacci squared. - let mut a = BaseField::one(); - let mut b = BaseField::one(); - for _ in 0..trace_domain.size() { - trace.push(a); - let tmp = a.square() + b.square(); - a = b; - b = tmp; - } + // Fill trace with range_check. // Returns as a CircleEvaluation. CircleEvaluation::new_canonical_ordered(trace_domain, trace) From 23d8696d3273cea0f7ed9a7e27176bc290770858 Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Mon, 29 Jul 2024 09:15:45 +0200 Subject: [PATCH 3/8] range_check example --- crates/prover/src/examples/range_check/air.rs | 5 +- .../src/examples/range_check/component.rs | 94 ++++++++++++++++--- crates/prover/src/examples/range_check/mod.rs | 93 +++++++++++++++++- 3 files changed, 177 insertions(+), 15 deletions(-) diff --git a/crates/prover/src/examples/range_check/air.rs b/crates/prover/src/examples/range_check/air.rs index a710080d6..47f8c6589 100644 --- a/crates/prover/src/examples/range_check/air.rs +++ b/crates/prover/src/examples/range_check/air.rs @@ -56,7 +56,10 @@ impl AirTraceGenerator for RangeCheckAirGenerator { let component_generator = self .registry .get_generator::("range_check"); - assert!(component_generator.inputs_set(), "range_check input not set."); + assert!( + component_generator.inputs_set(), + "range_check input not set." + ); component_generator .component() .max_constraint_log_degree_bound() diff --git a/crates/prover/src/examples/range_check/component.rs b/crates/prover/src/examples/range_check/component.rs index 5ca77d308..902f69964 100644 --- a/crates/prover/src/examples/range_check/component.rs +++ b/crates/prover/src/examples/range_check/component.rs @@ -4,8 +4,9 @@ use crate::core::air::accumulation::{DomainEvaluationAccumulator, PointEvaluatio use crate::core::air::mask::shifted_mask_points; use crate::core::air::{Component, ComponentProver, ComponentTrace}; use crate::core::backend::CpuBackend; -use crate::core::circle::CirclePoint; -use crate::core::fields::m31::BaseField; +use crate::core::circle::{CirclePoint, Coset}; +use crate::core::constraints::point_vanishing; +use crate::core::fields::m31::{BaseField, M31}; use crate::core::fields::qm31::SecureField; use crate::core::fields::ExtensionOf; use crate::core::pcs::TreeVec; @@ -32,19 +33,60 @@ impl RangeCheckComponent { /// mask[0]^2 + mask[1]^2 - mask[2] fn step_constraint_eval_quotient_by_mask>( &self, - _point: CirclePoint, - _mask: &[F; 3], + point: CirclePoint, + mask: &[F; 16], ) -> F { - todo!() + let two = F::from(M31::from(2_u32)); + + let constraint_zero_domain = Coset::subgroup(self.log_size); + let constraint_value = mask[0] + - (mask[1] * two.pow(0) + + mask[2] * two.pow(1) + + mask[3] * two.pow(2) + + mask[4] * two.pow(3) + + mask[5] * two.pow(4) + + mask[6] * two.pow(5) + + mask[7] * two.pow(6) + + mask[8] * two.pow(7) + + mask[9] * two.pow(8) + + mask[10] * two.pow(9) + + mask[11] * two.pow(10) + + mask[12] * two.pow(11) + + mask[13] * two.pow(12) + + mask[14] * two.pow(13) + + mask[15] * two.pow(14)); + let num = constraint_value; + let denom = point_vanishing(constraint_zero_domain.at(0).into_ef(), point); + num / denom } /// Evaluates the boundary constraint quotient polynomial on a single point. fn boundary_constraint_eval_quotient_by_mask>( &self, - _point: CirclePoint, - _mask: &[F; 1], + point: CirclePoint, + mask: &[F; 1], ) -> F { - todo!() + let constraint_zero_domain = Coset::subgroup(self.log_size); + let constraint_value = mask[0].square() - mask[0]; + // let selector = point_vanishing(constraint_zero_domain.at(0).into_ef(), point); + let num = constraint_value; + let denom = point_vanishing(constraint_zero_domain.at(1).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(2).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(3).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(4).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(5).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(6).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(7).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(8).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(9).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(10).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(11).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(12).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(13).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(14).into_ef(), point) + * point_vanishing(constraint_zero_domain.at(15).into_ef(), point); + // let denom = coset_vanishing(constraint_zero_domain, point); + num / denom } } @@ -67,7 +109,7 @@ impl Component for RangeCheckComponent { point: CirclePoint, ) -> TreeVec>>> { TreeVec::new(vec![shifted_mask_points( - &vec![vec![0, 1, 2]], + &vec![vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]], &[CanonicCoset::new(self.log_size)], point, )]) @@ -131,9 +173,20 @@ impl ComponentTraceGenerator for RangeCheckTraceGenerator { let trace_generator = registry.get_generator_mut::(component_id); assert!(trace_generator.inputs_set(), "range_check input not set."); let trace_domain = CanonicCoset::new(trace_generator.input.unwrap().log_size); - let trace = Vec::with_capacity(trace_domain.size()); + let mut trace = Vec::with_capacity(trace_domain.size()); + + if let Some(input) = trace_generator.input { + let mut value_bits = input.value.0; + + // Push the initial value to the trace. + trace.push(input.value); - // Fill trace with range_check. + // Fill trace with range_check. + for _ in 0..15 { + trace.push(M31::from(value_bits & 0x1)); + value_bits >>= 1; + } + } // Returns as a CircleEvaluation. vec![CircleEvaluation::new_canonical_ordered(trace_domain, trace)] @@ -180,7 +233,24 @@ impl ComponentProver for RangeCheckComponent { let eval = trace_eval.fetch_eval_on_coset(point_coset.shift(trace_domain.index_at(0))); let mul = trace_domain.step_size().div(point_coset.step_size); for (i, point) in point_coset.iter().enumerate() { - let mask = [eval[i], eval[i as isize + mul], eval[i as isize + 2 * mul]]; + let mask = [ + eval[i], + eval[i as isize + mul], + eval[i as isize + 2 * mul], + eval[i as isize + 3 * mul], + eval[i as isize + 4 * mul], + eval[i as isize + 5 * mul], + eval[i as isize + 6 * mul], + eval[i as isize + 7 * mul], + eval[i as isize + 8 * mul], + eval[i as isize + 9 * mul], + eval[i as isize + 10 * mul], + eval[i as isize + 11 * mul], + eval[i as isize + 12 * mul], + eval[i as isize + 13 * mul], + eval[i as isize + 14 * mul], + eval[i as isize + 15 * mul], + ]; let mut res = self.boundary_constraint_eval_quotient_by_mask(point, &[mask[0]]) * accum.random_coeff_powers[0]; res += self.step_constraint_eval_quotient_by_mask(point, &mask) diff --git a/crates/prover/src/examples/range_check/mod.rs b/crates/prover/src/examples/range_check/mod.rs index 1e28ac55e..537668803 100644 --- a/crates/prover/src/examples/range_check/mod.rs +++ b/crates/prover/src/examples/range_check/mod.rs @@ -3,7 +3,7 @@ use air::RangeCheckAir; use self::component::RangeCheckComponent; use crate::core::backend::cpu::CpuCircleEvaluation; use crate::core::channel::{Blake2sChannel, Channel}; -use crate::core::fields::m31::BaseField; +use crate::core::fields::m31::{BaseField, M31}; use crate::core::fields::IntoSlice; use crate::core::poly::circle::{CanonicCoset, CircleEvaluation}; use crate::core::poly::BitReversedOrder; @@ -31,9 +31,18 @@ impl RangeCheck { pub fn get_trace(&self) -> CpuCircleEvaluation { // Trace. let trace_domain = CanonicCoset::new(self.air.component.log_size); - let trace = Vec::with_capacity(trace_domain.size()); + let mut trace = Vec::with_capacity(trace_domain.size()); + + let mut value_bits = self.air.component.value.0; + + // Push the initial value to the trace. + trace.push(self.air.component.value); // Fill trace with range_check. + for _ in 0..15 { + trace.push(M31::from(value_bits & 0x1)); + value_bits >>= 1; + } // Returns as a CircleEvaluation. CircleEvaluation::new_canonical_ordered(trace_domain, trace) @@ -56,3 +65,83 @@ impl RangeCheck { commit_and_verify(proof, &self.air, channel) } } + +#[cfg(test)] +mod tests { + use std::iter::zip; + + use itertools::Itertools; + + use super::RangeCheck; + use crate::core::air::accumulation::PointEvaluationAccumulator; + use crate::core::air::{AirExt, AirProverExt, Component, ComponentTrace}; + use crate::core::circle::CirclePoint; + use crate::core::fields::qm31::SecureField; + use crate::core::pcs::TreeVec; + use crate::core::poly::circle::CanonicCoset; + use crate::core::{InteractionElements, LookupValues}; + use crate::trace_generation::BASE_TRACE; + use crate::{m31, qm31}; + + #[test] + fn test_composition_polynomial_is_low_degree() { + let range_check = RangeCheck::new(4, m31!(5)); + let trace = range_check.get_trace(); + println!("{:?}", trace); + let trace_poly = trace.interpolate(); + println!("{:?}", trace_poly); + let trace_eval = + trace_poly.evaluate(CanonicCoset::new(trace_poly.log_size() + 1).circle_domain()); + println!("{:?}", trace_eval); + let trace = ComponentTrace::new( + TreeVec::new(vec![vec![&trace_poly]]), + TreeVec::new(vec![vec![&trace_eval]]), + ); + + let random_coeff = qm31!(2213980, 2213981, 2213982, 2213983); + let component_traces = vec![trace]; + let composition_polynomial_poly = range_check.air.compute_composition_polynomial( + random_coeff, + &component_traces, + &InteractionElements::default(), + &LookupValues::default(), + ); + + // Evaluate this polynomial at another point out of the evaluation domain and compare to + // what we expect. + let point = CirclePoint::::get_point(98989892); + + let points = range_check.air.mask_points(point); + let mask_values = zip(&component_traces[0].polys[BASE_TRACE], &points[0]) + .map(|(poly, points)| { + points + .iter() + .map(|point| poly.eval_at_point(*point)) + .collect_vec() + }) + .collect_vec(); + + let mut evaluation_accumulator = PointEvaluationAccumulator::new(random_coeff); + range_check + .air + .component + .evaluate_constraint_quotients_at_point( + point, + &TreeVec::new(vec![mask_values]), + &mut evaluation_accumulator, + &InteractionElements::default(), + &LookupValues::default(), + ); + let oods_value = evaluation_accumulator.finalize(); + + assert_eq!(oods_value, composition_polynomial_poly.eval_at_point(point)); + } + #[test] + fn test_range_check_prove() { + const RANGE_CHECK_LOG_SIZE: u32 = 4; + let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(20)); + + let proof = range_check.prove().unwrap(); + range_check.verify(proof).unwrap(); + } +} From a43afbf2ee92c0e0007faddaf577d391814fd31d Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Mon, 29 Jul 2024 09:28:48 +0200 Subject: [PATCH 4/8] should panic test --- crates/prover/src/examples/range_check/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/prover/src/examples/range_check/mod.rs b/crates/prover/src/examples/range_check/mod.rs index 537668803..0b1315ef8 100644 --- a/crates/prover/src/examples/range_check/mod.rs +++ b/crates/prover/src/examples/range_check/mod.rs @@ -139,7 +139,17 @@ mod tests { #[test] fn test_range_check_prove() { const RANGE_CHECK_LOG_SIZE: u32 = 4; - let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(20)); + let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(32767)); + + let proof = range_check.prove().unwrap(); + range_check.verify(proof).unwrap(); + } + + #[test] + #[should_panic] + fn test_range_check_prove_overflow() { + const RANGE_CHECK_LOG_SIZE: u32 = 4; + let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(32768)); let proof = range_check.prove().unwrap(); range_check.verify(proof).unwrap(); From 4547d2c52cb6988d4ae9fa6910207a81b40868a4 Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Mon, 29 Jul 2024 13:45:25 +0200 Subject: [PATCH 5/8] code quality improvements --- .../src/examples/range_check/component.rs | 66 +++++-------------- 1 file changed, 15 insertions(+), 51 deletions(-) diff --git a/crates/prover/src/examples/range_check/component.rs b/crates/prover/src/examples/range_check/component.rs index 902f69964..7455c9a20 100644 --- a/crates/prover/src/examples/range_check/component.rs +++ b/crates/prover/src/examples/range_check/component.rs @@ -40,21 +40,11 @@ impl RangeCheckComponent { let constraint_zero_domain = Coset::subgroup(self.log_size); let constraint_value = mask[0] - - (mask[1] * two.pow(0) - + mask[2] * two.pow(1) - + mask[3] * two.pow(2) - + mask[4] * two.pow(3) - + mask[5] * two.pow(4) - + mask[6] * two.pow(5) - + mask[7] * two.pow(6) - + mask[8] * two.pow(7) - + mask[9] * two.pow(8) - + mask[10] * two.pow(9) - + mask[11] * two.pow(10) - + mask[12] * two.pow(11) - + mask[13] * two.pow(12) - + mask[14] * two.pow(13) - + mask[15] * two.pow(14)); + - mask[1..] + .iter() + .enumerate() + .map(|(i, &val)| val * two.pow(i as u128)) + .sum::(); let num = constraint_value; let denom = point_vanishing(constraint_zero_domain.at(0).into_ef(), point); num / denom @@ -68,24 +58,10 @@ impl RangeCheckComponent { ) -> F { let constraint_zero_domain = Coset::subgroup(self.log_size); let constraint_value = mask[0].square() - mask[0]; - // let selector = point_vanishing(constraint_zero_domain.at(0).into_ef(), point); let num = constraint_value; - let denom = point_vanishing(constraint_zero_domain.at(1).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(2).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(3).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(4).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(5).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(6).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(7).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(8).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(9).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(10).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(11).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(12).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(13).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(14).into_ef(), point) - * point_vanishing(constraint_zero_domain.at(15).into_ef(), point); - // let denom = coset_vanishing(constraint_zero_domain, point); + let denom = (1..16) + .map(|i| point_vanishing(constraint_zero_domain.at(i), point)) + .product::(); num / denom } } @@ -109,7 +85,7 @@ impl Component for RangeCheckComponent { point: CirclePoint, ) -> TreeVec>>> { TreeVec::new(vec![shifted_mask_points( - &vec![vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]], + &vec![(0..16).collect::>()], &[CanonicCoset::new(self.log_size)], point, )]) @@ -233,24 +209,12 @@ impl ComponentProver for RangeCheckComponent { let eval = trace_eval.fetch_eval_on_coset(point_coset.shift(trace_domain.index_at(0))); let mul = trace_domain.step_size().div(point_coset.step_size); for (i, point) in point_coset.iter().enumerate() { - let mask = [ - eval[i], - eval[i as isize + mul], - eval[i as isize + 2 * mul], - eval[i as isize + 3 * mul], - eval[i as isize + 4 * mul], - eval[i as isize + 5 * mul], - eval[i as isize + 6 * mul], - eval[i as isize + 7 * mul], - eval[i as isize + 8 * mul], - eval[i as isize + 9 * mul], - eval[i as isize + 10 * mul], - eval[i as isize + 11 * mul], - eval[i as isize + 12 * mul], - eval[i as isize + 13 * mul], - eval[i as isize + 14 * mul], - eval[i as isize + 15 * mul], - ]; + let mask: [M31; 16] = (0..16) + .map(|j| eval[i as isize + j * mul]) + .collect::>() + .try_into() + .unwrap(); + let mut res = self.boundary_constraint_eval_quotient_by_mask(point, &[mask[0]]) * accum.random_coeff_powers[0]; res += self.step_constraint_eval_quotient_by_mask(point, &mask) From 2d2d3657210ea7731eede1bd1274090dbda39f42 Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Mon, 29 Jul 2024 14:05:57 +0200 Subject: [PATCH 6/8] comments --- .../src/examples/range_check/component.rs | 15 ++-- crates/prover/src/examples/range_check/mod.rs | 74 +------------------ 2 files changed, 13 insertions(+), 76 deletions(-) diff --git a/crates/prover/src/examples/range_check/component.rs b/crates/prover/src/examples/range_check/component.rs index 7455c9a20..0fb54a2ea 100644 --- a/crates/prover/src/examples/range_check/component.rs +++ b/crates/prover/src/examples/range_check/component.rs @@ -36,9 +36,10 @@ impl RangeCheckComponent { point: CirclePoint, mask: &[F; 16], ) -> F { - let two = F::from(M31::from(2_u32)); - + let two = F::one().double(); let constraint_zero_domain = Coset::subgroup(self.log_size); + // Check if value at mask[0] equals value represented by 15 next bits little endian. + // If value can be represented with 15 bits, it means that it is in range of 0..2^15 let constraint_value = mask[0] - mask[1..] .iter() @@ -46,6 +47,7 @@ impl RangeCheckComponent { .map(|(i, &val)| val * two.pow(i as u128)) .sum::(); let num = constraint_value; + // Apply this step constrain on first row let denom = point_vanishing(constraint_zero_domain.at(0).into_ef(), point); num / denom } @@ -57,8 +59,10 @@ impl RangeCheckComponent { mask: &[F; 1], ) -> F { let constraint_zero_domain = Coset::subgroup(self.log_size); + // Check if mask value is a binary 0 | 1 let constraint_value = mask[0].square() - mask[0]; let num = constraint_value; + // Apply this boundary constrain on 1..16 trace rows let denom = (1..16) .map(|i| point_vanishing(constraint_zero_domain.at(i), point)) .product::(); @@ -152,12 +156,11 @@ impl ComponentTraceGenerator for RangeCheckTraceGenerator { let mut trace = Vec::with_capacity(trace_domain.size()); if let Some(input) = trace_generator.input { - let mut value_bits = input.value.0; - - // Push the initial value to the trace. + // Push the value to the trace. trace.push(input.value); - // Fill trace with range_check. + // Fill trace with binary representation of value. + let mut value_bits = input.value.0; for _ in 0..15 { trace.push(M31::from(value_bits & 0x1)); value_bits >>= 1; diff --git a/crates/prover/src/examples/range_check/mod.rs b/crates/prover/src/examples/range_check/mod.rs index 0b1315ef8..007db5232 100644 --- a/crates/prover/src/examples/range_check/mod.rs +++ b/crates/prover/src/examples/range_check/mod.rs @@ -33,12 +33,11 @@ impl RangeCheck { let trace_domain = CanonicCoset::new(self.air.component.log_size); let mut trace = Vec::with_capacity(trace_domain.size()); - let mut value_bits = self.air.component.value.0; - - // Push the initial value to the trace. + // Push the value to the trace. trace.push(self.air.component.value); - // Fill trace with range_check. + // Fill trace with binary representation of value. + let mut value_bits = self.air.component.value.0; for _ in 0..15 { trace.push(M31::from(value_bits & 0x1)); value_bits >>= 1; @@ -68,74 +67,9 @@ impl RangeCheck { #[cfg(test)] mod tests { - use std::iter::zip; - - use itertools::Itertools; - use super::RangeCheck; - use crate::core::air::accumulation::PointEvaluationAccumulator; - use crate::core::air::{AirExt, AirProverExt, Component, ComponentTrace}; - use crate::core::circle::CirclePoint; - use crate::core::fields::qm31::SecureField; - use crate::core::pcs::TreeVec; - use crate::core::poly::circle::CanonicCoset; - use crate::core::{InteractionElements, LookupValues}; - use crate::trace_generation::BASE_TRACE; - use crate::{m31, qm31}; - - #[test] - fn test_composition_polynomial_is_low_degree() { - let range_check = RangeCheck::new(4, m31!(5)); - let trace = range_check.get_trace(); - println!("{:?}", trace); - let trace_poly = trace.interpolate(); - println!("{:?}", trace_poly); - let trace_eval = - trace_poly.evaluate(CanonicCoset::new(trace_poly.log_size() + 1).circle_domain()); - println!("{:?}", trace_eval); - let trace = ComponentTrace::new( - TreeVec::new(vec![vec![&trace_poly]]), - TreeVec::new(vec![vec![&trace_eval]]), - ); + use crate::m31; - let random_coeff = qm31!(2213980, 2213981, 2213982, 2213983); - let component_traces = vec![trace]; - let composition_polynomial_poly = range_check.air.compute_composition_polynomial( - random_coeff, - &component_traces, - &InteractionElements::default(), - &LookupValues::default(), - ); - - // Evaluate this polynomial at another point out of the evaluation domain and compare to - // what we expect. - let point = CirclePoint::::get_point(98989892); - - let points = range_check.air.mask_points(point); - let mask_values = zip(&component_traces[0].polys[BASE_TRACE], &points[0]) - .map(|(poly, points)| { - points - .iter() - .map(|point| poly.eval_at_point(*point)) - .collect_vec() - }) - .collect_vec(); - - let mut evaluation_accumulator = PointEvaluationAccumulator::new(random_coeff); - range_check - .air - .component - .evaluate_constraint_quotients_at_point( - point, - &TreeVec::new(vec![mask_values]), - &mut evaluation_accumulator, - &InteractionElements::default(), - &LookupValues::default(), - ); - let oods_value = evaluation_accumulator.finalize(); - - assert_eq!(oods_value, composition_polynomial_poly.eval_at_point(point)); - } #[test] fn test_range_check_prove() { const RANGE_CHECK_LOG_SIZE: u32 = 4; From cead8eb7c7440826b553ab6bf75278e13bfefde6 Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Mon, 29 Jul 2024 14:11:41 +0200 Subject: [PATCH 7/8] proptests --- Cargo.lock | 148 ++++++++++++++++++ crates/prover/Cargo.toml | 1 + .../examples/range_check/mod.txt | 7 + crates/prover/src/examples/range_check/mod.rs | 35 +++-- 4 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 crates/prover/proptest-regressions/examples/range_check/mod.txt diff --git a/Cargo.lock b/Cargo.lock index 92ae452f9..ebd4efefc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,6 +135,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "blake2" version = "0.10.6" @@ -450,6 +471,28 @@ dependencies = [ "log", ] +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "generic-array" version = "0.14.7" @@ -560,6 +603,18 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "log" version = "0.4.21" @@ -617,6 +672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -692,6 +748,32 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.3", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.36" @@ -707,6 +789,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core", ] @@ -726,6 +809,18 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] [[package]] name = "rayon" @@ -810,6 +905,31 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.17" @@ -963,6 +1083,7 @@ dependencies = [ "hex", "itertools 0.12.1", "num-traits", + "proptest", "rand", "rayon", "serde", @@ -1002,6 +1123,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + [[package]] name = "test-log" version = "0.2.15" @@ -1131,6 +1264,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1149,6 +1288,15 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "walkdir" version = "2.5.0" diff --git a/crates/prover/Cargo.toml b/crates/prover/Cargo.toml index 381e912ea..abf486357 100644 --- a/crates/prover/Cargo.toml +++ b/crates/prover/Cargo.toml @@ -27,6 +27,7 @@ rayon = { version = "1.10.0", optional = true } serde = { version = "1.0", features = ["derive"] } [dev-dependencies] +proptest = "1.0" aligned = "0.4.2" test-log = { version = "0.2.15", features = ["trace"] } tracing-subscriber = "0.3.18" diff --git a/crates/prover/proptest-regressions/examples/range_check/mod.txt b/crates/prover/proptest-regressions/examples/range_check/mod.txt new file mode 100644 index 000000000..629150366 --- /dev/null +++ b/crates/prover/proptest-regressions/examples/range_check/mod.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc e1bb1f72c891764d16309d8fc8cfd7a23f6d31324a661979c6c684a2cc29724c # shrinks to invalid_value = 32768 diff --git a/crates/prover/src/examples/range_check/mod.rs b/crates/prover/src/examples/range_check/mod.rs index 007db5232..e5fd405c3 100644 --- a/crates/prover/src/examples/range_check/mod.rs +++ b/crates/prover/src/examples/range_check/mod.rs @@ -67,25 +67,32 @@ impl RangeCheck { #[cfg(test)] mod tests { + use proptest::prelude::*; + use super::RangeCheck; use crate::m31; - #[test] - fn test_range_check_prove() { - const RANGE_CHECK_LOG_SIZE: u32 = 4; - let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(32767)); + const RANGE_CHECK_LOG_SIZE: u32 = 4; - let proof = range_check.prove().unwrap(); - range_check.verify(proof).unwrap(); - } + proptest! { + #![proptest_config(ProptestConfig { + cases: 50, // Number of test cases to generate + .. ProptestConfig::default() + })] - #[test] - #[should_panic] - fn test_range_check_prove_overflow() { - const RANGE_CHECK_LOG_SIZE: u32 = 4; - let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(32768)); + #[test] + fn test_range_check_prove(valid_value in 0..32768_u32) { + let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(valid_value)); + let proof = range_check.prove().unwrap(); + range_check.verify(proof).unwrap(); + } - let proof = range_check.prove().unwrap(); - range_check.verify(proof).unwrap(); + #[test] + #[should_panic] + fn test_range_check_prove_overflow(invalid_value in 32768..u32::MAX) { + let range_check = RangeCheck::new(RANGE_CHECK_LOG_SIZE, m31!(invalid_value)); + let proof = range_check.prove().unwrap(); + range_check.verify(proof).unwrap(); + } } } From fe509dcf2239409824c92ef32c3092d5526211c3 Mon Sep 17 00:00:00 2001 From: Bartosz Nowak Date: Mon, 29 Jul 2024 14:16:43 +0200 Subject: [PATCH 8/8] comments --- crates/prover/src/examples/range_check/component.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/prover/src/examples/range_check/component.rs b/crates/prover/src/examples/range_check/component.rs index 0fb54a2ea..342d5f0ec 100644 --- a/crates/prover/src/examples/range_check/component.rs +++ b/crates/prover/src/examples/range_check/component.rs @@ -29,8 +29,6 @@ impl RangeCheckComponent { } /// Evaluates the step constraint quotient polynomial on a single point. - /// The step constraint is defined as: - /// mask[0]^2 + mask[1]^2 - mask[2] fn step_constraint_eval_quotient_by_mask>( &self, point: CirclePoint,