Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions executor/src/flamegraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,7 @@ impl FlamegraphGenerator {
/// Demangle a Rust symbol name using the official rustc-demangle crate.
///
/// Uses the alternate format (`{:#}`) to omit the hash suffix for cleaner output.
fn demangle(name: &str) -> String {
pub(crate) fn demangle(name: &str) -> String {
// Use rustc-demangle with alternate format to omit hash
format!("{:#}", rustc_demangle(name))
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_demangle_simple() {
assert_eq!(demangle("main"), "main");
assert_eq!(demangle("_start"), "_start");
}
}
2 changes: 2 additions & 0 deletions executor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod elf;
pub mod flamegraph;
#[cfg(test)]
pub mod tests;
Comment thread
MauroToscano marked this conversation as resolved.
pub mod vm;
9 changes: 9 additions & 0 deletions executor/src/tests/flamegraph_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Tests for symbol demangling in flamegraph generation.

use crate::flamegraph::demangle;

#[test]
fn test_demangle_simple() {
assert_eq!(demangle("main"), "main");
assert_eq!(demangle("_start"), "_start");
}
88 changes: 88 additions & 0 deletions executor/src/tests/keccak_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Tests for the Keccak-f[1600] permutation and the Keccak syscall.

use crate::vm::instruction::decoding::Instruction;
use crate::vm::instruction::execution::{ExecutionError, KECCAK_SYSCALL_NUMBER, keccak_f1600};
use crate::vm::memory::Memory;
use crate::vm::registers::Registers;

#[test]
fn test_keccak_f1600_zero_input() {
let mut state = [0u64; 25];
keccak_f1600(&mut state);

let expected: [u64; 25] = [
0xF1258F7940E1DDE7,
0x84D5CCF933C0478A,
0xD598261EA65AA9EE,
0xBD1547306F80494D,
0x8B284E056253D057,
0xFF97A42D7F8E6FD4,
0x90FEE5A0A44647C4,
0x8C5BDA0CD6192E76,
0xAD30A6F71B19059C,
0x30935AB7D08FFC64,
0xEB5AA93F2317D635,
0xA9A6E6260D712103,
0x81A57C16DBCF555F,
0x43B831CD0347C826,
0x01F22F1A11A5569F,
0x05E5635A21D9AE61,
0x64BEFEF28CC970F2,
0x613670957BC46611,
0xB87C5A554FD00ECB,
0x8C3EE88A1CCF32C8,
0x940C7922AE3A2614,
0x1841F924A2C509E4,
0x16F53526E70465C2,
0x75F644E97F30A13B,
0xEAF1FF7B5CECA249,
];

assert_eq!(state, expected, "keccak-f[1600] on zero input mismatch");
}

#[test]
fn test_keccak_f1600_nonzero_input() {
let mut state = [0u64; 25];
state[0] = 1;
let original = state;
keccak_f1600(&mut state);
assert_ne!(state, original);
assert!(state.iter().any(|&x| x != 0));
}

#[test]
fn test_keccak_syscall_rejects_unaligned_state_addr() {
let mut pc = 0;
let mut registers = Registers::default();
let mut memory = Memory::default();

registers.write(17, KECCAK_SYSCALL_NUMBER).unwrap();
registers.write(10, 0x1001).unwrap();

let err = Instruction::EcallEbreak
.run(&mut pc, &mut registers, &mut memory)
.unwrap_err();
assert!(matches!(
err,
ExecutionError::UnalignedKeccakStateAddress(0x1001)
));
}

#[test]
fn test_keccak_syscall_rejects_overflowing_state_range() {
let mut pc = 0;
let mut registers = Registers::default();
let mut memory = Memory::default();

registers.write(17, KECCAK_SYSCALL_NUMBER).unwrap();
registers.write(10, u64::MAX - 191).unwrap();

let err = Instruction::EcallEbreak
.run(&mut pc, &mut registers, &mut memory)
.unwrap_err();
assert!(matches!(
err,
ExecutionError::KeccakStateAddressOverflow(addr) if addr == u64::MAX - 191
));
}
111 changes: 111 additions & 0 deletions executor/src/tests/memory_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//! Tests for guest memory: public-output commits and bounds-checked loads.

use crate::vm::memory::{Memory, MemoryError};

#[test]
fn test_commit_public_output_single() {
let mut memory = Memory::default();
memory.store_byte(0x100, b'a');
memory.store_byte(0x101, b'b');

memory
.commit_public_output(0x100, 2)
.expect("commit should succeed");

assert_eq!(
memory
.read_return_value()
.expect("public output should be readable"),
b"ab".to_vec()
);
}

#[test]
fn test_commit_public_output_appends() {
let mut memory = Memory::default();
memory.store_byte(0x100, b'a');
memory.store_byte(0x101, b'b');
memory.store_byte(0x104, b'c');
memory.store_byte(0x105, b'd');

memory
.commit_public_output(0x100, 2)
.expect("first commit should succeed");
memory
.commit_public_output(0x104, 2)
.expect("second commit should succeed");

// Append semantics: calls concatenate (EF zkVM IO interface).
assert_eq!(
memory
.read_return_value()
.expect("public output should be readable"),
b"abcd".to_vec()
);
}

#[test]
fn test_commit_public_output_empty_is_ok() {
let mut memory = Memory::default();
memory
.commit_public_output(0, 0)
.expect("zero-length commit should succeed");
assert!(
memory
.read_return_value()
.expect("public output should be readable")
.is_empty()
);
}

#[test]
fn test_commit_public_output_address_overflow() {
let mut memory = Memory::default();
let err = memory
.commit_public_output(u64::MAX, 2)
.expect_err("address overflow must error, not panic");
assert!(matches!(err, MemoryError::AddressOverflow));
}

#[test]
fn test_load_bytes_huge_len_returns_alloc_error() {
let memory = Memory::default();
// A multi-petabyte allocation request from a guest must fail cleanly,
// not abort the host process via OOM. `addr=0` and `len=1<<50` keep
// `checked_add` happy so the path reaches the allocation.
let huge = 1u64 << 50;
let err = memory
.load_bytes(0, huge)
.expect_err("huge alloc must error, not abort");
assert!(matches!(err, MemoryError::AllocationFailed));
}

#[test]
fn test_load_bytes_overflow_errors() {
let memory = Memory::default();
let err = memory
.load_bytes(u64::MAX, 2)
.expect_err("address overflow must error, not panic");
assert!(matches!(err, MemoryError::AddressOverflow));
}

#[test]
fn test_commit_public_output_total_cap() {
let mut memory = Memory::default();
// Seed enough source bytes for two 512 KB writes.
let chunk = vec![0xAB; 512 * 1024];
memory
.set_bytes_aligned(0x1_0000, &chunk)
.expect("seed should succeed");

memory
.commit_public_output(0x1_0000, 512 * 1024)
.expect("first 512 KB commit should succeed");
memory
.commit_public_output(0x1_0000, 512 * 1024)
.expect("second 512 KB commit should succeed (total = 1 MB)");

// One more byte exceeds the 1 MB total cap.
let err = memory.commit_public_output(0x1_0000, 1).unwrap_err();
assert!(matches!(err, MemoryError::CommitSizeExceeded));
}
3 changes: 3 additions & 0 deletions executor/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod flamegraph_tests;
pub mod keccak_tests;
pub mod memory_tests;
87 changes: 0 additions & 87 deletions executor/src/vm/instruction/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,90 +618,3 @@ pub fn keccak_f1600(state: &mut [u64; 25]) {
state[0] ^= rc;
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_keccak_f1600_zero_input() {
let mut state = [0u64; 25];
keccak_f1600(&mut state);

let expected: [u64; 25] = [
0xF1258F7940E1DDE7,
0x84D5CCF933C0478A,
0xD598261EA65AA9EE,
0xBD1547306F80494D,
0x8B284E056253D057,
0xFF97A42D7F8E6FD4,
0x90FEE5A0A44647C4,
0x8C5BDA0CD6192E76,
0xAD30A6F71B19059C,
0x30935AB7D08FFC64,
0xEB5AA93F2317D635,
0xA9A6E6260D712103,
0x81A57C16DBCF555F,
0x43B831CD0347C826,
0x01F22F1A11A5569F,
0x05E5635A21D9AE61,
0x64BEFEF28CC970F2,
0x613670957BC46611,
0xB87C5A554FD00ECB,
0x8C3EE88A1CCF32C8,
0x940C7922AE3A2614,
0x1841F924A2C509E4,
0x16F53526E70465C2,
0x75F644E97F30A13B,
0xEAF1FF7B5CECA249,
];

assert_eq!(state, expected, "keccak-f[1600] on zero input mismatch");
}

#[test]
fn test_keccak_f1600_nonzero_input() {
let mut state = [0u64; 25];
state[0] = 1;
let original = state;
keccak_f1600(&mut state);
assert_ne!(state, original);
assert!(state.iter().any(|&x| x != 0));
}

#[test]
fn test_keccak_syscall_rejects_unaligned_state_addr() {
let mut pc = 0;
let mut registers = Registers::default();
let mut memory = Memory::default();

registers.write(17, KECCAK_SYSCALL_NUMBER).unwrap();
registers.write(10, 0x1001).unwrap();

let err = Instruction::EcallEbreak
.run(&mut pc, &mut registers, &mut memory)
.unwrap_err();
assert!(matches!(
err,
ExecutionError::UnalignedKeccakStateAddress(0x1001)
));
}

#[test]
fn test_keccak_syscall_rejects_overflowing_state_range() {
let mut pc = 0;
let mut registers = Registers::default();
let mut memory = Memory::default();

registers.write(17, KECCAK_SYSCALL_NUMBER).unwrap();
registers.write(10, u64::MAX - 191).unwrap();

let err = Instruction::EcallEbreak
.run(&mut pc, &mut registers, &mut memory)
.unwrap_err();
assert!(matches!(
err,
ExecutionError::KeccakStateAddressOverflow(addr) if addr == u64::MAX - 191
));
}
}
Loading
Loading