solana_nostd_blake3/
lib.rs

1use core::mem::MaybeUninit;
2
3#[cfg(not(target_os = "solana"))]
4use blake3::Hasher;
5
6pub const HASH_LENGTH: usize = 32;
7
8#[cfg(target_os = "solana")]
9extern "C" {
10    fn sol_blake3(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64;
11}
12
13#[cfg_attr(target_os = "solana", inline(always))]
14pub fn hash(data: &[u8]) -> [u8;HASH_LENGTH] {
15    hashv(&[data])
16}
17
18#[inline(always)]
19pub fn hash_ref<T: AsRef<[u8]>>(data: T) -> [u8;HASH_LENGTH] {
20    hashv(&[data.as_ref()])
21}
22
23#[cfg(not(target_os = "solana"))]
24pub fn hashv(data: &[&[u8]]) -> [u8; HASH_LENGTH] {
25    let mut out = MaybeUninit::<[u8; HASH_LENGTH]>::uninit();
26    unsafe {
27        hash_into(data, out.assume_init_mut());
28        out.assume_init()
29    }
30}
31
32#[cfg(target_os = "solana")]
33#[inline(always)]
34pub fn hashv(data: &[&[u8]]) -> [u8; HASH_LENGTH] {
35    let mut out = MaybeUninit::<[u8; HASH_LENGTH]>::uninit();
36    unsafe {
37        hash_into(data, out.as_mut_ptr());
38        out.assume_init()
39    }
40}
41
42#[cfg(not(target_os = "solana"))]
43pub fn hash_into(data: &[&[u8]], out: &mut [u8; HASH_LENGTH]) {
44    let mut hasher = Hasher::new();
45    for item in data {
46        hasher.update(item);
47    }
48    hasher.finalize_xof().fill(out);
49}
50
51#[cfg(target_os = "solana")]
52#[inline(always)]
53pub fn hash_into(data: &[&[u8]], out: *mut [u8; 32]) {
54    unsafe {
55        sol_blake3(
56            data as *const _ as *const u8,
57            data.len() as u64,
58            out as *mut u8,
59        );
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use crate::*;
66
67    #[test]
68    fn test_hash() {
69        let h = hash_ref("test");
70        let h2 = hashv(&[b"test".as_ref()]);
71        assert_eq!(h, h2);
72        assert_eq!(h2, [0x48, 0x78, 0xca, 0x04, 0x25, 0xc7, 0x39, 0xfa, 0x42, 0x7f, 0x7e, 0xda, 0x20, 0xfe, 0x84, 0x5f, 0x6b, 0x2e, 0x46, 0xba, 0x5f, 0xe2, 0xa1, 0x4d, 0xf5, 0xb1, 0xe3, 0x2f, 0x50, 0x60, 0x32, 0x15]);
73    }
74}