1use core::ops::Add;
8
9use derive_where::derive_where;
10use digest::Output;
11use generic_array::typenum::{Sum, Unsigned};
12use generic_array::{ArrayLength, GenericArray};
13use hybrid_array::Array;
14use rand::{CryptoRng, Rng};
15use voprf::{BlindedElement, BlindedElementLen, EvaluationElement, EvaluationElementLen};
16use zeroize::Zeroizing;
17
18use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
19use crate::envelope::{Envelope, EnvelopeLen};
20use crate::errors::ProtocolError;
21use crate::hash::OutputSize;
22use crate::key_exchange::group::Group;
23use crate::key_exchange::shared::NonceLen;
24use crate::key_exchange::{
25 Deserialize, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, Serialize,
26 SerializedCredentialRequest, SerializedCredentialResponse,
27};
28use crate::keypair::PublicKey;
29use crate::opaque::{
30 MaskedResponse, MaskedResponseLen, ServerLogin, ServerLoginStartResult, ServerSetup,
31};
32use crate::serialization::{ConcatExt, SliceExt};
33
34#[cfg_attr(
41 feature = "serde",
42 derive(serde::Deserialize, serde::Serialize),
43 serde(bound = "")
44)]
45#[derive_where(Clone)]
46#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfCs>)]
47pub struct RegistrationRequest<CS: CipherSuite> {
48 pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
50}
51
52#[cfg_attr(
55 feature = "serde",
56 derive(serde::Deserialize, serde::Serialize),
57 serde(bound(
58 deserialize = "<KeGroup<CS> as Group>::Pk: serde::Deserialize<'de>",
59 serialize = "<KeGroup<CS> as Group>::Pk: serde::Serialize"
60 ))
61)]
62#[derive_where(Clone)]
63#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfCs>, <KeGroup<CS> as Group>::Pk
64)]
65pub struct RegistrationResponse<CS: CipherSuite> {
66 pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
68 pub(crate) server_s_pk: PublicKey<KeGroup<CS>>,
70}
71
72#[cfg_attr(
75 feature = "serde",
76 derive(serde::Deserialize, serde::Serialize),
77 serde(bound(
78 deserialize = "<KeGroup<CS> as Group>::Pk: serde::Deserialize<'de>",
79 serialize = "<KeGroup<CS> as Group>::Pk: serde::Serialize"
80 ))
81)]
82#[derive_where(Clone, ZeroizeOnDrop)]
83#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <KeGroup<CS> as Group>::Pk)]
84pub struct RegistrationUpload<CS: CipherSuite> {
85 pub(crate) envelope: Envelope<CS>,
88 pub(crate) masking_key: Output<OprfHash<CS>>,
90 #[derive_where(skip(Zeroize))]
92 pub(crate) client_s_pk: PublicKey<KeGroup<CS>>,
93}
94
95#[cfg_attr(
97 feature = "serde",
98 derive(serde::Deserialize, serde::Serialize),
99 serde(bound(
100 deserialize = "<CS::KeyExchange as KeyExchange>::KE1Message: serde::Deserialize<'de>",
101 serialize = "<CS::KeyExchange as KeyExchange>::KE1Message: serde::Serialize"
102 ))
103)]
104#[derive_where(Clone, ZeroizeOnDrop)]
105#[derive_where(
106 Debug, Eq, Hash, PartialEq;
107 voprf::BlindedElement<CS::OprfCs>,
108 <CS::KeyExchange as KeyExchange>::KE1Message,
109)]
110pub struct CredentialRequest<CS: CipherSuite> {
111 pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
112 pub(crate) ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message,
113}
114
115#[cfg_attr(
117 feature = "serde",
118 derive(serde::Deserialize, serde::Serialize),
119 serde(bound(
120 deserialize = "SK: serde::Deserialize<'de>, <CS::KeyExchange as \
121 KeyExchange>::KE2Builder<'a, CS>: serde::Deserialize<'de>",
122 serialize = "SK: serde::Serialize, <CS::KeyExchange as KeyExchange>::KE2Builder<'a, CS>: \
123 serde::Serialize"
124 ))
125)]
126#[derive_where(Clone)]
127#[derive_where(
128 Debug, Eq, PartialEq;
129 <KeGroup<CS> as Group>::Pk,
130 SK,
131 voprf::EvaluationElement<CS::OprfCs>,
132 <CS::KeyExchange as KeyExchange>::KE2Builder<'a, CS>,
133)]
134pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> {
135 pub(crate) server_s_sk: SK,
136 pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
137 pub(crate) masking_nonce: Zeroizing<GenericArray<u8, NonceLen>>,
138 pub(crate) masked_response: MaskedResponse<CS>,
139 #[cfg(test)]
140 pub(crate) oprf_key: Zeroizing<GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>>,
141 pub(crate) ke2_builder: <CS::KeyExchange as KeyExchange>::KE2Builder<'a, CS>,
142}
143
144impl<CS: CipherSuite, SK: Clone> ServerLoginBuilder<'_, CS, SK> {
145 pub fn data(&self) -> <CS::KeyExchange as KeyExchange>::KE2BuilderData<'_, CS> {
150 CS::KeyExchange::ke2_builder_data(&self.ke2_builder)
151 }
152
153 pub fn private_key(&self) -> &SK {
155 &self.server_s_sk
156 }
157
158 pub fn build(
164 self,
165 input: <CS::KeyExchange as KeyExchange>::KE2BuilderInput<CS>,
166 ) -> Result<ServerLoginStartResult<CS>, ProtocolError> {
167 ServerLogin::build(self, input)
168 }
169}
170
171#[cfg_attr(
174 feature = "serde",
175 derive(serde::Deserialize, serde::Serialize),
176 serde(bound(
177 deserialize = "<CS::KeyExchange as KeyExchange>::KE2Message: serde::Deserialize<'de>",
178 serialize = "<CS::KeyExchange as KeyExchange>::KE2Message: serde::Serialize"
179 ))
180)]
181#[derive_where(Clone)]
182#[derive_where(
183 Debug, Eq, Hash, PartialEq;
184 EvaluationElement<CS::OprfCs>,
185 <CS::KeyExchange as KeyExchange>::KE2Message,
186)]
187pub struct CredentialResponse<CS: CipherSuite> {
188 pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
190 pub(crate) masking_nonce: GenericArray<u8, NonceLen>,
191 pub(crate) masked_response: MaskedResponse<CS>,
192 pub(crate) ke2_message: <CS::KeyExchange as KeyExchange>::KE2Message,
193}
194
195#[cfg_attr(
198 feature = "serde",
199 derive(serde::Deserialize, serde::Serialize),
200 serde(bound(
201 deserialize = "<CS::KeyExchange as KeyExchange>::KE3Message: serde::Deserialize<'de>",
202 serialize = "<CS::KeyExchange as KeyExchange>::KE3Message: serde::Serialize"
203 ))
204)]
205#[derive_where(Clone)]
206#[derive_where(
207 Debug, Eq, Hash, PartialEq;
208 <CS::KeyExchange as KeyExchange>::KE3Message,
209)]
210pub struct CredentialFinalization<CS: CipherSuite> {
211 pub(crate) ke3_message: <CS::KeyExchange as KeyExchange>::KE3Message,
212}
213
214pub type RegistrationRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Group>::ElemLen;
221
222impl<CS: CipherSuite> RegistrationRequest<CS> {
223 #[cfg(test)]
225 pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement<CS::OprfCs> {
226 self.blinded_element.clone()
227 }
228
229 pub fn serialize(&self) -> Array<u8, RegistrationRequestLen<CS>> {
231 <OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value())
232 }
233
234 pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
236 let elem_len = <OprfGroup<CS> as voprf::Group>::ElemLen::USIZE;
237 if input.len() < elem_len {
238 return Err(ProtocolError::SerializationError);
239 }
240 Ok(Self {
241 blinded_element: BlindedElement::deserialize(input)?,
242 })
243 }
244}
245
246pub type RegistrationResponseLen<CS: CipherSuite> =
248 Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, <KeGroup<CS> as Group>::PkLen>;
249
250impl<CS: CipherSuite> RegistrationResponse<CS> {
251 pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
253 where
254 <OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen> + ArrayLength,
256 RegistrationResponseLen<CS>: ArrayLength,
257 {
258 let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
259 self.evaluation_element.value(),
260 ));
261
262 elem.cat(self.server_s_pk.serialize())
263 }
264
265 pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError> {
267 let elem_len = EvaluationElementLen::<CS::OprfCs>::USIZE;
268 if input.len() < elem_len {
269 return Err(ProtocolError::SerializationError);
270 }
271 let evaluation_element = EvaluationElement::deserialize(&input[..elem_len])?;
272 input = &input[elem_len..];
273
274 Ok(Self {
275 evaluation_element,
276 server_s_pk: PublicKey::deserialize_take(&mut input)?,
277 })
278 }
279
280 #[cfg(test)]
281 pub(crate) fn set_evaluation_element_for_testing(
284 &self,
285 beta: <OprfGroup<CS> as voprf::Group>::Elem,
286 ) -> Self {
287 Self {
288 evaluation_element: EvaluationElement::from_value_unchecked(beta),
289 server_s_pk: self.server_s_pk.clone(),
290 }
291 }
292}
293
294pub type RegistrationUploadLen<CS: CipherSuite> =
296 Sum<Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>, EnvelopeLen<CS>>;
297
298impl<CS: CipherSuite> RegistrationUpload<CS> {
299 pub fn serialize(&self) -> GenericArray<u8, RegistrationUploadLen<CS>>
301 where
302 <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
304 Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
305 ArrayLength + Add<EnvelopeLen<CS>>,
306 RegistrationUploadLen<CS>: ArrayLength,
307 {
308 self.client_s_pk
309 .serialize()
310 .cat(GenericArray::from_slice(self.masking_key.as_slice()).clone())
311 .cat(self.envelope.serialize())
312 }
313
314 pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError> {
316 Ok(Self {
317 client_s_pk: PublicKey::deserialize_take(&mut input)?,
318 masking_key: input.take_array("masking key")?.into_ha0_4(),
319 envelope: Envelope::deserialize_take(&mut input)?,
320 })
321 }
322
323 pub(crate) fn dummy<R: Rng + CryptoRng, SK: Clone, OS: Clone>(
325 rng: &mut R,
326 server_setup: &ServerSetup<CS, SK, OS>,
327 ) -> Self {
328 let mut masking_key = Output::<OprfHash<CS>>::default();
329 rng.fill_bytes(&mut masking_key);
330
331 Self {
332 envelope: Envelope::<CS>::dummy(),
333 masking_key,
334 client_s_pk: server_setup.dummy_pk.clone(),
335 }
336 }
337}
338
339pub type CredentialRequestLen<CS: CipherSuite> =
341 Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, Ke1MessageLen<CS>>;
342
343impl<CS: CipherSuite> CredentialRequest<CS> {
344 pub fn serialize(&self) -> GenericArray<u8, CredentialRequestLen<CS>>
346 where
347 <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
348 <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>> + ArrayLength,
350 CredentialRequestLen<CS>: ArrayLength,
351 {
352 let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
353 self.blinded_element.value(),
354 ));
355
356 elem.cat(self.ke1_message.serialize())
357 }
358
359 pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError>
361 where
362 <CS::KeyExchange as KeyExchange>::KE1Message: Deserialize,
363 {
364 Self::deserialize_take(&mut input)
365 }
366
367 pub(crate) fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError>
368 where
369 <CS::KeyExchange as KeyExchange>::KE1Message: Deserialize,
370 {
371 let elem_len = BlindedElementLen::<CS::OprfCs>::USIZE;
372 if input.len() < elem_len {
373 return Err(ProtocolError::SerializationError);
374 }
375 let blinded_element = BlindedElement::deserialize(&input[..elem_len])?;
376 *input = &input[elem_len..];
377
378 Ok(Self {
379 blinded_element,
380 ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message::deserialize_take(input)?,
381 })
382 }
383
384 pub(crate) fn to_parts(&self) -> SerializedCredentialRequest<CS> {
385 SerializedCredentialRequest::new(&self.blinded_element)
386 }
387
388 #[cfg(test)]
390 pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement<CS::OprfCs> {
391 self.blinded_element.clone()
392 }
393}
394
395pub type CredentialResponseLen<CS: CipherSuite> =
397 Sum<CredentialResponseWithoutKeLen<CS>, Ke2MessageLen<CS>>;
398
399pub(crate) type CredentialResponseWithoutKeLen<CS: CipherSuite> =
400 Sum<Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>, MaskedResponseLen<CS>>;
401
402impl<CS: CipherSuite> CredentialResponse<CS> {
403 pub fn serialize(&self) -> GenericArray<u8, CredentialResponseLen<CS>>
405 where
406 <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
407 <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen> + ArrayLength,
409 Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
410 ArrayLength + Add<MaskedResponseLen<CS>>,
411 CredentialResponseWithoutKeLen<CS>: ArrayLength,
412 CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
414 CredentialResponseLen<CS>: ArrayLength,
415 {
416 let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
417 self.evaluation_element.value(),
418 ));
419
420 elem.cat(self.masking_nonce)
421 .cat(self.masked_response.serialize())
422 .cat(self.ke2_message.serialize())
423 }
424
425 pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError>
427 where
428 <CS::KeyExchange as KeyExchange>::KE2Message: Deserialize,
429 {
430 let elem_len = EvaluationElementLen::<CS::OprfCs>::USIZE;
431 if input.len() < elem_len {
432 return Err(ProtocolError::SerializationError);
433 }
434 let evaluation_element = EvaluationElement::deserialize(&input[..elem_len])?;
435 input = &input[elem_len..];
436
437 Ok(Self {
438 evaluation_element,
439 masking_nonce: input.take_array("masking nonce")?,
440 masked_response: MaskedResponse::deserialize_take(&mut input)?,
441 ke2_message: <CS::KeyExchange as KeyExchange>::KE2Message::deserialize_take(
442 &mut input,
443 )?,
444 })
445 }
446
447 pub(crate) fn to_parts(&self) -> SerializedCredentialResponse<CS> {
448 SerializedCredentialResponse::new(
449 &self.evaluation_element,
450 self.masking_nonce,
451 self.masked_response.clone(),
452 )
453 }
454
455 #[cfg(test)]
456 pub(crate) fn set_evaluation_element_for_testing(
459 &self,
460 beta: <OprfGroup<CS> as voprf::Group>::Elem,
461 ) -> Self {
462 Self {
463 evaluation_element: EvaluationElement::from_value_unchecked(beta),
464 masking_nonce: self.masking_nonce,
465 masked_response: self.masked_response.clone(),
466 ke2_message: self.ke2_message.clone(),
467 }
468 }
469}
470
471pub type CredentialFinalizationLen<CS: CipherSuite> = Ke3MessageLen<CS>;
473
474impl<CS: CipherSuite> CredentialFinalization<CS> {
475 pub fn serialize(&self) -> GenericArray<u8, CredentialFinalizationLen<CS>>
477 where
478 <CS::KeyExchange as KeyExchange>::KE3Message: Serialize,
479 {
480 self.ke3_message.serialize()
481 }
482
483 pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError>
485 where
486 <CS::KeyExchange as KeyExchange>::KE3Message: Deserialize,
487 {
488 Ok(Self {
489 ke3_message: <CS::KeyExchange as KeyExchange>::KE3Message::deserialize_take(
490 &mut input,
491 )?,
492 })
493 }
494}