diff --git a/Cargo.toml b/Cargo.toml index 677fe6ad3..a19bc0038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pairing" -version = "0.10.1" +version = "0.10.2" authors = ["Sean Bowe "] license = "MIT/Apache-2.0" @@ -12,7 +12,7 @@ repository = "https://github.com/ebfull/pairing" [dependencies] rand = "0.3" byteorder = "1.1.0" -clippy = { version = "0.0.145", optional = true } +clippy = { version = "0.0.148", optional = true } [features] unstable-wnaf = [] diff --git a/src/bls12_381/ec.rs b/src/bls12_381/ec.rs index a4eaa1a7f..16deca520 100644 --- a/src/bls12_381/ec.rs +++ b/src/bls12_381/ec.rs @@ -108,6 +108,7 @@ macro_rules! curve_impl { } impl CurveAffine for $affine { + type Engine = Bls12; type Scalar = $scalarfield; type Base = $basefield; type Prepared = $prepared; @@ -174,6 +175,7 @@ macro_rules! curve_impl { } impl CurveProjective for $projective { + type Engine = Bls12; type Scalar = $scalarfield; type Base = $basefield; type Affine = $affine; @@ -582,7 +584,7 @@ macro_rules! curve_impl { pub mod g1 { use rand::{Rand, Rng}; use super::g2::G2Affine; - use super::super::{Fq, Fr, FrRepr, FqRepr, Fq12}; + use super::super::{Bls12, Fq, Fr, FrRepr, FqRepr, Fq12}; use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint, GroupDecodingError, Engine}; curve_impl!("G1", G1, G1Affine, G1Prepared, Fq, Fr, G1Uncompressed, G1Compressed, G2Affine); @@ -1134,7 +1136,7 @@ pub mod g1 { pub mod g2 { use rand::{Rand, Rng}; - use super::super::{Fq2, Fr, Fq, FrRepr, FqRepr, Fq12}; + use super::super::{Bls12, Fq2, Fr, Fq, FrRepr, FqRepr, Fq12}; use super::g1::G1Affine; use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint, GroupDecodingError, Engine}; diff --git a/src/bls12_381/fq.rs b/src/bls12_381/fq.rs index e7be0ec59..edfe1500c 100644 --- a/src/bls12_381/fq.rs +++ b/src/bls12_381/fq.rs @@ -10,7 +10,7 @@ const MODULUS_BITS: u32 = 381; // The number of bits that must be shaved from the beginning of // the representation when randomly sampling. -const REPR_SHAVE_BITS: usize = 3; +const REPR_SHAVE_BITS: u32 = 3; // R = 2**384 % q const R: FqRepr = FqRepr([0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493]); @@ -25,7 +25,7 @@ const INV: u64 = 0x89f3fffcfffcfffd; const GENERATOR: FqRepr = FqRepr([0x321300000006554f, 0xb93c0018d6c40005, 0x57605e0db0ddbb51, 0x8b256521ed1f9bcb, 0x6cf28d7901622c03, 0x11ebab9dbb81e28c]); // 2^s * t = MODULUS - 1 with t odd -const S: usize = 1; +const S: u32 = 1; // 2^s root of unity computed by GENERATOR^t const ROOT_OF_UNITY: FqRepr = FqRepr([0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x7e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x40ab3263eff0206]); @@ -278,7 +278,7 @@ impl PrimeFieldRepr for FqRepr { } #[inline(always)] - fn divn(&mut self, mut n: usize) { + fn divn(&mut self, mut n: u32) { if n >= 64 * 6 { *self = Self::from(0); return; @@ -325,6 +325,32 @@ impl PrimeFieldRepr for FqRepr { } } + #[inline(always)] + fn muln(&mut self, mut n: u32) { + if n >= 64 * 6 { + *self = Self::from(0); + return; + } + + while n >= 64 { + let mut t = 0; + for i in &mut self.0 { + ::std::mem::swap(&mut t, i); + } + n -= 64; + } + + if n > 0 { + let mut t = 0; + for i in &mut self.0 { + let t2 = *i >> (64 - n); + *i <<= n; + *i |= t; + t = t2; + } + } + } + #[inline(always)] fn num_bits(&self) -> u32 { let mut ret = (6 as u32) * 64; @@ -444,7 +470,7 @@ impl PrimeField for Fq { Fq(GENERATOR) } - fn s() -> usize { + fn s() -> u32 { S } @@ -1740,6 +1766,7 @@ fn fq_field_tests() { ::tests::field::random_field_tests::(); ::tests::field::random_sqrt_tests::(); ::tests::field::random_frobenius_tests::(Fq::char(), 13); + ::tests::field::from_str_tests::(); } #[test] diff --git a/src/bls12_381/fr.rs b/src/bls12_381/fr.rs index 63cc26476..9fc90ee0a 100644 --- a/src/bls12_381/fr.rs +++ b/src/bls12_381/fr.rs @@ -8,7 +8,7 @@ const MODULUS_BITS: u32 = 255; // The number of bits that must be shaved from the beginning of // the representation when randomly sampling. -const REPR_SHAVE_BITS: usize = 1; +const REPR_SHAVE_BITS: u32 = 1; // R = 2**256 % r const R: FrRepr = FrRepr([0x1fffffffe, 0x5884b7fa00034802, 0x998c4fefecbc4ff5, 0x1824b159acc5056f]); @@ -23,7 +23,7 @@ const INV: u64 = 0xfffffffeffffffff; const GENERATOR: FrRepr = FrRepr([0xefffffff1, 0x17e363d300189c0f, 0xff9c57876f8457b0, 0x351332208fc5a8c4]); // 2^s * t = MODULUS - 1 with t odd -const S: usize = 32; +const S: u32 = 32; // 2^s root of unity computed by GENERATOR^t const ROOT_OF_UNITY: FrRepr = FrRepr([0xb9b58d8c5f0e466a, 0x5b1b4c801819d7ec, 0xaf53ae352a31e64, 0x5bf3adda19e9b27b]); @@ -114,7 +114,7 @@ impl PrimeFieldRepr for FrRepr { } #[inline(always)] - fn divn(&mut self, mut n: usize) { + fn divn(&mut self, mut n: u32) { if n >= 64 * 4 { *self = Self::from(0); return; @@ -161,6 +161,32 @@ impl PrimeFieldRepr for FrRepr { } } + #[inline(always)] + fn muln(&mut self, mut n: u32) { + if n >= 64 * 4 { + *self = Self::from(0); + return; + } + + while n >= 64 { + let mut t = 0; + for i in &mut self.0 { + ::std::mem::swap(&mut t, i); + } + n -= 64; + } + + if n > 0 { + let mut t = 0; + for i in &mut self.0 { + let t2 = *i >> (64 - n); + *i <<= n; + *i |= t; + t = t2; + } + } + } + #[inline(always)] fn num_bits(&self) -> u32 { let mut ret = (4 as u32) * 64; @@ -264,7 +290,7 @@ impl PrimeField for Fr { Fr(GENERATOR) } - fn s() -> usize { + fn s() -> u32 { S } @@ -1452,6 +1478,7 @@ fn fr_field_tests() { ::tests::field::random_field_tests::(); ::tests::field::random_sqrt_tests::(); ::tests::field::random_frobenius_tests::(Fr::char(), 13); + ::tests::field::from_str_tests::(); } #[test] diff --git a/src/bls12_381/mod.rs b/src/bls12_381/mod.rs index 6454877e9..28af9d8a0 100644 --- a/src/bls12_381/mod.rs +++ b/src/bls12_381/mod.rs @@ -11,6 +11,7 @@ mod tests; pub use self::fr::{Fr, FrRepr}; pub use self::fq::{Fq, FqRepr}; pub use self::fq2::Fq2; +pub use self::fq6::Fq6; pub use self::fq12::Fq12; pub use self::ec::{G1, G2, G1Affine, G2Affine, G1Prepared, G2Prepared, G1Uncompressed, G2Uncompressed, G1Compressed, G2Compressed}; diff --git a/src/lib.rs b/src/lib.rs index 6e98aa6ec..62abed95f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(feature = "clippy", plugin(clippy))] #![cfg_attr(feature = "clippy", allow(inline_always))] #![cfg_attr(feature = "clippy", allow(too_many_arguments))] +#![cfg_attr(feature = "clippy", allow(unreadable_literal))] // The compiler provides `test` (on nightly) for benchmarking tools, but // it's hidden behind a feature flag. Enable it if we're testing. @@ -34,21 +35,21 @@ use std::io::{self, Read, Write}; /// An "engine" is a collection of types (fields, elliptic curve groups, etc.) /// with well-defined relationships. In particular, the G1/G2 curve groups are /// of prime order `r`, and are equipped with a bilinear pairing function. -pub trait Engine { +pub trait Engine: Sized { /// This is the scalar field of the G1/G2 groups. type Fr: PrimeField; /// The projective representation of an element in G1. - type G1: CurveProjective + From; + type G1: CurveProjective + From; /// The affine representation of an element in G1. - type G1Affine: CurveAffine + From; + type G1Affine: CurveAffine + From; /// The projective representation of an element in G2. - type G2: CurveProjective + From; + type G2: CurveProjective + From; /// The affine representation of an element in G2. - type G2Affine: CurveAffine + From; + type G2Affine: CurveAffine + From; /// The base field that hosts G1. type Fq: PrimeField + SqrtField; @@ -97,6 +98,7 @@ pub trait CurveProjective: PartialEq + rand::Rand + 'static { + type Engine: Engine; type Scalar: PrimeField; type Base: SqrtField; type Affine: CurveAffine; @@ -166,6 +168,7 @@ pub trait CurveAffine: Copy + Eq + 'static { + type Engine: Engine; type Scalar: PrimeField; type Base: SqrtField; type Projective: CurveProjective; @@ -352,7 +355,8 @@ pub trait PrimeFieldRepr: Sized + /// Add another representation to this one, returning the carry bit. fn add_nocarry(&mut self, other: &Self) -> bool; - /// Compute the number of bits needed to encode this number. + /// Compute the number of bits needed to encode this number. Always a + /// multiple of 64. fn num_bits(&self) -> u32; /// Returns true iff this number is zero. @@ -369,12 +373,15 @@ pub trait PrimeFieldRepr: Sized + fn div2(&mut self); /// Performs a rightwise bitshift of this number by some amount. - fn divn(&mut self, amt: usize); + fn divn(&mut self, amt: u32); /// Performs a leftwise bitshift of this number, effectively multiplying /// it by 2. Overflow is ignored. fn mul2(&mut self); + /// Performs a leftwise bitshift of this number by some amount. + fn muln(&mut self, amt: u32); + /// Writes this `PrimeFieldRepr` as a big endian integer. Always writes /// `(num_bits` / 8) bytes. fn write_be(&self, mut writer: W) -> io::Result<()> { @@ -473,6 +480,46 @@ pub trait PrimeField: Field /// representation. type Repr: PrimeFieldRepr + From; + /// Interpret a string of numbers as a (congruent) prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + fn from_str(s: &str) -> Option { + if s.is_empty() { + return None; + } + + if s == "0" { + return Some(Self::zero()); + } + + let mut res = Self::zero(); + + let ten = Self::from_repr(Self::Repr::from(10)).unwrap(); + + let mut first_digit = true; + + for c in s.chars() { + match c.to_digit(10) { + Some(c) => { + if first_digit { + if c == 0 { + return None; + } + + first_digit = false; + } + + res.mul_assign(&ten); + res.add_assign(&Self::from_repr(Self::Repr::from(c as u64)).unwrap()); + }, + None => { + return None; + } + } + } + + Some(res) + } + /// Convert this prime field element into a biginteger representation. fn from_repr(Self::Repr) -> Result; @@ -496,7 +543,7 @@ pub trait PrimeField: Field fn multiplicative_generator() -> Self; /// Returns s such that 2^s * t = `char()` - 1 with t odd. - fn s() -> usize; + fn s() -> u32; /// Returns the 2^s root of unity computed by exponentiating the `multiplicative_generator()` /// by t. diff --git a/src/tests/field.rs b/src/tests/field.rs index dbc9f8cfc..5f9999296 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,5 +1,5 @@ use rand::{Rng, SeedableRng, XorShiftRng}; -use ::{SqrtField, Field}; +use ::{SqrtField, Field, PrimeField}; pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); @@ -87,6 +87,40 @@ pub fn random_field_tests() { } } +pub fn from_str_tests() { + { + let a = "84395729384759238745923745892374598234705297301958723458712394587103249587213984572934750213947582345792304758273458972349582734958273495872304598234"; + let b = "38495729084572938457298347502349857029384609283450692834058293405982304598230458230495820394850293845098234059823049582309485203948502938452093482039"; + let c = "3248875134290623212325429203829831876024364170316860259933542844758450336418538569901990710701240661702808867062612075657861768196242274635305077449545396068598317421057721935408562373834079015873933065667961469731886739181625866970316226171512545167081793907058686908697431878454091011239990119126"; + + let mut a = F::from_str(a).unwrap(); + let b = F::from_str(b).unwrap(); + let c = F::from_str(c).unwrap(); + + a.mul_assign(&b); + + assert_eq!(a, c); + } + + { + let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + for _ in 0..1000 { + let n: u64 = rng.gen(); + + let a = F::from_str(&format!("{}", n)).unwrap(); + let b = F::from_repr(n.into()).unwrap(); + + assert_eq!(a, b); + } + } + + assert!(F::from_str("").is_none()); + assert!(F::from_str("0").unwrap().is_zero()); + assert!(F::from_str("00").is_none()); + assert!(F::from_str("00000000000").is_none()); +} + fn random_multiplication_tests(rng: &mut R) { for _ in 0..10000 { let a = F::rand(rng); diff --git a/src/tests/repr.rs b/src/tests/repr.rs index b0c119cf3..9403df085 100644 --- a/src/tests/repr.rs +++ b/src/tests/repr.rs @@ -2,20 +2,64 @@ use rand::{SeedableRng, XorShiftRng}; use ::{PrimeFieldRepr}; pub fn random_repr_tests() { - random_encoding_tests::(); + random_encoding_tests::(); + random_muln_tests::(); + random_divn_tests::(); } fn random_encoding_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - for _ in 0..1000 { - let r = R::rand(&mut rng); - let mut rdecoded = R::default(); + for _ in 0..1000 { + let r = R::rand(&mut rng); + let mut rdecoded = R::default(); - let mut v: Vec = vec![]; - r.write_be(&mut v).unwrap(); - rdecoded.read_be(&v[0..]).unwrap(); + let mut v: Vec = vec![]; + r.write_be(&mut v).unwrap(); + rdecoded.read_be(&v[0..]).unwrap(); - assert_eq!(r, rdecoded); - } + assert_eq!(r, rdecoded); + } +} + +fn random_muln_tests() { + let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + for _ in 0..100 { + let r = R::rand(&mut rng); + + for shift in 0..(r.num_bits()+1) { + let mut r1 = r; + let mut r2 = r; + + for _ in 0..shift { + r1.mul2(); + } + + r2.muln(shift); + + assert_eq!(r1, r2); + } + } +} + +fn random_divn_tests() { + let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + for _ in 0..100 { + let r = R::rand(&mut rng); + + for shift in 0..(r.num_bits()+1) { + let mut r1 = r; + let mut r2 = r; + + for _ in 0..shift { + r1.div2(); + } + + r2.divn(shift); + + assert_eq!(r1, r2); + } + } }