diff --git a/crates/zkvm-interface/platform/Cargo.toml b/crates/zkvm-interface/platform/Cargo.toml index 9945640..63d7fc7 100644 --- a/crates/zkvm-interface/platform/Cargo.toml +++ b/crates/zkvm-interface/platform/Cargo.toml @@ -6,11 +6,10 @@ rust-version.workspace = true license.workspace = true [dependencies] -digest = { workspace = true, optional = true } +digest.workspace = true [features] default = [] -output-hasher = ["dep:digest"] [lints] workspace = true diff --git a/crates/zkvm-interface/platform/src/lib.rs b/crates/zkvm-interface/platform/src/lib.rs index 5aa537d..1a0da81 100644 --- a/crates/zkvm-interface/platform/src/lib.rs +++ b/crates/zkvm-interface/platform/src/lib.rs @@ -4,7 +4,6 @@ extern crate alloc; use alloc::vec::Vec; -#[cfg(feature = "output-hasher")] pub mod output_hasher; /// Platform dependent methods. diff --git a/crates/zkvm-interface/platform/src/output_hasher.rs b/crates/zkvm-interface/platform/src/output_hasher.rs index c252196..58c4b7b 100644 --- a/crates/zkvm-interface/platform/src/output_hasher.rs +++ b/crates/zkvm-interface/platform/src/output_hasher.rs @@ -1,23 +1,50 @@ -use core::marker::PhantomData; -use digest::{Digest, Output, OutputSizeUser, generic_array::ArrayLength}; +use core::{marker::PhantomData, ops::Deref}; +use digest::{ + Digest, Output, OutputSizeUser, + generic_array::{ArrayLength, GenericArray}, +}; pub use digest; -/// A hasher that given the output, returns a fixed size hash of it. -pub trait OutputHasher: OutputSizeUser { - fn output_hash(output: &[u8]) -> Output; +/// A hasher that given the output, returns a hash of it. +pub trait OutputHasher { + type Hash<'a>: Deref; + + fn output_hash(output: &[u8]) -> Self::Hash<'_>; } -/// [`OutputHasher`] implementation that expects the output size to be equal to -/// the fixed size, and returns it as is. -pub struct IdentityOutput(PhantomData); +/// A hasher that given the output, returns a fixed-size hash of it. +pub trait FixedOutputHasher: OutputHasher + OutputSizeUser {} -impl + 'static> OutputSizeUser for IdentityOutput { - type OutputSize = S; +impl FixedOutputHasher for T {} + +/// A marker used to mark [`IdentityOutput`] to accept unsized output. +pub struct Unsized; + +/// [`OutputHasher`] implementation that returns output as is. +/// +/// By setting generic `U = Unsized` it takes output with any size. +/// +/// By setting generic `U = typenum::U{SIZE}` it expects the output to match +/// the `SIZE`. +pub struct IdentityOutput(PhantomData); + +impl OutputHasher for IdentityOutput { + type Hash<'a> = &'a [u8]; + + fn output_hash(output: &[u8]) -> Self::Hash<'_> { + output + } } -impl + 'static> OutputHasher for IdentityOutput { - fn output_hash(output: &[u8]) -> Output { +impl + 'static> OutputSizeUser for IdentityOutput { + type OutputSize = U; +} + +impl + 'static> OutputHasher for IdentityOutput { + type Hash<'a> = GenericArray; + + fn output_hash(output: &[u8]) -> Self::Hash<'_> { assert!( output.len() == Self::output_size(), "output length should be equal to {}", @@ -29,16 +56,20 @@ impl + 'static> OutputHasher for IdentityOutput { } } -/// [`OutputHasher`] implementation that expects the output size to be less than -/// or equal to the fixed size, and returns it with 0s padding. -pub struct PaddedOutput(PhantomData); +/// [`OutputHasher`] implementation that returns output with 0s padding. +/// +/// By setting generic `U = typenum::U{SIZE}` it expects the output to be less +/// than or equal to the `SIZE`. +pub struct PaddedOutput(PhantomData); -impl + 'static> OutputSizeUser for PaddedOutput { - type OutputSize = S; +impl + 'static> OutputSizeUser for PaddedOutput { + type OutputSize = U; } -impl + 'static> OutputHasher for PaddedOutput { - fn output_hash(output: &[u8]) -> Output { +impl + 'static> OutputHasher for PaddedOutput { + type Hash<'a> = GenericArray; + + fn output_hash(output: &[u8]) -> Self::Hash<'_> { assert!( output.len() <= Self::output_size(), "output length should be less than or equal to {}", @@ -51,7 +82,9 @@ impl + 'static> OutputHasher for PaddedOutput { } impl OutputHasher for D { - fn output_hash(output: &[u8]) -> Output { + type Hash<'a> = Output; + + fn output_hash(output: &[u8]) -> Self::Hash<'_> { D::digest(output) } } diff --git a/crates/zkvm/airbender/platform/Cargo.toml b/crates/zkvm/airbender/platform/Cargo.toml index 21e98b4..379b0c7 100644 --- a/crates/zkvm/airbender/platform/Cargo.toml +++ b/crates/zkvm/airbender/platform/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true airbender_riscv_common.workspace = true # Local dependencies -ere-platform-trait = { workspace = true, features = ["output-hasher"] } +ere-platform-trait.workspace = true [features] default = [] diff --git a/crates/zkvm/airbender/platform/src/lib.rs b/crates/zkvm/airbender/platform/src/lib.rs index 08d2ebc..2d156b5 100644 --- a/crates/zkvm/airbender/platform/src/lib.rs +++ b/crates/zkvm/airbender/platform/src/lib.rs @@ -4,17 +4,17 @@ extern crate alloc; use alloc::vec::Vec; use core::{array, iter::repeat_with, marker::PhantomData}; -use ere_platform_trait::output_hasher::{OutputHasher, digest::typenum::U32}; +use ere_platform_trait::output_hasher::FixedOutputHasher; pub use airbender_riscv_common as riscv_common; pub use ere_platform_trait::{ Platform, - output_hasher::{IdentityOutput, PaddedOutput}, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32}, }; -pub struct AirbenderPlatform(PhantomData); +pub struct AirbenderPlatform(PhantomData); -impl> Platform for AirbenderPlatform { +impl> Platform for AirbenderPlatform { fn read_whole_input() -> Vec { let len = riscv_common::csr_read_word() as usize; repeat_with(riscv_common::csr_read_word) @@ -25,7 +25,7 @@ impl> Platform for AirbenderPlatform { } fn write_whole_output(output: &[u8]) { - let hash = D::output_hash(output); + let hash = H::output_hash(output); let words = array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| hash[4 * i + j]))); riscv_common::zksync_os_finish_success(&words); } diff --git a/crates/zkvm/jolt/platform/src/lib.rs b/crates/zkvm/jolt/platform/src/lib.rs index ed5b7e7..464dd68 100644 --- a/crates/zkvm/jolt/platform/src/lib.rs +++ b/crates/zkvm/jolt/platform/src/lib.rs @@ -4,8 +4,12 @@ extern crate alloc; use alloc::vec::Vec; use core::{marker::PhantomData, slice}; +use ere_platform_trait::output_hasher::OutputHasher; -pub use ere_platform_trait::Platform; +pub use ere_platform_trait::{ + Platform, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum}, +}; pub use jolt_sdk as jolt; // FIXME: Because the crate `jolt-common` is not `no_std` compatible, so we have @@ -65,9 +69,9 @@ impl JoltMemoryConfig for DefaulJoltMemoryConfig { const MEMORY_SIZE: u64 = DEFAULT_MEMORY_SIZE; } -pub struct JoltPlatform(PhantomData); +pub struct JoltPlatform(PhantomData<(C, H)>); -impl Platform for JoltPlatform { +impl Platform for JoltPlatform { fn read_whole_input() -> Vec { let memory_layout = C::memory_layout(); let input_ptr = memory_layout.input_start as *const u8; @@ -78,10 +82,11 @@ impl Platform for JoltPlatform { } fn write_whole_output(output: &[u8]) { + let hash = H::output_hash(output); let memory_layout = C::memory_layout(); let output_ptr = memory_layout.output_start as *mut u8; let max_output_len = memory_layout.max_output_size as usize; let output_slice = unsafe { core::slice::from_raw_parts_mut(output_ptr, max_output_len) }; - jolt::postcard::to_slice(output, output_slice).unwrap(); + jolt::postcard::to_slice(&*hash, output_slice).unwrap(); } } diff --git a/crates/zkvm/nexus/platform/src/lib.rs b/crates/zkvm/nexus/platform/src/lib.rs index 8b4ccb1..8dabcb4 100644 --- a/crates/zkvm/nexus/platform/src/lib.rs +++ b/crates/zkvm/nexus/platform/src/lib.rs @@ -3,18 +3,24 @@ extern crate alloc; use alloc::vec::Vec; +use core::marker::PhantomData; +use ere_platform_trait::output_hasher::OutputHasher; -pub use ere_platform_trait::Platform; +pub use ere_platform_trait::{ + Platform, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum}, +}; pub use nexus_rt; -pub struct NexusPlatform; +pub struct NexusPlatform(PhantomData); -impl Platform for NexusPlatform { +impl Platform for NexusPlatform { fn read_whole_input() -> Vec { nexus_rt::read_private_input().unwrap() } fn write_whole_output(output: &[u8]) { - nexus_rt::write_public_output(&output).unwrap() + let hash = H::output_hash(output); + nexus_rt::write_public_output(&*hash).unwrap() } } diff --git a/crates/zkvm/openvm/platform/Cargo.toml b/crates/zkvm/openvm/platform/Cargo.toml index ffcb0b5..f567f84 100644 --- a/crates/zkvm/openvm/platform/Cargo.toml +++ b/crates/zkvm/openvm/platform/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true openvm.workspace = true # Local dependencies -ere-platform-trait = { workspace = true, features = ["output-hasher"] } +ere-platform-trait.workspace = true [features] default = ["getrandom-unsupported"] diff --git a/crates/zkvm/openvm/platform/src/lib.rs b/crates/zkvm/openvm/platform/src/lib.rs index 1878891..a39ff5a 100644 --- a/crates/zkvm/openvm/platform/src/lib.rs +++ b/crates/zkvm/openvm/platform/src/lib.rs @@ -3,24 +3,24 @@ extern crate alloc; use alloc::vec::Vec; -use core::marker::PhantomData; -use ere_platform_trait::output_hasher::{OutputHasher, digest::typenum::U32}; +use core::{marker::PhantomData, ops::Deref}; +use ere_platform_trait::output_hasher::FixedOutputHasher; pub use ere_platform_trait::{ Platform, - output_hasher::{IdentityOutput, PaddedOutput}, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32}, }; pub use openvm; -pub struct OpenVMPlatform(PhantomData); +pub struct OpenVMPlatform(PhantomData); -impl> Platform for OpenVMPlatform { +impl> Platform for OpenVMPlatform { fn read_whole_input() -> Vec { openvm::io::read_vec() } fn write_whole_output(output: &[u8]) { - let hash = D::output_hash(output); - openvm::io::reveal_bytes32(hash.into()); + let hash = H::output_hash(output).deref().try_into().unwrap(); + openvm::io::reveal_bytes32(hash); } } diff --git a/crates/zkvm/pico/platform/src/lib.rs b/crates/zkvm/pico/platform/src/lib.rs index a57dd6a..43b9c51 100644 --- a/crates/zkvm/pico/platform/src/lib.rs +++ b/crates/zkvm/pico/platform/src/lib.rs @@ -3,18 +3,24 @@ extern crate alloc; use alloc::vec::Vec; +use core::marker::PhantomData; +use ere_platform_trait::output_hasher::OutputHasher; -pub use ere_platform_trait::Platform; +pub use ere_platform_trait::{ + Platform, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum}, +}; pub use pico_sdk; -pub struct PicoPlatform; +pub struct PicoPlatform(PhantomData); -impl Platform for PicoPlatform { +impl Platform for PicoPlatform { fn read_whole_input() -> Vec { pico_sdk::io::read_vec() } fn write_whole_output(output: &[u8]) { - pico_sdk::io::commit_bytes(output); + let hash = H::output_hash(output); + pico_sdk::io::commit_bytes(&*hash); } } diff --git a/crates/zkvm/risc0/platform/src/lib.rs b/crates/zkvm/risc0/platform/src/lib.rs index 458ec8a..33386f0 100644 --- a/crates/zkvm/risc0/platform/src/lib.rs +++ b/crates/zkvm/risc0/platform/src/lib.rs @@ -3,13 +3,18 @@ extern crate alloc; use alloc::{vec, vec::Vec}; +use core::marker::PhantomData; +use ere_platform_trait::output_hasher::OutputHasher; -pub use ere_platform_trait::Platform; +pub use ere_platform_trait::{ + Platform, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum}, +}; pub use risc0_zkvm; -pub struct Risc0Platform; +pub struct Risc0Platform(PhantomData); -impl Platform for Risc0Platform { +impl Platform for Risc0Platform { fn read_whole_input() -> Vec { let len = { let mut bytes = [0; 4]; @@ -22,6 +27,7 @@ impl Platform for Risc0Platform { } fn write_whole_output(output: &[u8]) { - risc0_zkvm::guest::env::commit_slice(output); + let hash = H::output_hash(output); + risc0_zkvm::guest::env::commit_slice(&*hash); } } diff --git a/crates/zkvm/sp1/platform/src/lib.rs b/crates/zkvm/sp1/platform/src/lib.rs index 3cdf5e6..cce618e 100644 --- a/crates/zkvm/sp1/platform/src/lib.rs +++ b/crates/zkvm/sp1/platform/src/lib.rs @@ -3,18 +3,24 @@ extern crate alloc; use alloc::vec::Vec; +use core::marker::PhantomData; +use ere_platform_trait::output_hasher::OutputHasher; -pub use ere_platform_trait::Platform; +pub use ere_platform_trait::{ + Platform, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum}, +}; pub use sp1_zkvm; -pub struct SP1Platform; +pub struct SP1Platform(PhantomData); -impl Platform for SP1Platform { +impl Platform for SP1Platform { fn read_whole_input() -> Vec { sp1_zkvm::io::read_vec() } fn write_whole_output(output: &[u8]) { - sp1_zkvm::io::commit_slice(output); + let hash = H::output_hash(output); + sp1_zkvm::io::commit_slice(&*hash); } } diff --git a/crates/zkvm/ziren/platform/src/lib.rs b/crates/zkvm/ziren/platform/src/lib.rs index 39e6b37..0dd30ee 100644 --- a/crates/zkvm/ziren/platform/src/lib.rs +++ b/crates/zkvm/ziren/platform/src/lib.rs @@ -3,18 +3,24 @@ extern crate alloc; use alloc::vec::Vec; +use core::marker::PhantomData; +use ere_platform_trait::output_hasher::OutputHasher; -pub use ere_platform_trait::Platform; +pub use ere_platform_trait::{ + Platform, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum}, +}; pub use zkm_zkvm; -pub struct ZirenPlatform; +pub struct ZirenPlatform(PhantomData); -impl Platform for ZirenPlatform { +impl Platform for ZirenPlatform { fn read_whole_input() -> Vec { zkm_zkvm::io::read_vec() } fn write_whole_output(output: &[u8]) { - zkm_zkvm::io::commit_slice(output); + let hash = H::output_hash(output); + zkm_zkvm::io::commit_slice(&*hash); } } diff --git a/crates/zkvm/zisk/platform/Cargo.toml b/crates/zkvm/zisk/platform/Cargo.toml index 81b6db5..8bb3f86 100644 --- a/crates/zkvm/zisk/platform/Cargo.toml +++ b/crates/zkvm/zisk/platform/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true ziskos.workspace = true # Local dependencies -ere-platform-trait = { workspace = true, features = ["output-hasher"] } +ere-platform-trait.workspace = true [features] default = [] diff --git a/crates/zkvm/zisk/platform/src/lib.rs b/crates/zkvm/zisk/platform/src/lib.rs index 153e09c..0f50900 100644 --- a/crates/zkvm/zisk/platform/src/lib.rs +++ b/crates/zkvm/zisk/platform/src/lib.rs @@ -4,23 +4,23 @@ extern crate alloc; use alloc::vec::Vec; use core::marker::PhantomData; -use ere_platform_trait::output_hasher::{OutputHasher, digest::typenum::U32}; +use ere_platform_trait::output_hasher::FixedOutputHasher; pub use ere_platform_trait::{ Platform, - output_hasher::{IdentityOutput, PaddedOutput}, + output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32}, }; pub use ziskos; -pub struct ZiskPlatform(PhantomData); +pub struct ZiskPlatform(PhantomData); -impl> Platform for ZiskPlatform { +impl> Platform for ZiskPlatform { fn read_whole_input() -> Vec { ziskos::read_input() } fn write_whole_output(output: &[u8]) { - let hash = D::output_hash(output); + let hash = H::output_hash(output); hash.chunks_exact(4).enumerate().for_each(|(idx, bytes)| { ziskos::set_output(idx, u32::from_le_bytes(bytes.try_into().unwrap())) }); diff --git a/tests/risc0/allocs_alignment/src/main.rs b/tests/risc0/allocs_alignment/src/main.rs index 3751b41..c2b3d16 100644 --- a/tests/risc0/allocs_alignment/src/main.rs +++ b/tests/risc0/allocs_alignment/src/main.rs @@ -1,8 +1,9 @@ use ere_platform_risc0::{Platform, Risc0Platform}; +type P = Risc0Platform; + fn main() { - let alignment = - u32::from_le_bytes(Risc0Platform::read_whole_input().try_into().unwrap()) as usize; + let alignment = u32::from_le_bytes(P::read_whole_input().try_into().unwrap()) as usize; let layout = std::alloc::Layout::from_size_align(1, alignment).unwrap(); let ptr = unsafe { std::alloc::alloc(layout) };