Skip to content

Commit 3adeb19

Browse files
author
Gilad Chase
committed
add addap/jmp_abs/jmp_rel opcodes
1 parent 3fae126 commit 3adeb19

File tree

6 files changed

+157
-3
lines changed

6 files changed

+157
-3
lines changed

crates/prover/src/components/add_mul_opcode/component.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ impl Claim {
161161
}
162162

163163
pub fn log_sizes(&self) -> TreeVec<Vec<u32>> {
164-
let log_size = self.n_rows.next_power_of_two().ilog2();
164+
let log_size = std::cmp::max(self.n_rows.next_power_of_two().ilog2(), LOG_N_LANES);
165165
let preprocessed_log_sizes = vec![log_size];
166166
let interaction_1_log_sizes = vec![log_size; N_TRACE_COLUMNS];
167167
let interaction_2_log_sizes = vec![log_size; SECURE_EXTENSION_DEGREE * 3];
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use num_traits::One;
2+
use serde::{Deserialize, Serialize};
3+
use stwo_prover::constraint_framework::logup::LogupSums;
4+
use stwo_prover::constraint_framework::{
5+
EvalAtRow, FrameworkComponent, FrameworkEval, RelationEntry,
6+
};
7+
use stwo_prover::core::backend::simd::m31::LOG_N_LANES;
8+
use stwo_prover::core::channel::Channel;
9+
use stwo_prover::core::fields::m31::M31;
10+
use stwo_prover::core::fields::secure_column::SECURE_EXTENSION_DEGREE;
11+
use stwo_prover::core::pcs::TreeVec;
12+
13+
use crate::relations::{MemoryRelation, StateRelation};
14+
use crate::utils::component::{decode_opcode, is_trit};
15+
use crate::utils::{Selector, SelectorTrait};
16+
17+
pub const N_TRACE_CELLS: usize = 7;
18+
19+
// Assumes Opcode_base=K such that:
20+
// ```
21+
// addap_imm = K
22+
// jmp_abs_imm = K + 1
23+
// jmp_rel_imm = K + 2
24+
/// ```
25+
// TODO: organize opcodes so that K will work as detailed above, instead of just 0.
26+
pub const K: M31 = M31::from_u32_unchecked(0);
27+
28+
pub type Component = FrameworkComponent<Eval>;
29+
30+
pub struct Eval {
31+
pub claim: Claim,
32+
pub memory_lookup: MemoryRelation,
33+
pub state_lookup: StateRelation,
34+
}
35+
36+
impl FrameworkEval for Eval {
37+
fn log_size(&self) -> u32 {
38+
std::cmp::max(self.claim.n_rows.next_power_of_two().ilog2(), LOG_N_LANES)
39+
}
40+
41+
fn max_constraint_log_degree_bound(&self) -> u32 {
42+
self.log_size() + 1
43+
}
44+
45+
fn evaluate<E: EvalAtRow>(&self, mut eval: E) -> E {
46+
let state = std::array::from_fn(|_| eval.next_trace_mask());
47+
// Use initial state.
48+
eval.add_to_relation(RelationEntry::new(&self.state_lookup, E::EF::one(), &state));
49+
let [pc, ap, fp] = state;
50+
51+
// Assert flag is in range: {0,1,2}.
52+
let opcode_type = eval.next_trace_mask();
53+
eval.add_constraint(is_trit::<E>(&opcode_type));
54+
55+
// Check instruction.
56+
let opcode = decode_opcode(
57+
K.into(),
58+
&[
59+
(opcode_type.clone(), 3), // [addap, jmp_abs, jmp_rel]
60+
],
61+
);
62+
63+
let imm = eval.next_trace_mask();
64+
65+
eval.add_to_relation(RelationEntry::new(
66+
&self.memory_lookup,
67+
E::EF::one(),
68+
&[pc.clone(), opcode.clone()],
69+
));
70+
71+
// Compute new pc and new ap.
72+
// NEW_PC = { addap: pc + 1, jmp_imm: imm, jmp_rel: pc + imm }[opcode_name]
73+
let new_pc = Selector::select(
74+
&opcode_type,
75+
[
76+
&(pc.clone() + E::F::one()),
77+
&imm,
78+
&(pc.clone() + imm.clone()),
79+
],
80+
);
81+
let new_pc_value = eval.next_trace_mask();
82+
eval.add_constraint(new_pc.clone() - new_pc_value.clone());
83+
84+
// NEW_AP = { addap: ap+imm, jmp_*: ap}[opcode_name]
85+
let new_ap = Selector::select(&opcode_type, [&(ap.clone() + imm.clone()), &ap, &ap]);
86+
let new_ap_value = eval.next_trace_mask();
87+
eval.add_constraint(new_ap.clone() - new_ap_value.clone());
88+
89+
// Yield final state.
90+
let new_state = [new_pc, new_ap, fp];
91+
eval.add_to_relation(RelationEntry::new(
92+
&self.state_lookup,
93+
-E::EF::one(),
94+
&new_state,
95+
));
96+
97+
eval.finalize_logup_in_pairs();
98+
eval
99+
}
100+
}
101+
102+
#[derive(Copy, Clone, Serialize, Deserialize)]
103+
pub struct Claim {
104+
pub n_rows: usize,
105+
}
106+
107+
impl Claim {
108+
pub fn log_sizes(&self) -> TreeVec<Vec<u32>> {
109+
let log_size = std::cmp::max(self.n_rows.next_power_of_two().ilog2(), LOG_N_LANES);
110+
let preprocessed_log_sizes = vec![log_size];
111+
let trace_log_sizes = vec![log_size; N_TRACE_CELLS];
112+
let interaction_log_sizes = vec![log_size; SECURE_EXTENSION_DEGREE * 3];
113+
TreeVec::new(vec![
114+
preprocessed_log_sizes,
115+
trace_log_sizes,
116+
interaction_log_sizes,
117+
])
118+
}
119+
120+
pub fn mix_into(&self, channel: &mut impl Channel) {
121+
channel.mix_u64(self.n_rows as u64);
122+
}
123+
}
124+
125+
#[derive(Clone, Serialize, Deserialize)]
126+
pub struct InteractionClaim {
127+
pub log_size: u32,
128+
pub logup_sums: LogupSums,
129+
}
130+
impl InteractionClaim {
131+
pub fn mix_into(&self, channel: &mut impl Channel) {
132+
let (total_sum, claimed_sum) = self.logup_sums;
133+
channel.mix_felts(&[total_sum]);
134+
if let Some(claimed_sum) = claimed_sum {
135+
channel.mix_felts(&[claimed_sum.0]);
136+
channel.mix_u64(claimed_sum.1 as u64);
137+
}
138+
}
139+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod component;
2+
pub use component::{Claim, Component, Eval, InteractionClaim};

crates/prover/src/components/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod add_mul_opcode;
2+
pub mod addap_jmpabs_jmprel_opcode;
23
pub mod memory;
34
pub mod ret_opcode;
45

crates/prover/src/components/ret_opcode/component.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
33
use stwo_prover::constraint_framework::{
44
EvalAtRow, FrameworkComponent, FrameworkEval, RelationEntry,
55
};
6+
use stwo_prover::core::backend::simd::m31::LOG_N_LANES;
67
use stwo_prover::core::channel::Channel;
78
use stwo_prover::core::fields::m31::M31;
89
use stwo_prover::core::fields::qm31::SecureField;
@@ -91,7 +92,7 @@ impl Claim {
9192
}
9293

9394
pub fn log_sizes(&self) -> TreeVec<Vec<u32>> {
94-
let log_size = self.n_rows.next_power_of_two().ilog2();
95+
let log_size = std::cmp::max(self.n_rows.next_power_of_two().ilog2(), LOG_N_LANES);
9596
let interaction_0_log_sizes = vec![log_size; RET_N_TRACE_CELLS];
9697
let interaction_1_log_sizes = vec![log_size; SECURE_EXTENSION_DEGREE * 3];
9798
let fixed_log_sizes = vec![log_size];

crates/prover/src/utils/component.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::ops::{Add, Mul};
22

33
use num_traits::One;
4-
use stwo_prover::core::fields::m31::M31;
4+
use stwo_prover::constraint_framework::EvalAtRow;
5+
use stwo_prover::core::fields::m31::{BaseField, M31};
56

67
/// Decodes an opcode to its base and flags. Returns the opcode.
78
/// `flags` is a list of pairs `(flag, n_variants)`, where `flag` is the flag value and
@@ -19,6 +20,16 @@ where
1920
opcode
2021
}
2122

23+
/// Assert that `flag` is a trit (a digit in {0,1,2}).
24+
pub fn is_trit<E: EvalAtRow>(flag: &E::F) -> E::F {
25+
let two = E::F::from(BaseField::from_u32_unchecked(2));
26+
let three = E::F::from(BaseField::from_u32_unchecked(3));
27+
let f = || flag.clone();
28+
29+
// is_trit(f) := (f - 2) * (f - 1) * (f) ==expands into==> f^3 - 3*f^2 + 2*f.
30+
f() * f() * f() - three * f() * f() + two * f()
31+
}
32+
2233
#[cfg(test)]
2334
mod tests {
2435
use stwo_prover::core::fields::m31::M31;

0 commit comments

Comments
 (0)