#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] use core::fmt::Debug; #[cfg(feature = "std")] use std::io::{self, Read}; use rand_core::{RngCore, CryptoRng}; use zeroize::Zeroize; use subtle::ConstantTimeEq; use digest::{core_api::BlockSizeUser, Digest}; use group::{ ff::{Field, PrimeField, PrimeFieldBits}, Group, GroupOps, prime::PrimeGroup, }; #[cfg(feature = "std")] use group::GroupEncoding; #[cfg(feature = "dalek")] mod dalek; #[cfg(feature = "ristretto")] pub use dalek::Ristretto; #[cfg(feature = "ed25519")] pub use dalek::Ed25519; #[cfg(feature = "kp256")] mod kp256; #[cfg(feature = "secp256k1")] pub use kp256::Secp256k1; #[cfg(feature = "p256")] pub use kp256::P256; #[cfg(feature = "ed448")] mod ed448; #[cfg(feature = "ed448")] pub use ed448::*; /// Unified trait defining a ciphersuite around an elliptic curve. pub trait Ciphersuite: Clone + Copy + PartialEq + Eq + Debug + Zeroize { /// Scalar field element type. // This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses type F: PrimeField + PrimeFieldBits + Zeroize; /// Group element type. type G: Group + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq; /// Hash algorithm used with this curve. // Requires BlockSizeUser so it can be used within Hkdf which requies that. type H: Clone + BlockSizeUser + Digest; /// ID for this curve. const ID: &'static [u8]; /// Generator for the group. // While group does provide this in its API, privacy coins may want to use a custom basepoint fn generator() -> Self::G; /// Hash the provided dst and message to a scalar. #[allow(non_snake_case)] fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F; /// Generate a random non-zero scalar. #[allow(non_snake_case)] fn random_nonzero_F(rng: &mut R) -> Self::F { let mut res; while { res = Self::F::random(&mut *rng); res.ct_eq(&Self::F::zero()).into() } {} res } /// Read a canonical scalar from something implementing std::io::Read. #[cfg(feature = "std")] #[allow(non_snake_case)] fn read_F(reader: &mut R) -> io::Result { let mut encoding = ::Repr::default(); reader.read_exact(encoding.as_mut())?; // ff mandates this is canonical let res = Option::::from(Self::F::from_repr(encoding)) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "non-canonical scalar")); for b in encoding.as_mut() { b.zeroize(); } res } /// Read a canonical point from something implementing std::io::Read. #[cfg(feature = "std")] #[allow(non_snake_case)] fn read_G(reader: &mut R) -> io::Result { let mut encoding = ::Repr::default(); reader.read_exact(encoding.as_mut())?; let point = Option::::from(Self::G::from_bytes(&encoding)) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point"))?; if point.to_bytes().as_ref() != encoding.as_ref() { Err(io::Error::new(io::ErrorKind::Other, "non-canonical point"))?; } Ok(point) } }