use crate::error::ProgramError;
pub type Sha256Hash = [u8; 32];
pub type Keccak256Hash = [u8; 32];
pub type Blake3Hash = [u8; 32];
pub const MAX_HASH_SEGMENTS: usize = 16;
#[inline]
#[allow(unused_mut)]
pub fn sha256(inputs: &[&[u8]]) -> Result<Sha256Hash, ProgramError> {
if inputs.len() > MAX_HASH_SEGMENTS {
return Err(ProgramError::InvalidArgument);
}
let mut result = [0u8; 32];
#[cfg(target_os = "solana")]
{
const _: () = assert!(core::mem::size_of::<&[u8]>() == 16);
let rc = unsafe {
crate::syscalls::sol_sha256(
inputs.as_ptr() as *const u8,
inputs.len() as u64,
result.as_mut_ptr(),
)
};
if rc != 0 {
return Err(ProgramError::InvalidArgument);
}
}
#[cfg(not(target_os = "solana"))]
{
let _ = inputs;
}
Ok(result)
}
#[inline]
pub fn sha256_single(input: &[u8]) -> Result<Sha256Hash, ProgramError> {
sha256(&[input])
}
#[inline]
#[allow(unused_mut)]
pub fn keccak256(inputs: &[&[u8]]) -> Result<Keccak256Hash, ProgramError> {
if inputs.len() > MAX_HASH_SEGMENTS {
return Err(ProgramError::InvalidArgument);
}
let mut result = [0u8; 32];
#[cfg(target_os = "solana")]
{
const _: () = assert!(core::mem::size_of::<&[u8]>() == 16);
let rc = unsafe {
crate::syscalls::sol_keccak256(
inputs.as_ptr() as *const u8,
inputs.len() as u64,
result.as_mut_ptr(),
)
};
if rc != 0 {
return Err(ProgramError::InvalidArgument);
}
}
#[cfg(not(target_os = "solana"))]
{
let _ = inputs;
}
Ok(result)
}
#[inline]
pub fn keccak256_single(input: &[u8]) -> Result<Keccak256Hash, ProgramError> {
keccak256(&[input])
}
#[inline]
#[allow(unused_mut)]
pub fn blake3(inputs: &[&[u8]]) -> Result<Blake3Hash, ProgramError> {
if inputs.len() > MAX_HASH_SEGMENTS {
return Err(ProgramError::InvalidArgument);
}
let mut result = [0u8; 32];
#[cfg(target_os = "solana")]
{
const _: () = assert!(core::mem::size_of::<&[u8]>() == 16);
let rc = unsafe {
crate::syscalls::sol_blake3(
inputs.as_ptr() as *const u8,
inputs.len() as u64,
result.as_mut_ptr(),
)
};
if rc != 0 {
return Err(ProgramError::InvalidArgument);
}
}
#[cfg(not(target_os = "solana"))]
{
let _ = inputs;
}
Ok(result)
}
#[inline]
pub fn blake3_single(input: &[u8]) -> Result<Blake3Hash, ProgramError> {
blake3(&[input])
}
#[cfg(test)]
mod tests {
use super::*;
const EMPTY: &[u8] = b"";
#[test]
fn sha256_accepts_sixteen_segments() {
let inputs = [EMPTY; MAX_HASH_SEGMENTS];
assert_eq!(sha256(&inputs), Ok([0; 32]));
}
#[test]
fn keccak256_accepts_sixteen_segments() {
let inputs = [EMPTY; MAX_HASH_SEGMENTS];
assert_eq!(keccak256(&inputs), Ok([0; 32]));
}
#[test]
fn blake3_accepts_sixteen_segments() {
let inputs = [EMPTY; MAX_HASH_SEGMENTS];
assert_eq!(blake3(&inputs), Ok([0; 32]));
}
#[test]
fn sha256_rejects_more_than_sixteen_segments() {
let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
assert_eq!(sha256(&inputs), Err(ProgramError::InvalidArgument));
}
#[test]
fn keccak256_rejects_more_than_sixteen_segments() {
let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
assert_eq!(keccak256(&inputs), Err(ProgramError::InvalidArgument));
}
#[test]
fn blake3_rejects_more_than_sixteen_segments() {
let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
assert_eq!(blake3(&inputs), Err(ProgramError::InvalidArgument));
}
}