1#[cfg(feature = "serialization")]
23use serde::{Deserialize, Serialize};
24#[cfg(feature = "serialization")]
25use serde_big_array::BigArray;
26
27use crate::ffi;
28use alloc::vec::Vec;
29use pqcrypto_traits::sign as primitive;
30use pqcrypto_traits::{Error, Result};
31
32macro_rules! simple_struct {
33 ($type: ident, $size: expr) => {
34 #[derive(Clone, Copy)]
35 #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
36 pub struct $type(
37 #[cfg_attr(feature = "serialization", serde(with = "BigArray"))] [u8; $size],
38 );
39
40 impl $type {
41 fn new() -> Self {
47 $type([0u8; $size])
48 }
49 }
50
51 impl primitive::$type for $type {
52 #[inline]
54 fn as_bytes(&self) -> &[u8] {
55 &self.0
56 }
57
58 fn from_bytes(bytes: &[u8]) -> Result<Self> {
60 if bytes.len() != $size {
61 Err(Error::BadLength {
62 name: stringify!($type),
63 actual: bytes.len(),
64 expected: $size,
65 })
66 } else {
67 let mut array = [0u8; $size];
68 array.copy_from_slice(bytes);
69 Ok($type(array))
70 }
71 }
72 }
73
74 impl PartialEq for $type {
75 fn eq(&self, other: &Self) -> bool {
77 self.0
78 .iter()
79 .zip(other.0.iter())
80 .try_for_each(|(a, b)| if a == b { Ok(()) } else { Err(()) })
81 .is_ok()
82 }
83 }
84 };
85}
86
87simple_struct!(
88 PublicKey,
89 ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES
90);
91simple_struct!(
92 SecretKey,
93 ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES
94);
95
96#[derive(Clone, Copy)]
97#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98pub struct DetachedSignature(
99 #[cfg_attr(feature = "serialization", serde(with = "BigArray"))]
100 [u8; ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES],
101 usize,
102);
103
104impl DetachedSignature {
106 fn new() -> Self {
107 DetachedSignature([0u8; ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES], 0)
108 }
109}
110
111impl primitive::DetachedSignature for DetachedSignature {
112 #[inline]
114 fn as_bytes(&self) -> &[u8] {
115 &self.0[..self.1]
116 }
117
118 #[inline]
119 fn from_bytes(bytes: &[u8]) -> Result<Self> {
120 let actual = bytes.len();
121 let expected = ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES;
122 if actual > expected {
123 return Err(Error::BadLength {
124 name: "DetachedSignature",
125 actual,
126 expected,
127 });
128 }
129 let mut array = [0u8; ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES];
130 array[..bytes.len()].copy_from_slice(bytes);
131 Ok(DetachedSignature(array, actual))
132 }
133}
134
135#[derive(Clone)]
136#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
137pub struct SignedMessage(Vec<u8>);
138impl primitive::SignedMessage for SignedMessage {
139 #[inline]
141 fn as_bytes(&self) -> &[u8] {
142 self.0.as_slice()
143 }
144
145 #[inline]
147 fn from_bytes(bytes: &[u8]) -> Result<Self> {
148 Ok(SignedMessage(bytes.to_vec()))
149 }
150}
151
152impl SignedMessage {
153 pub fn len(&self) -> usize {
154 self.0.len()
155 }
156}
157
158pub const fn public_key_bytes() -> usize {
160 ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES
161}
162
163pub const fn secret_key_bytes() -> usize {
165 ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES
166}
167
168pub const fn signature_bytes() -> usize {
170 ffi::PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES
171}
172
173macro_rules! gen_keypair {
174 ($variant:ident) => {{
175 let mut pk = PublicKey::new();
176 let mut sk = SecretKey::new();
177 assert_eq!(
178 unsafe { ffi::$variant(pk.0.as_mut_ptr(), sk.0.as_mut_ptr()) },
179 0
180 );
181 (pk, sk)
182 }};
183}
184
185pub fn keypair() -> (PublicKey, SecretKey) {
187 #[cfg(all(enable_x86_avx2, feature = "avx2"))]
188 {
189 if std::is_x86_feature_detected!("avx2") {
190 return gen_keypair!(PQCLEAN_DILITHIUM3_AVX2_crypto_sign_keypair);
191 }
192 }
193 #[cfg(all(enable_aarch64_neon, feature = "neon"))]
194 {
195 if true {
199 return gen_keypair!(PQCLEAN_DILITHIUM3_AARCH64_crypto_sign_keypair);
200 }
201 }
202 gen_keypair!(PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_keypair)
203}
204
205macro_rules! gen_signature {
206 ($variant:ident, $msg:ident, $sk:ident) => {{
207 let max_len = $msg.len() + signature_bytes();
208 let mut signed_msg = Vec::with_capacity(max_len);
209 let mut smlen: usize = 0;
210 unsafe {
211 ffi::$variant(
212 signed_msg.as_mut_ptr(),
213 &mut smlen as *mut usize,
214 $msg.as_ptr(),
215 $msg.len(),
216 $sk.0.as_ptr(),
217 );
218 debug_assert!(smlen <= max_len, "exceeded vector capacity");
219 signed_msg.set_len(smlen);
220 }
221 SignedMessage(signed_msg)
222 }};
223}
224
225pub fn sign(msg: &[u8], sk: &SecretKey) -> SignedMessage {
227 #[cfg(all(enable_x86_avx2, feature = "avx2"))]
228 {
229 if std::is_x86_feature_detected!("avx2") {
230 return gen_signature!(PQCLEAN_DILITHIUM3_AVX2_crypto_sign, msg, sk);
231 }
232 }
233 #[cfg(all(enable_aarch64_neon, feature = "neon"))]
234 {
235 if true {
236 return gen_signature!(PQCLEAN_DILITHIUM3_AARCH64_crypto_sign, msg, sk);
237 }
238 }
239 gen_signature!(PQCLEAN_DILITHIUM3_CLEAN_crypto_sign, msg, sk)
240}
241
242macro_rules! open_signed {
243 ($variant:ident, $sm:ident, $pk:ident) => {{
244 let mut m: Vec<u8> = Vec::with_capacity($sm.len());
245 let mut mlen: usize = 0;
246 match unsafe {
247 ffi::$variant(
248 m.as_mut_ptr(),
249 &mut mlen as *mut usize,
250 $sm.0.as_ptr(),
251 $sm.len(),
252 $pk.0.as_ptr(),
253 )
254 } {
255 0 => {
256 unsafe { m.set_len(mlen) };
257 Ok(m)
258 }
259 -1 => Err(primitive::VerificationError::InvalidSignature),
260 _ => Err(primitive::VerificationError::UnknownVerificationError),
261 }
262 }};
263}
264
265pub fn open(
267 sm: &SignedMessage,
268 pk: &PublicKey,
269) -> core::result::Result<Vec<u8>, primitive::VerificationError> {
270 #[cfg(all(enable_x86_avx2, feature = "avx2"))]
271 {
272 if std::is_x86_feature_detected!("avx2") {
273 return open_signed!(PQCLEAN_DILITHIUM3_AVX2_crypto_sign_open, sm, pk);
274 }
275 }
276 #[cfg(all(enable_aarch64_neon, feature = "neon"))]
277 {
278 if true {
279 return open_signed!(PQCLEAN_DILITHIUM3_AARCH64_crypto_sign_open, sm, pk);
280 }
281 }
282 open_signed!(PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_open, sm, pk)
283}
284
285macro_rules! detached_signature {
286 ($variant:ident, $msg:ident, $sk:ident) => {{
287 let mut sig = DetachedSignature::new();
288 unsafe {
289 ffi::$variant(
290 sig.0.as_mut_ptr(),
291 &mut sig.1 as *mut usize,
292 $msg.as_ptr(),
293 $msg.len(),
294 $sk.0.as_ptr(),
295 );
296 }
297 sig
298 }};
299}
300
301pub fn detached_sign(msg: &[u8], sk: &SecretKey) -> DetachedSignature {
303 #[cfg(all(enable_x86_avx2, feature = "avx2"))]
304 {
305 if std::is_x86_feature_detected!("avx2") {
306 return detached_signature!(PQCLEAN_DILITHIUM3_AVX2_crypto_sign_signature, msg, sk);
307 }
308 }
309 #[cfg(all(enable_aarch64_neon, feature = "neon"))]
310 {
311 if true {
312 return detached_signature!(PQCLEAN_DILITHIUM3_AARCH64_crypto_sign_signature, msg, sk);
313 }
314 }
315 detached_signature!(PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_signature, msg, sk)
316}
317
318macro_rules! verify_detached_sig {
319 ($variant:ident, $sig:ident, $msg:ident, $pk:ident) => {{
320 let res = unsafe {
321 ffi::$variant(
322 $sig.0.as_ptr(),
323 $sig.1,
324 $msg.as_ptr(),
325 $msg.len(),
326 $pk.0.as_ptr(),
327 )
328 };
329 match res {
330 0 => Ok(()),
331 -1 => Err(primitive::VerificationError::InvalidSignature),
332 _ => Err(primitive::VerificationError::UnknownVerificationError),
333 }
334 }};
335}
336
337pub fn verify_detached_signature(
339 sig: &DetachedSignature,
340 msg: &[u8],
341 pk: &PublicKey,
342) -> core::result::Result<(), primitive::VerificationError> {
343 #[cfg(all(enable_x86_avx2, feature = "avx2"))]
344 {
345 if std::is_x86_feature_detected!("avx2") {
346 return verify_detached_sig!(PQCLEAN_DILITHIUM3_AVX2_crypto_sign_verify, sig, msg, pk);
347 }
348 }
349 #[cfg(all(enable_aarch64_neon, feature = "neon"))]
350 {
351 if true {
352 return verify_detached_sig!(
353 PQCLEAN_DILITHIUM3_AARCH64_crypto_sign_verify,
354 sig,
355 msg,
356 pk
357 );
358 }
359 }
360 verify_detached_sig!(PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_verify, sig, msg, pk)
361}
362
363#[cfg(test)]
364mod test {
365 use super::*;
366 use rand::prelude::*;
367
368 #[test]
369 pub fn test_sign() {
370 let mut rng = rand::thread_rng();
371 let len: u16 = rng.gen();
372
373 let message = (0..len).map(|_| rng.gen::<u8>()).collect::<Vec<_>>();
374 let (pk, sk) = keypair();
375 let sm = sign(&message, &sk);
376 let verifiedmsg = open(&sm, &pk).unwrap();
377 assert!(verifiedmsg == message);
378 }
379
380 #[test]
381 pub fn test_sign_detached() {
382 let mut rng = rand::thread_rng();
383 let len: u16 = rng.gen();
384 let message = (0..len).map(|_| rng.gen::<u8>()).collect::<Vec<_>>();
385
386 let (pk, sk) = keypair();
387 let sig = detached_sign(&message, &sk);
388 assert!(verify_detached_signature(&sig, &message, &pk).is_ok());
389 assert!(!verify_detached_signature(&sig, &message[..message.len() - 1], &pk).is_ok());
390 }
391}