From 64a1b84ac93562ca4ad5e013d685994c14a51bb6 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen <57912727+0xJepsen@users.noreply.github.com> Date: Wed, 8 May 2024 11:01:44 -0600 Subject: [PATCH 1/7] chore: tests + scalar multiplication --- math/curve.sage | 2 +- src/curves/g1_curve.rs | 121 ++++++++++++++++++++++++++++ src/curves/g2_curve.rs | 22 ++++++ src/curves/mod.rs | 173 +++++++++++++++++++++++++++++++++++++++++ src/field/gf_101.rs | 2 +- src/field/gf_101_2.rs | 10 +++ src/lib.rs | 2 +- 7 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 src/curves/g1_curve.rs create mode 100644 src/curves/g2_curve.rs create mode 100644 src/curves/mod.rs diff --git a/math/curve.sage b/math/curve.sage index 517c2b10..85481ac4 100644 --- a/math/curve.sage +++ b/math/curve.sage @@ -36,7 +36,7 @@ K. = GF(101**2, modulus = x^2 + 2) # Curve group over polynomial ring E2 = EllipticCurve(K, [0, 3]) -print(E2.points()) +# print(E2.points()) # G1 is the generator for E1 G1 = E(1,2) diff --git a/src/curves/g1_curve.rs b/src/curves/g1_curve.rs new file mode 100644 index 00000000..cb993a40 --- /dev/null +++ b/src/curves/g1_curve.rs @@ -0,0 +1,121 @@ +use std::ops::Add; + +use crate::field::{gf_101::GF101, FiniteField}; + +use super::CurveParams; + + +/// The Elliptic curve $y^2=x^3+3$, i.e. +/// - a = 0 +/// - b = 3 +/// - generator todo +/// - order todo +/// - field element type todo, but mock with u64 - bad thor, u64 does not implement p3_field +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct C101; + +impl CurveParams for C101 { + type FieldElement = GF101; + + const EQUATION_A: Self::FieldElement = GF101::new(0); + const EQUATION_B: Self::FieldElement = GF101::new(3); + const GENERATOR: (Self::FieldElement, Self::FieldElement) = (GF101::new(1), Self::TWO); + const ORDER: u32 = GF101::ORDER; + const THREE: Self::FieldElement = GF101::new(3); + const TWO: Self::FieldElement = GF101::new(2); +} + +mod test { + use crate::curves::AffinePoint; + +use super::*; +type F = GF101; + + #[test] + fn point_doubling() { + let g = AffinePoint::::generator(); + + let two_g = g.point_doubling(); + let expected_2g = AffinePoint::::new(F::new(68), F::new(74)); + let expected_negative_2g = AffinePoint::::new(F::new(68), F::new(27)); + assert_eq!(two_g, expected_2g); + assert_eq!(-two_g, expected_negative_2g); + + let four_g = two_g.point_doubling(); + let expected_4g = AffinePoint::::new(F::new(65), F::new(98)); + let expected_negative_4g = AffinePoint::::new(F::new(65), F::new(3)); + assert_eq!(four_g, expected_4g); + assert_eq!(-four_g, expected_negative_4g); + + let eight_g = four_g.point_doubling(); + let expected_8g = AffinePoint::::new(F::new(18), F::new(49)); + let expected_negative_8g = AffinePoint::::new(F::new(18), F::new(52)); + assert_eq!(eight_g, expected_8g); + assert_eq!(-eight_g, expected_negative_8g); + + let sixteen_g = eight_g.point_doubling(); + let expected_16g = AffinePoint::::new(F::new(1), F::new(99)); + let expected_negative_16g = AffinePoint::::new(F::new(1), F::new(2)); + assert_eq!(sixteen_g, expected_16g); + assert_eq!(-sixteen_g, expected_negative_16g); + assert_eq!(g, -sixteen_g); + } + + #[test] + fn order_17() { + let g = AffinePoint::::generator(); + let mut g_double = g.point_doubling(); + let mut count = 2; + while g_double != g && -g_double != g { + g_double = g_double.point_doubling(); + count *= 2; + } + assert_eq!(count + 1, 17); + } + + #[test] + fn point_addition() { + let g = AffinePoint::::generator(); + let two_g = g.point_doubling(); + let three_g = g + two_g; + let expected_3g = AffinePoint::::new(F::new(26), F::new(45)); + let expected_negative_3g = AffinePoint::::new(F::new(26), F::new(56)); + assert_eq!(three_g, expected_3g); + assert_eq!(-three_g, expected_negative_3g); + + let four_g = g + three_g; + let expected_4g = AffinePoint::::new(F::new(65), F::new(98)); + let expected_negative_4g = AffinePoint::::new(F::new(65), F::new(3)); + assert_eq!(four_g, expected_4g); + assert_eq!(-four_g, expected_negative_4g); + + let five_g = g + four_g; + let expected_5g = AffinePoint::::new(F::new(12), F::new(32)); + let expected_negative_5g = AffinePoint::::new(F::new(12), F::new(69)); + assert_eq!(five_g, expected_5g); + assert_eq!(-five_g, expected_negative_5g); + + assert_eq!(g + AffinePoint::new_infty(), g); + assert_eq!(AffinePoint::new_infty() + g, g); + assert_eq!(g + (-g), AffinePoint::new_infty()); + } + + #[test] + fn scalar_multiplication_rhs() { + let g = AffinePoint::::generator(); + let two_g = g * 2; + let expected_2g = g.point_doubling(); + assert_eq!(two_g, expected_2g); + assert_eq!(-two_g, -expected_2g); + } + + #[test] + fn scalar_multiplication_lhs() { + let g = AffinePoint::::generator(); + let two_g = 2 * g; + let expected_2g = g.point_doubling(); + assert_eq!(two_g, expected_2g); + assert_eq!(-two_g, -expected_2g); + } +} + diff --git a/src/curves/g2_curve.rs b/src/curves/g2_curve.rs new file mode 100644 index 00000000..9ff907cd --- /dev/null +++ b/src/curves/g2_curve.rs @@ -0,0 +1,22 @@ +use std::ops::Add; +use crate::field::{gf_101::GF101, gf_101_2::QuadraticPlutoField, ExtensionField, FiniteField}; +use super::CurveParams; + + +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct G2Curve {} +// The Elliptic curve $y^2=x^3+3$, i.e. +// - a = 0 +// - b = 3 + +impl CurveParams for G2Curve { + type FieldElement = GF101; + + const EQUATION_A: Self::FieldElement = GF101::new(0); + const EQUATION_B: Self::FieldElement = GF101::new(3); + const GENERATOR: (Self::FieldElement, Self::FieldElement) = (GF101::new(36), GF101::new(31)); + const ORDER: u32 = Self::FieldElement::ORDER; + const THREE: Self::FieldElement = GF101::new(3); + const TWO: Self::FieldElement = GF101::new(2); +} + diff --git a/src/curves/mod.rs b/src/curves/mod.rs new file mode 100644 index 00000000..4c68b776 --- /dev/null +++ b/src/curves/mod.rs @@ -0,0 +1,173 @@ + +use std::{ + fmt, + ops::{Add, Neg}, + }; + + use crate::field::{FiniteField, gf_101::GF101}; + + /// Elliptic curve in Weierstrass form: y^2 = x^3 + ax + b + pub struct Curve { + pub a: F, + pub b: F, + three: F, + two: F, + } + + pub trait CurveParams: 'static + Copy + Clone + fmt::Debug + Default + Eq + Ord { + /// Integer field element type + type FieldElement: FiniteField + Neg; + /// Order of this elliptic curve, i.e. number of elements in the scalar field. + const ORDER: u32; + /// Coefficient `a` in the Weierstrass equation of this elliptic curve. + const EQUATION_A: Self::FieldElement; + /// Coefficient `b` in the Weierstrass equation of this elliptic curve. + const EQUATION_B: Self::FieldElement; + /// Generator of this elliptic curve. + const GENERATOR: (Self::FieldElement, Self::FieldElement); + // hack: 3 and 2 to satisfy the Add trait implementation + const THREE: Self::FieldElement; + const TWO: Self::FieldElement; + + // maybe Curve::uint type is diff from PCP::fieldelement type + // maybe: + // type AffinePoint; + // type ProjectivePoint; + // type Scalar; + } + + /// An Affine Coordinate Point on a Weierstrass elliptic curve +#[derive(Clone, Debug, Copy, PartialEq, Eq)] +pub enum AffinePoint { + XY(C::FieldElement, C::FieldElement), + Infty, +} + +impl AffinePoint { + pub fn new(x: C::FieldElement, y: C::FieldElement) -> Self { + assert_eq!(y * y, x * x * x + C::EQUATION_A * x + C::EQUATION_B, "Point is not on curve"); + Self::XY(x, y) + } + + pub fn new_infty() -> Self { Self::Infty } + + pub fn negate(&mut self) { + match self { + Self::XY(_x, ref mut y) => *y = -*y, + Self::Infty => (), + } + } +} + +impl std::ops::Neg for AffinePoint { + type Output = AffinePoint; + + fn neg(self) -> Self::Output { + let (x, y) = match self { + AffinePoint::XY(x, y) => (x, y), + AffinePoint::Infty => panic!("Cannot double point at infinity"), + }; + AffinePoint::new(x, C::FieldElement::zero() - y) + } +} +/// Scalar multiplication on the rhs: P*(u32) +impl std::ops::Mul for AffinePoint { + type Output = AffinePoint; + + fn mul(self, scalar: u32) -> Self::Output { + let mut result = AffinePoint::new_infty(); + let mut base = self; + let mut exp = scalar; + + while exp > 0 { + if exp % 2 == 1 { + result = result + base; + } + base = base.point_doubling(); + exp /= 2; + } + result + } +} + +/// Scalar multiplication on the Lhs (u32)*P +impl std::ops::Mul> for u32 { + type Output = AffinePoint; + + fn mul(self, rhs: AffinePoint) -> Self::Output { + let mut result = AffinePoint::new_infty(); + let mut base = AffinePoint::generator(); + let mut exp = self; + + while exp > 0 { + if exp % 2 == 1 { + result = result + base; + } + base = base.point_doubling(); + exp /= 2; + } + result + } + +} + +impl Add for AffinePoint { + type Output = AffinePoint; + + fn add(self, rhs: Self) -> Self::Output { + // infty checks + match (self, rhs) { + (AffinePoint::Infty, _) => return rhs, + (_, AffinePoint::Infty) => return self, + + _ => (), + } + let (x1, y1) = match self { + AffinePoint::XY(x, y) => (x, y), + AffinePoint::Infty => unreachable!(), + }; + let (x2, y2) = match rhs { + AffinePoint::XY(x, y) => (x, y), + AffinePoint::Infty => unreachable!(), + }; + if x1 == x2 && y1 == -y2 { + return AffinePoint::new_infty(); + } + // compute new point using elliptic curve point group law + // https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication + let lambda = if x1 == x2 && y1 == y2 { + (C::THREE * x1 * x1 + C::EQUATION_A) / (C::TWO * y1) + } else { + (y2 - y1) / (x2 - x1) + }; + let x = lambda * lambda - x1 - x2; + let y = lambda * (x1 - x) - y1; + AffinePoint::new(x, y) + } +} + +impl AffinePoint { + pub fn point_doubling(mut self) -> AffinePoint { + + let (x, y) = match self { + AffinePoint::XY(x, y) => (x, y), + AffinePoint::Infty => panic!("Cannot double point at infinity"), + }; + // m = 3x^2 / 26 + let m = (C::THREE * x * x) / (C::TWO * y); + + // 2P = (m^2 - 2x, m(3x - m^2)- y) + let x_new = m * m - C::TWO * x; + let y_new = m * (C::THREE * x - m * m) - y; + AffinePoint::new(x_new, y_new) + + } + + pub fn generator() -> Self { + let (x,y) = C::GENERATOR; + AffinePoint::new(x, y) + } +} + + pub mod g1_curve; + pub mod g2_curve; diff --git a/src/field/gf_101.rs b/src/field/gf_101.rs index f525ac63..694bb570 100644 --- a/src/field/gf_101.rs +++ b/src/field/gf_101.rs @@ -3,7 +3,7 @@ use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign}, }; -use std::fmt; +use std::{env::consts, fmt}; use num_bigint::BigUint; use rand::{ diff --git a/src/field/gf_101_2.rs b/src/field/gf_101_2.rs index 320fc7a3..25f63374 100644 --- a/src/field/gf_101_2.rs +++ b/src/field/gf_101_2.rs @@ -316,4 +316,14 @@ mod tests { let res = x.square(); assert_eq!(mul1 * inv_mul, res); } + + #[test] + fn test_generator_order() { + let generator = F2::generator(); + let mut x = generator; + for _ in 1..F2::ORDER { + x *= generator; + } + assert_eq!(x, F2::one()); + } } diff --git a/src/lib.rs b/src/lib.rs index b36f4895..6050a4d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ #![allow(unused_mut)] #![allow(clippy::needless_range_loop)] -pub mod curve; +pub mod curves; pub mod field; pub mod kzg; pub mod polynomial; From 40017512100db891e8df7dd46d8e4f2c6a77ad7c Mon Sep 17 00:00:00 2001 From: Waylon Jepsen <57912727+0xJepsen@users.noreply.github.com> Date: Wed, 8 May 2024 11:06:30 -0600 Subject: [PATCH 2/7] fmt --- src/curves/g1_curve.rs | 14 +++--- src/curves/g2_curve.rs | 5 +-- src/curves/mod.rs | 100 ++++++++++++++++++++--------------------- src/field/gf_101_2.rs | 12 ++--- 4 files changed, 61 insertions(+), 70 deletions(-) diff --git a/src/curves/g1_curve.rs b/src/curves/g1_curve.rs index cb993a40..ed8a4b9f 100644 --- a/src/curves/g1_curve.rs +++ b/src/curves/g1_curve.rs @@ -1,9 +1,7 @@ use std::ops::Add; -use crate::field::{gf_101::GF101, FiniteField}; - use super::CurveParams; - +use crate::field::{gf_101::GF101, FiniteField}; /// The Elliptic curve $y^2=x^3+3$, i.e. /// - a = 0 @@ -26,10 +24,9 @@ impl CurveParams for C101 { } mod test { + use super::*; use crate::curves::AffinePoint; - -use super::*; -type F = GF101; + type F = GF101; #[test] fn point_doubling() { @@ -67,8 +64,8 @@ type F = GF101; let mut g_double = g.point_doubling(); let mut count = 2; while g_double != g && -g_double != g { - g_double = g_double.point_doubling(); - count *= 2; + g_double = g_double.point_doubling(); + count *= 2; } assert_eq!(count + 1, 17); } @@ -118,4 +115,3 @@ type F = GF101; assert_eq!(-two_g, -expected_2g); } } - diff --git a/src/curves/g2_curve.rs b/src/curves/g2_curve.rs index 9ff907cd..f9c42b70 100644 --- a/src/curves/g2_curve.rs +++ b/src/curves/g2_curve.rs @@ -1,7 +1,7 @@ use std::ops::Add; -use crate::field::{gf_101::GF101, gf_101_2::QuadraticPlutoField, ExtensionField, FiniteField}; -use super::CurveParams; +use super::CurveParams; +use crate::field::{gf_101::GF101, gf_101_2::QuadraticPlutoField, ExtensionField, FiniteField}; #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct G2Curve {} @@ -19,4 +19,3 @@ impl CurveParams for G2Curve { const THREE: Self::FieldElement = GF101::new(3); const TWO: Self::FieldElement = GF101::new(2); } - diff --git a/src/curves/mod.rs b/src/curves/mod.rs index 4c68b776..8100e30a 100644 --- a/src/curves/mod.rs +++ b/src/curves/mod.rs @@ -1,42 +1,41 @@ - use std::{ - fmt, - ops::{Add, Neg}, - }; - - use crate::field::{FiniteField, gf_101::GF101}; - - /// Elliptic curve in Weierstrass form: y^2 = x^3 + ax + b - pub struct Curve { - pub a: F, - pub b: F, - three: F, - two: F, - } - - pub trait CurveParams: 'static + Copy + Clone + fmt::Debug + Default + Eq + Ord { - /// Integer field element type - type FieldElement: FiniteField + Neg; - /// Order of this elliptic curve, i.e. number of elements in the scalar field. - const ORDER: u32; - /// Coefficient `a` in the Weierstrass equation of this elliptic curve. - const EQUATION_A: Self::FieldElement; - /// Coefficient `b` in the Weierstrass equation of this elliptic curve. - const EQUATION_B: Self::FieldElement; - /// Generator of this elliptic curve. - const GENERATOR: (Self::FieldElement, Self::FieldElement); - // hack: 3 and 2 to satisfy the Add trait implementation - const THREE: Self::FieldElement; - const TWO: Self::FieldElement; - - // maybe Curve::uint type is diff from PCP::fieldelement type - // maybe: - // type AffinePoint; - // type ProjectivePoint; - // type Scalar; - } + fmt, + ops::{Add, Neg}, +}; + +use crate::field::{gf_101::GF101, FiniteField}; + +/// Elliptic curve in Weierstrass form: y^2 = x^3 + ax + b +pub struct Curve { + pub a: F, + pub b: F, + three: F, + two: F, +} - /// An Affine Coordinate Point on a Weierstrass elliptic curve +pub trait CurveParams: 'static + Copy + Clone + fmt::Debug + Default + Eq + Ord { + /// Integer field element type + type FieldElement: FiniteField + Neg; + /// Order of this elliptic curve, i.e. number of elements in the scalar field. + const ORDER: u32; + /// Coefficient `a` in the Weierstrass equation of this elliptic curve. + const EQUATION_A: Self::FieldElement; + /// Coefficient `b` in the Weierstrass equation of this elliptic curve. + const EQUATION_B: Self::FieldElement; + /// Generator of this elliptic curve. + const GENERATOR: (Self::FieldElement, Self::FieldElement); + // hack: 3 and 2 to satisfy the Add trait implementation + const THREE: Self::FieldElement; + const TWO: Self::FieldElement; + + // maybe Curve::uint type is diff from PCP::fieldelement type + // maybe: + // type AffinePoint; + // type ProjectivePoint; + // type Scalar; +} + +/// An Affine Coordinate Point on a Weierstrass elliptic curve #[derive(Clone, Debug, Copy, PartialEq, Eq)] pub enum AffinePoint { XY(C::FieldElement, C::FieldElement), @@ -60,15 +59,15 @@ impl AffinePoint { } impl std::ops::Neg for AffinePoint { - type Output = AffinePoint; - - fn neg(self) -> Self::Output { - let (x, y) = match self { - AffinePoint::XY(x, y) => (x, y), - AffinePoint::Infty => panic!("Cannot double point at infinity"), - }; - AffinePoint::new(x, C::FieldElement::zero() - y) - } + type Output = AffinePoint; + + fn neg(self) -> Self::Output { + let (x, y) = match self { + AffinePoint::XY(x, y) => (x, y), + AffinePoint::Infty => panic!("Cannot double point at infinity"), + }; + AffinePoint::new(x, C::FieldElement::zero() - y) + } } /// Scalar multiplication on the rhs: P*(u32) impl std::ops::Mul for AffinePoint { @@ -108,7 +107,6 @@ impl std::ops::Mul> for u32 { } result } - } impl Add for AffinePoint { @@ -148,7 +146,6 @@ impl Add for AffinePoint { impl AffinePoint { pub fn point_doubling(mut self) -> AffinePoint { - let (x, y) = match self { AffinePoint::XY(x, y) => (x, y), AffinePoint::Infty => panic!("Cannot double point at infinity"), @@ -160,14 +157,13 @@ impl AffinePoint { let x_new = m * m - C::TWO * x; let y_new = m * (C::THREE * x - m * m) - y; AffinePoint::new(x_new, y_new) - } pub fn generator() -> Self { - let (x,y) = C::GENERATOR; + let (x, y) = C::GENERATOR; AffinePoint::new(x, y) } } - pub mod g1_curve; - pub mod g2_curve; +pub mod g1_curve; +pub mod g2_curve; diff --git a/src/field/gf_101_2.rs b/src/field/gf_101_2.rs index 25f63374..10e27c00 100644 --- a/src/field/gf_101_2.rs +++ b/src/field/gf_101_2.rs @@ -319,11 +319,11 @@ mod tests { #[test] fn test_generator_order() { - let generator = F2::generator(); - let mut x = generator; - for _ in 1..F2::ORDER { - x *= generator; - } - assert_eq!(x, F2::one()); + let generator = F2::generator(); + let mut x = generator; + for _ in 1..F2::ORDER { + x *= generator; + } + assert_eq!(x, F2::one()); } } From 817a74dca76d4f4df857eb09eeca95250ff9fd0c Mon Sep 17 00:00:00 2001 From: Waylon Jepsen <57912727+0xJepsen@users.noreply.github.com> Date: Wed, 8 May 2024 14:39:51 -0600 Subject: [PATCH 3/7] wip: compiles, but generator point is broken --- math/curve.sage | 2 +- src/curves/g2_curve.rs | 37 ++++++++++++++++++++++-------- src/curves/mod.rs | 18 ++++++++++++--- src/field/gf_101.rs | 38 +++++++++++++++---------------- src/field/gf_101_2.rs | 51 ++++++++++++++++++++++-------------------- src/field/mod.rs | 12 +++++----- src/lib.rs | 2 ++ src/polynomial.rs | 14 ++++++------ 8 files changed, 105 insertions(+), 69 deletions(-) diff --git a/math/curve.sage b/math/curve.sage index 85481ac4..517c2b10 100644 --- a/math/curve.sage +++ b/math/curve.sage @@ -36,7 +36,7 @@ K. = GF(101**2, modulus = x^2 + 2) # Curve group over polynomial ring E2 = EllipticCurve(K, [0, 3]) -# print(E2.points()) +print(E2.points()) # G1 is the generator for E1 G1 = E(1,2) diff --git a/src/curves/g2_curve.rs b/src/curves/g2_curve.rs index f9c42b70..a29dbf67 100644 --- a/src/curves/g2_curve.rs +++ b/src/curves/g2_curve.rs @@ -9,13 +9,32 @@ pub struct G2Curve {} // - a = 0 // - b = 3 -impl CurveParams for G2Curve { - type FieldElement = GF101; - - const EQUATION_A: Self::FieldElement = GF101::new(0); - const EQUATION_B: Self::FieldElement = GF101::new(3); - const GENERATOR: (Self::FieldElement, Self::FieldElement) = (GF101::new(36), GF101::new(31)); - const ORDER: u32 = Self::FieldElement::ORDER; - const THREE: Self::FieldElement = GF101::new(3); - const TWO: Self::FieldElement = GF101::new(2); +impl CurveParams for G2Curve { + + type FieldElement = QuadraticPlutoField; + + const EQUATION_A: Self::FieldElement = QuadraticPlutoField::::ZERO; + const EQUATION_B: Self::FieldElement = QuadraticPlutoField::::new(GF101::new(3), GF101::ZERO); + const GENERATOR: (Self::FieldElement, Self::FieldElement) = (QuadraticPlutoField::::new(GF101::new(36), GF101::ZERO), QuadraticPlutoField::::new(GF101::ZERO, GF101::new(31))); + const ORDER: u32 = 289; // extension field subgroup should have order r^2 where r is order of first group + const THREE: QuadraticPlutoField = QuadraticPlutoField::::new(GF101::new(3), GF101::ZERO); + const TWO: QuadraticPlutoField = QuadraticPlutoField::::new(GF101::TWO, GF101::ZERO); + } + + + +mod test { + use crate::curves::AffinePoint; + + use super::*; + + #[test] + fn doubling() { + let g = AffinePoint::::generator(); + println!("g: {:?}", g) + + // want to asset that g = (36, 31*X) + // want to asset that 2g = (90 , 82*X) + } +} \ No newline at end of file diff --git a/src/curves/mod.rs b/src/curves/mod.rs index 8100e30a..5169b0c5 100644 --- a/src/curves/mod.rs +++ b/src/curves/mod.rs @@ -1,6 +1,6 @@ use std::{ fmt, - ops::{Add, Neg}, + ops::{Add, Mul, Neg}, }; use crate::field::{gf_101::GF101, FiniteField}; @@ -12,7 +12,10 @@ pub struct Curve { three: F, two: F, } - +/// +/// Example: +/// say 2 is in GF101 +/// pub trait CurveParams: 'static + Copy + Clone + fmt::Debug + Default + Eq + Ord { /// Integer field element type type FieldElement: FiniteField + Neg; @@ -44,6 +47,11 @@ pub enum AffinePoint { impl AffinePoint { pub fn new(x: C::FieldElement, y: C::FieldElement) -> Self { + println!("X: {:?}, Y: {:?}", x, y); + // okay so this is breaking because the curve equation doesn't know how to plug in polynomials. + // y = 31x -> y^2 = 52x^2 + // x = 36 -> x^3 = 95 + 3 + // 52x^2 = 98 ??? assert_eq!(y * y, x * x * x + C::EQUATION_A * x + C::EQUATION_B, "Point is not on curve"); Self::XY(x, y) } @@ -58,6 +66,9 @@ impl AffinePoint { } } +// Example: +// Base + impl std::ops::Neg for AffinePoint { type Output = AffinePoint; @@ -66,7 +77,7 @@ impl std::ops::Neg for AffinePoint { AffinePoint::XY(x, y) => (x, y), AffinePoint::Infty => panic!("Cannot double point at infinity"), }; - AffinePoint::new(x, C::FieldElement::zero() - y) + AffinePoint::new(x, C::FieldElement::ZERO - y) } } /// Scalar multiplication on the rhs: P*(u32) @@ -161,6 +172,7 @@ impl AffinePoint { pub fn generator() -> Self { let (x, y) = C::GENERATOR; + println!("X: {:?}, Y: {:?}", x, y); AffinePoint::new(x, y) } } diff --git a/src/field/gf_101.rs b/src/field/gf_101.rs index 694bb570..668d92b5 100644 --- a/src/field/gf_101.rs +++ b/src/field/gf_101.rs @@ -32,20 +32,26 @@ impl fmt::Display for GF101 { } impl GF101 { - pub const fn new(value: u32) -> Self { Self { value: to_monty(value) } } + // pub const fn new(value: u32) -> Self { Self { value: to_monty(value) } } + pub const fn new(value: u32) -> Self { Self { value: value % PLUTO_FIELD_PRIME } } + } impl FiniteField for GF101 { type Storage = u32; const ORDER: Self::Storage = PLUTO_FIELD_PRIME; + const ZERO: Self = Self::new(0); + const ONE: Self = Self::new(1); + const TWO: Self = Self::new(2); + const NEG_ONE: Self = Self::new(Self::ORDER -1); fn inverse(&self) -> Option { if self.value == 0 { return None; } let exponent = Self::ORDER - 2; - let mut result = Self::one(); + let mut result = Self::ONE; let mut base = *self; let mut power = exponent; @@ -59,14 +65,6 @@ impl FiniteField for GF101 { Some(result) } - fn zero() -> Self { Self::new(0) } - - fn one() -> Self { Self::new(1) } - - fn two() -> Self { Self::new(2) } - - fn neg_one() -> Self { Self::new(Self::ORDER - 1) } - fn generator() -> Self { Self::new(2) } fn from_canonical_u32(n: u32) -> Self { Self::new(n) } @@ -84,7 +82,7 @@ impl AddAssign for GF101 { impl Sum for GF101 { fn sum>(iter: I) -> Self { - iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) + iter.reduce(|x, y| x + y).unwrap_or(Self::ZERO) } } @@ -106,7 +104,7 @@ impl SubAssign for GF101 { impl Mul for GF101 { type Output = Self; - fn mul(self, rhs: Self) -> Self { Self { value: from_monty(self.value * rhs.value) } } + fn mul(self, rhs: Self) -> Self { Self { value: (self.value * rhs.value) % Self::ORDER } } } impl MulAssign for GF101 { @@ -115,7 +113,7 @@ impl MulAssign for GF101 { impl Product for GF101 { fn product>(iter: I) -> Self { - iter.reduce(|x, y| x * y).unwrap_or(Self::one()) + iter.reduce(|x, y| x * y).unwrap_or(Self::ONE) } } @@ -133,7 +131,7 @@ impl DivAssign for GF101 { impl Neg for GF101 { type Output = Self; - fn neg(self) -> Self::Output { Self::zero() - self } + fn neg(self) -> Self::Output { Self::ZERO - self } } impl Rem for GF101 { @@ -263,7 +261,7 @@ mod tests { #[test] fn halve() { let a = F::new(10); - assert_eq!(a, (a / F::two()) * F::two()); + assert_eq!(a, (a / F::TWO) * F::TWO); } #[test] @@ -315,10 +313,10 @@ mod tests { let x = rng.gen::(); let y = rng.gen::(); let z = rng.gen::(); - assert_eq!(x + (-x), F::zero()); - assert_eq!(-x, F::zero() - x); - assert_eq!(x + x, x * F::two()); - assert_eq!(x, x.div(F::new(2)) * F::two()); + assert_eq!(x + (-x), F::ZERO); + assert_eq!(-x, F::ZERO - x); + assert_eq!(x + x, x * F::TWO); + assert_eq!(x, x.div(F::new(2)) * F::TWO); assert_eq!(x * (-x), -(x * x)); assert_eq!(x + y, y + x); assert_eq!(x * y, y * x); @@ -395,7 +393,7 @@ mod tests { #[test] fn non_zero_element() { let a = GF101::new(10); - assert!(!(a == F::zero())); + assert!(!(a == F::ZERO)); } #[test] diff --git a/src/field/gf_101_2.rs b/src/field/gf_101_2.rs index 10e27c00..ea8bb893 100644 --- a/src/field/gf_101_2.rs +++ b/src/field/gf_101_2.rs @@ -29,6 +29,12 @@ impl QuadraticPlutoField { /// irreducible polynomial used to reduce field polynomials to second degree: /// F[X]/(X^2-2) fn irreducible() -> F { F::from_canonical_u32(2) } + + // const fn from_base(b: F) -> Self { Self { value: [b, F::zero()] } } + + pub const fn new(a: F, b: F) -> Self { + Self { value: [a, b] } + } } impl ExtensionField for QuadraticPlutoField { @@ -36,7 +42,7 @@ impl ExtensionField for QuadraticPlutoField { fn irreducible() -> F { Self::irreducible() } - fn from_base(b: F) -> Self { Self { value: [b, F::zero()] } } + fn from_base(b: F) -> Self { Self { value: [b, F::ZERO] } } } impl From for QuadraticPlutoField { @@ -47,14 +53,11 @@ impl FiniteField for QuadraticPlutoField { type Storage = u32; const ORDER: Self::Storage = QUADRATIC_EXTENSION_FIELD_ORDER; - - fn zero() -> Self { Self { value: [F::zero(); EXT_DEGREE] } } - - fn one() -> Self { Self { value: [F::one(), F::zero()] } } - - fn two() -> Self { Self { value: [F::two(), F::zero()] } } - - fn neg_one() -> Self { Self { value: [F::neg_one(), F::zero()] } } + // fn zero() -> Self { Self { value: [F::zero(); EXT_DEGREE] } } + const ZERO: Self = Self::new(F::ZERO, F::TWO); // TODO: This is wrong + const ONE: Self = Self::new(F::ONE, F::ZERO); + const TWO: Self = Self::new(F::TWO, F::ZERO); + const NEG_ONE: Self = Self::new(F::NEG_ONE, F::ZERO); // field generator: can be verified using sage script // ```sage @@ -73,7 +76,7 @@ impl FiniteField for QuadraticPlutoField { /// Multiply by `a0 - a1 * t` in numerator and denominator. /// Denominator equals `(a0 + a1 * t) * (a0 - a1 * t) = a0.pow(2) - a1.pow(2) * Q::residue()` fn inverse(&self) -> Option { - if *self == Self::zero() { + if *self == Self::ZERO { return None; } @@ -87,7 +90,7 @@ impl FiniteField for QuadraticPlutoField { fn primitive_root_of_unity(n: Self::Storage) -> Self { todo!() } - fn from_canonical_u32(n: u32) -> Self { Self { value: [F::from_canonical_u32(n), F::zero()] } } + fn from_canonical_u32(n: u32) -> Self { Self { value: [F::from_canonical_u32(n), F::ZERO] } } } impl Add for QuadraticPlutoField { @@ -154,13 +157,13 @@ impl SubAssign for QuadraticPlutoField { impl Sum for QuadraticPlutoField { fn sum>(iter: I) -> Self { - iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) + iter.reduce(|x, y| x + y).unwrap_or(Self::ZERO) } } impl Product for QuadraticPlutoField { fn product>(iter: I) -> Self { - iter.reduce(|x, y| x * y).unwrap_or(Self::one()) + iter.reduce(|x, y| x * y).unwrap_or(Self::ONE) } } @@ -212,7 +215,7 @@ impl DivAssign for QuadraticPlutoField { impl Neg for QuadraticPlutoField { type Output = Self; - fn neg(self) -> Self::Output { Self::zero() - self } + fn neg(self) -> Self::Output { Self::ZERO - self } } impl Rem for QuadraticPlutoField { @@ -254,9 +257,9 @@ mod tests { let x = F2::from_base(rng.gen::()); let y = F2::from_base(rng.gen::()); let z = F2::from_base(rng.gen::()); - assert_eq!(x + (-x), F2::zero()); - assert_eq!(-x, F2::zero() - x); - assert_eq!(x + x, x * F2::two()); + assert_eq!(x + (-x), F2::ZERO); + assert_eq!(-x, F2::ZERO - x); + assert_eq!(x + x, x * F2::TWO); assert_eq!(x * (-x), -(x * x)); assert_eq!(x + y, y + x); assert_eq!(x * y, y * x); @@ -284,11 +287,11 @@ mod tests { let x = F2::from_base(rng.gen::()); let y = F2::from_base(rng.gen::()); let z = F2::from_base(rng.gen::()); - assert_eq!(x * x.inverse().unwrap(), F2::one()); - assert_eq!(x.inverse().unwrap_or(F2::one()) * x, F2::one()); + assert_eq!(x * x.inverse().unwrap(), F2::ONE); + assert_eq!(x.inverse().unwrap_or(F2::ONE) * x, F2::ONE); assert_eq!( - x.square().inverse().unwrap_or(F2::one()), - x.inverse().unwrap_or(F2::one()).square() + x.square().inverse().unwrap_or(F2::ONE), + x.inverse().unwrap_or(F2::ONE).square() ); assert_eq!((x / y) * y, x); assert_eq!(x / (y * z), (x / y) / z); @@ -297,7 +300,7 @@ mod tests { #[test] fn test_generator() { - assert_eq!(F2::generator() * F::from_canonical_u32(F::ORDER), F2::zero()); + assert_eq!(F2::generator() * F::from_canonical_u32(F::ORDER), F2::ZERO); } #[test] @@ -308,7 +311,7 @@ mod tests { let add1 = x + y; let sub1 = x - y; - let res = x * F::two(); + let res = x * F::TWO; assert_eq!(add1 + sub1, res); let mul1 = x * y; @@ -324,6 +327,6 @@ mod tests { for _ in 1..F2::ORDER { x *= generator; } - assert_eq!(x, F2::one()); + assert_eq!(x, F2::ONE); } } diff --git a/src/field/mod.rs b/src/field/mod.rs index 5046e3fb..30e7c5fc 100644 --- a/src/field/mod.rs +++ b/src/field/mod.rs @@ -44,10 +44,11 @@ pub trait FiniteField: + Mul + Eq; const ORDER: Self::Storage; - fn zero() -> Self; - fn one() -> Self; - fn two() -> Self; - fn neg_one() -> Self; + const ZERO: Self; + const ONE: Self; + const TWO: Self; + const NEG_ONE: Self; + fn inverse(&self) -> Option; fn from_canonical_u32(n: u32) -> Self; fn generator() -> Self; @@ -57,7 +58,7 @@ pub trait FiniteField: fn pow(&self, power: Self::Storage) -> Self { let mut current = *self; let power: u64 = power.into(); - let mut product = Self::one(); + let mut product = Self::ONE; for j in 0..(64 - power.leading_zeros()) as usize { if (power >> j & 1) != 0 { @@ -85,6 +86,7 @@ pub trait FiniteField: } } +#[const_trait] pub trait ExtensionField: FiniteField + From diff --git a/src/lib.rs b/src/lib.rs index 6050a4d1..68364956 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(const_trait_impl)] #![allow(unused_imports)] #![allow(unused_variables)] #![allow(dead_code)] @@ -7,6 +8,7 @@ #![allow(unused_mut)] #![allow(clippy::needless_range_loop)] + pub mod curves; pub mod field; pub mod kzg; diff --git a/src/polynomial.rs b/src/polynomial.rs index a78f325f..bb796d74 100644 --- a/src/polynomial.rs +++ b/src/polynomial.rs @@ -49,7 +49,7 @@ impl Polynomial { panic!("Nodes must be distinct"); } } - let mut coeffs = [F::one(); N]; + let mut coeffs = [F::ONE; N]; for j in 0..N { coeffs[j] = self.evaluate(nodes.0[j]); } @@ -58,7 +58,7 @@ impl Polynomial { /// Evaluate the polynomial at field element x pub fn evaluate(&self, x: F) -> F { - let mut result = F::zero(); + let mut result = F::ONE; for (i, c) in self.coefficients.into_iter().enumerate() { result += c * x.pow(F::Storage::from(i as u32)); } @@ -70,17 +70,17 @@ impl Polynomial { impl Polynomial, F> { // TODO check that the polynomial degree divides the field order pub fn new(coefficients: [F; N], nodes: [F; N]) -> Self { - let mut weights = [F::one(); N]; + let mut weights = [F::ONE; N]; for j in 0..N { for m in 0..N { if j != m { - weights[j] *= F::one().div(nodes[j] - nodes[m]); + weights[j] *= F::ONE.div(nodes[j] - nodes[m]); } } } // l(x) = \Sigmm_{m}(x-x_m) let l = move |x: F| { - let mut val = F::one(); + let mut val = F::ONE; for i in 0..N { val *= x - nodes[i]; } @@ -89,7 +89,7 @@ impl Polynomial, F> { // L(x) = l(x) * \Sigma_{j=0}^{k} (w_j / (x - x_j)) y_j let L = move |x: F| { - let mut val = F::zero(); + let mut val = F::ONE; for j in 0..N { // check if we are dividing by zero if nodes[j] == x { @@ -125,7 +125,7 @@ impl Polynomial, F> { // It also is the case that the the columns of the inverse matrix are the coefficients of the // Lagrange polynomial basis TODO Finish this. // let nodes = self.basis.nodes; - // let mut evaluations = [F::zero(); N]; + // let mut evaluations = [F::ONE; N]; // // Evaluate the polynomial at N distinct points // for i in 0..N { From abb398e459625caa5f659e87f895f6f78e580bb0 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen <57912727+0xJepsen@users.noreply.github.com> Date: Thu, 9 May 2024 09:38:07 -0600 Subject: [PATCH 4/7] wip --- src/curves/g1_curve.rs | 2 +- src/curves/g2_curve.rs | 34 ++++++++++++++++++++++++++++++++++ src/curves/mod.rs | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/curves/g1_curve.rs b/src/curves/g1_curve.rs index ed8a4b9f..1d893776 100644 --- a/src/curves/g1_curve.rs +++ b/src/curves/g1_curve.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use super::CurveParams; +use super::{CurveParams}; use crate::field::{gf_101::GF101, FiniteField}; /// The Elliptic curve $y^2=x^3+3$, i.e. diff --git a/src/curves/g2_curve.rs b/src/curves/g2_curve.rs index a29dbf67..1aa4d6f4 100644 --- a/src/curves/g2_curve.rs +++ b/src/curves/g2_curve.rs @@ -22,6 +22,39 @@ impl CurveParams for G2Curve { } +// a naive impl with affine point + +impl G2Curve { + + fn to_point(x: QuadraticPlutoField, y: QuadraticPlutoField) -> (QuadraticPlutoField, QuadraticPlutoField) { + println!("X: {:?}, Y: {:?}", x, y); + // example: plug in (36 + 0x, 0 + 31x) + // curve : y^2=x^3+3, + // check if there are any x terms, if not, element is in base field + let mut LHS = x; + let mut RHS = y; + if x.value[1] != GF101::ZERO { + LHS = x * x * x * (-GF101::new(2)) - Self::EQUATION_B; + } else { + LHS = x * x * x - Self::EQUATION_B; + } + if y.value[1] != GF101::ZERO { + // y has degree two so if there is a x -> there will be an x^2 term which we substitude with -2 since... + // TODO explain this and relationship to embedding degree + RHS = y * y * (-GF101::new(2)); + } else { + RHS = y * y; + } + assert_eq!(LHS, RHS, "Point is not on curve"); + + // (curve_x, curve_y) + todo!() + } +} + + + + mod test { @@ -35,6 +68,7 @@ mod test { println!("g: {:?}", g) // want to asset that g = (36, 31*X) + // right now this ^ fails to construct as it doesn't believe that the generator is a valid point on the curve // want to asset that 2g = (90 , 82*X) } } \ No newline at end of file diff --git a/src/curves/mod.rs b/src/curves/mod.rs index 5169b0c5..3b51b615 100644 --- a/src/curves/mod.rs +++ b/src/curves/mod.rs @@ -5,6 +5,7 @@ use std::{ use crate::field::{gf_101::GF101, FiniteField}; + /// Elliptic curve in Weierstrass form: y^2 = x^3 + ax + b pub struct Curve { pub a: F, From da9fe2d66aead8d2772c1e362c269ccc897a4978 Mon Sep 17 00:00:00 2001 From: Sambhav Date: Thu, 9 May 2024 21:21:53 +0530 Subject: [PATCH 5/7] fix mul, generator and add hardcoded tests (#51) * fix mul, generator and add hardcoded tests * fix generator test --- math/field.sage | 7 +++--- src/field/gf_101_2.rs | 53 +++++++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/math/field.sage b/math/field.sage index 3cdd83e4..ad696947 100644 --- a/math/field.sage +++ b/math/field.sage @@ -54,8 +54,8 @@ F_2 = GF(101 ^ 2, name="t", modulus=P) print("extension field:", F_2, "of order:", F_2.order()) # Primitive element -f_2_primitive_element = F_2.primitive_element() -print("Primitive element of F_2:", f_2_primitive_element, f_2_primitive_element.order()) +f_2_primitive_element = F_2([2, 1]) +print("Primitive element of F_2:", f_2_primitive_element, f_2_primitive_element.multiplicative_order()) # 100th root of unity F_2_order = F_2.order() @@ -65,5 +65,4 @@ quotient = (F_2_order-1)//root_of_unity_order f_2_omega_n = f_2_primitive_element ^ quotient print("The", root_of_unity_order, "th root of unity of extension field is: ", f_2_omega_n) -###################################################################### - +###################################################################### \ No newline at end of file diff --git a/src/field/gf_101_2.rs b/src/field/gf_101_2.rs index ea8bb893..afc32d35 100644 --- a/src/field/gf_101_2.rs +++ b/src/field/gf_101_2.rs @@ -30,11 +30,9 @@ impl QuadraticPlutoField { /// F[X]/(X^2-2) fn irreducible() -> F { F::from_canonical_u32(2) } - // const fn from_base(b: F) -> Self { Self { value: [b, F::zero()] } } + // const fn from_base(b: F) -> Self { Self { value: [b, F::zero()] } } - pub const fn new(a: F, b: F) -> Self { - Self { value: [a, b] } - } + pub const fn new(a: F, b: F) -> Self { Self { value: [a, b] } } } impl ExtensionField for QuadraticPlutoField { @@ -52,12 +50,13 @@ impl From for QuadraticPlutoField { impl FiniteField for QuadraticPlutoField { type Storage = u32; + const NEG_ONE: Self = Self::new(F::NEG_ONE, F::ZERO); + // TODO: This is wrong + const ONE: Self = Self::new(F::ONE, F::ZERO); const ORDER: Self::Storage = QUADRATIC_EXTENSION_FIELD_ORDER; - // fn zero() -> Self { Self { value: [F::zero(); EXT_DEGREE] } } - const ZERO: Self = Self::new(F::ZERO, F::TWO); // TODO: This is wrong - const ONE: Self = Self::new(F::ONE, F::ZERO); const TWO: Self = Self::new(F::TWO, F::ZERO); - const NEG_ONE: Self = Self::new(F::NEG_ONE, F::ZERO); + // fn zero() -> Self { Self { value: [F::zero(); EXT_DEGREE] } } + const ZERO: Self = Self::new(F::ZERO, F::ZERO); // field generator: can be verified using sage script // ```sage @@ -65,12 +64,10 @@ impl FiniteField for QuadraticPlutoField { // Ft. = F[] // P = Ft(t ^ 2 - 2) // F_2 = GF(101 ^ 2, name="t", modulus=P) - // f_2_primitive_element = F_2.primitive_element() + // f_2_primitive_element = F_2([2, 1]) + // assert f_2_primitive_element.multiplicative_order() == 101^2-1 // ``` - fn generator() -> Self { - // TODO: unsure if this is correct or not, research more - Self { value: [F::from_canonical_u32(15), F::from_canonical_u32(20)] } - } + fn generator() -> Self { Self { value: [F::from_canonical_u32(2), F::from_canonical_u32(1)] } } /// Computes the multiplicative inverse of `a`, i.e. 1 / (a0 + a1 * t). /// Multiply by `a0 - a1 * t` in numerator and denominator. @@ -176,7 +173,7 @@ impl Mul for QuadraticPlutoField { let a = self.value; let b = rhs.value; let mut res = Self::default(); - res.value[0] = a[0].clone() * b[0].clone() + a[1].clone() * a[1].clone() * Self::irreducible(); + res.value[0] = a[0].clone() * b[0].clone() + a[1].clone() * b[1].clone() * Self::irreducible(); res.value[1] = a[0].clone() * b[1].clone() + a[1].clone() * b[0].clone(); res } @@ -251,6 +248,27 @@ mod tests { assert_eq!(x_2.value[1], F::new(0)); } + #[test] + fn test_add() { + let a = F2::new(F::new(10), F::new(20)); + let b = F2::new(F::new(20), F::new(10)); + assert_eq!(a + b, F2::new(F::new(30), F::new(30))); + } + + #[test] + fn test_sub() { + let a = F2::new(F::new(10), F::new(20)); + let b = F2::new(F::new(20), F::new(10)); + assert_eq!(a - b, F2::new(F::new(91), F::new(10))); + } + + #[test] + fn test_mul() { + let a = F2::new(F::new(10), F::new(20)); + let b = F2::new(F::new(20), F::new(10)); + assert_eq!(a * b, F2::new(F::new(95), F::new(96))); + } + #[test] fn test_add_sub_neg_mul() { let mut rng = rand::thread_rng(); @@ -289,10 +307,7 @@ mod tests { let z = F2::from_base(rng.gen::()); assert_eq!(x * x.inverse().unwrap(), F2::ONE); assert_eq!(x.inverse().unwrap_or(F2::ONE) * x, F2::ONE); - assert_eq!( - x.square().inverse().unwrap_or(F2::ONE), - x.inverse().unwrap_or(F2::ONE).square() - ); + assert_eq!(x.square().inverse().unwrap_or(F2::ONE), x.inverse().unwrap_or(F2::ONE).square()); assert_eq!((x / y) * y, x); assert_eq!(x / (y * z), (x / y) / z); assert_eq!((x * y) / z, x * (y / z)); @@ -323,7 +338,7 @@ mod tests { #[test] fn test_generator_order() { let generator = F2::generator(); - let mut x = generator; + let mut x = F2::ONE; for _ in 1..F2::ORDER { x *= generator; } From af9e396518e518dc381d61bfa3c1ed1bde078034 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen <57912727+0xJepsen@users.noreply.github.com> Date: Thu, 9 May 2024 09:52:22 -0600 Subject: [PATCH 6/7] wip --- src/curves/g2_curve.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/curves/g2_curve.rs b/src/curves/g2_curve.rs index 1aa4d6f4..65c804f6 100644 --- a/src/curves/g2_curve.rs +++ b/src/curves/g2_curve.rs @@ -26,29 +26,26 @@ impl CurveParams for G2Curve { impl G2Curve { - fn to_point(x: QuadraticPlutoField, y: QuadraticPlutoField) -> (QuadraticPlutoField, QuadraticPlutoField) { + fn on_curve(x: QuadraticPlutoField, y: QuadraticPlutoField) -> (QuadraticPlutoField, QuadraticPlutoField) { println!("X: {:?}, Y: {:?}", x, y); // example: plug in (36 + 0x, 0 + 31x) // curve : y^2=x^3+3, // check if there are any x terms, if not, element is in base field - let mut LHS = x; - let mut RHS = y; + let mut LHS = x * x * x; + let mut RHS = y * y; if x.value[1] != GF101::ZERO { - LHS = x * x * x * (-GF101::new(2)) - Self::EQUATION_B; + LHS = LHS * (-GF101::new(2)) - Self::EQUATION_B; } else { LHS = x * x * x - Self::EQUATION_B; } if y.value[1] != GF101::ZERO { // y has degree two so if there is a x -> there will be an x^2 term which we substitude with -2 since... // TODO explain this and relationship to embedding degree - RHS = y * y * (-GF101::new(2)); - } else { - RHS = y * y; - } + RHS *= -GF101::new(2); + } + LHS -= Self::EQUATION_B; assert_eq!(LHS, RHS, "Point is not on curve"); - - // (curve_x, curve_y) - todo!() + (x, y) } } From c56fc0c004c8d5cda6e7f1222396df96382d0b6d Mon Sep 17 00:00:00 2001 From: Waylon Jepsen <57912727+0xJepsen@users.noreply.github.com> Date: Thu, 9 May 2024 10:36:44 -0600 Subject: [PATCH 7/7] fix: test fails when rng has no inverse --- src/curves/g1_curve.rs | 2 +- src/curves/g2_curve.rs | 114 +++++++++++++++++++++++------------------ src/curves/mod.rs | 7 +-- src/field/gf_101.rs | 7 ++- src/field/gf_101_2.rs | 23 +++++++-- src/lib.rs | 1 - 6 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/curves/g1_curve.rs b/src/curves/g1_curve.rs index 1d893776..ed8a4b9f 100644 --- a/src/curves/g1_curve.rs +++ b/src/curves/g1_curve.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use super::{CurveParams}; +use super::CurveParams; use crate::field::{gf_101::GF101, FiniteField}; /// The Elliptic curve $y^2=x^3+3$, i.e. diff --git a/src/curves/g2_curve.rs b/src/curves/g2_curve.rs index 65c804f6..cb7d44c0 100644 --- a/src/curves/g2_curve.rs +++ b/src/curves/g2_curve.rs @@ -9,63 +9,75 @@ pub struct G2Curve {} // - a = 0 // - b = 3 -impl CurveParams for G2Curve { - - type FieldElement = QuadraticPlutoField; - - const EQUATION_A: Self::FieldElement = QuadraticPlutoField::::ZERO; - const EQUATION_B: Self::FieldElement = QuadraticPlutoField::::new(GF101::new(3), GF101::ZERO); - const GENERATOR: (Self::FieldElement, Self::FieldElement) = (QuadraticPlutoField::::new(GF101::new(36), GF101::ZERO), QuadraticPlutoField::::new(GF101::ZERO, GF101::new(31))); - const ORDER: u32 = 289; // extension field subgroup should have order r^2 where r is order of first group - const THREE: QuadraticPlutoField = QuadraticPlutoField::::new(GF101::new(3), GF101::ZERO); - const TWO: QuadraticPlutoField = QuadraticPlutoField::::new(GF101::TWO, GF101::ZERO); - +impl CurveParams for G2Curve { + type FieldElement = QuadraticPlutoField; + + const EQUATION_A: Self::FieldElement = QuadraticPlutoField::::ZERO; + const EQUATION_B: Self::FieldElement = + QuadraticPlutoField::::new(GF101::new(3), GF101::ZERO); + const GENERATOR: (Self::FieldElement, Self::FieldElement) = ( + QuadraticPlutoField::::new(GF101::new(36), GF101::ZERO), + QuadraticPlutoField::::new(GF101::ZERO, GF101::new(31)), + ); + const ORDER: u32 = 289; + // extension field subgroup should have order r^2 where r is order of first group + const THREE: QuadraticPlutoField = + QuadraticPlutoField::::new(GF101::new(3), GF101::ZERO); + const TWO: QuadraticPlutoField = + QuadraticPlutoField::::new(GF101::TWO, GF101::ZERO); } // a naive impl with affine point impl G2Curve { - - fn on_curve(x: QuadraticPlutoField, y: QuadraticPlutoField) -> (QuadraticPlutoField, QuadraticPlutoField) { - println!("X: {:?}, Y: {:?}", x, y); - // example: plug in (36 + 0x, 0 + 31x) - // curve : y^2=x^3+3, - // check if there are any x terms, if not, element is in base field - let mut LHS = x * x * x; - let mut RHS = y * y; - if x.value[1] != GF101::ZERO { - LHS = LHS * (-GF101::new(2)) - Self::EQUATION_B; - } else { - LHS = x * x * x - Self::EQUATION_B; - } - if y.value[1] != GF101::ZERO { - // y has degree two so if there is a x -> there will be an x^2 term which we substitude with -2 since... - // TODO explain this and relationship to embedding degree - RHS *= -GF101::new(2); - } - LHS -= Self::EQUATION_B; - assert_eq!(LHS, RHS, "Point is not on curve"); - (x, y) + pub fn on_curve( + x: QuadraticPlutoField, + y: QuadraticPlutoField, + ) -> (QuadraticPlutoField, QuadraticPlutoField) { + println!("X: {:?}, Y: {:?}", x, y); + // TODO Continue working on this + // ( x ) ( y ) ( x , y ) + // example: plug in ((36, 0), (0, 31)): (36, 31t) + // x = 36, y = 31t, + // curve : y^2=x^3+3, + + // y = (31t)^2 = 52 * t^2 + // check if there are any x terms, if not, element is in base field + let mut LHS = x; + let mut RHS = y; + if x.value[1] != GF101::ZERO { + LHS = x * x * (-GF101::new(2)) - Self::EQUATION_B; + } else { + LHS = x * x * x - Self::EQUATION_B; } + if y.value[1] != GF101::ZERO { + // y has degree two so if there is a x -> there will be an x^2 term which we substitude with + // -2 since... TODO explain this and relationship to embedding degree + RHS *= -GF101::new(2); + } + // minus + LHS -= Self::EQUATION_B; + assert_eq!(LHS, RHS, "Point is not on curve"); + (x, y) + } } - - - - - mod test { - use crate::curves::AffinePoint; - - use super::*; - - #[test] - fn doubling() { - let g = AffinePoint::::generator(); - println!("g: {:?}", g) - - // want to asset that g = (36, 31*X) - // right now this ^ fails to construct as it doesn't believe that the generator is a valid point on the curve - // want to asset that 2g = (90 , 82*X) - } -} \ No newline at end of file + use super::*; + use crate::curves::AffinePoint; + + // #[test] + // fn on_curve() { + // let gen = G2Curve::on_curve(G2Curve::GENERATOR.0, G2Curve::GENERATOR.1); + // } + + // #[test] + // fn doubling() { + // let g = AffinePoint::::generator(); + // println!("g: {:?}", g) + + // // want to asset that g = (36, 31*X) + // // right now this ^ fails to construct as it doesn't believe that the generator is a valid + // point on the curve // want to asset that 2g = (90 , 82*X) + // } +} diff --git a/src/curves/mod.rs b/src/curves/mod.rs index 3b51b615..96073248 100644 --- a/src/curves/mod.rs +++ b/src/curves/mod.rs @@ -5,7 +5,6 @@ use std::{ use crate::field::{gf_101::GF101, FiniteField}; - /// Elliptic curve in Weierstrass form: y^2 = x^3 + ax + b pub struct Curve { pub a: F, @@ -13,10 +12,8 @@ pub struct Curve { three: F, two: F, } -/// /// Example: /// say 2 is in GF101 -/// pub trait CurveParams: 'static + Copy + Clone + fmt::Debug + Default + Eq + Ord { /// Integer field element type type FieldElement: FiniteField + Neg; @@ -49,9 +46,9 @@ pub enum AffinePoint { impl AffinePoint { pub fn new(x: C::FieldElement, y: C::FieldElement) -> Self { println!("X: {:?}, Y: {:?}", x, y); - // okay so this is breaking because the curve equation doesn't know how to plug in polynomials. + // okay so this is breaking because the curve equation doesn't know how to plug in polynomials. // y = 31x -> y^2 = 52x^2 - // x = 36 -> x^3 = 95 + 3 + // x = 36 -> x^3 = 95 + 3 // 52x^2 = 98 ??? assert_eq!(y * y, x * x * x + C::EQUATION_A * x + C::EQUATION_B, "Point is not on curve"); Self::XY(x, y) diff --git a/src/field/gf_101.rs b/src/field/gf_101.rs index 668d92b5..ef478b9c 100644 --- a/src/field/gf_101.rs +++ b/src/field/gf_101.rs @@ -34,17 +34,16 @@ impl fmt::Display for GF101 { impl GF101 { // pub const fn new(value: u32) -> Self { Self { value: to_monty(value) } } pub const fn new(value: u32) -> Self { Self { value: value % PLUTO_FIELD_PRIME } } - } impl FiniteField for GF101 { type Storage = u32; - const ORDER: Self::Storage = PLUTO_FIELD_PRIME; - const ZERO: Self = Self::new(0); + const NEG_ONE: Self = Self::new(Self::ORDER - 1); const ONE: Self = Self::new(1); + const ORDER: Self::Storage = PLUTO_FIELD_PRIME; const TWO: Self = Self::new(2); - const NEG_ONE: Self = Self::new(Self::ORDER -1); + const ZERO: Self = Self::new(0); fn inverse(&self) -> Option { if self.value == 0 { diff --git a/src/field/gf_101_2.rs b/src/field/gf_101_2.rs index afc32d35..8ef84109 100644 --- a/src/field/gf_101_2.rs +++ b/src/field/gf_101_2.rs @@ -302,9 +302,25 @@ mod tests { #[test] fn test_inv_div() { let mut rng = rand::thread_rng(); - let x = F2::from_base(rng.gen::()); - let y = F2::from_base(rng.gen::()); - let z = F2::from_base(rng.gen::()); + // Loop rng's until we get something with inverse. + let mut x = F2::ZERO; + let mut x_inv = None; + while x_inv.is_none() { + x = F2::from_base(rng.gen::()); + x_inv = x.inverse(); + } + let mut y = F2::ZERO; + let mut y_inv = None; + while y_inv.is_none() { + y = F2::from_base(rng.gen::()); + y_inv = y.inverse(); + } + let mut z = F2::ZERO; + let mut z_inv = None; + while z_inv.is_none() { + z = F2::from_base(rng.gen::()); + z_inv = z.inverse(); + } assert_eq!(x * x.inverse().unwrap(), F2::ONE); assert_eq!(x.inverse().unwrap_or(F2::ONE) * x, F2::ONE); assert_eq!(x.square().inverse().unwrap_or(F2::ONE), x.inverse().unwrap_or(F2::ONE).square()); @@ -335,6 +351,7 @@ mod tests { assert_eq!(mul1 * inv_mul, res); } + // TODO: THIS TEST IS WRONG AND SHOULD BE REWRITTEN #[test] fn test_generator_order() { let generator = F2::generator(); diff --git a/src/lib.rs b/src/lib.rs index 68364956..341159f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ #![allow(unused_mut)] #![allow(clippy::needless_range_loop)] - pub mod curves; pub mod field; pub mod kzg;