1use crate::{
4 consts::*,
5 kem::{KemPublicKey, KemSecretKey},
6 pke::ciphertext_len,
7};
8
9use rand_core::CryptoRng;
10use zeroize::{Zeroize, ZeroizeOnDrop};
11
12#[derive(Zeroize, ZeroizeOnDrop)]
15pub struct SharedSecret([u8; 32]);
16
17impl SharedSecret {
18 #[inline]
20 pub fn as_bytes(&self) -> &[u8; 32] {
21 &self.0
22 }
23}
24
25macro_rules! variant_impl {
27 (
28 $variant_name:ident,
29 $mod_doc:expr,
30 $pubkey_name:ident,
31 $privkey_name:ident,
32 $ciphertext_name:ident,
33 $ciphertext_len_name:ident,
34 $variant_ell:expr,
35 $variant_mu:expr,
36 $variant_modt_bits:expr
37 ) => {
38 #[doc = $mod_doc]
39 pub mod $variant_name {
40 use super::*;
41
42 #[derive(ZeroizeOnDrop)]
44 pub struct $privkey_name(KemSecretKey<$variant_ell>);
45
46 pub struct $pubkey_name(KemPublicKey<$variant_ell>);
48
49 pub const $ciphertext_len_name: usize =
51 ciphertext_len::<$variant_ell, $variant_modt_bits>();
52
53 #[doc = stringify!($ciphertext_len_name)]
56 pub type $ciphertext_name = [u8; $ciphertext_len_name];
58
59 impl $privkey_name {
60 pub fn generate(rng: &mut impl CryptoRng) -> Self {
62 Self(KemSecretKey::generate::<$variant_mu>(rng))
63 }
64
65 pub fn seed(&self) -> &[u8; 32] {
67 self.0.seed()
68 }
69
70 pub fn expand_from_seed(bytes: &[u8; 32]) -> Self {
72 Self(KemSecretKey::expand_from_seed::<$variant_mu>(bytes))
73 }
74
75 pub fn public_key(&self) -> $pubkey_name {
77 $pubkey_name(self.0.public_key())
78 }
79 }
80
81 impl $pubkey_name {
82 pub const SERIALIZED_LEN: usize = KemPublicKey::<$variant_ell>::SERIALIZED_LEN;
84
85 pub fn serialize(&self, out_buf: &mut [u8; Self::SERIALIZED_LEN]) {
87 self.0.serialize(out_buf);
88 }
89
90 pub fn from_bytes(bytes: &[u8; Self::SERIALIZED_LEN]) -> Self {
92 Self(KemPublicKey::from_bytes(bytes))
93 }
94 }
95
96 impl $pubkey_name {
97 pub fn encapsulate(
99 &self,
100 rng: &mut impl CryptoRng,
101 ) -> ($ciphertext_name, SharedSecret) {
102 let mut randomness = [0u8; 32];
103 rng.fill_bytes(&mut randomness);
104 let out = self.encapsulate_deterministic(&randomness);
105
106 randomness.zeroize();
107 out
108 }
109
110 pub fn encapsulate_deterministic(
114 &self,
115 randomness: &[u8; 32],
116 ) -> ($ciphertext_name, SharedSecret) {
117 let mut ct = [0u8; $ciphertext_len_name];
118 let ss = crate::kem::encap_deterministic::<
119 $variant_ell,
120 $variant_mu,
121 $variant_modt_bits,
122 >(randomness, &self.0, &mut ct);
123
124 (ct, SharedSecret(ss))
125 }
126 }
127
128 impl $privkey_name {
129 pub fn decapsulate(&self, encapsulated_key: &$ciphertext_name) -> SharedSecret {
133 SharedSecret(crate::kem::decap::<
134 $variant_ell,
135 $variant_mu,
136 $variant_modt_bits,
137 >(&self.0, encapsulated_key))
138 }
139 }
140
141 #[test]
143 fn test_api() {
144 let mut rng = rand::rng();
145 let sk = $privkey_name::generate(&mut rng);
146 let pk = sk.public_key();
147
148 let sk_seed = sk.seed();
150 let sk = $privkey_name::expand_from_seed(&sk_seed);
151
152 let mut pk_bytes = [0u8; $pubkey_name::SERIALIZED_LEN];
153 pk.serialize(&mut pk_bytes);
154 let pk = $pubkey_name::from_bytes(&pk_bytes);
155
156 let (ct, ss1) = pk.encapsulate(&mut rng);
157 let ct_bytes = ct.as_ref();
158
159 let ct_arr = ct_bytes.try_into().unwrap();
160 let ss2 = sk.decapsulate(&ct_arr);
161
162 assert_eq!(ss1.as_bytes(), ss2.as_bytes());
163 }
164 }
165 };
166}
167
168variant_impl!(
169 kopis512,
170 "Kopis-512 is designed to have security close to that of AES-128",
171 Kopis512PublicKey,
172 Kopis512SecretKey,
173 Kopis512Ciphertext,
174 KOPIS512_CIPHERTEXT_LEN,
175 KOPIS512_L,
176 KOPIS512_MU,
177 KOPIS512_T
178);
179
180variant_impl!(
181 kopis768,
182 "Kopis-768 is designed to have security close to that of AES-192",
183 Kopis768PublicKey,
184 Kopis768SecretKey,
185 Kopis768Ciphertext,
186 KOPIS768_CIPHERTEXT_LEN,
187 KOPIS768_L,
188 KOPIS768_MU,
189 KOPIS768_T
190);
191
192variant_impl!(
193 kopis1024,
194 "Kopis-1024 is designed to have security close to that of AES-256",
195 Kopis1024PublicKey,
196 Kopis1024SecretKey,
197 Kopis1024Ciphertext,
198 KOPIS1024_CIPHERTEXT_LEN,
199 KOPIS1024_L,
200 KOPIS1024_MU,
201 KOPIS1024_T
202);