Skip to main content

miden_crypto/ies/
keys.rs

1use alloc::vec::Vec;
2use core::fmt;
3
4use rand::CryptoRng;
5
6use super::{
7    IesError, IesScheme, crypto_box::CryptoBox, ecgfp5_eidos::adapter, message::SealedMessage,
8};
9use crate::{
10    Felt,
11    aead::{aead_eidos::AeadEidos, xchacha::XChaCha},
12    dsa::{
13        ecdsa_k256_keccak::PUBLIC_KEY_BYTES as K256_PUBLIC_KEY_BYTES,
14        eddsa_25519_sha512::PUBLIC_KEY_BYTES as X25519_PUBLIC_KEY_BYTES,
15    },
16    ecdh::{KeyAgreementScheme, ecgfp5, k256::K256, x25519::X25519},
17    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
18};
19
20// TYPE ALIASES
21// ================================================================================================
22
23/// Sealed-box construction using K256 and XChaCha20-Poly1305.
24type K256XChaCha20Poly1305 = CryptoBox<K256, XChaCha>;
25/// Sealed-box construction using X25519 and XChaCha20-Poly1305.
26type X25519XChaCha20Poly1305 = CryptoBox<X25519, XChaCha>;
27/// Sealed-box construction using K256 and Eidos authenticated encryption.
28type K256AeadEidos = CryptoBox<K256, AeadEidos>;
29/// Sealed-box construction using X25519 and Eidos authenticated encryption.
30type X25519AeadEidos = CryptoBox<X25519, AeadEidos>;
31
32// HELPER MACROS
33// ================================================================================================
34
35/// Implements byte sealing for each supported scheme.
36macro_rules! impl_seal_bytes_with_associated_data {
37    ($($variant:path => $crypto_box:ty, $ephemeral_variant:path;)*) => {
38        /// Seals the provided plaintext (represented as bytes) and associated data with this
39        /// sealing key.
40        ///
41        /// The returned message can be unsealed with the [UnsealingKey] associated with this
42        /// sealing key.
43        pub fn seal_bytes_with_associated_data<R: CryptoRng>(
44            &self,
45            rng: &mut R,
46            plaintext: &[u8],
47            associated_data: &[u8],
48        ) -> Result<SealedMessage, IesError> {
49            match self {
50                SealingKey::Ecgfp5Eidos(key) => {
51                    adapter::seal_bytes(key, rng, plaintext, associated_data)
52                },
53                $(
54                    $variant(key) => {
55                        let scheme = self.scheme();
56                        let (ciphertext, ephemeral) = <$crypto_box>::seal_bytes_with_associated_data(
57                            rng,
58                            key,
59                            scheme,
60                            plaintext,
61                            associated_data,
62                        )?;
63
64                        Ok(SealedMessage {
65                            ephemeral_key: $ephemeral_variant(ephemeral),
66                            ciphertext,
67                        })
68                    }
69                )*
70            }
71        }
72    };
73}
74
75/// Implements field-element sealing for each supported scheme.
76macro_rules! impl_seal_elements_with_associated_data {
77    ($($variant:path => $crypto_box:ty, $ephemeral_variant:path;)*) => {
78        /// Seals the provided field elements and associated data with
79        /// this sealing key.
80        ///
81        /// The returned message can be unsealed with the [UnsealingKey] associated with this
82        /// sealing key.
83        pub fn seal_elements_with_associated_data<R: CryptoRng>(
84            &self,
85            rng: &mut R,
86            plaintext: &[Felt],
87            associated_data: &[Felt],
88        ) -> Result<SealedMessage, IesError> {
89            match self {
90                SealingKey::Ecgfp5Eidos(key) => {
91                    adapter::seal_elements(key, rng, plaintext, associated_data)
92                },
93                $(
94                    $variant(key) => {
95                        let scheme = self.scheme();
96                        let (ciphertext, ephemeral) = <$crypto_box>::seal_elements_with_associated_data(
97                            rng,
98                            key,
99                            scheme,
100                            plaintext,
101                            associated_data,
102                        )?;
103
104                        Ok(SealedMessage {
105                            ephemeral_key: $ephemeral_variant(ephemeral),
106                            ciphertext,
107                        })
108                    }
109                )*
110            }
111        }
112    };
113}
114
115/// Implements byte unsealing for each supported scheme.
116macro_rules! impl_unseal_bytes_with_associated_data {
117    ($($variant:path => $crypto_box:ty, $ephemeral_variant:path;)*) => {
118        /// Unseals the provided message using this unsealing key and returns the plaintext as bytes.
119        ///
120        /// # Errors
121        /// Returns an error if:
122        /// - The message was not sealed as bytes (i.e., if it was sealed using `seal_elements()`
123        ///   or `seal_elements_with_associated_data()`)
124        /// - The scheme used to seal the message does not match this unsealing key's scheme
125        /// - Decryption or authentication fails
126        pub fn unseal_bytes_with_associated_data(
127            &self,
128            sealed_message: SealedMessage,
129            associated_data: &[u8],
130        ) -> Result<Vec<u8>, IesError> {
131            let self_algo = self.scheme() as u8;
132            let msg_algo = sealed_message.ephemeral_key.scheme() as u8;
133
134            let compatible = self_algo == msg_algo;
135            if !compatible {
136                return Err(IesError::SchemeMismatch);
137            }
138
139            let SealedMessage { ephemeral_key, ciphertext } = sealed_message;
140
141            match (self, ephemeral_key) {
142                (UnsealingKey::Ecgfp5Eidos(key), EphemeralPublicKey::Ecgfp5Eidos(ephemeral)) => {
143                    adapter::open_bytes(key, ephemeral, &ciphertext, associated_data)
144                },
145                $(
146                    ($variant(key), $ephemeral_variant(ephemeral)) => {
147                        <$crypto_box>::unseal_bytes_with_associated_data(
148                            key,
149                            &ephemeral,
150                            self.scheme(),
151                            &ciphertext,
152                            associated_data,
153                        )
154                    }
155                )*
156                _ => Err(IesError::SchemeMismatch),
157            }
158        }
159    };
160}
161
162/// Implements field-element unsealing for each supported scheme.
163macro_rules! impl_unseal_elements_with_associated_data {
164    ($($variant:path => $crypto_box:ty, $ephemeral_variant:path;)*) => {
165        /// Unseals the provided message using this unsealing key and returns the plaintext as field elements.
166        ///
167        /// # Errors
168        /// Returns an error if:
169        /// - The message was not sealed as elements (i.e., if it was sealed using `seal_bytes()`
170        ///   or `seal_bytes_with_associated_data()`)
171        /// - The scheme used to seal the message does not match this unsealing key's scheme
172        /// - Decryption or authentication fails
173        pub fn unseal_elements_with_associated_data(
174            &self,
175            sealed_message: SealedMessage,
176            associated_data: &[Felt],
177        ) -> Result<Vec<Felt>, IesError> {
178            let self_algo = self.scheme() as u8;
179            let msg_algo = sealed_message.ephemeral_key.scheme() as u8;
180
181            let compatible = self_algo == msg_algo;
182            if !compatible {
183                return Err(IesError::SchemeMismatch);
184            }
185
186            let SealedMessage { ephemeral_key, ciphertext } = sealed_message;
187
188            match (self, ephemeral_key) {
189                (UnsealingKey::Ecgfp5Eidos(key), EphemeralPublicKey::Ecgfp5Eidos(ephemeral)) => {
190                    adapter::open_elements(key, ephemeral, &ciphertext, associated_data)
191                },
192                $(
193                    ($variant(key), $ephemeral_variant(ephemeral)) => {
194                        <$crypto_box>::unseal_elements_with_associated_data(
195                            key,
196                            &ephemeral,
197                            self.scheme(),
198                            &ciphertext,
199                            associated_data,
200                        )
201                    }
202                )*
203                _ => Err(IesError::SchemeMismatch),
204            }
205        }
206    };
207}
208
209// SEALING KEY
210// ================================================================================================
211
212/// Public key for sealing messages to a recipient.
213#[derive(Debug, Clone, PartialEq, Eq)]
214#[cfg_attr(
215    all(feature = "arbitrary", test),
216    miden_test_serialization_macros::serialization_test
217)]
218pub enum SealingKey {
219    K256XChaCha20Poly1305(crate::dsa::ecdsa_k256_keccak::PublicKey),
220    X25519XChaCha20Poly1305(crate::dsa::eddsa_25519_sha512::PublicKey),
221    K256AeadEidos(crate::dsa::ecdsa_k256_keccak::PublicKey),
222    X25519AeadEidos(crate::dsa::eddsa_25519_sha512::PublicKey),
223    Ecgfp5Eidos(ecgfp5::PublicKey),
224}
225
226impl SealingKey {
227    /// Returns scheme identifier for this sealing key.
228    pub fn scheme(&self) -> IesScheme {
229        match self {
230            SealingKey::K256XChaCha20Poly1305(_) => IesScheme::K256XChaCha20Poly1305,
231            SealingKey::X25519XChaCha20Poly1305(_) => IesScheme::X25519XChaCha20Poly1305,
232            SealingKey::K256AeadEidos(_) => IesScheme::K256AeadEidos,
233            SealingKey::X25519AeadEidos(_) => IesScheme::X25519AeadEidos,
234            SealingKey::Ecgfp5Eidos(_) => IesScheme::Ecgfp5Eidos,
235        }
236    }
237
238    /// Seals the provided plaintext (represented as bytes) with this sealing key.
239    ///
240    /// The returned message can be unsealed with the [UnsealingKey] associated with this sealing
241    /// key.
242    pub fn seal_bytes<R: CryptoRng>(
243        &self,
244        rng: &mut R,
245        plaintext: &[u8],
246    ) -> Result<SealedMessage, IesError> {
247        self.seal_bytes_with_associated_data(rng, plaintext, &[])
248    }
249
250    impl_seal_bytes_with_associated_data! {
251        SealingKey::K256XChaCha20Poly1305 => K256XChaCha20Poly1305, EphemeralPublicKey::K256XChaCha20Poly1305;
252        SealingKey::X25519XChaCha20Poly1305 => X25519XChaCha20Poly1305, EphemeralPublicKey::X25519XChaCha20Poly1305;
253        SealingKey::K256AeadEidos => K256AeadEidos, EphemeralPublicKey::K256AeadEidos;
254        SealingKey::X25519AeadEidos => X25519AeadEidos, EphemeralPublicKey::X25519AeadEidos;
255    }
256
257    /// Seals the provided field elements with this sealing key.
258    ///
259    /// The returned message can be unsealed with the [UnsealingKey] associated with this sealing
260    /// key.
261    pub fn seal_elements<R: CryptoRng>(
262        &self,
263        rng: &mut R,
264        plaintext: &[Felt],
265    ) -> Result<SealedMessage, IesError> {
266        self.seal_elements_with_associated_data(rng, plaintext, &[])
267    }
268
269    impl_seal_elements_with_associated_data! {
270        SealingKey::K256XChaCha20Poly1305 => K256XChaCha20Poly1305, EphemeralPublicKey::K256XChaCha20Poly1305;
271        SealingKey::X25519XChaCha20Poly1305 => X25519XChaCha20Poly1305, EphemeralPublicKey::X25519XChaCha20Poly1305;
272        SealingKey::K256AeadEidos => K256AeadEidos, EphemeralPublicKey::K256AeadEidos;
273        SealingKey::X25519AeadEidos => X25519AeadEidos, EphemeralPublicKey::X25519AeadEidos;
274    }
275}
276
277impl fmt::Display for SealingKey {
278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279        write!(f, "{} sealing key", self.scheme())
280    }
281}
282
283impl Serializable for SealingKey {
284    fn write_into<W: ByteWriter>(&self, target: &mut W) {
285        target.write_u8(self.scheme().into());
286
287        match self {
288            SealingKey::K256XChaCha20Poly1305(key) => key.write_into(target),
289            SealingKey::X25519XChaCha20Poly1305(key) => key.write_into(target),
290            SealingKey::K256AeadEidos(key) => key.write_into(target),
291            SealingKey::X25519AeadEidos(key) => key.write_into(target),
292            SealingKey::Ecgfp5Eidos(key) => key.write_into(target),
293        }
294    }
295}
296
297impl Deserializable for SealingKey {
298    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
299        let scheme = IesScheme::try_from(source.read_u8()?)
300            .map_err(|_| DeserializationError::InvalidValue("Unsupported IES scheme".into()))?;
301
302        match scheme {
303            IesScheme::K256XChaCha20Poly1305 => {
304                let key = crate::dsa::ecdsa_k256_keccak::PublicKey::read_from(source)?;
305                Ok(SealingKey::K256XChaCha20Poly1305(key))
306            },
307            IesScheme::X25519XChaCha20Poly1305 => {
308                let key = crate::dsa::eddsa_25519_sha512::PublicKey::read_from(source)?;
309                Ok(SealingKey::X25519XChaCha20Poly1305(key))
310            },
311            IesScheme::K256AeadEidos => {
312                let key = crate::dsa::ecdsa_k256_keccak::PublicKey::read_from(source)?;
313                Ok(SealingKey::K256AeadEidos(key))
314            },
315            IesScheme::X25519AeadEidos => {
316                let key = crate::dsa::eddsa_25519_sha512::PublicKey::read_from(source)?;
317                Ok(SealingKey::X25519AeadEidos(key))
318            },
319            IesScheme::Ecgfp5Eidos => {
320                Ok(SealingKey::Ecgfp5Eidos(ecgfp5::PublicKey::read_from(source)?))
321            },
322        }
323    }
324}
325
326// UNSEALING KEY
327// ================================================================================================
328
329/// Secret key for unsealing messages.
330pub enum UnsealingKey {
331    K256XChaCha20Poly1305(crate::dsa::ecdsa_k256_keccak::KeyExchangeKey),
332    X25519XChaCha20Poly1305(crate::dsa::eddsa_25519_sha512::KeyExchangeKey),
333    K256AeadEidos(crate::dsa::ecdsa_k256_keccak::KeyExchangeKey),
334    X25519AeadEidos(crate::dsa::eddsa_25519_sha512::KeyExchangeKey),
335    Ecgfp5Eidos(ecgfp5::SecretKey),
336}
337
338impl UnsealingKey {
339    /// Returns scheme identifier for this unsealing key.
340    pub fn scheme(&self) -> IesScheme {
341        match self {
342            UnsealingKey::K256XChaCha20Poly1305(_) => IesScheme::K256XChaCha20Poly1305,
343            UnsealingKey::X25519XChaCha20Poly1305(_) => IesScheme::X25519XChaCha20Poly1305,
344            UnsealingKey::K256AeadEidos(_) => IesScheme::K256AeadEidos,
345            UnsealingKey::X25519AeadEidos(_) => IesScheme::X25519AeadEidos,
346            UnsealingKey::Ecgfp5Eidos(_) => IesScheme::Ecgfp5Eidos,
347        }
348    }
349
350    /// Returns scheme name for this unsealing key.
351    pub fn scheme_name(&self) -> &'static str {
352        self.scheme().name()
353    }
354
355    /// Unseals the provided message using this unsealing key.
356    ///
357    /// The message must have been sealed as bytes (i.e., using `seal_bytes()` or
358    /// `seal_bytes_with_associated_data()` method), otherwise an error will be returned.
359    pub fn unseal_bytes(&self, sealed_message: SealedMessage) -> Result<Vec<u8>, IesError> {
360        self.unseal_bytes_with_associated_data(sealed_message, &[])
361    }
362
363    impl_unseal_bytes_with_associated_data! {
364        UnsealingKey::K256XChaCha20Poly1305 => K256XChaCha20Poly1305, EphemeralPublicKey::K256XChaCha20Poly1305;
365        UnsealingKey::X25519XChaCha20Poly1305 => X25519XChaCha20Poly1305, EphemeralPublicKey::X25519XChaCha20Poly1305;
366        UnsealingKey::K256AeadEidos => K256AeadEidos, EphemeralPublicKey::K256AeadEidos;
367        UnsealingKey::X25519AeadEidos => X25519AeadEidos, EphemeralPublicKey::X25519AeadEidos;
368    }
369
370    /// Unseals the provided message using this unsealing key.
371    ///
372    /// The message must have been sealed as elements (i.e., using `seal_elements()` or
373    /// `seal_elements_with_associated_data()` method), otherwise an error will be returned.
374    pub fn unseal_elements(&self, sealed_message: SealedMessage) -> Result<Vec<Felt>, IesError> {
375        self.unseal_elements_with_associated_data(sealed_message, &[])
376    }
377
378    impl_unseal_elements_with_associated_data! {
379        UnsealingKey::K256XChaCha20Poly1305 => K256XChaCha20Poly1305, EphemeralPublicKey::K256XChaCha20Poly1305;
380        UnsealingKey::X25519XChaCha20Poly1305 => X25519XChaCha20Poly1305, EphemeralPublicKey::X25519XChaCha20Poly1305;
381        UnsealingKey::K256AeadEidos => K256AeadEidos, EphemeralPublicKey::K256AeadEidos;
382        UnsealingKey::X25519AeadEidos => X25519AeadEidos, EphemeralPublicKey::X25519AeadEidos;
383    }
384}
385
386impl fmt::Display for UnsealingKey {
387    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388        write!(f, "{} unsealing key", self.scheme())
389    }
390}
391
392impl Serializable for UnsealingKey {
393    fn write_into<W: ByteWriter>(&self, target: &mut W) {
394        target.write_u8(self.scheme().into());
395
396        match self {
397            UnsealingKey::K256XChaCha20Poly1305(key) => key.write_into(target),
398            UnsealingKey::X25519XChaCha20Poly1305(key) => key.write_into(target),
399            UnsealingKey::K256AeadEidos(key) => key.write_into(target),
400            UnsealingKey::X25519AeadEidos(key) => key.write_into(target),
401            UnsealingKey::Ecgfp5Eidos(key) => key.write_into(target),
402        }
403    }
404}
405
406impl Deserializable for UnsealingKey {
407    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
408        let scheme = IesScheme::try_from(source.read_u8()?)
409            .map_err(|_| DeserializationError::InvalidValue("Unsupported IES scheme".into()))?;
410
411        match scheme {
412            IesScheme::K256XChaCha20Poly1305 => {
413                let key = crate::dsa::ecdsa_k256_keccak::KeyExchangeKey::read_from(source)?;
414                Ok(UnsealingKey::K256XChaCha20Poly1305(key))
415            },
416            IesScheme::X25519XChaCha20Poly1305 => {
417                let key = crate::dsa::eddsa_25519_sha512::KeyExchangeKey::read_from(source)?;
418                Ok(UnsealingKey::X25519XChaCha20Poly1305(key))
419            },
420            IesScheme::K256AeadEidos => {
421                let key = crate::dsa::ecdsa_k256_keccak::KeyExchangeKey::read_from(source)?;
422                Ok(UnsealingKey::K256AeadEidos(key))
423            },
424            IesScheme::X25519AeadEidos => {
425                let key = crate::dsa::eddsa_25519_sha512::KeyExchangeKey::read_from(source)?;
426                Ok(UnsealingKey::X25519AeadEidos(key))
427            },
428            IesScheme::Ecgfp5Eidos => {
429                Ok(UnsealingKey::Ecgfp5Eidos(ecgfp5::SecretKey::read_from(source)?))
430            },
431        }
432    }
433}
434
435// EPHEMERAL PUBLIC KEY
436// ================================================================================================
437
438/// Ephemeral public key, part of sealed messages
439#[derive(Debug, Clone, PartialEq, Eq)]
440pub(super) enum EphemeralPublicKey {
441    K256XChaCha20Poly1305(crate::ecdh::k256::EphemeralPublicKey),
442    X25519XChaCha20Poly1305(crate::ecdh::x25519::EphemeralPublicKey),
443    K256AeadEidos(crate::ecdh::k256::EphemeralPublicKey),
444    X25519AeadEidos(crate::ecdh::x25519::EphemeralPublicKey),
445    Ecgfp5Eidos(ecgfp5::PublicKey),
446}
447
448impl EphemeralPublicKey {
449    /// Returns the scheme identifier for this ephemeral key.
450    pub fn scheme(&self) -> IesScheme {
451        match self {
452            EphemeralPublicKey::K256XChaCha20Poly1305(_) => IesScheme::K256XChaCha20Poly1305,
453            EphemeralPublicKey::X25519XChaCha20Poly1305(_) => IesScheme::X25519XChaCha20Poly1305,
454            EphemeralPublicKey::K256AeadEidos(_) => IesScheme::K256AeadEidos,
455            EphemeralPublicKey::X25519AeadEidos(_) => IesScheme::X25519AeadEidos,
456            EphemeralPublicKey::Ecgfp5Eidos(_) => IesScheme::Ecgfp5Eidos,
457        }
458    }
459
460    /// Serializes this key to bytes.
461    pub fn to_bytes(&self) -> Vec<u8> {
462        match self {
463            EphemeralPublicKey::K256XChaCha20Poly1305(key) => key.to_bytes(),
464            EphemeralPublicKey::X25519XChaCha20Poly1305(key) => key.to_bytes(),
465            EphemeralPublicKey::K256AeadEidos(key) => key.to_bytes(),
466            EphemeralPublicKey::X25519AeadEidos(key) => key.to_bytes(),
467            EphemeralPublicKey::Ecgfp5Eidos(key) => key.to_bytes().to_vec(),
468        }
469    }
470
471    /// Deserializes an ephemeral key for the specified scheme.
472    pub fn from_bytes(scheme: IesScheme, bytes: &[u8]) -> Result<Self, IesError> {
473        let expected_len = match scheme {
474            IesScheme::K256XChaCha20Poly1305 | IesScheme::K256AeadEidos => K256_PUBLIC_KEY_BYTES,
475            IesScheme::X25519XChaCha20Poly1305 | IesScheme::X25519AeadEidos => {
476                X25519_PUBLIC_KEY_BYTES
477            },
478            IesScheme::Ecgfp5Eidos => 40,
479        };
480
481        if bytes.len() != expected_len {
482            return Err(IesError::EphemeralPublicKeyDeserializationFailed);
483        }
484
485        match scheme {
486            IesScheme::Ecgfp5Eidos => {
487                let bytes = bytes
488                    .try_into()
489                    .map_err(|_| IesError::EphemeralPublicKeyDeserializationFailed)?;
490                let key = ecgfp5::PublicKey::from_bytes(bytes)
491                    .map_err(|_| IesError::EphemeralPublicKeyDeserializationFailed)?;
492                Ok(EphemeralPublicKey::Ecgfp5Eidos(key))
493            },
494            IesScheme::K256XChaCha20Poly1305 => {
495                let key =
496                    <K256 as KeyAgreementScheme>::EphemeralPublicKey::read_from_bytes_with_budget(
497                        bytes,
498                        expected_len,
499                    )
500                    .map_err(|_| IesError::EphemeralPublicKeyDeserializationFailed)?;
501                Ok(EphemeralPublicKey::K256XChaCha20Poly1305(key))
502            },
503            IesScheme::K256AeadEidos => {
504                let key =
505                    <K256 as KeyAgreementScheme>::EphemeralPublicKey::read_from_bytes_with_budget(
506                        bytes,
507                        expected_len,
508                    )
509                    .map_err(|_| IesError::EphemeralPublicKeyDeserializationFailed)?;
510                Ok(EphemeralPublicKey::K256AeadEidos(key))
511            },
512            IesScheme::X25519XChaCha20Poly1305 => {
513                let key =
514                    <X25519 as KeyAgreementScheme>::EphemeralPublicKey::read_from_bytes_with_budget(
515                        bytes,
516                        expected_len,
517                    )
518                        .map_err(|_| IesError::EphemeralPublicKeyDeserializationFailed)?;
519                Ok(EphemeralPublicKey::X25519XChaCha20Poly1305(key))
520            },
521            IesScheme::X25519AeadEidos => {
522                let key =
523                    <X25519 as KeyAgreementScheme>::EphemeralPublicKey::read_from_bytes_with_budget(
524                        bytes,
525                        expected_len,
526                    )
527                        .map_err(|_| IesError::EphemeralPublicKeyDeserializationFailed)?;
528                Ok(EphemeralPublicKey::X25519AeadEidos(key))
529            },
530        }
531    }
532}
533
534// ARBITRARY (proptest)
535// ================================================================================================
536
537#[cfg(any(test, feature = "arbitrary"))]
538mod key_arbitrary {
539    use proptest::prelude::*;
540    use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
541
542    use super::{EphemeralPublicKey, SealingKey};
543    use crate::dsa::{
544        ecdsa_k256_keccak::KeyExchangeKey as K256KeyExchangeKey,
545        eddsa_25519_sha512::PublicKey as Ed25519PublicKey,
546    };
547
548    fn seed32(a: u64) -> [u8; 32] {
549        let mut seed = [0u8; 32];
550        seed[..8].copy_from_slice(&a.to_be_bytes());
551        seed
552    }
553
554    fn k256_key_exchange_key(seed: [u8; 32]) -> K256KeyExchangeKey {
555        let mut rng = ChaCha20Rng::from_seed(seed);
556        K256KeyExchangeKey::with_rng(&mut rng)
557    }
558
559    fn k256_public_key(seed: [u8; 32]) -> crate::dsa::ecdsa_k256_keccak::PublicKey {
560        k256_key_exchange_key(seed).public_key()
561    }
562
563    fn ecgfp5_public_key(seed: [u8; 32]) -> crate::ecdh::ecgfp5::PublicKey {
564        let mut rng = ChaCha20Rng::from_seed(seed);
565        crate::ecdh::ecgfp5::SecretKey::with_rng(&mut rng).public_key()
566    }
567
568    impl Arbitrary for SealingKey {
569        type Parameters = ();
570        type Strategy = BoxedStrategy<Self>;
571
572        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
573            // Derive public keys from valid secrets so they pass point validation on read.
574            prop_oneof![
575                (0u64..)
576                    .prop_map(|a| Self::K256XChaCha20Poly1305(k256_public_key(seed32(a))))
577                    .boxed(),
578                any::<Ed25519PublicKey>().prop_map(Self::X25519XChaCha20Poly1305).boxed(),
579                (0u64..).prop_map(|a| Self::K256AeadEidos(k256_public_key(seed32(a)))).boxed(),
580                any::<Ed25519PublicKey>().prop_map(Self::X25519AeadEidos).boxed(),
581                (0u64..).prop_map(|a| Self::Ecgfp5Eidos(ecgfp5_public_key(seed32(a)))).boxed(),
582            ]
583            .boxed()
584        }
585    }
586
587    impl Arbitrary for EphemeralPublicKey {
588        type Parameters = ();
589        type Strategy = BoxedStrategy<Self>;
590
591        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
592            prop_oneof![
593                any::<crate::ecdh::k256::EphemeralPublicKey>()
594                    .prop_map(Self::K256XChaCha20Poly1305)
595                    .boxed(),
596                any::<crate::ecdh::x25519::EphemeralPublicKey>()
597                    .prop_map(Self::X25519XChaCha20Poly1305)
598                    .boxed(),
599                any::<crate::ecdh::k256::EphemeralPublicKey>()
600                    .prop_map(Self::K256AeadEidos)
601                    .boxed(),
602                any::<crate::ecdh::x25519::EphemeralPublicKey>()
603                    .prop_map(Self::X25519AeadEidos)
604                    .boxed(),
605                (0u64..).prop_map(|a| Self::Ecgfp5Eidos(ecgfp5_public_key(seed32(a)))).boxed(),
606            ]
607            .boxed()
608        }
609    }
610}