use crate::syscalls::{syscall_sha256_f, SyscallSha256Params};
use super::is_aligned_8;
const SHA256_INIT: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
pub fn sha256(input: &[u8], #[cfg(feature = "hints")] hints: &mut Vec<u64>) -> [u8; 32] {
let mut state = SHA256_INIT;
let input_len = input.len();
let mut offset = 0;
if is_aligned_8(input.as_ptr()) {
while offset + 64 <= input_len {
let block: &[u8; 64] = input[offset..offset + 64].try_into().unwrap();
compress_block(
&mut state,
block,
#[cfg(feature = "hints")]
hints,
);
offset += 64;
}
} else {
let mut aligned_block = [0u8; 64];
while offset + 64 <= input_len {
aligned_block.copy_from_slice(&input[offset..offset + 64]);
compress_block(
&mut state,
&aligned_block,
#[cfg(feature = "hints")]
hints,
);
offset += 64;
}
}
let remaining = input_len - offset;
let bit_len = (input_len as u64) * 8;
let mut final_block = [0u8; 64];
final_block[..remaining].copy_from_slice(&input[offset..]);
final_block[remaining] = 0x80;
if remaining + 9 > 64 {
compress_block(
&mut state,
&final_block,
#[cfg(feature = "hints")]
hints,
);
final_block = [0u8; 64];
final_block[56..64].copy_from_slice(&bit_len.to_be_bytes());
compress_block(
&mut state,
&final_block,
#[cfg(feature = "hints")]
hints,
);
} else {
final_block[56..64].copy_from_slice(&bit_len.to_be_bytes());
compress_block(
&mut state,
&final_block,
#[cfg(feature = "hints")]
hints,
);
}
let mut result = [0u8; 32];
for (i, &word) in state.iter().enumerate() {
result[i * 4..(i + 1) * 4].copy_from_slice(&word.to_be_bytes());
}
result
}
#[inline]
fn compress_block(
state: &mut [u32; 8],
block: &[u8; 64],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) {
let state_64: &mut [u64; 4] = unsafe { &mut *(state.as_mut_ptr() as *mut [u64; 4]) };
let input_u64: &[u64; 8] = unsafe { &*(block.as_ptr() as *const [u64; 8]) };
let mut sha256_params = SyscallSha256Params { state: state_64, input: input_u64 };
syscall_sha256_f(
&mut sha256_params,
#[cfg(feature = "hints")]
hints,
);
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_sha256f_compress_c")]
pub unsafe extern "C" fn sha256f_compress_c(
state_ptr: *mut u32,
blocks_ptr: *const u8,
num_blocks: usize,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) {
let state: &mut [u32; 8] = &mut *(state_ptr as *mut [u32; 8]);
let mut state_64 = convert_u32_to_u64(state);
for i in 0..num_blocks {
let block: &[u8; 64] = &*(blocks_ptr.add(i * 64) as *const [u8; 64]);
let input_u64 = convert_bytes_to_u64(block);
let mut sha256_params = SyscallSha256Params { state: &mut state_64, input: &input_u64 };
syscall_sha256_f(
&mut sha256_params,
#[cfg(feature = "hints")]
hints,
);
}
*state = convert_u64_to_u32(&state_64);
}
#[inline]
fn convert_u32_to_u64(state: &[u32; 8]) -> [u64; 4] {
unsafe { *(state.as_ptr() as *const [u64; 4]) }
}
#[inline]
fn convert_u64_to_u32(state: &[u64; 4]) -> [u32; 8] {
unsafe { *(state.as_ptr() as *const [u32; 8]) }
}
#[inline]
fn convert_bytes_to_u64(block: &[u8; 64]) -> [u64; 8] {
unsafe { *(block.as_ptr() as *const [u64; 8]) }
}
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn sha256_c(
input: *const u8,
input_len: usize,
output: *mut u8,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) {
let input_slice = core::slice::from_raw_parts(input, input_len);
let hash = sha256(
input_slice,
#[cfg(feature = "hints")]
hints,
);
let output_slice = core::slice::from_raw_parts_mut(output, 32);
output_slice.copy_from_slice(&hash);
}