openvm_sha256_guest/
lib.rs

1#![no_std]
2
3#[cfg(target_os = "zkvm")]
4use openvm_platform::alloc::AlignedBuf;
5
6/// This is custom-0 defined in RISC-V spec document
7pub const OPCODE: u8 = 0x0b;
8pub const SHA256_FUNCT3: u8 = 0b100;
9pub const SHA256_FUNCT7: u8 = 0x1;
10
11/// Native hook for sha256
12///
13/// # Safety
14///
15/// The VM accepts the preimage by pointer and length, and writes the
16/// 32-byte hash.
17/// - `bytes` must point to an input buffer at least `len` long.
18/// - `output` must point to a buffer that is at least 32-bytes long.
19///
20/// [`sha2`]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
21#[cfg(target_os = "zkvm")]
22#[inline(always)]
23#[no_mangle]
24pub extern "C" fn zkvm_sha256_impl(bytes: *const u8, len: usize, output: *mut u8) {
25    // SAFETY: assuming safety assumptions of the inputs, we handle all cases where `bytes` or
26    // `output` are not aligned to 4 bytes.
27    // The minimum alignment required for the input and output buffers
28    const MIN_ALIGN: usize = 4;
29    // The preferred alignment for the input buffer, since the input is read in chunks of 16 bytes
30    const INPUT_ALIGN: usize = 16;
31    // The preferred alignment for the output buffer, since the output is written in chunks of 32
32    // bytes
33    const OUTPUT_ALIGN: usize = 32;
34    unsafe {
35        if bytes as usize % MIN_ALIGN != 0 {
36            let aligned_buff = AlignedBuf::new(bytes, len, INPUT_ALIGN);
37            if output as usize % MIN_ALIGN != 0 {
38                let aligned_out = AlignedBuf::uninit(32, OUTPUT_ALIGN);
39                __native_sha256(aligned_buff.ptr, len, aligned_out.ptr);
40                core::ptr::copy_nonoverlapping(aligned_out.ptr as *const u8, output, 32);
41            } else {
42                __native_sha256(aligned_buff.ptr, len, output);
43            }
44        } else {
45            if output as usize % MIN_ALIGN != 0 {
46                let aligned_out = AlignedBuf::uninit(32, OUTPUT_ALIGN);
47                __native_sha256(bytes, len, aligned_out.ptr);
48                core::ptr::copy_nonoverlapping(aligned_out.ptr as *const u8, output, 32);
49            } else {
50                __native_sha256(bytes, len, output);
51            }
52        };
53    }
54}
55
56/// sha256 intrinsic binding
57///
58/// # Safety
59///
60/// The VM accepts the preimage by pointer and length, and writes the
61/// 32-byte hash.
62/// - `bytes` must point to an input buffer at least `len` long.
63/// - `output` must point to a buffer that is at least 32-bytes long.
64/// - `bytes` and `output` must be 4-byte aligned.
65#[cfg(target_os = "zkvm")]
66#[inline(always)]
67fn __native_sha256(bytes: *const u8, len: usize, output: *mut u8) {
68    openvm_platform::custom_insn_r!(opcode = OPCODE, funct3 = SHA256_FUNCT3, funct7 = SHA256_FUNCT7, rd = In output, rs1 = In bytes, rs2 = In len);
69}