pqcrypto_ntru/
ntruhrss701.rs1#[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 fn new() -> Self {
42 $type([0u8; $size])
43 }
44 }
45
46 impl primitive::$type for $type {
47 #[inline]
49 fn as_bytes(&self) -> &[u8] {
50 &self.0
51 }
52
53 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 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
96pub const fn public_key_bytes() -> usize {
98 ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_PUBLICKEYBYTES
99}
100
101pub const fn secret_key_bytes() -> usize {
103 ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_SECRETKEYBYTES
104}
105
106pub const fn ciphertext_bytes() -> usize {
108 ffi::PQCLEAN_NTRUHRSS701_CLEAN_CRYPTO_CIPHERTEXTBYTES
109}
110
111pub 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
128pub 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
151pub 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
173pub 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}