solana_sha256_hasher/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4#[cfg(any(target_os = "solana", target_arch = "bpf"))]
5pub use solana_define_syscall::definitions::sol_sha256;
6use solana_hash::Hash;
7#[cfg(any(target_os = "solana", target_arch = "bpf"))]
8use {core::mem::MaybeUninit, solana_hash::HASH_BYTES};
9#[cfg(all(feature = "sha2", not(any(target_os = "solana", target_arch = "bpf"))))]
10use {
11    sha2::{Digest, Sha256},
12    solana_hash::HASH_BYTES,
13};
14
15#[cfg(all(feature = "sha2", not(any(target_os = "solana", target_arch = "bpf"))))]
16#[derive(Clone, Default)]
17pub struct Hasher {
18    hasher: Sha256,
19}
20
21#[cfg(all(feature = "sha2", not(any(target_os = "solana", target_arch = "bpf"))))]
22impl Hasher {
23    #[inline(always)]
24    pub fn hash(&mut self, val: &[u8]) {
25        self.hasher.update(val);
26    }
27
28    #[inline(always)]
29    pub fn hashv(&mut self, vals: &[&[u8]]) {
30        for val in vals {
31            self.hash(val);
32        }
33    }
34
35    #[inline(always)]
36    pub fn result(self) -> Hash {
37        let bytes: [u8; HASH_BYTES] = self.hasher.finalize().into();
38        bytes.into()
39    }
40}
41
42/// Return a Sha256 hash for the given data.
43#[cfg_attr(target_os = "solana", inline(always))]
44pub fn hashv(vals: &[&[u8]]) -> Hash {
45    // Perform the calculation inline, calling this from within a program is
46    // not supported
47    #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
48    {
49        #[cfg(feature = "sha2")]
50        {
51            let mut hasher = Hasher::default();
52            hasher.hashv(vals);
53            hasher.result()
54        }
55        #[cfg(not(feature = "sha2"))]
56        {
57            core::hint::black_box(vals);
58            panic!("hashv is only available on target `solana` or with the `sha2` feature enabled on this crate")
59        }
60    }
61    // Call via a system call to perform the calculation
62    #[cfg(any(target_os = "solana", target_arch = "bpf"))]
63    {
64        let mut hash_result = MaybeUninit::<[u8; HASH_BYTES]>::uninit();
65        // SAFETY: This is sound as sol_sha256 always fills all 32 bytes of our hash
66        unsafe {
67            sol_sha256(
68                vals as *const _ as *const u8,
69                vals.len() as u64,
70                hash_result.as_mut_ptr() as *mut u8,
71            );
72            Hash::new_from_array(hash_result.assume_init())
73        }
74    }
75}
76
77/// Return a Sha256 hash for the given data.
78#[cfg_attr(target_os = "solana", inline(always))]
79pub fn hash(val: &[u8]) -> Hash {
80    hashv(&[val])
81}