diff --git a/src/curves/bls381/ec.rs b/src/curves/bls381/ec.rs index 74fb8f4..4d4db81 100644 --- a/src/curves/bls381/ec.rs +++ b/src/curves/bls381/ec.rs @@ -112,10 +112,10 @@ macro_rules! curve_impl { self.infinity } - fn mul>(&self, e: &$engine, other: &S) -> $name { + fn mul>::Repr, $engine>>(&self, e: &$engine, other: &S) -> $name { let mut res = $name::zero(e); - for i in BitIterator::from((*other.convert(e)).borrow()) + for i in BitIterator::new((*other.convert(e)).borrow()) { res.double(e); @@ -314,10 +314,10 @@ macro_rules! curve_impl { } } - fn mul_assign>(&mut self, engine: &$engine, other: &S) { + fn mul_assign>::Repr, $engine>>(&mut self, engine: &$engine, other: &S) { let mut res = Self::zero(engine); - for i in BitIterator::from((*other.convert(engine)).borrow()) + for i in BitIterator::new((*other.convert(engine)).borrow()) { res.double(engine); diff --git a/src/curves/bls381/fp.rs b/src/curves/bls381/fp.rs index 7d7dd07..43fc77a 100644 --- a/src/curves/bls381/fp.rs +++ b/src/curves/bls381/fp.rs @@ -183,6 +183,7 @@ macro_rules! fp_impl { engine = $engine:ident, params = $params_field:ident : $params_name:ident, arith = $arith_mod:ident, + repr = $repr:ident, limbs = $limbs:expr, $($params:tt)* ) => { @@ -218,15 +219,72 @@ macro_rules! fp_impl { #[repr(C)] pub struct $name([u64; $limbs]); + #[derive(Copy, Clone, PartialEq, Eq)] + #[repr(C)] + pub struct $repr([u64; $limbs]); + + impl PrimeFieldRepr for $repr { + fn from_u64(a: u64) -> Self { + let mut tmp: [u64; $limbs] = Default::default(); + tmp[0] = a; + $repr(tmp) + } + + fn sub_noborrow(&mut self, other: &Self) { + $arith_mod::sub_noborrow(&mut self.0, &other.0); + } + + fn add_nocarry(&mut self, other: &Self) { + $arith_mod::add_nocarry(&mut self.0, &other.0); + } + + fn num_bits(&self) -> usize { + $arith_mod::num_bits(&self.0) + } + + fn is_zero(&self) -> bool { + self.0.iter().all(|&e| e==0) + } + + fn is_odd(&self) -> bool { + $arith_mod::odd(&self.0) + } + + fn div2(&mut self) { + $arith_mod::div2(&mut self.0); + } + } + + impl AsRef<[u64]> for $repr { + fn as_ref(&self) -> &[u64] { + &self.0 + } + } + + impl Ord for $repr { + fn cmp(&self, other: &$repr) -> Ordering { + if $arith_mod::lt(&self.0, &other.0) { + Ordering::Less + } else if self.0 == other.0 { + Ordering::Equal + } else { + Ordering::Greater + } + } + } + + impl PartialOrd for $repr { + fn partial_cmp(&self, other: &$repr) -> Option { + Some(self.cmp(other)) + } + } + impl fmt::Debug for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ENGINE.with(|e| { - let mut repr = self.into_repr(&e); - repr.reverse(); - try!(write!(f, "Fp(0x")); - for i in &repr { + for i in self.into_repr(&e).0.iter().rev() { try!(write!(f, "{:016x}", *i)); } write!(f, ")") @@ -260,21 +318,21 @@ macro_rules! fp_impl { } } - impl Convert<[u64], $engine> for $name + impl Convert<$repr, $engine> for $name { - type Target = [u64; $limbs]; + type Target = $repr; - fn convert(&self, engine: &$engine) -> Cow<[u64; $limbs]> { + fn convert(&self, engine: &$engine) -> Cow<$repr> { Cow::Owned(self.into_repr(engine)) } } impl PrimeField<$engine> for $name { - type Repr = [u64; $limbs]; + type Repr = $repr; fn from_repr(engine: &$engine, repr: Self::Repr) -> Result { - let mut tmp = $name(repr); + let mut tmp = $name(repr.0); if $arith_mod::lt(&tmp.0, &engine.$params_field.modulus) { tmp.mul_assign(engine, &engine.$params_field.r2); Ok(tmp) @@ -283,55 +341,17 @@ macro_rules! fp_impl { } } - fn repr_lt(a: &Self::Repr, b: &Self::Repr) -> bool { - $arith_mod::lt(a, b) - } - - fn repr_sub_noborrow(a: &mut Self::Repr, b: &Self::Repr) { - $arith_mod::sub_noborrow(a, b); - } - - fn repr_add_nocarry(a: &mut Self::Repr, b: &Self::Repr) { - $arith_mod::add_nocarry(a, b); - } - - fn repr_num_bits(a: &Self::Repr) -> usize { - $arith_mod::num_bits(a) - } - - fn repr_is_zero(a: &Self::Repr) -> bool { - a.iter().all(|&e| e==0) - } - - fn repr_is_odd(a: &Self::Repr) -> bool { - $arith_mod::odd(a) - } - - fn repr_least_significant_limb(a: &Self::Repr) -> u64 { - a[0] - } - - fn repr_div2(a: &mut Self::Repr) { - $arith_mod::div2(a); - } - - fn repr_from_u64(a: u64) -> Self::Repr { - let mut tmp = Self::Repr::default(); - tmp[0] = a; - tmp - } - fn into_repr(&self, engine: &$engine) -> Self::Repr { let mut tmp = *self; tmp.mul_assign(engine, &engine.$params_field.one); - tmp.0 + $repr(tmp.0) } fn from_u64(engine: &$engine, n: u64) -> Self { let mut r = [0; $limbs]; r[0] = n; - Self::from_repr(engine, r).unwrap() + Self::from_repr(engine, $repr(r)).unwrap() } fn from_str(engine: &$engine, s: &str) -> Result { @@ -351,12 +371,8 @@ macro_rules! fp_impl { Ok(res) } - fn bits(&self, engine: &$engine) -> BitIterator { - self.into_repr(engine).into() - } - fn char(engine: &$engine) -> Self::Repr { - engine.$params_field.modulus + $repr(engine.$params_field.modulus) } fn num_bits(engine: &$engine) -> usize { @@ -495,19 +511,20 @@ macro_rules! fp_impl { } mod $arith_mod { - use super::BitIterator; // Arithmetic #[allow(dead_code)] pub fn num_bits(v: &[u64; $limbs]) -> usize { - // TODO: optimize - for (i, b) in BitIterator::from(&v[..]).enumerate() { - if b { - return ($limbs*64) - i; + let mut ret = 64 * $limbs; + for i in v.iter().rev() { + let leading = i.leading_zeros() as usize; + ret -= leading; + if leading != 64 { + break; } } - 0 + ret } #[inline] diff --git a/src/curves/bls381/mod.rs b/src/curves/bls381/mod.rs index 4036206..1266eb9 100644 --- a/src/curves/bls381/mod.rs +++ b/src/curves/bls381/mod.rs @@ -1,6 +1,7 @@ use rand; use std::fmt; +use std::cmp::Ordering; use std::borrow::Borrow; use super::{ Engine, @@ -9,6 +10,7 @@ use super::{ CurveAffine, CurveRepresentation, PrimeField, + PrimeFieldRepr, Field, SnarkField, SqrtField, @@ -62,6 +64,7 @@ fp_impl!( engine = Bls381, params = fqparams: FqParams, arith = fq_arith, + repr = FqRepr, limbs = 6, // q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 modulus = [ 0xb9feffffffffaaab, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a ], @@ -81,6 +84,7 @@ fp_impl!( engine = Bls381, params = frparams: FrParams, arith = fr_arith, + repr = FrRepr, limbs = 4, // r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 modulus = [ 0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48 ], @@ -375,8 +379,8 @@ impl CurveRepresentation for G1Uncompressed { } Ok(G1Affine { - x: try!(Fq::from_repr(e, x)), - y: try!(Fq::from_repr(e, y)), + x: try!(Fq::from_repr(e, FqRepr(x))), + y: try!(Fq::from_repr(e, FqRepr(y))), infinity: false }) } @@ -411,12 +415,12 @@ impl CurveRepresentation for G2Uncompressed { if let (Some(y_c1), y_c0) = fq_arith::divrem(&y, &e.fqparams.modulus) { return Ok(G2Affine { x: Fq2 { - c0: try!(Fq::from_repr(e, x_c0)), - c1: try!(Fq::from_repr(e, x_c1)) + c0: try!(Fq::from_repr(e, FqRepr(x_c0))), + c1: try!(Fq::from_repr(e, FqRepr(x_c1))) }, y: Fq2 { - c0: try!(Fq::from_repr(e, y_c0)), - c1: try!(Fq::from_repr(e, y_c1)) + c0: try!(Fq::from_repr(e, FqRepr(y_c0))), + c1: try!(Fq::from_repr(e, FqRepr(y_c1))) }, infinity: false }); @@ -440,14 +444,14 @@ impl G1Uncompressed { { let mut tmp = &mut tmp[0..]; - for &digit in p.x.into_repr(e).iter().rev() { + for &digit in p.x.into_repr(e).0.iter().rev() { tmp.write_u64::(digit).unwrap(); } } { let mut tmp = &mut tmp[48..]; - for &digit in p.y.into_repr(e).iter().rev() { + for &digit in p.y.into_repr(e).0.iter().rev() { tmp.write_u64::(digit).unwrap(); } } @@ -469,8 +473,8 @@ impl G2Uncompressed { { let mut tmp = &mut tmp[0..]; let mut x = [0; 12]; - fq_arith::mac3(&mut x, &p.x.c1.into_repr(e), &e.fqparams.modulus); - fq_arith::add_carry(&mut x, &p.x.c0.into_repr(e)); + fq_arith::mac3(&mut x, &p.x.c1.into_repr(e).0, &e.fqparams.modulus); + fq_arith::add_carry(&mut x, &p.x.c0.into_repr(e).0); for &digit in x.iter().rev() { tmp.write_u64::(digit).unwrap(); @@ -480,8 +484,8 @@ impl G2Uncompressed { { let mut tmp = &mut tmp[96..]; let mut y = [0; 12]; - fq_arith::mac3(&mut y, &p.y.c1.into_repr(e), &e.fqparams.modulus); - fq_arith::add_carry(&mut y, &p.y.c0.into_repr(e)); + fq_arith::mac3(&mut y, &p.y.c1.into_repr(e).0, &e.fqparams.modulus); + fq_arith::add_carry(&mut y, &p.y.c0.into_repr(e).0); for &digit in y.iter().rev() { tmp.write_u64::(digit).unwrap(); @@ -690,7 +694,7 @@ impl G2Prepared { let mut r = q.to_jacobian(e); let mut found_one = false; - for i in BitIterator::from([BLS_X >> 1]) { + for i in BitIterator::new(&[BLS_X >> 1]) { if !found_one { found_one = i; continue; @@ -1004,7 +1008,7 @@ impl Engine for Bls381 { let mut f = Fq12::one(self); let mut found_one = false; - for i in BitIterator::from([BLS_X >> 1]) { + for i in BitIterator::new(&[BLS_X >> 1]) { if !found_one { found_one = i; continue; diff --git a/src/curves/mod.rs b/src/curves/mod.rs index 1462a90..549b780 100644 --- a/src/curves/mod.rs +++ b/src/curves/mod.rs @@ -12,8 +12,8 @@ pub mod wnaf; pub trait Engine: Sized + Clone + Send + Sync { - type Fq: PrimeField; - type Fr: SnarkField; + type Fq: PrimeField + Convert<>::Repr, Self>; + type Fr: SnarkField + Convert<>::Repr, Self>; type Fqe: SqrtField; type Fqk: Field; type G1: Curve + Convert<>::Affine, Self>; @@ -85,7 +85,7 @@ pub trait Curve: Sized + fn add_assign(&mut self, &E, other: &Self); fn sub_assign(&mut self, &E, other: &Self); fn add_assign_mixed(&mut self, &E, other: &Self::Affine); - fn mul_assign>(&mut self, &E, other: &S); + fn mul_assign>::Repr, E>>(&mut self, &E, other: &S); fn optimal_window(&E, scalar_bits: usize) -> Option; fn optimal_window_batch(&self, &E, scalars: usize) -> wnaf::WindowTable; @@ -99,7 +99,7 @@ pub trait Curve: Sized + table: &mut wnaf::WindowTable, scratch: &mut wnaf::WNAFTable ) -> Self { - let bits = E::Fr::repr_num_bits(&scalar); + let bits = scalar.num_bits(); match Self::optimal_window(e, bits) { Some(window) => { table.set_base(e, *self, window); @@ -131,7 +131,7 @@ pub trait CurveAffine: Copy + fn to_jacobian(&self, &E) -> Self::Jacobian; fn prepare(self, &E) -> >::Prepared; fn is_zero(&self) -> bool; - fn mul>(&self, &E, other: &S) -> Self::Jacobian; + fn mul>::Repr, E>>(&self, &E, other: &S) -> Self::Jacobian; fn negate(&mut self, &E); /// Returns true iff the point is on the curve and in the correct @@ -187,11 +187,11 @@ pub trait Field: Sized + fn mul_assign(&mut self, &E, other: &Self); fn inverse(&self, &E) -> Option; fn frobenius_map(&mut self, &E, power: usize); - fn pow>(&self, engine: &E, exp: &S) -> Self + fn pow>(&self, engine: &E, exp: S) -> Self { let mut res = Self::one(engine); - for i in BitIterator::from((*exp.convert(engine)).borrow()) { + for i in BitIterator::new(exp) { res.square(engine); if i { res.mul_assign(engine, self); @@ -209,45 +209,25 @@ pub trait SqrtField: Field fn sqrt(&self, engine: &E) -> Option; } -pub trait PrimeField: SqrtField + Convert<[u64], E> +pub trait PrimeFieldRepr: Clone + Eq + Ord + AsRef<[u64]> { + fn from_u64(a: u64) -> Self; + fn sub_noborrow(&mut self, other: &Self); + fn add_nocarry(&mut self, other: &Self); + fn num_bits(&self) -> usize; + fn is_zero(&self) -> bool; + fn is_odd(&self) -> bool; + fn div2(&mut self); +} + +pub trait PrimeField: SqrtField { - /// Little endian representation of a field element. - type Repr: Convert<[u64], E> + Eq + Clone; + type Repr: PrimeFieldRepr; + fn from_u64(&E, u64) -> Self; fn from_str(&E, s: &str) -> Result; fn from_repr(&E, Self::Repr) -> Result; fn into_repr(&self, &E) -> Self::Repr; - /// Determines if a is less than b - fn repr_lt(a: &Self::Repr, b: &Self::Repr) -> bool; - - /// Subtracts b from a. Undefined behavior if b > a. - fn repr_sub_noborrow(a: &mut Self::Repr, b: &Self::Repr); - - /// Adds b to a. Undefined behavior if overflow occurs. - fn repr_add_nocarry(a: &mut Self::Repr, b: &Self::Repr); - - /// Calculates the number of bits. - fn repr_num_bits(a: &Self::Repr) -> usize; - - /// Determines if the representation is of a zero. - fn repr_is_zero(a: &Self::Repr) -> bool; - - /// Determines if the representation is odd. - fn repr_is_odd(a: &Self::Repr) -> bool; - - /// Divides by two via rightshift. - fn repr_div2(a: &mut Self::Repr); - - /// Returns the limb of least significance - fn repr_least_significant_limb(a: &Self::Repr) -> u64; - - /// Creates a repr given a u64. - fn repr_from_u64(a: u64) -> Self::Repr; - - /// Returns an interator over all bits, most significant bit first. - fn bits(&self, &E) -> BitIterator; - /// Returns the field characteristic; the modulus. fn char(&E) -> Self::Repr; @@ -272,6 +252,17 @@ pub struct BitIterator { n: usize } +impl> BitIterator { + fn new(t: T) -> Self { + let bits = 64 * t.as_ref().len(); + + BitIterator { + t: t, + n: bits + } + } +} + impl> Iterator for BitIterator { type Item = bool; @@ -288,46 +279,6 @@ impl> Iterator for BitIterator { } } -impl<'a> From<&'a [u64]> for BitIterator<&'a [u64]> -{ - fn from(v: &'a [u64]) -> Self { - assert!(v.len() < 100); - - BitIterator { - t: v, - n: v.len() * 64 - } - } -} - -macro_rules! bit_iter_impl( - ($n:expr) => { - impl From<[u64; $n]> for BitIterator<[u64; $n]> { - fn from(v: [u64; $n]) -> Self { - BitIterator { - t: v, - n: $n * 64 - } - } - } - - impl Convert<[u64], E> for [u64; $n] { - type Target = [u64; $n]; - - fn convert(&self, _: &E) -> Cow<[u64; $n]> { - Cow::Borrowed(self) - } - } - }; -); - -bit_iter_impl!(1); -bit_iter_impl!(2); -bit_iter_impl!(3); -bit_iter_impl!(4); -bit_iter_impl!(5); -bit_iter_impl!(6); - #[cfg(test)] mod tests; diff --git a/src/curves/multiexp.rs b/src/curves/multiexp.rs index 5fee937..37b583b 100644 --- a/src/curves/multiexp.rs +++ b/src/curves/multiexp.rs @@ -1,6 +1,6 @@ //! This module provides an abstract implementation of the Bos-Coster multi-exponentiation algorithm. -use super::{Engine, Curve, CurveAffine, Field, PrimeField}; +use super::{Engine, Curve, CurveAffine, Field, PrimeField, PrimeFieldRepr}; use super::wnaf; use std::cmp::Ordering; use std::collections::BinaryHeap; @@ -109,8 +109,8 @@ fn justexp( { use std::cmp::min; - let abits = E::Fr::repr_num_bits(largest); - let bbits = E::Fr::repr_num_bits(smallest); + let abits = largest.num_bits(); + let bbits = smallest.num_bits(); let limit = min(abits-bbits, 20); if bbits < (1<>( // Rewrite let second_greatest = second_greatest.unwrap(); - E::Fr::repr_sub_noborrow(&mut greatest.scalar, &second_greatest.scalar); + greatest.scalar.sub_noborrow(&second_greatest.scalar); let mut tmp = elements[second_greatest.index]; elements[greatest.index].add_to_projective(e, &mut tmp); elements[second_greatest.index] = tmp; } } - if !E::Fr::repr_is_zero(&greatest.scalar) { + if !greatest.scalar.is_zero() { // Reinsert only nonzero scalars. heap.push(greatest); } @@ -213,13 +213,7 @@ struct Exp { impl Ord for Exp { fn cmp(&self, other: &Exp) -> Ordering { - if E::Fr::repr_lt(&self.scalar, &other.scalar) { - Ordering::Less - } else if self.scalar == other.scalar { - Ordering::Equal - } else { - Ordering::Greater - } + self.scalar.cmp(&other.scalar) } } diff --git a/src/curves/tests/mod.rs b/src/curves/tests/mod.rs index 2d8da83..c615526 100644 --- a/src/curves/tests/mod.rs +++ b/src/curves/tests/mod.rs @@ -106,7 +106,7 @@ fn test_bilinearity(e: &E) { let mut test4 = e.pairing(&a, &b); assert!(test4 != test1); - test4 = test4.pow(e, &s); + test4 = test4.pow(e, &s.into_repr(e)); assert_eq!(test1, test4); } diff --git a/src/curves/wnaf.rs b/src/curves/wnaf.rs index 2c2d05c..c4f062e 100644 --- a/src/curves/wnaf.rs +++ b/src/curves/wnaf.rs @@ -1,5 +1,5 @@ use std::marker::PhantomData; -use super::{Engine, Curve, PrimeField}; +use super::{Engine, Curve, PrimeField, PrimeFieldRepr}; /// Represents the scratch space for a wNAF form scalar. pub struct WNAFTable { @@ -20,19 +20,19 @@ impl WNAFTable { self.window = table.window; self.wnaf.truncate(0); - while !E::Fr::repr_is_zero(&c) { + while !c.is_zero() { let mut u; - if E::Fr::repr_is_odd(&c) { - u = (E::Fr::repr_least_significant_limb(&c) % (1 << (self.window+1))) as i64; + if c.is_odd() { + u = (c.as_ref()[0] % (1 << (self.window+1))) as i64; if u > (1 << self.window) { u -= 1 << (self.window+1); } if u > 0 { - E::Fr::repr_sub_noborrow(&mut c, &E::Fr::repr_from_u64(u as u64)); + c.sub_noborrow(&<>::Repr as PrimeFieldRepr>::from_u64(u as u64)); } else { - E::Fr::repr_add_nocarry(&mut c, &E::Fr::repr_from_u64((-u) as u64)); + c.add_nocarry(&<>::Repr as PrimeFieldRepr>::from_u64((-u) as u64)); } } else { u = 0; @@ -40,7 +40,7 @@ impl WNAFTable { self.wnaf.push(u); - E::Fr::repr_div2(&mut c); + c.div2(); } } }