SHA-2
The SHA-2 extension guest provides functions that are meant to be linked to other external libraries. The external libraries can use these functions as a hook for SHA-2 intrinsics. This is enabled only when the target is zkvm. We support the SHA-256 and SHA-512 hash functions.
We provide the following functions to compute the SHA-2 compression function.
unsafe extern "C" fn zkvm_shaXXX_impl(state: *const u8, input: *const u8, output: *mut u8)whereXXXis256or512. These functions haveCABI. They take in a pointer to the current hasher state (state), a pointer to the next block of the message (input), and a pointer where the new hasher state will be written (output).stateis expected to be a pointer to 8 little-endian words, even though its type is*const u8. For Sha256 that means it is a pointer to[u32; 8], and for Sha512 it's[u64; 8].
In the external library, you can do something like the following:
unsafe extern "C" {
unsafe fn zkvm_sha256_impl(state: *const u8, input: *const u8, output: *mut u8);
}
fn sha256(input: &[u8]) -> [u8; 32] {
#[cfg(target_os = "zkvm")]
{
let mut state = [
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19,
];
let padded_input = add_padding(input);
for input_block in padded_input.chunks_exact(64) {
let mut output = [0u32; 8];
unsafe {
zkvm_sha256_impl(
state.as_ptr() as *const u8,
input_block.as_ptr(),
output.as_mut_ptr() as *mut u8,
);
}
state = output;
}
let mut digest = [0u8; 32];
for (i, word) in state.iter().enumerate() {
digest[i * 4..(i + 1) * 4].copy_from_slice(&word.to_be_bytes());
}
digest
}
#[cfg(not(target_os = "zkvm"))] {
unimplemented!("native sha256 is only available on zkvm target")
}
}Here, add_padding applies the standard SHA-2 padding (append a 1 bit, pad with 0 bits, then append the message length) so the input is a multiple of the block size, since zkvm_shaXXX_impl only operates on full blocks.
Config parameters
For the guest program to build successfully add the following to your .toml file:
[app_vm_config.sha2]