diff --git a/Cargo.lock b/Cargo.lock index 155eb73..74e3a51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2069,9 +2069,8 @@ dependencies = [ [[package]] name = "bonsai-sdk" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21055e2f49cbbdbfe9f8f96d597c5527b0c6ab7933341fdc2f147180e48a988e" +version = "1.4.2" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "duplicate", "maybe-async", @@ -6323,9 +6322,8 @@ checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53" [[package]] name = "risc0-binfmt" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8f97f81bcdead4101bca06469ecef481a2695cd04e7e877b49dea56a7f6f2a" +version = "3.0.3" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "borsh", @@ -6345,9 +6343,8 @@ dependencies = [ [[package]] name = "risc0-build" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbb512d728e011d03ce0958ca7954624ee13a215bcafd859623b3c63b2a3f60" +version = "4.0.0" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "cargo_metadata 0.19.2", @@ -6355,6 +6352,7 @@ dependencies = [ "dirs 6.0.0", "docker-generate", "hex", + "rayon", "risc0-binfmt", "risc0-zkos-v1compat", "risc0-zkp", @@ -6369,9 +6367,8 @@ dependencies = [ [[package]] name = "risc0-build-kernel" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaaa3e04c71e4244354dd9e3f8b89378cfecfbb03f9c72de4e2e7e0482b30c9a" +version = "2.0.2" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "cc", "directories", @@ -6383,9 +6380,8 @@ dependencies = [ [[package]] name = "risc0-circuit-keccak" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f195f865ac1afdc21a172d7756fdcc21be18e13eb01d78d3d7f2b128fa881ba" +version = "4.0.3" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "bytemuck", @@ -6405,9 +6401,8 @@ dependencies = [ [[package]] name = "risc0-circuit-keccak-sys" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a8f21cc053fe9892acebbe0ebe2610a5d79ad638cd17f2e5122cf0b3e7cd1a" +version = "4.0.2" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "cc", "cust", @@ -6421,9 +6416,8 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca8f15c8abc0fd8c097aa7459879110334d191c63dd51d4c28881c4a497279e" +version = "4.0.3" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "bytemuck", @@ -6447,9 +6441,8 @@ dependencies = [ [[package]] name = "risc0-circuit-recursion-sys" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f137bcd382520efcd982e4ee131da43f448b12ade979fe9d1fa92d4337dec0" +version = "4.0.2" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "glob", "risc0-build-kernel", @@ -6460,9 +6453,8 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1b0689f4a270a2f247b04397ebb431b8f64fe5170e98ee4f9d71bd04825205" +version = "4.0.3" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "bit-vec", @@ -6494,9 +6486,8 @@ dependencies = [ [[package]] name = "risc0-circuit-rv32im-sys" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb25f3935e53e89ca020224ad0c09de96cab89a215054c0cee290405074a5166" +version = "4.0.2" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "cc", "cust", @@ -6510,9 +6501,8 @@ dependencies = [ [[package]] name = "risc0-core" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f2723fedace48c6c5a505bd8f97ac4e1712bc4cb769083e10536d862b66987" +version = "3.0.1" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "bytemuck", "nvtx", @@ -6522,9 +6512,8 @@ dependencies = [ [[package]] name = "risc0-groth16" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724285dc79604abfb2d40feaefe3e335420a6b293511661f77d6af62f1f5fae9" +version = "3.0.3" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "ark-bn254", @@ -6536,6 +6525,7 @@ dependencies = [ "cfg-if", "circom-witnesscalc", "hex", + "memmap2", "num-bigint 0.4.6", "num-traits", "risc0-binfmt", @@ -6552,9 +6542,8 @@ dependencies = [ [[package]] name = "risc0-groth16-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580750e1394c5a79b691c8197906263f17a1d3aa7bb46a934362f1ba1475b1a5" +version = "0.2.0" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "blst", @@ -6564,9 +6553,8 @@ dependencies = [ [[package]] name = "risc0-sys" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960c8295fbb87e1e73e332f8f7de2fba0252377575042d9d3e9a4eb50a38e078" +version = "1.5.1" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "blst", @@ -6577,9 +6565,8 @@ dependencies = [ [[package]] name = "risc0-zkos-v1compat" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "840c2228803557a8b7dc035a8f196516b6fd68c9dc6ac092f0c86241b5b1bafb" +version = "2.2.1" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "include_bytes_aligned", "no_std_strings", @@ -6588,9 +6575,8 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb6bf356f469bb8744f72a07a37134c5812c1d55d6271bba80e87bdb7a58c8e" +version = "3.0.3" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "anyhow", "blake2", @@ -6620,9 +6606,8 @@ dependencies = [ [[package]] name = "risc0-zkvm" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcce11648a9ff60b8e7af2f0ce7fbf8d25275ab6d414cc91b9da69ee75bc978" +version = "4.0.0" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "addr2line", "anyhow", @@ -6670,9 +6655,8 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" +version = "2.3.0" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "bytemuck", "cfg-if", @@ -6974,9 +6958,8 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "rzup" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2aed296f203fa64bcb4b52069356dd86d6ec578593985b919b6995bee1f0ae" +version = "0.6.0" +source = "git+https://github.com/risc0/risc0.git?rev=e03b8f0#e03b8f086e3c0ca64e130788d493a00892b4aabe" dependencies = [ "hex", "rsa", @@ -8828,6 +8811,8 @@ dependencies = [ "bytemuck_derive", "hex", "rayon", + "risc0-zkp", + "risc0-zkvm-platform", "serde", "sha2", "tiny-keccak", diff --git a/Cargo.toml b/Cargo.toml index ebcde10..6b5428a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ futures = "0.3.31" hex = "0.4.3" rayon = "1.10.0" reqwest = "0.12.15" +risc0-zkp = "3.0.2" +risc0-zkvm-platform = "2.2.1" serde = { version = "1", features = ["derive"] } serde_json = "1" sha2 = "0.10.8" diff --git a/app-swap/core/Cargo.toml b/app-swap/core/Cargo.toml index e559ceb..e977a1d 100644 --- a/app-swap/core/Cargo.toml +++ b/app-swap/core/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" repository = "https://github.com/essential-contributions/void-reference-impl" [dependencies] -void-core = { path = "../../void/void-core", version = "0.1.0" } +void-core = { path = "../../void/void-core", version = "0.1.0", features = ["poseidon2-r0"] } #Testing only dependencies tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_info"], optional = true } diff --git a/app-swap/core/src/lib.rs b/app-swap/core/src/lib.rs index 079704a..f63c96d 100644 --- a/app-swap/core/src/lib.rs +++ b/app-swap/core/src/lib.rs @@ -1,5 +1,5 @@ use void_core::{ - hash::Sha256, + hash::{Poseidon2, Sha256}, state::kv_store::{ binary_trie_store::BinaryTrieStore, zk_binary_trie_store::{BinaryTrieWitness, ZkBinaryTrieStore}, @@ -13,7 +13,7 @@ pub mod testing; pub mod queries; pub type EventsHash = Sha256; -pub type StorageHash = Sha256; +pub type StorageHash = Poseidon2; pub type AppState = BinaryTrieStore; pub type ZkAppState = ZkBinaryTrieStore; diff --git a/benchmarks/zk-proving/risczero/README.md b/benchmarks/zk-proving/risczero/README.md index c4a720c..89b7b9a 100644 --- a/benchmarks/zk-proving/risczero/README.md +++ b/benchmarks/zk-proving/risczero/README.md @@ -62,31 +62,7 @@ The following results were obtained on the various reference machines. ### AMD Ryzen 9 9950X + RTX 5090 GPU proving ``` -Proof generation benchmark results: -Events Time (s) TPS -1 3.84 0.26 -2 3.92 0.51 -5 4.47 1.12 -10 4.23 2.36 -20 5.66 3.53 -50 7.96 6.28 -100 11.43 8.75 -200 19.53 10.24 -500 39.54 12.65 -1000 74.62 13.40 -2000 135.90 14.72 -5000 309.93 16.13 -10000 566.03 17.67 -20000 1021.02 19.59 -Estimated TPS at various latencies: -Latency (s) TPS -5 3.07 -10 7.94 -30 11.90 -60 13.19 -120 14.50 -300 16.10 ``` ### AWS g6.xlarge @@ -94,50 +70,33 @@ GPU proving ``` Proof generation benchmark results: Events Time (s) TPS -1 6.23 0.16 -2 6.26 0.32 -5 6.79 0.74 -10 7.78 1.29 -20 9.23 2.17 -50 13.66 3.66 -100 19.64 5.09 -200 32.81 6.10 -500 69.10 7.24 -1000 126.09 7.93 -2000 234.46 8.53 -5000 520.38 9.61 -10000 942.56 10.61 +1 6.10 0.16 +2 6.11 0.33 +5 6.40 0.78 +10 6.86 1.46 +20 6.98 2.86 +50 9.12 5.48 +100 12.08 8.28 +200 18.05 11.08 +500 35.28 14.17 +1000 61.64 16.22 +2000 112.62 17.76 +5000 256.39 19.50 +10000 473.71 21.11 Estimated TPS at various latencies: Latency (s) TPS 5 -- -10 2.52 -30 5.96 -60 7.08 -120 7.89 -300 8.96 +10 6.48 +30 13.60 +60 16.15 +120 17.95 +300 20.01 +600 -- ``` ### AWS c6i.8xlarge CPU proving ``` -Proof generation benchmark results: -Events Time (s) TPS -1 66.61 0.02 -2 66.52 0.03 -5 84.84 0.06 -10 125.10 0.08 -20 152.68 0.13 -50 297.24 0.17 -100 472.23 0.21 -200 848.63 0.24 -Estimated TPS at various latencies: -Latency (s) TPS -5 -- -10 -- -30 -- -60 -- -120 0.08 -300 0.17 ``` diff --git a/benchmarks/zk-proving/risczero/methods/Cargo.toml b/benchmarks/zk-proving/risczero/methods/Cargo.toml index 0704499..381a13f 100644 --- a/benchmarks/zk-proving/risczero/methods/Cargo.toml +++ b/benchmarks/zk-proving/risczero/methods/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [build-dependencies] -risc0-build = { version = "^3.0.3" } +risc0-build = { git = "https://github.com/risc0/risc0.git", rev = "e03b8f0" } [package.metadata.risc0] methods = ["guest"] diff --git a/void/void-core/Cargo.toml b/void/void-core/Cargo.toml index 683a72c..9d38cb5 100644 --- a/void/void-core/Cargo.toml +++ b/void/void-core/Cargo.toml @@ -13,6 +13,12 @@ bytemuck = { workspace = true, features = ["must_cast"] } bytemuck_derive.workspace = true hex.workspace = true rayon.workspace = true -serde = {workspace = true, features = ["derive"]} +risc0-zkp = { git = "https://github.com/risc0/risc0.git", rev = "e03b8f0", optional = true } +risc0-zkvm-platform = { git = "https://github.com/risc0/risc0.git", rev = "e03b8f0", optional = true } +serde = { workspace = true, features = ["derive"] } sha2 = { workspace = true, features = ["compress"] } tiny-keccak = { workspace = true, features = ["keccak"] } + +[features] +default = [] +poseidon2-r0 = ["risc0-zkp", "risc0-zkvm-platform"] diff --git a/void/void-core/src/hash.rs b/void/void-core/src/hash.rs index eaad459..2c7c6ed 100644 --- a/void/void-core/src/hash.rs +++ b/void/void-core/src/hash.rs @@ -4,6 +4,11 @@ mod sha256; pub use keccak::*; pub use sha256::*; +#[cfg(feature = "poseidon2-r0")] +mod poseidon2_r0; +#[cfg(feature = "poseidon2-r0")] +pub use poseidon2_r0::*; + use crate::types::Bytes32; pub trait Hasher: Default { diff --git a/void/void-core/src/hash/poseidon2_r0.rs b/void/void-core/src/hash/poseidon2_r0.rs new file mode 100644 index 0000000..ae16b64 --- /dev/null +++ b/void/void-core/src/hash/poseidon2_r0.rs @@ -0,0 +1,301 @@ +use crate::types::Bytes32; +use super::Hasher; + +/// A wrapper around the Poseidon2 hash function used by RISC0 in their zkVM. +#[derive(Copy, Clone, Debug, Default)] +pub struct Poseidon2; + +impl Hasher for Poseidon2 { + #[inline(always)] + fn hash(&self, input: &[u8]) -> Bytes32 { + sys_poseidon2::hash(&pad_data(&[input])).into() + } + + #[inline(always)] + fn hash_multi(&self, input: &[&[u8]]) -> Bytes32 { + sys_poseidon2::hash(&pad_data(input)).into() + } + + #[inline(always)] + fn compress(&self, input: [Bytes32; 2]) -> Bytes32 { + sys_poseidon2::hash(&pad_data(&[&input[0].as_ref(), &input[1].as_ref()])).into() + } +} + +impl Poseidon2 { + #[inline(always)] + pub fn hash(&self, input: &[u8]) -> Bytes32 { + ::hash(self, input) + } + #[inline(always)] + pub fn hash_multi(&self, input: &[&[u8]]) -> Bytes32 { + ::hash_multi(self, input) + } + #[inline(always)] + pub fn compress(&self, input: [Bytes32; 2]) -> Bytes32 { + ::compress(self, input) + } +} + +#[inline(always)] +fn pad_data(data: &[&[u8]]) -> Vec { + let len_bytes = 4 + data.iter().map(|d| d.len()).sum::(); + + // round up to 32-byte blocks (8 u32 per block) + let blocks = (len_bytes + 31) / 32; + let mut out = vec![0u32; blocks * 8]; + let bytes: &mut [u8] = bytemuck::cast_slice_mut(&mut out); + + // copy data len + data + bytes[..4].copy_from_slice(&(data.len() as u32).to_be_bytes()); + let mut off = 4; + for &chunk in data { + let end = off + chunk.len(); + bytes[off..end].copy_from_slice(chunk); + off = end; + } + + out +} + +#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] +mod sys_poseidon2 { + use risc0_zkvm_platform::syscall::{sys_poseidon2, DIGEST_WORDS}; + + pub fn hash(padded_data: &[u32]) -> [u32; 8] { + let mut state = [0u32; DIGEST_WORDS]; + let mut out_buf = [0u32; DIGEST_WORDS]; + let block_count = padded_data.len() / 8; + unsafe { + sys_poseidon2(&mut state, padded_data.as_ptr() as *const u8, &mut out_buf, block_count as u32); + } + out_buf + } +} + +#[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] +mod sys_poseidon2 { + #![allow(clippy::needless_range_loop)] + + use risc0_zkp::core::digest::DIGEST_WORDS; + + pub fn hash(padded_data: &[u32]) -> [u32; 8] { + let state: [u32; 8] = [0u32; DIGEST_WORDS]; + let mut out_buf = [0u32; DIGEST_WORDS]; + let block_count = padded_data.len() / 8; + sys_poseidon2_emulated(&state, &padded_data, &mut out_buf, block_count as u32); + out_buf + } + + // --------- Code for emulating Poseidon2 syscall ---------- + use risc0_zkp::core::{ + hash::poseidon2::{ + CELLS, M_INT_DIAG_HZN, ROUND_CONSTANTS, ROUNDS_HALF_FULL, ROUNDS_PARTIAL, + }, + }; + use risc0_zkp::field::baby_bear; + + const BABY_BEAR_P_U32: u32 = baby_bear::P; + const BABY_BEAR_P_U64: u64 = baby_bear::P as u64; + + // Flags + pub const PFLAG_IS_ELEM: u32 = 0x8000_0000; + pub const PFLAG_CHECK_OUT: u32 = 0x4000_0000; + + /// Emulated Poseidon2 syscall that operates on values (slices) instead of raw addresses. + /// + /// Notes: + /// - This mirrors the RV32IM circuit emulation path for Poseidon2. + /// - The chaining state (inner[16..24]) is read from `state_in` and updated internally. + /// + /// Parameters: + /// - state_in: initial chaining state (8 words). If you want "no state", pass an array of zeros. + /// - in_buf: input words (u32). Interpreted as blocks: + /// - If PFLAG_IS_ELEM is set: 16 u32 words per block (each word is a field element candidate). + /// - Otherwise: 8 u32 words per block, each split into 2 field elements via its low/high 16-bit halves. + /// - out_buf: output digest (8 words). If PFLAG_CHECK_OUT is set, this function will compare and panic if mismatch. + /// - bits_count: flags and count in the low 16 bits. Upper bits may include PFLAG_IS_ELEM and PFLAG_CHECK_OUT. + /// + /// Panics: + /// - If in_buf is not large enough for the declared count. + /// - If PFLAG_CHECK_OUT is set and out_buf does not match the computed digest. + pub fn sys_poseidon2_emulated( + state_in: &[u32; DIGEST_WORDS], + in_buf: &[u32], + out_buf: &mut [u32; DIGEST_WORDS], + bits_count: u32, + ) { + let is_elem = (bits_count & PFLAG_IS_ELEM) != 0; + let check_out = (bits_count & PFLAG_CHECK_OUT) != 0; + let count = (bits_count & 0xffff) as usize; + + // Determine per-block size (in words) + let words_per_block = if is_elem { 2 * DIGEST_WORDS } else { DIGEST_WORDS }; + let needed_words = count + .checked_mul(words_per_block) + .expect("input size overflow"); + assert!( + in_buf.len() >= needed_words, + "insufficient input: have {}, need {} words", + in_buf.len(), + needed_words + ); + + let mut inner = [0u32; CELLS]; + + // Load chaining state into inner[16..24] + for i in 0..DIGEST_WORDS { + inner[DIGEST_WORDS * 2 + i] = state_in[i]; + } + + // Process each block + for blk in 0..count { + let base = blk * words_per_block; + + if is_elem { + // Load 16 u32 words directly as field elements + for i in 0..DIGEST_WORDS { + inner[i] = in_buf[base + i]; + } + for i in 0..DIGEST_WORDS { + inner[DIGEST_WORDS + i] = in_buf[base + DIGEST_WORDS + i]; + } + } else { + // Load 8 u32 words, split each into two 16-bit elements + for i in 0..DIGEST_WORDS { + let word = in_buf[base + i]; + inner[2 * i] = word & 0xffff; + inner[2 * i + 1] = word >> 16; + } + } + + // Do the mix: M_EXT, half-full rounds, partial rounds (M_INT), final half-full rounds + multiply_by_m_ext(&mut inner); + for i in 0..ROUNDS_HALF_FULL { + do_ext_round(&mut inner, i); + } + do_int_rounds(&mut inner); + for i in ROUNDS_HALF_FULL..ROUNDS_HALF_FULL * 2 { + do_ext_round(&mut inner, i); + } + } + + // Output: either check against provided out_buf or write into it + if check_out { + for i in 0..DIGEST_WORDS { + if out_buf[i] != inner[i] { + panic!( + "poseidon2 check failed: {:#010x} != {:#010x} at word {}", + out_buf[i], inner[i], i + ); + } + } + } else { + for i in 0..DIGEST_WORDS { + out_buf[i] = inner[i]; + } + } + } + + // --------- Helpers that mirror the circuit emulation ---------- + + #[inline(always)] + fn sbox2(x: u32) -> u32 { + let x = x as u64; + let x2 = (x * x) % BABY_BEAR_P_U64; + let x4 = (x2 * x2) % BABY_BEAR_P_U64; + let x6 = (x4 * x2) % BABY_BEAR_P_U64; + let x7 = (x6 * x) % BABY_BEAR_P_U64; + x7 as u32 + } + + #[inline(always)] + fn multiply_by_4x4_circulant(x: &[u32; 4]) -> [u32; 4] { + // See appendix B of the Poseidon2 paper. + const CIRC_FACTOR_2: u64 = 2; + const CIRC_FACTOR_4: u64 = 4; + let t0 = (x[0] as u64 + x[1] as u64) % BABY_BEAR_P_U64; + let t1 = (x[2] as u64 + x[3] as u64) % BABY_BEAR_P_U64; + let t2 = (CIRC_FACTOR_2 * x[1] as u64 + t1) % BABY_BEAR_P_U64; + let t3 = (CIRC_FACTOR_2 * x[3] as u64 + t0) % BABY_BEAR_P_U64; + let t4 = (CIRC_FACTOR_4 * t1 + t3) % BABY_BEAR_P_U64; + let t5 = (CIRC_FACTOR_4 * t0 + t2) % BABY_BEAR_P_U64; + let t6 = (t3 + t5) % BABY_BEAR_P_U64; + let t7 = (t2 + t4) % BABY_BEAR_P_U64; + [t6 as u32, t5 as u32, t7 as u32, t4 as u32] + } + + // Optimized method for multiplication by M_EXT. + #[inline(always)] + fn multiply_by_m_ext(inner: &mut [u32; CELLS]) { + let mut out = [0u32; CELLS]; + let mut tmp_sums = [0u32; 4]; + + for i in 0..(CELLS / 4) { + let chunk = multiply_by_4x4_circulant(&[ + inner[i * 4], + inner[i * 4 + 1], + inner[i * 4 + 2], + inner[i * 4 + 3], + ]); + for j in 0..4 { + let to_add = (chunk[j] as u64 % BABY_BEAR_P_U64) as u32; + tmp_sums[j] = (tmp_sums[j] + to_add) % BABY_BEAR_P_U32; + out[i * 4 + j] = (out[i * 4 + j] + to_add) % BABY_BEAR_P_U32; + } + } + for i in 0..CELLS { + inner[i] = (out[i] + tmp_sums[i % 4]) % BABY_BEAR_P_U32; + } + } + + // Exploit the fact that off-diagonal entries of M_INT are all 1. + #[inline(always)] + fn multiply_by_m_int(inner: &mut [u32; CELLS]) { + let mut sum = 0u64; + for i in 0..CELLS { + sum += inner[i] as u64; + } + sum %= BABY_BEAR_P_U64; + for (i, diag) in M_INT_DIAG_HZN.iter().enumerate().take(CELLS) { + let diag = diag.as_u32() as u64; + let cell = inner[i] as u64; + inner[i] = ((sum + diag * cell) % BABY_BEAR_P_U64) as u32; + } + } + + #[inline(always)] + fn add_round_constants_full(inner: &mut [u32; CELLS], round: usize) { + for i in 0..CELLS { + inner[i] += ROUND_CONSTANTS[round * CELLS + i].as_u32(); + inner[i] %= BABY_BEAR_P_U32; + } + } + + #[inline(always)] + fn add_round_constants_partial(inner: &mut [u32; CELLS], round: usize) { + inner[0] += ROUND_CONSTANTS[round * CELLS].as_u32(); + inner[0] %= BABY_BEAR_P_U32; + } + + #[inline(always)] + fn do_ext_round(inner: &mut [u32; CELLS], mut idx: usize) { + if idx >= ROUNDS_HALF_FULL { + idx += ROUNDS_PARTIAL; + } + add_round_constants_full(inner, idx); + for i in 0..CELLS { + inner[i] = sbox2(inner[i]); + } + multiply_by_m_ext(inner); + } + + #[inline(always)] + fn do_int_rounds(inner: &mut [u32; CELLS]) { + for i in 0..ROUNDS_PARTIAL { + add_round_constants_partial(inner, ROUNDS_HALF_FULL + i); + inner[0] = sbox2(inner[0]); + multiply_by_m_int(inner); + } + } +} diff --git a/void/void-node/Cargo.toml b/void/void-node/Cargo.toml index 767f1a8..618ae74 100644 --- a/void/void-node/Cargo.toml +++ b/void/void-node/Cargo.toml @@ -22,7 +22,7 @@ void-core.workspace = true axum = { version = "0.8.4", features = ["json"], optional = true } #risc0 dependencies -risc0-zkvm = { version = "^3.0.3", optional = true } +risc0-zkvm = { git = "https://github.com/risc0/risc0.git", rev = "e03b8f0", optional = true } #sp1 dependencies sp1-sdk = { version = "5.0.8", optional = true } diff --git a/void/void-prove/Cargo.toml b/void/void-prove/Cargo.toml index 790a6ae..2b7e06e 100644 --- a/void/void-prove/Cargo.toml +++ b/void/void-prove/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true repository.workspace = true [dependencies] -risc0-zkvm = { version = "^3.0.3", default-features = false, features = ['std'], optional = true } +risc0-zkvm = { git = "https://github.com/risc0/risc0.git", rev = "e03b8f0", default-features = false, features = ['std'], optional = true } sp1-zkvm = { version = "5.0.8", features = ["verify"], optional = true } void-core.workspace = true