Skip to main content

libcrux_ed25519/
impl_hacl.rs

1#[cfg(feature = "codec")]
2use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize};
3
4#[cfg(feature = "codec")]
5extern crate std;
6
7#[cfg(feature = "codec")]
8use std::format;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Error {
12    SigningError,
13    InvalidSignature,
14    KeyGen,
15}
16
17/// An Ed25519 public, verification key
18#[derive(Default, Clone, Copy)]
19#[cfg_attr(feature = "codec", derive(TlsSerialize, TlsDeserialize, TlsSize))]
20pub struct VerificationKey {
21    value: [u8; 32],
22}
23
24impl VerificationKey {
25    /// Get the raw bytes
26    pub fn into_bytes(self) -> [u8; 32] {
27        self.value
28    }
29
30    /// Build a new verification key
31    pub fn from_bytes(value: [u8; 32]) -> Self {
32        Self { value }
33    }
34}
35
36impl AsRef<[u8; 32]> for VerificationKey {
37    fn as_ref(&self) -> &[u8; 32] {
38        &self.value
39    }
40}
41
42/// An Ed25519 private, signing  key
43#[derive(Default)]
44pub struct SigningKey {
45    value: [u8; 32],
46}
47
48impl SigningKey {
49    /// Get the raw bytes
50    pub fn into_bytes(self) -> [u8; 32] {
51        self.value
52    }
53
54    /// Build a new signing key
55    pub fn from_bytes(value: [u8; 32]) -> Self {
56        Self { value }
57    }
58}
59
60impl AsRef<[u8; 32]> for SigningKey {
61    fn as_ref(&self) -> &[u8; 32] {
62        &self.value
63    }
64}
65
66/// The hacl implementation requires that
67/// - the private key is a 32 byte buffer
68/// - the signature is a 64 byte buffer,
69/// - the payload buffer is not shorter than payload_len.
70///
71/// We enforce the first two using types, and the latter by using `payload.len()` and `payload_len`.
72/// This has the caveat that `payload_len` must be <= u32::MAX, so we return an error if that is
73/// not the case.
74#[inline(always)]
75pub fn sign(payload: &[u8], private_key: &[u8; 32]) -> Result<[u8; 64], Error> {
76    let mut signature = [0u8; 64];
77    crate::hacl::ed25519::sign(
78        &mut signature,
79        private_key,
80        payload.len().try_into().map_err(|_| Error::SigningError)?,
81        payload,
82    );
83
84    Ok(signature)
85}
86
87/// The hacl implementation requires that
88/// - the public key is a 32 byte buffer
89/// - the signature is a 64 byte buffer,
90/// - the payload buffer is not shorter than payload_len.
91///
92/// We enforce the first two using types, and the latter by using `payload.len()` and `payload_len`.
93/// This has the caveat that `payload_len` must be <= u32::MAX, so we return an error if that is
94/// not the case.
95#[inline(always)]
96pub fn verify(payload: &[u8], public_key: &[u8; 32], signature: &[u8; 64]) -> Result<(), Error> {
97    if crate::hacl::ed25519::verify(
98        public_key,
99        payload.len().try_into().map_err(|_| Error::SigningError)?,
100        payload,
101        signature,
102    ) {
103        Ok(())
104    } else {
105        Err(Error::InvalidSignature)
106    }
107}
108
109/// Compute the public point for the given secret key `sk`.
110/// The hacl implementation requires that these are both 32 byte buffers, which we enforce through
111/// types.
112#[inline(always)]
113pub fn secret_to_public(pk: &mut [u8; 32], sk: &[u8; 32]) {
114    crate::hacl::ed25519::secret_to_public(pk, sk)
115}
116
117#[cfg(feature = "rand")]
118pub fn generate_key_pair(
119    rng: &mut impl rand_core::CryptoRng,
120) -> Result<(SigningKey, VerificationKey), Error> {
121    use rand_core::TryRngCore;
122
123    const LIMIT: usize = 100;
124    let mut sk = [0u8; 32];
125    let mut pk = [0u8; 32];
126
127    for _ in 0..LIMIT {
128        rng.try_fill_bytes(&mut sk).map_err(|_| Error::KeyGen)?;
129
130        // We don't want a 0 key.
131        if sk.iter().all(|&b| b == 0) {
132            sk = [0u8; 32];
133            continue;
134        }
135
136        break;
137    }
138
139    secret_to_public(&mut pk, &sk);
140
141    Ok((SigningKey { value: sk }, VerificationKey { value: pk }))
142}