diff --git a/executor/programs/rust/commit/src/main.rs b/executor/programs/rust/commit/src/main.rs index bbf79f54a..6dd776e39 100644 --- a/executor/programs/rust/commit/src/main.rs +++ b/executor/programs/rust/commit/src/main.rs @@ -1,7 +1,7 @@ use lambda_vm_syscalls as syscalls; pub fn main() { - let input: Vec = syscalls::syscalls::get_private_input(); + let input = syscalls::syscalls::get_private_input(); syscalls::syscalls::print_string(format!("Private input received: {:?}\n", input).as_str()); - syscalls::syscalls::commit(&input); + syscalls::syscalls::commit(input); } diff --git a/executor/programs/rust/commit_sum/src/main.rs b/executor/programs/rust/commit_sum/src/main.rs index 6eb84bc83..4661eb2ff 100644 --- a/executor/programs/rust/commit_sum/src/main.rs +++ b/executor/programs/rust/commit_sum/src/main.rs @@ -1,7 +1,7 @@ use lambda_vm_syscalls as syscalls; pub fn main() { - let input: Vec = syscalls::syscalls::get_private_input(); + let input = syscalls::syscalls::get_private_input(); let a = input[0]; let b = input[1]; syscalls::syscalls::commit((a + b).to_le_bytes().as_ref()); diff --git a/executor/programs/rust/ethrex/src/main.rs b/executor/programs/rust/ethrex/src/main.rs index 30a39f4b5..b2c6bdc30 100644 --- a/executor/programs/rust/ethrex/src/main.rs +++ b/executor/programs/rust/ethrex/src/main.rs @@ -6,7 +6,7 @@ use rkyv::rancor::Error; pub fn main() { let input = lambda_vm_syscalls::syscalls::get_private_input(); - let input = rkyv::from_bytes::(&input).unwrap(); + let input = rkyv::from_bytes::(input).unwrap(); // LambdaVM crypto provider, defined in the lambda_vm repo and injected here // (so crypto changes don't require an ethrex PR — see `crypto/ethrex-crypto`). // It accelerates trait-routed `keccak256` (via the keccak_permute precompile) diff --git a/syscalls/README.md b/syscalls/README.md index 9e972e0d0..240fad757 100644 --- a/syscalls/README.md +++ b/syscalls/README.md @@ -9,7 +9,7 @@ Published as `lambda-vm-syscalls`. Intended to be used from RISC-V (RV64IM) gues | Function | Purpose | |---|---| | `commit(bytes: &[u8])` | Append bytes to the **public output** that the verifier checks. | -| `get_private_input() -> Vec` | Read the host-supplied private input bytes (memory-mapped at `0xFF000000`). | +| `get_private_input() -> &'static [u8]` | Read the host-supplied private input bytes zero-copy (memory-mapped at `0xFF000000`). | | `sys_halt() -> !` | Terminate execution cleanly. Called automatically after `main` by the default entry point. | | `keccak_permute(state: &mut [u64; 25])` | Keccak-f[1600] permutation precompile. | | `ecsm_mul(xr: &mut [u8; 32], xg: &[u8; 32], k: &[u8; 32])` | secp256k1 scalar multiplication: writes `xR = (k·G)_x` (32-byte little-endian; `0 < k < N`). | diff --git a/syscalls/src/syscalls.rs b/syscalls/src/syscalls.rs index 491315ecb..8f8cbf8c6 100644 --- a/syscalls/src/syscalls.rs +++ b/syscalls/src/syscalls.rs @@ -78,22 +78,27 @@ pub fn commit(slice: &[u8]) { /// `PRIVATE_INPUT_START = 0xFF000000`. /// /// The host pre-loads the input before execution; this function reads the -/// 4-byte LE length prefix and then copies the data bytes into a new `Vec`. +/// 4-byte LE length prefix and returns a zero-copy slice over the data bytes. /// No ecall is performed — it's a plain memory read (ZisK-style). +/// +/// The returned slice borrows from the fixed private-input mapping: the host +/// writes it before execution starts and never mutates it afterward, so the +/// borrow is valid for the whole run. #[cfg(target_arch = "riscv64")] -pub fn get_private_input() -> Vec { +pub fn get_private_input() -> &'static [u8] { // SAFETY: The host pre-loads private input at PRIVATE_INPUT_START before // execution. The 4-byte LE length prefix is always valid (written by the - // executor). The data pointer and length are within the memory-mapped region. + // executor). The data pointer and length are within the memory-mapped region, + // which lives for the entire program execution and is never mutated after + // loading, so the 'static borrow is sound. let len_ptr = PRIVATE_INPUT_START as *const u32; let len = unsafe { core::ptr::read_volatile(len_ptr) } as usize; let data_ptr = (PRIVATE_INPUT_START + 4) as *const u8; - let slice = unsafe { core::slice::from_raw_parts(data_ptr, len) }; - slice.to_vec() + unsafe { core::slice::from_raw_parts(data_ptr, len) } } #[cfg(not(target_arch = "riscv64"))] -pub fn get_private_input() -> Vec { +pub fn get_private_input() -> &'static [u8] { unimplemented!("syscalls are only implemented for riscv64 targets"); }