Skip to content

Commit 52a0d00

Browse files
committed
whirlaway: cp vm crate
1 parent ec4cdff commit 52a0d00

File tree

5 files changed

+973
-0
lines changed

5 files changed

+973
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ members = [
1717
"crates/pcs",
1818
"crates/lookup",
1919
"crates/xmss",
20+
"crates/vm",
2021
]
2122
resolver = "3"
2223

@@ -54,6 +55,7 @@ sumcheck = { path = "crates/sumcheck" }
5455
pcs = { path = "crates/pcs" }
5556
lookup = { path = "crates/lookup" }
5657
xmss = { path = "crates/xmss" }
58+
vm = { path = "crates/vm" }
5759

5860
rand = "0.9.2"
5961
sha3 = "0.10.8"

crates/vm/Cargo.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "vm"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
license.workspace = true
7+
8+
[lints]
9+
workspace = true
10+
11+
[dependencies]
12+
pest.workspace = true
13+
pest_derive.workspace = true
14+
utils.workspace = true
15+
p3-field.workspace = true
16+
xmss.workspace = true
17+
rand.workspace = true
18+
p3-poseidon2.workspace = true
19+
p3-koala-bear.workspace = true
20+
p3-challenger.workspace = true
21+
p3-air.workspace = true
22+
p3-matrix.workspace = true
23+
p3-symmetric.workspace = true
24+
p3-util.workspace = true
25+
whir-p3.workspace = true
26+
rayon.workspace = true
27+
tracing.workspace = true
28+
air.workspace = true
29+
pcs.workspace = true
30+
p3-poseidon2-air.workspace = true
31+
lookup.workspace = true
32+
sumcheck.workspace = true

crates/vm/src/bytecode.rs

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
use crate::F;
2+
use p3_field::PrimeCharacteristicRing;
3+
use std::collections::BTreeMap;
4+
5+
pub type Label = String;
6+
7+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8+
pub struct Bytecode {
9+
pub instructions: Vec<Instruction>,
10+
pub hints: BTreeMap<usize, Vec<Hint>>, // pc -> hints
11+
pub starting_frame_memory: usize,
12+
pub ending_pc: usize,
13+
}
14+
15+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16+
pub enum MemOrConstant {
17+
Constant(F),
18+
MemoryAfterFp { offset: usize }, // m[fp + offset]
19+
}
20+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21+
pub enum MemOrFpOrConstant {
22+
MemoryAfterFp { offset: usize }, // m[fp + offset]
23+
Fp,
24+
Constant(F),
25+
}
26+
27+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
28+
pub enum MemOrFp {
29+
MemoryAfterFp { offset: usize }, // m[fp + offset]
30+
Fp,
31+
}
32+
33+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34+
pub enum Operation {
35+
Add,
36+
Mul,
37+
}
38+
39+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40+
pub enum Instruction {
41+
// 3 basic instructions
42+
Computation {
43+
operation: Operation,
44+
arg_a: MemOrConstant,
45+
arg_c: MemOrFp,
46+
res: MemOrConstant,
47+
},
48+
Deref {
49+
shift_0: usize,
50+
shift_1: usize,
51+
res: MemOrFpOrConstant,
52+
}, // res = m[m[fp + shift_0] + shift_1]
53+
JumpIfNotZero {
54+
condition: MemOrConstant,
55+
dest: MemOrConstant,
56+
updated_fp: MemOrFp,
57+
},
58+
// 4 precompiles:
59+
Poseidon2_16 {
60+
arg_a: MemOrConstant, // vectorized pointer, of size 1
61+
arg_b: MemOrConstant, // vectorized pointer, of size 1
62+
res: MemOrFp, // vectorized pointer, of size 2 (The Fp would never be used in practice)
63+
},
64+
Poseidon2_24 {
65+
arg_a: MemOrConstant, // vectorized pointer, of size 2 (2 first inputs)
66+
arg_b: MemOrConstant, // vectorized pointer, of size 1 (3rd = last input)
67+
res: MemOrFp, // vectorized pointer, of size 1 (3rd = last output) (The Fp would never be used in practice)
68+
},
69+
DotProductExtensionExtension {
70+
arg0: MemOrConstant, // vectorized pointer
71+
arg1: MemOrConstant, // vectorized pointer
72+
res: MemOrFp, // vectorized pointer, of size 1 (never Fp in practice)
73+
size: usize,
74+
},
75+
MultilinearEval {
76+
coeffs: MemOrConstant, // vectorized pointer, chunk size = 2^n_vars
77+
point: MemOrConstant, // vectorized pointer, of size `n_vars`
78+
res: MemOrFp, // vectorized pointer, of size 1 (never fp in practice)
79+
n_vars: usize,
80+
},
81+
}
82+
83+
impl Operation {
84+
pub fn compute(&self, a: F, b: F) -> F {
85+
match self {
86+
Operation::Add => a + b,
87+
Operation::Mul => a * b,
88+
}
89+
}
90+
91+
pub fn inverse_compute(&self, a: F, b: F) -> Option<F> {
92+
match self {
93+
Operation::Add => Some(a - b),
94+
Operation::Mul => {
95+
if b == F::ZERO {
96+
None
97+
} else {
98+
Some(a / b)
99+
}
100+
}
101+
}
102+
}
103+
}
104+
105+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
106+
pub enum Hint {
107+
Inverse {
108+
arg: MemOrConstant, // the value to invert (return 0 if arg is zero)
109+
res_offset: usize, // m[fp + res_offset] will contain the result
110+
},
111+
RequestMemory {
112+
offset: usize, // m[fp + offset] where the hint will be stored
113+
size: MemOrConstant, // the hint
114+
vectorized: bool,
115+
},
116+
DecomposeBits {
117+
res_offset: usize, // m[fp + res_offset..fp + res_offset + 31] will contain the decomposed bits
118+
to_decompose: MemOrConstant,
119+
},
120+
Print {
121+
line_info: String,
122+
content: Vec<MemOrConstant>,
123+
},
124+
}
125+
126+
impl MemOrConstant {
127+
pub fn zero() -> Self {
128+
MemOrConstant::Constant(F::ZERO)
129+
}
130+
131+
pub fn one() -> Self {
132+
MemOrConstant::Constant(F::ONE)
133+
}
134+
}
135+
136+
impl ToString for Bytecode {
137+
fn to_string(&self) -> String {
138+
let mut pc = 0;
139+
let mut res = String::new();
140+
for instruction in &self.instructions {
141+
for hint in self.hints.get(&pc).unwrap_or(&Vec::new()) {
142+
res.push_str(&format!("hint: {}\n", hint.to_string()));
143+
}
144+
res.push_str(&format!("{:>4}: {}\n", pc, instruction.to_string()));
145+
pc += 1;
146+
}
147+
return res;
148+
}
149+
}
150+
151+
impl ToString for MemOrConstant {
152+
fn to_string(&self) -> String {
153+
match self {
154+
Self::Constant(c) => format!("{}", c),
155+
Self::MemoryAfterFp { offset } => format!("m[fp + {}]", offset),
156+
}
157+
}
158+
}
159+
160+
impl ToString for MemOrFp {
161+
fn to_string(&self) -> String {
162+
match self {
163+
Self::MemoryAfterFp { offset } => format!("m[fp + {}]", offset),
164+
Self::Fp => "fp".to_string(),
165+
}
166+
}
167+
}
168+
169+
impl ToString for MemOrFpOrConstant {
170+
fn to_string(&self) -> String {
171+
match self {
172+
Self::MemoryAfterFp { offset } => format!("m[fp + {}]", offset),
173+
Self::Fp => "fp".to_string(),
174+
Self::Constant(c) => format!("{}", c),
175+
}
176+
}
177+
}
178+
179+
impl ToString for Operation {
180+
fn to_string(&self) -> String {
181+
match self {
182+
Self::Add => "+".to_string(),
183+
Self::Mul => "x".to_string(),
184+
}
185+
}
186+
}
187+
188+
impl ToString for Instruction {
189+
fn to_string(&self) -> String {
190+
match self {
191+
Self::Computation {
192+
operation,
193+
arg_a,
194+
arg_c,
195+
res,
196+
} => {
197+
format!(
198+
"{} = {} {} {}",
199+
res.to_string(),
200+
arg_a.to_string(),
201+
operation.to_string(),
202+
arg_c.to_string()
203+
)
204+
}
205+
Self::Deref {
206+
shift_0,
207+
shift_1,
208+
res,
209+
} => {
210+
format!("{} = m[m[fp + {}] + {}]", res.to_string(), shift_0, shift_1)
211+
}
212+
Self::DotProductExtensionExtension {
213+
arg0,
214+
arg1,
215+
res,
216+
size,
217+
} => {
218+
format!(
219+
"dot_product({}, {}, {}, {})",
220+
arg0.to_string(),
221+
arg1.to_string(),
222+
res.to_string(),
223+
size
224+
)
225+
}
226+
Self::MultilinearEval {
227+
coeffs,
228+
point,
229+
res,
230+
n_vars,
231+
} => {
232+
format!(
233+
"multilinear_eval({}, {}, {}, {})",
234+
coeffs.to_string(),
235+
point.to_string(),
236+
res.to_string(),
237+
n_vars
238+
)
239+
}
240+
Self::JumpIfNotZero {
241+
condition,
242+
dest,
243+
updated_fp,
244+
} => {
245+
format!(
246+
"if {} != 0 jump to {} with next(fp) = {}",
247+
condition.to_string(),
248+
dest.to_string(),
249+
updated_fp.to_string()
250+
)
251+
}
252+
Self::Poseidon2_16 { arg_a, arg_b, res } => {
253+
format!(
254+
"{} = poseidon2_16({}, {})",
255+
res.to_string(),
256+
arg_a.to_string(),
257+
arg_b.to_string(),
258+
)
259+
}
260+
Self::Poseidon2_24 { arg_a, arg_b, res } => {
261+
format!(
262+
"{} = poseidon2_24({}, {})",
263+
res.to_string(),
264+
arg_a.to_string(),
265+
arg_b.to_string(),
266+
)
267+
}
268+
}
269+
}
270+
}
271+
272+
impl ToString for Hint {
273+
fn to_string(&self) -> String {
274+
match self {
275+
Self::RequestMemory {
276+
offset,
277+
size,
278+
vectorized,
279+
} => {
280+
format!(
281+
"m[fp + {}] = {}({})",
282+
offset,
283+
if *vectorized { "malloc_vec" } else { "malloc" },
284+
size.to_string()
285+
)
286+
}
287+
Self::DecomposeBits {
288+
res_offset,
289+
to_decompose,
290+
} => {
291+
format!(
292+
"m[fp + {}] = decompose_bits({})",
293+
res_offset,
294+
to_decompose.to_string()
295+
)
296+
}
297+
Self::Print { line_info, content } => {
298+
format!(
299+
"print({}) for \"{}\"",
300+
content
301+
.iter()
302+
.map(|v| v.to_string())
303+
.collect::<Vec<String>>()
304+
.join(", "),
305+
line_info,
306+
)
307+
}
308+
Self::Inverse { arg, res_offset } => {
309+
format!("m[fp + {}] = inverse({})", res_offset, arg.to_string())
310+
}
311+
}
312+
}
313+
}

crates/vm/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use p3_field::extension::BinomialExtensionField;
2+
use p3_koala_bear::KoalaBear;
3+
4+
mod bytecode;
5+
mod runner;
6+
pub use bytecode::*;
7+
pub use runner::*;
8+
9+
pub const DIMENSION: usize = 8;
10+
pub type F = KoalaBear;
11+
pub type EF = BinomialExtensionField<F, DIMENSION>;
12+
13+
pub const ZERO_VEC_PTR: usize = 0; // convention (vectorized pointer of size 1, pointing to 8 zeros)
14+
pub const POSEIDON_16_NULL_HASH_PTR: usize = 2; // convention (vectorized pointer of size 2, = the 16 elements of poseidon_16(0))
15+
pub const POSEIDON_24_NULL_HASH_PTR: usize = 4; // convention (vectorized pointer of size 1, = the last 8 elements of poseidon_24(0))
16+
pub const PUBLIC_INPUT_START: usize = 5 * 8; // normal pointer

0 commit comments

Comments
 (0)