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"))]
7#[allow(unused_imports)]
8use std_shims::prelude::*;
9#[cfg(any(feature = "alloc", feature = "std"))]
10use std_shims::io::{self, Read};
11
12use rand_core::{RngCore, CryptoRng};
13
14use zeroize::Zeroize;
15use subtle::ConstantTimeEq;
16
17use digest::{core_api::BlockSizeUser, Digest, HashMarker};
18use transcript::SecureDigest;
19
20pub use group;
21use group::{
22 ff::{Field, PrimeField, PrimeFieldBits},
23 Group, GroupOps,
24 prime::PrimeGroup,
25};
26#[cfg(any(feature = "alloc", feature = "std"))]
27use group::GroupEncoding;
28
29#[cfg(feature = "dalek")]
30mod dalek;
31#[cfg(feature = "ristretto")]
32pub use dalek::Ristretto;
33#[cfg(feature = "ed25519")]
34pub use dalek::Ed25519;
35
36#[cfg(feature = "kp256")]
37mod kp256;
38#[cfg(feature = "secp256k1")]
39pub use kp256::Secp256k1;
40#[cfg(feature = "p256")]
41pub use kp256::P256;
42
43#[cfg(feature = "ed448")]
44mod ed448;
45#[cfg(feature = "ed448")]
46pub use ed448::*;
47
48pub trait Ciphersuite:
50 'static + Send + Sync + Clone + Copy + PartialEq + Eq + Debug + Zeroize
51{
52 type F: PrimeField + PrimeFieldBits + Zeroize;
55 type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq;
57 type H: Send + Clone + BlockSizeUser + Digest + HashMarker + SecureDigest;
60
61 const ID: &'static [u8];
63
64 fn generator() -> Self::G;
67
68 #[allow(non_snake_case)]
77 fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
78
79 #[allow(non_snake_case)]
81 fn random_nonzero_F<R: RngCore + CryptoRng>(rng: &mut R) -> Self::F {
82 let mut res;
83 while {
84 res = Self::F::random(&mut *rng);
85 res.ct_eq(&Self::F::ZERO).into()
86 } {}
87 res
88 }
89
90 #[cfg(any(feature = "alloc", feature = "std"))]
92 #[allow(non_snake_case)]
93 fn read_F<R: Read>(reader: &mut R) -> io::Result<Self::F> {
94 let mut encoding = <Self::F as PrimeField>::Repr::default();
95 reader.read_exact(encoding.as_mut())?;
96
97 let res = Option::<Self::F>::from(Self::F::from_repr(encoding))
99 .ok_or_else(|| io::Error::other("non-canonical scalar"));
100 encoding.as_mut().zeroize();
101 res
102 }
103
104 #[cfg(any(feature = "alloc", feature = "std"))]
109 #[allow(non_snake_case)]
110 fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
111 let mut encoding = <Self::G as GroupEncoding>::Repr::default();
112 reader.read_exact(encoding.as_mut())?;
113
114 let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
115 .ok_or_else(|| io::Error::other("invalid point"))?;
116 if point.to_bytes().as_ref() != encoding.as_ref() {
117 Err(io::Error::other("non-canonical point"))?;
118 }
119 Ok(point)
120 }
121}