Skip to main content

opaque_vx/key_exchange/sigma_i/
mod.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) VexaHub and contributors.
3// Copyright (c) Meta Platforms, Inc. and affiliates.
4
5//! An implementation of the SIGMA-I key exchange protocol
6//!
7//! ⚠️ **Warning**: This implementation has not been audited. Use at your own
8//! risk!
9
10#[cfg(feature = "ecdsa")]
11pub mod ecdsa;
12pub mod hash_eddsa;
13mod message;
14pub mod pure_eddsa;
15pub(super) mod shared;
16
17use core::iter;
18use core::marker::PhantomData;
19use core::ops::Add;
20
21use derive_where::derive_where;
22use digest::block_api::{BlockSizeUser, CoreProxy, SmallBlockSizeUser};
23use digest::{Mac, Output, OutputSizeUser};
24use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
25use generic_array::{ArrayLength, GenericArray};
26use hmac::{KeyInit, SimpleHmac};
27use rand::{CryptoRng, Rng};
28use subtle::{ConstantTimeEq, CtOption};
29use zeroize::Zeroize;
30
31use self::message::Role;
32pub use self::message::{CachedMessage, HashOutput, Message, MessageBuilder, VerifyMessage};
33use super::{
34    Deserialize, GenerateKe1Result, GenerateKe2Result, GenerateKe3Result, KeyExchange, Serialize,
35    SerializedContext, SerializedCredentialRequest, SerializedCredentialResponse,
36    SerializedIdentifier, SerializedIdentifiers,
37};
38use crate::ciphersuite::{CipherSuite, KeGroup, KeHash};
39use crate::envelope::NonceLen;
40use crate::errors::{InternalError, ProtocolError};
41use crate::hash::{Hash, OutputSize, ProxyHash};
42use crate::key_exchange::group::Group;
43pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
44use crate::key_exchange::shared::{derive_keys, generate_ke1, generate_nonce, transcript};
45use crate::keypair::{KeyPair, PrivateKey, PublicKey};
46use crate::opaque::Identifiers;
47use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
48
49/// The SIGMA-I key exchange implementation
50///
51/// `SIG` determines the algorithm used for the signature. `KE` determines the
52/// algorithm used for establishing the shared secret. `KEH` determines the hash
53/// used for the key exchange.
54///
55/// # Remote Key
56///
57/// [`ServerLoginBuilder::data()`](crate::ServerLoginBuilder::data()) will
58/// return [`Message`].
59///
60/// [`ServerLoginBuilder::build()`](crate::ServerLoginBuilder::build()) expects
61/// a signature from signing the [message](Message::sign_message) with the
62/// servers private key, and a ["verification
63/// state"](SignatureProtocol::VerifyState).
64///
65/// To understand what kind of "verification state" is expected here exactly,
66/// refer to the documentation of your chosen [`SignatureProtocol`] `SIG`. E.g.
67/// [`Ecdsa`](ecdsa::Ecdsa), [`PureEddsa`](pure_eddsa::PureEddsa) or
68/// [`HashEddsa`](hash_eddsa::HashEddsa).
69pub struct SigmaI<SIG, KE, KEH>(PhantomData<(SIG, KE, KEH)>);
70
71/// Trait to implement for `SIG` used in [`SigmaI`].
72///
73/// The [`sign()`] and [`verify()`] methods do not function independent of each
74/// other. [`sign()`] is always called first and receives a [Message] containing
75/// the message for both signing and verifying. A ["verification
76/// state"](Self::VerifyState) is created by [`sign()`] and then passed onto
77/// [`verify()`].
78///
79/// The most straightforward implementation would simply store the message for
80/// verifying in [`VerifyState`](Self::VerifyState). However, protocols that
81/// allow for pre-hashing don't need to store the whole message and can
82/// preemptively hash the verification message and only store that instead,
83/// getting rid of the much larger message.
84///
85/// [`sign()`]: Self::sign
86/// [`verify()`]: Self::verify
87pub trait SignatureProtocol {
88    /// The [`Group`] used to generate and derive keys.
89    type Group: Group;
90    /// The signature.
91    type Signature: Clone + Zeroize;
92    /// Length of a serialized [`Signature`](Self::Signature).
93    type SignatureLen: ArrayLength;
94    /// The state required to run the verification. This is used to cache the
95    /// pre-hash for curves that support that, otherwise the [`Message`] to
96    /// verify is stored via [`CachedMessage`].
97    type VerifyState<CS: CipherSuite, KE: Group>: Clone + Zeroize;
98
99    /// Returns a signature from the given message signed by the given private
100    /// key.
101    ///
102    /// [`Message`] contains both signature messages for signing and
103    /// verification. If you need it again during verification, consider
104    /// using [`CachedMessage`].
105    ///
106    /// The returned [`VerifyState`](Self::VerifyState) will be passed to
107    /// [`verify()`](Self::verify) and must contain the necessary
108    /// information to verify the incoming signature.
109    fn sign<R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
110        sk: &<Self::Group as Group>::Sk,
111        rng: &mut R,
112        message: &Message<CS, KE>,
113    ) -> (Self::Signature, Self::VerifyState<CS, KE>);
114
115    /// Validates that the signature was created by signing the message with the
116    /// corresponding private key.
117    ///
118    /// The [`MessageBuilder`] can be used with [`CachedMessage`] to create
119    /// [`VerifyMessage`] which contains the message of the given `signature`.
120    ///
121    /// The `state` is created by [`sign()`](Self::sign()).
122    fn verify<CS: CipherSuite, KE: Group>(
123        pk: &<Self::Group as Group>::Pk,
124        message_builder: MessageBuilder<'_, CS>,
125        state: Self::VerifyState<CS, KE>,
126        signature: &Self::Signature,
127    ) -> Result<(), ProtocolError>;
128
129    /// Serialize [`Signature`](Self::Signature) into a fixed-sized byte array.
130    fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen>;
131
132    /// Deserialize [`Signature`](Self::Signature) from the given `bytes`.
133    ///
134    /// The deserialized bytes must be taken from `bytes`.
135    fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError>;
136}
137
138/// Builder for the second key exchange message
139#[cfg_attr(
140    feature = "serde",
141    derive(serde::Deserialize, serde::Serialize),
142    serde(bound(
143        deserialize = "'de: 'a, <KeGroup<CS> as Group>::Pk: serde::Deserialize<'de>, KE::Pk: \
144                       serde::Deserialize<'de>",
145        serialize = "<KeGroup<CS> as Group>::Pk: serde::Serialize, KE::Pk: serde::Serialize"
146    ))
147)]
148#[derive_where(Clone, ZeroizeOnDrop)]
149#[derive_where(Debug, Eq, Hash, PartialEq; <KeGroup<CS> as Group>::Pk, KE::Pk)]
150pub struct Ke2Builder<'a, CS: CipherSuite, KE: Group> {
151    transcript: Message<'a, CS, KE>,
152    server_nonce: GenericArray<u8, NonceLen>,
153    #[derive_where(skip(Zeroize))]
154    client_s_pk: PublicKey<KeGroup<CS>>,
155    #[derive_where(skip(Zeroize))]
156    server_e_pk: PublicKey<KE>,
157    expected_mac: Output<KeHash<CS>>,
158    session_key: Output<KeHash<CS>>,
159    #[cfg(test)]
160    handshake_secret: Output<KeHash<CS>>,
161    #[cfg(test)]
162    km2: Output<KeHash<CS>>,
163}
164
165/// The server state produced after the second key exchange message
166#[cfg_attr(
167    feature = "serde",
168    derive(serde::Deserialize, serde::Serialize),
169    serde(bound(
170        deserialize = "<SIG::Group as Group>::Pk: serde::Deserialize<'de>, SIG::VerifyState<CS, \
171                       KE>: serde::Deserialize<'de>",
172        serialize = "<SIG::Group as Group>::Pk: serde::Serialize, SIG::VerifyState<CS, KE>: \
173                     serde::Serialize"
174    ))
175)]
176#[derive_where(Clone, ZeroizeOnDrop)]
177#[derive_where(Debug, Eq, Hash, PartialEq; <SIG::Group as Group>::Pk, SIG::VerifyState<CS, KE>)]
178pub struct Ke2State<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> {
179    #[derive_where(skip(Zeroize))]
180    client_s_pk: PublicKey<SIG::Group>,
181    session_key: Output<KeHash<CS>>,
182    verify_state: SIG::VerifyState<CS, KE>,
183    expected_mac: Output<KeHash<CS>>,
184}
185
186/// The second key exchange message
187#[cfg_attr(
188    feature = "serde",
189    derive(serde::Deserialize, serde::Serialize),
190    serde(bound(
191        deserialize = "KE::Pk: serde::Deserialize<'de>, SIG::Signature: serde::Deserialize<'de>",
192        serialize = "KE::Pk: serde::Serialize, SIG::Signature: serde::Serialize"
193    ))
194)]
195#[derive_where(Clone, ZeroizeOnDrop)]
196#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KE::Pk, SIG::Signature)]
197pub struct Ke2Message<SIG: SignatureProtocol, KE: Group, KEH: Hash>
198where
199    KEH::Core: ProxyHash,
200    <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
201    Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
202    OutputSize<KEH>: ArrayLength,
203{
204    server_nonce: GenericArray<u8, NonceLen>,
205    #[derive_where(skip(Zeroize))]
206    server_e_pk: PublicKey<KE>,
207    signature: SIG::Signature,
208    mac: Output<KEH>,
209}
210
211/// The third key exchange message
212#[cfg_attr(
213    feature = "serde",
214    derive(serde::Deserialize, serde::Serialize),
215    serde(bound(
216        deserialize = "SIG::Signature: serde::Deserialize<'de>",
217        serialize = "SIG::Signature: serde::Serialize"
218    ))
219)]
220#[derive_where(Clone, ZeroizeOnDrop)]
221#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; SIG::Signature)]
222pub struct Ke3Message<SIG: SignatureProtocol, KEH: OutputSizeUser>
223where
224    <KEH as OutputSizeUser>::OutputSize: ArrayLength,
225{
226    signature: SIG::Signature,
227    mac: Output<KEH>,
228}
229
230impl<SIG: SignatureProtocol, KE: 'static + Group, KEH: Hash + BlockSizeUser> KeyExchange
231    for SigmaI<SIG, KE, KEH>
232where
233    KE::Sk: DiffieHellman<KE>,
234    KEH::Core: ProxyHash,
235    <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
236    Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
237    OutputSize<KEH>: ArrayLength,
238{
239    type Group = SIG::Group;
240    type Hash = KEH;
241
242    type KE1State = Ke1State<KE>;
243    type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
244    type KE1Message = Ke1Message<KE>;
245    type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>> = Ke2Builder<'a, CS, KE>;
246    type KE2BuilderData<'a, CS: 'static + CipherSuite> = &'a Message<'a, CS, KE>;
247    type KE2BuilderInput<CS: CipherSuite> = (SIG::Signature, SIG::VerifyState<CS, KE>);
248    type KE2Message = Ke2Message<SIG, KE, KEH>;
249    type KE3Message = Ke3Message<SIG, KEH>;
250
251    fn generate_ke1<R: Rng + CryptoRng>(
252        rng: &mut R,
253    ) -> Result<GenerateKe1Result<Self>, ProtocolError> {
254        generate_ke1(rng)
255    }
256
257    fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
258        rng: &mut R,
259        credential_request: SerializedCredentialRequest<CS>,
260        ke1_message: Self::KE1Message,
261        credential_response: SerializedCredentialResponse<CS>,
262        client_s_pk: PublicKey<Self::Group>,
263        identifiers: SerializedIdentifiers<'a, KeGroup<CS>>,
264        context: SerializedContext<'a>,
265    ) -> Result<Self::KE2Builder<'a, CS>, ProtocolError> {
266        let server_e = KeyPair::<KE>::derive_random(rng);
267        let server_nonce = generate_nonce::<R>(rng);
268
269        let ke1_message_iter = ke1_message.to_iter();
270        let server_e_pk = server_e.public().serialize();
271
272        let transcript_hasher = transcript(
273            &context,
274            &identifiers,
275            &credential_request,
276            &ke1_message_iter,
277            &credential_response,
278            server_nonce,
279            &server_e_pk,
280        );
281
282        let shared_secret = server_e
283            .private()
284            .ke_diffie_hellman(&ke1_message.client_e_pk);
285
286        let derived_keys = derive_keys::<KEH>(
287            iter::once(shared_secret.as_slice()),
288            &transcript_hasher.finalize(),
289        )?;
290
291        let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
292            .map_err(|_| InternalError::HmacError)?;
293        server_mac.update_iter(identifiers.server.iter());
294        let server_mac = server_mac.finalize().into_bytes();
295
296        let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
297            .map_err(|_| InternalError::HmacError)?;
298        client_mac.update_iter(identifiers.client.iter());
299        let client_mac = client_mac.finalize().into_bytes();
300
301        let message = Message {
302            role: Role::Server,
303            context,
304            identifiers,
305            cache: CachedMessage {
306                credential_request,
307                ke1_message: ke1_message_iter,
308                credential_response,
309                server_nonce,
310                server_e_pk,
311                server_mac,
312            },
313        };
314
315        Ok(Ke2Builder {
316            transcript: message,
317            server_nonce,
318            client_s_pk,
319            server_e_pk: server_e.public().clone(),
320            expected_mac: client_mac,
321            session_key: derived_keys.session_key,
322            #[cfg(test)]
323            handshake_secret: derived_keys.handshake_secret,
324            #[cfg(test)]
325            km2: derived_keys.km2,
326        })
327    }
328
329    fn ke2_builder_data<'a, CS: 'static + CipherSuite<KeyExchange = Self>>(
330        builder: &'a Self::KE2Builder<'_, CS>,
331    ) -> Self::KE2BuilderData<'a, CS> {
332        &builder.transcript
333    }
334
335    fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
336        builder: &Self::KE2Builder<'_, CS>,
337        rng: &mut R,
338        server_s_sk: &PrivateKey<Self::Group>,
339    ) -> Self::KE2BuilderInput<CS> {
340        server_s_sk.sign::<_, CS, SIG, KE>(rng, &builder.transcript)
341    }
342
343    fn build_ke2<CS: CipherSuite<KeyExchange = Self>>(
344        builder: Self::KE2Builder<'_, CS>,
345        input: Self::KE2BuilderInput<CS>,
346    ) -> Result<GenerateKe2Result<CS>, ProtocolError> {
347        Ok(GenerateKe2Result {
348            state: Ke2State {
349                client_s_pk: builder.client_s_pk.clone(),
350                session_key: builder.session_key.clone(),
351                verify_state: input.1,
352                expected_mac: builder.expected_mac.clone(),
353            },
354            message: Ke2Message {
355                server_nonce: builder.server_nonce,
356                server_e_pk: builder.server_e_pk.clone(),
357                signature: input.0,
358                mac: builder.transcript.cache.server_mac.clone(),
359            },
360            #[cfg(test)]
361            handshake_secret: builder.handshake_secret.clone(),
362            #[cfg(test)]
363            km2: builder.km2.clone(),
364        })
365    }
366
367    fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
368        rng: &mut R,
369        credential_request: SerializedCredentialRequest<CS>,
370        ke1_message: Self::KE1Message,
371        credential_response: SerializedCredentialResponse<CS>,
372        ke1_state: &Self::KE1State,
373        ke2_message: Self::KE2Message,
374        server_s_pk: PublicKey<Self::Group>,
375        client_s_sk: PrivateKey<Self::Group>,
376        identifiers: SerializedIdentifiers<'_, KeGroup<CS>>,
377        context: SerializedContext<'_>,
378    ) -> Result<GenerateKe3Result<Self>, ProtocolError> {
379        let ke1_message_iter = ke1_message.to_iter();
380        let server_e_pk = ke2_message.server_e_pk.serialize();
381
382        let transcript_hasher = transcript(
383            &context,
384            &identifiers,
385            &credential_request,
386            &ke1_message_iter,
387            &credential_response,
388            ke2_message.server_nonce,
389            &server_e_pk,
390        );
391
392        let shared_secret = ke1_state
393            .client_e_sk
394            .ke_diffie_hellman(&ke2_message.server_e_pk);
395
396        let derived_keys = derive_keys::<KEH>(
397            iter::once(shared_secret.as_slice()),
398            &transcript_hasher.finalize(),
399        )?;
400
401        let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
402            .map_err(|_| InternalError::HmacError)?;
403        server_mac.update_iter(identifiers.server.iter());
404        let server_mac = server_mac.finalize().into_bytes();
405
406        bool::from(server_mac.ct_eq(&ke2_message.mac))
407            .then_some(())
408            .ok_or(ProtocolError::InvalidLoginError)?;
409
410        let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
411            .map_err(|_| InternalError::HmacError)?;
412        client_mac.update_iter(identifiers.client.iter());
413        let client_mac = client_mac.finalize().into_bytes();
414
415        let message = Message {
416            role: Role::Client,
417            context: context.clone(),
418            identifiers: identifiers.clone(),
419            cache: CachedMessage {
420                credential_request,
421                ke1_message: ke1_message_iter,
422                credential_response,
423                server_nonce: ke2_message.server_nonce,
424                server_e_pk,
425                server_mac,
426            },
427        };
428
429        let (signature, state) = client_s_sk.sign::<_, CS, SIG, KE>(rng, &message);
430
431        server_s_pk.verify::<CS, SIG, KE>(
432            MessageBuilder {
433                role: Role::Client,
434                context,
435                identifier: identifiers.server,
436            },
437            state,
438            &ke2_message.signature,
439        )?;
440
441        Ok(GenerateKe3Result {
442            session_key: derived_keys.session_key,
443            message: Ke3Message {
444                signature,
445                mac: client_mac,
446            },
447            #[cfg(test)]
448            handshake_secret: derived_keys.handshake_secret,
449            #[cfg(test)]
450            km3: derived_keys.km3,
451        })
452    }
453
454    fn finish_ke<CS: CipherSuite<KeyExchange = Self>>(
455        ke2_state: &Self::KE2State<CS>,
456        ke3_message: Self::KE3Message,
457        identifiers: Identifiers<'_>,
458        context: SerializedContext<'_>,
459    ) -> Result<Output<KEH>, ProtocolError> {
460        ke2_state.client_s_pk.verify::<CS, SIG, KE>(
461            MessageBuilder {
462                role: Role::Server,
463                context,
464                identifier: SerializedIdentifier::from_identifier(
465                    identifiers.client,
466                    ke2_state.client_s_pk.serialize(),
467                )?,
468            },
469            ke2_state.verify_state.clone(),
470            &ke3_message.signature,
471        )?;
472
473        CtOption::new(
474            ke2_state.session_key.clone(),
475            ke2_state.expected_mac.ct_eq(&ke3_message.mac),
476        )
477        .into_option()
478        .ok_or(ProtocolError::InvalidLoginError)
479    }
480}
481
482impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Deserialize for Ke2State<CS, SIG, KE>
483where
484    SIG::VerifyState<CS, KE>: Deserialize,
485    OutputSize<KeHash<CS>>: ArrayLength,
486{
487    fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
488        Ok(Self {
489            client_s_pk: PublicKey::deserialize_take(input)?,
490            session_key: input.take_array("session key")?.into_ha0_4(),
491            verify_state: SIG::VerifyState::<CS, KE>::deserialize_take(input)?,
492            expected_mac: input.take_array("expected mac")?.into_ha0_4(),
493        })
494    }
495}
496
497type Ke2StateLen<CS, SIG: SignatureProtocol, KE> = Sum<
498    Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>,
499    OutputSize<KeHash<CS>>,
500>;
501
502type VerifyStateLen<CS, SIG: SignatureProtocol, KE> = <SIG::VerifyState<CS, KE> as Serialize>::Len;
503
504impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Serialize for Ke2State<CS, SIG, KE>
505where
506    SIG::VerifyState<CS, KE>: Serialize,
507    OutputSize<KeHash<CS>>: ArrayLength,
508    // Ke2State: ((SigPk + Hash) + VerifyState) + Hash
509    <SIG::Group as Group>::PkLen: Add<OutputSize<KeHash<CS>>>,
510    Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>:
511        ArrayLength + Add<VerifyStateLen<CS, SIG, KE>>,
512    Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>:
513        ArrayLength + Add<OutputSize<KeHash<CS>>>,
514    Ke2StateLen<CS, SIG, KE>: ArrayLength,
515{
516    type Len = Ke2StateLen<CS, SIG, KE>;
517
518    fn serialize(&self) -> GenericArray<u8, Self::Len> {
519        self.client_s_pk
520            .serialize()
521            .cat(GenericArray::from_slice(self.session_key.as_slice()).clone())
522            .cat(self.verify_state.serialize())
523            .cat(GenericArray::from_slice(self.expected_mac.as_slice()).clone())
524    }
525}
526
527impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Deserialize for Ke2Message<SIG, KE, KEH>
528where
529    KEH::Core: ProxyHash,
530    <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
531    Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
532    OutputSize<KEH>: ArrayLength,
533{
534    fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
535        Ok(Self {
536            server_nonce: input.take_array("server nonce")?,
537            server_e_pk: PublicKey::deserialize_take(input)?,
538            signature: SIG::deserialize_take_signature(input)?,
539            mac: input.take_array("mac")?.into_ha0_4(),
540        })
541    }
542}
543
544impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Serialize for Ke2Message<SIG, KE, KEH>
545where
546    KEH::Core: ProxyHash,
547    <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
548    Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
549    OutputSize<KEH>: ArrayLength,
550    // Ke2Message: ((Nonce + KePk) + Signature) + Hash
551    NonceLen: Add<KE::PkLen>,
552    Sum<NonceLen, KE::PkLen>: ArrayLength + Add<SIG::SignatureLen>,
553    Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength + Add<OutputSize<KEH>>,
554    Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength,
555{
556    type Len = Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>;
557
558    fn serialize(&self) -> GenericArray<u8, Self::Len> {
559        self.server_nonce
560            .cat(self.server_e_pk.serialize())
561            .cat(SIG::serialize_signature(&self.signature))
562            .cat(GenericArray::from_slice(self.mac.as_slice()).clone())
563    }
564}
565
566impl<SIG: SignatureProtocol, KEH: Hash> Deserialize for Ke3Message<SIG, KEH>
567where
568    KEH::Core: ProxyHash,
569    <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
570    Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
571    OutputSize<KEH>: ArrayLength,
572{
573    fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
574        Ok(Self {
575            signature: SIG::deserialize_take_signature(input)?,
576            mac: input.take_array("mac")?.into_ha0_4(),
577        })
578    }
579}
580
581impl<SIG: SignatureProtocol, KEH: Hash> Serialize for Ke3Message<SIG, KEH>
582where
583    KEH::Core: ProxyHash,
584    <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
585    Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
586    OutputSize<KEH>: ArrayLength,
587    // Ke2Message: Signature + Hash
588    SIG::SignatureLen: Add<OutputSize<KEH>>,
589    Sum<SIG::SignatureLen, OutputSize<KEH>>: ArrayLength,
590{
591    type Len = Sum<SIG::SignatureLen, OutputSize<KEH>>;
592
593    fn serialize(&self) -> GenericArray<u8, Self::Len> {
594        SIG::serialize_signature(&self.signature)
595            .cat(GenericArray::from_slice(self.mac.as_slice()).clone())
596    }
597}