From 0a50704caa9de88b2238fd5e2efdd2c1033176f6 Mon Sep 17 00:00:00 2001 From: Nicole Date: Mon, 28 Oct 2024 18:14:18 -0300 Subject: [PATCH 01/10] addition between referenced and non-referenced values --- math/src/circle/point.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/math/src/circle/point.rs b/math/src/circle/point.rs index e4fc6000f..e512eb9e3 100644 --- a/math/src/circle/point.rs +++ b/math/src/circle/point.rs @@ -78,6 +78,24 @@ impl> Add for &CirclePoint { CirclePoint { x, y } } } +impl> Add> for CirclePoint { + type Output = CirclePoint; + fn add(self, rhs: CirclePoint) -> Self::Output { + &self + &rhs + } +} +impl> Add> for &CirclePoint { + type Output = CirclePoint; + fn add(self, rhs: CirclePoint) -> Self::Output { + self + &rhs + } +} +impl> Add<&CirclePoint> for CirclePoint { + type Output = CirclePoint; + fn add(self, rhs: &CirclePoint) -> Self::Output { + &self + rhs + } +} /// Multiplication between a point and a scalar (i.e. group operation repeatedly): /// (x, y) * n = (x ,y) + ... + (x, y) n-times. From a045516f0f022d98f0b4d5f0dc014e154645ee9f Mon Sep 17 00:00:00 2001 From: Nicole Graus Date: Wed, 30 Oct 2024 11:15:13 -0300 Subject: [PATCH 02/10] Update math/src/circle/point.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- math/src/circle/point.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/math/src/circle/point.rs b/math/src/circle/point.rs index e512eb9e3..9c6e0662c 100644 --- a/math/src/circle/point.rs +++ b/math/src/circle/point.rs @@ -102,7 +102,8 @@ impl> Add<&CirclePoint> for CirclePoint { impl> Mul for CirclePoint { type Output = CirclePoint; - fn mul(self, mut scalar: u128) -> Self { + fn mul(self, scalar: u128) -> Self { + let mut scalar = scalar; let mut res = Self::zero(); let mut cur = self; loop { From c00a2236b949a225bc0ea33727864fd0991a5125 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 30 Oct 2024 11:25:02 -0300 Subject: [PATCH 03/10] explain why won't panic --- math/src/circle/polynomial.rs | 7 ++++++- math/src/circle/twiddles.rs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/math/src/circle/polynomial.rs b/math/src/circle/polynomial.rs index 4f1f92527..3017ba184 100644 --- a/math/src/circle/polynomial.rs +++ b/math/src/circle/polynomial.rs @@ -39,6 +39,10 @@ pub fn evaluate_cfft( pub fn interpolate_cfft( mut eval: Vec>, ) -> Vec> { + if eval.len() == 0 { + return vec![FieldElement::::zero()]; + } + // We get the twiddles for the interpolation. let domain_log_2_size: u32 = eval.len().trailing_zeros(); let coset = Coset::new_standard(domain_log_2_size); @@ -53,7 +57,8 @@ pub fn interpolate_cfft( in_place_bit_reverse_permute::>(&mut eval_ordered); // The icfft returns all the coefficients multiplied by 2^n, the length of the evaluations. - // So we multiply every element that outputs the icfft byt the inverse of 2^n to get the actual coefficients. + // So we multiply every element that outputs the icfft by the inverse of 2^n to get the actual coefficients. + // Note that this `unwrap` will never panic because eval.len() != 0. let factor = (FieldElement::::from(eval.len() as u64)) .inv() .unwrap(); diff --git a/math/src/circle/twiddles.rs b/math/src/circle/twiddles.rs index 68fae42fb..6a07804c4 100644 --- a/math/src/circle/twiddles.rs +++ b/math/src/circle/twiddles.rs @@ -45,6 +45,8 @@ pub fn get_twiddles( if config == TwiddlesConfig::Interpolation { // For the interpolation, we need to take the inverse element of each twiddle in the default order. + // We can take inverse being sure that the `unwrap` won't panic because the twiddles are coordinates + // of elements of the coset (or their squares) so they can't be zero. twiddles.iter_mut().for_each(|x| { FieldElement::::inplace_batch_inverse(x).unwrap(); }); From e0fa3904aeb98a3146f4a5f73f05c4f801f76287 Mon Sep 17 00:00:00 2001 From: Joaquin Carletti Date: Wed, 30 Oct 2024 11:32:27 -0300 Subject: [PATCH 04/10] add errors.rs --- math/src/circle/errors.rs | 4 ++ math/src/circle/mod.rs | 1 + math/src/circle/point.rs | 129 ++++++++++++++++++-------------------- 3 files changed, 67 insertions(+), 67 deletions(-) create mode 100644 math/src/circle/errors.rs diff --git a/math/src/circle/errors.rs b/math/src/circle/errors.rs new file mode 100644 index 000000000..51dcb720b --- /dev/null +++ b/math/src/circle/errors.rs @@ -0,0 +1,4 @@ +#[derive(Debug)] +pub enum CircleError { + PointDoesntSatisfyCircleEquation, +} diff --git a/math/src/circle/mod.rs b/math/src/circle/mod.rs index f5a65721f..ac576194f 100644 --- a/math/src/circle/mod.rs +++ b/math/src/circle/mod.rs @@ -1,5 +1,6 @@ pub mod cfft; pub mod cosets; +pub mod errors; pub mod point; pub mod polynomial; pub mod twiddles; diff --git a/math/src/circle/point.rs b/math/src/circle/point.rs index 9c6e0662c..24759a043 100644 --- a/math/src/circle/point.rs +++ b/math/src/circle/point.rs @@ -1,3 +1,4 @@ +use super::errors::CircleError; use crate::field::traits::IsField; use crate::field::{ element::FieldElement, @@ -9,16 +10,73 @@ use core::ops::{Add, Mul}; /// x in F, y in F and x^2 + y^2 = 1, i.e. the Circle. The operation of the group will have /// additive notation and is as follows: /// (a, b) + (c, d) = (a * c - b * d, a * d + b * c) - #[derive(Debug, Clone)] pub struct CirclePoint { pub x: FieldElement, pub y: FieldElement, } -#[derive(Debug)] -pub enum CircleError { - PointDoesntSatisfyCircleEquation, +impl> CirclePoint { + pub fn new(x: FieldElement, y: FieldElement) -> Result { + if x.square() + y.square() == FieldElement::one() { + Ok(Self { x, y }) + } else { + Err(CircleError::PointDoesntSatisfyCircleEquation) + } + } + + /// Neutral element of the Circle group (with additive notation). + pub fn zero() -> Self { + Self::new(FieldElement::one(), FieldElement::zero()).unwrap() + } + + /// Computes 2(x, y) = (2x^2 - 1, 2xy). + pub fn double(self) -> Self { + Self::new( + self.x.square().double() - FieldElement::one(), + self.x.double() * self.y, + ) + .unwrap() + } + + /// Computes 2^n * (x, y). + pub fn repeated_double(self, n: u32) -> Self { + let mut res = self; + for _ in 0..n { + res = res.double(); + } + res + } + + /// Computes the inverse of the point. + /// We are using -(x, y) = (x, -y), i.e. the inverse of the group opertion is conjugation + /// because the norm of every point in the circle is one. + pub fn conjugate(self) -> Self { + Self { + x: self.x, + y: -self.y, + } + } + + pub fn antipode(self) -> Self { + Self { + x: -self.x, + y: -self.y, + } + } + + pub const GENERATOR: Self = Self { + x: F::CIRCLE_GENERATOR_X, + y: F::CIRCLE_GENERATOR_Y, + }; + + /// Returns the generator of the subgroup of order n = 2^log_2_size. + /// We are using that 2^k * g is a generator of the subgroup of order 2^{31 - k}. + pub fn get_generator_of_subgroup(log_2_size: u32) -> Self { + Self::GENERATOR.repeated_double(31 - log_2_size) + } + + pub const ORDER: u128 = F::ORDER; } /// Parameters of the base field that we'll need to define its Circle. @@ -119,69 +177,6 @@ impl> Mul for CirclePoint { } } -impl> CirclePoint { - pub fn new(x: FieldElement, y: FieldElement) -> Result { - if x.square() + y.square() == FieldElement::one() { - Ok(Self { x, y }) - } else { - Err(CircleError::PointDoesntSatisfyCircleEquation) - } - } - - /// Neutral element of the Circle group (with additive notation). - pub fn zero() -> Self { - Self::new(FieldElement::one(), FieldElement::zero()).unwrap() - } - - /// Computes 2(x, y) = (2x^2 - 1, 2xy). - pub fn double(self) -> Self { - Self::new( - self.x.square().double() - FieldElement::one(), - self.x.double() * self.y, - ) - .unwrap() - } - - /// Computes 2^n * (x, y). - pub fn repeated_double(self, n: u32) -> Self { - let mut res = self; - for _ in 0..n { - res = res.double(); - } - res - } - - /// Computes the inverse of the point. - /// We are using -(x, y) = (x, -y), i.e. the inverse of the group opertion is conjugation - /// because the norm of every point in the circle is one. - pub fn conjugate(self) -> Self { - Self { - x: self.x, - y: -self.y, - } - } - - pub fn antipode(self) -> Self { - Self { - x: -self.x, - y: -self.y, - } - } - - pub const GENERATOR: Self = Self { - x: F::CIRCLE_GENERATOR_X, - y: F::CIRCLE_GENERATOR_Y, - }; - - /// Returns the generator of the subgroup of order n = 2^log_2_size. - /// We are using that 2^k * g is a generator of the subgroup of order 2^{31 - k}. - pub fn get_generator_of_subgroup(log_2_size: u32) -> Self { - Self::GENERATOR.repeated_double(31 - log_2_size) - } - - pub const ORDER: u128 = F::ORDER; -} - #[cfg(test)] mod tests { use super::*; From 3ed8ac1f893ab655532fd2ce7e4c29a53dca0318 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 30 Oct 2024 11:47:53 -0300 Subject: [PATCH 05/10] fix vec --- math/src/circle/polynomial.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/math/src/circle/polynomial.rs b/math/src/circle/polynomial.rs index 3017ba184..d9764c475 100644 --- a/math/src/circle/polynomial.rs +++ b/math/src/circle/polynomial.rs @@ -40,7 +40,9 @@ pub fn interpolate_cfft( mut eval: Vec>, ) -> Vec> { if eval.len() == 0 { - return vec![FieldElement::::zero()]; + let mut poly = Vec::new(); + poly.push(FieldElement::::zero()); + return poly; } // We get the twiddles for the interpolation. From a7161f252ea6796518eb4da6afd438c835bd05fa Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 30 Oct 2024 13:15:17 -0300 Subject: [PATCH 06/10] Evaluate and interpolate functions have non-mutable inputs --- math/src/circle/cfft.rs | 2 +- math/src/circle/polynomial.rs | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/math/src/circle/cfft.rs b/math/src/circle/cfft.rs index 3b327a954..5e360b1bf 100644 --- a/math/src/circle/cfft.rs +++ b/math/src/circle/cfft.rs @@ -78,7 +78,7 @@ pub fn icfft( /// This function permutes the slice [0, 2, 4, 6, 7, 5, 3, 1] into [0, 1, 2, 3, 4, 5, 6, 7]. /// TODO: This can be optimized by performing in-place value swapping (WIP). pub fn order_cfft_result_naive( - input: &mut [FieldElement], + input: &[FieldElement], ) -> Vec> { let mut result = Vec::new(); let length = input.len(); diff --git a/math/src/circle/polynomial.rs b/math/src/circle/polynomial.rs index d9764c475..a3ee2fadc 100644 --- a/math/src/circle/polynomial.rs +++ b/math/src/circle/polynomial.rs @@ -16,8 +16,10 @@ use alloc::vec::Vec; /// Note that coeff has to be a vector with length a power of two 2^n. #[cfg(feature = "alloc")] pub fn evaluate_cfft( - mut coeff: Vec>, + coeff: Vec>, ) -> Vec> { + let mut coeff = coeff; + // We get the twiddles for the Evaluation. let domain_log_2_size: u32 = coeff.len().trailing_zeros(); let coset = Coset::new_standard(domain_log_2_size); @@ -29,19 +31,21 @@ pub fn evaluate_cfft( cfft(&mut coeff, twiddles); // The cfft returns the evaluations in a certain order, so we permute them to get the natural order. - order_cfft_result_naive(&mut coeff) + order_cfft_result_naive(&coeff) } /// Interpolates the 2^n evaluations of a two-variables polynomial of degree 2^n - 1 on the points of the standard coset of size 2^n. /// As a result we obtain the coefficients of the polynomial in the basis: {1, y, x, xy, 2xˆ2 -1, 2xˆ2y-y, 2xˆ3-x, 2xˆ3y-xy,...} /// Note that eval has to be a vector of length a power of two 2^n. +/// If the vector of evaluations is empty, it returns an empty vector. #[cfg(feature = "alloc")] pub fn interpolate_cfft( - mut eval: Vec>, + eval: Vec>, ) -> Vec> { - if eval.len() == 0 { - let mut poly = Vec::new(); - poly.push(FieldElement::::zero()); + let mut eval = eval; + + if eval.is_empty() { + let poly: Vec> = Vec::new(); return poly; } @@ -135,8 +139,9 @@ mod tests { expected_result.push(point_eval); } + let input_vec = input.to_vec(); // We evaluate the polynomial using now the cfft. - let result = evaluate_cfft(input.to_vec()); + let result = evaluate_cfft(input_vec); let slice_result: &[FE] = &result; assert_eq!(slice_result, expected_result); From b88794f3cbc55c2a779b3fbfa510f6d7bf7cb5a3 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 30 Oct 2024 13:29:37 -0300 Subject: [PATCH 07/10] fix clippy --- math/src/circle/cfft.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/math/src/circle/cfft.rs b/math/src/circle/cfft.rs index 5e360b1bf..f060e02d6 100644 --- a/math/src/circle/cfft.rs +++ b/math/src/circle/cfft.rs @@ -121,9 +121,9 @@ mod tests { fn ordering_cfft_result_works_for_4_points() { let expected_slice = [FE::from(0), FE::from(1), FE::from(2), FE::from(3)]; - let mut slice = [FE::from(0), FE::from(2), FE::from(3), FE::from(1)]; + let slice = [FE::from(0), FE::from(2), FE::from(3), FE::from(1)]; - let res = order_cfft_result_naive(&mut slice); + let res = order_cfft_result_naive(&slice); assert_eq!(res, expected_slice) } @@ -149,7 +149,7 @@ mod tests { FE::from(15), ]; - let mut slice = [ + let slice = [ FE::from(0), FE::from(2), FE::from(4), @@ -168,7 +168,7 @@ mod tests { FE::from(1), ]; - let res = order_cfft_result_naive(&mut slice); + let res = order_cfft_result_naive(&slice); assert_eq!(res, expected_slice) } From b2e9b9d0948b6c92ee153247bcf66324c136aeb7 Mon Sep 17 00:00:00 2001 From: Nicole Date: Wed, 30 Oct 2024 18:37:49 -0300 Subject: [PATCH 08/10] MulAssign for points and double function takes a reference --- math/src/circle/cosets.rs | 4 +- math/src/circle/point.rs | 177 +++++++++++++++++++++++--------------- 2 files changed, 109 insertions(+), 72 deletions(-) diff --git a/math/src/circle/cosets.rs b/math/src/circle/cosets.rs index 709ea76fc..957097efb 100644 --- a/math/src/circle/cosets.rs +++ b/math/src/circle/cosets.rs @@ -3,8 +3,8 @@ use crate::circle::point::CirclePoint; use crate::field::fields::mersenne31::field::Mersenne31Field; use alloc::vec::Vec; -/// Given g_n, a generator of the subgroup of the circle of size n, -/// and given a shift, that is a another point of the cirvle, +/// Given g_n, a generator of the subgroup of size n of the circle, i.e. , +/// and given a shift, that is a another point of the circle, /// we define the coset shift + which is the set of all the points in /// plus the shift. /// For example, if = {p1, p2, p3, p4}, then g_8 + = {g_8 + p1, g_8 + p2, g_8 + p3, g_8 + p4}. diff --git a/math/src/circle/point.rs b/math/src/circle/point.rs index 24759a043..6676d0e5f 100644 --- a/math/src/circle/point.rs +++ b/math/src/circle/point.rs @@ -1,82 +1,24 @@ -use super::errors::CircleError; use crate::field::traits::IsField; use crate::field::{ element::FieldElement, fields::mersenne31::{extensions::Degree4ExtensionField, field::Mersenne31Field}, }; -use core::ops::{Add, Mul}; +use core::ops::{Add, AddAssign, Mul, MulAssign}; /// Given a Field F, we implement here the Group which consists of all the points (x, y) such as /// x in F, y in F and x^2 + y^2 = 1, i.e. the Circle. The operation of the group will have /// additive notation and is as follows: -/// (a, b) + (c, d) = (a * c - b * d, a * d + b * c) +/// (a, b) + (c, d) = (a * c - b * d, a * d + b * c). + #[derive(Debug, Clone)] pub struct CirclePoint { pub x: FieldElement, pub y: FieldElement, } -impl> CirclePoint { - pub fn new(x: FieldElement, y: FieldElement) -> Result { - if x.square() + y.square() == FieldElement::one() { - Ok(Self { x, y }) - } else { - Err(CircleError::PointDoesntSatisfyCircleEquation) - } - } - - /// Neutral element of the Circle group (with additive notation). - pub fn zero() -> Self { - Self::new(FieldElement::one(), FieldElement::zero()).unwrap() - } - - /// Computes 2(x, y) = (2x^2 - 1, 2xy). - pub fn double(self) -> Self { - Self::new( - self.x.square().double() - FieldElement::one(), - self.x.double() * self.y, - ) - .unwrap() - } - - /// Computes 2^n * (x, y). - pub fn repeated_double(self, n: u32) -> Self { - let mut res = self; - for _ in 0..n { - res = res.double(); - } - res - } - - /// Computes the inverse of the point. - /// We are using -(x, y) = (x, -y), i.e. the inverse of the group opertion is conjugation - /// because the norm of every point in the circle is one. - pub fn conjugate(self) -> Self { - Self { - x: self.x, - y: -self.y, - } - } - - pub fn antipode(self) -> Self { - Self { - x: -self.x, - y: -self.y, - } - } - - pub const GENERATOR: Self = Self { - x: F::CIRCLE_GENERATOR_X, - y: F::CIRCLE_GENERATOR_Y, - }; - - /// Returns the generator of the subgroup of order n = 2^log_2_size. - /// We are using that 2^k * g is a generator of the subgroup of order 2^{31 - k}. - pub fn get_generator_of_subgroup(log_2_size: u32) -> Self { - Self::GENERATOR.repeated_double(31 - log_2_size) - } - - pub const ORDER: u128 = F::ORDER; +#[derive(Debug)] +pub enum CircleError { + PointDoesntSatisfyCircleEquation, } /// Parameters of the base field that we'll need to define its Circle. @@ -136,7 +78,7 @@ impl> Add for &CirclePoint { CirclePoint { x, y } } } -impl> Add> for CirclePoint { +impl> Add for CirclePoint { type Output = CirclePoint; fn add(self, rhs: CirclePoint) -> Self::Output { &self + &rhs @@ -154,28 +96,123 @@ impl> Add<&CirclePoint> for CirclePoint { &self + rhs } } +impl> AddAssign<&CirclePoint> for CirclePoint { + fn add_assign(&mut self, rhs: &CirclePoint) { + *self = &*self + rhs; + } +} +impl> AddAssign> for CirclePoint { + fn add_assign(&mut self, rhs: CirclePoint) { + *self += &rhs; + } +} /// Multiplication between a point and a scalar (i.e. group operation repeatedly): /// (x, y) * n = (x ,y) + ... + (x, y) n-times. -impl> Mul for CirclePoint { +impl> Mul for &CirclePoint { type Output = CirclePoint; - fn mul(self, scalar: u128) -> Self { + fn mul(self, scalar: u128) -> Self::Output { let mut scalar = scalar; - let mut res = Self::zero(); - let mut cur = self; + let mut res = CirclePoint::::zero(); + let mut cur = self.clone(); loop { if scalar == 0 { return res; } if scalar & 1 == 1 { - res = &res + &cur; + res += &cur; } cur = cur.double(); scalar >>= 1; } } } +impl> Mul for CirclePoint { + type Output = CirclePoint; + fn mul(self, scalar: u128) -> Self::Output { + &self * scalar + } +} +impl> MulAssign for CirclePoint { + fn mul_assign(&mut self, scalar: u128) { + let mut scalar = scalar; + let mut res = CirclePoint::::zero(); + loop { + if scalar == 0 { + *self = res.clone(); + } + if scalar & 1 == 1 { + res += &*self; + } + *self = self.double(); + scalar >>= 1; + } + } +} + +impl> CirclePoint { + pub fn new(x: FieldElement, y: FieldElement) -> Result { + if x.square() + y.square() == FieldElement::one() { + Ok(Self { x, y }) + } else { + Err(CircleError::PointDoesntSatisfyCircleEquation) + } + } + + /// Neutral element of the Circle group (with additive notation). + pub fn zero() -> Self { + Self::new(FieldElement::one(), FieldElement::zero()).unwrap() + } + + /// Computes 2(x, y) = (2x^2 - 1, 2xy). + pub fn double(&self) -> Self { + Self::new( + self.x.square().double() - FieldElement::one(), + self.x.double() * self.y.clone(), + ) + .unwrap() + } + + /// Computes 2^n * (x, y). + pub fn repeated_double(self, n: u32) -> Self { + let mut res = self; + for _ in 0..n { + res = res.double(); + } + res + } + + /// Computes the inverse of the point. + /// We are using -(x, y) = (x, -y), i.e. the inverse of the group opertion is conjugation + /// because the norm of every point in the circle is one. + pub fn conjugate(self) -> Self { + Self { + x: self.x, + y: -self.y, + } + } + + pub fn antipode(self) -> Self { + Self { + x: -self.x, + y: -self.y, + } + } + + pub const GENERATOR: Self = Self { + x: F::CIRCLE_GENERATOR_X, + y: F::CIRCLE_GENERATOR_Y, + }; + + /// Returns the generator of the subgroup of order n = 2^log_2_size. + /// We are using that 2^k * g is a generator of the subgroup of order 2^{31 - k}. + pub fn get_generator_of_subgroup(log_2_size: u32) -> Self { + Self::GENERATOR.repeated_double(31 - log_2_size) + } + + pub const ORDER: u128 = F::ORDER; +} #[cfg(test)] mod tests { From 26d60788696944ab121dabd1a6d60c287140606c Mon Sep 17 00:00:00 2001 From: Nicole Date: Thu, 31 Oct 2024 10:29:56 -0300 Subject: [PATCH 09/10] Revert "MulAssign for points and double function takes a reference" This reverts commit b2e9b9d0948b6c92ee153247bcf66324c136aeb7. --- math/src/circle/cosets.rs | 4 +- math/src/circle/point.rs | 177 +++++++++++++++----------------------- 2 files changed, 72 insertions(+), 109 deletions(-) diff --git a/math/src/circle/cosets.rs b/math/src/circle/cosets.rs index 957097efb..709ea76fc 100644 --- a/math/src/circle/cosets.rs +++ b/math/src/circle/cosets.rs @@ -3,8 +3,8 @@ use crate::circle::point::CirclePoint; use crate::field::fields::mersenne31::field::Mersenne31Field; use alloc::vec::Vec; -/// Given g_n, a generator of the subgroup of size n of the circle, i.e. , -/// and given a shift, that is a another point of the circle, +/// Given g_n, a generator of the subgroup of the circle of size n, +/// and given a shift, that is a another point of the cirvle, /// we define the coset shift + which is the set of all the points in /// plus the shift. /// For example, if = {p1, p2, p3, p4}, then g_8 + = {g_8 + p1, g_8 + p2, g_8 + p3, g_8 + p4}. diff --git a/math/src/circle/point.rs b/math/src/circle/point.rs index 6676d0e5f..24759a043 100644 --- a/math/src/circle/point.rs +++ b/math/src/circle/point.rs @@ -1,24 +1,82 @@ +use super::errors::CircleError; use crate::field::traits::IsField; use crate::field::{ element::FieldElement, fields::mersenne31::{extensions::Degree4ExtensionField, field::Mersenne31Field}, }; -use core::ops::{Add, AddAssign, Mul, MulAssign}; +use core::ops::{Add, Mul}; /// Given a Field F, we implement here the Group which consists of all the points (x, y) such as /// x in F, y in F and x^2 + y^2 = 1, i.e. the Circle. The operation of the group will have /// additive notation and is as follows: -/// (a, b) + (c, d) = (a * c - b * d, a * d + b * c). - +/// (a, b) + (c, d) = (a * c - b * d, a * d + b * c) #[derive(Debug, Clone)] pub struct CirclePoint { pub x: FieldElement, pub y: FieldElement, } -#[derive(Debug)] -pub enum CircleError { - PointDoesntSatisfyCircleEquation, +impl> CirclePoint { + pub fn new(x: FieldElement, y: FieldElement) -> Result { + if x.square() + y.square() == FieldElement::one() { + Ok(Self { x, y }) + } else { + Err(CircleError::PointDoesntSatisfyCircleEquation) + } + } + + /// Neutral element of the Circle group (with additive notation). + pub fn zero() -> Self { + Self::new(FieldElement::one(), FieldElement::zero()).unwrap() + } + + /// Computes 2(x, y) = (2x^2 - 1, 2xy). + pub fn double(self) -> Self { + Self::new( + self.x.square().double() - FieldElement::one(), + self.x.double() * self.y, + ) + .unwrap() + } + + /// Computes 2^n * (x, y). + pub fn repeated_double(self, n: u32) -> Self { + let mut res = self; + for _ in 0..n { + res = res.double(); + } + res + } + + /// Computes the inverse of the point. + /// We are using -(x, y) = (x, -y), i.e. the inverse of the group opertion is conjugation + /// because the norm of every point in the circle is one. + pub fn conjugate(self) -> Self { + Self { + x: self.x, + y: -self.y, + } + } + + pub fn antipode(self) -> Self { + Self { + x: -self.x, + y: -self.y, + } + } + + pub const GENERATOR: Self = Self { + x: F::CIRCLE_GENERATOR_X, + y: F::CIRCLE_GENERATOR_Y, + }; + + /// Returns the generator of the subgroup of order n = 2^log_2_size. + /// We are using that 2^k * g is a generator of the subgroup of order 2^{31 - k}. + pub fn get_generator_of_subgroup(log_2_size: u32) -> Self { + Self::GENERATOR.repeated_double(31 - log_2_size) + } + + pub const ORDER: u128 = F::ORDER; } /// Parameters of the base field that we'll need to define its Circle. @@ -78,7 +136,7 @@ impl> Add for &CirclePoint { CirclePoint { x, y } } } -impl> Add for CirclePoint { +impl> Add> for CirclePoint { type Output = CirclePoint; fn add(self, rhs: CirclePoint) -> Self::Output { &self + &rhs @@ -96,123 +154,28 @@ impl> Add<&CirclePoint> for CirclePoint { &self + rhs } } -impl> AddAssign<&CirclePoint> for CirclePoint { - fn add_assign(&mut self, rhs: &CirclePoint) { - *self = &*self + rhs; - } -} -impl> AddAssign> for CirclePoint { - fn add_assign(&mut self, rhs: CirclePoint) { - *self += &rhs; - } -} /// Multiplication between a point and a scalar (i.e. group operation repeatedly): /// (x, y) * n = (x ,y) + ... + (x, y) n-times. -impl> Mul for &CirclePoint { +impl> Mul for CirclePoint { type Output = CirclePoint; - fn mul(self, scalar: u128) -> Self::Output { + fn mul(self, scalar: u128) -> Self { let mut scalar = scalar; - let mut res = CirclePoint::::zero(); - let mut cur = self.clone(); + let mut res = Self::zero(); + let mut cur = self; loop { if scalar == 0 { return res; } if scalar & 1 == 1 { - res += &cur; + res = &res + &cur; } cur = cur.double(); scalar >>= 1; } } } -impl> Mul for CirclePoint { - type Output = CirclePoint; - fn mul(self, scalar: u128) -> Self::Output { - &self * scalar - } -} -impl> MulAssign for CirclePoint { - fn mul_assign(&mut self, scalar: u128) { - let mut scalar = scalar; - let mut res = CirclePoint::::zero(); - loop { - if scalar == 0 { - *self = res.clone(); - } - if scalar & 1 == 1 { - res += &*self; - } - *self = self.double(); - scalar >>= 1; - } - } -} - -impl> CirclePoint { - pub fn new(x: FieldElement, y: FieldElement) -> Result { - if x.square() + y.square() == FieldElement::one() { - Ok(Self { x, y }) - } else { - Err(CircleError::PointDoesntSatisfyCircleEquation) - } - } - - /// Neutral element of the Circle group (with additive notation). - pub fn zero() -> Self { - Self::new(FieldElement::one(), FieldElement::zero()).unwrap() - } - - /// Computes 2(x, y) = (2x^2 - 1, 2xy). - pub fn double(&self) -> Self { - Self::new( - self.x.square().double() - FieldElement::one(), - self.x.double() * self.y.clone(), - ) - .unwrap() - } - - /// Computes 2^n * (x, y). - pub fn repeated_double(self, n: u32) -> Self { - let mut res = self; - for _ in 0..n { - res = res.double(); - } - res - } - - /// Computes the inverse of the point. - /// We are using -(x, y) = (x, -y), i.e. the inverse of the group opertion is conjugation - /// because the norm of every point in the circle is one. - pub fn conjugate(self) -> Self { - Self { - x: self.x, - y: -self.y, - } - } - - pub fn antipode(self) -> Self { - Self { - x: -self.x, - y: -self.y, - } - } - - pub const GENERATOR: Self = Self { - x: F::CIRCLE_GENERATOR_X, - y: F::CIRCLE_GENERATOR_Y, - }; - - /// Returns the generator of the subgroup of order n = 2^log_2_size. - /// We are using that 2^k * g is a generator of the subgroup of order 2^{31 - k}. - pub fn get_generator_of_subgroup(log_2_size: u32) -> Self { - Self::GENERATOR.repeated_double(31 - log_2_size) - } - - pub const ORDER: u128 = F::ORDER; -} #[cfg(test)] mod tests { From a6738c7af8a693ceb7ef8989544699a5c79edc9a Mon Sep 17 00:00:00 2001 From: Nicole Date: Thu, 31 Oct 2024 10:46:18 -0300 Subject: [PATCH 10/10] MulAssign and AddAssign --- math/src/circle/cosets.rs | 4 +-- math/src/circle/point.rs | 53 ++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/math/src/circle/cosets.rs b/math/src/circle/cosets.rs index 709ea76fc..957097efb 100644 --- a/math/src/circle/cosets.rs +++ b/math/src/circle/cosets.rs @@ -3,8 +3,8 @@ use crate::circle::point::CirclePoint; use crate::field::fields::mersenne31::field::Mersenne31Field; use alloc::vec::Vec; -/// Given g_n, a generator of the subgroup of the circle of size n, -/// and given a shift, that is a another point of the cirvle, +/// Given g_n, a generator of the subgroup of size n of the circle, i.e. , +/// and given a shift, that is a another point of the circle, /// we define the coset shift + which is the set of all the points in /// plus the shift. /// For example, if = {p1, p2, p3, p4}, then g_8 + = {g_8 + p1, g_8 + p2, g_8 + p3, g_8 + p4}. diff --git a/math/src/circle/point.rs b/math/src/circle/point.rs index 24759a043..e0e7aa210 100644 --- a/math/src/circle/point.rs +++ b/math/src/circle/point.rs @@ -4,7 +4,7 @@ use crate::field::{ element::FieldElement, fields::mersenne31::{extensions::Degree4ExtensionField, field::Mersenne31Field}, }; -use core::ops::{Add, Mul}; +use core::ops::{Add, AddAssign, Mul, MulAssign}; /// Given a Field F, we implement here the Group which consists of all the points (x, y) such as /// x in F, y in F and x^2 + y^2 = 1, i.e. the Circle. The operation of the group will have @@ -31,10 +31,10 @@ impl> CirclePoint { } /// Computes 2(x, y) = (2x^2 - 1, 2xy). - pub fn double(self) -> Self { + pub fn double(&self) -> Self { Self::new( self.x.square().double() - FieldElement::one(), - self.x.double() * self.y, + self.x.double() * self.y.clone(), ) .unwrap() } @@ -129,14 +129,13 @@ impl> PartialEq for CirclePoint { /// (a, b) + (c, d) = (a * c - b * d, a * d + b * c) impl> Add for &CirclePoint { type Output = CirclePoint; - fn add(self, other: Self) -> Self::Output { let x = &self.x * &other.x - &self.y * &other.y; let y = &self.x * &other.y + &self.y * &other.x; CirclePoint { x, y } } } -impl> Add> for CirclePoint { +impl> Add for CirclePoint { type Output = CirclePoint; fn add(self, rhs: CirclePoint) -> Self::Output { &self + &rhs @@ -154,28 +153,58 @@ impl> Add<&CirclePoint> for CirclePoint { &self + rhs } } - +impl> AddAssign<&CirclePoint> for CirclePoint { + fn add_assign(&mut self, rhs: &CirclePoint) { + *self = &*self + rhs; + } +} +impl> AddAssign> for CirclePoint { + fn add_assign(&mut self, rhs: CirclePoint) { + *self += &rhs; + } +} /// Multiplication between a point and a scalar (i.e. group operation repeatedly): /// (x, y) * n = (x ,y) + ... + (x, y) n-times. -impl> Mul for CirclePoint { +impl> Mul for &CirclePoint { type Output = CirclePoint; - - fn mul(self, scalar: u128) -> Self { + fn mul(self, scalar: u128) -> Self::Output { let mut scalar = scalar; - let mut res = Self::zero(); - let mut cur = self; + let mut res = CirclePoint::::zero(); + let mut cur = self.clone(); loop { if scalar == 0 { return res; } if scalar & 1 == 1 { - res = &res + &cur; + res += &cur; } cur = cur.double(); scalar >>= 1; } } } +impl> Mul for CirclePoint { + type Output = CirclePoint; + fn mul(self, scalar: u128) -> Self::Output { + &self * scalar + } +} +impl> MulAssign for CirclePoint { + fn mul_assign(&mut self, scalar: u128) { + let mut scalar = scalar; + let mut res = CirclePoint::::zero(); + loop { + if scalar == 0 { + *self = res.clone(); + } + if scalar & 1 == 1 { + res += &*self; + } + *self = self.double(); + scalar >>= 1; + } + } +} #[cfg(test)] mod tests {