use openmls_traits::{crypto::OpenMlsCrypto, types::CryptoError};
use serde::{Deserialize, Serialize};
use tls_codec::{
Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
VLByteSlice, VLBytes,
};
use super::Ciphersuite;
const KEY_PACKAGE_REF_LABEL: &[u8; 28] = b"MLS 1.0 KeyPackage Reference";
const PROPOSAL_REF_LABEL: &[u8; 26] = b"MLS 1.0 Proposal Reference";
#[derive(
Clone,
Hash,
PartialEq,
Eq,
Serialize,
Ord,
PartialOrd,
Deserialize,
TlsDeserialize,
TlsDeserializeBytes,
TlsSerialize,
TlsSize,
)]
pub struct HashReference {
value: VLBytes,
}
pub type KeyPackageRef = HashReference;
pub type ProposalRef = HashReference;
#[derive(TlsSerialize, TlsSize)]
struct HashReferenceInput<'a> {
label: VLByteSlice<'a>,
value: VLBytes,
}
pub fn make_proposal_ref(
value: &[u8],
ciphersuite: Ciphersuite,
crypto: &impl OpenMlsCrypto,
) -> Result<ProposalRef, CryptoError> {
HashReference::new(value, ciphersuite, crypto, PROPOSAL_REF_LABEL)
}
pub fn make_key_package_ref(
value: &[u8],
ciphersuite: Ciphersuite,
crypto: &impl OpenMlsCrypto,
) -> Result<KeyPackageRef, CryptoError> {
HashReference::new(value, ciphersuite, crypto, KEY_PACKAGE_REF_LABEL)
}
impl HashReference {
pub fn new(
value: &[u8],
ciphersuite: Ciphersuite,
crypto: &impl OpenMlsCrypto,
label: &[u8],
) -> Result<Self, CryptoError> {
let input = HashReferenceInput {
label: VLByteSlice(label),
value: VLBytes::new(value.to_vec()),
};
let payload = input
.tls_serialize_detached()
.map_err(|_| CryptoError::TlsSerializationError)?;
let value = crypto.hash(ciphersuite.hash_algorithm(), &payload)?;
Ok(Self {
value: VLBytes::new(value),
})
}
pub fn as_slice(&self) -> &[u8] {
self.value.as_slice()
}
#[cfg(any(feature = "test-utils", test))]
pub fn from_slice(slice: &[u8]) -> Self {
Self {
value: VLBytes::from(slice),
}
}
}
impl core::fmt::Display for HashReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "HashReference: ")?;
for b in self.value.as_slice() {
write!(f, "{b:02X}")?;
}
Ok(())
}
}
impl core::fmt::Debug for HashReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}