Skip to content

Commit 5dd2a71

Browse files
authored
instructions: update the precompiles (#11)
1 parent 97bd5bd commit 5dd2a71

File tree

8 files changed

+181
-99
lines changed

8 files changed

+181
-99
lines changed

Cargo.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ lean-isa = { path = "crates/leanIsa" }
3636
lean-snark = { path = "crates/leanSnark" }
3737
lean-vm = { path = "crates/leanVm" }
3838

39-
p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
40-
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
41-
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
42-
p3-koala-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
43-
p3-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
44-
p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "d0c4a36" }
39+
p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
40+
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
41+
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
42+
p3-koala-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
43+
p3-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
44+
p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "5ebf8e4" }
45+
46+
whir-p3 = { git = "https://github.com/tcoratger/whir-p3.git", rev = "df2241d" }
4547

4648
thiserror = "2.0"
4749
proptest = "1.7"

crates/leanVm/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ p3-symmetric.workspace = true
1616
p3-air.workspace = true
1717
p3-matrix.workspace = true
1818

19+
whir-p3.workspace = true
20+
1921
thiserror.workspace = true
2022
num-traits.workspace = true
2123

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use p3_field::{BasedVectorSpace, dot_product};
2+
3+
use crate::{
4+
bytecode::operand::{MemOrConstant, MemOrFp},
5+
constant::{DIMENSION, EF, F},
6+
context::run_context::RunContext,
7+
errors::vm::VirtualMachineError,
8+
memory::{address::MemoryAddress, manager::MemoryManager},
9+
};
10+
11+
/// An instruction to compute the dot product of two vectors of extension field elements.
12+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13+
pub struct DotProductInstruction {
14+
/// The first operand, a pointer to the start of the first vector.
15+
pub arg0: MemOrConstant,
16+
/// The second operand, a pointer to the start of the second vector.
17+
pub arg1: MemOrConstant,
18+
/// The destination pointer for the result.
19+
pub res: MemOrFp,
20+
/// The number of elements in each vector.
21+
pub size: usize,
22+
}
23+
24+
impl DotProductInstruction {
25+
/// Executes the `DotProductExtensionExtension` instruction.
26+
///
27+
/// This function performs the following steps:
28+
/// 1. Resolves the pointers to the two input vectors and the output location from memory.
29+
/// 2. Reads the vector data for both operands from memory.
30+
/// 3. Computes the dot product of the two vectors in the extension field.
31+
/// 4. Writes the resulting extension field element back to the specified memory location.
32+
pub fn execute(
33+
&self,
34+
run_context: &RunContext,
35+
memory_manager: &mut MemoryManager,
36+
) -> Result<(), VirtualMachineError> {
37+
// Resolve the memory addresses for the two input vectors and the result.
38+
let ptr_arg_0: MemoryAddress = run_context
39+
.value_from_mem_or_constant(&self.arg0, memory_manager)?
40+
.try_into()?;
41+
let ptr_arg_1: MemoryAddress = run_context
42+
.value_from_mem_or_constant(&self.arg1, memory_manager)?
43+
.try_into()?;
44+
let ptr_res: MemoryAddress = run_context
45+
.value_from_mem_or_fp(&self.res, memory_manager)?
46+
.try_into()?;
47+
48+
// Read the first vector slice from memory.
49+
let slice_0: Vec<EF> = (0..self.size)
50+
.map(|i| {
51+
let addr = (ptr_arg_0 + i)?;
52+
let vector_coeffs = memory_manager.memory.get_array_as::<F, DIMENSION>(addr)?;
53+
EF::from_basis_coefficients_slice(&vector_coeffs)
54+
.ok_or(VirtualMachineError::InvalidExtensionField)
55+
})
56+
.collect::<Result<_, _>>()?;
57+
58+
// Read the second vector slice from memory.
59+
let slice_1: Vec<EF> = (0..self.size)
60+
.map(|i| {
61+
let addr = (ptr_arg_1 + i)?;
62+
let vector_coeffs = memory_manager.memory.get_array_as::<F, DIMENSION>(addr)?;
63+
EF::from_basis_coefficients_slice(&vector_coeffs)
64+
.ok_or(VirtualMachineError::InvalidExtensionField)
65+
})
66+
.collect::<Result<_, _>>()?;
67+
68+
// Compute the dot product of the two slices by converting them into iterators.
69+
let dot_product_res = dot_product::<EF, _, _>(slice_0.into_iter(), slice_1.into_iter());
70+
71+
// Write the resulting vector back to memory.
72+
memory_manager.load_data::<F>(ptr_res, dot_product_res.as_basis_coefficients_slice())?;
73+
74+
Ok(())
75+
}
76+
}

crates/leanVm/src/bytecode/instruction/extension_mul.rs

Lines changed: 0 additions & 74 deletions
This file was deleted.

crates/leanVm/src/bytecode/instruction/mod.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use computation::ComputationInstruction;
22
use deref::DerefInstruction;
3-
use extension_mul::ExtensionMulInstruction;
3+
use dot_product::DotProductInstruction;
44
use jump::JumpIfNotZeroInstruction;
5+
use multilinear_eval::MultilinearEvalInstruction;
56
use p3_symmetric::Permutation;
67
use poseidon16::Poseidon2_16Instruction;
78
use poseidon24::Poseidon2_24Instruction;
@@ -15,15 +16,13 @@ use crate::{
1516

1617
pub mod computation;
1718
pub mod deref;
18-
pub mod extension_mul;
19+
pub mod dot_product;
1920
pub mod jump;
21+
pub mod multilinear_eval;
2022
pub mod poseidon16;
2123
pub mod poseidon24;
2224

2325
/// Defines the instruction set for this zkVM, specialized for the `AggregateMerge` logic.
24-
///
25-
/// The ISA is minimal and includes basic arithmetic, memory operations, control flow,
26-
/// and powerful precompiles for hashing and extension field arithmetic.
2726
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2827
pub enum Instruction {
2928
/// Performs a basic arithmetic computation: `res = arg_a op arg_b`.
@@ -53,10 +52,12 @@ pub enum Instruction {
5352
///
5453
/// It reads 6 pointers from memory, starting at `m[fp+shift]`.
5554
Poseidon2_24(Poseidon2_24Instruction),
56-
/// **Precompile** for multiplication in the degree-8 extension field.
57-
///
58-
/// This is important for speeding up recursive proof verification (`snark_verify`).
59-
ExtensionMul(ExtensionMulInstruction),
55+
56+
/// Dot product of two vectors of extension field elements.
57+
DotProduct(DotProductInstruction),
58+
59+
/// Evaluation of a multilinear polynomial over the extension field.
60+
MultilinearEval(MultilinearEvalInstruction),
6061
}
6162

6263
impl Instruction {
@@ -100,8 +101,10 @@ impl Instruction {
100101
Self::Poseidon2_24(instruction) => {
101102
instruction.execute(run_context, memory_manager, perm24)
102103
}
103-
// Handle the extension field multiplication precompile.
104-
Self::ExtensionMul(instruction) => instruction.execute(run_context, memory_manager),
104+
// Handle the dot product precompile.
105+
Self::DotProduct(instruction) => instruction.execute(run_context, memory_manager),
106+
// Handle the multilinear evaluation precompile.
107+
Self::MultilinearEval(instruction) => instruction.execute(run_context, memory_manager),
105108
}
106109
}
107110
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use p3_field::BasedVectorSpace;
2+
use whir_p3::poly::{coeffs::CoefficientList, multilinear::MultilinearPoint};
3+
4+
use crate::{
5+
bytecode::operand::{MemOrConstant, MemOrFp},
6+
constant::{DIMENSION, EF, F},
7+
context::run_context::RunContext,
8+
errors::vm::VirtualMachineError,
9+
memory::{address::MemoryAddress, manager::MemoryManager},
10+
};
11+
12+
/// An instruction to evaluate a multilinear polynomial at a point in the extension field.
13+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14+
pub struct MultilinearEvalInstruction {
15+
/// A pointer to the polynomial's coefficients.
16+
pub coeffs: MemOrConstant,
17+
/// A pointer to the evaluation point's coordinates.
18+
pub point: MemOrConstant,
19+
/// The destination pointer for the result.
20+
pub res: MemOrFp,
21+
/// The number of variables in the multilinear polynomial.
22+
pub n_vars: usize,
23+
}
24+
25+
impl MultilinearEvalInstruction {
26+
/// Executes the `MultilinearEval` instruction.
27+
///
28+
/// This function performs the following steps:
29+
/// 1. Resolves pointers to the polynomial coefficients, evaluation point, and output location.
30+
/// 2. Reads the polynomial coefficients (base field elements) from memory.
31+
/// 3. Reads the evaluation point (extension field elements) from memory.
32+
/// 4. Evaluates the polynomial at the given point.
33+
/// 5. Writes the resulting extension field element back to memory.
34+
pub fn execute(
35+
&self,
36+
run_context: &RunContext,
37+
memory_manager: &mut MemoryManager,
38+
) -> Result<(), VirtualMachineError> {
39+
// Resolve the memory addresses for the coefficients, point, and result.
40+
let ptr_coeffs: MemoryAddress = run_context
41+
.value_from_mem_or_constant(&self.coeffs, memory_manager)?
42+
.try_into()?;
43+
let ptr_point: MemoryAddress = run_context
44+
.value_from_mem_or_constant(&self.point, memory_manager)?
45+
.try_into()?;
46+
let ptr_res: MemoryAddress = run_context
47+
.value_from_mem_or_fp(&self.res, memory_manager)?
48+
.try_into()?;
49+
50+
// Read the polynomial coefficients from memory.
51+
//
52+
// The total number of coefficients is 2^n_vars.
53+
let num_coeffs = 1 << self.n_vars;
54+
let slice_coeffs: Vec<F> = (0..num_coeffs)
55+
.map(|i| {
56+
let addr = (ptr_coeffs + i)?;
57+
memory_manager.memory.get_as(addr)
58+
})
59+
.collect::<Result<_, _>>()?;
60+
61+
// Read the evaluation point from memory.
62+
let point: Vec<EF> = (0..self.n_vars)
63+
.map(|i| {
64+
let addr = (ptr_point + i)?;
65+
let vector_coeffs = memory_manager.memory.get_array_as::<F, DIMENSION>(addr)?;
66+
EF::from_basis_coefficients_slice(&vector_coeffs)
67+
.ok_or(VirtualMachineError::InvalidExtensionField)
68+
})
69+
.collect::<Result<_, _>>()?;
70+
71+
// Evaluate the multilinear polynomial.
72+
let eval = CoefficientList::new(slice_coeffs).evaluate(&MultilinearPoint(point));
73+
74+
// Write the resulting vector back to memory.
75+
memory_manager.load_data::<F>(ptr_res, eval.as_basis_coefficients_slice())?;
76+
77+
Ok(())
78+
}
79+
}

crates/leanVm/src/core.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ pub struct VirtualMachine<Perm16, Perm24> {
2929
pub(crate) cpu_cycles: u64,
3030
pub(crate) poseidon16_calls: u64,
3131
pub(crate) poseidon24_calls: u64,
32-
pub(crate) ext_mul_calls: u64,
3332
// A string buffer to hold output from the Print hint.
3433
pub(crate) std_out: String,
3534
}
@@ -52,7 +51,6 @@ where
5251
cpu_cycles: 0,
5352
poseidon16_calls: 0,
5453
poseidon24_calls: 0,
55-
ext_mul_calls: 0,
5654
std_out: String::new(),
5755
}
5856
}
@@ -289,7 +287,6 @@ where
289287
self.cpu_cycles = 0;
290288
self.poseidon16_calls = 0;
291289
self.poseidon24_calls = 0;
292-
self.ext_mul_calls = 0;
293290
self.std_out.clear();
294291
}
295292

@@ -298,7 +295,6 @@ where
298295
match instruction {
299296
Instruction::Poseidon2_16(_) => self.poseidon16_calls += 1,
300297
Instruction::Poseidon2_24(_) => self.poseidon24_calls += 1,
301-
Instruction::ExtensionMul(_) => self.ext_mul_calls += 1,
302298
_ => (), // Other instructions do not have special counters.
303299
}
304300
}
@@ -412,10 +408,6 @@ where
412408
self.cpu_cycles / total_poseidon_calls
413409
);
414410
}
415-
416-
if self.ext_mul_calls > 0 {
417-
println!("ExtensionMul calls: {}", self.ext_mul_calls,);
418-
}
419411
}
420412
}
421413

crates/leanVm/src/errors/vm.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ pub enum VirtualMachineError {
2424
TooManyUnknownOperands,
2525
#[error("Program counter (pc) is out of bounds.")]
2626
PCOutOfBounds,
27+
#[error("Invalid extensionn field.")]
28+
InvalidExtensionField,
2729
}

0 commit comments

Comments
 (0)