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    /// How many bytes are in this hash.
40    pub const BYTES: usize = 32;
41
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 rusqlite::ToSql for Sha256Hash {
79    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
80        self.as_ref().to_sql()
81    }
82}
83
84impl rusqlite::types::FromSql for Sha256Hash {
85    fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
86        <[u8; 32]>::column_result(value).map(Self)
87    }
88}