diff --git a/ed_on_bls12_381/src/constraints/curves.rs b/ed_on_bls12_381/src/constraints/curves.rs index 9c9f783..f392a01 100644 --- a/ed_on_bls12_381/src/constraints/curves.rs +++ b/ed_on_bls12_381/src/constraints/curves.rs @@ -1,12 +1,17 @@ use crate::*; -use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar; +use ark_r1cs_std::groups::curves::{short_weierstrass::ProjectiveVar, twisted_edwards::AffineVar}; use crate::constraints::FqVar; /// A variable that is the R1CS equivalent of `crate::EdwardsAffine`. -pub type EdwardsVar = AffineVar; +pub type EdwardsVar = AffineVar; + +/// A variable that is the R1CS equivalent of `crate::SWProjective` +pub type SWVar = ProjectiveVar; #[test] fn test() { ark_curve_constraint_tests::curves::te_test::<_, EdwardsVar>().unwrap(); + ark_curve_constraint_tests::curves::sw_test::<_, SWVar>().unwrap(); + ark_curve_constraint_tests::curves::group_test::<_, Fq, EdwardsVar>().unwrap(); } diff --git a/ed_on_bls12_381/src/curves/mod.rs b/ed_on_bls12_381/src/curves/mod.rs index affbba0..433509e 100644 --- a/ed_on_bls12_381/src/curves/mod.rs +++ b/ed_on_bls12_381/src/curves/mod.rs @@ -1,15 +1,21 @@ use crate::{Fq, Fr}; use ark_ec::{ models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + short_weierstrass_jacobian::{ + GroupAffine as SWGroupAffine, GroupProjective as SWGroupProjective, + }, twisted_edwards_extended::{GroupAffine, GroupProjective}, + SWModelParameters, }; use ark_ff::field_new; #[cfg(test)] mod tests; -pub type EdwardsAffine = GroupAffine; -pub type EdwardsProjective = GroupProjective; +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; +pub type SWAffine = SWGroupAffine; +pub type SWProjective = SWGroupProjective; /// `JubJub` is a twisted Edwards curve. These curves have equations of the /// form: ax² + y² = 1 - dx²y². @@ -32,15 +38,29 @@ pub type EdwardsProjective = GroupProjective; /// ``` /// These parameters and the sage script obtained from: /// +/// +/// +/// `jubjub` also has a short Weierstrass curve form, following the +/// form: y² = x³ + A * x + B +/// where +/// +/// A = 52296097456646850916096512823759002727550416093741407922227928430486925478210 +/// B = 48351165704696163914533707656614864561753505123260775585269522553028192119009 +/// +/// We can use the script available +/// [here](https://github.com/zhenfeizhang/bandersnatch/blob/main/bandersnatch/script/jubjub.sage) +/// to convert between the different representations. #[derive(Clone, Default, PartialEq, Eq)] -pub struct EdwardsParameters; +pub struct JubjubParameters; +pub type EdwardsParameters = JubjubParameters; +pub type SWParameters = JubjubParameters; -impl ModelParameters for EdwardsParameters { +impl ModelParameters for JubjubParameters { type BaseField = Fq; type ScalarField = Fr; } -impl TEModelParameters for EdwardsParameters { +impl TEModelParameters for JubjubParameters { /// COEFF_A = -1 #[rustfmt::skip] const COEFF_A: Fq = field_new!(Fq, "-1"); @@ -60,7 +80,7 @@ impl TEModelParameters for EdwardsParameters { /// AFFINE_GENERATOR_COEFFS = (GENERATOR_X, GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); - type MontgomeryModelParameters = EdwardsParameters; + type MontgomeryModelParameters = JubjubParameters; /// Multiplication by `a` is simply negation here. #[inline(always)] @@ -69,7 +89,7 @@ impl TEModelParameters for EdwardsParameters { } } -impl MontgomeryModelParameters for EdwardsParameters { +impl MontgomeryModelParameters for JubjubParameters { /// COEFF_A = 40962 #[rustfmt::skip] const COEFF_A: Fq = field_new!(Fq, "40962"); @@ -77,10 +97,39 @@ impl MontgomeryModelParameters for EdwardsParameters { #[rustfmt::skip] const COEFF_B: Fq = field_new!(Fq, "-40964"); - type TEModelParameters = EdwardsParameters; + type TEModelParameters = JubjubParameters; } #[rustfmt::skip] const GENERATOR_X: Fq = field_new!(Fq, "8076246640662884909881801758704306714034609987455869804520522091855516602923"); #[rustfmt::skip] const GENERATOR_Y: Fq = field_new!(Fq, "13262374693698910701929044844600465831413122818447359594527400194675274060458"); + +impl SWModelParameters for JubjubParameters { + /// COEFF_A = 52296097456646850916096512823759002727550416093741407922227928430486925478210 + #[rustfmt::skip] + const COEFF_A: Self::BaseField = field_new!(Fq, "52296097456646850916096512823759002727550416093741407922227928430486925478210"); + + /// COEFF_B = 48351165704696163914533707656614864561753505123260775585269522553028192119009 + #[rustfmt::skip] + const COEFF_B: Self::BaseField = field_new!(Fq, "48351165704696163914533707656614864561753505123260775585269522553028192119009"); + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR^(-1) mod r = + /// 819310549611346726241370945440405716213240158234039660170669895299022906775 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, "819310549611346726241370945440405716213240158234039660170669895299022906775"); + + /// generators + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (SW_GENERATOR_X, SW_GENERATOR_Y); +} + +/// x coordinate for SW curve generator +#[rustfmt::skip] +const SW_GENERATOR_X: Fq = field_new!(Fq, "33835869156188682335217394949746694649676633840125476177319971163079011318731"); +/// y coordinate for SW curve generator +#[rustfmt::skip] +const SW_GENERATOR_Y: Fq = field_new!(Fq, "43777270878440091394432848052353307184915192688165709016756678962558652055320"); diff --git a/ed_on_bls12_381/src/curves/tests.rs b/ed_on_bls12_381/src/curves/tests.rs index 1ba5d2f..7f7f00e 100644 --- a/ed_on_bls12_381/src/curves/tests.rs +++ b/ed_on_bls12_381/src/curves/tests.rs @@ -1,8 +1,6 @@ use ark_ec::{AffineCurve, ProjectiveCurve}; use ark_ff::{bytes::FromBytes, Zero}; -use ark_std::rand::Rng; -use ark_std::str::FromStr; -use ark_std::test_rng; +use ark_std::{rand::Rng, str::FromStr, test_rng}; use crate::*; @@ -12,7 +10,9 @@ use ark_algebra_test_templates::{curves::*, groups::*}; fn test_projective_curve() { curve_tests::(); - edwards_tests::(); + edwards_tests::(); + montgomery_conversion_test::(); + sw_tests::(); } #[test] @@ -20,8 +20,13 @@ fn test_projective_group() { let mut rng = test_rng(); let a = rng.gen(); let b = rng.gen(); + + let c = rng.gen(); + let d = rng.gen(); + for _i in 0..100 { group_test::(a, b); + group_test::(c, d); } } @@ -37,9 +42,15 @@ fn test_affine_group() { #[test] fn test_generator() { + // edward curve let generator = EdwardsAffine::prime_subgroup_generator(); assert!(generator.is_on_curve()); assert!(generator.is_in_correct_subgroup_assuming_on_curve()); + + // weierstrass curve + let generator = SWAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); } #[test] @@ -103,5 +114,5 @@ fn test_bytes() { #[test] fn test_montgomery_conversion() { - montgomery_conversion_test::(); + montgomery_conversion_test::(); } diff --git a/ed_on_bls12_381/src/fields/tests.rs b/ed_on_bls12_381/src/fields/tests.rs index 6314166..caf55fc 100644 --- a/ed_on_bls12_381/src/fields/tests.rs +++ b/ed_on_bls12_381/src/fields/tests.rs @@ -9,8 +9,7 @@ use ark_std::test_rng; use ark_algebra_test_templates::fields::*; -use ark_std::rand::Rng; -use ark_std::str::FromStr; +use ark_std::{rand::Rng, str::FromStr}; #[test] fn test_fr() { diff --git a/ed_on_bls12_381/src/lib.rs b/ed_on_bls12_381/src/lib.rs index aa6e78c..3aa2a15 100644 --- a/ed_on_bls12_381/src/lib.rs +++ b/ed_on_bls12_381/src/lib.rs @@ -8,14 +8,16 @@ )] #![forbid(unsafe_code)] -//! This library implements a twisted Edwards curve whose base field is the scalar field of the -//! curve BLS12-381. This allows defining cryptographic primitives that use elliptic curves over -//! the scalar field of the latter curve. This curve was generated by Sean Bowe, and is also known -//! as [Jubjub](https://github.com/zkcrypto/jubjub). +//! This library implements a twisted Edwards curve whose base field is the +//! scalar field of the curve BLS12-381. This allows defining cryptographic +//! primitives that use elliptic curves over the scalar field of the latter +//! curve. This curve was generated by Sean Bowe, and is also known as [Jubjub](https://github.com/zkcrypto/jubjub). //! //! Curve information: -//! * Base field: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 -//! * Scalar field: r = 6554484396890773809930967563523245729705921265872317281365359162392183254199 +//! * Base field: q = +//! 52435875175126190479447740508185965837690552500527637822603658699938581184513 +//! * Scalar field: r = +//! 6554484396890773809930967563523245729705921265872317281365359162392183254199 //! * Valuation(q - 1, 2) = 32 //! * Valuation(r - 1, 2) = 1 //! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where diff --git a/ed_on_bls12_381_bandersnatch/src/constraints/curves.rs b/ed_on_bls12_381_bandersnatch/src/constraints/curves.rs index 9c9f783..c563839 100644 --- a/ed_on_bls12_381_bandersnatch/src/constraints/curves.rs +++ b/ed_on_bls12_381_bandersnatch/src/constraints/curves.rs @@ -1,12 +1,15 @@ -use crate::*; -use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar; +use crate::{constraints::FqVar, *}; +use ark_r1cs_std::groups::curves::{short_weierstrass::ProjectiveVar, twisted_edwards::AffineVar}; -use crate::constraints::FqVar; +/// A variable that is the R1CS equivalent of `crate::BandersnatchParameters`. +pub type EdwardsVar = AffineVar; -/// A variable that is the R1CS equivalent of `crate::EdwardsAffine`. -pub type EdwardsVar = AffineVar; +/// A variable that is the R1CS equivalent of `crate::SWProjective` +pub type SWVar = ProjectiveVar; #[test] fn test() { ark_curve_constraint_tests::curves::te_test::<_, EdwardsVar>().unwrap(); + ark_curve_constraint_tests::curves::sw_test::<_, SWVar>().unwrap(); + ark_curve_constraint_tests::curves::group_test::<_, Fq, EdwardsVar>().unwrap(); } diff --git a/ed_on_bls12_381_bandersnatch/src/curves/mod.rs b/ed_on_bls12_381_bandersnatch/src/curves/mod.rs index 7754669..676cc7a 100644 --- a/ed_on_bls12_381_bandersnatch/src/curves/mod.rs +++ b/ed_on_bls12_381_bandersnatch/src/curves/mod.rs @@ -1,26 +1,34 @@ use crate::{Fq, Fr}; use ark_ec::{ models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + short_weierstrass_jacobian::{ + GroupAffine as SWGroupAffine, GroupProjective as SWGroupProjective, + }, twisted_edwards_extended::{GroupAffine, GroupProjective}, + SWModelParameters, }; use ark_ff::{field_new, Field}; + #[cfg(test)] mod tests; -pub type EdwardsAffine = GroupAffine; -pub type EdwardsProjective = GroupProjective; +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +pub type SWAffine = SWGroupAffine; +pub type SWProjective = SWGroupProjective; -/// `banersnatch` is a twisted Edwards curve. These curves have equations of the +/// `bandersnatch` is a twisted Edwards curve. These curves have equations of the /// form: ax² + y² = 1 - dx²y². /// over some base finite field Fq. /// -/// banersnatch's curve equation: -5x² + y² = 1 - dx²y² +/// bandersnatch's curve equation: -5x² + y² = 1 - dx²y² /// /// q = 52435875175126190479447740508185965837690552500527637822603658699938581184513. /// -/// a = 52435875175126190479447740508185965837690552500527637822603658699938581184508. +/// a = -5. /// d = (138827208126141220649022263972958607803/ -/// 171449701953573178309673572579671231137) mod q +/// 171449701953573178309673572579671231137) mod q /// = 45022363124591815672509500913686876175488063829319466900776701791074614335719. /// /// Sage script to calculate these: @@ -32,17 +40,30 @@ pub type EdwardsProjective = GroupProjective; /// ``` /// These parameters and the sage script obtained from: /// +/// +/// bandersnatch also has a short Weierstrass curve form, following the +/// form: y² = x³ + A * x + B +/// where +/// +/// A = 10773120815616481058602537765553212789256758185246796157495669123169359657269 +/// B = 29569587568322301171008055308580903175558631321415017492731745847794083609535 +/// +/// Script to transfer between different curves are available +/// +/// #[derive(Clone, Default, PartialEq, Eq)] -pub struct EdwardsParameters; +pub struct BandersnatchParameters; + +pub type EdwardsParameters = BandersnatchParameters; +pub type SWParameters = BandersnatchParameters; -impl ModelParameters for EdwardsParameters { +impl ModelParameters for BandersnatchParameters { type BaseField = Fq; type ScalarField = Fr; } -impl TEModelParameters for EdwardsParameters { +impl TEModelParameters for BandersnatchParameters { /// COEFF_A = -5 - #[rustfmt::skip] const COEFF_A: Fq = field_new!(Fq, "-5"); /// COEFF_D = (138827208126141220649022263972958607803/ @@ -59,9 +80,10 @@ impl TEModelParameters for EdwardsParameters { const COFACTOR_INV: Fr = field_new!(Fr, "9831726595336160714896451345284868594481866920080427688839802480047265754601"); /// AFFINE_GENERATOR_COEFFS = (GENERATOR_X, GENERATOR_Y) - const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (TE_GENERATOR_X, TE_GENERATOR_Y); - type MontgomeryModelParameters = EdwardsParameters; + type MontgomeryModelParameters = BandersnatchParameters; /// Multiplication by `a` is multiply by `-5`. #[inline(always)] @@ -71,24 +93,56 @@ impl TEModelParameters for EdwardsParameters { } } -impl MontgomeryModelParameters for EdwardsParameters { +impl MontgomeryModelParameters for BandersnatchParameters { /// COEFF_A = 29978822694968839326280996386011761570173833766074948509196803838190355340952 #[rustfmt::skip] const COEFF_A: Fq = field_new!(Fq, "29978822694968839326280996386011761570173833766074948509196803838190355340952"); + /// COEFF_B = 25465760566081946422412445027709227188579564747101592991722834452325077642517 #[rustfmt::skip] const COEFF_B: Fq = field_new!(Fq, "25465760566081946422412445027709227188579564747101592991722834452325077642517"); - type TEModelParameters = EdwardsParameters; + type TEModelParameters = BandersnatchParameters; } -// using the generator from bench.py (in affine form) -// P = BandersnatchPoint( -// 13738737789055671334382939318077718462576533426798874551591468520593954805549, -// 11575885077368931610486103676191793534029821920164915325066801506752632626968, -// 14458123306641001284399433086015669988340559992755622870694102351476334505845, -// C) +// The TE form generator is generated following Zcash's fashion: +// "The generators of G1 and G2 are computed by finding the lexicographically smallest +// valid x-coordinate, and its lexicographically smallest y-coordinate and scaling it +// by the cofactor such that the result is not the point at infinity." +// The SW form generator is the same TE generator converted into SW form, obtained from the scripts: +// + +/// x coordinate for TE curve generator #[rustfmt::skip] -const GENERATOR_X: Fq = field_new!(Fq, "29627151942733444043031429156003786749302466371339015363120350521834195802525"); +const TE_GENERATOR_X: Fq = field_new!(Fq, "18886178867200960497001835917649091219057080094937609519140440539760939937304"); +/// y coordinate for TE curve generator #[rustfmt::skip] -const GENERATOR_Y: Fq = field_new!(Fq, "27488387519748396681411951718153463804682561779047093991696427532072116857978"); +const TE_GENERATOR_Y: Fq = field_new!(Fq, "19188667384257783945677642223292697773471335439753913231509108946878080696678"); +/// x coordinate for SW curve generator +#[rustfmt::skip] +const SW_GENERATOR_X: Fq = field_new!(Fq, "30900340493481298850216505686589334086208278925799850409469406976849338430199"); +/// y coordinate for SW curve generator +#[rustfmt::skip] +const SW_GENERATOR_Y: Fq = field_new!(Fq, "12663882780877899054958035777720958383845500985908634476792678820121468453298"); + +impl SWModelParameters for BandersnatchParameters { + /// COEFF_A = 10773120815616481058602537765553212789256758185246796157495669123169359657269 + #[rustfmt::skip] + const COEFF_A: Self::BaseField = field_new!(Fq, "10773120815616481058602537765553212789256758185246796157495669123169359657269"); + + /// COEFF_B = 29569587568322301171008055308580903175558631321415017492731745847794083609535 + #[rustfmt::skip] + const COEFF_B: Self::BaseField = field_new!(Fq, "29569587568322301171008055308580903175558631321415017492731745847794083609535"); + + /// COFACTOR = 4 + const COFACTOR: &'static [u64] = &[4]; + + /// COFACTOR^(-1) mod r = + /// 9831726595336160714896451345284868594481866920080427688839802480047265754601 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, "9831726595336160714896451345284868594481866920080427688839802480047265754601"); + + /// generators + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (SW_GENERATOR_X, SW_GENERATOR_Y); +} diff --git a/ed_on_bls12_381_bandersnatch/src/curves/tests.rs b/ed_on_bls12_381_bandersnatch/src/curves/tests.rs index 92ee746..e1829c4 100644 --- a/ed_on_bls12_381_bandersnatch/src/curves/tests.rs +++ b/ed_on_bls12_381_bandersnatch/src/curves/tests.rs @@ -8,7 +8,9 @@ use ark_std::{rand::Rng, str::FromStr, test_rng}; fn test_projective_curve() { curve_tests::(); - edwards_tests::(); + edwards_tests::(); + montgomery_conversion_test::(); + sw_tests::(); } #[test] @@ -16,8 +18,13 @@ fn test_projective_group() { let mut rng = test_rng(); let a = rng.gen(); let b = rng.gen(); + + let c = rng.gen(); + let d = rng.gen(); + for _i in 0..100 { group_test::(a, b); + group_test::(c, d); } } @@ -33,13 +40,20 @@ fn test_affine_group() { #[test] fn test_generator() { + // edward curve let generator = EdwardsAffine::prime_subgroup_generator(); assert!(generator.is_on_curve()); assert!(generator.is_in_correct_subgroup_assuming_on_curve()); + + // weierstrass curve + let generator = SWAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); } #[test] fn test_conversion() { + // edward curve let mut rng = test_rng(); let a: EdwardsAffine = rng.gen(); let b: EdwardsAffine = rng.gen(); @@ -52,6 +66,14 @@ fn test_conversion() { .double(); assert_eq!(a_b, a_b2.into_affine()); assert_eq!(a_b.into_projective(), a_b2); + + // weierstrass curve + let mut rng = test_rng(); + let a: SWProjective = rng.gen(); + let b: SWProjective = rng.gen(); + let a_b = { (a + &b).double().double() }; + let a_b2 = (a + &b).double().double(); + assert_eq!(a_b.into_affine(), a_b2.into_affine()); } #[test] @@ -99,5 +121,5 @@ fn test_bytes() { #[test] fn test_montgomery_conversion() { - montgomery_conversion_test::(); + montgomery_conversion_test::(); } diff --git a/ed_on_bls12_381_bandersnatch/src/lib.rs b/ed_on_bls12_381_bandersnatch/src/lib.rs index 93f4ab6..a449955 100644 --- a/ed_on_bls12_381_bandersnatch/src/lib.rs +++ b/ed_on_bls12_381_bandersnatch/src/lib.rs @@ -11,8 +11,8 @@ //! This library implements the Bendersnatch curve, a twisted Edwards curve //! whose base field is the scalar field of the curve BLS12-381. This allows //! defining cryptographic primitives that use elliptic curves over the scalar -//! field of the latter curve. This curve was generated by Simon Masson from Anoma, -//! and Antonio Sanso from Ethereum Foundation, and is also known as [bandersnatch](https://ethresear.ch/t/introducing-bandersnatch-a-fast-elliptic-curve-built-over-the-bls12-381-scalar-field/9957). +//! field of the latter curve. This curve was generated by Simon Masson from +//! Anoma, and Antonio Sanso from Ethereum Foundation, and is also known as [bandersnatch](https://ethresear.ch/t/introducing-bandersnatch-a-fast-elliptic-curve-built-over-the-bls12-381-scalar-field/9957). //! //! See [here](https://github.com/asanso/Bandersnatch/blob/main/README.md) for the specification of the curve. //! There was also a Python implementation [here](https://github.com/asanso/Bandersnatch/).