pqcrypto_kyber/
kyber768.rs

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