From f49d75c7d08e8e15a415e273d096614f19a123d4 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Mon, 15 Jul 2024 16:23:57 -0300 Subject: [PATCH] add circle points --- stwo_cairo_verifier/src/circle.cairo | 120 +++++++++++++++++++++++++++ stwo_cairo_verifier/src/lib.cairo | 1 + stwo_cairo_verifier/src/utils.cairo | 31 +++++++ 3 files changed, 152 insertions(+) create mode 100644 stwo_cairo_verifier/src/circle.cairo diff --git a/stwo_cairo_verifier/src/circle.cairo b/stwo_cairo_verifier/src/circle.cairo new file mode 100644 index 000000000..2ba9a3927 --- /dev/null +++ b/stwo_cairo_verifier/src/circle.cairo @@ -0,0 +1,120 @@ +use stwo_cairo_verifier::fields::m31::{M31, m31}; + +pub const M31_CIRCLE_GEN: CirclePointM31 = + CirclePointM31 { x: M31 { inner: 2 }, y: M31 { inner: 1268011823 }, }; + +#[derive(Drop, Copy, Debug, PartialEq, Eq)] +pub struct CirclePointM31 { + pub x: M31, + pub y: M31, +} + +#[generate_trait] +pub impl CirclePointM31Impl of CirclePointM31Trait { + // Returns the neutral element of the circle. + fn zero() -> CirclePointM31 { + CirclePointM31 { x: m31(1), y: m31(0) } + } + + fn mul(self: @CirclePointM31, mut scalar: u32) -> CirclePointM31 { + let mut result = Self::zero(); + let mut cur = *self; + while scalar > 0 { + if scalar & 1 == 1 { + result = result + cur; + } + cur = cur + cur; + scalar = scalar / 2; + }; + result + } +} + +impl CirclePointM31Add of Add { + // The operation of the circle as a group with additive notation. + fn add(lhs: CirclePointM31, rhs: CirclePointM31) -> CirclePointM31 { + CirclePointM31 { x: lhs.x * rhs.x - lhs.y * rhs.y, y: lhs.x * rhs.y + lhs.y * rhs.x } + } +} + +#[cfg(test)] +mod tests { + use super::{M31_CIRCLE_GEN, CirclePointM31, CirclePointM31Impl}; + use stwo_cairo_verifier::fields::m31::m31; + use stwo_cairo_verifier::utils::pow; + + #[test] + fn test_add_1() { + let i = CirclePointM31 { x: m31(0), y: m31(1) }; + let result = i + i; + let expected_result = CirclePointM31 { x: -m31(1), y: m31(0) }; + + assert_eq!(result, expected_result); + } + + #[test] + fn test_add_2() { + let point_1 = CirclePointM31 { x: m31(750649172), y: m31(1991648574) }; + let point_2 = CirclePointM31 { x: m31(1737427771), y: m31(309481134) }; + let result = point_1 + point_2; + let expected_result = CirclePointM31 { x: m31(1476625263), y: m31(1040927458) }; + + assert_eq!(result, expected_result); + } + + #[test] + fn test_zero_1() { + let result = CirclePointM31Impl::zero(); + let expected_result = CirclePointM31 { x: m31(1), y: m31(0) }; + assert_eq!(result, expected_result); + } + + #[test] + fn test_zero_2() { + let point_1 = CirclePointM31 { x: m31(750649172), y: m31(1991648574) }; + let point_2 = CirclePointM31Impl::zero(); + let expected_result = point_1.clone(); + let result = point_1 + point_2; + + assert_eq!(result, expected_result); + } + + #[test] + fn test_mul_1() { + let point_1 = CirclePointM31 { x: m31(750649172), y: m31(1991648574) }; + let result = point_1.mul(5); + let expected_result = point_1 + point_1 + point_1 + point_1 + point_1; + + assert_eq!(result, expected_result); + } + + #[test] + fn test_mul_2() { + let point_1 = CirclePointM31 { x: m31(750649172), y: m31(1991648574) }; + let result = point_1.mul(8); + let mut expected_result = point_1 + point_1; + expected_result = expected_result + expected_result; + expected_result = expected_result + expected_result; + + assert_eq!(result, expected_result); + } + + #[test] + fn test_mul_3() { + let point_1 = CirclePointM31 { x: m31(750649172), y: m31(1991648574) }; + let result = point_1.mul(418776494); + let expected_result = CirclePointM31 { x: m31(1987283985), y: m31(1500510905) }; + + assert_eq!(result, expected_result); + } + + #[test] + fn test_generator_order() { + let mut result = M31_CIRCLE_GEN.mul(pow(2, 30).try_into().unwrap()); + let expected_result = CirclePointM31 { x: -m31(1), y: m31(0) }; + + // Assert `M31_CIRCLE_GEN^{2^30}` equals `-1`. + assert_eq!(expected_result, result); + } +} + diff --git a/stwo_cairo_verifier/src/lib.cairo b/stwo_cairo_verifier/src/lib.cairo index a2525a1f8..25f60c384 100644 --- a/stwo_cairo_verifier/src/lib.cairo +++ b/stwo_cairo_verifier/src/lib.cairo @@ -1,4 +1,5 @@ mod channel; +mod circle; mod fields; mod utils; mod vcs; diff --git a/stwo_cairo_verifier/src/utils.cairo b/stwo_cairo_verifier/src/utils.cairo index 7c25b0a3c..b444247c3 100644 --- a/stwo_cairo_verifier/src/utils.cairo +++ b/stwo_cairo_verifier/src/utils.cairo @@ -80,3 +80,34 @@ pub fn pack4(cur: felt252, values: [BaseField; 4]) -> felt252 { (((cur * M31_SHIFT + x0.into()) * M31_SHIFT + x1.into()) * M31_SHIFT + x2.into()) * M31_SHIFT + 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 +} + +#[cfg(test)] +mod tests { + use super::pow; + + #[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)); + } +} +