light_hasher/
sha256.rs

1use crate::{
2    errors::HasherError,
3    zero_bytes::{sha256::ZERO_BYTES, ZeroBytes},
4    zero_indexed_leaf::sha256::ZERO_INDEXED_LEAF,
5    Hash, Hasher,
6};
7
8/// Compile-time assertion trait that ensures a generic Hasher type is SHA256.
9/// Used by LightHasherSha macro to enforce SHA256-only implementation at compile time.
10pub trait RequireSha256: Hasher {
11    const ASSERT: () = assert!(
12        Self::ID == 1,
13        "DataHasher for LightHasherSha only works with SHA256 (ID=1). Example: your_struct.hash::<Sha256>()?"
14    );
15}
16
17impl<T: Hasher> RequireSha256 for T {}
18
19#[derive(Clone, Copy)] // To allow using with zero copy Solana accounts.
20pub struct Sha256;
21
22impl Hasher for Sha256 {
23    const ID: u8 = 1;
24    fn hash(val: &[u8]) -> Result<Hash, HasherError> {
25        Self::hashv(&[val])
26    }
27
28    fn hashv(_vals: &[&[u8]]) -> Result<Hash, HasherError> {
29        #[cfg(all(not(target_os = "solana"), feature = "sha256"))]
30        {
31            use sha2::{Digest, Sha256};
32
33            let mut hasher = Sha256::default();
34            for val in _vals {
35                hasher.update(val);
36            }
37            Ok(hasher.finalize().into())
38        }
39        #[cfg(all(not(target_os = "solana"), not(feature = "sha256")))]
40        {
41            Err(HasherError::Sha256FeatureNotEnabled)
42        }
43        // Call via a system call to perform the calculation
44        #[cfg(target_os = "solana")]
45        {
46            use crate::HASH_BYTES;
47
48            let mut hash_result = [0; HASH_BYTES];
49            unsafe {
50                crate::syscalls::sol_sha256(
51                    _vals as *const _ as *const u8,
52                    _vals.len() as u64,
53                    &mut hash_result as *mut _ as *mut u8,
54                );
55            }
56            Ok(hash_result)
57        }
58    }
59
60    fn zero_bytes() -> ZeroBytes {
61        ZERO_BYTES
62    }
63
64    fn zero_indexed_leaf() -> [u8; 32] {
65        ZERO_INDEXED_LEAF
66    }
67}
68
69/// SHA256 hasher that sets byte 0 to zero after hashing.
70/// Used for big-endian compatibility with BN254 field size.
71#[derive(Clone, Copy)]
72pub struct Sha256BE;
73
74impl Hasher for Sha256BE {
75    const ID: u8 = 3;
76
77    fn hash(val: &[u8]) -> Result<Hash, HasherError> {
78        let mut result = Sha256::hash(val)?;
79        result[0] = 0;
80        Ok(result)
81    }
82
83    fn hashv(vals: &[&[u8]]) -> Result<Hash, HasherError> {
84        let mut result = Sha256::hashv(vals)?;
85        result[0] = 0;
86        Ok(result)
87    }
88
89    fn zero_bytes() -> ZeroBytes {
90        ZERO_BYTES
91    }
92
93    fn zero_indexed_leaf() -> [u8; 32] {
94        ZERO_INDEXED_LEAF
95    }
96}