pqcrypto_ntru/
ntruhrss701.rs

1//! ntruhrss701
2//!
3//! These bindings use the clean version from [PQClean][pqc]
4//!
5//! # Example
6//! ```
7//! use pqcrypto_ntru::ntruhrss701::*;
8//! let (pk, sk) = keypair();
9//! let (ss1, ct) = encapsulate(&pk);
10//! let ss2 = decapsulate(&ct, &sk);
11//! assert!(ss1 == ss2);
12//! ```
13//!
14//! [pqc]: https://github.com/pqclean/pqclean/
15
16// This file is generated.
17
18#[cfg(feature = "serialization")]
19use serde::{Deserialize, Serialize};
20#[cfg(feature = "serialization")]
21use serde_big_array::BigArray;
22
23use crate::ffi;
24use pqcrypto_traits::kem as primitive;
25use pqcrypto_traits::{Error, Result};
26
27macro_rules! simple_struct {
28    ($type: ident, $size: expr) => {
29        #[derive(Clone, Copy)]
30        #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
31        pub struct $type(
32            #[cfg_attr(feature = "serialization", serde(with = "BigArray"))] [u8; $size],
33        );
34
35        impl $type {
36            /// Generates an uninitialized object
37            ///
38            /// Used to pass to ``ffi`` interfaces.
39            ///
40            /// Internal use only!
41            fn new() -> Self {
42                $type([0u8; $size])
43            }
44        }
45
46        impl primitive::$type for $type {
47            /// Get this object as a byte slice
48            #[inline]
49            fn as_bytes(&self) -> &[u8] {
50                &self.0
51            }
52
53            /// Construct this object from a byte slice
54            fn from_bytes(bytes: &[u8]) -> Result<Self> {
55                if bytes.len() != $size {
56                    Err(Error::BadLength {
57                        name: stringify!($type),
58                        actual: bytes.len(),
59                        expected: $size,
60                    })
61                } else {
62                    let mut array = [0u8; $size];
63                    array.copy_from_slice(bytes);
64                    Ok($type(array))
65                }
66            }
67        }
68
69        impl PartialEq for $type {
70            /// By no means constant time comparison
71            fn eq(&self, other: &Self) -> bool {
72                self.0
73                    .iter()
74                    .zip(other.0.iter())
75                    .try_for_each(|(a, b)| if a == b { Ok(()) } else { Err(()) })
76                    .is_ok()
77            }
78        }
79    };
80}
81
82simple_struct!(
83    PublicKey,
84    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_PUBLICKEYBYTES
85);
86simple_struct!(
87    SecretKey,
88    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_SECRETKEYBYTES
89);
90simple_struct!(
91    Ciphertext,
92    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_CIPHERTEXTBYTES
93);
94simple_struct!(SharedSecret, ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_BYTES);
95
96/// Get the number of bytes for a public key
97pub const fn public_key_bytes() -> usize {
98    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_PUBLICKEYBYTES
99}
100
101/// Get the number of bytes for a secret key
102pub const fn secret_key_bytes() -> usize {
103    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_SECRETKEYBYTES
104}
105
106/// Get the number of bytes for the encapsulated ciphertext
107pub const fn ciphertext_bytes() -> usize {
108    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_CIPHERTEXTBYTES
109}
110
111/// Get the number of bytes for the shared secret
112pub const fn shared_secret_bytes() -> usize {
113    ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_BYTES
114}
115
116macro_rules! gen_keypair {
117    ($variant:ident) => {{
118        let mut pk = PublicKey::new();
119        let mut sk = SecretKey::new();
120        assert_eq!(
121            unsafe { ffi::$variant(pk.0.as_mut_ptr(), sk.0.as_mut_ptr()) },
122            0
123        );
124        (pk, sk)
125    }};
126}
127
128/// Generate a ntruhrss701 keypair
129pub fn keypair() -> (PublicKey, SecretKey) {
130    #[cfg(all(enable_x86_avx2, feature = "avx2"))]
131    {
132        if std::is_x86_feature_detected!("avx2") {
133            return gen_keypair!(PQCLEAN_NTRUHRSS701_AVX2_crypto_kem_keypair);
134        }
135    }
136    gen_keypair!(PQCLEAN_NTRUHRSS701_CLEAN_crypto_kem_keypair)
137}
138
139macro_rules! encap {
140    ($variant:ident, $pk:ident) => {{
141        let mut ss = SharedSecret::new();
142        let mut ct = Ciphertext::new();
143        assert_eq!(
144            unsafe { ffi::$variant(ct.0.as_mut_ptr(), ss.0.as_mut_ptr(), $pk.0.as_ptr()) },
145            0,
146        );
147        (ss, ct)
148    }};
149}
150
151/// Encapsulate to a ntruhrss701 public key
152pub fn encapsulate(pk: &PublicKey) -> (SharedSecret, Ciphertext) {
153    #[cfg(all(enable_x86_avx2, feature = "avx2"))]
154    {
155        if std::is_x86_feature_detected!("avx2") {
156            return encap!(PQCLEAN_NTRUHRSS701_AVX2_crypto_kem_enc, pk);
157        }
158    }
159    encap!(PQCLEAN_NTRUHRSS701_CLEAN_crypto_kem_enc, pk)
160}
161
162macro_rules! decap {
163    ($variant:ident, $ct:ident, $sk:ident) => {{
164        let mut ss = SharedSecret::new();
165        assert_eq!(
166            unsafe { ffi::$variant(ss.0.as_mut_ptr(), $ct.0.as_ptr(), $sk.0.as_ptr(),) },
167            0
168        );
169        ss
170    }};
171}
172
173/// Decapsulate the received ntruhrss701 ciphertext
174pub fn decapsulate(ct: &Ciphertext, sk: &SecretKey) -> SharedSecret {
175    #[cfg(all(enable_x86_avx2, feature = "avx2"))]
176    {
177        if std::is_x86_feature_detected!("avx2") {
178            return decap!(PQCLEAN_NTRUHRSS701_AVX2_crypto_kem_dec, ct, sk);
179        }
180    }
181    decap!(PQCLEAN_NTRUHRSS701_CLEAN_crypto_kem_dec, ct, sk)
182}
183
184#[cfg(test)]
185mod test {
186    use super::*;
187
188    #[test]
189    pub fn test_kem() {
190        let (pk, sk) = keypair();
191        let (ss1, ct) = encapsulate(&pk);
192        let ss2 = decapsulate(&ct, &sk);
193        assert_eq!(&ss1.0[..], &ss2.0[..], "Difference in shared secrets!");
194    }
195}