|
1 | 1 | #![no_std]
|
2 | 2 |
|
| 3 | +#[cfg(target_os = "zkvm")] |
| 4 | +use openvm_platform::alloc::AlignedBuf; |
| 5 | + |
3 | 6 | /// This is custom-0 defined in RISC-V spec document
|
4 | 7 | pub const OPCODE: u8 = 0x0b;
|
5 | 8 | pub const SHA256_FUNCT3: u8 = 0b100;
|
6 | 9 | pub const SHA256_FUNCT7: u8 = 0x1;
|
7 | 10 |
|
8 |
| -/// zkvm native implementation of sha256 |
| 11 | +/// Native hook for sha256 |
| 12 | +/// |
9 | 13 | /// # Safety
|
10 | 14 | ///
|
11 | 15 | /// The VM accepts the preimage by pointer and length, and writes the
|
12 | 16 | /// 32-byte hash.
|
13 | 17 | /// - `bytes` must point to an input buffer at least `len` long.
|
14 | 18 | /// - `output` must point to a buffer that is at least 32-bytes long.
|
15 | 19 | ///
|
16 |
| -/// [`sha2-256`]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| 20 | +/// [`sha2`]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
17 | 21 | #[cfg(target_os = "zkvm")]
|
18 | 22 | #[inline(always)]
|
19 | 23 | #[no_mangle]
|
20 | 24 | pub 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)] |
| 67 | +fn __native_sha256(bytes: *const u8, len: usize, output: *mut u8) { |
21 | 68 | openvm_platform::custom_insn_r!(opcode = OPCODE, funct3 = SHA256_FUNCT3, funct7 = SHA256_FUNCT7, rd = In output, rs1 = In bytes, rs2 = In len);
|
22 | 69 | }
|
0 commit comments