1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc = include_str!("lib.md")]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5use core::fmt::Debug;
6#[cfg(any(feature = "alloc", feature = "std"))]
7use std_shims::io::{self, Read};
8
9use rand_core::{RngCore, CryptoRng};
10
11use zeroize::Zeroize;
12use subtle::ConstantTimeEq;
13
14use digest::{core_api::BlockSizeUser, Digest, HashMarker};
15use transcript::SecureDigest;
16
17pub use group;
18use group::{
19 ff::{Field, PrimeField, PrimeFieldBits},
20 Group, GroupOps,
21 prime::PrimeGroup,
22};
23#[cfg(any(feature = "alloc", feature = "std"))]
24use group::GroupEncoding;
25
26#[cfg(feature = "dalek")]
27mod dalek;
28#[cfg(feature = "ristretto")]
29pub use dalek::Ristretto;
30#[cfg(feature = "ed25519")]
31pub use dalek::Ed25519;
32
33#[cfg(feature = "kp256")]
34mod kp256;
35#[cfg(feature = "secp256k1")]
36pub use kp256::Secp256k1;
37#[cfg(feature = "p256")]
38pub use kp256::P256;
39
40#[cfg(feature = "ed448")]
41mod ed448;
42#[cfg(feature = "ed448")]
43pub use ed448::*;
44
45pub trait Ciphersuite:
47 'static + Send + Sync + Clone + Copy + PartialEq + Eq + Debug + Zeroize
48{
49 type F: PrimeField + PrimeFieldBits + Zeroize;
52 type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq;
54 type H: Send + Clone + BlockSizeUser + Digest + HashMarker + SecureDigest;
57
58 const ID: &'static [u8];
60
61 fn generator() -> Self::G;
64
65 #[allow(non_snake_case)]
74 fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
75
76 #[allow(non_snake_case)]
78 fn random_nonzero_F<R: RngCore + CryptoRng>(rng: &mut R) -> Self::F {
79 let mut res;
80 while {
81 res = Self::F::random(&mut *rng);
82 res.ct_eq(&Self::F::ZERO).into()
83 } {}
84 res
85 }
86
87 #[cfg(any(feature = "alloc", feature = "std"))]
89 #[allow(non_snake_case)]
90 fn read_F<R: Read>(reader: &mut R) -> io::Result<Self::F> {
91 let mut encoding = <Self::F as PrimeField>::Repr::default();
92 reader.read_exact(encoding.as_mut())?;
93
94 let res = Option::<Self::F>::from(Self::F::from_repr(encoding))
96 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "non-canonical scalar"));
97 encoding.as_mut().zeroize();
98 res
99 }
100
101 #[cfg(any(feature = "alloc", feature = "std"))]
103 #[allow(non_snake_case)]
104 fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
105 let mut encoding = <Self::G as GroupEncoding>::Repr::default();
106 reader.read_exact(encoding.as_mut())?;
107
108 let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
109 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point"))?;
110 if point.to_bytes().as_ref() != encoding.as_ref() {
111 Err(io::Error::new(io::ErrorKind::Other, "non-canonical point"))?;
112 }
113 Ok(point)
114 }
115}