From c4c4eae6e07d631d5009c61f4b4dd3f1e34e6ee0 Mon Sep 17 00:00:00 2001 From: Andrew Milson Date: Sun, 17 Nov 2024 17:03:24 -0500 Subject: [PATCH] Remove pow function --- stwo_cairo_verifier/src/circle.cairo | 6 +- stwo_cairo_verifier/src/fri.cairo | 4 +- stwo_cairo_verifier/src/pcs/quotients.cairo | 5 +- stwo_cairo_verifier/src/poly/circle.cairo | 4 +- stwo_cairo_verifier/src/poly/line.cairo | 6 +- stwo_cairo_verifier/src/queries.cairo | 14 +-- stwo_cairo_verifier/src/utils.cairo | 107 ++++++++------------ 7 files changed, 62 insertions(+), 84 deletions(-) diff --git a/stwo_cairo_verifier/src/circle.cairo b/stwo_cairo_verifier/src/circle.cairo index 2abb4d0f..507c6f6d 100644 --- a/stwo_cairo_verifier/src/circle.cairo +++ b/stwo_cairo_verifier/src/circle.cairo @@ -11,7 +11,7 @@ use stwo_cairo_verifier::fields::Invertible; use stwo_cairo_verifier::fields::cm31::CM31; use stwo_cairo_verifier::fields::m31::{M31, M31Impl}; use stwo_cairo_verifier::fields::qm31::{QM31, QM31Impl, QM31One, QM31Trait}; -use super::utils::pow; +use super::utils::pow2; /// A generator for the circle group over [`M31`]. pub const M31_CIRCLE_GEN: CirclePoint = CirclePoint { @@ -168,7 +168,7 @@ pub impl CosetImpl of CosetTrait { /// Returns the size of the coset. fn size(self: @Coset) -> usize { - pow(2, *self.log_size) + pow2(*self.log_size) } /// Creates a coset of the form `G_2n + `. @@ -216,7 +216,7 @@ pub impl CirclePointIndexImpl of CirclePointIndexTrait { fn subgroup_gen(log_size: u32) -> CirclePointIndex { assert!(log_size <= M31_CIRCLE_LOG_ORDER); - CirclePointIndex { index: pow(2, M31_CIRCLE_LOG_ORDER - log_size) } + CirclePointIndex { index: pow2(M31_CIRCLE_LOG_ORDER - log_size) } } // TODO(andrew): When associated types are supported, support the Mul. diff --git a/stwo_cairo_verifier/src/fri.cairo b/stwo_cairo_verifier/src/fri.cairo index abf1746b..12362d29 100644 --- a/stwo_cairo_verifier/src/fri.cairo +++ b/stwo_cairo_verifier/src/fri.cairo @@ -13,7 +13,7 @@ use stwo_cairo_verifier::poly::line::{ use stwo_cairo_verifier::poly::line::{LinePoly, LinePolyImpl}; use stwo_cairo_verifier::queries::SparseSubCircleDomain; use stwo_cairo_verifier::queries::{Queries, QueriesImpl}; -use stwo_cairo_verifier::utils::{ArrayImpl, OptionImpl, SpanExTrait, bit_reverse_index, find, pow}; +use stwo_cairo_verifier::utils::{ArrayImpl, OptionImpl, SpanExTrait, bit_reverse_index, find, pow2}; use stwo_cairo_verifier::vcs::hasher::PoseidonMerkleHasher; use stwo_cairo_verifier::vcs::verifier::{MerkleDecommitment, MerkleVerifier, MerkleVerifierTrait}; @@ -270,7 +270,7 @@ pub impl FriVerifierImpl of FriVerifierTrait { return Result::Err(FriVerificationError::InvalidNumFriLayers); } - if proof.last_layer_poly.len() != pow(2, config.log_last_layer_degree_bound) { + if proof.last_layer_poly.len() != pow2(config.log_last_layer_degree_bound) { return Result::Err(FriVerificationError::LastLayerDegreeInvalid); } diff --git a/stwo_cairo_verifier/src/pcs/quotients.cairo b/stwo_cairo_verifier/src/pcs/quotients.cairo index 0f548bee..55bbea65 100644 --- a/stwo_cairo_verifier/src/pcs/quotients.cairo +++ b/stwo_cairo_verifier/src/pcs/quotients.cairo @@ -507,7 +507,7 @@ mod tests { }; use stwo_cairo_verifier::queries::SubCircleDomainImpl; use stwo_cairo_verifier::queries::{SparseSubCircleDomain, SubCircleDomain}; - use stwo_cairo_verifier::utils::{DictImpl, pow}; + use stwo_cairo_verifier::utils::{DictImpl, pow2}; use super::{ ColumnSampleBatch, ColumnSampleBatchImpl, ComplexConjugateLineCoeffsImpl, PointSample, QuotientConstantsImpl, accumulate_row_quotients, fri_answers, fri_answers_for_log_size, @@ -777,7 +777,6 @@ mod tests { let n_columns = 1000; let log_fold_step = CIRCLE_TO_LINE_FOLD_STEP; let random_coeff = qm31(9, 8, 7, 6); - assert!(n_queries < pow(2, log_size), "Query indices need to be unique"); assert!(n_columns >= 3, "First three columns are manually created"); let mut query_subdomains = array![]; for coset_index in 0..n_queries { @@ -797,7 +796,7 @@ mod tests { let col2_samples = array![sample0, sample2]; let mut samples_per_column = array![@col0_samples, @col1_samples, @col2_samples]; let mut col_query_values = array![]; - for i in 0..n_queries * pow(2, log_fold_step) { + for i in 0..n_queries * pow2(log_fold_step) { col_query_values.append(m31(i)); }; let col0_query_values = col_query_values.clone(); diff --git a/stwo_cairo_verifier/src/poly/circle.cairo b/stwo_cairo_verifier/src/poly/circle.cairo index 344d1621..f11366ae 100644 --- a/stwo_cairo_verifier/src/poly/circle.cairo +++ b/stwo_cairo_verifier/src/poly/circle.cairo @@ -6,7 +6,7 @@ use stwo_cairo_verifier::fields::BatchInvertible; use stwo_cairo_verifier::fields::m31::M31; use stwo_cairo_verifier::fields::qm31::QM31; use stwo_cairo_verifier::poly::utils::ibutterfly; -use stwo_cairo_verifier::utils::pow; +use stwo_cairo_verifier::utils::pow2; /// A valid domain for circle polynomial interpolation and evaluation. /// @@ -28,7 +28,7 @@ pub impl CircleDomainImpl of CircleDomainTrait { /// Returns the size of the domain. #[inline] fn size(self: @CircleDomain) -> usize { - pow(2, self.log_size()) + pow2(self.log_size()) } /// Returns the log size of the domain. diff --git a/stwo_cairo_verifier/src/poly/line.cairo b/stwo_cairo_verifier/src/poly/line.cairo index 23d3ef7a..c005261a 100644 --- a/stwo_cairo_verifier/src/poly/line.cairo +++ b/stwo_cairo_verifier/src/poly/line.cairo @@ -7,7 +7,7 @@ use stwo_cairo_verifier::fields::m31::{M31, m31}; use stwo_cairo_verifier::fields::qm31::{QM31, QM31Impl, QM31Zero}; use stwo_cairo_verifier::fields::{BaseField, SecureField}; use stwo_cairo_verifier::poly::utils::{butterfly, fold, ibutterfly}; -use stwo_cairo_verifier::utils::pow; +use stwo_cairo_verifier::utils::pow2; /// A univariate polynomial defined on a [LineDomain]. #[derive(Debug, Drop, Clone)] @@ -55,7 +55,7 @@ pub impl LinePolyImpl of LinePolyTrait { let log_domain_size = domain.log_size(); let log_degree_bound = *self.log_size; let n_skipped_layers = log_domain_size - log_degree_bound; - let duplicity = pow(2, n_skipped_layers); + let duplicity = pow2(n_skipped_layers); let coeffs = repeat_value(self.coeffs.span(), duplicity); LineEvaluationImpl::new(domain, line_fft(coeffs, domain, n_skipped_layers)) @@ -164,7 +164,7 @@ pub impl LinePolySerde of Serde { }; // Check the sizes match. - if res.coeffs.len() != pow(2, res.log_size) { + if res.coeffs.len() != pow2(res.log_size) { return Option::None; } diff --git a/stwo_cairo_verifier/src/queries.cairo b/stwo_cairo_verifier/src/queries.cairo index 03547fa3..27dcc531 100644 --- a/stwo_cairo_verifier/src/queries.cairo +++ b/stwo_cairo_verifier/src/queries.cairo @@ -1,7 +1,7 @@ use stwo_cairo_verifier::channel::{Channel, ChannelTrait}; use stwo_cairo_verifier::circle::CosetImpl; use stwo_cairo_verifier::poly::circle::{CircleDomain, CircleDomainImpl}; -use super::utils::{ArrayImpl, bit_reverse_index, find, pow}; +use super::utils::{ArrayImpl, bit_reverse_index, find, pow2}; /// An ordered set of query indices over a bit reversed [CircleDomain]. @@ -16,7 +16,7 @@ pub impl QueriesImpl of QueriesImplTrait { /// Randomizes a set of query indices uniformly over the range [0, 2^`log_query_size`). fn generate(ref channel: Channel, log_domain_size: u32, n_queries: usize) -> Queries { let mut unsorted_positions = array![]; - let max_query = pow(2, log_domain_size) - 1; + let max_query = pow2(log_domain_size) - 1; let mut finished = false; loop { let random_bytes = channel.draw_random_bytes(); @@ -51,7 +51,7 @@ pub impl QueriesImpl of QueriesImplTrait { fn fold(self: @Queries, n_folds: u32) -> Queries { assert!(n_folds <= *self.log_domain_size); assert!(self.positions.len() > 0); - let folding_factor = pow(2, n_folds); + let folding_factor = pow2(n_folds); let mut new_last_position = *self.positions[0] / folding_factor; let mut new_positions = array![new_last_position]; let mut i = 1; @@ -68,7 +68,7 @@ pub impl QueriesImpl of QueriesImplTrait { fn opening_positions(self: @Queries, fri_step_size: u32) -> SparseSubCircleDomain { assert!(fri_step_size > 0); - let fold_factor = pow(2, fri_step_size); + let fold_factor = pow2(fri_step_size); let mut domains = array![]; let snap_positions = self.positions; let mut already_added = array![]; @@ -103,7 +103,7 @@ pub struct SubCircleDomain { pub impl SubCircleDomainImpl of SubCircleDomainTrait { /// Calculates the decommitment positions needed for each query given the fri step size. fn to_decommitment_positions(self: @SubCircleDomain) -> Array { - let sub_circle_size = pow(2, *self.log_size); + let sub_circle_size = pow2(*self.log_size); let start = *self.coset_index * sub_circle_size; let end = start + sub_circle_size; let mut res = array![]; @@ -115,7 +115,7 @@ pub impl SubCircleDomainImpl of SubCircleDomainTrait { /// Returns the represented [CircleDomain]. fn to_circle_domain(self: @SubCircleDomain, query_domain: CircleDomain) -> CircleDomain { - let index = *self.coset_index * pow(2, *self.log_size); + let index = *self.coset_index * pow2(*self.log_size); let query = bit_reverse_index(index, query_domain.log_size()); let initial_index = query_domain.index_at(query); let half_coset = CosetImpl::new(initial_index, *self.log_size - 1); @@ -123,7 +123,7 @@ pub impl SubCircleDomainImpl of SubCircleDomainTrait { } fn size(self: @SubCircleDomain) -> usize { - pow(2, *self.log_size).into() + pow2(*self.log_size).into() } } diff --git a/stwo_cairo_verifier/src/utils.cairo b/stwo_cairo_verifier/src/utils.cairo index 85c7c10a..55f6bd96 100644 --- a/stwo_cairo_verifier/src/utils.cairo +++ b/stwo_cairo_verifier/src/utils.cairo @@ -8,7 +8,48 @@ use core::num::traits::BitSize; use core::traits::DivRem; use core::traits::PanicDestruct; use stwo_cairo_verifier::BaseField; -use stwo_cairo_verifier::fields::qm31::{QM31, qm31}; + +/// Look up table where index `i` stores value `2^i`. +const POW_2: [u32; 32] = [ + 0b1, + 0b10, + 0b100, + 0b1000, + 0b10000, + 0b100000, + 0b1000000, + 0b10000000, + 0b100000000, + 0b1000000000, + 0b10000000000, + 0b100000000000, + 0b1000000000000, + 0b10000000000000, + 0b100000000000000, + 0b1000000000000000, + 0b10000000000000000, + 0b100000000000000000, + 0b1000000000000000000, + 0b10000000000000000000, + 0b100000000000000000000, + 0b1000000000000000000000, + 0b10000000000000000000000, + 0b100000000000000000000000, + 0b1000000000000000000000000, + 0b10000000000000000000000000, + 0b100000000000000000000000000, + 0b1000000000000000000000000000, + 0b10000000000000000000000000000, + 0b100000000000000000000000000000, + 0b1000000000000000000000000000000, + 0b10000000000000000000000000000000, +]; + +/// Returns `2^n`. +#[inline(always)] +pub fn pow2(n: u32) -> u32 { + *POW_2.span()[n] +} #[generate_trait] pub impl DictImpl, +PanicDestruct> of DictTrait { @@ -153,22 +194,6 @@ pub fn pack4(cur: felt252, values: [BaseField; 4]) -> felt252 { + x3.into() } -pub fn pow(base: u32, mut exponent: u32) -> u32 { - let mut result = 1; - let mut base_power = base; - loop { - if exponent & 1 == 1 { - result *= base_power; - } - exponent = exponent / 2; - if exponent == 0 { - break; - } - base_power = base_power * base_power; - }; - result -} - pub fn bit_reverse_index(mut index: usize, mut bits: u32) -> usize { assert!(bits <= BitSize::::bits()); @@ -197,34 +222,9 @@ pub fn find(n: u32, a: Span) -> bool { res } -pub fn pow_qm31(base: QM31, mut exponent: u32) -> QM31 { - let mut result = qm31(1, 0, 0, 0); - let mut base_power = base; - loop { - if exponent & 1 == 1 { - result = result * base_power; - } - exponent = exponent / 2; - if exponent == 0 { - break; - } - base_power = base_power * base_power; - }; - result -} - #[cfg(test)] mod tests { - use super::{ArrayImpl, bit_reverse_index, pow, pow_qm31, qm31}; - - #[test] - fn test_pow() { - assert_eq!(25, pow(5, 2)); - assert_eq!(16, pow(2, 4)); - assert_eq!(1024, pow(2, 10)); - assert_eq!(4096, pow(2, 12)); - assert_eq!(1048576, pow(2, 20)); - } + use super::{ArrayImpl, bit_reverse_index}; #[test] fn test_bit_reverse() { @@ -251,27 +251,6 @@ mod tests { assert_eq!(16448250, bit_reverse_index(800042880, 31)); } - #[test] - fn test_pow_qm31_1() { - let result = pow_qm31(qm31(1, 2, 3, 4), 0); - let expected_result = qm31(1, 0, 0, 0); - assert_eq!(expected_result, result) - } - - #[test] - fn test_pow_qm31_2() { - let result = pow_qm31(qm31(1, 2, 3, 4), 1); - let expected_result = qm31(1, 2, 3, 4); - assert_eq!(expected_result, result) - } - - #[test] - fn test_pow_qm31_3() { - let result = pow_qm31(qm31(1, 2, 3, 4), 37); - let expected_result = qm31(1394542587, 260510989, 997191897, 2127074080); - assert_eq!(expected_result, result) - } - #[test] fn test_sort_ascending() { assert_eq!(array![6_usize, 5, 1, 4, 2, 3].sort_ascending(), array![1, 2, 3, 4, 5, 6]);