Add Pallas and Vesta curves (#21) Co-authored-by: Ying Tong Lai <yingtong@electriccoin.co> Co-authored-by: Daira Hopwood <daira@jacaranda.org> Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu> Co-authored-by: therealyingtong <yingtong@z.cash>
Daira Hopwood daira@jacaranda.org
Thu, 31 Dec 2020 00:56:00 +0000
25 files changed,
840 insertions(+),
10 deletions(-)
jump to
M
Cargo.toml
→
Cargo.toml
@@ -27,6 +27,9 @@
"mnt4_753", "mnt6_753", "ed_on_mnt4_298", + + "pallas", + "vesta", ] [profile.release]
M
README.md
→
README.md
@@ -29,3 +29,7 @@ ### MNT-753 cycle of curves and related curves
* [`ark-mnt4-753`](mnt4_753): Implements the MNT4-753 pairing-friendly curve. This curve forms a pairing-friendly cycle with MNT6-753 * [`ark-mnt6-753`](mnt6_753): Implements the MNT6-753 pairing-friendly curve. This curve forms a pairing-friendly cycle with MNT4-753 * [`ark-ed-on-mnt4-753`](ed_on_mnt4_753): Implements a Twisted Edwards curve atop the scalar field of MNT4-753 + +### [Pasta](https://electriccoin.co/blog/the-pasta-curves-for-halo-2-and-beyond/) cycle of curves +* [`ark-pallas`](pallas): Implements Pallas, a prime-order curve that forms an amicable pair with Vesta +* [`ark-vesta`](vesta): Implements Vesta, a prime-order curve that forms an amicable pair with Pallas
M
curve-tests/src/fields.rs
→
curve-tests/src/fields.rs
@@ -417,20 +417,14 @@
#[derive(Default, Clone, Copy, Debug)] struct DummyFlags; impl Flags for DummyFlags { + const BIT_SIZE: usize = 200; + fn u8_bitmask(&self) -> u8 { 0 } - fn from_u8(_value: u8) -> Self { - DummyFlags - } - - fn from_u8_remove_flags(_value: &mut u8) -> Self { - DummyFlags - } - - fn len() -> usize { - 200 + fn from_u8(_value: u8) -> Option<Self> { + Some(DummyFlags) } }
A
pallas/Cargo.toml
@@ -0,0 +1,36 @@
+[package] +name = "ark-pallas" +version = "0.1.0" +authors = [ "Ying Tong Lai", "Daira Hopwood", "O(1) Labs", "arkworks contributors" ] +description = "The Pallas prime-order elliptic curve" +homepage = "https://arkworks.rs" +repository = "https://github.com/arkworks-rs/curves" +documentation = "https://docs.rs/ark-pallas/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std", default-features = false, optional = true } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +[dev-dependencies] +ark-relations = { git = "https://github.com/arkworks-rs/snark", default-features = false } +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +ark-curve-constraint-tests = { path = "../curve-constraint-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [ "curve" ] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] + +curve = [ "scalar_field", "base_field" ] +scalar_field = [] +base_field = [] +r1cs = [ "base_field", "ark-r1cs-std" ]
A
pallas/src/constraints/curves.rs
@@ -0,0 +1,12 @@
+use crate::*; +use ark_r1cs_std::groups::curves::short_weierstrass::ProjectiveVar; + +use crate::constraints::FBaseVar; + +/// A group element in the Pallas prime-order group. +pub type GVar = ProjectiveVar<PallasParameters, FBaseVar>; + +#[test] +fn test() { + ark_curve_constraint_tests::curves::sw_test::<PallasParameters, GVar>().unwrap(); +}
A
pallas/src/constraints/fields.rs
@@ -0,0 +1,10 @@
+use crate::fq::Fq; +use ark_r1cs_std::fields::fp::FpVar; + +/// A variable that is the R1CS equivalent of `crate::Fq`. +pub type FBaseVar = FpVar<Fq>; + +#[test] +fn test() { + ark_curve_constraint_tests::fields::field_test::<_, _, FBaseVar>().unwrap(); +}
A
pallas/src/constraints/mod.rs
@@ -0,0 +1,107 @@
+//! This module implements the R1CS equivalent of `ark_pallas`. +//! +//! It implements field variables for `crate::Fq`, +//! and group variables for `crate::GroupProjective`. +//! +//! The field underlying these constraints is `crate::Fq`. +//! +//! # Examples +//! +//! One can perform standard algebraic operations on `FBaseVar`: +//! +//! ``` +//! # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { +//! use ark_std::UniformRand; +//! use ark_relations::r1cs::*; +//! use ark_r1cs_std::prelude::*; +//! use ark_pallas::{*, constraints::*}; +//! +//! let cs = ConstraintSystem::<Fq>::new_ref(); +//! // This rng is just for test purposes; do not use it +//! // in real applications. +//! let mut rng = ark_std::test_rng(); +//! +//! // Generate some random `Fq` elements. +//! let a_native = Fq::rand(&mut rng); +//! let b_native = Fq::rand(&mut rng); +//! +//! // Allocate `a_native` and `b_native` as witness variables in `cs`. +//! let a = FBaseVar::new_witness(ark_relations::ns!(cs, "generate_a"), || Ok(a_native))?; +//! let b = FBaseVar::new_witness(ark_relations::ns!(cs, "generate_b"), || Ok(b_native))?; +//! +//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any +//! // constraints or variables. +//! let a_const = FBaseVar::new_constant(ark_relations::ns!(cs, "a_as_constant"), a_native)?; +//! let b_const = FBaseVar::new_constant(ark_relations::ns!(cs, "b_as_constant"), b_native)?; +//! +//! let one = FBaseVar::one(); +//! let zero = FBaseVar::zero(); +//! +//! // Sanity check one + one = two +//! let two = &one + &one + &zero; +//! two.enforce_equal(&one.double()?)?; +//! +//! assert!(cs.is_satisfied()?); +//! +//! // Check that the value of &a + &b is correct. +//! assert_eq!((&a + &b).value()?, a_native + &b_native); +//! +//! // Check that the value of &a * &b is correct. +//! assert_eq!((&a * &b).value()?, a_native * &b_native); +//! +//! // Check that operations on variables and constants are equivalent. +//! (&a + &b).enforce_equal(&(&a_const + &b_const))?; +//! assert!(cs.is_satisfied()?); +//! # Ok(()) +//! # } +//! ``` +//! +//! One can also perform standard algebraic operations on `GVar`: +//! +//! ``` +//! # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { +//! # use ark_std::UniformRand; +//! # use ark_relations::r1cs::*; +//! # use ark_r1cs_std::prelude::*; +//! # use ark_pallas::{*, constraints::*}; +//! +//! # let cs = ConstraintSystem::<Fq>::new_ref(); +//! # let mut rng = ark_std::test_rng(); +//! +//! // Generate some random `Projective` elements. +//! let a_native = Projective::rand(&mut rng); +//! let b_native = Projective::rand(&mut rng); +//! +//! // Allocate `a_native` and `b_native` as witness variables in `cs`. +//! let a = GVar::new_witness(ark_relations::ns!(cs, "a"), || Ok(a_native))?; +//! let b = GVar::new_witness(ark_relations::ns!(cs, "b"), || Ok(b_native))?; +//! +//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any +//! // constraints or variables. +//! let a_const = GVar::new_constant(ark_relations::ns!(cs, "a_as_constant"), a_native)?; +//! let b_const = GVar::new_constant(ark_relations::ns!(cs, "b_as_constant"), b_native)?; +//! +//! // This returns the identity. +//! let zero = GVar::zero(); +//! +//! // Sanity check one + one = two +//! let two_a = &a + &a + &zero; +//! two_a.enforce_equal(&a.double()?)?; +//! +//! assert!(cs.is_satisfied()?); +//! +//! // Check that the value of &a + &b is correct. +//! assert_eq!((&a + &b).value()?, a_native + &b_native); +//! +//! // Check that operations on variables and constants are equivalent. +//! (&a + &b).enforce_equal(&(&a_const + &b_const))?; +//! assert!(cs.is_satisfied()?); +//! # Ok(()) +//! # } +//! ``` + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*;
A
pallas/src/curves/mod.rs
@@ -0,0 +1,49 @@
+use crate::{fq::Fq, fr::Fr}; +use ark_ec::{ + models::{ModelParameters, SWModelParameters}, + short_weierstrass_jacobian::{GroupAffine, GroupProjective}, +}; +use ark_ff::{field_new, Zero}; + +#[cfg(test)] +mod tests; + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub struct PallasParameters; + +impl ModelParameters for PallasParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +pub type Affine = GroupAffine<PallasParameters>; +pub type Projective = GroupProjective<PallasParameters>; + +impl SWModelParameters for PallasParameters { + /// COEFF_A = 0 + const COEFF_A: Fq = field_new!(Fq, "0"); + + /// COEFF_B = 5 + const COEFF_B: Fq = field_new!(Fq, "5"); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[0x1]; + + /// COFACTOR_INV = 1 + const COFACTOR_INV: Fr = field_new!(Fr, "1"); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G_GENERATOR_X, G_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +/// G_GENERATOR_X = -1 +pub const G_GENERATOR_X: Fq = field_new!(Fq, "-1"); + +/// G_GENERATOR_Y = 2 +pub const G_GENERATOR_Y: Fq = field_new!(Fq, "2");
A
pallas/src/curves/tests.rs
@@ -0,0 +1,39 @@
+#![allow(unused_imports)] +use ark_ff::{ + fields::{Field, FpParameters, PrimeField, SquareRootField}, + One, Zero, +}; +use ark_serialize::CanonicalSerialize; +use ark_std::test_rng; + +use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; +use core::ops::{AddAssign, MulAssign}; +use rand::Rng; + +use crate::{Affine, PallasParameters, Projective}; + +use ark_curve_tests::{ + curves::{curve_tests, sw_tests}, + groups::group_test, +}; + +#[test] +fn test_projective_curve() { + curve_tests::<Projective>(); + sw_tests::<PallasParameters>(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a: Projective = rng.gen(); + let b: Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_generator() { + let generator = Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +}
A
pallas/src/fields/fq.rs
@@ -0,0 +1,90 @@
+use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters}, +}; + +pub type Fq = Fp256<FqParameters>; + +pub struct FqParameters; + +impl Fp256Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 32; + + // TWO_ADIC_ROOT_OF_UNITY = GENERATOR^T + // Encoded in Montgomery form, so the value here is (5^T)R mod p. + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0xa28db849bad6dbf0, + 0x9083cd03d3b539df, + 0xfba6b9ca9dc8448e, + 0x3ec928747b89c6da, + ]); +} + +impl ark_ff::fields::FpParameters for FqParameters { + // 28948022309329048855892746252171976963363056481941560715954676764349967630337 + const MODULUS: BigInteger = BigInteger([ + 0x992d30ed00000001, + 0x224698fc094cf91b, + 0x0000000000000000, + 0x4000000000000000, + ]); + + // R = 2^256 mod p + const R: BigInteger = BigInteger([ + 0x34786d38fffffffd, + 0x992c350be41914ad, + 0xffffffffffffffff, + 0x3fffffffffffffff, + ]); + + // R2 = (2^256)^2 mod p + const R2: BigInteger = BigInteger([ + 0x8c78ecb30000000f, + 0xd7d30dbd8b0de0e7, + 0x7797a99bc3c95d18, + 0x096d41af7b9cb714, + ]); + + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xcc96987680000000, + 0x11234c7e04a67c8d, + 0x0000000000000000, + 0x2000000000000000, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + const T: BigInteger = BigInteger([ + 0x094cf91b992d30ed, + 0x00000000224698fc, + 0x0000000000000000, + 0x0000000040000000, + ]); + + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x04a67c8dcc969876, + 0x0000000011234c7e, + 0x0000000000000000, + 0x0000000020000000, + ]); + + // GENERATOR = 5 + // Encoded in Montgomery form, so the value here is 5R mod p. + const GENERATOR: BigInteger = BigInteger([ + 0xa1a55e68ffffffed, + 0x74c2a54b4f4982f3, + 0xfffffffffffffffd, + 0x3fffffffffffffff, + ]); + + const MODULUS_BITS: u32 = 255; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 1; + + // INV = -p^{-1} (mod 2^64) + const INV: u64 = 11037532056220336127; +}
A
pallas/src/fields/fr.rs
@@ -0,0 +1,91 @@
+use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, +}; + +pub struct FrParameters; + +pub type Fr = Fp256<FrParameters>; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 32; + + // TWO_ADIC_ROOT_OF_UNITY = GENERATOR^T + // Encoded in Montgomery form, so the value here is (5^T)R mod q. + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x218077428c9942de, + 0xcc49578921b60494, + 0xac2e5d27b2efbee2, + 0x0b79fa897f2db056, + ]); +} + +impl FpParameters for FrParameters { + // 28948022309329048855892746252171976963363056481941647379679742748393362948097 + const MODULUS: BigInteger = BigInteger([ + 0x8c46eb2100000001, + 0x224698fc0994a8dd, + 0x0000000000000000, + 0x4000000000000000, + ]); + + // R = 2^256 mod q + const R: BigInteger = BigInteger([ + 0x5b2b3e9cfffffffd, + 0x992c350be3420567, + 0xffffffffffffffff, + 0x3fffffffffffffff, + ]); + + // R2 = (2^256)^2 mod q + const R2: BigInteger = BigInteger([ + 0xfc9678ff0000000f, + 0x67bb433d891a16e3, + 0x7fae231004ccf590, + 0x096d41af7ccfdaa9, + ]); + + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xc623759080000000, + 0x11234c7e04ca546e, + 0x0000000000000000, + 0x2000000000000000, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + const T: BigInteger = BigInteger([ + 0x0994a8dd8c46eb21, + 0x00000000224698fc, + 0x0000000000000000, + 0x0000000040000000, + ]); + + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x04ca546ec6237590, + 0x0000000011234c7e, + 0x0000000000000000, + 0x0000000020000000, + ]); + + // GENERATOR = 5 + // Encoded in Montgomery form, so the value here is 5R mod q. + const GENERATOR: BigInteger = BigInteger([ + 0x96bc8c8cffffffed, + 0x74c2a54b49f7778e, + 0xfffffffffffffffd, + 0x3fffffffffffffff, + ]); + + const MODULUS_BITS: u32 = 255; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 1; + + // INV = -q^{-1} (mod 2^64) + const INV: u64 = 10108024940646105087; +}
A
pallas/src/fields/mod.rs
@@ -0,0 +1,12 @@
+#[cfg(feature = "base_field")] +pub mod fq; +#[cfg(feature = "base_field")] +pub use self::fq::*; + +#[cfg(feature = "scalar_field")] +pub mod fr; +#[cfg(feature = "scalar_field")] +pub use self::fr::*; + +#[cfg(all(feature = "curve", test))] +mod tests;
A
pallas/src/fields/tests.rs
@@ -0,0 +1,26 @@
+use ark_std::test_rng; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::<Fr>(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::<Fq>(); +}
A
pallas/src/lib.rs
@@ -0,0 +1,36 @@
+#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the prime-order curve Pallas, generated by +//! [Daira Hopwood](https://github.com/zcash/pasta). The main feature of this +//! curve is that it forms a cycle with Vesta, i.e. its scalar field and base +//! field respectively are the base field and scalar field of Vesta. +//! +//! +//! Curve information: +//! * Base field: q = +//! 28948022309329048855892746252171976963363056481941560715954676764349967630337 +//! * Scalar field: r = +//! 28948022309329048855892746252171976963363056481941647379679742748393362948097 +//! * Curve equation: y^2 = x^3 + 5 +//! * Valuation(q - 1, 2) = 32 +//! * Valuation(r - 1, 2) = 32 + +#[cfg(feature = "r1cs")] +pub mod constraints; +#[cfg(feature = "curve")] +mod curves; +#[cfg(any(feature = "scalar_field", feature = "base_field"))] +mod fields; + +#[cfg(feature = "curve")] +pub use curves::*; +#[cfg(any(feature = "scalar_field", feature = "base_field"))] +pub use fields::*;
A
vesta/Cargo.toml
@@ -0,0 +1,33 @@
+[package] +name = "ark-vesta" +version = "0.1.0" +authors = [ "Ying Tong Lai", "Daira Hopwood", "O(1) Labs", "arkworks contributors" ] +description = "The Vesta prime-order elliptic curve" +homepage = "https://arkworks.rs" +repository = "https://github.com/arkworks-rs/curves" +documentation = "https://docs.rs/ark-vesta/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std", default-features = false, optional = true } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-pallas = { path = "../pallas", default-features = false, features = [ "scalar_field", "base_field" ] } + +[dev-dependencies] +ark-relations = { git = "https://github.com/arkworks-rs/snark", default-features = false } +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +ark-curve-constraint-tests = { path = "../curve-constraint-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] +r1cs = [ "ark-r1cs-std" ]
A
vesta/src/constraints/curves.rs
@@ -0,0 +1,12 @@
+use crate::*; +use ark_r1cs_std::groups::curves::short_weierstrass::ProjectiveVar; + +use crate::constraints::FBaseVar; + +/// A group element in the Vesta prime-order group. +pub type GVar = ProjectiveVar<VestaParameters, FBaseVar>; + +#[test] +fn test() { + ark_curve_constraint_tests::curves::sw_test::<VestaParameters, GVar>().unwrap(); +}
A
vesta/src/constraints/fields.rs
@@ -0,0 +1,10 @@
+use crate::fq::Fq; +use ark_r1cs_std::fields::fp::FpVar; + +/// A variable that is the R1CS equivalent of `crate::Fq`. +pub type FBaseVar = FpVar<Fq>; + +#[test] +fn test() { + ark_curve_constraint_tests::fields::field_test::<_, _, FBaseVar>().unwrap(); +}
A
vesta/src/constraints/mod.rs
@@ -0,0 +1,107 @@
+//! This module implements the R1CS equivalent of `ark_vesta`. +//! +//! It implements field variables for `crate::Fq`, +//! and group variables for `crate::GroupProjective`. +//! +//! The field underlying these constraints is `crate::Fq`. +//! +//! # Examples +//! +//! One can perform standard algebraic operations on `FBaseVar`: +//! +//! ``` +//! # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { +//! use ark_std::UniformRand; +//! use ark_relations::r1cs::*; +//! use ark_r1cs_std::prelude::*; +//! use ark_vesta::{*, constraints::*}; +//! +//! let cs = ConstraintSystem::<Fq>::new_ref(); +//! // This rng is just for test purposes; do not use it +//! // in real applications. +//! let mut rng = ark_std::test_rng(); +//! +//! // Generate some random `Fq` elements. +//! let a_native = Fq::rand(&mut rng); +//! let b_native = Fq::rand(&mut rng); +//! +//! // Allocate `a_native` and `b_native` as witness variables in `cs`. +//! let a = FBaseVar::new_witness(ark_relations::ns!(cs, "generate_a"), || Ok(a_native))?; +//! let b = FBaseVar::new_witness(ark_relations::ns!(cs, "generate_b"), || Ok(b_native))?; +//! +//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any +//! // constraints or variables. +//! let a_const = FBaseVar::new_constant(ark_relations::ns!(cs, "a_as_constant"), a_native)?; +//! let b_const = FBaseVar::new_constant(ark_relations::ns!(cs, "b_as_constant"), b_native)?; +//! +//! let one = FBaseVar::one(); +//! let zero = FBaseVar::zero(); +//! +//! // Sanity check one + one = two +//! let two = &one + &one + &zero; +//! two.enforce_equal(&one.double()?)?; +//! +//! assert!(cs.is_satisfied()?); +//! +//! // Check that the value of &a + &b is correct. +//! assert_eq!((&a + &b).value()?, a_native + &b_native); +//! +//! // Check that the value of &a * &b is correct. +//! assert_eq!((&a * &b).value()?, a_native * &b_native); +//! +//! // Check that operations on variables and constants are equivalent. +//! (&a + &b).enforce_equal(&(&a_const + &b_const))?; +//! assert!(cs.is_satisfied()?); +//! # Ok(()) +//! # } +//! ``` +//! +//! One can also perform standard algebraic operations on `GVar`: +//! +//! ``` +//! # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { +//! # use ark_std::UniformRand; +//! # use ark_relations::r1cs::*; +//! # use ark_r1cs_std::prelude::*; +//! # use ark_vesta::{*, constraints::*}; +//! +//! # let cs = ConstraintSystem::<Fq>::new_ref(); +//! # let mut rng = ark_std::test_rng(); +//! +//! // Generate some random `Projective` elements. +//! let a_native = Projective::rand(&mut rng); +//! let b_native = Projective::rand(&mut rng); +//! +//! // Allocate `a_native` and `b_native` as witness variables in `cs`. +//! let a = GVar::new_witness(ark_relations::ns!(cs, "a"), || Ok(a_native))?; +//! let b = GVar::new_witness(ark_relations::ns!(cs, "b"), || Ok(b_native))?; +//! +//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any +//! // constraints or variables. +//! let a_const = GVar::new_constant(ark_relations::ns!(cs, "a_as_constant"), a_native)?; +//! let b_const = GVar::new_constant(ark_relations::ns!(cs, "b_as_constant"), b_native)?; +//! +//! // This returns the identity. +//! let zero = GVar::zero(); +//! +//! // Sanity check one + one = two +//! let two_a = &a + &a + &zero; +//! two_a.enforce_equal(&a.double()?)?; +//! +//! assert!(cs.is_satisfied()?); +//! +//! // Check that the value of &a + &b is correct. +//! assert_eq!((&a + &b).value()?, a_native + &b_native); +//! +//! // Check that operations on variables and constants are equivalent. +//! (&a + &b).enforce_equal(&(&a_const + &b_const))?; +//! assert!(cs.is_satisfied()?); +//! # Ok(()) +//! # } +//! ``` + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*;
A
vesta/src/curves/mod.rs
@@ -0,0 +1,51 @@
+use crate::{fq::Fq, fr::Fr}; +use ark_ec::{ + models::{ModelParameters, SWModelParameters}, + short_weierstrass_jacobian::{GroupAffine, GroupProjective}, +}; +use ark_ff::{field_new, Zero}; + +#[cfg(test)] +mod tests; + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub struct VestaParameters; + +impl ModelParameters for VestaParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +pub type Affine = GroupAffine<VestaParameters>; +pub type Projective = GroupProjective<VestaParameters>; + +impl SWModelParameters for VestaParameters { + /// COEFF_A = 0 + const COEFF_A: Fq = field_new!(Fq, "0"); + + /// COEFF_B = 5 + const COEFF_B: Fq = field_new!(Fq, "5"); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[0x1]; + + /// COFACTOR_INV = 1 + const COFACTOR_INV: Fr = field_new!(Fr, "1"); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G_GENERATOR_X, G_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +/// G_GENERATOR_X = -1 +/// Encoded in Montgomery form, so the value here is -R mod p. +pub const G_GENERATOR_X: Fq = field_new!(Fq, "-1"); + +/// G_GENERATOR_Y = 2 +/// Encoded in Montgomery form, so the value here is 2R mod p. +pub const G_GENERATOR_Y: Fq = field_new!(Fq, "2");
A
vesta/src/curves/tests.rs
@@ -0,0 +1,39 @@
+#![allow(unused_imports)] +use ark_ff::{ + fields::{Field, FpParameters, PrimeField, SquareRootField}, + One, Zero, +}; +use ark_serialize::CanonicalSerialize; +use ark_std::test_rng; + +use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; +use core::ops::{AddAssign, MulAssign}; +use rand::Rng; + +use crate::{Affine, Projective, VestaParameters}; + +use ark_curve_tests::{ + curves::{curve_tests, sw_tests}, + groups::group_test, +}; + +#[test] +fn test_projective_curve() { + curve_tests::<Projective>(); + sw_tests::<VestaParameters>(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a: Projective = rng.gen(); + let b: Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_generator() { + let generator = Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +}
A
vesta/src/fields/fq.rs
@@ -0,0 +1,1 @@
+pub use ark_pallas::{Fr as Fq, FrParameters as FqParameters};
A
vesta/src/fields/fr.rs
@@ -0,0 +1,1 @@
+pub use ark_pallas::{Fq as Fr, FqParameters as FrParameters};
A
vesta/src/fields/mod.rs
@@ -0,0 +1,8 @@
+pub mod fq; +pub use self::fq::*; + +pub mod fr; +pub use self::fr::*; + +#[cfg(test)] +mod tests;
A
vesta/src/fields/tests.rs
@@ -0,0 +1,26 @@
+use ark_std::test_rng; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::<Fr>(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::<Fq>(); +}
A
vesta/src/lib.rs
@@ -0,0 +1,33 @@
+#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the prime-order curve Vesta, generated by +//! [Daira Hopwood](https://github.com/zcash/pasta). The main feature of this +//! curve is that it forms a cycle with Pallas, i.e. its scalar field and base +//! field respectively are the base field and scalar field of Pallas. +//! +//! +//! Curve information: +//! Vesta: +//! * Base field: q = +//! 28948022309329048855892746252171976963363056481941647379679742748393362948097 +//! * Scalar field: r = +//! 28948022309329048855892746252171976963363056481941560715954676764349967630337 +//! * Curve equation: y^2 = x^3 + 5 +//! * Valuation(q - 1, 2) = 32 +//! * Valuation(r - 1, 2) = 32 + +#[cfg(feature = "r1cs")] +pub mod constraints; +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*;