Skip to main content

libcrux_ml_dsa/
types.rs

1//! Common types
2
3macro_rules! impl_struct {
4    ($name:ident, $doc:expr) => {
5        #[doc = $doc]
6        #[derive(Clone)]
7        pub struct $name<const SIZE: usize> {
8            pub(crate) value: [u8; SIZE],
9        }
10
11        impl<const SIZE: usize> $name<SIZE> {
12            /// Init with zero
13            pub const fn zero() -> Self {
14                Self { value: [0u8; SIZE] }
15            }
16
17            /// Build
18            pub const fn new(value: [u8; SIZE]) -> Self {
19                Self { value }
20            }
21
22            /// A reference to the raw byte slice.
23            pub const fn as_slice(&self) -> &[u8] {
24                &self.value
25            }
26
27            /// A reference to the raw byte array.
28            pub const fn as_ref(&self) -> &[u8; SIZE] {
29                &self.value
30            }
31
32            /// The number of bytes
33            pub const fn len() -> usize {
34                SIZE
35            }
36        }
37    };
38}
39
40impl_struct!(MLDSASigningKey, "An ML-DSA signature key.");
41impl_struct!(MLDSAVerificationKey, "An ML-DSA verification key.");
42impl_struct!(MLDSASignature, "An ML-DSA signature.");
43
44macro_rules! impl_non_hax_types {
45    ($name:ident) => {
46        impl<const SIZE: usize> $name<SIZE> {
47            /// A mutable reference to the raw byte slice.
48            pub fn as_mut_slice(&mut self) -> &mut [u8] {
49                &mut self.value
50            }
51
52            /// A mutable reference to the raw byte array.
53            pub fn as_ref_mut(&mut self) -> &mut [u8; SIZE] {
54                &mut self.value
55            }
56        }
57    };
58}
59
60// Hax can't handle these.
61mod non_hax_impls {
62    use super::*;
63    impl_non_hax_types!(MLDSASigningKey);
64    impl_non_hax_types!(MLDSAVerificationKey);
65    impl_non_hax_types!(MLDSASignature);
66}
67
68/// An ML-DSA key pair.
69pub struct MLDSAKeyPair<const VERIFICATION_KEY_SIZE: usize, const SIGNING_KEY_SIZE: usize> {
70    pub signing_key: MLDSASigningKey<SIGNING_KEY_SIZE>,
71    pub verification_key: MLDSAVerificationKey<VERIFICATION_KEY_SIZE>,
72}
73
74#[cfg_attr(not(eurydice), derive(Debug))]
75pub enum VerificationError {
76    MalformedHintError,
77    SignerResponseExceedsBoundError,
78    CommitmentHashesDontMatchError,
79    // FIXME: Eurydice can't handle enum variants with the same name
80    // https://github.com/AeneasVerif/eurydice/issues/102
81    VerificationContextTooLongError,
82}
83
84#[cfg_attr(not(eurydice), derive(Debug))]
85pub enum SigningError {
86    RejectionSamplingError,
87    ContextTooLongError,
88}
89
90#[cfg(feature = "codec")]
91mod codec {
92    use super::*;
93
94    macro_rules! impl_tls_codec_for_generic_struct {
95        ($name:ident) => {
96            // XXX: `tls_codec::{Serialize, Deserialize}` are only
97            // available for feature `std`. For `no_std` scenarios, we
98            // need to implement `tls_codec::{SerializeBytes,
99            // DeserializeBytes}`, but `SerializeBytes` is not
100            // implemented for `VLByteSlice`.
101            impl<const SIZE: usize> tls_codec::DeserializeBytes for $name<SIZE> {
102                fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), tls_codec::Error> {
103                    let (bytes, remainder) = tls_codec::VLBytes::tls_deserialize_bytes(bytes)?;
104                    Ok((
105                        Self {
106                            value: bytes
107                                .as_ref()
108                                .try_into()
109                                .map_err(|_| tls_codec::Error::InvalidInput)?,
110                        },
111                        remainder,
112                    ))
113                }
114            }
115
116            #[cfg(feature = "std")]
117            impl<const SIZE: usize> tls_codec::Serialize for $name<SIZE> {
118                fn tls_serialize<W: std::io::Write>(
119                    &self,
120                    writer: &mut W,
121                ) -> Result<usize, tls_codec::Error> {
122                    let out = tls_codec::VLByteSlice(self.as_ref());
123                    out.tls_serialize(writer)
124                }
125            }
126
127            #[cfg(feature = "std")]
128            impl<const SIZE: usize> tls_codec::Serialize for &$name<SIZE> {
129                fn tls_serialize<W: std::io::Write>(
130                    &self,
131                    writer: &mut W,
132                ) -> Result<usize, tls_codec::Error> {
133                    (*self).tls_serialize(writer)
134                }
135            }
136
137            #[cfg(feature = "std")]
138            impl<const SIZE: usize> tls_codec::Deserialize for $name<SIZE> {
139                fn tls_deserialize<R: std::io::Read>(
140                    bytes: &mut R,
141                ) -> Result<Self, tls_codec::Error> {
142                    let bytes = tls_codec::VLBytes::tls_deserialize(bytes)?;
143                    Ok(Self {
144                        value: bytes
145                            .as_ref()
146                            .try_into()
147                            .map_err(|_| tls_codec::Error::InvalidInput)?,
148                    })
149                }
150            }
151
152            impl<const SIZE: usize> tls_codec::Size for $name<SIZE> {
153                fn tls_serialized_len(&self) -> usize {
154                    tls_codec::VLByteSlice(self.as_ref()).tls_serialized_len()
155                }
156            }
157
158            impl<const SIZE: usize> tls_codec::Size for &$name<SIZE> {
159                fn tls_serialized_len(&self) -> usize {
160                    (*self).tls_serialized_len()
161                }
162            }
163        };
164    }
165
166    impl_tls_codec_for_generic_struct!(MLDSAVerificationKey);
167    impl_tls_codec_for_generic_struct!(MLDSASignature);
168}