From 7dfc50e7636a9d3da7f128c7d9449e5b8bcedfff Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 2 Jul 2018 12:50:47 +0100 Subject: [PATCH] Use group crate for curve traits --- Cargo.toml | 1 + benches/bls12_381/ec.rs | 4 +- benches/bls12_381/mod.rs | 2 +- benches/pairing_benches.rs | 1 + src/bls12_381/ec.rs | 30 ++- src/bls12_381/mod.rs | 7 +- src/bls12_381/tests/mod.rs | 2 + src/lib.rs | 203 +----------------- src/tests/curve.rs | 421 ------------------------------------- src/tests/engine.rs | 3 +- src/tests/mod.rs | 1 - src/wnaf.rs | 179 ---------------- 12 files changed, 42 insertions(+), 812 deletions(-) delete mode 100644 src/tests/curve.rs delete mode 100644 src/wnaf.rs diff --git a/Cargo.toml b/Cargo.toml index 5f16018..68971c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ repository = "https://github.com/ebfull/pairing" rand = "0.4" byteorder = "1" ff = { version = "0.4", features = ["derive"] } +group = "0.1" [features] unstable-features = ["expose-arith"] diff --git a/benches/bls12_381/ec.rs b/benches/bls12_381/ec.rs index cbd0590..d8f6618 100644 --- a/benches/bls12_381/ec.rs +++ b/benches/bls12_381/ec.rs @@ -1,8 +1,8 @@ mod g1 { use rand::{Rand, SeedableRng, XorShiftRng}; + use group::CurveProjective; use pairing::bls12_381::*; - use pairing::CurveProjective; #[bench] fn bench_g1_mul_assign(b: &mut ::test::Bencher) { @@ -65,8 +65,8 @@ mod g1 { mod g2 { use rand::{Rand, SeedableRng, XorShiftRng}; + use group::CurveProjective; use pairing::bls12_381::*; - use pairing::CurveProjective; #[bench] fn bench_g2_mul_assign(b: &mut ::test::Bencher) { diff --git a/benches/bls12_381/mod.rs b/benches/bls12_381/mod.rs index 9b46c85..96bcdd5 100644 --- a/benches/bls12_381/mod.rs +++ b/benches/bls12_381/mod.rs @@ -7,7 +7,7 @@ mod fr; use rand::{Rand, SeedableRng, XorShiftRng}; use pairing::bls12_381::*; -use pairing::{CurveAffine, Engine}; +use pairing::{Engine, PairingCurveAffine}; #[bench] fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { diff --git a/benches/pairing_benches.rs b/benches/pairing_benches.rs index af32a8a..d76e50b 100644 --- a/benches/pairing_benches.rs +++ b/benches/pairing_benches.rs @@ -1,6 +1,7 @@ #![feature(test)] extern crate ff; +extern crate group; extern crate pairing; extern crate rand; extern crate test; diff --git a/src/bls12_381/ec.rs b/src/bls12_381/ec.rs index 37fcbba..f5a6d8f 100644 --- a/src/bls12_381/ec.rs +++ b/src/bls12_381/ec.rs @@ -148,12 +148,9 @@ macro_rules! curve_impl { type Engine = Bls12; type Scalar = $scalarfield; type Base = $basefield; - type Prepared = $prepared; type Projective = $projective; type Uncompressed = $uncompressed; type Compressed = $compressed; - type Pair = $pairing; - type PairingResult = Fq12; fn zero() -> Self { $affine { @@ -182,6 +179,17 @@ macro_rules! curve_impl { } } + fn into_projective(&self) -> $projective { + (*self).into() + } + + } + + impl PairingCurveAffine for $affine { + type Prepared = $prepared; + type Pair = $pairing; + type PairingResult = Fq12; + fn prepare(&self) -> Self::Prepared { $prepared::from_affine(*self) } @@ -190,10 +198,6 @@ macro_rules! curve_impl { self.perform_pairing(other) } - fn into_projective(&self) -> $projective { - (*self).into() - } - } impl Rand for $projective { @@ -624,9 +628,10 @@ pub mod g1 { use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr}; use super::g2::G2Affine; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; + use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand::{Rand, Rng}; use std::fmt; - use {CurveAffine, CurveProjective, EncodedPoint, Engine, GroupDecodingError}; + use {Engine, PairingCurveAffine}; curve_impl!( "G1", @@ -1261,7 +1266,8 @@ pub mod g1 { #[test] fn g1_curve_tests() { - ::tests::curve::curve_tests::(); + use group::tests::curve_tests; + curve_tests::(); } } @@ -1269,9 +1275,10 @@ pub mod g2 { use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr}; use super::g1::G1Affine; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; + use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand::{Rand, Rng}; use std::fmt; - use {CurveAffine, CurveProjective, EncodedPoint, Engine, GroupDecodingError}; + use {Engine, PairingCurveAffine}; curve_impl!( "G2", @@ -2014,7 +2021,8 @@ pub mod g2 { #[test] fn g2_curve_tests() { - ::tests::curve::curve_tests::(); + use group::tests::curve_tests; + curve_tests::(); } } diff --git a/src/bls12_381/mod.rs b/src/bls12_381/mod.rs index 106591e..7bc03c6 100644 --- a/src/bls12_381/mod.rs +++ b/src/bls12_381/mod.rs @@ -18,9 +18,10 @@ pub use self::fq2::Fq2; pub use self::fq6::Fq6; pub use self::fr::{Fr, FrRepr}; -use super::{CurveAffine, Engine}; +use super::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, ScalarEngine}; +use group::CurveAffine; // The BLS parameter x for BLS12-381 is -0xd201000000010000 const BLS_X: u64 = 0xd201000000010000; @@ -46,8 +47,8 @@ impl Engine for Bls12 { where I: IntoIterator< Item = &'a ( - &'a ::Prepared, - &'a ::Prepared, + &'a ::Prepared, + &'a ::Prepared, ), >, { diff --git a/src/bls12_381/tests/mod.rs b/src/bls12_381/tests/mod.rs index bf6c595..6f13661 100644 --- a/src/bls12_381/tests/mod.rs +++ b/src/bls12_381/tests/mod.rs @@ -1,3 +1,5 @@ +use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; + use super::*; use *; diff --git a/src/lib.rs b/src/lib.rs index bbced76..d2e4299 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ extern crate byteorder; #[macro_use] extern crate ff; +extern crate group; extern crate rand; #[cfg(test)] @@ -21,12 +22,8 @@ pub mod tests; pub mod bls12_381; -mod wnaf; -pub use self::wnaf::Wnaf; - use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField}; -use std::error::Error; -use std::fmt; +use group::{CurveAffine, CurveProjective}; /// An "engine" is a collection of types (fields, elliptic curve groups, etc.) /// with well-defined relationships. In particular, the G1/G2 curve groups are @@ -42,7 +39,7 @@ pub trait Engine: ScalarEngine { + From; /// The affine representation of an element in G1. - type G1Affine: CurveAffine< + type G1Affine: PairingCurveAffine< Engine = Self, Base = Self::Fq, Scalar = Self::Fr, @@ -62,7 +59,7 @@ pub trait Engine: ScalarEngine { + From; /// The affine representation of an element in G2. - type G2Affine: CurveAffine< + type G2Affine: PairingCurveAffine< Engine = Self, Base = Self::Fqe, Scalar = Self::Fr, @@ -86,8 +83,8 @@ pub trait Engine: ScalarEngine { where I: IntoIterator< Item = &'a ( - &'a ::Prepared, - &'a ::Prepared, + &'a ::Prepared, + &'a ::Prepared, ), >; @@ -106,196 +103,16 @@ pub trait Engine: ScalarEngine { } } -/// Projective representation of an elliptic curve point guaranteed to be -/// in the correct prime order subgroup. -pub trait CurveProjective: - PartialEq - + Eq - + Sized - + Copy - + Clone - + Send - + Sync - + fmt::Debug - + fmt::Display - + rand::Rand - + 'static -{ - type Engine: Engine; - type Scalar: PrimeField + SqrtField; - type Base: SqrtField; - type Affine: CurveAffine; - - /// Returns the additive identity. - fn zero() -> Self; - - /// Returns a fixed generator of unknown exponent. - fn one() -> Self; - - /// Determines if this point is the point at infinity. - fn is_zero(&self) -> bool; - - /// Normalizes a slice of projective elements so that - /// conversion to affine is cheap. - fn batch_normalization(v: &mut [Self]); - - /// Checks if the point is already "normalized" so that - /// cheap affine conversion is possible. - fn is_normalized(&self) -> bool; - - /// Doubles this element. - fn double(&mut self); - - /// Adds another element to this element. - fn add_assign(&mut self, other: &Self); - - /// Subtracts another element from this element. - fn sub_assign(&mut self, other: &Self) { - let mut tmp = *other; - tmp.negate(); - self.add_assign(&tmp); - } - - /// Adds an affine element to this element. - fn add_assign_mixed(&mut self, other: &Self::Affine); - - /// Negates this element. - fn negate(&mut self); - - /// Performs scalar multiplication of this element. - fn mul_assign::Repr>>(&mut self, other: S); - - /// Converts this element into its affine representation. - fn into_affine(&self) -> Self::Affine; - - /// Recommends a wNAF window table size given a scalar. Always returns a number - /// between 2 and 22, inclusive. - fn recommended_wnaf_for_scalar(scalar: ::Repr) -> usize; - - /// Recommends a wNAF window size given the number of scalars you intend to multiply - /// a base by. Always returns a number between 2 and 22, inclusive. - fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize; -} - -/// Affine representation of an elliptic curve point guaranteed to be -/// in the correct prime order subgroup. -pub trait CurveAffine: - Copy + Clone + Sized + Send + Sync + fmt::Debug + fmt::Display + PartialEq + Eq + 'static -{ - type Engine: Engine; - type Scalar: PrimeField + SqrtField; - type Base: SqrtField; - type Projective: CurveProjective; +/// Affine representation of an elliptic curve point that can be used +/// to perform pairings. +pub trait PairingCurveAffine: CurveAffine { type Prepared: Clone + Send + Sync + 'static; - type Uncompressed: EncodedPoint; - type Compressed: EncodedPoint; - type Pair: CurveAffine; + type Pair: PairingCurveAffine; type PairingResult: Field; - /// Returns the additive identity. - fn zero() -> Self; - - /// Returns a fixed generator of unknown exponent. - fn one() -> Self; - - /// Determines if this point represents the point at infinity; the - /// additive identity. - fn is_zero(&self) -> bool; - - /// Negates this element. - fn negate(&mut self); - - /// Performs scalar multiplication of this element with mixed addition. - fn mul::Repr>>(&self, other: S) -> Self::Projective; - /// Prepares this element for pairing purposes. fn prepare(&self) -> Self::Prepared; /// Perform a pairing fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult; - - /// Converts this element into its affine representation. - fn into_projective(&self) -> Self::Projective; - - /// Converts this element into its compressed encoding, so long as it's not - /// the point at infinity. - fn into_compressed(&self) -> Self::Compressed { - ::from_affine(*self) - } - - /// Converts this element into its uncompressed encoding, so long as it's not - /// the point at infinity. - fn into_uncompressed(&self) -> Self::Uncompressed { - ::from_affine(*self) - } -} - -/// An encoded elliptic curve point, which should essentially wrap a `[u8; N]`. -pub trait EncodedPoint: - Sized + Send + Sync + AsRef<[u8]> + AsMut<[u8]> + Clone + Copy + 'static -{ - type Affine: CurveAffine; - - /// Creates an empty representation. - fn empty() -> Self; - - /// Returns the number of bytes consumed by this representation. - fn size() -> usize; - - /// Converts an `EncodedPoint` into a `CurveAffine` element, - /// if the encoding represents a valid element. - fn into_affine(&self) -> Result; - - /// Converts an `EncodedPoint` into a `CurveAffine` element, - /// without guaranteeing that the encoding represents a valid - /// element. This is useful when the caller knows the encoding is - /// valid already. - /// - /// If the encoding is invalid, this can break API invariants, - /// so caution is strongly encouraged. - fn into_affine_unchecked(&self) -> Result; - - /// Creates an `EncodedPoint` from an affine point, as long as the - /// point is not the point at infinity. - fn from_affine(affine: Self::Affine) -> Self; -} - -/// An error that may occur when trying to decode an `EncodedPoint`. -#[derive(Debug)] -pub enum GroupDecodingError { - /// The coordinate(s) do not lie on the curve. - NotOnCurve, - /// The element is not part of the r-order subgroup. - NotInSubgroup, - /// One of the coordinates could not be decoded - CoordinateDecodingError(&'static str, PrimeFieldDecodingError), - /// The compression mode of the encoded element was not as expected - UnexpectedCompressionMode, - /// The encoding contained bits that should not have been set - UnexpectedInformation, -} - -impl Error for GroupDecodingError { - fn description(&self) -> &str { - match *self { - GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve", - GroupDecodingError::NotInSubgroup => "the element is not part of an r-order subgroup", - GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded", - GroupDecodingError::UnexpectedCompressionMode => { - "encoding has unexpected compression mode" - } - GroupDecodingError::UnexpectedInformation => "encoding has unexpected information", - } - } -} - -impl fmt::Display for GroupDecodingError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - GroupDecodingError::CoordinateDecodingError(description, ref err) => { - write!(f, "{} decoding error: {}", description, err) - } - _ => write!(f, "{}", self.description()), - } - } } diff --git a/src/tests/curve.rs b/src/tests/curve.rs deleted file mode 100644 index bb0406c..0000000 --- a/src/tests/curve.rs +++ /dev/null @@ -1,421 +0,0 @@ -use ff::Field; -use rand::{Rand, Rng, SeedableRng, XorShiftRng}; - -use {CurveAffine, CurveProjective, EncodedPoint}; - -pub fn curve_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - // Negation edge case with zero. - { - let mut z = G::zero(); - z.negate(); - assert!(z.is_zero()); - } - - // Doubling edge case with zero. - { - let mut z = G::zero(); - z.double(); - assert!(z.is_zero()); - } - - // Addition edge cases with zero - { - let mut r = G::rand(&mut rng); - let rcopy = r; - r.add_assign(&G::zero()); - assert_eq!(r, rcopy); - r.add_assign_mixed(&G::Affine::zero()); - assert_eq!(r, rcopy); - - let mut z = G::zero(); - z.add_assign(&G::zero()); - assert!(z.is_zero()); - z.add_assign_mixed(&G::Affine::zero()); - assert!(z.is_zero()); - - let mut z2 = z; - z2.add_assign(&r); - - z.add_assign_mixed(&r.into_affine()); - - assert_eq!(z, z2); - assert_eq!(z, r); - } - - // Transformations - { - let a = G::rand(&mut rng); - let b = a.into_affine().into_projective(); - let c = a - .into_affine() - .into_projective() - .into_affine() - .into_projective(); - assert_eq!(a, b); - assert_eq!(b, c); - } - - random_addition_tests::(); - random_multiplication_tests::(); - random_doubling_tests::(); - random_negation_tests::(); - random_transformation_tests::(); - random_wnaf_tests::(); - random_encoding_tests::(); -} - -fn random_wnaf_tests() { - use ff::PrimeField; - use wnaf::*; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - { - let mut table = vec![]; - let mut wnaf = vec![]; - - for w in 2..14 { - for _ in 0..100 { - let g = G::rand(&mut rng); - let s = G::Scalar::rand(&mut rng).into_repr(); - let mut g1 = g; - g1.mul_assign(s); - - wnaf_table(&mut table, g, w); - wnaf_form(&mut wnaf, s, w); - let g2 = wnaf_exp(&table, &wnaf); - - assert_eq!(g1, g2); - } - } - } - - { - fn only_compiles_if_send(_: &S) {} - - for _ in 0..100 { - let g = G::rand(&mut rng); - let s = G::Scalar::rand(&mut rng).into_repr(); - let mut g1 = g; - g1.mul_assign(s); - - let g2 = { - let mut wnaf = Wnaf::new(); - wnaf.base(g, 1).scalar(s) - }; - let g3 = { - let mut wnaf = Wnaf::new(); - wnaf.scalar(s).base(g) - }; - let g4 = { - let mut wnaf = Wnaf::new(); - let mut shared = wnaf.base(g, 1).shared(); - - only_compiles_if_send(&shared); - - shared.scalar(s) - }; - let g5 = { - let mut wnaf = Wnaf::new(); - let mut shared = wnaf.scalar(s).shared(); - - only_compiles_if_send(&shared); - - shared.base(g) - }; - - let g6 = { - let mut wnaf = Wnaf::new(); - { - // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); - } - wnaf.base(g, 1).scalar(s) - }; - let g7 = { - let mut wnaf = Wnaf::new(); - { - // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); - } - wnaf.scalar(s).base(g) - }; - let g8 = { - let mut wnaf = Wnaf::new(); - { - // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); - } - let mut shared = wnaf.base(g, 1).shared(); - - only_compiles_if_send(&shared); - - shared.scalar(s) - }; - let g9 = { - let mut wnaf = Wnaf::new(); - { - // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); - } - let mut shared = wnaf.scalar(s).shared(); - - only_compiles_if_send(&shared); - - shared.base(g) - }; - - assert_eq!(g1, g2); - assert_eq!(g1, g3); - assert_eq!(g1, g4); - assert_eq!(g1, g5); - assert_eq!(g1, g6); - assert_eq!(g1, g7); - assert_eq!(g1, g8); - assert_eq!(g1, g9); - } - } -} - -fn random_negation_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let r = G::rand(&mut rng); - - let s = G::Scalar::rand(&mut rng); - let mut sneg = s; - sneg.negate(); - - let mut t1 = r; - t1.mul_assign(s); - - let mut t2 = r; - t2.mul_assign(sneg); - - let mut t3 = t1; - t3.add_assign(&t2); - assert!(t3.is_zero()); - - let mut t4 = t1; - t4.add_assign_mixed(&t2.into_affine()); - assert!(t4.is_zero()); - - t1.negate(); - assert_eq!(t1, t2); - } -} - -fn random_doubling_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let mut a = G::rand(&mut rng); - let mut b = G::rand(&mut rng); - - // 2(a + b) - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.double(); - - // 2a + 2b - a.double(); - b.double(); - - let mut tmp2 = a; - tmp2.add_assign(&b); - - let mut tmp3 = a; - tmp3.add_assign_mixed(&b.into_affine()); - - assert_eq!(tmp1, tmp2); - assert_eq!(tmp1, tmp3); - } -} - -fn random_multiplication_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let mut a = G::rand(&mut rng); - let mut b = G::rand(&mut rng); - let a_affine = a.into_affine(); - let b_affine = b.into_affine(); - - let s = G::Scalar::rand(&mut rng); - - // s ( a + b ) - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.mul_assign(s); - - // sa + sb - a.mul_assign(s); - b.mul_assign(s); - - let mut tmp2 = a; - tmp2.add_assign(&b); - - // Affine multiplication - let mut tmp3 = a_affine.mul(s); - tmp3.add_assign(&b_affine.mul(s)); - - assert_eq!(tmp1, tmp2); - assert_eq!(tmp1, tmp3); - } -} - -fn random_addition_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let a = G::rand(&mut rng); - let b = G::rand(&mut rng); - let c = G::rand(&mut rng); - let a_affine = a.into_affine(); - let b_affine = b.into_affine(); - let c_affine = c.into_affine(); - - // a + a should equal the doubling - { - let mut aplusa = a; - aplusa.add_assign(&a); - - let mut aplusamixed = a; - aplusamixed.add_assign_mixed(&a.into_affine()); - - let mut adouble = a; - adouble.double(); - - assert_eq!(aplusa, adouble); - assert_eq!(aplusa, aplusamixed); - } - - let mut tmp = vec![G::zero(); 6]; - - // (a + b) + c - tmp[0] = a; - tmp[0].add_assign(&b); - tmp[0].add_assign(&c); - - // a + (b + c) - tmp[1] = b; - tmp[1].add_assign(&c); - tmp[1].add_assign(&a); - - // (a + c) + b - tmp[2] = a; - tmp[2].add_assign(&c); - tmp[2].add_assign(&b); - - // Mixed addition - - // (a + b) + c - tmp[3] = a_affine.into_projective(); - tmp[3].add_assign_mixed(&b_affine); - tmp[3].add_assign_mixed(&c_affine); - - // a + (b + c) - tmp[4] = b_affine.into_projective(); - tmp[4].add_assign_mixed(&c_affine); - tmp[4].add_assign_mixed(&a_affine); - - // (a + c) + b - tmp[5] = a_affine.into_projective(); - tmp[5].add_assign_mixed(&c_affine); - tmp[5].add_assign_mixed(&b_affine); - - // Comparisons - for i in 0..6 { - for j in 0..6 { - assert_eq!(tmp[i], tmp[j]); - assert_eq!(tmp[i].into_affine(), tmp[j].into_affine()); - } - - assert!(tmp[i] != a); - assert!(tmp[i] != b); - assert!(tmp[i] != c); - - assert!(a != tmp[i]); - assert!(b != tmp[i]); - assert!(c != tmp[i]); - } - } -} - -fn random_transformation_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let g = G::rand(&mut rng); - let g_affine = g.into_affine(); - let g_projective = g_affine.into_projective(); - assert_eq!(g, g_projective); - } - - // Batch normalization - for _ in 0..10 { - let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::>(); - - for i in &v { - assert!(!i.is_normalized()); - } - - use rand::distributions::{IndependentSample, Range}; - let between = Range::new(0, 1000); - // Sprinkle in some normalized points - for _ in 0..5 { - v[between.ind_sample(&mut rng)] = G::zero(); - } - for _ in 0..5 { - let s = between.ind_sample(&mut rng); - v[s] = v[s].into_affine().into_projective(); - } - - let expected_v = v - .iter() - .map(|v| v.into_affine().into_projective()) - .collect::>(); - G::batch_normalization(&mut v); - - for i in &v { - assert!(i.is_normalized()); - } - - assert_eq!(v, expected_v); - } -} - -fn random_encoding_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - assert_eq!( - G::zero().into_uncompressed().into_affine().unwrap(), - G::zero() - ); - - assert_eq!( - G::zero().into_compressed().into_affine().unwrap(), - G::zero() - ); - - for _ in 0..1000 { - let mut r = G::Projective::rand(&mut rng).into_affine(); - - let uncompressed = r.into_uncompressed(); - let de_uncompressed = uncompressed.into_affine().unwrap(); - assert_eq!(de_uncompressed, r); - - let compressed = r.into_compressed(); - let de_compressed = compressed.into_affine().unwrap(); - assert_eq!(de_compressed, r); - - r.negate(); - - let compressed = r.into_compressed(); - let de_compressed = compressed.into_affine().unwrap(); - assert_eq!(de_compressed, r); - } -} diff --git a/src/tests/engine.rs b/src/tests/engine.rs index 52ff4e0..7b1944d 100644 --- a/src/tests/engine.rs +++ b/src/tests/engine.rs @@ -1,6 +1,7 @@ +use group::{CurveAffine, CurveProjective}; use rand::{Rand, SeedableRng, XorShiftRng}; -use {CurveAffine, CurveProjective, Engine, Field, PrimeField}; +use {Engine, Field, PairingCurveAffine, PrimeField}; pub fn engine_tests() { let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); diff --git a/src/tests/mod.rs b/src/tests/mod.rs index bc83958..d6ad6a1 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,3 @@ -pub mod curve; pub mod engine; pub mod field; pub mod repr; diff --git a/src/wnaf.rs b/src/wnaf.rs deleted file mode 100644 index 69c6fd9..0000000 --- a/src/wnaf.rs +++ /dev/null @@ -1,179 +0,0 @@ -use super::{CurveProjective, PrimeField, PrimeFieldRepr}; - -/// Replaces the contents of `table` with a w-NAF window table for the given window size. -pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, window: usize) { - table.truncate(0); - table.reserve(1 << (window - 1)); - - let mut dbl = base; - dbl.double(); - - for _ in 0..(1 << (window - 1)) { - table.push(base); - base.add_assign(&dbl); - } -} - -/// Replaces the contents of `wnaf` with the w-NAF representation of a scalar. -pub(crate) fn wnaf_form(wnaf: &mut Vec, mut c: S, window: usize) { - wnaf.truncate(0); - - while !c.is_zero() { - let mut u; - if c.is_odd() { - u = (c.as_ref()[0] % (1 << (window + 1))) as i64; - - if u > (1 << window) { - u -= 1 << (window + 1); - } - - if u > 0 { - c.sub_noborrow(&S::from(u as u64)); - } else { - c.add_nocarry(&S::from((-u) as u64)); - } - } else { - u = 0; - } - - wnaf.push(u); - - c.div2(); - } -} - -/// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar. -/// -/// This function must be provided a `table` and `wnaf` that were constructed with -/// the same window size; otherwise, it may panic or produce invalid results. -pub(crate) fn wnaf_exp(table: &[G], wnaf: &[i64]) -> G { - let mut result = G::zero(); - - let mut found_one = false; - - for n in wnaf.iter().rev() { - if found_one { - result.double(); - } - - if *n != 0 { - found_one = true; - - if *n > 0 { - result.add_assign(&table[(n / 2) as usize]); - } else { - result.sub_assign(&table[((-n) / 2) as usize]); - } - } - } - - result -} - -/// A "w-ary non-adjacent form" exponentiation context. -#[derive(Debug)] -pub struct Wnaf { - base: B, - scalar: S, - window_size: W, -} - -impl Wnaf<(), Vec, Vec> { - /// Construct a new wNAF context without allocating. - pub fn new() -> Self { - Wnaf { - base: vec![], - scalar: vec![], - window_size: (), - } - } - - /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that - /// can perform exponentiations with `.scalar(..)`. - pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf> { - // Compute the appropriate window size based on the number of scalars. - let window_size = G::recommended_wnaf_for_num_scalars(num_scalars); - - // Compute a wNAF table for the provided base and window size. - wnaf_table(&mut self.base, base, window_size); - - // Return a Wnaf object that immutably borrows the computed base storage location, - // but mutably borrows the scalar storage location. - Wnaf { - base: &self.base[..], - scalar: &mut self.scalar, - window_size, - } - } - - /// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform - /// exponentiations with `.base(..)`. - pub fn scalar( - &mut self, - scalar: <::Scalar as PrimeField>::Repr, - ) -> Wnaf, &[i64]> { - // Compute the appropriate window size for the scalar. - let window_size = G::recommended_wnaf_for_scalar(scalar); - - // Compute the wNAF form of the scalar. - wnaf_form(&mut self.scalar, scalar, window_size); - - // Return a Wnaf object that mutably borrows the base storage location, but - // immutably borrows the computed wNAF form scalar location. - Wnaf { - base: &mut self.base, - scalar: &self.scalar[..], - window_size, - } - } -} - -impl<'a, G: CurveProjective> Wnaf> { - /// Constructs new space for the scalar representation while borrowing - /// the computed window table, for sending the window table across threads. - pub fn shared(&self) -> Wnaf> { - Wnaf { - base: self.base, - scalar: vec![], - window_size: self.window_size, - } - } -} - -impl<'a, G: CurveProjective> Wnaf, &'a [i64]> { - /// Constructs new space for the window table while borrowing - /// the computed scalar representation, for sending the scalar representation - /// across threads. - pub fn shared(&self) -> Wnaf, &'a [i64]> { - Wnaf { - base: vec![], - scalar: self.scalar, - window_size: self.window_size, - } - } -} - -impl> Wnaf { - /// Performs exponentiation given a base. - pub fn base(&mut self, base: G) -> G - where - B: AsMut>, - { - wnaf_table(self.base.as_mut(), base, self.window_size); - wnaf_exp(self.base.as_mut(), self.scalar.as_ref()) - } -} - -impl>> Wnaf { - /// Performs exponentiation given a scalar. - pub fn scalar( - &mut self, - scalar: <::Scalar as PrimeField>::Repr, - ) -> G - where - B: AsRef<[G]>, - { - wnaf_form(self.scalar.as_mut(), scalar, self.window_size); - wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) - } -}