Skip to content

Commit 7d2e343

Browse files
Update docs related to SHA-2
1 parent 12bf122 commit 7d2e343

File tree

8 files changed

+65
-63
lines changed

8 files changed

+65
-63
lines changed

docs/vocs/docs/pages/book/acceleration-using-extensions/sha-2.mdx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# SHA-2
22

3-
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, SHA-512, and SHA-384 hash functions.
3+
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.
44

5-
- `zkvm_shaXXX_impl(input: *const u8, len: usize, output: *mut u8)` where XXX is one of `256`, `512`, or `384`. These functions have `C` ABI. They take in a pointer to the input, the length of the input, and a pointer to the output buffer.
5+
We provide the following functions to compute the SHA-2 compression function.
6+
- `zkvm_shaXXX_impl(state: *const u8, input: *const u8, output: *mut u8)` where `XXX` is `256` or `512`. These functions have `C` ABI. 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`). `state` is 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]`.
67

7-
In the external library, you can do the following:
8+
In the external library, you can do something like the following:
89

910
```rust
1011
extern "C" {
@@ -14,11 +15,20 @@ extern "C" {
1415
fn sha256(input: &[u8]) -> [u8; 32] {
1516
#[cfg(target_os = "zkvm")]
1617
{
17-
let mut output = [0u8; 32];
18-
unsafe {
19-
zkvm_sha256_impl(input.as_ptr(), input.len(), output.as_mut_ptr() as *mut u8);
20-
}
21-
output
18+
let mut state = [0u32; 8];
19+
let padded_input = add_padding(input);
20+
padded_input
21+
.chunks_exact(32)
22+
.for_each(|input_block| {
23+
unsafe {
24+
zkvm_sha256_impl(state.as_ptr() as *const u8, input_block.as_ptr(), output.as_mut_ptr() as *mut u8);
25+
}
26+
})
27+
state
28+
.map(|word| word.to_be_bytes())
29+
.collect::<Vec<_>>()
30+
.try_into()
31+
.unwrap()
2232
}
2333
#[cfg(not(target_os = "zkvm"))] {
2434
// Regular SHA-256 implementation

docs/vocs/docs/pages/book/getting-started/introduction.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ OpenVM is an open-source zero-knowledge virtual machine (zkVM) framework focused
1212

1313
- RISC-V support via RV32IM
1414
- A native field arithmetic extension for proof recursion and aggregation
15-
- The Keccak-256, SHA-256, SHA-512, and SHA-384 hash functions
15+
- The Keccak-256, SHA-256 and SHA-512 hash functions
1616
- Int256 arithmetic
1717
- Modular arithmetic over arbitrary fields
1818
- Elliptic curve operations, including multi-scalar multiplication and ECDSA signature verification, including for the secp256k1 and secp256r1 curves

docs/vocs/docs/pages/book/guest-libraries/sha2.mdx

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,30 @@ The OpenVM SHA-2 guest library provides access to a set of accelerated SHA-2 fam
66
- SHA-512
77
- SHA-384
88

9-
Refer [here](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) for more details on the SHA-2 family of hash functions.
10-
11-
For SHA-256, the SHA2 guest library provides two functions for use in your guest code:
12-
- `sha256(input: &[u8]) -> [u8; 32]`: Computes the SHA-256 hash of the input data and returns it as an array of 32 bytes.
13-
- `set_sha256(input: &[u8], output: &mut [u8; 32])`: Sets the output to the SHA-256 hash of the input data into the provided output buffer.
14-
15-
For SHA-512, we provide:
16-
- `sha512(input: &[u8]) -> [u8; 46]`: Computes the SHA-512 hash of the input data and returns it as an array of 64 bytes.
17-
- `set_sha512(input: &[u8], output: &mut [u8; 64])`: Sets the output to the SHA-512 hash of the input data into the provided output buffer.
18-
19-
For SHA-384, we provide:
20-
- `sha384(input: &[u8]) -> [u8; 48]`: Computes the SHA-384 hash of the input data and returns it as an array of 48 bytes.
21-
- `set_sha384(input: &[u8], output: &mut [u8; 48])`: Sets the output to the SHA-384 hash of the input data into the provided output buffer.
22-
23-
See the full example [here](https://github.com/openvm-org/openvm/blob/feat/sha-512-new-execution/examples/sha2/src/main.rs).
24-
9+
Refer to [the FIPS publication](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) for more details on the SHA-2 family of hash functions.
10+
11+
The SHA-2 guest library provides the `Sha256`, `Sha512`, and `Sha384` structs for use in your guest code.
12+
These structs mimic the identically-named structs found in the `sha2` crate, in that they implement the [`sha2::Digest` trait](https://docs.rs/sha2/latest/sha2/trait.Digest.html).
13+
Importantly, the `sha2::Digest` trait has the following methods, which can be used to incrementally hash a stream of bytes.
14+
```Rust
15+
fn update(&mut self, data: impl AsRef<[u8]>);
16+
fn finalize(self) -> GenericArray<u8, Self::OutputSize>;
17+
```
2518
### Example
2619

20+
The following example can be run as guest code or host code (i.e. run in the zkvm or natively).
21+
To run with guest code, use `cargo openvm run`, and for host code use `cargo run`.
22+
The implementations for `Sha256`, `Sha512`, and `Sha384` fall back to using `sha2` when running as host code.
2723
```rust
28-
// [!include ~/snippets/examples/sha2/src/main.rs:imports]
29-
// [!include ~/snippets/examples/sha2/src/main.rs:main]
24+
[!include ~/snippets/examples/sha2/src/main.rs:imports]
25+
[!include ~/snippets/examples/sha2/src/main.rs:main]
3026
```
3127

3228
To be able to import the `shaXXX` functions and run the example, add the following to your `Cargo.toml` file:
3329

3430
```toml
35-
openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v1.4.1" }
36-
hex = { version = "0.4.3" }
31+
openvm = { git = "https://github.com/openvm-org/openvm.git" }
32+
openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git" }
3733
```
3834

3935
### Config parameters

docs/vocs/docs/pages/specs/openvm/isa.mdx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This specification describes the overall architecture and default VM extensions
66
- [RV32IM](#rv32im-extension): An extension supporting the 32-bit RISC-V ISA with multiplication.
77
- [Native](#native-extension): An extension supporting native field arithmetic for proof recursion and aggregation.
88
- [Keccak-256](#keccak-extension): An extension implementing the Keccak-256 hash function compatibly with RISC-V memory.
9-
- [SHA2](#sha-2-extension): An extension implementing the SHA-256, SHA-512, and SHA-384 hash functions compatibly with RISC-V memory.
9+
- [SHA2](#sha-2-extension): An extension implementing the SHA-256 and SHA-512 hash functions compatibly with RISC-V memory.
1010
- [BigInt](#bigint-extension): An extension supporting 256-bit signed and unsigned integer arithmetic, including
1111
multiplication. This extension respects the RISC-V memory format.
1212
- [Algebra](#algebra-extension): An extension supporting modular arithmetic over arbitrary fields and their complex
@@ -557,9 +557,8 @@ meaning all memory cells are constrained to be bytes.
557557

558558
| Name | Operands | Description |
559559
| ----------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
560-
| SHA256_RV32 | `a,b,c,1,2` | `[r32{0}(a):32]_2 = sha256([r32{0}(b)..r32{0}(b)+r32{0}(c)]_2)`. Does the necessary padding. Performs memory reads with block size `16` and writes with block size `32`. |
561-
| SHA512_RV32 | `a,b,c,1,2` | `[r32{0}(a):64]_2 = sha512([r32{0}(b)..r32{0}(b)+r32{0}(c)]_2)`. Does the necessary padding. Performs memory reads with block size `32` and writes with block size `32`. |
562-
| SHA384_RV32 | `a,b,c,1,2` | `[r32{0}(a):64]_2 = sha384([r32{0}(b)..r32{0}(b)+r32{0}(c)]_2)`. Does the necessary padding. Performs memory reads with block size `32` and writes with block size `32`. Writes 64 bytes to memory: the first 48 are the SHA-384 digest and the last 16 are zeros. |
560+
| SHA256_UPDATE_RV32 | `a,b,c,1,2` | `[r32{0}(a):32]_2 = compress256([r32{0}(b):32]_2, [r32{0}(c):64]_2)`. where `compress256(state, input)` is the SHA-256 block compression function which returns the updated state. This instruction performs memory reads and writes with block size `4`. |
561+
| SHA512_UPDATE_RV32 | `a,b,c,1,2` | `[r32{0}(a):64]_2 = compress512([r32{0}(b):64]_2, [r32{0}(c):128]_2)`. where `compress512(state, input)` is the SHA-512 block compression function which returns the updated state. This instruction performs memory reads and writes with block size `4`. |
563562

564563
### BigInt Extension
565564

docs/vocs/docs/pages/specs/reference/instruction-reference.mdx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,10 @@ In the tables below, we provide the mapping between the `LocalOpcode` and `Phant
134134

135135
#### Instructions
136136

137-
| VM Extension | `LocalOpcode` | ISA Instruction |
138-
| ------------- | ---------- | ------------- |
139-
| SHA-2 | `Rv32Sha2Opcode::SHA256` | SHA256_RV32 |
140-
| SHA-2 | `Rv32Sha2Opcode::SHA512` | SHA512_RV32 |
141-
| SHA-2 | `Rv32Sha2Opcode::SHA384` | SHA384_RV32 |
137+
| VM Extension | `LocalOpcode` | ISA Instruction |
138+
| ------------- | ------------------------ | ------------------------ |
139+
| SHA-2 | `Rv32Sha2Opcode::SHA256` | SHA256_UPDATE_RV32 |
140+
| SHA-2 | `Rv32Sha2Opcode::SHA512` | SHA512_UPDATE_RV32 |
142141

143142
## BigInt Extension
144143

docs/vocs/docs/pages/specs/reference/riscv-custom-code.mdx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ The default VM extensions that support transpilation are:
55

66
- [RV32IM](#rv32im-extension): An extension supporting the 32-bit RISC-V ISA with multiplication.
77
- [Keccak-256](#keccak-extension): An extension implementing the Keccak-256 hash function compatibly with RISC-V memory.
8-
- [SHA2](#sha-2-extension): An extension implementing the SHA-256, SHA-512, and SHA-384 hash functions compatibly with RISC-V memory.
8+
- [SHA2](#sha-2-extension): An extension implementing the SHA-256 and SHA-512 hash functions compatibly with RISC-V memory.
99
- [BigInt](#bigint-extension): An extension supporting 256-bit signed and unsigned integer arithmetic, including multiplication. This extension respects the RISC-V memory format.
1010
- [Algebra](#algebra-extension): An extension supporting modular arithmetic over arbitrary fields and their complex field extensions. This extension respects the RISC-V memory format.
1111
- [Elliptic curve](#elliptic-curve-extension): An extension for elliptic curve operations over Weierstrass curves, including addition and doubling. This can be used to implement multi-scalar multiplication and ECDSA scalar multiplication. This extension respects the RISC-V memory format.
@@ -87,11 +87,10 @@ implementation is here. But we use `funct3 = 111` because the native extension h
8787

8888
## SHA-2 Extension
8989

90-
| RISC-V Inst | FMT | opcode[6:0] | funct3 | funct7 | RISC-V description and notes |
91-
| ----------- | --- | ----------- | ------ | ------ | ---------------------------------------- |
92-
| sha256 | R | 0001011 | 100 | 0x1 | `[rd:32]_2 = sha256([rs1..rs1 + rs2]_2)` |
93-
| sha512 | R | 0001011 | 100 | 0x2 | `[rd:64]_2 = sha512([rs1..rs1 + rs2]_2)` |
94-
| sha384 | R | 0001011 | 100 | 0x3 | `[rd:64]_2 = sha384([rs1..rs1 + rs2]_2)`. Last 16 bytes will be set to zeros. |
90+
| RISC-V Inst | FMT | opcode[6:0] | funct3 | funct7 | RISC-V description and notes |
91+
| ------------- | --- | ----------- | ------ | ------ | -------------------------------------------------- |
92+
| sha256_update | R | 0001011 | 100 | 0x1 | `[rd:32]_2 = compress256([rs1:32]_2, [rs2:64]_2)` |
93+
| sha512_update | R | 0001011 | 100 | 0x2 | `[rd:64]_2 = compress512([rs1:64]_2, [rs2:128]_2)` |
9594

9695
## BigInt Extension
9796

docs/vocs/docs/pages/specs/reference/transpiler.mdx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,10 @@ Each VM extension's behavior is specified below.
153153

154154
### SHA-2 Extension
155155

156-
| RISC-V Inst | OpenVM Instruction |
157-
| ----------- | ----------------------------------------------- |
158-
| sha256 | SHA256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
159-
| sha512 | SHA512_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
160-
| sha384 | SHA384_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
156+
| RISC-V Inst | OpenVM Instruction |
157+
| ------------- | ------------------------------------------------------ |
158+
| sha256_update | SHA256_UPDATE_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
159+
| sha512_update | SHA512_UPDATE_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
161160

162161
### BigInt Extension
163162

extensions/sha2/guest/src/lib.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub enum Sha2BaseFunct7 {
2121
///
2222
/// The VM accepts the previous hash state and the next block of input, and writes the
2323
/// new hash state.
24-
/// - `prev_state` must point to a buffer of at least 32 bytes, storing the previous hash state as 8
24+
/// - `state` must point to a buffer of at least 32 bytes, storing the previous hash state as 8
2525
/// 32-bit words in little-endian order
2626
/// - `input` must point to a buffer of at least 64 bytes
2727
/// - `output` must point to a buffer of at least 32 bytes. It will be filled with the new hash
@@ -31,21 +31,21 @@ pub enum Sha2BaseFunct7 {
3131
#[cfg(target_os = "zkvm")]
3232
#[inline(always)]
3333
#[no_mangle]
34-
pub extern "C" fn zkvm_sha256_impl(prev_state: *const u8, input: *const u8, output: *mut u8) {
34+
pub extern "C" fn zkvm_sha256_impl(state: *const u8, input: *const u8, output: *mut u8) {
3535
// SAFETY: we handle all cases where `prev_state`, `input`, or `output` are not aligned to 4
3636
// bytes.
3737

3838
// The minimum alignment required for the buffers
3939
const MIN_ALIGN: usize = 4;
4040
unsafe {
41-
let prev_state_is_aligned = prev_state as usize % MIN_ALIGN == 0;
41+
let state_is_aligned = state as usize % MIN_ALIGN == 0;
4242
let input_is_aligned = input as usize % MIN_ALIGN == 0;
4343
let output_is_aligned = output as usize % MIN_ALIGN == 0;
4444

45-
let prev_state_ptr = if prev_state_is_aligned {
46-
prev_state
45+
let state_ptr = if state_is_aligned {
46+
state
4747
} else {
48-
AlignedBuf::new(prev_state, 32, MIN_ALIGN).ptr
48+
AlignedBuf::new(state, 32, MIN_ALIGN).ptr
4949
};
5050

5151
let input_ptr = if input_is_aligned {
@@ -60,7 +60,7 @@ pub extern "C" fn zkvm_sha256_impl(prev_state: *const u8, input: *const u8, outp
6060
AlignedBuf::uninit(32, MIN_ALIGN).ptr
6161
};
6262

63-
__native_sha256_compress(prev_state_ptr, input_ptr, output_ptr);
63+
__native_sha256_compress(state_ptr, input_ptr, output_ptr);
6464

6565
if !output_is_aligned {
6666
core::ptr::copy_nonoverlapping(output_ptr, output, 32);
@@ -73,7 +73,7 @@ pub extern "C" fn zkvm_sha256_impl(prev_state: *const u8, input: *const u8, outp
7373
///
7474
/// The VM accepts the previous hash state and the next block of input, and writes the
7575
/// new hash state.
76-
/// - `prev_state` must point to a buffer of at least 64 bytes, storing the previous hash state as 8
76+
/// - `state` must point to a buffer of at least 64 bytes, storing the previous hash state as 8
7777
/// 64-bit words in little-endian order
7878
/// - `input` must point to a buffer of at least 128 bytes
7979
/// - `output` must point to a buffer of at least 64 bytes. It will be filled with the new hash
@@ -83,21 +83,21 @@ pub extern "C" fn zkvm_sha256_impl(prev_state: *const u8, input: *const u8, outp
8383
#[cfg(target_os = "zkvm")]
8484
#[inline(always)]
8585
#[no_mangle]
86-
pub extern "C" fn zkvm_sha512_impl(prev_state: *const u8, input: *const u8, output: *mut u8) {
86+
pub extern "C" fn zkvm_sha512_impl(state: *const u8, input: *const u8, output: *mut u8) {
8787
// SAFETY: we handle all cases where `prev_state`, `input`, or `output` are not aligned to 4
8888
// bytes.
8989

9090
// The minimum alignment required for the buffers
9191
const MIN_ALIGN: usize = 4;
9292
unsafe {
93-
let prev_state_is_aligned = prev_state as usize % MIN_ALIGN == 0;
93+
let state_is_aligned = state as usize % MIN_ALIGN == 0;
9494
let input_is_aligned = input as usize % MIN_ALIGN == 0;
9595
let output_is_aligned = output as usize % MIN_ALIGN == 0;
9696

97-
let prev_state_ptr = if prev_state_is_aligned {
98-
prev_state
97+
let state_ptr = if state_is_aligned {
98+
state
9999
} else {
100-
AlignedBuf::new(prev_state, 64, MIN_ALIGN).ptr
100+
AlignedBuf::new(state, 64, MIN_ALIGN).ptr
101101
};
102102

103103
let input_ptr = if input_is_aligned {
@@ -112,7 +112,7 @@ pub extern "C" fn zkvm_sha512_impl(prev_state: *const u8, input: *const u8, outp
112112
AlignedBuf::uninit(64, MIN_ALIGN).ptr
113113
};
114114

115-
__native_sha512_compress(prev_state_ptr, input_ptr, output_ptr);
115+
__native_sha512_compress(state_ptr, input_ptr, output_ptr);
116116

117117
if !output_is_aligned {
118118
core::ptr::copy_nonoverlapping(output_ptr, output, 64);

0 commit comments

Comments
 (0)