Skip to content

Commit d9e9e8c

Browse files
committed
vm core: implement execute_poseidon2_16
1 parent a38f1d3 commit d9e9e8c

File tree

4 files changed

+68
-6
lines changed

4 files changed

+68
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ lean-snark = { path = "crates/leanSnark" }
3737
lean-vm = { path = "crates/leanVm" }
3838

3939
p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
40+
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
4041
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
4142
p3-koala-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
4243

crates/leanVm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ workspace = true
1212
p3-baby-bear.workspace = true
1313
p3-koala-bear.workspace = true
1414
p3-field.workspace = true
15+
p3-symmetric.workspace = true
1516

1617
thiserror.workspace = true
1718
num-traits.workspace = true

crates/leanVm/src/core.rs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use p3_field::PrimeField64;
2+
use p3_symmetric::Permutation;
23

34
use crate::{
45
bytecode::{
@@ -11,13 +12,17 @@ use crate::{
1112
memory::{address::MemoryAddress, manager::MemoryManager, val::MemoryValue},
1213
};
1314

15+
const DIMENSION: usize = 8;
16+
1417
#[derive(Debug, Default)]
15-
pub struct VirtualMachine {
18+
pub struct VirtualMachine<PERM16, PERM24> {
1619
pub(crate) run_context: RunContext,
1720
pub memory_manager: MemoryManager,
21+
pub poseidon2_16: PERM16,
22+
pub poseidon2_24: PERM24,
1823
}
1924

20-
impl VirtualMachine {
25+
impl<PERM16, PERM24> VirtualMachine<PERM16, PERM24> {
2126
/// Advances the program counter (`pc`) to the next instruction.
2227
///
2328
/// This function embodies the control flow logic of the zkVM. For most instructions,
@@ -146,6 +151,7 @@ impl VirtualMachine {
146151
) -> Result<(), VirtualMachineError<F>>
147152
where
148153
F: PrimeField64,
154+
PERM16: Permutation<[F; DIMENSION * 2]>,
149155
{
150156
// Dispatch to the appropriate execution logic based on the instruction type.
151157
match instruction {
@@ -316,11 +322,63 @@ impl VirtualMachine {
316322
Ok(())
317323
}
318324

319-
fn execute_poseidon2_16<F>(&self, _shift: usize) -> Result<(), VirtualMachineError<F>>
325+
/// Executes the `Poseidon2_16` precompile instruction.
326+
///
327+
/// This function orchestrates a Poseidon2 permutation over 16 field elements,
328+
/// as defined by the zkVM's ISA. It reads two 8-element input vectors and
329+
/// writes two 8-element output vectors using pointers stored relative to the
330+
/// frame pointer (`fp`).
331+
///
332+
/// The operation is: `Poseidon2(m_vec[ptr_0], m_vec[ptr_1]) -> (m_vec[ptr_2], m_vec[ptr_3])`
333+
fn execute_poseidon2_16<F>(&mut self, shift: usize) -> Result<(), VirtualMachineError<F>>
320334
where
321335
F: PrimeField64,
336+
PERM16: Permutation<[F; 2 * DIMENSION]>,
322337
{
323-
// TODO: implement this instruction.
338+
// Read Pointers from Memory
339+
//
340+
// The instruction specifies 4 consecutive pointers starting at `fp + shift`.
341+
let base_ptr_addr = self.run_context.fp.add_usize(shift)?;
342+
let ptrs: [MemoryValue<F>; 4] = self.memory_manager.get_array(base_ptr_addr)?;
343+
344+
// Convert the `MemoryValue` pointers to `MemoryAddress`.
345+
let ptr_arg_0: MemoryAddress = ptrs[0].try_into()?;
346+
let ptr_arg_1: MemoryAddress = ptrs[1].try_into()?;
347+
let ptr_res_0: MemoryAddress = ptrs[2].try_into()?;
348+
let ptr_res_1: MemoryAddress = ptrs[3].try_into()?;
349+
350+
// Read Input Vectors
351+
//
352+
// Read the 8-element vectors from the locations pointed to by `ptr_arg_0` and `ptr_arg_1`.
353+
let arg0: [MemoryValue<F>; DIMENSION] = self.memory_manager.get_array(ptr_arg_0)?;
354+
let arg1: [MemoryValue<F>; DIMENSION] = self.memory_manager.get_array(ptr_arg_1)?;
355+
356+
// Perform Hashing
357+
//
358+
// Concatenate the two input vectors into a single 16-element array for the permutation.
359+
let mut state = [MemoryValue::default(); DIMENSION * 2];
360+
state[..DIMENSION].copy_from_slice(&arg0);
361+
state[DIMENSION..].copy_from_slice(&arg1);
362+
363+
// Convert the state to an array of field
364+
let mut state_f: [F; DIMENSION * 2] = [F::ZERO; DIMENSION * 2];
365+
for i in 0..DIMENSION {
366+
state_f[i] = state[i].to_f()?;
367+
}
368+
369+
// Apply the Poseidon2 permutation to the state.
370+
self.poseidon2_16.permute_mut(&mut state_f);
371+
372+
// Write Output Vectors
373+
//
374+
// Split the permuted state back into two 8-element output vectors.
375+
let res0: [F; DIMENSION] = state_f[..DIMENSION].try_into().unwrap();
376+
let res1: [F; DIMENSION] = state_f[DIMENSION..].try_into().unwrap();
377+
378+
// Write the output vectors to the memory locations pointed to by `ptr_res_0` and `ptr_res_1`.
379+
self.memory_manager.load_data(ptr_res_0, &res0)?;
380+
self.memory_manager.load_data(ptr_res_1, &res1)?;
381+
324382
Ok(())
325383
}
326384

crates/leanVm/src/memory/manager.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,15 @@ impl MemoryManager {
6464
/// - Memory cell already initialized with a different value.
6565
/// - Overflow when computing addresses.
6666
/// - Exceeding vector capacity.
67-
pub fn load_data<F>(
67+
pub fn load_data<F, V>(
6868
&mut self,
6969
ptr: MemoryAddress,
70-
data: &[MemoryValue<F>],
70+
data: &[V],
7171
) -> Result<MemoryAddress, MemoryError<F>>
7272
where
7373
F: PrimeField64,
74+
V: Copy,
75+
MemoryValue<F>: From<V>,
7476
{
7577
// Iterate over the data values in reverse order, with indices.
7678
//

0 commit comments

Comments
 (0)