openvm_keccak256_guest/
lib.rs

1#![no_std]
2
3#[cfg(target_os = "zkvm")]
4extern crate alloc;
5#[cfg(target_os = "zkvm")]
6use openvm_platform::alloc::AlignedBuf;
7
8/// This is custom-0 defined in RISC-V spec document
9pub const OPCODE: u8 = 0x0b;
10pub const KECCAK256_FUNCT3: u8 = 0b100;
11pub const KECCAK256_FUNCT7: u8 = 0;
12
13/// Native hook for keccak256 for use with `alloy-primitives` "native-keccak" feature.
14///
15/// # Safety
16///
17/// The VM accepts the preimage by pointer and length, and writes the
18/// 32-byte hash.
19/// - `bytes` must point to an input buffer at least `len` long.
20/// - `output` must point to a buffer that is at least 32-bytes long.
21///
22/// [`keccak256`]: https://en.wikipedia.org/wiki/SHA-3
23/// [`sha3`]: https://docs.rs/sha3/latest/sha3/
24/// [`tiny_keccak`]: https://docs.rs/tiny-keccak/latest/tiny_keccak/
25#[cfg(target_os = "zkvm")]
26#[inline(always)]
27#[no_mangle]
28pub extern "C" fn native_keccak256(bytes: *const u8, len: usize, output: *mut u8) {
29    // SAFETY: assuming safety assumptions of the inputs, we handle all cases where `bytes` or
30    // `output` are not aligned to 4 bytes.
31    const MIN_ALIGN: usize = 4;
32    unsafe {
33        if bytes as usize % MIN_ALIGN != 0 {
34            let aligned_buff = AlignedBuf::new(bytes, len, MIN_ALIGN);
35            if output as usize % MIN_ALIGN != 0 {
36                let aligned_out = AlignedBuf::uninit(32, MIN_ALIGN);
37                __native_keccak256(aligned_buff.ptr, len, aligned_out.ptr);
38                core::ptr::copy_nonoverlapping(aligned_out.ptr as *const u8, output, 32);
39            } else {
40                __native_keccak256(aligned_buff.ptr, len, output);
41            }
42        } else {
43            if output as usize % MIN_ALIGN != 0 {
44                let aligned_out = AlignedBuf::uninit(32, MIN_ALIGN);
45                __native_keccak256(bytes, len, aligned_out.ptr);
46                core::ptr::copy_nonoverlapping(aligned_out.ptr as *const u8, output, 32);
47            } else {
48                __native_keccak256(bytes, len, output);
49            }
50        };
51    }
52}
53
54/// keccak256 intrinsic binding
55///
56/// # Safety
57///
58/// The VM accepts the preimage by pointer and length, and writes the
59/// 32-byte hash.
60/// - `bytes` must point to an input buffer at least `len` long.
61/// - `output` must point to a buffer that is at least 32-bytes long.
62/// - `bytes` and `output` must be 4-byte aligned.
63#[cfg(target_os = "zkvm")]
64#[inline(always)]
65fn __native_keccak256(bytes: *const u8, len: usize, output: *mut u8) {
66    openvm_platform::custom_insn_r!(
67        opcode = OPCODE,
68        funct3 = KECCAK256_FUNCT3,
69        funct7 = KECCAK256_FUNCT7,
70        rd = In output,
71        rs1 = In bytes,
72        rs2 = In len
73    );
74}