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