Skip to main content

core_crypto_keystore/
hash.rs

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