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