use rand; use std::fmt; use std::borrow::Borrow; use serde::{Serialize, Deserialize}; use super::BitIterator; use super::{Cow, Convert}; pub mod bls381; pub mod multiexp; pub mod wnaf; pub mod domain; pub trait Engine: Sized + Clone + Send + Sync { type Fq: PrimeField + Convert<>::Repr, Self>; type Fr: SnarkField + Convert<>::Repr, Self>; type Fqe: SqrtField; type Fqk: Field; type G1: Curve + Convert<>::Affine, Self>; type G2: Curve + Convert<>::Affine, Self>; fn new() -> Self; /// Operate over the thread-local engine instance fn with FnOnce(&'a Self) -> R>(F) -> R; fn pairing(&self, p: &G1, q: &G2) -> Self::Fqk where G1: Convert<>::Affine, Self>, G2: Convert<>::Affine, Self> { self.final_exponentiation(&self.miller_loop( [( &(*p.convert(self)).borrow().prepare(self), &(*q.convert(self)).borrow().prepare(self) )].into_iter() )) } fn miller_loop<'a, I>(&self, I) -> Self::Fqk where I: IntoIterator>::Prepared, &'a >::Prepared )>; fn final_exponentiation(&self, &Self::Fqk) -> Self::Fqk; /// Perform multi-exponentiation. g and s must have the same length. fn multiexp>(&self, g: &[G::Affine], s: &[Self::Fr]) -> Result; fn batch_baseexp, S: AsRef<[Self::Fr]>>(&self, table: &wnaf::WindowTable, scalars: S) -> Vec; fn batchexp, S: AsRef<[Self::Fr]>>(&self, g: &mut [G::Affine], scalars: S, coeff: Option<&Self::Fr>); } pub trait Group: Copy + Send + Sync + Sized { fn group_zero(&E) -> Self; fn group_mul_assign(&mut self, &E, scalar: &E::Fr); fn group_add_assign(&mut self, &E, other: &Self); fn group_sub_assign(&mut self, &E, other: &Self); } pub trait Curve: Sized + Copy + Clone + Send + Sync + fmt::Debug + 'static + Group + self::multiexp::Projective { type Affine: CurveAffine; type Prepared: Clone + Send + Sync + 'static; fn zero(&E) -> Self; fn one(&E) -> Self; fn random(&E, &mut R) -> Self; fn is_zero(&self) -> bool; fn is_equal(&self, &E, other: &Self) -> bool; fn to_affine(&self, &E) -> Self::Affine; fn prepare(&self, &E) -> Self::Prepared; fn double(&mut self, &E); fn negate(&mut self, engine: &E); 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>::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; /// Performs optimal exponentiation of this curve element given the scalar, using /// wNAF when necessary. fn optimal_exp( &self, e: &E, scalar: >::Repr, table: &mut wnaf::WindowTable, scratch: &mut wnaf::WNAFTable ) -> Self { let bits = scalar.num_bits(); match Self::optimal_window(e, bits) { Some(window) => { table.set_base(e, *self, window); scratch.set_scalar(table, scalar); table.exp(e, scratch) }, None => { let mut tmp = *self; tmp.mul_assign(e, &scalar); tmp } } } } pub trait CurveAffine: Copy + Clone + Sized + Send + Sync + fmt::Debug + PartialEq + Eq + 'static { type Jacobian: Curve; type Uncompressed: CurveRepresentation; fn to_jacobian(&self, &E) -> Self::Jacobian; fn prepare(self, &E) -> >::Prepared; fn is_zero(&self) -> bool; 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 /// subgroup. This is guaranteed to return true unless the user /// invokes `to_affine_unchecked`. fn is_valid(&self, &E) -> bool; /// Produces an "uncompressed" representation of the curve point according /// to IEEE standards. fn to_uncompressed(&self, &E) -> Self::Uncompressed; } pub trait CurveRepresentation: Serialize + for<'a> Deserialize<'a> { type Affine: CurveAffine; /// If the point representation is valid (lies on the curve, correct /// subgroup) this function will return it. fn to_affine(&self, e: &E) -> Result { let p = try!(self.to_affine_unchecked(e)); if p.is_valid(e) { Ok(p) } else { Err(()) } } /// Returns the point under the assumption that it is valid. Undefined /// behavior if `to_affine` would have rejected the point. fn to_affine_unchecked(&self, &E) -> Result; } pub trait Field: Sized + Eq + PartialEq + Copy + Clone + Send + Sync + fmt::Debug + 'static { fn zero() -> Self; fn one(&E) -> Self; fn random(&E, &mut R) -> Self; fn is_zero(&self) -> bool; fn square(&mut self, engine: &E); fn double(&mut self, engine: &E); fn negate(&mut self, &E); fn add_assign(&mut self, &E, other: &Self); fn sub_assign(&mut self, &E, other: &Self); 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 { let mut res = Self::one(engine); for i in BitIterator::new(exp) { res.square(engine); if i { res.mul_assign(engine, self); } } res } } pub trait SqrtField: Field { /// Returns a square root of the field element, if it is /// quadratic residue. fn sqrt(&self, engine: &E) -> Option; } 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 { 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; /// Returns the field characteristic; the modulus. fn char(&E) -> Self::Repr; /// Returns how many bits are needed to represent an element of this /// field. fn num_bits(&E) -> usize; /// Returns how many bits of information can be reliably stored in the /// field element. fn capacity(&E) -> usize; } pub trait SnarkField: PrimeField + Group { fn s(&E) -> u64; fn multiplicative_generator(&E) -> Self; fn root_of_unity(&E) -> Self; } #[cfg(test)] mod tests; #[test] fn bls381_test_suite() { tests::test_engine::(); }