From b51e6fdadf81534939f9951d8fdfbf1bffd1624f Mon Sep 17 00:00:00 2001 From: Andrew Milson Date: Sat, 12 Oct 2024 14:22:23 -0400 Subject: [PATCH] Refactor Coset with CirclePointIndex --- stwo_cairo_verifier/src/circle.cairo | 239 +++++++++++----------- stwo_cairo_verifier/src/fields/qm31.cairo | 3 + stwo_cairo_verifier/src/fri.cairo | 51 +++-- stwo_cairo_verifier/src/poly/circle.cairo | 39 ++-- stwo_cairo_verifier/src/poly/line.cairo | 17 +- 5 files changed, 166 insertions(+), 183 deletions(-) diff --git a/stwo_cairo_verifier/src/circle.cairo b/stwo_cairo_verifier/src/circle.cairo index 7040da72..47a01421 100644 --- a/stwo_cairo_verifier/src/circle.cairo +++ b/stwo_cairo_verifier/src/circle.cairo @@ -1,14 +1,24 @@ use core::num::traits::one::One; use core::num::traits::zero::Zero; -use core::num::traits::{WrappingAdd, WideMul}; +use core::num::traits::{WrappingAdd, WrappingSub, WrappingMul}; use stwo_cairo_verifier::fields::cm31::CM31; use stwo_cairo_verifier::fields::m31::{M31, M31Impl}; use stwo_cairo_verifier::fields::qm31::{QM31Impl, QM31, QM31Trait}; use super::utils::pow; +/// A generator for the circle group over [`M31`]. pub const M31_CIRCLE_GEN: CirclePoint = CirclePoint { x: M31 { inner: 2 }, y: M31 { inner: 1268011823 }, }; +pub const M31_CIRCLE_LOG_ORDER: u32 = 31; + +/// Equals `2^31`. +pub const M31_CIRCLE_ORDER: u32 = 2147483648; + +/// Equals `2^31 - 1`. +pub const M31_CIRCLE_ORDER_BIT_MASK: u32 = 0x7fffffff; + +/// A generator for the circle group over [`QM31`]. pub const QM31_CIRCLE_GEN: CirclePoint = CirclePoint { x: QM31 { @@ -21,16 +31,8 @@ pub const QM31_CIRCLE_GEN: CirclePoint = }, }; -pub const CIRCLE_LOG_ORDER: u32 = 31; - -// `CIRCLE_ORDER` equals 2^31 -pub const CIRCLE_ORDER: u32 = 2147483648; - -// `CIRCLE_ORDER_BIT_MASK` equals 2^31 - 1 -pub const CIRCLE_ORDER_BIT_MASK: u32 = 0x7fffffff; - -// `U32_BIT_MASK` equals 2^32 - 1 -pub const U32_BIT_MASK: u64 = 0xffffffff; +/// Order of [`QM31_CIRCLE_GEN`]. +pub const QM31_CIRCLE_ORDER: u128 = 21267647892944572736998860269687930880; /// A point on the complex circle. Treated as an additive group. #[derive(Drop, Copy, Debug, PartialEq)] @@ -71,18 +73,20 @@ pub trait CirclePointTrait< } fn mul( - self: @CirclePoint, ref scalar: u128 + self: @CirclePoint, scalar: u128 ) -> CirclePoint< F > { + // TODO: `mut scalar: u128` doesn't work in trait. + let mut scalar = scalar; let mut result = Self::zero(); let mut cur = *self; - while scalar > 0 { + while scalar != 0 { if scalar & 1 == 1 { result = result + cur; } cur = cur + cur; - scalar = scalar / 2; + scalar /= 2; }; result } @@ -109,44 +113,34 @@ pub impl ComplexConjugateImpl of ComplexConjugateTrait { /// Represents the coset `initial + `. #[derive(Copy, Clone, Debug, PartialEq, Drop)] pub struct Coset { - // This is an index in the range [0, 2^31) - pub initial_index: usize, - pub step_size: usize, + pub initial_index: CirclePointIndex, + pub step_size: CirclePointIndex, pub log_size: u32, } #[generate_trait] pub impl CosetImpl of CosetTrait { - fn new(initial_index: usize, log_size: u32) -> Coset { - assert!(initial_index < CIRCLE_ORDER); - let step_size = pow(2, CIRCLE_LOG_ORDER - log_size); + fn new(initial_index: CirclePointIndex, log_size: u32) -> Coset { + let step_size = CirclePointIndexImpl::subgroup_gen(log_size); Coset { initial_index, step_size, log_size } } - fn index_at(self: @Coset, index: usize) -> usize { - let index_times_step = ((*self.step_size).wide_mul(index) & U32_BIT_MASK) - .try_into() - .unwrap(); - let result = (*self.initial_index).wrapping_add(index_times_step); - result & CIRCLE_ORDER_BIT_MASK + fn index_at(self: @Coset, index: usize) -> CirclePointIndex { + *self.initial_index + self.step_size.mul(index) } fn double(self: @Coset) -> Coset { assert!(*self.log_size > 0); - let double_initial_index = *self.initial_index * 2; - let double_step_size = *self.step_size * 2; - let new_log_size = *self.log_size - 1; - Coset { - initial_index: double_initial_index & CIRCLE_ORDER_BIT_MASK, - step_size: double_step_size & CIRCLE_ORDER_BIT_MASK, - log_size: new_log_size + initial_index: *self.initial_index + *self.initial_index, + step_size: *self.step_size + *self.step_size, + log_size: *self.log_size - 1 } } + #[inline] fn at(self: @Coset, index: usize) -> CirclePoint { - let mut scalar = self.index_at(index).into(); - M31_CIRCLE_GEN.mul(ref scalar) + self.index_at(index).to_point() } /// Returns the size of the coset. @@ -158,35 +152,95 @@ pub impl CosetImpl of CosetTrait { /// /// For example, for `n=8`, we get the point indices `[1,3,5,7,9,11,13,15]`. fn odds(log_size: u32) -> Coset { - let subgroup_generator_index = Self::subgroup_generator_index(log_size); - Self::new(subgroup_generator_index, log_size) + Self::new(CirclePointIndexImpl::subgroup_gen(log_size + 1), log_size) } /// Creates a coset of the form `G_4n + `. - /// + /// /// For example, for `n=8`, we get the point indices `[1,5,9,13,17,21,25,29]`. /// Its conjugate will be `[3,7,11,15,19,23,27,31]`. fn half_odds(log_size: u32) -> Coset { - Self::new(Self::subgroup_generator_index(log_size + 2), log_size) + Self::new(CirclePointIndexImpl::subgroup_gen(log_size + 2), log_size) + } +} + +/// Integer `i` that represent the circle point `i * M31_CIRCLE_GEN`. +/// +/// Treated as an additive ring modulo `1 << M31_CIRCLE_LOG_ORDER`. +#[derive(Copy, Debug, Drop)] +pub struct CirclePointIndex { + /// The index, stored as an unreduced `u32` for performance reasons. + index: u32, +} + +#[generate_trait] +pub impl CirclePointIndexImpl of CirclePointIndexTrait { + fn new(index: u32) -> CirclePointIndex { + CirclePointIndex { index } + } + + fn zero() -> CirclePointIndex { + CirclePointIndex { index: 0 } + } + + fn generator() -> CirclePointIndex { + CirclePointIndex { index: 1 } + } + + fn reduce(self: @CirclePointIndex) -> CirclePointIndex { + CirclePointIndex { index: *self.index & M31_CIRCLE_ORDER_BIT_MASK } + } + + fn subgroup_gen(log_size: u32) -> CirclePointIndex { + assert!(log_size <= M31_CIRCLE_LOG_ORDER); + CirclePointIndex { index: pow(2, M31_CIRCLE_LOG_ORDER - log_size) } + } + + // TODO(andrew): When associated types are supported, support the Mul. + fn mul(self: @CirclePointIndex, scalar: u32) -> CirclePointIndex { + CirclePointIndex { index: (*self.index).wrapping_mul(scalar) } + } + + fn index(self: @CirclePointIndex) -> u32 { + self.reduce().index + } + + fn to_point(self: @CirclePointIndex) -> CirclePoint { + // No need to call `reduce()`. + M31_CIRCLE_GEN.mul((*self.index).into()) + } +} + +impl CirclePointIndexAdd of Add { + #[inline] + fn add(lhs: CirclePointIndex, rhs: CirclePointIndex) -> CirclePointIndex { + CirclePointIndex { index: lhs.index.wrapping_add(rhs.index) } } +} - fn subgroup_generator_index(log_size: u32) -> u32 { - assert!(log_size <= CIRCLE_LOG_ORDER); - pow(2, CIRCLE_LOG_ORDER - log_size) +impl CirclePointIndexNeg of Neg { + #[inline] + fn neg(a: CirclePointIndex) -> CirclePointIndex { + CirclePointIndex { index: M31_CIRCLE_ORDER.wrapping_sub(a.index) } } } +impl CirclePointIndexPartialEx of PartialEq { + fn eq(lhs: @CirclePointIndex, rhs: @CirclePointIndex) -> bool { + lhs.index() == rhs.index() + } + + fn ne(lhs: @CirclePointIndex, rhs: @CirclePointIndex) -> bool { + lhs.index() != rhs.index() + } +} #[cfg(test)] mod tests { - use core::array::ArrayTrait; - use core::option::OptionTrait; - use core::traits::TryInto; use stwo_cairo_verifier::fields::m31::m31; - use stwo_cairo_verifier::fields::qm31::QM31One; + use stwo_cairo_verifier::fields::qm31::{QM31One, qm31}; use stwo_cairo_verifier::utils::pow; - use super::{CirclePointQM31Impl, QM31_CIRCLE_GEN}; - use super::{M31_CIRCLE_GEN, CIRCLE_ORDER, CirclePoint, CirclePointM31Impl, Coset, CosetImpl}; + use super::{M31_CIRCLE_GEN, CirclePointQM31Impl, QM31_CIRCLE_GEN, M31_CIRCLE_ORDER, CirclePoint, CirclePointM31Impl, CirclePointIndexImpl, Coset, CosetImpl, QM31_CIRCLE_ORDER}; #[test] fn test_add_1() { @@ -224,8 +278,7 @@ mod tests { #[test] fn test_mul_1() { let point_1 = CirclePoint { x: m31(750649172), y: m31(1991648574) }; - let mut scalar = 5; - let result = point_1.mul(ref scalar); + let result = point_1.mul(5); assert_eq!(result, point_1 + point_1 + point_1 + point_1 + point_1); } @@ -233,8 +286,7 @@ mod tests { #[test] fn test_mul_2() { let point_1 = CirclePoint { x: m31(750649172), y: m31(1991648574) }; - let mut scalar = 8; - let result = point_1.mul(ref scalar); + let result = point_1.mul(8); assert_eq!( result, point_1 + point_1 + point_1 + point_1 + point_1 + point_1 + point_1 + point_1 @@ -244,17 +296,15 @@ mod tests { #[test] fn test_mul_3() { let point_1 = CirclePoint { x: m31(750649172), y: m31(1991648574) }; - let mut scalar = 418776494; - let result = point_1.mul(ref scalar); + let result = point_1.mul(418776494); assert_eq!(result, CirclePoint { x: m31(1987283985), y: m31(1500510905) }); } #[test] fn test_generator_order() { - let half_order = CIRCLE_ORDER / 2; - let mut scalar = half_order.into(); - let mut result = M31_CIRCLE_GEN.mul(ref scalar); + let half_order = M31_CIRCLE_ORDER / 2; + let mut result = M31_CIRCLE_GEN.mul(half_order.into()); // Assert `M31_CIRCLE_GEN^{2^30}` equals `-1`. assert_eq!(result, CirclePoint { x: -m31(1), y: m31(0) }); @@ -262,38 +312,37 @@ mod tests { #[test] fn test_generator() { - let mut scalar = pow(2, 30).try_into().unwrap(); - let mut result = M31_CIRCLE_GEN.mul(ref scalar); + let mut result = M31_CIRCLE_GEN.mul(pow(2, 30).into()); assert_eq!(result, CirclePoint { x: -m31(1), y: m31(0) }); } #[test] fn test_coset_index_at() { - let coset = Coset { initial_index: 16777216, log_size: 5, step_size: 67108864 }; + let coset = Coset { initial_index: CirclePointIndexImpl::new(16777216), log_size: 5, step_size: CirclePointIndexImpl::new(67108864) }; let result = coset.index_at(8); - assert_eq!(result, 553648128); + assert_eq!(result, CirclePointIndexImpl::new(553648128)); } #[test] fn test_coset_constructor() { - let result = CosetImpl::new(16777216, 5); + let result = CosetImpl::new(CirclePointIndexImpl::new(16777216), 5); - assert_eq!(result, Coset { initial_index: 16777216, log_size: 5, step_size: 67108864 }); + assert_eq!(result, Coset { initial_index: CirclePointIndexImpl::new(16777216), log_size: 5, step_size: CirclePointIndexImpl::new(67108864) }); } #[test] fn test_coset_double() { - let coset = Coset { initial_index: 16777216, step_size: 67108864, log_size: 5 }; + let coset = Coset { initial_index: CirclePointIndexImpl::new(16777216), step_size: CirclePointIndexImpl::new(67108864), log_size: 5 }; let result = coset.double(); - assert_eq!(result, Coset { initial_index: 33554432, step_size: 134217728, log_size: 4 }); + assert_eq!(result, Coset { initial_index: CirclePointIndexImpl::new(33554432), step_size: CirclePointIndexImpl::new(134217728), log_size: 4 }); } #[test] fn test_coset_at() { - let coset = Coset { initial_index: 16777216, step_size: 67108864, log_size: 5 }; + let coset = Coset { initial_index: CirclePointIndexImpl::new(16777216), step_size: CirclePointIndexImpl::new(67108864), log_size: 5 }; let result = coset.at(17); assert_eq!(result, CirclePoint { x: m31(7144319), y: m31(1742797653) }); @@ -301,7 +350,7 @@ mod tests { #[test] fn test_coset_size() { - let coset = Coset { initial_index: 16777216, step_size: 67108864, log_size: 5 }; + let coset = Coset { initial_index: CirclePointIndexImpl::new(16777216), step_size: CirclePointIndexImpl::new(67108864), log_size: 5 }; let result = coset.size(); assert_eq!(result, 32); @@ -309,61 +358,7 @@ mod tests { #[test] fn test_qm31_circle_gen() { - let P4: u128 = 21267647892944572736998860269687930881; - - let first_prime = 2; - let last_prime = 368140581013; - let prime_factors: Array<(u128, u32)> = array![ - (first_prime, 33), - (3, 2), - (5, 1), - (7, 1), - (11, 1), - (31, 1), - (151, 1), - (331, 1), - (733, 1), - (1709, 1), - (last_prime, 1), - ]; - - let product = iter_product(first_prime, @prime_factors, last_prime); - - assert_eq!(product, P4 - 1); - - assert_eq!( - QM31_CIRCLE_GEN.x * QM31_CIRCLE_GEN.x + QM31_CIRCLE_GEN.y * QM31_CIRCLE_GEN.y, - QM31One::one() - ); - - let mut scalar = P4 - 1; - assert_eq!(QM31_CIRCLE_GEN.mul(ref scalar), CirclePointQM31Impl::zero()); - - let mut i = 0; - while i < prime_factors.len() { - let (p, _) = *prime_factors.at(i); - let mut scalar = (P4 - 1) / p.into(); - assert_ne!(QM31_CIRCLE_GEN.mul(ref scalar), CirclePointQM31Impl::zero()); - - i = i + 1; - } - } - - fn iter_product( - first_prime: u128, prime_factors: @Array<(u128, u32)>, last_prime: u128 - ) -> u128 { - let mut accum_product: u128 = 1; - accum_product = accum_product - * pow(first_prime.try_into().unwrap(), 31).into() - * 4; // * 2^33 - let mut i = 1; - while i < prime_factors.len() - 1 { - let (prime, exponent): (u128, u32) = *prime_factors.at(i); - accum_product = accum_product * pow(prime.try_into().unwrap(), exponent).into(); - i = i + 1; - }; - accum_product = accum_product * last_prime; - accum_product + assert_eq!(QM31_CIRCLE_GEN.mul(QM31_CIRCLE_ORDER / 2), CirclePoint { x: -qm31(1, 0, 0, 0), y: qm31(0, 0, 0, 0) }); } } diff --git a/stwo_cairo_verifier/src/fields/qm31.cairo b/stwo_cairo_verifier/src/fields/qm31.cairo index f34dd3ba..a7533769 100644 --- a/stwo_cairo_verifier/src/fields/qm31.cairo +++ b/stwo_cairo_verifier/src/fields/qm31.cairo @@ -3,6 +3,9 @@ use core::num::traits::zero::Zero; use super::cm31::{CM31, cm31, CM31Trait}; use super::m31::{M31, M31Impl}; +/// Equals `(2^31 - 1)^4`. +pub const P4: u128 = 21267647892944572736998860269687930881; + pub const R: CM31 = CM31 { a: M31 { inner: 2 }, b: M31 { inner: 1 } }; #[derive(Copy, Drop, Debug, PartialEq)] diff --git a/stwo_cairo_verifier/src/fri.cairo b/stwo_cairo_verifier/src/fri.cairo index d2ee8b0c..b6eff33b 100644 --- a/stwo_cairo_verifier/src/fri.cairo +++ b/stwo_cairo_verifier/src/fri.cairo @@ -241,12 +241,7 @@ pub impl FriVerifierImpl of FriVerifierTrait { let mut inner_layers = array![]; let mut layer_bound = *max_column_bound - CIRCLE_TO_LINE_FOLD_STEP; - let mut layer_domain = LineDomain { - coset: CosetImpl::new( - pow(2, 31 - layer_bound - config.log_blowup_factor - 2), - layer_bound + config.log_blowup_factor - ) - }; + let mut layer_domain = LineDomainImpl::new(CosetImpl::half_odds(layer_bound + config.log_blowup_factor)); let mut layer_index = 0; let mut invalid_fri_layers_number = false; @@ -532,7 +527,7 @@ pub fn ibutterfly(v0: QM31, v1: QM31, itwid: M31) -> (QM31, QM31) { #[cfg(test)] mod test { use stwo_cairo_verifier::channel::ChannelTrait; - use stwo_cairo_verifier::circle::{Coset, CosetImpl}; + use stwo_cairo_verifier::circle::{Coset, CosetImpl, CirclePointIndexImpl}; use stwo_cairo_verifier::fields::qm31::qm31; use stwo_cairo_verifier::poly::circle::{ CircleDomain, CircleEvaluationImpl, SparseCircleEvaluation, SparseCircleEvaluationImpl @@ -548,7 +543,7 @@ mod test { #[test] fn test_fold_line_1() { - let domain = LineDomainImpl::new(CosetImpl::new(67108864, 1)); + let domain = LineDomainImpl::new(CosetImpl::new(CirclePointIndexImpl::new(67108864), 1)); let values = array![ qm31(440443058, 1252794525, 1129773609, 1309365757), qm31(974589897, 1592795796, 649052897, 863407657) @@ -565,7 +560,7 @@ mod test { #[test] fn test_fold_line_2() { - let domain = LineDomainImpl::new(CosetImpl::new(553648128, 1)); + let domain = LineDomainImpl::new(CosetImpl::new(CirclePointIndexImpl::new(553648128), 1)); let values = array![ qm31(730692421, 1363821003, 2146256633, 106012305), qm31(1387266930, 149259209, 1148988082, 1930518101) @@ -582,7 +577,7 @@ mod test { #[test] fn test_fold_circle_into_line_1() { - let domain = CircleDomain { half_coset: CosetImpl::new(553648128, 0) }; + let domain = CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(553648128), 0) }; let values = array![qm31(807167738, 0, 0, 0), qm31(1359821401, 0, 0, 0)]; let sparse_circle_evaluation: SparseCircleEvaluation = SparseCircleEvaluation { subcircle_evals: array![CircleEvaluationImpl::new(domain, values)] @@ -856,7 +851,7 @@ mod test { let queries = Queries { positions: array![5], log_domain_size: 4 }; let domain = CircleDomain { - half_coset: Coset { initial_index: 603979776, step_size: 2147483648, log_size: 0 } + half_coset: Coset { initial_index: CirclePointIndexImpl::new(603979776), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }; let decommitted_values = array![ SparseCircleEvaluation { @@ -902,7 +897,7 @@ mod test { let queries = Queries { positions: array![5], log_domain_size: 4 }; let domain = CircleDomain { - half_coset: Coset { initial_index: 603979776, step_size: 2147483648, log_size: 0 } + half_coset: Coset { initial_index: CirclePointIndexImpl::new(603979776), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }; let decommitted_values = array![ SparseCircleEvaluation { @@ -981,7 +976,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 545259520, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(545259520), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(1464849549, 0, 0, 0), qm31(35402781, 0, 0, 0),], @@ -1073,7 +1068,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1619001344, step_size: 2147483648, log_size: 0 + initial_index: CirclePointIndexImpl::new(1619001344), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }, array![qm31(83295654, 0, 0, 0), qm31(666640840, 0, 0, 0)] @@ -1081,7 +1076,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1652555776, step_size: 2147483648, log_size: 0 + initial_index: CirclePointIndexImpl::new(1652555776), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }, array![qm31(1598588979, 0, 0, 0), qm31(1615371031, 0, 0, 0)] @@ -1093,7 +1088,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1090519040, step_size: 2147483648, log_size: 0 + initial_index: CirclePointIndexImpl::new(1090519040), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }, array![qm31(985597997, 0, 0, 0), qm31(139496415, 0, 0, 0)] @@ -1101,7 +1096,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1157627904, step_size: 2147483648, log_size: 0 + initial_index: CirclePointIndexImpl::new(1157627904), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }, array![qm31(1718103579, 0, 0, 0), qm31(1537119660, 0, 0, 0)] @@ -1113,7 +1108,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 33554432, step_size: 2147483648, log_size: 0 + initial_index: CirclePointIndexImpl::new(33554432), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }, array![qm31(1645691043, 0, 0, 0), qm31(2009531552, 0, 0, 0)] @@ -1121,7 +1116,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 167772160, step_size: 2147483648, log_size: 0 + initial_index: CirclePointIndexImpl::new(167772160), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0 } }, array![qm31(354887788, 0, 0, 0), qm31(934393698, 0, 0, 0)] @@ -1217,7 +1212,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 209715200, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(209715200), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(1784241578, 0, 0, 0), qm31(714402375, 0, 0, 0),], @@ -1225,7 +1220,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 578813952, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(578813952), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(673384396, 0, 0, 0), qm31(475618425, 0, 0, 0),], @@ -1233,7 +1228,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 981467136, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(981467136), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(315059915, 0, 0, 0), qm31(558088919, 0, 0, 0),], @@ -1245,7 +1240,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 419430400, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(419430400), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(142767236, 0, 0, 0), qm31(537984732, 0, 0, 0),], @@ -1253,7 +1248,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1157627904, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(1157627904), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(1718103579, 0, 0, 0), qm31(1537119660, 0, 0, 0),], @@ -1261,7 +1256,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1962934272, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(1962934272), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(2124636505, 0, 0, 0), qm31(1506525049, 0, 0, 0),], @@ -1273,7 +1268,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 838860800, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(838860800), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(1014591066, 0, 0, 0), qm31(1931899148, 0, 0, 0),], @@ -1281,7 +1276,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 167772160, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(167772160), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(354887788, 0, 0, 0), qm31(934393698, 0, 0, 0),], @@ -1289,7 +1284,7 @@ mod test { CircleEvaluationImpl::new( CircleDomain { half_coset: Coset { - initial_index: 1778384896, step_size: 2147483648, log_size: 0, + initial_index: CirclePointIndexImpl::new(1778384896), step_size: CirclePointIndexImpl::new(2147483648), log_size: 0, }, }, array![qm31(509977960, 0, 0, 0), qm31(1887908506, 0, 0, 0),], diff --git a/stwo_cairo_verifier/src/poly/circle.cairo b/stwo_cairo_verifier/src/poly/circle.cairo index 65e63d9f..407148e6 100644 --- a/stwo_cairo_verifier/src/poly/circle.cairo +++ b/stwo_cairo_verifier/src/poly/circle.cairo @@ -1,7 +1,5 @@ -use core::num::traits::ops::wrapping::WrappingSub; -use stwo_cairo_verifier::circle::CirclePointTrait; use stwo_cairo_verifier::circle::{ - Coset, CosetImpl, CirclePoint, CirclePointM31Impl, M31_CIRCLE_GEN, CIRCLE_ORDER + Coset, CosetImpl, CirclePoint, CirclePointM31Impl, CirclePointIndex, CirclePointIndexImpl }; use stwo_cairo_verifier::fields::m31::M31; use stwo_cairo_verifier::fields::qm31::QM31; @@ -26,32 +24,29 @@ pub impl CircleDomainImpl of CircleDomainTrait { } /// Returns the size of the domain. + #[inline] fn size(self: @CircleDomain) -> usize { pow(2, self.log_size()) } /// Returns the log size of the domain. + #[inline] fn log_size(self: @CircleDomain) -> usize { *self.half_coset.log_size + 1 } - /// Returns the circle point index of the `i`th domain element. - fn index_at(self: @CircleDomain, index: usize) -> usize { + /// Returns the [`CirclePointIndex`] of the `i`th domain element. + fn index_at(self: @CircleDomain, index: usize) -> CirclePointIndex { if index < self.half_coset.size() { self.half_coset.index_at(index) } else { - CIRCLE_ORDER.wrapping_sub(self.half_coset.index_at(index - self.half_coset.size())) + -self.half_coset.index_at(index - self.half_coset.size()) } } - /// Returns the `i` th domain element. + #[inline] fn at(self: @CircleDomain, index: usize) -> CirclePoint { - let mut scalar = self.index_at(index).into(); - M31_CIRCLE_GEN.mul(ref scalar) - } - - fn new_with_log_size(log_size: u32) -> CircleDomain { - CircleDomain { half_coset: CosetImpl::half_odds(log_size - 1) } + self.index_at(index).to_point() } } @@ -124,7 +119,7 @@ pub impl SparseCircleEvaluationImpl of SparseCircleEvaluationImplTrait { #[cfg(test)] mod tests { - use stwo_cairo_verifier::circle::{Coset, CosetImpl, CirclePoint}; + use stwo_cairo_verifier::circle::{Coset, CosetImpl, CirclePoint, CirclePointIndexImpl}; use stwo_cairo_verifier::fields::m31::m31; use stwo_cairo_verifier::fields::qm31::qm31; use super::{ @@ -134,7 +129,7 @@ mod tests { #[test] fn test_circle_domain_at_1() { - let half_coset = Coset { initial_index: 16777216, step_size: 67108864, log_size: 5 }; + let half_coset = Coset { initial_index: CirclePointIndexImpl::new(16777216), step_size: CirclePointIndexImpl::new(67108864), log_size: 5 }; let domain = CircleDomain { half_coset }; let index = 17; let result = domain.at(index); @@ -144,7 +139,7 @@ mod tests { #[test] fn test_circle_domain_at_2() { - let half_coset = Coset { initial_index: 16777216, step_size: 67108864, log_size: 5 }; + let half_coset = Coset { initial_index: CirclePointIndexImpl::new(16777216), step_size: CirclePointIndexImpl::new(67108864), log_size: 5 }; let domain = CircleDomain { half_coset }; let index = 37; let result = domain.at(index); @@ -158,15 +153,15 @@ mod tests { let lhs = SparseCircleEvaluation { subcircle_evals: array![ CircleEvaluationImpl::new( - CircleDomain { half_coset: CosetImpl::new(16777216, 0) }, + CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(16777216), 0) }, array![qm31(28672, 0, 0, 0), qm31(36864, 0, 0, 0)] ), CircleEvaluationImpl::new( - CircleDomain { half_coset: CosetImpl::new(2030043136, 0) }, + CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(2030043136), 0) }, array![qm31(28672, 0, 0, 0), qm31(36864, 0, 0, 0)] ), CircleEvaluationImpl::new( - CircleDomain { half_coset: CosetImpl::new(2097152000, 0) }, + CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(2097152000), 0) }, array![qm31(2147454975, 0, 0, 0), qm31(2147446783, 0, 0, 0)] ), ] @@ -179,21 +174,21 @@ mod tests { SparseCircleEvaluation { subcircle_evals: array![ CircleEvaluationImpl::new( - CircleDomain { half_coset: CosetImpl::new(16777216, 0) }, + CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(16777216), 0) }, array![ qm31(667173716, 1020487722, 1791736788, 1346152946), qm31(1471361534, 84922130, 1076528072, 810417939) ] ), CircleEvaluationImpl::new( - CircleDomain { half_coset: CosetImpl::new(2030043136, 0) }, + CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(2030043136), 0) }, array![ qm31(667173716, 1020487722, 1791736788, 1346152946), qm31(1471361534, 84922130, 1076528072, 810417939) ] ), CircleEvaluationImpl::new( - CircleDomain { half_coset: CosetImpl::new(2097152000, 0) }, + CircleDomain { half_coset: CosetImpl::new(CirclePointIndexImpl::new(2097152000), 0) }, array![ qm31(1480309931, 1126995925, 355746859, 801330701), qm31(676122113, 2062561517, 1070955575, 1337065708) diff --git a/stwo_cairo_verifier/src/poly/line.cairo b/stwo_cairo_verifier/src/poly/line.cairo index 7f55d511..7ea626ab 100644 --- a/stwo_cairo_verifier/src/poly/line.cairo +++ b/stwo_cairo_verifier/src/poly/line.cairo @@ -1,4 +1,4 @@ -use stwo_cairo_verifier::circle::{Coset, CosetImpl, CirclePointTrait, M31_CIRCLE_GEN}; +use stwo_cairo_verifier::circle::{Coset, CosetImpl, CirclePointIndexImpl, CirclePointTrait}; use stwo_cairo_verifier::fields::SecureField; use stwo_cairo_verifier::fields::m31::{M31, m31}; use stwo_cairo_verifier::fields::qm31::{QM31, QM31Zero}; @@ -64,10 +64,8 @@ pub impl LineDomainImpl of LineDomainTrait { // Let our coset be `E = c + ` with `|E| > 2` then: // 1. if `ord(c) <= ord(G)` the coset contains two points at x=0 // 2. if `ord(c) = 2 * ord(G)` then `c` and `-c` are in our coset - let mut scalar = coset.step_size.into(); - let coset_step = M31_CIRCLE_GEN.mul(ref scalar); assert!( - coset.at(0).log_order() >= coset_step.log_order() + 2, + coset.initial_index.to_point().log_order() >= coset.log_size + 2, "coset x-coordinates not unique" ); } @@ -134,19 +132,16 @@ pub impl SparseLineEvaluationImpl of SparseLineEvaluationTrait { #[cfg(test)] mod tests { - use stwo_cairo_verifier::circle::{CosetImpl, CIRCLE_LOG_ORDER}; + use stwo_cairo_verifier::circle::{CosetImpl, CirclePointIndexImpl}; use stwo_cairo_verifier::fields::m31::m31; use stwo_cairo_verifier::fields::qm31::qm31; - use stwo_cairo_verifier::utils::pow; use super::{LinePoly, LinePolyTrait, LineDomainImpl}; #[test] #[should_panic] fn bad_line_domain() { // This coset doesn't have points with unique x-coordinates. - let LOG_SIZE = 2; - let initial_index = pow(2, CIRCLE_LOG_ORDER - (LOG_SIZE + 1)); - let coset = CosetImpl::new(initial_index, LOG_SIZE); + let coset = CosetImpl::odds(2); LineDomainImpl::new(coset); } @@ -154,7 +149,7 @@ mod tests { #[test] fn line_domain_of_size_two_works() { let LOG_SIZE: u32 = 1; - let coset = CosetImpl::new(0, LOG_SIZE); + let coset = CosetImpl::new(CirclePointIndexImpl::new(0), LOG_SIZE); LineDomainImpl::new(coset); } @@ -162,7 +157,7 @@ mod tests { #[test] fn line_domain_of_size_one_works() { let LOG_SIZE: u32 = 0; - let coset = CosetImpl::new(0, LOG_SIZE); + let coset = CosetImpl::new(CirclePointIndexImpl::new(0), LOG_SIZE); LineDomainImpl::new(coset); }