// `clippy` is a code linting tool for improving code quality by catching // common mistakes or strange code patterns. If the `clippy` feature is // provided, it is enabled and all compiler warnings are prohibited. #![cfg_attr(feature = "clippy", deny(warnings))] #![cfg_attr(feature = "clippy", feature(plugin))] #![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))] #![cfg_attr(feature = "clippy", allow(many_single_char_names))] #![cfg_attr(feature = "clippy", allow(new_without_default_derive))] #![cfg_attr(feature = "clippy", allow(write_literal))] // Force public structures to implement Debug #![deny(missing_debug_implementations)] extern crate byteorder; extern crate ff; extern crate rand; #[cfg(test)] pub mod tests; pub mod bls12_381; mod wnaf; pub use self::wnaf::Wnaf; use ff::*; use std::error::Error; use std::fmt; /// 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: Sized + 'static + Clone { /// This is the scalar field of the G1/G2 groups. type Fr: PrimeField + SqrtField; /// The projective representation of an element in G1. type G1: CurveProjective< Engine = Self, Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine, > + From; /// The affine representation of an element in G1. type G1Affine: CurveAffine< Engine = Self, Base = Self::Fq, Scalar = Self::Fr, Projective = Self::G1, Pair = Self::G2Affine, PairingResult = Self::Fqk, > + From; /// The projective representation of an element in G2. type G2: CurveProjective< Engine = Self, Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine, > + From; /// The affine representation of an element in G2. type G2Affine: CurveAffine< Engine = Self, Base = Self::Fqe, Scalar = Self::Fr, Projective = Self::G2, Pair = Self::G1Affine, PairingResult = Self::Fqk, > + From; /// The base field that hosts G1. type Fq: PrimeField + SqrtField; /// The extension field that hosts G2. type Fqe: SqrtField; /// The extension field that hosts the target group of the pairing. type Fqk: Field; /// Perform a miller loop with some number of (G1, G2) pairs. fn miller_loop<'a, I>(i: I) -> Self::Fqk where I: IntoIterator< Item = &'a ( &'a ::Prepared, &'a ::Prepared, ), >; /// Perform final exponentiation of the result of a miller loop. fn final_exponentiation(&Self::Fqk) -> Option; /// Performs a complete pairing operation `(p, q)`. fn pairing(p: G1, q: G2) -> Self::Fqk where G1: Into, G2: Into, { Self::final_exponentiation(&Self::miller_loop( [(&(p.into().prepare()), &(q.into().prepare()))].into_iter(), )).unwrap() } } /// 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; type Prepared: Clone + Send + Sync + 'static; type Uncompressed: EncodedPoint; type Compressed: EncodedPoint; type Pair: CurveAffine; 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()), } } }