openvm_keccak256_guest/
lib.rs1#![no_std]
2
3#[cfg(target_os = "zkvm")]
4use openvm_platform::alloc::AlignedBuf;
5
6pub const OPCODE: u8 = 0x0b;
7pub const KECCAKF_FUNCT3: u8 = 0b100;
8pub const KECCAKF_FUNCT7: u8 = 0;
9pub const XORIN_FUNCT3: u8 = 0b100;
10pub const XORIN_FUNCT7: u8 = 1;
11
12pub const KECCAK_WIDTH_BYTES: usize = 200;
13pub const KECCAK_RATE: usize = 136;
14pub const KECCAK_OUTPUT_SIZE: usize = 32;
15pub const MIN_ALIGN: usize = 4;
16
17#[cfg(target_os = "zkvm")]
29#[no_mangle]
30pub unsafe extern "C" fn native_xorin(buffer: *mut u8, input: *const u8, len: usize) {
31 assert!(
32 len <= KECCAK_RATE,
33 "native_xorin: len exceeds the XORIN circuit's maximum rate of {} bytes",
34 KECCAK_RATE
35 );
36 if len == 0 {
37 return;
38 }
39 unsafe {
40 let buffer_aligned = buffer as usize % MIN_ALIGN == 0;
41 let input_aligned = input as usize % MIN_ALIGN == 0;
42 let len_aligned = len % MIN_ALIGN == 0;
43 let all_aligned = buffer_aligned && input_aligned && len_aligned;
44
45 if all_aligned {
46 __native_xorin(buffer, input, len);
47 } else {
48 let adjusted_len = len.next_multiple_of(MIN_ALIGN);
49 let aligned_buffer;
50 let aligned_input;
51
52 let actual_buffer = if buffer_aligned && len_aligned {
53 buffer
54 } else {
55 aligned_buffer = AlignedBuf::uninit(adjusted_len, MIN_ALIGN);
56 core::ptr::copy_nonoverlapping(buffer, aligned_buffer.ptr, len);
57 aligned_buffer.ptr
58 };
59
60 let actual_input = if input_aligned && len_aligned {
61 input
62 } else {
63 aligned_input = AlignedBuf::uninit(adjusted_len, MIN_ALIGN);
64 core::ptr::copy_nonoverlapping(input, aligned_input.ptr, len);
65 aligned_input.ptr
66 };
67
68 __native_xorin(actual_buffer, actual_input, adjusted_len);
69
70 if !buffer_aligned || !len_aligned {
71 core::ptr::copy_nonoverlapping(actual_buffer as *const u8, buffer, len);
72 }
73 }
74 }
75}
76
77#[cfg(target_os = "zkvm")]
83#[no_mangle]
84pub unsafe extern "C" fn native_keccakf(buffer: *mut u8) {
85 unsafe {
86 if buffer as usize % MIN_ALIGN == 0 {
87 __native_keccakf(buffer);
88 } else {
89 let aligned_buffer = AlignedBuf::new(buffer, KECCAK_WIDTH_BYTES, MIN_ALIGN);
90 __native_keccakf(aligned_buffer.ptr);
91 core::ptr::copy_nonoverlapping(
92 aligned_buffer.ptr as *const u8,
93 buffer,
94 KECCAK_WIDTH_BYTES,
95 );
96 }
97 }
98}
99
100#[cfg(target_os = "zkvm")]
101#[inline(always)]
102fn __native_xorin(mut buffer: *mut u8, input: *const u8, len: usize) {
103 openvm_platform::custom_insn_r!(
104 opcode = OPCODE,
105 funct3 = XORIN_FUNCT3,
106 funct7 = XORIN_FUNCT7,
107 rd = InOut buffer,
108 rs1 = In input,
109 rs2 = In len
110 );
111}
112
113#[cfg(target_os = "zkvm")]
114#[inline(always)]
115fn __native_keccakf(mut buffer: *mut u8) {
116 openvm_platform::custom_insn_r!(
117 opcode = OPCODE,
118 funct3 = KECCAKF_FUNCT3,
119 funct7 = KECCAKF_FUNCT7,
120 rd = InOut buffer,
121 rs1 = Const "x0",
122 rs2 = Const "x0",
123 );
124}