solana_keccak_hasher/
lib.rs

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