pqcrypto_sphincsplus/
sphincsshake128ssimple.rs

1//! sphincs-shake-128s-simple
2//!
3//! These bindings use the clean version from [PQClean][pqc]
4//!
5//! # Example
6//! ```
7//! // if using pqcrypto-sphincsplus
8//! use pqcrypto_sphincsplus::sphincsshake128ssimple::*;
9//! // or if using the pqcrypto crate:
10//! // use pqcrypto::sign::sphincsshake128ssimple::*;
11//! let message = vec![0, 1, 2, 3, 4, 5];
12//! let (pk, sk) = keypair();
13//! let sm = sign(&message, &sk);
14//! let verifiedmsg = open(&sm, &pk).unwrap();
15//! assert!(verifiedmsg == message);
16//! ```
17//!
18//! [pqc]: https://github.com/pqclean/pqclean/
19
20// This file is generated.
21
22#[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            /// Generates an uninitialized object
45            ///
46            /// Used to pass to ``ffi`` interfaces.
47            ///
48            /// Internal use only!
49            fn new() -> Self {
50                $type([0u8; $size])
51            }
52        }
53
54        impl primitive::$type for $type {
55            /// Get this object as a byte slice
56            #[inline]
57            fn as_bytes(&self) -> &[u8] {
58                &self.0
59            }
60
61            /// Construct this object from a byte slice
62            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            /// By no means constant time comparison
79            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            /// Add a debug implementation that won't leak private values
91            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
115// for internal use
116impl 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    /// Get this object as a byte slice
127    #[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    /// Get this object as a byte slice
154    #[inline]
155    fn as_bytes(&self) -> &[u8] {
156        self.0.as_slice()
157    }
158
159    /// Construct this object from a byte slice
160    #[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
172/// Get the number of bytes for a public key
173pub const fn public_key_bytes() -> usize {
174    ffi::PQCLEAN_SPHINCSSHAKE128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES
175}
176
177/// Get the number of bytes for a secret key
178pub const fn secret_key_bytes() -> usize {
179    ffi::PQCLEAN_SPHINCSSHAKE128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES
180}
181
182/// Get the number of bytes that a signature occupies
183pub 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
199/// Generate a sphincs-shake-128s-simple keypair
200pub 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
230/// Sign the message and return the signed message.
231pub 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
264/// Open the signed message and if verification succeeds return the message
265pub 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
298/// Create a detached signature on the message
299pub 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
336/// Verify the detached signature
337pub 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}