1use crate::Error;
2
3#[derive(Debug, Clone)]
5pub struct PublicKey<const LEN: usize> {
6 n: [u8; LEN],
7}
8
9pub struct PrivateKey<const LEN: usize> {
11 pk: PublicKey<LEN>,
12 d: [u8; LEN],
13}
14
15impl<const LEN: usize> alloc::fmt::Debug for PrivateKey<LEN> {
16 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17 f.debug_struct("PrivateKey")
18 .field("pk", &self.pk)
19 .field("d", &"****")
20 .finish()
21 }
22}
23
24#[derive(Debug, Clone)]
26pub struct VarLenPublicKey<'a> {
27 n: &'a [u8],
28}
29
30impl<'a> TryFrom<&'a [u8]> for VarLenPublicKey<'a> {
31 type Error = Error;
32
33 fn try_from(n: &'a [u8]) -> Result<Self, Error> {
34 match n.len() {
35 256 | 384 | 512 | 768 | 1024 => Ok(Self { n }),
36 _ => Err(Error::InvalidKeyLength),
37 }
38 }
39}
40
41impl VarLenPublicKey<'_> {
42 pub fn key_len(&self) -> usize {
44 self.n.len()
45 }
46
47 pub fn n(&self) -> &[u8] {
49 self.n
50 }
51}
52impl alloc::fmt::Debug for VarLenPrivateKey<'_> {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 f.debug_struct("PrivateKey")
55 .field("pk", &self.pk)
56 .field("d", &"****")
57 .finish()
58 }
59}
60
61pub struct VarLenPrivateKey<'a> {
63 pk: VarLenPublicKey<'a>,
64 d: &'a [u8],
65}
66
67impl<'a> VarLenPrivateKey<'a> {
68 pub fn from_components(n: &'a [u8], d: &'a [u8]) -> Result<Self, Error> {
70 if n.len() != d.len() {
71 return Err(Error::KeyLengthMismatch);
72 }
73
74 Ok(Self {
75 pk: n.try_into()?,
76 d,
77 })
78 }
79
80 pub fn pk(&self) -> &VarLenPublicKey {
82 &self.pk
83 }
84
85 pub fn key_len(&self) -> usize {
87 self.d.len()
88 }
89
90 pub fn d(&self) -> &[u8] {
92 self.d
93 }
94}
95
96const E_BITS: u32 = 17;
97const E: [u8; 3] = [1, 0, 1];
98
99fn hacl_hash_alg(alg: crate::DigestAlgorithm) -> libcrux_hacl_rs::streaming_types::hash_alg {
100 match alg {
101 crate::DigestAlgorithm::Sha2_256 => libcrux_hacl_rs::streaming_types::hash_alg::SHA2_256,
102 crate::DigestAlgorithm::Sha2_384 => libcrux_hacl_rs::streaming_types::hash_alg::SHA2_384,
103 crate::DigestAlgorithm::Sha2_512 => libcrux_hacl_rs::streaming_types::hash_alg::SHA2_512,
104 }
105}
106
107macro_rules! impl_rsapss {
110 ($sign_fn:ident, $verify_fn:ident, $bits:literal, $bytes:literal) => {
111 impl From<[u8; $bytes]> for PublicKey<$bytes> {
112 fn from(n: [u8; $bytes]) -> Self {
113 Self { n }
114 }
115 }
116
117 impl PublicKey<$bytes> {
118 pub fn as_var_len(&self) -> VarLenPublicKey<'_> {
120 VarLenPublicKey { n: &self.n }
121 }
122
123 pub fn n(&self) -> &[u8; $bytes] {
125 &self.n
126 }
127 }
128
129 impl PrivateKey<$bytes> {
130 pub fn from_components(n: [u8; $bytes], d: [u8; $bytes]) -> Self {
132 Self { pk: n.into(), d }
133 }
134
135 pub fn pk(&self) -> &PublicKey<$bytes> {
137 &self.pk
138 }
139
140 pub fn as_var_len(&self) -> VarLenPrivateKey<'_> {
142 VarLenPrivateKey {
143 pk: self.pk.as_var_len(),
144 d: &self.d,
145 }
146 }
147
148 pub fn d(&self) -> &[u8; $bytes] {
150 &self.d
151 }
152 }
153
154 impl<'a> From<&'a PublicKey<$bytes>> for VarLenPublicKey<'a> {
155 fn from(value: &'a PublicKey<$bytes>) -> Self {
156 value.as_var_len()
157 }
158 }
159
160 impl<'a> From<&'a PrivateKey<$bytes>> for VarLenPrivateKey<'a> {
161 fn from(value: &'a PrivateKey<$bytes>) -> Self {
162 value.as_var_len()
163 }
164 }
165
166 pub fn $sign_fn(
174 alg: crate::DigestAlgorithm,
175 sk: &PrivateKey<$bytes>,
176 msg: &[u8],
177 salt: &[u8],
178 sig: &mut [u8; $bytes],
179 ) -> Result<(), Error> {
180 sign_varlen(alg, &sk.into(), msg, salt, sig)
181 }
182
183 pub fn $verify_fn(
191 alg: crate::DigestAlgorithm,
192 pk: &PublicKey<$bytes>,
193 msg: &[u8],
194 salt_len: u32,
195 sig: &[u8; $bytes],
196 ) -> Result<(), Error> {
197 verify_varlen(alg, &pk.into(), msg, salt_len, sig)
198 }
199 };
200}
201
202impl_rsapss!(sign_2048, verify_2048, 2048, 256);
203impl_rsapss!(sign_3072, verify_3072, 3072, 384);
204impl_rsapss!(sign_4096, verify_4096, 4096, 512);
205impl_rsapss!(sign_6144, verify_6144, 6144, 768);
206impl_rsapss!(sign_8192, verify_8192, 8192, 1024);
207
208pub fn sign(
217 alg: crate::DigestAlgorithm,
218 sk: &VarLenPrivateKey<'_>,
219 msg: &[u8],
220 salt: &[u8],
221 sig: &mut [u8],
222) -> Result<(), Error> {
223 if sig.len() != sk.key_len() {
224 return Err(Error::InvalidSignatureLength);
225 }
226
227 sign_varlen(alg, sk, msg, salt, sig)
228}
229
230pub fn verify(
238 alg: crate::DigestAlgorithm,
239 pk: &VarLenPublicKey<'_>,
240 msg: &[u8],
241 salt_len: u32,
242 sig: &[u8],
243) -> Result<(), Error> {
244 if pk.key_len() != sig.len() {
245 return Err(Error::InvalidSignatureLength);
246 }
247
248 verify_varlen(alg, pk, msg, salt_len, sig)
249}
250
251pub fn sign_varlen(
272 alg: crate::DigestAlgorithm,
273 sk: &VarLenPrivateKey<'_>,
274 msg: &[u8],
275 salt: &[u8],
276 sig: &mut [u8],
277) -> Result<(), Error> {
278 let salt_len = salt.len().try_into().map_err(|_| Error::SaltTooLarge)?;
279 let msg_len = msg.len().try_into().map_err(|_| Error::MessageTooLarge)?;
280
281 if (salt_len as u64) + alg.hash_len() as u64 + 8 > u32::MAX as u64 {
285 return Err(Error::SaltTooLarge);
286 }
287
288 let a = hacl_hash_alg(alg);
289 let mod_bits = sk.pk.n.len() as u32 * 8;
290 let e_bits = E_BITS;
291 let d_bits = sk.d.len() as u32 * 8;
292
293 if salt_len as u64 + alg.hash_len() as u64 + 2 > (mod_bits as u64 - 1) / 8 + 1 {
297 return Err(Error::SaltTooLarge);
298 }
299
300 match crate::hacl::rsapss::rsapss_skey_sign(
301 a, mod_bits, e_bits, d_bits, sk.pk.n, &E, sk.d, salt_len, salt, msg_len, msg, sig,
302 ) {
303 true => Ok(()),
304 false => Err(Error::SigningFailed),
305 }
306}
307
308pub fn verify_varlen(
326 alg: crate::DigestAlgorithm,
327 pk: &VarLenPublicKey<'_>,
328 msg: &[u8],
329 salt_len: u32,
330 sig: &[u8],
331) -> Result<(), Error> {
332 if (salt_len as u64) + alg.hash_len() as u64 + 8 > u32::MAX as u64 {
336 return Err(Error::SaltTooLarge);
337 }
338
339 let msg_len = msg.len().try_into().map_err(|_| Error::MessageTooLarge)?;
340
341 let a = hacl_hash_alg(alg);
342 let mod_bits = pk.n.len() as u32 * 8;
343 let e_bits = E_BITS;
344
345 match crate::hacl::rsapss::rsapss_pkey_verify(
346 a,
347 mod_bits,
348 e_bits,
349 pk.n,
350 &E,
351 salt_len,
352 sig.len() as u32, sig,
354 msg_len,
355 msg,
356 ) {
357 true => Ok(()),
358 false => Err(Error::VerificationFailed),
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365
366 const MODULUS: [u8; 256] = [
367 0xd2, 0x78, 0x16, 0xcb, 0x72, 0xbb, 0x6e, 0x27, 0xdb, 0x10, 0x1a, 0x6f, 0x3e, 0x64, 0x62,
368 0x93, 0xd9, 0xec, 0xa7, 0xb3, 0x98, 0xe3, 0x36, 0x6c, 0x9e, 0x69, 0x31, 0xc4, 0x5d, 0xd7,
369 0x24, 0xd3, 0xf8, 0x90, 0xb0, 0xd0, 0x57, 0x78, 0x3e, 0xdd, 0xee, 0xf0, 0xc9, 0x0e, 0x98,
370 0x6d, 0xad, 0xe9, 0x46, 0x47, 0xc5, 0xcb, 0x4d, 0xa4, 0xc6, 0x9c, 0x83, 0x1a, 0x13, 0x9f,
371 0xb7, 0x8d, 0xe7, 0xe3, 0x79, 0x97, 0xf2, 0x9e, 0x36, 0x5c, 0x96, 0xaa, 0xf6, 0x29, 0xfe,
372 0x6e, 0x3c, 0x0d, 0xb0, 0xcb, 0x04, 0x7d, 0x35, 0xd3, 0xeb, 0xf7, 0xee, 0x36, 0x59, 0xda,
373 0xb5, 0xb2, 0x34, 0x08, 0x86, 0x87, 0x27, 0x02, 0x4b, 0x49, 0xb3, 0x85, 0x33, 0x9b, 0x63,
374 0x8f, 0x28, 0x3b, 0x27, 0x83, 0x65, 0xf9, 0x62, 0x23, 0xe0, 0x8b, 0x15, 0x1d, 0xd3, 0x00,
375 0xb1, 0xd6, 0x37, 0x3e, 0x7b, 0xa7, 0x1d, 0xc7, 0x63, 0x79, 0xe2, 0xa2, 0xca, 0x2d, 0xa4,
376 0xb6, 0xcd, 0xef, 0x8d, 0x73, 0xec, 0x56, 0xfc, 0x0b, 0xac, 0xcb, 0x80, 0x53, 0xcf, 0x34,
377 0x2f, 0x29, 0xb0, 0xe7, 0xf0, 0xb9, 0x24, 0xf4, 0xe4, 0x99, 0xb2, 0x58, 0xc0, 0x9e, 0x1f,
378 0xf5, 0x43, 0x6e, 0xca, 0xc6, 0xeb, 0x65, 0xd0, 0x5f, 0xdb, 0x13, 0x4c, 0x8c, 0xca, 0x82,
379 0xd9, 0xad, 0xc1, 0xfd, 0x7a, 0xd9, 0x78, 0xc7, 0xed, 0xdf, 0xc9, 0x70, 0x54, 0xd3, 0x80,
380 0x5f, 0x06, 0x48, 0x11, 0x6e, 0xfb, 0x9b, 0x46, 0xfa, 0x02, 0x65, 0xde, 0xcc, 0xe9, 0x6e,
381 0x91, 0x98, 0x93, 0x3d, 0x3d, 0x6d, 0xb1, 0x99, 0xa4, 0x73, 0xc1, 0x2c, 0xa2, 0x16, 0x55,
382 0x97, 0xf3, 0x0f, 0x67, 0xf7, 0x9a, 0x78, 0x74, 0x15, 0x66, 0xb1, 0xd4, 0xdc, 0x98, 0x47,
383 0x8a, 0x50, 0xb6, 0x2d, 0x63, 0xf9, 0xce, 0xa2, 0x76, 0x70, 0x91, 0xa8, 0x3b, 0x00, 0x28,
384 0x01,
385 ];
386
387 const PRIVATE_EXPONENT: [u8; 256] = [
388 0x5a, 0x90, 0x21, 0xfe, 0xd9, 0x17, 0x9d, 0x86, 0xb8, 0xd4, 0x6d, 0x0b, 0x81, 0x25, 0x60,
389 0xe5, 0x8d, 0xd8, 0x2f, 0x31, 0x30, 0x90, 0x54, 0x52, 0xd8, 0xb7, 0x1b, 0x1b, 0x0b, 0xe6,
390 0x0f, 0x8a, 0xc6, 0x62, 0x3c, 0x32, 0xe9, 0xf0, 0x6b, 0xdc, 0xc3, 0x7c, 0x08, 0x87, 0xa7,
391 0x3f, 0x4a, 0x9e, 0x1e, 0x07, 0xb4, 0x2c, 0x8e, 0xf4, 0x60, 0x21, 0xe8, 0xa7, 0xc7, 0xd9,
392 0xe9, 0xf9, 0xbd, 0xd6, 0x3b, 0xf4, 0x0e, 0x09, 0xd6, 0x0a, 0x71, 0x2a, 0x8f, 0x51, 0xf2,
393 0x91, 0x2c, 0x76, 0x17, 0xa4, 0xc4, 0x01, 0xbc, 0xaf, 0xbb, 0xd1, 0xab, 0x46, 0xe7, 0xd3,
394 0x1c, 0x6b, 0xd9, 0xc7, 0xf1, 0x5b, 0x26, 0x85, 0xee, 0x2f, 0x80, 0x77, 0xc8, 0x85, 0x0c,
395 0x8a, 0x05, 0x1d, 0xaf, 0x1a, 0xf3, 0x3e, 0x23, 0xe4, 0x9c, 0x32, 0x3c, 0x9b, 0xe0, 0xb7,
396 0x63, 0xce, 0x71, 0x67, 0x09, 0x7e, 0x17, 0x69, 0x74, 0x9a, 0xec, 0x2a, 0x71, 0xf4, 0xeb,
397 0xe2, 0x84, 0x23, 0x8b, 0xa8, 0x27, 0x69, 0x19, 0x53, 0x52, 0x8f, 0xc3, 0x62, 0xd5, 0x2a,
398 0x43, 0xb0, 0x78, 0x90, 0x54, 0x98, 0x22, 0x12, 0x2d, 0x32, 0x28, 0xcf, 0xf9, 0x04, 0x1c,
399 0x4f, 0x28, 0xb7, 0xad, 0x98, 0x1a, 0xdf, 0x2e, 0xdb, 0x94, 0xd5, 0x3d, 0xe2, 0xa9, 0x29,
400 0x3c, 0x3e, 0xaa, 0x81, 0x2a, 0x61, 0x8d, 0x4b, 0x41, 0x2f, 0xda, 0x99, 0x8b, 0x78, 0x7a,
401 0xd5, 0xec, 0x93, 0x53, 0x5a, 0x84, 0x43, 0x47, 0x1a, 0xaf, 0x68, 0xa7, 0x5f, 0x4e, 0x62,
402 0xe5, 0xcf, 0x07, 0xc9, 0x2b, 0x67, 0x34, 0x82, 0x27, 0xf6, 0xe0, 0x6d, 0x51, 0xca, 0x21,
403 0xea, 0xfa, 0x32, 0xf0, 0x9f, 0x84, 0xb4, 0xfb, 0xaf, 0x25, 0x1e, 0x91, 0x08, 0x94, 0x5e,
404 0x83, 0x7f, 0x0f, 0x6a, 0x86, 0x98, 0x77, 0xb8, 0xb0, 0xca, 0xd0, 0x34, 0x10, 0x69, 0x59,
405 0x21,
406 ];
407
408 #[test]
409 fn self_test_rsa_pss() {
410 let pk = PublicKey { n: MODULUS };
411 let sk = PrivateKey {
412 pk: pk.clone(),
413 d: PRIVATE_EXPONENT,
414 };
415 let salt = [1, 2, 3, 4, 5];
416 let msg = [7, 8, 9, 10];
417 let mut signature = [0u8; 256];
418 sign_2048(
419 crate::DigestAlgorithm::Sha2_256,
420 &sk,
421 &msg,
422 &salt,
423 &mut signature,
424 )
425 .unwrap();
426 verify_2048(
427 crate::DigestAlgorithm::Sha2_256,
428 &pk,
429 &msg,
430 salt.len() as u32,
431 &signature,
432 )
433 .expect("Error verifying signature");
434 }
435}