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
14 changes: 8 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ lean-isa = { path = "crates/leanIsa" }
lean-snark = { path = "crates/leanSnark" }
lean-vm = { path = "crates/leanVm" }

p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
p3-koala-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
p3-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
p3-koala-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
p3-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }

whir-p3 = { git = "https://github.com/tcoratger/whir-p3.git", rev = "df2241d" }

thiserror = "2.0"
proptest = "1.7"
Expand Down
2 changes: 2 additions & 0 deletions crates/leanVm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ p3-symmetric.workspace = true
p3-air.workspace = true
p3-matrix.workspace = true

whir-p3.workspace = true

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

Expand Down
76 changes: 76 additions & 0 deletions crates/leanVm/src/bytecode/instruction/dot_product.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use p3_field::{BasedVectorSpace, dot_product};

use crate::{
bytecode::operand::{MemOrConstant, MemOrFp},
constant::{DIMENSION, EF, F},
context::run_context::RunContext,
errors::vm::VirtualMachineError,
memory::{address::MemoryAddress, manager::MemoryManager},
};

/// An instruction to compute the dot product of two vectors of extension field elements.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DotProductInstruction {
/// The first operand, a pointer to the start of the first vector.
pub arg0: MemOrConstant,
/// The second operand, a pointer to the start of the second vector.
pub arg1: MemOrConstant,
/// The destination pointer for the result.
pub res: MemOrFp,
/// The number of elements in each vector.
pub size: usize,
}

impl DotProductInstruction {
/// Executes the `DotProductExtensionExtension` instruction.
///
/// This function performs the following steps:
/// 1. Resolves the pointers to the two input vectors and the output location from memory.
/// 2. Reads the vector data for both operands from memory.
/// 3. Computes the dot product of the two vectors in the extension field.
/// 4. Writes the resulting extension field element back to the specified memory location.
pub fn execute(
&self,
run_context: &RunContext,
memory_manager: &mut MemoryManager,
) -> Result<(), VirtualMachineError> {
// Resolve the memory addresses for the two input vectors and the result.
let ptr_arg_0: MemoryAddress = run_context
.value_from_mem_or_constant(&self.arg0, memory_manager)?
.try_into()?;
let ptr_arg_1: MemoryAddress = run_context
.value_from_mem_or_constant(&self.arg1, memory_manager)?
.try_into()?;
let ptr_res: MemoryAddress = run_context
.value_from_mem_or_fp(&self.res, memory_manager)?
.try_into()?;

// Read the first vector slice from memory.
let slice_0: Vec<EF> = (0..self.size)
.map(|i| {
let addr = (ptr_arg_0 + i)?;
let vector_coeffs = memory_manager.memory.get_array_as::<F, DIMENSION>(addr)?;
EF::from_basis_coefficients_slice(&vector_coeffs)
.ok_or(VirtualMachineError::InvalidExtensionField)
})
.collect::<Result<_, _>>()?;

// Read the second vector slice from memory.
let slice_1: Vec<EF> = (0..self.size)
.map(|i| {
let addr = (ptr_arg_1 + i)?;
let vector_coeffs = memory_manager.memory.get_array_as::<F, DIMENSION>(addr)?;
EF::from_basis_coefficients_slice(&vector_coeffs)
.ok_or(VirtualMachineError::InvalidExtensionField)
})
.collect::<Result<_, _>>()?;

// Compute the dot product of the two slices by converting them into iterators.
let dot_product_res = dot_product::<EF, _, _>(slice_0.into_iter(), slice_1.into_iter());

// Write the resulting vector back to memory.
memory_manager.load_data::<F>(ptr_res, dot_product_res.as_basis_coefficients_slice())?;

Ok(())
}
}
74 changes: 0 additions & 74 deletions crates/leanVm/src/bytecode/instruction/extension_mul.rs

This file was deleted.

25 changes: 14 additions & 11 deletions crates/leanVm/src/bytecode/instruction/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use computation::ComputationInstruction;
use deref::DerefInstruction;
use extension_mul::ExtensionMulInstruction;
use dot_product::DotProductInstruction;
use jump::JumpIfNotZeroInstruction;
use multilinear_eval::MultilinearEvalInstruction;
use p3_symmetric::Permutation;
use poseidon16::Poseidon2_16Instruction;
use poseidon24::Poseidon2_24Instruction;
Expand All @@ -15,15 +16,13 @@ use crate::{

pub mod computation;
pub mod deref;
pub mod extension_mul;
pub mod dot_product;
pub mod jump;
pub mod multilinear_eval;
pub mod poseidon16;
pub mod poseidon24;

/// Defines the instruction set for this zkVM, specialized for the `AggregateMerge` logic.
///
/// The ISA is minimal and includes basic arithmetic, memory operations, control flow,
/// and powerful precompiles for hashing and extension field arithmetic.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Instruction {
/// Performs a basic arithmetic computation: `res = arg_a op arg_b`.
Expand Down Expand Up @@ -53,10 +52,12 @@ pub enum Instruction {
///
/// It reads 6 pointers from memory, starting at `m[fp+shift]`.
Poseidon2_24(Poseidon2_24Instruction),
/// **Precompile** for multiplication in the degree-8 extension field.
///
/// This is important for speeding up recursive proof verification (`snark_verify`).
ExtensionMul(ExtensionMulInstruction),

/// Dot product of two vectors of extension field elements.
DotProduct(DotProductInstruction),

/// Evaluation of a multilinear polynomial over the extension field.
MultilinearEval(MultilinearEvalInstruction),
}

impl Instruction {
Expand Down Expand Up @@ -100,8 +101,10 @@ impl Instruction {
Self::Poseidon2_24(instruction) => {
instruction.execute(run_context, memory_manager, perm24)
}
// Handle the extension field multiplication precompile.
Self::ExtensionMul(instruction) => instruction.execute(run_context, memory_manager),
// Handle the dot product precompile.
Self::DotProduct(instruction) => instruction.execute(run_context, memory_manager),
// Handle the multilinear evaluation precompile.
Self::MultilinearEval(instruction) => instruction.execute(run_context, memory_manager),
}
}
}
79 changes: 79 additions & 0 deletions crates/leanVm/src/bytecode/instruction/multilinear_eval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use p3_field::BasedVectorSpace;
use whir_p3::poly::{coeffs::CoefficientList, multilinear::MultilinearPoint};

use crate::{
bytecode::operand::{MemOrConstant, MemOrFp},
constant::{DIMENSION, EF, F},
context::run_context::RunContext,
errors::vm::VirtualMachineError,
memory::{address::MemoryAddress, manager::MemoryManager},
};

/// An instruction to evaluate a multilinear polynomial at a point in the extension field.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MultilinearEvalInstruction {
/// A pointer to the polynomial's coefficients.
pub coeffs: MemOrConstant,
/// A pointer to the evaluation point's coordinates.
pub point: MemOrConstant,
/// The destination pointer for the result.
pub res: MemOrFp,
/// The number of variables in the multilinear polynomial.
pub n_vars: usize,
}

impl MultilinearEvalInstruction {
/// Executes the `MultilinearEval` instruction.
///
/// This function performs the following steps:
/// 1. Resolves pointers to the polynomial coefficients, evaluation point, and output location.
/// 2. Reads the polynomial coefficients (base field elements) from memory.
/// 3. Reads the evaluation point (extension field elements) from memory.
/// 4. Evaluates the polynomial at the given point.
/// 5. Writes the resulting extension field element back to memory.
pub fn execute(
&self,
run_context: &RunContext,
memory_manager: &mut MemoryManager,
) -> Result<(), VirtualMachineError> {
// Resolve the memory addresses for the coefficients, point, and result.
let ptr_coeffs: MemoryAddress = run_context
.value_from_mem_or_constant(&self.coeffs, memory_manager)?
.try_into()?;
let ptr_point: MemoryAddress = run_context
.value_from_mem_or_constant(&self.point, memory_manager)?
.try_into()?;
let ptr_res: MemoryAddress = run_context
.value_from_mem_or_fp(&self.res, memory_manager)?
.try_into()?;

// Read the polynomial coefficients from memory.
//
// The total number of coefficients is 2^n_vars.
let num_coeffs = 1 << self.n_vars;
let slice_coeffs: Vec<F> = (0..num_coeffs)
.map(|i| {
let addr = (ptr_coeffs + i)?;
memory_manager.memory.get_as(addr)
})
.collect::<Result<_, _>>()?;

// Read the evaluation point from memory.
let point: Vec<EF> = (0..self.n_vars)
.map(|i| {
let addr = (ptr_point + i)?;
let vector_coeffs = memory_manager.memory.get_array_as::<F, DIMENSION>(addr)?;
EF::from_basis_coefficients_slice(&vector_coeffs)
.ok_or(VirtualMachineError::InvalidExtensionField)
})
.collect::<Result<_, _>>()?;

// Evaluate the multilinear polynomial.
let eval = CoefficientList::new(slice_coeffs).evaluate(&MultilinearPoint(point));

// Write the resulting vector back to memory.
memory_manager.load_data::<F>(ptr_res, eval.as_basis_coefficients_slice())?;

Ok(())
}
}
8 changes: 0 additions & 8 deletions crates/leanVm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub struct VirtualMachine<Perm16, Perm24> {
pub(crate) cpu_cycles: u64,
pub(crate) poseidon16_calls: u64,
pub(crate) poseidon24_calls: u64,
pub(crate) ext_mul_calls: u64,
// A string buffer to hold output from the Print hint.
pub(crate) std_out: String,
}
Expand All @@ -52,7 +51,6 @@ where
cpu_cycles: 0,
poseidon16_calls: 0,
poseidon24_calls: 0,
ext_mul_calls: 0,
std_out: String::new(),
}
}
Expand Down Expand Up @@ -289,7 +287,6 @@ where
self.cpu_cycles = 0;
self.poseidon16_calls = 0;
self.poseidon24_calls = 0;
self.ext_mul_calls = 0;
self.std_out.clear();
}

Expand All @@ -298,7 +295,6 @@ where
match instruction {
Instruction::Poseidon2_16(_) => self.poseidon16_calls += 1,
Instruction::Poseidon2_24(_) => self.poseidon24_calls += 1,
Instruction::ExtensionMul(_) => self.ext_mul_calls += 1,
_ => (), // Other instructions do not have special counters.
}
}
Expand Down Expand Up @@ -412,10 +408,6 @@ where
self.cpu_cycles / total_poseidon_calls
);
}

if self.ext_mul_calls > 0 {
println!("ExtensionMul calls: {}", self.ext_mul_calls,);
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/leanVm/src/errors/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ pub enum VirtualMachineError {
TooManyUnknownOperands,
#[error("Program counter (pc) is out of bounds.")]
PCOutOfBounds,
#[error("Invalid extensionn field.")]
InvalidExtensionField,
}