Skip to main content

miden_crypto/ies/
message.rs

1use alloc::vec::Vec;
2use core::convert::TryFrom;
3
4use super::{IesScheme, keys::EphemeralPublicKey};
5use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
6
7// SEALED MESSAGE
8// ================================================================================================
9
10/// A sealed message containing encrypted data
11#[derive(Debug, Clone, PartialEq, Eq)]
12#[cfg_attr(
13    all(feature = "arbitrary", test),
14    miden_test_serialization_macros::serialization_test
15)]
16pub struct SealedMessage {
17    /// Ephemeral public key (determines scheme and provides key material)
18    pub(super) ephemeral_key: EphemeralPublicKey,
19    /// Scheme-specific ciphertext encoding, including its authentication tag.
20    pub(super) ciphertext: Vec<u8>,
21}
22
23impl SealedMessage {
24    /// Returns the scheme used to create this sealed message.
25    pub(super) fn scheme(&self) -> IesScheme {
26        self.ephemeral_key.scheme()
27    }
28
29    /// Returns the scheme name used to create this sealed message.
30    pub fn scheme_name(&self) -> &'static str {
31        self.scheme().name()
32    }
33
34    /// Returns the byte representation of this sealed message.
35    pub fn to_bytes(&self) -> Vec<u8> {
36        <Self as Serializable>::to_bytes(self)
37    }
38}
39
40#[cfg(any(test, feature = "arbitrary"))]
41mod sealed_message_arbitrary {
42    use proptest::prelude::*;
43
44    use super::SealedMessage;
45    use crate::ies::keys::EphemeralPublicKey;
46
47    impl Arbitrary for SealedMessage {
48        type Parameters = ();
49        type Strategy = BoxedStrategy<Self>;
50
51        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
52            // The reader re-parses the ephemeral key under the scheme byte, so use a valid
53            // key (its own covered strategy); the ciphertext payload is any-valid bytes.
54            (any::<EphemeralPublicKey>(), proptest::collection::vec(any::<u8>(), 0..=32))
55                .prop_map(|(ephemeral_key, ciphertext)| Self { ephemeral_key, ciphertext })
56                .boxed()
57        }
58    }
59}
60
61impl Serializable for SealedMessage {
62    fn write_into<W: ByteWriter>(&self, target: &mut W) {
63        let scheme = self.scheme();
64        target.write_u8(scheme as u8);
65
66        self.ephemeral_key.to_bytes().write_into(target);
67        self.ciphertext.write_into(target);
68    }
69}
70
71impl Deserializable for SealedMessage {
72    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
73        let scheme = match IesScheme::try_from(source.read_u8()?) {
74            Ok(a) => a,
75            Err(_) => {
76                return Err(DeserializationError::InvalidValue("Unsupported scheme".into()));
77            },
78        };
79
80        let eph_key_bytes = Vec::<u8>::read_from(source)?;
81        let ephemeral_key =
82            EphemeralPublicKey::from_bytes(scheme, &eph_key_bytes).map_err(|e| {
83                DeserializationError::InvalidValue(format!("Invalid ephemeral key: {e}"))
84            })?;
85
86        let ciphertext = Vec::<u8>::read_from(source)?;
87
88        Ok(Self { ephemeral_key, ciphertext })
89    }
90}