diff --git a/stwo_cairo_verifier/Scarb.lock b/stwo_cairo_verifier/Scarb.lock index e776b9b5..0c9db427 100644 --- a/stwo_cairo_verifier/Scarb.lock +++ b/stwo_cairo_verifier/Scarb.lock @@ -1,22 +1,6 @@ # Code generated by scarb DO NOT EDIT. version = 1 -[[package]] -name = "snforge_scarb_plugin" -version = "0.32.0" -source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.32.0#3817c903b640201c72e743b9bbe70a97149828a2" - -[[package]] -name = "snforge_std" -version = "0.32.0" -source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.32.0#3817c903b640201c72e743b9bbe70a97149828a2" -dependencies = [ - "snforge_scarb_plugin", -] - [[package]] name = "stwo_cairo_verifier" version = "0.1.0" -dependencies = [ - "snforge_std", -] diff --git a/stwo_cairo_verifier/Scarb.toml b/stwo_cairo_verifier/Scarb.toml index ef5531f8..63179256 100644 --- a/stwo_cairo_verifier/Scarb.toml +++ b/stwo_cairo_verifier/Scarb.toml @@ -12,11 +12,11 @@ sort-module-level-items = true [dependencies] [dev-dependencies] -# cairo_test = "2.8.0" -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.32.0" } -# TODO(andrew): Remove once get scarb >=2.8.3 working. -assert_macros = "2.8.0" +cairo_test = "2.8.0" +# snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.32.0" } +# # TODO(andrew): Remove once get scarb >=2.8.3 working. +# assert_macros = "2.8.0" -[scripts] -test = "snforge test --max-n-steps 100000000" +# [scripts] +# test = "snforge test --max-n-steps 100000000" diff --git a/stwo_cairo_verifier/src/circle.cairo b/stwo_cairo_verifier/src/circle.cairo index 146f30ca..3847db09 100644 --- a/stwo_cairo_verifier/src/circle.cairo +++ b/stwo_cairo_verifier/src/circle.cairo @@ -2,6 +2,11 @@ use core::num::traits::one::One; use core::num::traits::zero::Zero; use core::num::traits::{WrappingAdd, WrappingSub, WrappingMul}; use stwo_cairo_verifier::channel::{Channel, ChannelImpl}; +use stwo_cairo_verifier::circle_mul_table::{ + M31_CIRCLE_GEN_MUL_TABLE_BITS_24_TO_29, M31_CIRCLE_GEN_MUL_TABLE_BITS_18_TO_23, + M31_CIRCLE_GEN_MUL_TABLE_BITS_12_TO_17, M31_CIRCLE_GEN_MUL_TABLE_BITS_6_TO_11, + M31_CIRCLE_GEN_MUL_TABLE_BITS_0_TO_5 +}; use stwo_cairo_verifier::fields::cm31::CM31; use stwo_cairo_verifier::fields::m31::{M31, M31Impl}; use stwo_cairo_verifier::fields::qm31::{QM31Impl, QM31One, QM31, QM31Trait}; @@ -42,9 +47,7 @@ pub struct CirclePoint { pub y: F } -pub trait CirclePointTrait< - F, +Add, +Sub, +Mul, +Drop, +Copy, +Zero, +One, +PartialEq -> { +pub trait CirclePointTrait, +Sub, +Mul, +Drop, +Copy, +Zero, +One> { // Returns the neutral element of the circle. fn zero() -> CirclePoint { CirclePoint { x: One::one(), y: Zero::zero() } @@ -55,42 +58,6 @@ pub trait CirclePointTrait< let sqx = x * x; sqx + sqx - One::one() } - - /// Returns the log order of a point. - /// - /// All points have an order of the form `2^k`. - fn log_order( - self: @CirclePoint - ) -> u32 { - // we only need the x-coordinate to check order since the only point - // with x=1 is the circle's identity - let mut res = 0; - let mut cur = self.x.clone(); - while cur != One::one() { - cur = Self::double_x(cur); - res += 1; - }; - res - } - - fn mul( - 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 { - if scalar & 1 == 1 { - result = result + cur; - } - cur = cur + cur; - scalar /= 2; - }; - result - } } impl CirclePointAdd, +Sub, +Mul, +Drop, +Copy> of Add> { @@ -241,9 +208,43 @@ pub impl CirclePointIndexImpl of CirclePointIndexTrait { self.reduce().index } + // Context: After running the initial verifier this function accounted for 50% of the steps. + // Most of the calls are made during the FRI folding. With these changes this function accounts + // for ~4% of total steps. fn to_point(self: @CirclePointIndex) -> CirclePoint { + const NZ_2_POW_24: NonZero = 0b1000000000000000000000000; + const NZ_2_POW_18: NonZero = 0b1000000000000000000; + const NZ_2_POW_12: NonZero = 0b1000000000000; + const NZ_2_POW_6: NonZero = 0b1000000; + // No need to call `reduce()`. - M31_CIRCLE_GEN.mul((*self.index).into()) + // Start with MSBs since small domains (more common) have LSBs equal 0. + let (bits_24_to_31, bits_0_to_23) = DivRem::div_rem(*self.index, NZ_2_POW_24); + let (bits_30_to_31, bits_24_to_29) = DivRem::div_rem(bits_24_to_31, NZ_2_POW_6); + let mut res = *M31_CIRCLE_GEN_MUL_TABLE_BITS_24_TO_29.span()[bits_24_to_29]; + if bits_0_to_23 != 0 { + let (bits_18_to_23, bits_0_to_17) = DivRem::div_rem(bits_0_to_23, NZ_2_POW_18); + res = res + *M31_CIRCLE_GEN_MUL_TABLE_BITS_18_TO_23.span()[bits_18_to_23]; + if bits_0_to_17 != 0 { + let (bits_12_to_17, bits_0_to_11) = DivRem::div_rem(bits_0_to_17, NZ_2_POW_12); + res = res + *M31_CIRCLE_GEN_MUL_TABLE_BITS_12_TO_17.span()[bits_12_to_17]; + if bits_0_to_11 != 0 { + let (bits_6_to_11, bits_0_to_5) = DivRem::div_rem(bits_0_to_11, NZ_2_POW_6); + res = res + *M31_CIRCLE_GEN_MUL_TABLE_BITS_6_TO_11.span()[bits_6_to_11]; + if bits_0_to_5 != 0 { + res = res + *M31_CIRCLE_GEN_MUL_TABLE_BITS_0_TO_5.span()[bits_0_to_5]; + } + } + } + } + + // Note this applies the appropriate transformation based on the two highest bits. + // The highest bit has no effect. The 30th bit indicates weather to take the antipode. + if bits_30_to_31 == 0b11 || bits_30_to_31 == 0b01 { + res = CirclePoint { x: -res.x, y: -res.y }; + } + + res } } @@ -274,13 +275,30 @@ impl CirclePointIndexPartialEx of PartialEq { #[cfg(test)] mod tests { use stwo_cairo_verifier::fields::m31::m31; - use stwo_cairo_verifier::fields::qm31::{QM31One, qm31}; - use stwo_cairo_verifier::utils::pow; + use stwo_cairo_verifier::fields::qm31::QM31One; use super::{ - M31_CIRCLE_GEN, CirclePointQM31Impl, QM31_CIRCLE_GEN, M31_CIRCLE_ORDER, CirclePoint, - CirclePointM31Impl, CirclePointIndexImpl, Coset, CosetImpl, QM31_CIRCLE_ORDER + M31_CIRCLE_GEN, CirclePointQM31Impl, CirclePoint, CirclePointM31Impl, CirclePointIndex, + CirclePointIndexImpl, Coset, CosetImpl }; + + #[test] + fn test_to_point() { + let index = CirclePointIndex { index: 0b01111111111111111111111111111111 }; + assert_eq!(index.to_point(), -M31_CIRCLE_GEN); + let index = CirclePointIndex { index: 0b00111111111111111111111111111111 }; + assert_eq!(index.to_point(), CirclePoint { x: -M31_CIRCLE_GEN.x, y: M31_CIRCLE_GEN.y }); + } + + + #[test] + fn test_to_point_with_unreduced_index() { + // All 32 bits are `1`. + let index = CirclePointIndex { index: 0b11111111111111111111111111111111 }; + + assert_eq!(index.to_point(), -M31_CIRCLE_GEN); + } + #[test] fn test_add_1() { let g4 = CirclePoint { x: m31(0), y: m31(1) }; @@ -314,52 +332,6 @@ mod tests { assert_eq!(result, point_1.clone()); } - #[test] - fn test_mul_1() { - let point_1 = CirclePoint { x: m31(750649172), y: m31(1991648574) }; - - let result = point_1.mul(5); - - assert_eq!(result, point_1 + point_1 + point_1 + point_1 + point_1); - } - - #[test] - fn test_mul_2() { - let point_1 = CirclePoint { x: m31(750649172), y: m31(1991648574) }; - - 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 - ); - } - - #[test] - fn test_mul_3() { - let point_1 = CirclePoint { x: m31(750649172), y: m31(1991648574) }; - - let result = point_1.mul(418776494); - - assert_eq!(result, CirclePoint { x: m31(1987283985), y: m31(1500510905) }); - } - - #[test] - fn test_generator_order() { - 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) }); - } - - #[test] - fn test_generator() { - 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 { @@ -432,13 +404,5 @@ mod tests { assert_eq!(result, 32); } - - #[test] - fn test_qm31_circle_gen() { - 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/circle_mul_table.cairo b/stwo_cairo_verifier/src/circle_mul_table.cairo new file mode 100644 index 00000000..f616d616 --- /dev/null +++ b/stwo_cairo_verifier/src/circle_mul_table.cairo @@ -0,0 +1,405 @@ +use stwo_cairo_verifier::circle::CirclePoint; +use stwo_cairo_verifier::fields::m31::M31; + +/// Index `i` stores `M31_CIRCLE_GEN * i`. +pub const M31_CIRCLE_GEN_MUL_TABLE_BITS_0_TO_5: [ + CirclePoint + ; 64] = [ + CirclePoint { x: M31 { inner: 1 }, y: M31 { inner: 0 } }, + CirclePoint { x: M31 { inner: 2 }, y: M31 { inner: 1268011823 } }, + CirclePoint { x: M31 { inner: 7 }, y: M31 { inner: 777079998 } }, + CirclePoint { x: M31 { inner: 26 }, y: M31 { inner: 1840308169 } }, + CirclePoint { x: M31 { inner: 97 }, y: M31 { inner: 141701737 } }, + CirclePoint { x: M31 { inner: 362 }, y: M31 { inner: 873982426 } }, + CirclePoint { x: M31 { inner: 1351 }, y: M31 { inner: 1206744320 } }, + CirclePoint { x: M31 { inner: 5042 }, y: M31 { inner: 1805511207 } }, + CirclePoint { x: M31 { inner: 18817 }, y: M31 { inner: 1720333214 } }, + CirclePoint { x: M31 { inner: 70226 }, y: M31 { inner: 780854355 } }, + CirclePoint { x: M31 { inner: 262087 }, y: M31 { inner: 1403084206 } }, + CirclePoint { x: M31 { inner: 978122 }, y: M31 { inner: 536515175 } }, + CirclePoint { x: M31 { inner: 3650401 }, y: M31 { inner: 742976494 } }, + CirclePoint { x: M31 { inner: 13623482 }, y: M31 { inner: 287907154 } }, + CirclePoint { x: M31 { inner: 50843527 }, y: M31 { inner: 408652122 } }, + CirclePoint { x: M31 { inner: 189750626 }, y: M31 { inner: 1346701334 } }, + CirclePoint { x: M31 { inner: 708158977 }, y: M31 { inner: 683185920 } }, + CirclePoint { x: M31 { inner: 495401635 }, y: M31 { inner: 1386042346 } }, + CirclePoint { x: M31 { inner: 1273447563 }, y: M31 { inner: 566016170 } }, + CirclePoint { x: M31 { inner: 303421323 }, y: M31 { inner: 878022334 } }, + CirclePoint { x: M31 { inner: 2087721376 }, y: M31 { inner: 798589519 } }, + CirclePoint { x: M31 { inner: 1605013240 }, y: M31 { inner: 168852095 } }, + CirclePoint { x: M31 { inner: 37364290 }, y: M31 { inner: 2024302508 } }, + CirclePoint { x: M31 { inner: 691927567 }, y: M31 { inner: 1485906996 } }, + CirclePoint { x: M31 { inner: 582862331 }, y: M31 { inner: 1771841829 } }, + CirclePoint { x: M31 { inner: 1639521757 }, y: M31 { inner: 1306493026 } }, + CirclePoint { x: M31 { inner: 1680257403 }, y: M31 { inner: 1306646628 } }, + CirclePoint { x: M31 { inner: 786540561 }, y: M31 { inner: 1772609839 } }, + CirclePoint { x: M31 { inner: 1465904841 }, y: M31 { inner: 1488825434 } }, + CirclePoint { x: M31 { inner: 782111509 }, y: M31 { inner: 2035208250 } }, + CirclePoint { x: M31 { inner: 1662541195 }, y: M31 { inner: 209556625 } }, + CirclePoint { x: M31 { inner: 1573085977 }, y: M31 { inner: 950501897 } }, + CirclePoint { x: M31 { inner: 334835419 }, y: M31 { inner: 1444967316 } }, + CirclePoint { x: M31 { inner: 1913739346 }, y: M31 { inner: 534400073 } }, + CirclePoint { x: M31 { inner: 877671024 }, y: M31 { inner: 692632976 } }, + CirclePoint { x: M31 { inner: 1596944750 }, y: M31 { inner: 88648184 } }, + CirclePoint { x: M31 { inner: 1215140682 }, y: M31 { inner: 1809443407 } }, + CirclePoint { x: M31 { inner: 1116134331 }, y: M31 { inner: 706674503 } }, + CirclePoint { x: M31 { inner: 1101912995 }, y: M31 { inner: 1017254605 } }, + CirclePoint { x: M31 { inner: 1144034002 }, y: M31 { inner: 1214860270 } }, + CirclePoint { x: M31 { inner: 1326739366 }, y: M31 { inner: 1694702828 } }, + CirclePoint { x: M31 { inner: 2015439815 }, y: M31 { inner: 1268983748 } }, + CirclePoint { x: M31 { inner: 292568953 }, y: M31 { inner: 1233748517 } }, + CirclePoint { x: M31 { inner: 1302319644 }, y: M31 { inner: 1518526673 } }, + CirclePoint { x: M31 { inner: 621742329 }, y: M31 { inner: 545390881 } }, + CirclePoint { x: M31 { inner: 1184649672 }, y: M31 { inner: 663036851 } }, + CirclePoint { x: M31 { inner: 1969372712 }, y: M31 { inner: 2106756523 } }, + CirclePoint { x: M31 { inner: 250390235 }, y: M31 { inner: 1321538300 } }, + CirclePoint { x: M31 { inner: 1179671875 }, y: M31 { inner: 1031913030 } }, + CirclePoint { x: M31 { inner: 173329971 }, y: M31 { inner: 658630173 } }, + CirclePoint { x: M31 { inner: 1661131656 }, y: M31 { inner: 1602607662 } }, + CirclePoint { x: M31 { inner: 28745712 }, y: M31 { inner: 1456833181 } }, + CirclePoint { x: M31 { inner: 601334839 }, y: M31 { inner: 2077241415 } }, + CirclePoint { x: M31 { inner: 229109997 }, y: M31 { inner: 409681538 } }, + CirclePoint { x: M31 { inner: 315105149 }, y: M31 { inner: 1708968384 } }, + CirclePoint { x: M31 { inner: 1031310599 }, y: M31 { inner: 2131224704 } }, + CirclePoint { x: M31 { inner: 1662653600 }, y: M31 { inner: 373479491 } }, + CirclePoint { x: M31 { inner: 1324336507 }, y: M31 { inner: 1510176907 } }, + CirclePoint { x: M31 { inner: 1487208781 }, y: M31 { inner: 1372260843 } }, + CirclePoint { x: M31 { inner: 329531323 }, y: M31 { inner: 1831382818 } }, + CirclePoint { x: M31 { inner: 1978400158 }, y: M31 { inner: 1658303135 } }, + CirclePoint { x: M31 { inner: 1141618368 }, y: M31 { inner: 506862428 } }, + CirclePoint { x: M31 { inner: 440589667 }, y: M31 { inner: 369146577 } }, + CirclePoint { x: M31 { inner: 620740300 }, y: M31 { inner: 969723880 } }, +]; + +/// Index `i` stores `M31_CIRCLE_GEN * i * 2^6`. +pub const M31_CIRCLE_GEN_MUL_TABLE_BITS_6_TO_11: [ + CirclePoint + ; 64] = [ + CirclePoint { x: M31 { inner: 1 }, y: M31 { inner: 0 } }, + CirclePoint { x: M31 { inner: 2042371533 }, y: M31 { inner: 1362265296 } }, + CirclePoint { x: M31 { inner: 212706801 }, y: M31 { inner: 1223819887 } }, + CirclePoint { x: M31 { inner: 1343082982 }, y: M31 { inner: 1656388718 } }, + CirclePoint { x: M31 { inner: 421007138 }, y: M31 { inner: 256177860 } }, + CirclePoint { x: M31 { inner: 1637047685 }, y: M31 { inner: 109864373 } }, + CirclePoint { x: M31 { inner: 1594705154 }, y: M31 { inner: 1156423391 } }, + CirclePoint { x: M31 { inner: 1326191972 }, y: M31 { inner: 1554410474 } }, + CirclePoint { x: M31 { inner: 6346213 }, y: M31 { inner: 905523693 } }, + CirclePoint { x: M31 { inner: 1603309155 }, y: M31 { inner: 1317339952 } }, + CirclePoint { x: M31 { inner: 982766847 }, y: M31 { inner: 1369509443 } }, + CirclePoint { x: M31 { inner: 1130890301 }, y: M31 { inner: 1314091057 } }, + CirclePoint { x: M31 { inner: 784830374 }, y: M31 { inner: 912241638 } }, + CirclePoint { x: M31 { inner: 529167155 }, y: M31 { inner: 49384636 } }, + CirclePoint { x: M31 { inner: 1475671350 }, y: M31 { inner: 739745329 } }, + CirclePoint { x: M31 { inner: 418523497 }, y: M31 { inner: 1921984699 } }, + CirclePoint { x: M31 { inner: 1022251061 }, y: M31 { inner: 788094511 } }, + CirclePoint { x: M31 { inner: 1453585800 }, y: M31 { inner: 1686756607 } }, + CirclePoint { x: M31 { inner: 2144756169 }, y: M31 { inner: 1973977555 } }, + CirclePoint { x: M31 { inner: 222118537 }, y: M31 { inner: 1014253609 } }, + CirclePoint { x: M31 { inner: 1774187400 }, y: M31 { inner: 1713497086 } }, + CirclePoint { x: M31 { inner: 1447121614 }, y: M31 { inner: 1053732556 } }, + CirclePoint { x: M31 { inner: 105012991 }, y: M31 { inner: 261334420 } }, + CirclePoint { x: M31 { inner: 1509980434 }, y: M31 { inner: 1580004926 } }, + CirclePoint { x: M31 { inner: 999230472 }, y: M31 { inner: 1852479283 } }, + CirclePoint { x: M31 { inner: 517742188 }, y: M31 { inner: 968413651 } }, + CirclePoint { x: M31 { inner: 288424812 }, y: M31 { inner: 1959942454 } }, + CirclePoint { x: M31 { inner: 1136461567 }, y: M31 { inner: 2028297119 } }, + CirclePoint { x: M31 { inner: 344093444 }, y: M31 { inner: 1723950257 } }, + CirclePoint { x: M31 { inner: 2162587 }, y: M31 { inner: 1662102570 } }, + CirclePoint { x: M31 { inner: 203869561 }, y: M31 { inner: 313423390 } }, + CirclePoint { x: M31 { inner: 57053772 }, y: M31 { inner: 179506272 } }, + CirclePoint { x: M31 { inner: 1633461177 }, y: M31 { inner: 574296567 } }, + CirclePoint { x: M31 { inner: 2063130879 }, y: M31 { inner: 1272838818 } }, + CirclePoint { x: M31 { inner: 1655011431 }, y: M31 { inner: 2085598907 } }, + CirclePoint { x: M31 { inner: 1882985882 }, y: M31 { inner: 1884234849 } }, + CirclePoint { x: M31 { inner: 505774551 }, y: M31 { inner: 1187398701 } }, + CirclePoint { x: M31 { inner: 39852141 }, y: M31 { inner: 123936243 } }, + CirclePoint { x: M31 { inner: 1676081227 }, y: M31 { inner: 1135991864 } }, + CirclePoint { x: M31 { inner: 603512862 }, y: M31 { inner: 13573590 } }, + CirclePoint { x: M31 { inner: 1743980363 }, y: M31 { inner: 345791924 } }, + CirclePoint { x: M31 { inner: 1221120023 }, y: M31 { inner: 1584263814 } }, + CirclePoint { x: M31 { inner: 319360190 }, y: M31 { inner: 618255967 } }, + CirclePoint { x: M31 { inner: 937276350 }, y: M31 { inner: 1889866233 } }, + CirclePoint { x: M31 { inner: 638925477 }, y: M31 { inner: 1200786367 } }, + CirclePoint { x: M31 { inner: 2050207099 }, y: M31 { inner: 979596272 } }, + CirclePoint { x: M31 { inner: 1091919627 }, y: M31 { inner: 1535715623 } }, + CirclePoint { x: M31 { inner: 327335145 }, y: M31 { inner: 1879026140 } }, + CirclePoint { x: M31 { inner: 2054061671 }, y: M31 { inner: 949045631 } }, + CirclePoint { x: M31 { inner: 2017447582 }, y: M31 { inner: 2138555804 } }, + CirclePoint { x: M31 { inner: 1230785717 }, y: M31 { inner: 932947748 } }, + CirclePoint { x: M31 { inner: 1045835668 }, y: M31 { inner: 1112919339 } }, + CirclePoint { x: M31 { inner: 1399167609 }, y: M31 { inner: 1906303117 } }, + CirclePoint { x: M31 { inner: 968612238 }, y: M31 { inner: 1641022910 } }, + CirclePoint { x: M31 { inner: 1696585972 }, y: M31 { inner: 468920631 } }, + CirclePoint { x: M31 { inner: 19290124 }, y: M31 { inner: 887640976 } }, + CirclePoint { x: M31 { inner: 1309393381 }, y: M31 { inner: 53742718 } }, + CirclePoint { x: M31 { inner: 2120725548 }, y: M31 { inner: 846203964 } }, + CirclePoint { x: M31 { inner: 1273782452 }, y: M31 { inner: 924138332 } }, + CirclePoint { x: M31 { inner: 1759380646 }, y: M31 { inner: 1693051226 } }, + CirclePoint { x: M31 { inner: 2080156404 }, y: M31 { inner: 1988869649 } }, + CirclePoint { x: M31 { inner: 314388810 }, y: M31 { inner: 1013513450 } }, + CirclePoint { x: M31 { inner: 1619251001 }, y: M31 { inner: 830366565 } }, + CirclePoint { x: M31 { inner: 1385987562 }, y: M31 { inner: 2130936594 } }, +]; + +/// Index `i` stores `M31_CIRCLE_GEN * i * 2^12`. +pub const M31_CIRCLE_GEN_MUL_TABLE_BITS_12_TO_17: [ + CirclePoint + ; 64] = [ + CirclePoint { x: M31 { inner: 1 }, y: M31 { inner: 0 } }, + CirclePoint { x: M31 { inner: 595037635 }, y: M31 { inner: 2111542451 } }, + CirclePoint { x: M31 { inner: 1799120754 }, y: M31 { inner: 343598868 } }, + CirclePoint { x: M31 { inner: 1475016787 }, y: M31 { inner: 1876816901 } }, + CirclePoint { x: M31 { inner: 438833264 }, y: M31 { inner: 1327019128 } }, + CirclePoint { x: M31 { inner: 433600440 }, y: M31 { inner: 167145119 } }, + CirclePoint { x: M31 { inner: 503318431 }, y: M31 { inner: 730224775 } }, + CirclePoint { x: M31 { inner: 1124768046 }, y: M31 { inner: 299494314 } }, + CirclePoint { x: M31 { inner: 1389168750 }, y: M31 { inner: 838891026 } }, + CirclePoint { x: M31 { inner: 1421883301 }, y: M31 { inner: 1767600112 } }, + CirclePoint { x: M31 { inner: 263253631 }, y: M31 { inner: 1948074535 } }, + CirclePoint { x: M31 { inner: 1984370174 }, y: M31 { inner: 548484416 } }, + CirclePoint { x: M31 { inner: 377761958 }, y: M31 { inner: 572545120 } }, + CirclePoint { x: M31 { inner: 528497962 }, y: M31 { inner: 2048433423 } }, + CirclePoint { x: M31 { inner: 347749121 }, y: M31 { inner: 1576860820 } }, + CirclePoint { x: M31 { inner: 1168068815 }, y: M31 { inner: 1631133982 } }, + CirclePoint { x: M31 { inner: 1543902459 }, y: M31 { inner: 1632329423 } }, + CirclePoint { x: M31 { inner: 1964662320 }, y: M31 { inner: 1382435771 } }, + CirclePoint { x: M31 { inner: 124482577 }, y: M31 { inner: 226221110 } }, + CirclePoint { x: M31 { inner: 1214106985 }, y: M31 { inner: 780900129 } }, + CirclePoint { x: M31 { inner: 1635360495 }, y: M31 { inner: 1075839836 } }, + CirclePoint { x: M31 { inner: 36975016 }, y: M31 { inner: 821963373 } }, + CirclePoint { x: M31 { inner: 338018326 }, y: M31 { inner: 944583937 } }, + CirclePoint { x: M31 { inner: 1753543609 }, y: M31 { inner: 1294275673 } }, + CirclePoint { x: M31 { inner: 13191618 }, y: M31 { inner: 303576968 } }, + CirclePoint { x: M31 { inner: 606906923 }, y: M31 { inner: 1264738384 } }, + CirclePoint { x: M31 { inner: 1488671228 }, y: M31 { inner: 939868393 } }, + CirclePoint { x: M31 { inner: 854984042 }, y: M31 { inner: 63484416 } }, + CirclePoint { x: M31 { inner: 1825664712 }, y: M31 { inner: 501661179 } }, + CirclePoint { x: M31 { inner: 845078094 }, y: M31 { inner: 149898124 } }, + CirclePoint { x: M31 { inner: 1829052821 }, y: M31 { inner: 673049321 } }, + CirclePoint { x: M31 { inner: 1029759507 }, y: M31 { inner: 977441374 } }, + CirclePoint { x: M31 { inner: 1330239767 }, y: M31 { inner: 1446369578 } }, + CirclePoint { x: M31 { inner: 798338207 }, y: M31 { inner: 2110850421 } }, + CirclePoint { x: M31 { inner: 521340221 }, y: M31 { inner: 1824173925 } }, + CirclePoint { x: M31 { inner: 957870942 }, y: M31 { inner: 905094216 } }, + CirclePoint { x: M31 { inner: 1384581133 }, y: M31 { inner: 347627210 } }, + CirclePoint { x: M31 { inner: 2001642678 }, y: M31 { inner: 1520422911 } }, + CirclePoint { x: M31 { inner: 940196297 }, y: M31 { inner: 1361581394 } }, + CirclePoint { x: M31 { inner: 1924483244 }, y: M31 { inner: 1528988896 } }, + CirclePoint { x: M31 { inner: 296310565 }, y: M31 { inner: 109983397 } }, + CirclePoint { x: M31 { inner: 729011542 }, y: M31 { inner: 952009042 } }, + CirclePoint { x: M31 { inner: 735504938 }, y: M31 { inner: 198004457 } }, + CirclePoint { x: M31 { inner: 591304555 }, y: M31 { inner: 68989614 } }, + CirclePoint { x: M31 { inner: 324121113 }, y: M31 { inner: 147452506 } }, + CirclePoint { x: M31 { inner: 1029245122 }, y: M31 { inner: 1158447597 } }, + CirclePoint { x: M31 { inner: 1213375404 }, y: M31 { inner: 771547637 } }, + CirclePoint { x: M31 { inner: 1389630114 }, y: M31 { inner: 73256692 } }, + CirclePoint { x: M31 { inner: 1338697498 }, y: M31 { inner: 1881711368 } }, + CirclePoint { x: M31 { inner: 1631496031 }, y: M31 { inner: 481893475 } }, + CirclePoint { x: M31 { inner: 607954189 }, y: M31 { inner: 1091734815 } }, + CirclePoint { x: M31 { inner: 891287480 }, y: M31 { inner: 1172290213 } }, + CirclePoint { x: M31 { inner: 1004021208 }, y: M31 { inner: 1870425365 } }, + CirclePoint { x: M31 { inner: 1876139646 }, y: M31 { inner: 119923533 } }, + CirclePoint { x: M31 { inner: 1212070390 }, y: M31 { inner: 338345678 } }, + CirclePoint { x: M31 { inner: 122809504 }, y: M31 { inner: 181977862 } }, + CirclePoint { x: M31 { inner: 1577483195 }, y: M31 { inner: 846841358 } }, + CirclePoint { x: M31 { inner: 953139263 }, y: M31 { inner: 265503960 } }, + CirclePoint { x: M31 { inner: 474711937 }, y: M31 { inner: 1020011657 } }, + CirclePoint { x: M31 { inner: 1696657789 }, y: M31 { inner: 2121958423 } }, + CirclePoint { x: M31 { inner: 640220223 }, y: M31 { inner: 1154724018 } }, + CirclePoint { x: M31 { inner: 887385898 }, y: M31 { inner: 608769478 } }, + CirclePoint { x: M31 { inner: 44588143 }, y: M31 { inner: 2058311453 } }, + CirclePoint { x: M31 { inner: 404074859 }, y: M31 { inner: 398369746 } }, +]; + +/// Index `i` stores `M31_CIRCLE_GEN * i * 2^18`. +pub const M31_CIRCLE_GEN_MUL_TABLE_BITS_18_TO_23: [ + CirclePoint + ; 64] = [ + CirclePoint { x: M31 { inner: 1 }, y: M31 { inner: 0 } }, + CirclePoint { x: M31 { inner: 1420207432 }, y: M31 { inner: 2023238517 } }, + CirclePoint { x: M31 { inner: 2015554631 }, y: M31 { inner: 1088093947 } }, + CirclePoint { x: M31 { inner: 1720479643 }, y: M31 { inner: 177413607 } }, + CirclePoint { x: M31 { inner: 996212859 }, y: M31 { inner: 1140996376 } }, + CirclePoint { x: M31 { inner: 816861480 }, y: M31 { inner: 962195439 } }, + CirclePoint { x: M31 { inner: 816867225 }, y: M31 { inner: 1001272228 } }, + CirclePoint { x: M31 { inner: 451378731 }, y: M31 { inner: 1322552846 } }, + CirclePoint { x: M31 { inner: 1434706457 }, y: M31 { inner: 1835793811 } }, + CirclePoint { x: M31 { inner: 306425233 }, y: M31 { inner: 1445476898 } }, + CirclePoint { x: M31 { inner: 108989434 }, y: M31 { inner: 171027633 } }, + CirclePoint { x: M31 { inner: 2071133460 }, y: M31 { inner: 426561857 } }, + CirclePoint { x: M31 { inner: 497251457 }, y: M31 { inner: 850319468 } }, + CirclePoint { x: M31 { inner: 1261210341 }, y: M31 { inner: 453089266 } }, + CirclePoint { x: M31 { inner: 1658851911 }, y: M31 { inner: 228916482 } }, + CirclePoint { x: M31 { inner: 2034814864 }, y: M31 { inner: 1083531373 } }, + CirclePoint { x: M31 { inner: 13610297 }, y: M31 { inner: 1064696601 } }, + CirclePoint { x: M31 { inner: 1070779035 }, y: M31 { inner: 1741827866 } }, + CirclePoint { x: M31 { inner: 1818030451 }, y: M31 { inner: 1183201954 } }, + CirclePoint { x: M31 { inner: 741042664 }, y: M31 { inner: 44265284 } }, + CirclePoint { x: M31 { inner: 903851705 }, y: M31 { inner: 1384342623 } }, + CirclePoint { x: M31 { inner: 1074738377 }, y: M31 { inner: 922667469 } }, + CirclePoint { x: M31 { inner: 505405055 }, y: M31 { inner: 327810224 } }, + CirclePoint { x: M31 { inner: 1396305186 }, y: M31 { inner: 1953641782 } }, + CirclePoint { x: M31 { inner: 609228044 }, y: M31 { inner: 827893883 } }, + CirclePoint { x: M31 { inner: 814418619 }, y: M31 { inner: 258209920 } }, + CirclePoint { x: M31 { inner: 1215555130 }, y: M31 { inner: 798189752 } }, + CirclePoint { x: M31 { inner: 2054815690 }, y: M31 { inner: 101808551 } }, + CirclePoint { x: M31 { inner: 1272801243 }, y: M31 { inner: 632096738 } }, + CirclePoint { x: M31 { inner: 1716313062 }, y: M31 { inner: 1918467562 } }, + CirclePoint { x: M31 { inner: 2020345262 }, y: M31 { inner: 2075173999 } }, + CirclePoint { x: M31 { inner: 1119352987 }, y: M31 { inner: 277348337 } }, + CirclePoint { x: M31 { inner: 785043271 }, y: M31 { inner: 1260750973 } }, + CirclePoint { x: M31 { inner: 612772931 }, y: M31 { inner: 67557103 } }, + CirclePoint { x: M31 { inner: 1626319062 }, y: M31 { inner: 1695214127 } }, + CirclePoint { x: M31 { inner: 933993899 }, y: M31 { inner: 1989600800 } }, + CirclePoint { x: M31 { inner: 608020784 }, y: M31 { inner: 1658232706 } }, + CirclePoint { x: M31 { inner: 1095416042 }, y: M31 { inner: 2064872520 } }, + CirclePoint { x: M31 { inner: 503059345 }, y: M31 { inner: 472488427 } }, + CirclePoint { x: M31 { inner: 1030627222 }, y: M31 { inner: 1992293517 } }, + CirclePoint { x: M31 { inner: 477465227 }, y: M31 { inner: 1464821634 } }, + CirclePoint { x: M31 { inner: 1395612878 }, y: M31 { inner: 23814109 } }, + CirclePoint { x: M31 { inner: 889125072 }, y: M31 { inner: 992347850 } }, + CirclePoint { x: M31 { inner: 483482869 }, y: M31 { inner: 1961673230 } }, + CirclePoint { x: M31 { inner: 1584592502 }, y: M31 { inner: 821845974 } }, + CirclePoint { x: M31 { inner: 1132606208 }, y: M31 { inner: 1726336308 } }, + CirclePoint { x: M31 { inner: 1842504837 }, y: M31 { inner: 844472455 } }, + CirclePoint { x: M31 { inner: 1848107793 }, y: M31 { inner: 1406793602 } }, + CirclePoint { x: M31 { inner: 655387905 }, y: M31 { inner: 752064346 } }, + CirclePoint { x: M31 { inner: 1888484876 }, y: M31 { inner: 944217688 } }, + CirclePoint { x: M31 { inner: 870057820 }, y: M31 { inner: 841184532 } }, + CirclePoint { x: M31 { inner: 211324925 }, y: M31 { inner: 1758927877 } }, + CirclePoint { x: M31 { inner: 1616257580 }, y: M31 { inner: 975311156 } }, + CirclePoint { x: M31 { inner: 1550009808 }, y: M31 { inner: 1892920908 } }, + CirclePoint { x: M31 { inner: 326246026 }, y: M31 { inner: 459902653 } }, + CirclePoint { x: M31 { inner: 1943811611 }, y: M31 { inner: 1441409520 } }, + CirclePoint { x: M31 { inner: 1919800332 }, y: M31 { inner: 1732277387 } }, + CirclePoint { x: M31 { inner: 1949082454 }, y: M31 { inner: 963118347 } }, + CirclePoint { x: M31 { inner: 1315700354 }, y: M31 { inner: 133468241 } }, + CirclePoint { x: M31 { inner: 653789815 }, y: M31 { inner: 1573078736 } }, + CirclePoint { x: M31 { inner: 947277864 }, y: M31 { inner: 1089459781 } }, + CirclePoint { x: M31 { inner: 494332398 }, y: M31 { inner: 1387925761 } }, + CirclePoint { x: M31 { inner: 1536875846 }, y: M31 { inner: 1146921693 } }, + CirclePoint { x: M31 { inner: 1792250398 }, y: M31 { inner: 609879011 } }, +]; + +/// Index `i` stores `M31_CIRCLE_GEN * i * 2^24`. +pub const M31_CIRCLE_GEN_MUL_TABLE_BITS_24_TO_29: [ + CirclePoint + ; 64] = [ + CirclePoint { x: M31 { inner: 1 }, y: M31 { inner: 0 } }, + CirclePoint { x: M31 { inner: 838195206 }, y: M31 { inner: 1774253895 } }, + CirclePoint { x: M31 { inner: 579625837 }, y: M31 { inner: 1690787918 } }, + CirclePoint { x: M31 { inner: 2013328190 }, y: M31 { inner: 1108537731 } }, + CirclePoint { x: M31 { inner: 1179735656 }, y: M31 { inner: 1241207368 } }, + CirclePoint { x: M31 { inner: 2140339328 }, y: M31 { inner: 404685994 } }, + CirclePoint { x: M31 { inner: 1866536500 }, y: M31 { inner: 1133522282 } }, + CirclePoint { x: M31 { inner: 1263730590 }, y: M31 { inner: 350742286 } }, + CirclePoint { x: M31 { inner: 590768354 }, y: M31 { inner: 978592373 } }, + CirclePoint { x: M31 { inner: 206059115 }, y: M31 { inner: 212443077 } }, + CirclePoint { x: M31 { inner: 1952787376 }, y: M31 { inner: 1580223790 } }, + CirclePoint { x: M31 { inner: 2079025011 }, y: M31 { inner: 2137679949 } }, + CirclePoint { x: M31 { inner: 34602070 }, y: M31 { inner: 732393395 } }, + CirclePoint { x: M31 { inner: 14530030 }, y: M31 { inner: 228509164 } }, + CirclePoint { x: M31 { inner: 26164677 }, y: M31 { inner: 505542828 } }, + CirclePoint { x: M31 { inner: 1885292596 }, y: M31 { inner: 408478793 } }, + CirclePoint { x: M31 { inner: 32768 }, y: M31 { inner: 2147450879 } }, + CirclePoint { x: M31 { inner: 1739004854 }, y: M31 { inner: 262191051 } }, + CirclePoint { x: M31 { inner: 1641940819 }, y: M31 { inner: 2121318970 } }, + CirclePoint { x: M31 { inner: 1918974483 }, y: M31 { inner: 2132953617 } }, + CirclePoint { x: M31 { inner: 1415090252 }, y: M31 { inner: 2112881577 } }, + CirclePoint { x: M31 { inner: 9803698 }, y: M31 { inner: 68458636 } }, + CirclePoint { x: M31 { inner: 567259857 }, y: M31 { inner: 194696271 } }, + CirclePoint { x: M31 { inner: 1935040570 }, y: M31 { inner: 1941424532 } }, + CirclePoint { x: M31 { inner: 1168891274 }, y: M31 { inner: 1556715293 } }, + CirclePoint { x: M31 { inner: 1796741361 }, y: M31 { inner: 883753057 } }, + CirclePoint { x: M31 { inner: 1013961365 }, y: M31 { inner: 280947147 } }, + CirclePoint { x: M31 { inner: 1742797653 }, y: M31 { inner: 7144319 } }, + CirclePoint { x: M31 { inner: 906276279 }, y: M31 { inner: 967747991 } }, + CirclePoint { x: M31 { inner: 1038945916 }, y: M31 { inner: 134155457 } }, + CirclePoint { x: M31 { inner: 456695729 }, y: M31 { inner: 1567857810 } }, + CirclePoint { x: M31 { inner: 373229752 }, y: M31 { inner: 1309288441 } }, + CirclePoint { x: M31 { inner: 0 }, y: M31 { inner: 2147483646 } }, + CirclePoint { x: M31 { inner: 1774253895 }, y: M31 { inner: 1309288441 } }, + CirclePoint { x: M31 { inner: 1690787918 }, y: M31 { inner: 1567857810 } }, + CirclePoint { x: M31 { inner: 1108537731 }, y: M31 { inner: 134155457 } }, + CirclePoint { x: M31 { inner: 1241207368 }, y: M31 { inner: 967747991 } }, + CirclePoint { x: M31 { inner: 404685994 }, y: M31 { inner: 7144319 } }, + CirclePoint { x: M31 { inner: 1133522282 }, y: M31 { inner: 280947147 } }, + CirclePoint { x: M31 { inner: 350742286 }, y: M31 { inner: 883753057 } }, + CirclePoint { x: M31 { inner: 978592373 }, y: M31 { inner: 1556715293 } }, + CirclePoint { x: M31 { inner: 212443077 }, y: M31 { inner: 1941424532 } }, + CirclePoint { x: M31 { inner: 1580223790 }, y: M31 { inner: 194696271 } }, + CirclePoint { x: M31 { inner: 2137679949 }, y: M31 { inner: 68458636 } }, + CirclePoint { x: M31 { inner: 732393395 }, y: M31 { inner: 2112881577 } }, + CirclePoint { x: M31 { inner: 228509164 }, y: M31 { inner: 2132953617 } }, + CirclePoint { x: M31 { inner: 505542828 }, y: M31 { inner: 2121318970 } }, + CirclePoint { x: M31 { inner: 408478793 }, y: M31 { inner: 262191051 } }, + CirclePoint { x: M31 { inner: 2147450879 }, y: M31 { inner: 2147450879 } }, + CirclePoint { x: M31 { inner: 262191051 }, y: M31 { inner: 408478793 } }, + CirclePoint { x: M31 { inner: 2121318970 }, y: M31 { inner: 505542828 } }, + CirclePoint { x: M31 { inner: 2132953617 }, y: M31 { inner: 228509164 } }, + CirclePoint { x: M31 { inner: 2112881577 }, y: M31 { inner: 732393395 } }, + CirclePoint { x: M31 { inner: 68458636 }, y: M31 { inner: 2137679949 } }, + CirclePoint { x: M31 { inner: 194696271 }, y: M31 { inner: 1580223790 } }, + CirclePoint { x: M31 { inner: 1941424532 }, y: M31 { inner: 212443077 } }, + CirclePoint { x: M31 { inner: 1556715293 }, y: M31 { inner: 978592373 } }, + CirclePoint { x: M31 { inner: 883753057 }, y: M31 { inner: 350742286 } }, + CirclePoint { x: M31 { inner: 280947147 }, y: M31 { inner: 1133522282 } }, + CirclePoint { x: M31 { inner: 7144319 }, y: M31 { inner: 404685994 } }, + CirclePoint { x: M31 { inner: 967747991 }, y: M31 { inner: 1241207368 } }, + CirclePoint { x: M31 { inner: 134155457 }, y: M31 { inner: 1108537731 } }, + CirclePoint { x: M31 { inner: 1567857810 }, y: M31 { inner: 1690787918 } }, + CirclePoint { x: M31 { inner: 1309288441 }, y: M31 { inner: 1774253895 } }, +]; + +#[cfg(test)] +mod tests { + use stwo_cairo_verifier::circle::{M31_CIRCLE_GEN, CirclePointM31Impl}; + use super::{ + M31_CIRCLE_GEN_MUL_TABLE_BITS_0_TO_5, M31_CIRCLE_GEN_MUL_TABLE_BITS_6_TO_11, + M31_CIRCLE_GEN_MUL_TABLE_BITS_12_TO_17, M31_CIRCLE_GEN_MUL_TABLE_BITS_18_TO_23, + M31_CIRCLE_GEN_MUL_TABLE_BITS_24_TO_29, + }; + + #[test] + fn test_constants_valid() { + let step_1 = M31_CIRCLE_GEN; + let mut acc = CirclePointM31Impl::zero(); + for p in M31_CIRCLE_GEN_MUL_TABLE_BITS_0_TO_5 + .span() { + assert_eq!(*p, acc); + acc = acc + step_1; + }; + + let step_2_pow_6 = acc; + let mut acc = CirclePointM31Impl::zero(); + for p in M31_CIRCLE_GEN_MUL_TABLE_BITS_6_TO_11 + .span() { + assert_eq!(*p, acc); + acc = acc + step_2_pow_6; + }; + + let step_2_pow_12 = acc; + let mut acc = CirclePointM31Impl::zero(); + for p in M31_CIRCLE_GEN_MUL_TABLE_BITS_12_TO_17 + .span() { + assert_eq!(*p, acc); + acc = acc + step_2_pow_12; + }; + + let step_2_pow_18 = acc; + let mut acc = CirclePointM31Impl::zero(); + for p in M31_CIRCLE_GEN_MUL_TABLE_BITS_18_TO_23 + .span() { + assert_eq!(*p, acc); + acc = acc + step_2_pow_18; + }; + + let step_2_pow_24 = acc; + let mut acc = CirclePointM31Impl::zero(); + for p in M31_CIRCLE_GEN_MUL_TABLE_BITS_24_TO_29 + .span() { + assert_eq!(*p, acc); + acc = acc + step_2_pow_24; + }; + } +} diff --git a/stwo_cairo_verifier/src/fri.cairo b/stwo_cairo_verifier/src/fri.cairo index e81545e8..b4b8c647 100644 --- a/stwo_cairo_verifier/src/fri.cairo +++ b/stwo_cairo_verifier/src/fri.cairo @@ -3,7 +3,7 @@ use stwo_cairo_verifier::channel::{Channel, ChannelTrait}; use stwo_cairo_verifier::circle::CosetImpl; use stwo_cairo_verifier::fields::m31::M31; use stwo_cairo_verifier::fields::m31::M31Trait; -use stwo_cairo_verifier::fields::qm31::{QM31, QM31Zero, QM31Trait}; +use stwo_cairo_verifier::fields::qm31::{QM31_EXTENSION_DEGREE, QM31, QM31Zero, QM31Trait}; use stwo_cairo_verifier::poly::circle::CircleDomainImpl; use stwo_cairo_verifier::poly::circle::{ CircleEvaluation, SparseCircleEvaluation, SparseCircleEvaluationImpl @@ -15,13 +15,22 @@ use stwo_cairo_verifier::poly::line::{LineDomain, LineDomainImpl}; 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::{bit_reverse_index, ArrayImpl, SpanExTrait, pow, pow_qm31, find}; +use stwo_cairo_verifier::utils::{bit_reverse_index, ArrayImpl, SpanExTrait, pow, find}; use stwo_cairo_verifier::vcs::hasher::PoseidonMerkleHasher; use stwo_cairo_verifier::vcs::verifier::{MerkleDecommitment, MerkleVerifier, MerkleVerifierTrait}; +/// Fold step size for circle polynomials. pub const CIRCLE_TO_LINE_FOLD_STEP: u32 = 1; + +/// Equals `2^CIRCLE_TO_LINE_FOLD_STEP`. +pub const CIRCLE_TO_LINE_FOLD_FACTOR: usize = 2; + +/// Fold step size for univariate polynomials. pub const FOLD_STEP: u32 = 1; +/// Equals `2^FOLD_STEP`. +pub const FOLD_FACTOR: usize = 2; + #[derive(Debug, Drop, PartialEq)] pub enum FriVerificationError { InvalidNumFriLayers, @@ -46,72 +55,62 @@ impl FriLayerVerifierImpl of FriLayerVerifierTrait { fn verify_and_fold( self: @FriLayerVerifier, queries: @Queries, evals_at_queries: @Array ) -> Result<(Queries, Array), FriVerificationError> { - let commitment = self.proof.commitment; - let sparse_evaluation = self.extract_evaluation(queries, evals_at_queries)?; - let mut column_0: Array = array![]; - let mut column_1: Array = array![]; - let mut column_2: Array = array![]; - let mut column_3: Array = array![]; - let mut i = 0; - while i < (sparse_evaluation).subline_evals.len() { - let mut j = 0; - let subline_eval = sparse_evaluation.subline_evals[i]; - while j < (sparse_evaluation.subline_evals[i]).values.len() { - let [x0, x1, x2, x3] = (*subline_eval.values[j]).to_array(); - - column_0.append(x0); - column_1.append(x1); - column_2.append(x2); - column_3.append(x3); - j += 1; + + let mut column_0 = array![]; + let mut column_1 = array![]; + let mut column_2 = array![]; + let mut column_3 = array![]; + + for subline_eval in sparse_evaluation + .subline_evals + .span() { + for eval in subline_eval + .values + .span() { + let [x0, x1, x2, x3] = (*eval).to_array(); + column_0.append(x0); + column_1.append(x1); + column_2.append(x2); + column_3.append(x3); + }; }; - i += 1; - }; + let actual_decommitment_array = array![column_0, column_1, column_2, column_3]; let folded_queries = queries.fold(FOLD_STEP); - let folded_queries_snapshot = @folded_queries; - let mut decommitment_positions = array![]; - let mut i = 0; - while i < folded_queries_snapshot.len() { - let start = *folded_queries_snapshot.positions[i] * pow(2, FOLD_STEP); - let end = start + pow(2, FOLD_STEP); - let mut j = start; - while j < end { - decommitment_positions.append(j); - j += 1; + + for folded_query_position in folded_queries + .positions + .span() { + let start = *folded_query_position * FOLD_FACTOR; + let end = start + FOLD_FACTOR; + for i in start..end { + decommitment_positions.append(i); + }; }; - i += 1; - }; + let column_log_size = self.domain.log_size(); let merkle_verifier = MerkleVerifier { - root: *commitment.clone(), - column_log_sizes: array![ - // TODO: adapt to handle other secure_extension_degree - self.domain.log_size(), - self.domain.log_size(), - self.domain.log_size(), - self.domain.log_size() - ] + root: **self.proof.commitment, + column_log_sizes: ArrayImpl::new_repeated(QM31_EXTENSION_DEGREE, column_log_size), }; let mut queries_per_log_size: Felt252Dict>> = Default::default(); queries_per_log_size - .insert( - self.domain.log_size().into(), NullableTrait::new(decommitment_positions.span()) - ); + .insert(column_log_size.into(), NullableTrait::new(decommitment_positions.span())); - let decommitment = self.proof.decommitment.clone(); - let result = merkle_verifier - .verify(queries_per_log_size, @actual_decommitment_array, decommitment.clone()); + let decommitment = (*self.proof.decommitment).clone(); - let evals_at_folded_queries = sparse_evaluation.fold(*self.folding_alpha); - match result { - Result::Ok(()) => Result::Ok((folded_queries, evals_at_folded_queries)), - Result::Err(_) => Result::Err(FriVerificationError::InnerLayerCommitmentInvalid) + if let Result::Err(_) = merkle_verifier + .verify(queries_per_log_size, @actual_decommitment_array, decommitment) { + return Result::Err(FriVerificationError::InnerLayerCommitmentInvalid); } + + let evals_at_folded_queries = sparse_evaluation.fold(*self.folding_alpha); + + Result::Ok((folded_queries, evals_at_folded_queries)) } /// Returns the evaluations needed for decommitment. @@ -137,15 +136,15 @@ impl FriLayerVerifierImpl of FriLayerVerifierTrait { i += 1; while i < queries.positions.len() && (*queries.positions[i - - 1] / pow(2, FOLD_STEP)) == (*queries.positions[i] / pow(2, FOLD_STEP)) { + - 1] / FOLD_FACTOR) == (*queries.positions[i] / FOLD_FACTOR) { i = i + 1; }; let end_subline_index = i; // These are the values whose evaluations are required. - let subline_start = (*queries.positions[start_subline_index] / pow(2, FOLD_STEP)) - * pow(2, FOLD_STEP); - let subline_end = subline_start + pow(2, FOLD_STEP); + let subline_start = (*queries.positions[start_subline_index] / FOLD_FACTOR) + * FOLD_FACTOR; + let subline_end = subline_start + FOLD_FACTOR; let mut subline_evals: Array = array![]; @@ -176,7 +175,9 @@ impl FriLayerVerifierImpl of FriLayerVerifierTrait { let subline_initial_index = bit_reverse_index(subline_start, self.domain.log_size()); let subline_initial = self.domain.coset.index_at(subline_initial_index); - let subline_domain = LineDomainImpl::new(CosetImpl::new(subline_initial, FOLD_STEP)); + let subline_domain = LineDomainImpl::new_unchecked( + CosetImpl::new(subline_initial, FOLD_STEP) + ); all_subline_evals.append(LineEvaluationImpl::new(subline_domain, subline_evals)); }; @@ -238,7 +239,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 = LineDomainImpl::new( + let mut layer_domain = LineDomainImpl::new_unchecked( CosetImpl::half_odds(layer_bound + config.log_blowup_factor) ); @@ -327,8 +328,8 @@ pub impl FriVerifierImpl of FriVerifierTrait { fn decommit_inner_layers( self: @FriVerifier, queries: @Queries, mut decommitted_values: Array ) -> Result<(Queries, Array), FriVerificationError> { - let circle_poly_alpha = self.circle_poly_alpha; - let circle_poly_alpha_sq = *circle_poly_alpha * *circle_poly_alpha; + let circle_poly_alpha = *self.circle_poly_alpha; + let circle_poly_alpha_pow_fold_factor = circle_poly_alpha * circle_poly_alpha; let mut inner_layers = self.inner_layers.span(); let mut column_bounds = self.column_bounds.span(); @@ -338,16 +339,14 @@ pub impl FriVerifierImpl of FriVerifierTrait { loop { let layer = match inner_layers.pop_front() { Option::Some(layer) => layer, - Option::None => { - break Result::Ok(()); - } + Option::None => { break Result::Ok(()); } }; let circle_poly_degree_bound = *layer.degree_bound + CIRCLE_TO_LINE_FOLD_STEP; while let Option::Some(_) = column_bounds.next_if_eq(@circle_poly_degree_bound) { let sparse_evaluation = decommitted_values.pop_front().unwrap(); - let mut folded_evals = sparse_evaluation.fold(*circle_poly_alpha); + let mut folded_evals = sparse_evaluation.fold(circle_poly_alpha); let n = folded_evals.len(); assert!(folded_evals.len() == layer_query_evals.len()); @@ -357,7 +356,7 @@ pub impl FriVerifierImpl of FriVerifierTrait { let layer_eval = layer_query_evals.pop_front().unwrap(); let folded_eval = folded_evals.pop_front().unwrap(); next_layer_query_evals - .append(layer_eval * circle_poly_alpha_sq + folded_eval); + .append(layer_eval * circle_poly_alpha_pow_fold_factor + folded_eval); }; layer_query_evals = next_layer_query_evals; }; @@ -479,7 +478,7 @@ pub fn fold_line(eval: LineEvaluation, alpha: QM31) -> LineEvaluation { for i in 0 ..eval.values.len() / 2 { - let x = domain.at(bit_reverse_index(i * pow(2, FOLD_STEP), domain.log_size())); + let x = domain.at(bit_reverse_index(i * FOLD_FACTOR, domain.log_size())); let f_x = eval.values[2 * i]; let f_neg_x = eval.values[2 * i + 1]; let (f0, f1) = ibutterfly(*f_x, *f_neg_x, x.inverse()); @@ -496,18 +495,18 @@ pub fn fold_line(eval: LineEvaluation, alpha: QM31) -> LineEvaluation { /// `dst = dst * alpha^2 + f'`. pub fn fold_circle_into_line(eval: CircleEvaluation, alpha: QM31) -> LineEvaluation { let domain = eval.domain; - let fold_factor = pow(2, CIRCLE_TO_LINE_FOLD_STEP); let mut values = array![]; for i in 0 ..eval.bit_reversed_values.len() / 2 { - let p = domain.at(bit_reverse_index(i * fold_factor, domain.log_size())); + let p = domain + .at(bit_reverse_index(i * CIRCLE_TO_LINE_FOLD_FACTOR, domain.log_size())); let f_p = eval.bit_reversed_values[2 * i]; let f_neg_p = eval.bit_reversed_values[2 * i + 1]; let (f0, f1) = ibutterfly(*f_p, *f_neg_p, p.y.inverse()); values.append(f0 + alpha * f1); }; - LineEvaluation { values, domain: LineDomainImpl::new(domain.half_coset) } + LineEvaluation { values, domain: LineDomainImpl::new_unchecked(domain.half_coset) } } pub fn ibutterfly(v0: QM31, v1: QM31, itwid: M31) -> (QM31, QM31) { @@ -533,7 +532,9 @@ mod test { #[test] fn test_fold_line_1() { - let domain = LineDomainImpl::new(CosetImpl::new(CirclePointIndexImpl::new(67108864), 1)); + let domain = LineDomainImpl::new_unchecked( + CosetImpl::new(CirclePointIndexImpl::new(67108864), 1) + ); let values = array![ qm31(440443058, 1252794525, 1129773609, 1309365757), qm31(974589897, 1592795796, 649052897, 863407657) @@ -550,7 +551,9 @@ mod test { #[test] fn test_fold_line_2() { - let domain = LineDomainImpl::new(CosetImpl::new(CirclePointIndexImpl::new(553648128), 1)); + let domain = LineDomainImpl::new_unchecked( + CosetImpl::new(CirclePointIndexImpl::new(553648128), 1) + ); let values = array![ qm31(730692421, 1363821003, 2146256633, 106012305), qm31(1387266930, 149259209, 1148988082, 1930518101) diff --git a/stwo_cairo_verifier/src/lib.cairo b/stwo_cairo_verifier/src/lib.cairo index 392f3b43..0f232fba 100644 --- a/stwo_cairo_verifier/src/lib.cairo +++ b/stwo_cairo_verifier/src/lib.cairo @@ -1,5 +1,6 @@ pub mod channel; pub mod circle; +mod circle_mul_table; pub mod fields; pub mod fri; pub mod pcs; diff --git a/stwo_cairo_verifier/src/pcs/quotients.cairo b/stwo_cairo_verifier/src/pcs/quotients.cairo index 9d99b54c..47321134 100644 --- a/stwo_cairo_verifier/src/pcs/quotients.cairo +++ b/stwo_cairo_verifier/src/pcs/quotients.cairo @@ -510,9 +510,7 @@ mod tests { use core::array::ArrayImpl; use core::dict::Felt252Dict; use core::nullable::{NullableTrait}; - use stwo_cairo_verifier::circle::{ - QM31_CIRCLE_GEN, CosetImpl, CirclePointIndexImpl, CirclePointTrait - }; + use stwo_cairo_verifier::circle::{QM31_CIRCLE_GEN, CosetImpl, CirclePointIndexImpl}; use stwo_cairo_verifier::fields::cm31::cm31; use stwo_cairo_verifier::fields::m31::m31; use stwo_cairo_verifier::fields::qm31::{qm31, PackedUnreducedQM31Impl}; @@ -534,9 +532,12 @@ mod tests { fn test_fri_answers_for_log_size() { let log_size = 5; let commitment_domain = CanonicCosetImpl::new(log_size).circle_domain(); - let sample0 = PointSample { point: QM31_CIRCLE_GEN, value: qm31(0, 1, 2, 3) }; - let sample1 = PointSample { point: QM31_CIRCLE_GEN.mul(2), value: qm31(1, 2, 3, 4) }; - let sample2 = PointSample { point: QM31_CIRCLE_GEN.mul(3), value: qm31(2, 3, 4, 5) }; + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let p2 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let sample0 = PointSample { point: p0, value: qm31(0, 1, 2, 3) }; + let sample1 = PointSample { point: p1, value: qm31(1, 2, 3, 4) }; + let sample2 = PointSample { point: p2, value: qm31(2, 3, 4, 5) }; let col0_samples = array![sample0, sample1, sample2]; let col1_samples = array![sample0]; let col2_samples = array![sample0, sample2]; @@ -588,8 +589,10 @@ mod tests { let log_size_per_column = array![col0_log_size, col1_log_size]; let col0_commitment_domain = CanonicCosetImpl::new(col0_log_size).circle_domain(); let col1_commitment_domain = CanonicCosetImpl::new(col1_log_size).circle_domain(); - let sample0 = PointSample { point: QM31_CIRCLE_GEN, value: qm31(0, 1, 2, 3) }; - let sample1 = PointSample { point: QM31_CIRCLE_GEN.mul(2), value: qm31(1, 2, 3, 4) }; + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let sample0 = PointSample { point: p0, value: qm31(0, 1, 2, 3) }; + let sample1 = PointSample { point: p1, value: qm31(1, 2, 3, 4) }; let col0_samples = array![sample0, sample1]; let col1_samples = array![sample0]; let samples_per_column = array![col0_samples, col1_samples]; @@ -662,9 +665,11 @@ mod tests { #[test] fn test_quotient_denominator_inverses() { let domain = CircleDomainImpl::new(CosetImpl::new(CirclePointIndexImpl::new(1), 0)); + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; let samples = array![ - ColumnSampleBatch { point: QM31_CIRCLE_GEN, columns_and_values: array![] }, - ColumnSampleBatch { point: QM31_CIRCLE_GEN.mul(2), columns_and_values: array![] }, + ColumnSampleBatch { point: p0, columns_and_values: array![] }, + ColumnSampleBatch { point: p1, columns_and_values: array![] }, ]; let denominator_inverses = quotient_denominator_inverses(@samples, domain); @@ -681,9 +686,12 @@ mod tests { #[test] fn test_column_sample_batch_group_by_point() { - let sample0 = PointSample { point: QM31_CIRCLE_GEN, value: qm31(0, 1, 2, 3) }; - let sample1 = PointSample { point: QM31_CIRCLE_GEN.mul(2), value: qm31(1, 2, 3, 4) }; - let sample2 = PointSample { point: QM31_CIRCLE_GEN.mul(3), value: qm31(2, 3, 4, 5) }; + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let p2 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let sample0 = PointSample { point: p0, value: qm31(0, 1, 2, 3) }; + let sample1 = PointSample { point: p1, value: qm31(1, 2, 3, 4) }; + let sample2 = PointSample { point: p2, value: qm31(2, 3, 4, 5) }; let col0_samples = array![sample0, sample1, sample2]; let col1_samples = array![sample0]; let col2_samples = array![sample0, sample2]; @@ -717,13 +725,11 @@ mod tests { let column1_query_values = array![m31(1), m31(9)]; let column0_query_values = array![m31(5), m31(3)]; let queried_values_per_column = array![@column0_query_values, @column1_query_values]; + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; let sample_batches = array![ - ColumnSampleBatch { - point: QM31_CIRCLE_GEN, columns_and_values: array![(0, @qm31(0, 1, 2, 3))] - }, - ColumnSampleBatch { - point: QM31_CIRCLE_GEN.mul(2), columns_and_values: array![(1, @qm31(1, 2, 3, 4))] - } + ColumnSampleBatch { point: p0, columns_and_values: array![(0, @qm31(0, 1, 2, 3))] }, + ColumnSampleBatch { point: p1, columns_and_values: array![(1, @qm31(1, 2, 3, 4))] } ]; let quotient_constants = QuotientConstantsImpl::gen(@sample_batches, alpha); let denominator_inverses = quotient_denominator_inverses(@sample_batches, domain); @@ -750,13 +756,11 @@ mod tests { let column1_query_values = array![m31(1), m31(9), m31(2), m31(5)]; let column0_query_values = array![m31(5), m31(3), m31(3), m31(1)]; let queried_values_per_column = array![@column0_query_values, @column1_query_values]; + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; let sample_batches = array![ - ColumnSampleBatch { - point: QM31_CIRCLE_GEN, columns_and_values: array![(0, @qm31(0, 1, 2, 3))] - }, - ColumnSampleBatch { - point: QM31_CIRCLE_GEN.mul(2), columns_and_values: array![(1, @qm31(1, 2, 3, 4))] - } + ColumnSampleBatch { point: p0, columns_and_values: array![(0, @qm31(0, 1, 2, 3))] }, + ColumnSampleBatch { point: p1, columns_and_values: array![(1, @qm31(1, 2, 3, 4))] } ]; let quotient_constants = QuotientConstantsImpl::gen(@sample_batches, alpha); let denominator_inverses = quotient_denominator_inverses(@sample_batches, domain); @@ -796,9 +800,12 @@ mod tests { let query_domain = SparseSubCircleDomain { domains: query_subdomains, large_domain_log_size: log_size }; - let sample0 = PointSample { point: QM31_CIRCLE_GEN, value: qm31(0, 1, 2, 3) }; - let sample1 = PointSample { point: QM31_CIRCLE_GEN.mul(2), value: qm31(1, 2, 3, 4) }; - let sample2 = PointSample { point: QM31_CIRCLE_GEN.mul(3), value: qm31(2, 3, 4, 5) }; + let p0 = QM31_CIRCLE_GEN; + let p1 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let p2 = QM31_CIRCLE_GEN + QM31_CIRCLE_GEN + QM31_CIRCLE_GEN; + let sample0 = PointSample { point: p0, value: qm31(0, 1, 2, 3) }; + let sample1 = PointSample { point: p1, value: qm31(1, 2, 3, 4) }; + let sample2 = PointSample { point: p2, value: qm31(2, 3, 4, 5) }; let col0_samples = array![sample0, sample1, sample2]; let col1_samples = array![sample0]; let col2_samples = array![sample0, sample2]; diff --git a/stwo_cairo_verifier/src/poly/line.cairo b/stwo_cairo_verifier/src/poly/line.cairo index 8f9dc428..dc4863e4 100644 --- a/stwo_cairo_verifier/src/poly/line.cairo +++ b/stwo_cairo_verifier/src/poly/line.cairo @@ -157,21 +157,11 @@ pub struct LineDomain { #[generate_trait] pub impl LineDomainImpl of LineDomainTrait { /// Returns a domain comprising of the x-coordinates of points in a coset. - fn new(coset: Coset) -> LineDomain { - // TODO(andrew): Remove. - // #[cfg(debug)] - // if (coset.size() == 2) { - // // If the coset with two points contains (0, y) then the coset is {(0, y), (0, -y)}. - // assert!(!coset.at(0).x.is_zero(), "coset x-coordinates not unique"); - // } else if (coset.size() > 2) { - // // 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 - // assert!( - // coset.initial_index.to_point().log_order() >= coset.log_size + 2, - // "coset x-coordinates not unique" - // ); - // } + /// + /// # Saftey + /// + /// All coset points must have unique `x` coordinates. + fn new_unchecked(coset: Coset) -> LineDomain { LineDomain { coset: coset } } @@ -273,24 +263,16 @@ mod tests { use stwo_cairo_verifier::fields::qm31::qm31; use super::{LinePoly, LinePolyTrait, LineDomain, LineDomainImpl, LineDomainIterator}; - #[test] - #[should_panic] - fn bad_line_domain() { - // This coset doesn't have points with unique x-coordinates. - let coset = CosetImpl::odds(2); - LineDomainImpl::new(coset); - } - #[test] fn line_domain_of_size_two_works() { let coset = CosetImpl::new(CirclePointIndexImpl::new(0), 1); - LineDomainImpl::new(coset); + LineDomainImpl::new_unchecked(coset); } #[test] fn line_domain_of_size_one_works() { let coset = CosetImpl::new(CirclePointIndexImpl::new(0), 0); - LineDomainImpl::new(coset); + LineDomainImpl::new_unchecked(coset); } #[test] @@ -346,7 +328,7 @@ mod tests { #[test] fn test_evaluate() { let log_size = 3; - let domain = LineDomainImpl::new(CosetImpl::half_odds(log_size)); + let domain = LineDomainImpl::new_unchecked(CosetImpl::half_odds(log_size)); let poly = LinePoly { coeffs: array![ qm31(1, 8, 0, 1), @@ -373,7 +355,7 @@ mod tests { #[test] fn test_evaluate_with_large_domain() { let log_size = 3; - let domain = LineDomainImpl::new(CosetImpl::half_odds(log_size + 2)); + let domain = LineDomainImpl::new_unchecked(CosetImpl::half_odds(log_size + 2)); let poly = LinePoly { coeffs: array![ qm31(1, 8, 0, 1), @@ -399,7 +381,7 @@ mod tests { #[test] fn test_line_domain_iterator() { - let domain = LineDomainImpl::new(CosetImpl::half_odds(3)); + let domain = LineDomainImpl::new_unchecked(CosetImpl::half_odds(3)); let domain_iter = domain.into_iter(); diff --git a/stwo_cairo_verifier/src/queries.cairo b/stwo_cairo_verifier/src/queries.cairo index e7c5feb7..bad69822 100644 --- a/stwo_cairo_verifier/src/queries.cairo +++ b/stwo_cairo_verifier/src/queries.cairo @@ -68,6 +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 mut domains = array![]; let snap_positions = self.positions; let mut already_added = array![]; @@ -78,9 +79,7 @@ pub impl QueriesImpl of QueriesImplTrait { already_added.append(v); domains .append( - SubCircleDomain { - coset_index: v / pow(2, fri_step_size), log_size: fri_step_size - } + SubCircleDomain { coset_index: v / fold_factor, log_size: fri_step_size } ); }