libcrux_traits/ecdh/
slice.rs

1//! This module contains the trait and related errors for an ECDH
2//! implementation that takes slices as arguments and writes outputs
3//! to mutable slices.
4
5use super::arrayref;
6use libcrux_secrets::U8;
7
8pub trait EcdhSlice {
9    /// Generate a Diffie-Hellman secret value.
10    /// It is the responsibility of the caller to ensure  that the `rand` argument is actually
11    /// random.
12    fn generate_secret(secret: &mut [U8], rand: &[U8]) -> Result<(), GenerateSecretError>;
13
14    /// Derive a Diffie-Hellman public value from a secret value.
15    fn secret_to_public(public: &mut [u8], secret: &[U8]) -> Result<(), SecretToPublicError>;
16
17    /// Generate a Diffie-Hellman secret value and derive the
18    /// corresponding public value in one step.
19    fn generate_pair(
20        public: &mut [u8],
21        secret: &mut [U8],
22        rand: &[U8],
23    ) -> Result<(), GenerateSecretError> {
24        Self::generate_secret(secret, rand)?;
25        Self::secret_to_public(public, secret).map_err(|_| GenerateSecretError::Unknown)
26    }
27
28    /// Derive a Diffie-Hellman shared secret from a public and a
29    /// secret value.
30    ///
31    /// This value is NOT (!) safe for use as a key and needs to be processed in a round of key
32    /// derivation, to ensure both that the output is uniformly random and that unkown key share
33    /// attacks can not happen.
34    fn derive_ecdh(derived: &mut [U8], public: &[u8], secret: &[U8]) -> Result<(), DeriveError>;
35
36    /// Check the validity of a Diffie-Hellman secret value.
37    fn validate_secret(secret: &[U8]) -> Result<(), ValidateSecretError>;
38}
39
40/// Implements [`EcdhSlice`] for any `$ty : arrayref::EcdhArrayref`
41/// with the given array bounds.
42#[macro_export]
43macro_rules! impl_ecdh_slice_trait {
44    ($type:ty => $rand_len:expr, $sk_len:expr, $pk_len:expr) => {
45        impl $crate::ecdh::slice::EcdhSlice for $type {
46            fn generate_secret(secret: &mut [U8], rand: &[U8]) -> Result<(), $crate::ecdh::slice::GenerateSecretError> {
47                let secret: &mut [U8; $sk_len] = secret
48                .try_into()
49                .map_err(|_|
50                    $crate::ecdh::slice::GenerateSecretError::InvalidSecretLength)?;
51
52                let rand: &[U8; $rand_len] = rand
53                .try_into()
54                .map_err(|_|
55                    $crate::ecdh::slice::GenerateSecretError::InvalidRandomnessLength)?;
56
57                <$type as $crate::ecdh::arrayref::EcdhArrayref<$rand_len, $sk_len, $pk_len>>::generate_secret(secret, rand)
58                .map_err($crate::ecdh::slice::GenerateSecretError::from)
59            }
60
61            fn secret_to_public(public: &mut [u8], secret: &[U8]) -> Result<(), $crate::ecdh::slice::SecretToPublicError> {
62                let secret: &[U8; $sk_len] = secret
63                .try_into()
64                .map_err(|_|
65                    $crate::ecdh::slice::SecretToPublicError::InvalidSecretLength)?;
66
67                let public: &mut [u8; $pk_len] = public
68                .try_into()
69                .map_err(|_|
70                    $crate::ecdh::slice::SecretToPublicError::InvalidPublicLength)?;
71
72                <$type as $crate::ecdh::arrayref::EcdhArrayref<$rand_len, $sk_len, $pk_len>>::secret_to_public(public, secret)
73                .map_err($crate::ecdh::slice::SecretToPublicError::from)
74            }
75
76            fn derive_ecdh(derived: &mut [U8], public: &[u8], secret: &[U8]) -> Result<(), $crate::ecdh::slice::DeriveError> {
77                let derived: &mut [U8; $pk_len] = derived
78                .try_into()
79                .map_err(|_|
80                    $crate::ecdh::slice::DeriveError::InvalidDeriveLength)?;
81
82                let secret: &[U8; $sk_len] = secret
83                .try_into()
84                .map_err(|_|
85                    $crate::ecdh::slice::DeriveError::InvalidSecretLength)?;
86
87                let public: &[u8; $pk_len] = public
88                .try_into()
89                .map_err(|_|
90                    $crate::ecdh::slice::DeriveError::InvalidPublicLength)?;
91
92                <$type as $crate::ecdh::arrayref::EcdhArrayref<$rand_len, $sk_len, $pk_len>>::derive_ecdh(derived, public, secret)
93                .map_err($crate::ecdh::slice::DeriveError::from)
94            }
95
96            fn validate_secret(secret: &[U8]) -> Result<(), $crate::ecdh::slice::ValidateSecretError> {
97                let secret: &[U8; $sk_len] = secret
98                .try_into()
99                .map_err(|_|
100                    $crate::ecdh::slice::ValidateSecretError::InvalidSecretLength)?;
101
102                <$type as $crate::ecdh::arrayref::EcdhArrayref<$rand_len, $sk_len, $pk_len>>::validate_secret(secret)
103                .map_err($crate::ecdh::slice::ValidateSecretError::from)
104            }
105        }
106    };
107}
108
109pub use impl_ecdh_slice_trait;
110
111#[derive(Debug)]
112/// An error during secret value generation.
113pub enum GenerateSecretError {
114    /// Error generating secret value with provided randomness
115    InvalidRandomness,
116    /// The provided secret value buffer has the wrong length
117    InvalidSecretLength,
118    /// The provided randomness has the wrong length
119    InvalidRandomnessLength,
120    /// An unknown error occurred
121    Unknown,
122}
123
124#[derive(Debug)]
125/// An error during derivation of a public value from a secret value.
126pub enum SecretToPublicError {
127    /// Secret value was invalid
128    InvalidSecret,
129    /// The provided secret value buffer has the wrong length
130    InvalidSecretLength,
131    /// The provided public value buffer has the wrong length
132    InvalidPublicLength,
133    /// An unknown error occurred
134    Unknown,
135}
136
137#[derive(Debug)]
138/// An error derivation of Diffie-Hellman shared secret.
139pub enum DeriveError {
140    /// Public value was invalid
141    InvalidPublic,
142    /// Secret value was invalid
143    InvalidSecret,
144    /// The provided secret value buffer has the wrong length
145    InvalidSecretLength,
146    /// The provided public value buffer has the wrong length
147    InvalidPublicLength,
148    /// The provided shared secret buffer has the wrong length
149    InvalidDeriveLength,
150    /// An unknown error occurred
151    Unknown,
152}
153
154#[derive(Debug)]
155/// A Diffie-Hellman secret value was found to be invalid.
156pub enum ValidateSecretError {
157    /// Secret value was invalid
158    InvalidSecret,
159    /// The provided secret value buffer has the wrong length
160    InvalidSecretLength,
161    /// An unknown error occurred
162    Unknown,
163}
164
165impl From<arrayref::GenerateSecretError> for GenerateSecretError {
166    fn from(value: arrayref::GenerateSecretError) -> Self {
167        match value {
168            arrayref::GenerateSecretError::InvalidRandomness => {
169                GenerateSecretError::InvalidRandomness
170            }
171            arrayref::GenerateSecretError::Unknown => GenerateSecretError::Unknown,
172        }
173    }
174}
175impl From<arrayref::SecretToPublicError> for SecretToPublicError {
176    fn from(value: arrayref::SecretToPublicError) -> Self {
177        match value {
178            arrayref::SecretToPublicError::InvalidSecret => SecretToPublicError::InvalidSecret,
179            arrayref::SecretToPublicError::Unknown => SecretToPublicError::Unknown,
180        }
181    }
182}
183impl From<arrayref::DeriveError> for DeriveError {
184    fn from(value: arrayref::DeriveError) -> Self {
185        match value {
186            arrayref::DeriveError::InvalidPublic => DeriveError::InvalidPublic,
187            arrayref::DeriveError::InvalidSecret => DeriveError::InvalidSecret,
188            arrayref::DeriveError::Unknown => DeriveError::Unknown,
189        }
190    }
191}
192impl From<arrayref::ValidateSecretError> for ValidateSecretError {
193    fn from(value: arrayref::ValidateSecretError) -> Self {
194        match value {
195            arrayref::ValidateSecretError::InvalidSecret => ValidateSecretError::InvalidSecret,
196            arrayref::ValidateSecretError::Unknown => ValidateSecretError::Unknown,
197        }
198    }
199}
200
201impl core::fmt::Display for GenerateSecretError {
202    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203        let text = match self {
204            GenerateSecretError::InvalidRandomness => {
205                "error generating secret value with provided randomness"
206            }
207            GenerateSecretError::Unknown => "an unknown error occured",
208            GenerateSecretError::InvalidRandomnessLength => {
209                "the provided randomess buffer has the wrong length"
210            }
211            GenerateSecretError::InvalidSecretLength => {
212                "the provided secret value buffer has the wrong length"
213            }
214        };
215
216        f.write_str(text)
217    }
218}
219
220impl core::fmt::Display for SecretToPublicError {
221    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222        let text = match self {
223            SecretToPublicError::InvalidSecret => "secret value is invalid",
224            SecretToPublicError::Unknown => "an unknown error occured",
225            SecretToPublicError::InvalidSecretLength => {
226                "the provided secret value buffer has the wrong length"
227            }
228            SecretToPublicError::InvalidPublicLength => {
229                "the provided public value buffer has the wrong length"
230            }
231        };
232
233        f.write_str(text)
234    }
235}
236
237impl core::fmt::Display for DeriveError {
238    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239        let text = match self {
240            DeriveError::InvalidPublic => "public value is invalid",
241            DeriveError::InvalidSecret => "secret value is invalid",
242            DeriveError::Unknown => "an unknown error occured",
243            DeriveError::InvalidSecretLength => {
244                "the provided secret value buffer has the wrong length"
245            }
246            DeriveError::InvalidPublicLength => {
247                "the provided public value buffer has the wrong length"
248            }
249            DeriveError::InvalidDeriveLength => {
250                "the provided shared secret buffer has the wrong length"
251            }
252        };
253
254        f.write_str(text)
255    }
256}
257
258impl core::fmt::Display for ValidateSecretError {
259    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
260        let text = match self {
261            ValidateSecretError::InvalidSecret => "secret value is invalid",
262            ValidateSecretError::Unknown => "an unknown error occured",
263            ValidateSecretError::InvalidSecretLength => {
264                "the provided secret value buffer has the wrong length"
265            }
266        };
267
268        f.write_str(text)
269    }
270}
271
272#[cfg(feature = "error-in-core")]
273/// Here we implement the Error trait. This has only been added to core relatively recently, so we
274/// are hiding that behind a feature.
275mod error_in_core {
276    impl core::error::Error for super::GenerateSecretError {}
277    impl core::error::Error for super::SecretToPublicError {}
278    impl core::error::Error for super::DeriveError {}
279    impl core::error::Error for super::ValidateSecretError {}
280}