// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright by contributors to this project. // SPDX-License-Identifier: (Apache-2.0 OR MIT) #[cfg(feature = "psk")] use crate::psk::PreSharedKey; #[cfg(any(feature = "secret_tree_access", feature = "private_message"))] use crate::tree_kem::node::NodeIndex; #[cfg(feature = "prior_epoch")] use crate::{crypto::SignaturePublicKey, group::GroupContext, tree_kem::node::LeafIndex}; use alloc::vec::Vec; use core::{ fmt::{self, Debug}, ops::Deref, }; use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize}; use zeroize::Zeroizing; #[cfg(all(feature = "prior_epoch", feature = "private_message"))] use super::ciphertext_processor::GroupStateProvider; #[cfg(any(feature = "secret_tree_access", feature = "private_message"))] use crate::group::secret_tree::SecretTree; #[cfg(feature = "prior_epoch")] #[derive(Debug, Clone, MlsEncode, MlsDecode, MlsSize, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub(crate) struct PriorEpoch { pub(crate) context: GroupContext, pub(crate) self_index: LeafIndex, pub(crate) secrets: EpochSecrets, pub(crate) signature_public_keys: Vec>, } #[cfg(feature = "prior_epoch")] impl PriorEpoch { #[inline(always)] pub(crate) fn epoch_id(&self) -> u64 { self.context.epoch } #[inline(always)] pub(crate) fn group_id(&self) -> &[u8] { &self.context.group_id } } #[cfg(all(feature = "private_message", feature = "prior_epoch"))] impl GroupStateProvider for PriorEpoch { fn group_context(&self) -> &GroupContext { &self.context } fn self_index(&self) -> LeafIndex { self.self_index } fn epoch_secrets_mut(&mut self) -> &mut EpochSecrets { &mut self.secrets } fn epoch_secrets(&self) -> &EpochSecrets { &self.secrets } } #[derive(Debug, Clone, PartialEq, MlsEncode, MlsDecode, MlsSize)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub(crate) struct EpochSecrets { #[cfg(feature = "psk")] #[mls_codec(with = "mls_rs_codec::byte_vec")] pub(crate) resumption_secret: PreSharedKey, #[mls_codec(with = "mls_rs_codec::byte_vec")] pub(crate) sender_data_secret: SenderDataSecret, #[cfg(any(feature = "secret_tree_access", feature = "private_message"))] pub(crate) secret_tree: SecretTree, } #[derive(Clone, PartialEq, MlsEncode, MlsDecode, MlsSize)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub(crate) struct SenderDataSecret( #[mls_codec(with = "mls_rs_codec::byte_vec")] #[cfg_attr(feature = "serde", serde(with = "mls_rs_core::zeroizing_serde"))] Zeroizing>, ); impl Debug for SenderDataSecret { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { mls_rs_core::debug::pretty_bytes(&self.0) .named("SenderDataSecret") .fmt(f) } } impl AsRef<[u8]> for SenderDataSecret { fn as_ref(&self) -> &[u8] { &self.0 } } impl Deref for SenderDataSecret { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl From> for SenderDataSecret { fn from(bytes: Vec) -> Self { Self(Zeroizing::new(bytes)) } } impl From>> for SenderDataSecret { fn from(bytes: Zeroizing>) -> Self { Self(bytes) } } #[cfg(test)] pub(crate) mod test_utils { use mls_rs_core::crypto::CipherSuiteProvider; use super::*; use crate::cipher_suite::CipherSuite; use crate::crypto::test_utils::test_cipher_suite_provider; #[cfg(any(feature = "secret_tree_access", feature = "private_message"))] use crate::group::secret_tree::test_utils::get_test_tree; #[cfg(feature = "prior_epoch")] use crate::group::test_utils::get_test_group_context_with_id; use crate::group::test_utils::random_bytes; pub(crate) fn get_test_epoch_secrets(cipher_suite: CipherSuite) -> EpochSecrets { let cs_provider = test_cipher_suite_provider(cipher_suite); #[cfg(any(feature = "secret_tree_access", feature = "private_message"))] let secret_tree = get_test_tree(random_bytes(cs_provider.kdf_extract_size()), 2); EpochSecrets { #[cfg(feature = "psk")] resumption_secret: random_bytes(cs_provider.kdf_extract_size()).into(), sender_data_secret: random_bytes(cs_provider.kdf_extract_size()).into(), #[cfg(any(feature = "secret_tree_access", feature = "private_message"))] secret_tree, } } #[cfg(feature = "prior_epoch")] pub(crate) fn get_test_epoch_with_id( group_id: Vec, cipher_suite: CipherSuite, id: u64, ) -> PriorEpoch { PriorEpoch { context: get_test_group_context_with_id(group_id, id, cipher_suite), self_index: LeafIndex(0), secrets: get_test_epoch_secrets(cipher_suite), signature_public_keys: Default::default(), } } }