use hopper_runtime::error::ProgramError;
#[inline]
pub fn verify_merkle_proof(
root: &[u8; 32],
leaf: &[u8; 32],
proof: &[[u8; 32]],
) -> Result<(), ProgramError> {
let mut computed = *leaf;
for sibling in proof {
computed = hash_sorted_pair(&computed, sibling);
}
if computed != *root {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}
#[inline(always)]
pub fn sha256_leaf(data: &[u8]) -> [u8; 32] {
let prefix = [0x00u8];
sha256_two_slices(&prefix, data)
}
#[inline(always)]
fn hash_sorted_pair(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
let prefix = [0x01u8];
if a <= b {
sha256_three_slices(&prefix, a, b)
} else {
sha256_three_slices(&prefix, b, a)
}
}
#[inline(always)]
fn sha256_two_slices(a: &[u8], b: &[u8]) -> [u8; 32] {
#[cfg(target_os = "solana")]
{
use core::mem::MaybeUninit;
let slices: [&[u8]; 2] = [a, b];
let mut result = MaybeUninit::<[u8; 32]>::uninit();
unsafe {
hopper_runtime::syscalls::sol_sha256(
slices.as_ptr() as *const u8,
2u64,
result.as_mut_ptr() as *mut u8,
);
result.assume_init()
}
}
#[cfg(not(target_os = "solana"))]
{
let _ = (a, b);
unreachable!("sol_sha256 is only available on target `solana`");
}
}
#[inline(always)]
fn sha256_three_slices(a: &[u8], b: &[u8], c: &[u8]) -> [u8; 32] {
#[cfg(target_os = "solana")]
{
use core::mem::MaybeUninit;
let slices: [&[u8]; 3] = [a, b, c];
let mut result = MaybeUninit::<[u8; 32]>::uninit();
unsafe {
hopper_runtime::syscalls::sol_sha256(
slices.as_ptr() as *const u8,
3u64,
result.as_mut_ptr() as *mut u8,
);
result.assume_init()
}
}
#[cfg(not(target_os = "solana"))]
{
let _ = (a, b, c);
unreachable!("sol_sha256 is only available on target `solana`");
}
}