1pub mod group;
9pub(crate) mod shared;
10pub mod sigma_i;
11pub mod tripledh;
12#[cfg(feature = "kem")]
13pub mod tripledh_kem;
14
15use core::iter;
16use core::ops::Add;
17
18use derive_where::derive_where;
19use digest::Output;
20use digest::block_api::{CoreProxy, SmallBlockSizeUser};
21use generic_array::typenum::{IsLess, Le, NonZero, Sum, U2, U256};
22use generic_array::{ArrayLength, GenericArray};
23use hybrid_array::Array;
24use rand::{CryptoRng, Rng};
25use voprf::{BlindedElement, EvaluationElement};
26use zeroize::{Zeroize, ZeroizeOnDrop};
27
28#[cfg(test)]
29use crate::ciphersuite::KeHash;
30use crate::ciphersuite::{CipherSuite, OprfGroup};
31use crate::errors::ProtocolError;
32use crate::hash::{Hash, OutputSize, ProxyHash};
33use crate::key_exchange::group::Group;
34use crate::key_exchange::shared::{NonceLen, STR_CONTEXT};
35use crate::keypair::{PrivateKey, PublicKey};
36use crate::opaque::{Identifiers, MaskedResponse, MaskedResponseLen};
37use crate::serialization::{ConcatExt, SliceExt, i2osp};
38
39pub trait KeyExchange
41where
42 <Self::Hash as CoreProxy>::Core: ProxyHash,
43 <<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
44 Le<<<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
45 OutputSize<Self::Hash>: ArrayLength,
46{
47 type Group: Group;
49 type Hash: Hash;
51
52 type KE1State: ZeroizeOnDrop + Clone;
54 type KE2State<CS: CipherSuite>: ZeroizeOnDrop + Clone;
56 type KE1Message: ZeroizeOnDrop + Clone;
58 type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>>: ZeroizeOnDrop + Clone;
60 type KE2BuilderData<'a, CS: 'static + CipherSuite>;
62 type KE2BuilderInput<CS: CipherSuite>;
64 type KE2Message: ZeroizeOnDrop + Clone;
66 type KE3Message: ZeroizeOnDrop + Clone;
68
69 fn generate_ke1<R: Rng + CryptoRng>(
72 rng: &mut R,
73 ) -> Result<GenerateKe1Result<Self>, ProtocolError>;
74
75 fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
77 rng: &mut R,
78 credential_request: SerializedCredentialRequest<CS>,
79 ke1_message: Self::KE1Message,
80 credential_response: SerializedCredentialResponse<CS>,
81 client_s_pk: PublicKey<Self::Group>,
82 identifiers: SerializedIdentifiers<'a, Self::Group>,
83 context: SerializedContext<'a>,
84 ) -> Result<Self::KE2Builder<'a, CS>, ProtocolError>;
85
86 fn ke2_builder_data<'a, CS: CipherSuite<KeyExchange = Self>>(
88 builder: &'a Self::KE2Builder<'_, CS>,
89 ) -> Self::KE2BuilderData<'a, CS>;
90
91 fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
93 builder: &Self::KE2Builder<'_, CS>,
94 rng: &mut R,
95 server_s_sk: &PrivateKey<Self::Group>,
96 ) -> Self::KE2BuilderInput<CS>;
97
98 fn build_ke2<CS: CipherSuite<KeyExchange = Self>>(
101 builder: Self::KE2Builder<'_, CS>,
102 input: Self::KE2BuilderInput<CS>,
103 ) -> Result<GenerateKe2Result<CS>, ProtocolError>;
104
105 #[allow(clippy::too_many_arguments)]
107 fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
108 rng: &mut R,
109 credential_request: SerializedCredentialRequest<CS>,
110 ke1_message: Self::KE1Message,
111 credential_response: SerializedCredentialResponse<CS>,
112 ke1_state: &Self::KE1State,
113 ke2_message: Self::KE2Message,
114 server_s_pk: PublicKey<Self::Group>,
115 client_s_sk: PrivateKey<Self::Group>,
116 identifiers: SerializedIdentifiers<'_, Self::Group>,
117 context: SerializedContext<'_>,
118 ) -> Result<GenerateKe3Result<Self>, ProtocolError>;
119
120 fn finish_ke<CS: CipherSuite<KeyExchange = Self>>(
122 ke2_state: &Self::KE2State<CS>,
123 ke3_message: Self::KE3Message,
124 identifiers: Identifiers<'_>,
125 context: SerializedContext<'_>,
126 ) -> Result<Output<Self::Hash>, ProtocolError>;
127}
128
129#[cfg_attr(
131 feature = "serde",
132 derive(serde::Deserialize, serde::Serialize),
133 serde(bound = "")
134)]
135#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)]
136pub struct SerializedCredentialRequest<CS: CipherSuite>(
137 Array<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
138);
139
140impl<CS: CipherSuite> SerializedCredentialRequest<CS> {
141 pub(crate) fn new(blinded_element: &BlindedElement<CS::OprfCs>) -> Self {
142 Self(blinded_element.serialize())
143 }
144
145 pub fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> {
148 iter::once(self.0.as_slice())
149 }
150
151 pub fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
154 Ok(Self(bytes.take_array("blinded element")?.into_ha0_4()))
155 }
156}
157
158type SerializedCredentialRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Group>::ElemLen;
159
160impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS>
161where
162 <OprfGroup<CS> as voprf::Group>::ElemLen: ArrayLength,
163{
164 type Len = SerializedCredentialRequestLen<CS>;
165
166 fn serialize(&self) -> GenericArray<u8, Self::Len> {
167 GenericArray::from_slice(self.0.as_slice()).clone()
168 }
169}
170
171#[cfg_attr(
173 feature = "serde",
174 derive(serde::Deserialize, serde::Serialize),
175 serde(bound = "")
176)]
177#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
178pub struct SerializedCredentialResponse<CS: CipherSuite> {
179 evaluation_element: Array<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
180 masking_nonce: GenericArray<u8, NonceLen>,
181 masked_response: MaskedResponse<CS>,
182}
183
184impl<CS: CipherSuite> SerializedCredentialResponse<CS> {
185 pub(crate) fn new(
186 evaluation_element: &EvaluationElement<CS::OprfCs>,
187 masking_nonce: GenericArray<u8, NonceLen>,
188 masked_response: MaskedResponse<CS>,
189 ) -> Self {
190 Self {
191 evaluation_element: evaluation_element.serialize(),
192 masking_nonce,
193 masked_response,
194 }
195 }
196
197 pub fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> {
201 [self.evaluation_element.as_slice(), &self.masking_nonce]
202 .into_iter()
203 .chain(self.masked_response.iter())
204 }
205
206 pub fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
209 Ok(Self {
210 evaluation_element: input.take_array("evaluation element")?.into_ha0_4(),
211 masking_nonce: input.take_array("masking nonce")?,
212 masked_response: MaskedResponse::deserialize_take(input)?,
213 })
214 }
215}
216
217type SerializedCredentialResponseLen<CS: CipherSuite> =
218 Sum<Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>, MaskedResponseLen<CS>>;
219
220impl<CS: CipherSuite> Serialize for SerializedCredentialResponse<CS>
221where
222 <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
223 Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
224 ArrayLength + Add<MaskedResponseLen<CS>>,
225 SerializedCredentialResponseLen<CS>: ArrayLength,
226{
227 type Len = SerializedCredentialResponseLen<CS>;
228
229 fn serialize(&self) -> GenericArray<u8, Self::Len> {
230 let elem = GenericArray::<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>::from_slice(
231 self.evaluation_element.as_slice(),
232 )
233 .clone();
234
235 elem.cat(self.masking_nonce)
236 .cat(self.masked_response.serialize())
237 }
238}
239
240#[cfg_attr(
244 feature = "serde",
245 derive(serde::Deserialize, serde::Serialize),
246 serde(bound = "")
247)]
248#[derive(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
249#[allow(unused_assignments)]
250pub struct SerializedContext<'a> {
251 length: GenericArray<u8, U2>,
252 #[zeroize(skip)]
253 context: &'a [u8],
254}
255
256impl<'a> SerializedContext<'a> {
257 pub(crate) fn from(context: Option<&'a [u8]>) -> Result<Self, ProtocolError> {
258 let context = context.unwrap_or(&[]);
259
260 Ok(Self {
261 length: i2osp::<U2>(context.len())?,
262 context,
263 })
264 }
265
266 pub fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> {
268 iter::once(STR_CONTEXT).chain([self.length.as_slice(), self.context])
269 }
270}
271
272#[cfg_attr(
274 feature = "serde",
275 derive(serde::Deserialize, serde::Serialize),
276 serde(bound(deserialize = "'de: 'a", serialize = ""))
277)]
278#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
279pub struct SerializedIdentifiers<'a, G: Group> {
280 pub client: SerializedIdentifier<'a, G>,
282 pub server: SerializedIdentifier<'a, G>,
284}
285
286#[cfg_attr(
288 feature = "serde",
289 derive(serde::Deserialize, serde::Serialize),
290 serde(bound(deserialize = "'de: 'a", serialize = ""))
291)]
292#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
293pub struct SerializedIdentifier<'a, G: Group> {
294 length: GenericArray<u8, U2>,
295 identifier: Identifier<'a, G>,
296}
297
298#[cfg_attr(
299 feature = "serde",
300 derive(serde::Deserialize, serde::Serialize),
301 serde(bound = "")
302)]
303#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
304enum Identifier<'a, G: Group> {
305 Owned(GenericArray<u8, G::PkLen>),
306 #[derive_where(skip_inner(Zeroize))]
307 Borrowed(&'a [u8]),
308}
309
310impl<'a, G: Group> SerializedIdentifiers<'a, G> {
311 pub(crate) fn from_identifiers(
312 ids: Identifiers<'a>,
313 client_s_pk: GenericArray<u8, G::PkLen>,
314 server_s_pk: GenericArray<u8, G::PkLen>,
315 ) -> Result<Self, ProtocolError> {
316 let client = SerializedIdentifier::from_identifier(ids.client, client_s_pk)?;
317 let server = SerializedIdentifier::from_identifier(ids.server, server_s_pk)?;
318
319 Ok(Self { client, server })
320 }
321}
322
323impl<'a, G: Group> SerializedIdentifier<'a, G> {
324 pub fn from_identifier(
327 id: Option<&'a [u8]>,
328 s_pk: GenericArray<u8, G::PkLen>,
329 ) -> Result<Self, ProtocolError> {
330 if let Some(id) = id {
331 Ok(SerializedIdentifier {
332 length: i2osp::<U2>(id.len())?,
333 identifier: Identifier::Borrowed(id),
334 })
335 } else {
336 Ok(SerializedIdentifier {
337 length: i2osp::<U2>(s_pk.len())?,
338 identifier: Identifier::Owned(s_pk),
339 })
340 }
341 }
342
343 pub fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> {
345 [self.length.as_slice()]
346 .into_iter()
347 .chain(match &self.identifier {
348 Identifier::Owned(bytes) => [bytes.as_slice()],
349 Identifier::Borrowed(bytes) => [*bytes],
350 })
351 }
352}
353
354pub trait Deserialize: Sized {
356 fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError>;
360}
361
362pub trait Serialize {
364 type Len: ArrayLength;
366
367 fn serialize(&self) -> GenericArray<u8, Self::Len>;
369}
370
371pub struct GenerateKe1Result<KE: KeyExchange + ?Sized> {
373 pub state: KE::KE1State,
375 pub message: KE::KE1Message,
377}
378
379pub struct GenerateKe2Result<CS: CipherSuite> {
381 pub state: <CS::KeyExchange as KeyExchange>::KE2State<CS>,
383 pub message: <CS::KeyExchange as KeyExchange>::KE2Message,
385 #[cfg(test)]
386 pub(crate) handshake_secret: Output<KeHash<CS>>,
387 #[cfg(test)]
388 pub(crate) km2: Output<KeHash<CS>>,
389}
390
391pub struct GenerateKe3Result<KE: KeyExchange + ?Sized> {
393 pub session_key: Output<KE::Hash>,
395 pub message: KE::KE3Message,
397 #[cfg(test)]
398 pub(crate) handshake_secret: Output<KE::Hash>,
399 #[cfg(test)]
400 pub(crate) km3: Output<KE::Hash>,
401}
402
403pub(crate) type Ke1StateLen<CS: CipherSuite> =
404 <<CS::KeyExchange as KeyExchange>::KE1State as Serialize>::Len;
405pub(crate) type Ke1MessageLen<CS: CipherSuite> =
406 <<CS::KeyExchange as KeyExchange>::KE1Message as Serialize>::Len;
407pub(crate) type Ke2StateLen<CS: CipherSuite> =
408 <<CS::KeyExchange as KeyExchange>::KE2State<CS> as Serialize>::Len;
409pub(crate) type Ke2MessageLen<CS: CipherSuite> =
410 <<CS::KeyExchange as KeyExchange>::KE2Message as Serialize>::Len;
411pub(crate) type Ke3MessageLen<CS: CipherSuite> =
412 <<CS::KeyExchange as KeyExchange>::KE3Message as Serialize>::Len;