Skip to main content

core_crypto_keystore/
hash.rs

1use std::fmt;
2
3use sha2::{Digest, Sha256};
4
5use crate::{
6    CryptoKeystoreResult,
7    traits::{KeyType, OwnedKeyType},
8};
9
10/// Used to calculate ID hashes for some MlsEntities' SQLite tables.
11pub(crate) fn sha256(data: &[u8]) -> String {
12    Sha256Hash::hash_from(data).to_string()
13}
14
15/// A Sha256 hash.
16///
17/// Certain entities use this kind of hash as a key. It's a small value which lives on the stack,
18/// as opposed to the longer, heap-allocated values which it replaces.
19///
20/// This type enables this use case with the new entity traits.
21#[derive(
22    Debug,
23    Default,
24    Clone,
25    Copy,
26    PartialEq,
27    Eq,
28    PartialOrd,
29    Ord,
30    Hash,
31    derive_more::Deref,
32    derive_more::AsRef,
33    derive_more::From,
34    derive_more::Into,
35    serde::Serialize,
36    serde::Deserialize,
37)]
38#[as_ref(forward)]
39pub struct Sha256Hash([u8; 32]);
40
41impl Sha256Hash {
42    /// Create an instance by hashing a single input value.
43    pub fn hash_from(input: impl AsRef<[u8]>) -> Self {
44        Self::hash_from_many([input])
45    }
46
47    /// Create an instance by hashing several input values.
48    ///
49    /// Note: for Sha256 hashes, hashing multiple inputs `A`, `B`, `C` in sequence will
50    /// always produce the same output as hashing the concatenation `A || B || C``.
51    pub fn hash_from_many(inputs: impl IntoIterator<Item = impl AsRef<[u8]>>) -> Self {
52        let mut hasher = Sha256::new();
53        for input in inputs {
54            hasher.update(input);
55        }
56        Self(hasher.finalize().into())
57    }
58
59    /// Convert an existing hash into an instance of this type.
60    ///
61    /// Only basic length checking is performed!
62    pub fn from_existing_hash(hash: impl AsRef<[u8]>) -> CryptoKeystoreResult<Self> {
63        let array = hash.as_ref().try_into()?;
64        Ok(Self(array))
65    }
66}
67
68impl fmt::Display for Sha256Hash {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        let mut hex_bytes = [0; 64];
71        hex::encode_to_slice(self.0, hex_bytes.as_mut_slice())
72            .expect("infallible given inputs and outputs of fixed correct length");
73        let hex_str = str::from_utf8(&hex_bytes).expect("hex crate always produces valid utf8 data");
74        write!(f, "{hex_str}")
75    }
76}
77
78impl KeyType for Sha256Hash {
79    fn bytes(&self) -> std::borrow::Cow<'_, [u8]> {
80        (&self.0).into()
81    }
82}
83
84impl OwnedKeyType for Sha256Hash {
85    fn from_bytes(bytes: &[u8]) -> Option<Self> {
86        bytes.try_into().ok().map(Self)
87    }
88}
89
90impl rusqlite::ToSql for Sha256Hash {
91    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
92        self.as_ref().to_sql()
93    }
94}