-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: keccak + bigint guest libraries (#1058)
* feat: keccak + bigint guest libraries * fix: don't use hinting * address review comments
- Loading branch information
1 parent
2c216cd
commit 5b98791
Showing
2 changed files
with
264 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,197 @@ | ||
# OpenVM BigInt | ||
|
||
The OpenVM BigInt extension (aka `Int256`) provides two structs: `U256` and `I256`. These structs can be used to perform 256 bit arithmetic operations. The functional part is provided by the `openvm-bigint-guest` crate, which is a guest library that can be used in any OpenVM program. | ||
|
||
## `U256` | ||
|
||
The `U256` struct is a 256-bit unsigned integer type. | ||
|
||
### Constants | ||
|
||
The `U256` struct has the following constants: | ||
|
||
- `MAX`: The maximum value of a `U256`. | ||
- `MIN`: The minimum value of a `U256`. | ||
- `ZERO`: The zero constant. | ||
|
||
### Constructors | ||
|
||
The `U256` struct implements the following constructors: `from_u8`, `from_u32`, and `from_u64`. | ||
|
||
### Binary Operations | ||
|
||
The `U256` struct implements the following binary operations: `addition`, `subtraction`, `multiplication`, `bitwise and`, `bitwise or`, `bitwise xor`, `bitwise shift right`, and `bitwise shift left`. All operations will wrap the result when the result is outside the range of the `U256` type. | ||
|
||
All of the operations can be used in 6 different ways: | ||
`U256 op U256` or `U256 op &U256` or `&U256 op U256` or `&U256 op &U256` or `U256 op= U256` or `&U256 op= U256`. | ||
|
||
### Other | ||
|
||
When using the `U256` struct with `target_os = "zkvm"`, the struct utilizes efficient implementations of comparison operators as well as the `clone` method. | ||
|
||
### Example matrix multiplication using `U256` | ||
|
||
See the full example [here](https://github.com/openvm-org/openvm/blob/main/crates/toolchain/tests/programs/examples/matrix-power.rs). | ||
|
||
```rust | ||
#![cfg_attr(not(feature = "std"), no_main)] | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
openvm::entry!(main); | ||
use core::array; | ||
use openvm_bigint_guest::U256; | ||
|
||
const N: usize = 16; | ||
type Matrix = [[U256; N]; N]; | ||
|
||
pub fn get_matrix(val: u8) -> Matrix { | ||
array::from_fn(|_| array::from_fn(|_| U256::from_u8(val))) | ||
} | ||
|
||
pub fn mult(a: &Matrix, b: &Matrix) -> Matrix { | ||
let mut c = get_matrix(0); | ||
for i in 0..N { | ||
for j in 0..N { | ||
for k in 0..N { | ||
c[i][j] += &a[i][k] * &b[k][j]; | ||
} | ||
} | ||
} | ||
c | ||
} | ||
|
||
pub fn get_identity_matrix() -> Matrix { | ||
let mut res = get_matrix(0); | ||
for i in 0..N { | ||
res[i][i] = U256::from_u8(1); | ||
} | ||
res | ||
} | ||
|
||
pub fn main() { | ||
let a: Matrix = get_identity_matrix(); | ||
let b: Matrix = get_matrix(28); | ||
let c: Matrix = mult(&a, &b); | ||
assert_eq!(c, b); | ||
} | ||
``` | ||
|
||
## `I256` | ||
|
||
The `I256` struct is a 256-bit signed integer type. The `I256` struct is very similar to the `U256` struct. | ||
|
||
### Constants | ||
|
||
The `I256` struct has the following constants: | ||
|
||
- `MAX`: The maximum value of a `I256`. | ||
- `MIN`: The minimum value of a `I256`. | ||
- `ZERO`: The zero constant. | ||
|
||
### Binary Operations | ||
|
||
The `I256` struct implements the following binary operations: `addition`, `subtraction`, `multiplication`, `bitwise and`, `bitwise or`, `bitwise xor`, `bitwise shift right`, and `bitwise shift left`. All operations will wrap the result when the result is outside the range of the `I256` type. Note that unlike the `U256`, when performing the shift right operation `I256` will perform an arithmetic shift right (i.e. sign extends the result). | ||
|
||
All of the operations can be used in 6 different ways: | ||
`I256 op I256` or `I256 op &I256` or `&I256 op I256` or `&I256 op &I256` or `I256 op= I256` or `&I256 op= I256`. | ||
|
||
### Constructors | ||
|
||
The `I256` struct implements the following constructors: `from_i8`, `from_i32`, and `from_i64`. | ||
|
||
### Other | ||
|
||
When using the `I256` struct with `target_os = "zkvm"`, the struct utilizes efficient implementations of comparison operators as well as the `clone` method. | ||
|
||
### Example matrix multiplication using `I256` | ||
|
||
See the full example [here](https://github.com/openvm-org/openvm/blob/main/crates/toolchain/tests/programs/examples/signed-matrix-power.rs). | ||
|
||
```rust | ||
#![cfg_attr(not(feature = "std"), no_main)] | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
openvm::entry!(main); | ||
use core::array; | ||
use openvm_bigint_guest::I256; | ||
|
||
const N: usize = 16; | ||
type Matrix = [[I256; N]; N]; | ||
|
||
pub fn get_matrix(val: i32) -> Matrix { | ||
array::from_fn(|_| array::from_fn(|_| I256::from_i32(val))) | ||
} | ||
|
||
pub fn mult(a: &Matrix, b: &Matrix) -> Matrix { | ||
let mut c = get_matrix(0); | ||
for i in 0..N { | ||
for j in 0..N { | ||
for k in 0..N { | ||
c[i][j] += &a[i][k] * &b[k][j]; | ||
} | ||
} | ||
} | ||
c | ||
} | ||
|
||
pub fn get_identity_matrix() -> Matrix { | ||
let mut res = get_matrix(0); | ||
for i in 0..N { | ||
res[i][i] = I256::from_i32(1); | ||
} | ||
res | ||
} | ||
|
||
pub fn main() { | ||
let a: Matrix = get_identity_matrix(); | ||
let b: Matrix = get_matrix(-28); | ||
let c: Matrix = mult(&a, &b); | ||
assert_eq!(c, b); | ||
} | ||
``` | ||
|
||
## External Functions | ||
|
||
The Bigint Guest extension provides another way to use the native implementation. It provides external functions that are meant to be linked to other external libraries. The external libraries can use these functions as a hook for the 256 bit integer native implementations. Enabled only when the `target_os = "zkvm"`. All of the functions are defined as `unsafe extern "C" fn`. Also, note that you must enable the feature `export-intrinsics` to make them globally linkable. | ||
|
||
- `zkvm_u256_wrapping_add_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a + b`. | ||
- `zkvm_u256_wrapping_sub_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a - b`. | ||
- `zkvm_u256_wrapping_mul_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a * b`. | ||
- `zkvm_u256_bitxor_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a ^ b`. | ||
- `zkvm_u256_bitand_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a & b`. | ||
- `zkvm_u256_bitor_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a | b`. | ||
- `zkvm_u256_wrapping_shl_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a << b`. | ||
- `zkvm_u256_wrapping_shr_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a >> b`. | ||
- `zkvm_u256_arithmetic_shr_impl(result: *mut u8, a: *const u8, b: *const u8)`: takes in a pointer to the result, and two pointers to the inputs. `result = a.arithmetic_shr(b)`. | ||
- `zkvm_u256_eq_impl(a: *const u8, b: *const u8) -> bool`: takes in two pointers to the inputs. Returns `true` if `a == b`, otherwise `false`. | ||
- `zkvm_u256_cmp_impl(a: *const u8, b: *const u8) -> Ordering`: takes in two pointers to the inputs. Returns the ordering of `a` and `b`. | ||
- `zkvm_u256_clone_impl(result: *mut u8, a: *const u8)`: takes in a pointer to the result buffer, and a pointer to the input. `result = a`. | ||
|
||
And in the external library, you can do the following: | ||
|
||
```rust | ||
extern "C" { | ||
fn zkvm_u256_wrapping_add_impl(result: *mut u8, a: *const u8, b: *const u8); | ||
} | ||
|
||
fn wrapping_add(a: &Custom_U256, b: &Custom_U256) -> Custom_U256 { | ||
#[cfg(target_os = "zkvm")] { | ||
let mut result: MaybeUninit<Custom_U256> = MaybeUninit::uninit(); | ||
unsafe { | ||
zkvm_u256_wrapping_add_impl(result.as_mut_ptr() as *mut u8, a as *const u8, b as *const u8); | ||
} | ||
unsafe { result.assume_init() } | ||
} | ||
#[cfg(not(target_os = "zkvm"))] { | ||
// Regular wrapping add implementation | ||
} | ||
} | ||
``` | ||
|
||
### Config parameters | ||
|
||
For the guest program to build successfully add the following to your `.toml` file: | ||
|
||
```toml | ||
[app_vm_config.bigint] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,68 @@ | ||
# OpenVM Keccak | ||
# OpenVM Keccak256 | ||
|
||
The OpenVm Keccak256 extension provides tools for using the Keccak-256 hash function. | ||
The functional part is provided by the `openvm-keccak-guest` crate, which is a guest library that can be used in any OpenVM program. | ||
|
||
## Functions for guest code | ||
|
||
The OpenVM Keccak256 Guest extension provides two functions for using in your guest code: | ||
|
||
- `keccak256(input: &[u8]) -> [u8; 32]`: Computes the Keccak-256 hash of the input data and returns it as an array of 32 bytes. | ||
- `set_keccak256(input: &[u8], output: &mut [u8; 32])`: Sets the output to the Keccak-256 hash of the input data into the provided output buffer. | ||
|
||
See the full example [here](https://github.com/openvm-org/openvm/blob/main/crates/toolchain/tests/programs/examples/keccak.rs). | ||
|
||
### Example: | ||
```rust | ||
use openvm_keccak256_guest::keccak256; | ||
|
||
pub fn main() { | ||
let test_vectors = [ | ||
("", "C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470"), | ||
("CC", "EEAD6DBFC7340A56CAEDC044696A168870549A6A7F6F56961E84A54BD9970B8A"), | ||
]; | ||
for (input, expected_output) in test_vectors.iter() { | ||
let input = Vec::from_hex(input).unwrap(); | ||
let expected_output = Vec::from_hex(expected_output).unwrap(); | ||
let output = keccak256(&black_box(input)); | ||
if output != *expected_output { | ||
panic!(); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Native Keccak256 | ||
|
||
Keccak guest extension also provides another way to use the native Keccak-256 implementation. It provides a function that is meant to be linked to other external libraries. The external libraries can use this function as a hook for the Keccak-256 native implementation. Enabled only when the target is `zkvm`. | ||
|
||
- `native_keccak256(input: *const u8, len: usize, output: *mut u8)`: This function has `C` ABI. It takes in a pointer to the input, the length of the input, and a pointer to the output buffer. | ||
|
||
In the external library, you can do the following: | ||
|
||
```rust | ||
extern "C" { | ||
fn native_keccak256(input: *const u8, len: usize, output: *mut u8); | ||
} | ||
|
||
fn keccak256(input: &[u8]) -> [u8; 32] { | ||
#[cfg(target_os = "zkvm")] { | ||
let mut output = [0u8; 32]; | ||
unsafe { | ||
native_keccak256(input.as_ptr(), input.len(), output.as_mut_ptr() as *mut u8); | ||
} | ||
output | ||
} | ||
#[cfg(not(target_os = "zkvm"))] { | ||
// Regular Keccak-256 implementation | ||
} | ||
} | ||
``` | ||
|
||
### Config parameters | ||
|
||
For the guest program to build successfully add the following to your `.toml` file: | ||
|
||
```toml | ||
[app_vm_config.keccak256] | ||
``` |