openmls/ciphersuite/
hash_ref.rs1use openmls_traits::{crypto::OpenMlsCrypto, types::CryptoError};
30use serde::{Deserialize, Serialize};
31use tls_codec::{
32    Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
33    VLByteSlice, VLBytes,
34};
35
36use super::Ciphersuite;
37
38const KEY_PACKAGE_REF_LABEL: &[u8; 28] = b"MLS 1.0 KeyPackage Reference";
39const PROPOSAL_REF_LABEL: &[u8; 26] = b"MLS 1.0 Proposal Reference";
40
41#[derive(
43    Clone,
44    Hash,
45    PartialEq,
46    Eq,
47    Serialize,
48    Ord,
49    PartialOrd,
50    Deserialize,
51    TlsDeserialize,
52    TlsDeserializeBytes,
53    TlsSerialize,
54    TlsSize,
55)]
56pub struct HashReference {
57    value: VLBytes,
58}
59
60pub type KeyPackageRef = HashReference;
63
64pub type ProposalRef = HashReference;
67
68#[derive(TlsSerialize, TlsSize)]
69struct HashReferenceInput<'a> {
70    label: VLByteSlice<'a>,
71    value: VLBytes,
72}
73
74pub fn make_proposal_ref(
76    value: &[u8],
77    ciphersuite: Ciphersuite,
78    crypto: &impl OpenMlsCrypto,
79) -> Result<ProposalRef, CryptoError> {
80    HashReference::new(value, ciphersuite, crypto, PROPOSAL_REF_LABEL)
81}
82
83pub fn make_key_package_ref(
85    value: &[u8],
86    ciphersuite: Ciphersuite,
87    crypto: &impl OpenMlsCrypto,
88) -> Result<KeyPackageRef, CryptoError> {
89    HashReference::new(value, ciphersuite, crypto, KEY_PACKAGE_REF_LABEL)
90}
91
92impl HashReference {
93    pub fn new(
95        value: &[u8],
96        ciphersuite: Ciphersuite,
97        crypto: &impl OpenMlsCrypto,
98        label: &[u8],
99    ) -> Result<Self, CryptoError> {
100        let input = HashReferenceInput {
101            label: VLByteSlice(label),
102            value: VLBytes::new(value.to_vec()),
103        };
104        let payload = input
105            .tls_serialize_detached()
106            .map_err(|_| CryptoError::TlsSerializationError)?;
107        let value = crypto.hash(ciphersuite.hash_algorithm(), &payload)?;
108        Ok(Self {
109            value: VLBytes::new(value),
110        })
111    }
112
113    pub fn as_slice(&self) -> &[u8] {
115        self.value.as_slice()
116    }
117
118    #[cfg(any(feature = "test-utils", test))]
119    pub fn from_slice(slice: &[u8]) -> Self {
120        Self {
121            value: VLBytes::from(slice),
122        }
123    }
124}
125
126impl core::fmt::Display for HashReference {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        write!(f, "HashReference: ")?;
129        for b in self.value.as_slice() {
130            write!(f, "{b:02X}")?;
131        }
132        Ok(())
133    }
134}
135
136impl core::fmt::Debug for HashReference {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        write!(f, "{self}")
139    }
140}