openvm_native_compiler/ir/instructions.rs
1use serde::{Deserialize, Serialize};
2
3use super::{Array, Config, Ext, Felt, MemIndex, Ptr, RVar, TracedVec, Usize, Var};
4
5/// An intermediate instruction set for implementing programs.
6///
7/// Programs written in the DSL can compile both to the recursive zkVM and the R1CS or Plonk-ish
8/// circuits.
9#[derive(Debug, Clone, strum_macros::Display, Serialize, Deserialize)]
10pub enum DslIr<C: Config> {
11 // Immediates.
12 /// Assigns an immediate to a variable (var = imm).
13 ImmV(Var<C::N>, C::N),
14 /// Assigns a field immediate to a field element (felt = field imm).
15 ImmF(Felt<C::F>, C::F),
16 /// Assigns an ext field immediate to an extension field element (ext = ext field imm).
17 ImmE(Ext<C::F, C::EF>, C::EF),
18
19 // Additions.
20 /// Add two variables (var = var + var).
21 AddV(Var<C::N>, Var<C::N>, Var<C::N>),
22 /// Add a variable and an immediate (var = var + imm).
23 AddVI(Var<C::N>, Var<C::N>, C::N),
24 /// Add two field elements (felt = felt + felt).
25 AddF(Felt<C::F>, Felt<C::F>, Felt<C::F>),
26 /// Add a field element and a field immediate (felt = felt + field imm).
27 AddFI(Felt<C::F>, Felt<C::F>, C::F),
28 /// Add two extension field elements (ext = ext + ext).
29 AddE(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Ext<C::F, C::EF>),
30 /// Add an extension field element and an ext field immediate (ext = ext + ext field imm).
31 AddEI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::EF),
32 /// Add an extension field element and a field element (ext = ext + felt).
33 AddEF(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Felt<C::F>),
34 /// Add an extension field element and a field immediate (ext = ext + field imm).
35 AddEFI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::F),
36 /// Add a field element and an ext field immediate (ext = felt + ext field imm).
37 AddEFFI(Ext<C::F, C::EF>, Felt<C::F>, C::EF),
38
39 // Subtractions.
40 /// Subtracts two variables (var = var - var).
41 SubV(Var<C::N>, Var<C::N>, Var<C::N>),
42 /// Subtracts a variable and an immediate (var = var - imm).
43 SubVI(Var<C::N>, Var<C::N>, C::N),
44 /// Subtracts an immediate and a variable (var = imm - var).
45 SubVIN(Var<C::N>, C::N, Var<C::N>),
46 /// Subtracts two field elements (felt = felt - felt).
47 SubF(Felt<C::F>, Felt<C::F>, Felt<C::F>),
48 /// Subtracts a field element and a field immediate (felt = felt - field imm).
49 SubFI(Felt<C::F>, Felt<C::F>, C::F),
50 /// Subtracts a field immediate and a field element (felt = field imm - felt).
51 SubFIN(Felt<C::F>, C::F, Felt<C::F>),
52 /// Subtracts two extension field elements (ext = ext - ext).
53 SubE(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Ext<C::F, C::EF>),
54 /// Subtracts an extension field element and an extension field immediate (ext = ext - ext
55 /// field imm).
56 SubEI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::EF),
57 /// Subtracts an extension field immediate and an extension field element (ext = ext field imm
58 /// - ext).
59 SubEIN(Ext<C::F, C::EF>, C::EF, Ext<C::F, C::EF>),
60 /// Subtracts an extension field element and a field immediate (ext = ext - field imm).
61 SubEFI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::F),
62 /// Subtracts an extension field element and a field element (ext = ext - felt).
63 SubEF(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Felt<C::F>),
64
65 // Multiplications.
66 /// Multiplies two variables (var = var * var).
67 MulV(Var<C::N>, Var<C::N>, Var<C::N>),
68 /// Multiplies a variable and an immediate (var = var * imm).
69 MulVI(Var<C::N>, Var<C::N>, C::N),
70 /// Multiplies two field elements (felt = felt * felt).
71 MulF(Felt<C::F>, Felt<C::F>, Felt<C::F>),
72 /// Multiplies a field element and a field immediate (felt = felt * field imm).
73 MulFI(Felt<C::F>, Felt<C::F>, C::F),
74 /// Multiplies two extension field elements (ext = ext * ext).
75 MulE(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Ext<C::F, C::EF>),
76 /// Multiplies an extension field element and an extension field immediate (ext = ext * ext
77 /// field imm).
78 MulEI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::EF),
79 /// Multiplies an extension field element and a field immediate (ext = ext * field imm).
80 MulEFI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::F),
81 /// Multiplies an extension field element and a field element (ext = ext * felt).
82 MulEF(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Felt<C::F>),
83
84 // Divisions.
85 /// Divides two variables (var = var / var).
86 DivF(Felt<C::F>, Felt<C::F>, Felt<C::F>),
87 /// Divides a field element and a field immediate (felt = felt / field imm).
88 DivFI(Felt<C::F>, Felt<C::F>, C::F),
89 /// Divides a field immediate and a field element (felt = field imm / felt).
90 DivFIN(Felt<C::F>, C::F, Felt<C::F>),
91 /// Divides two extension field elements (ext = ext / ext).
92 DivE(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Ext<C::F, C::EF>),
93 /// Divides an extension field element and an extension field immediate (ext = ext / ext field
94 /// imm).
95 DivEI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::EF),
96 /// Divides and extension field immediate and an extension field element (ext = ext field imm /
97 /// ext).
98 DivEIN(Ext<C::F, C::EF>, C::EF, Ext<C::F, C::EF>),
99 /// Divides an extension field element and a field immediate (ext = ext / field imm).
100 DivEFI(Ext<C::F, C::EF>, Ext<C::F, C::EF>, C::F),
101 /// Divides an extension field element and a field element (ext = ext / felt).
102 DivEF(Ext<C::F, C::EF>, Ext<C::F, C::EF>, Felt<C::F>),
103
104 // Negations.
105 /// Negates a variable (var = -var).
106 NegV(Var<C::N>, Var<C::N>),
107 /// Negates a field element (felt = -felt).
108 NegF(Felt<C::F>, Felt<C::F>),
109 /// Negates an extension field element (ext = -ext).
110 NegE(Ext<C::F, C::EF>, Ext<C::F, C::EF>),
111
112 /// Cast a Felt to a Var.
113 CastFV(Var<C::N>, Felt<C::F>),
114 /// Cast a Var to a Felt. This is unsafe because of possible overflow. Dynamic mode only.
115 UnsafeCastVF(Felt<C::F>, Var<C::N>),
116
117 // =======
118
119 // Control flow.
120 /// Executes a zipped iterator for loop over pointers with the parameters
121 /// (start step values, end step value of first pointer, step sizes, step variables, body).
122 ZipFor(
123 Vec<RVar<C::N>>,
124 RVar<C::N>,
125 Vec<C::N>,
126 Vec<Var<C::N>>,
127 TracedVec<DslIr<C>>,
128 ),
129
130 /// Executes an equal conditional branch with the parameters (lhs var, rhs var, then body, else
131 /// body).
132 IfEq(
133 Var<C::N>,
134 Var<C::N>,
135 TracedVec<DslIr<C>>,
136 TracedVec<DslIr<C>>,
137 ),
138 /// Executes a not equal conditional branch with the parameters (lhs var, rhs var, then body,
139 /// else body).
140 IfNe(
141 Var<C::N>,
142 Var<C::N>,
143 TracedVec<DslIr<C>>,
144 TracedVec<DslIr<C>>,
145 ),
146 /// Executes an equal conditional branch with the parameters (lhs var, rhs imm, then body, else
147 /// body).
148 IfEqI(Var<C::N>, C::N, TracedVec<DslIr<C>>, TracedVec<DslIr<C>>),
149 /// Executes a not equal conditional branch with the parameters (lhs var, rhs imm, then body,
150 /// else body).
151 IfNeI(Var<C::N>, C::N, TracedVec<DslIr<C>>, TracedVec<DslIr<C>>),
152
153 // Assertions.
154 /// Assert that two variables are equal (var == var).
155 AssertEqV(Var<C::N>, Var<C::N>),
156 /// Assert that two field elements are equal (felt == felt).
157 AssertEqF(Felt<C::F>, Felt<C::F>),
158 /// Assert that two extension field elements are equal (ext == ext).
159 AssertEqE(Ext<C::F, C::EF>, Ext<C::F, C::EF>),
160 /// Assert that a variable is equal to an immediate (var == imm).
161 AssertEqVI(Var<C::N>, C::N),
162 /// Assert that a field element is equal to a field immediate (felt == field imm).
163 AssertEqFI(Felt<C::F>, C::F),
164 /// Assert that an extension field element is equal to an extension field immediate (ext == ext
165 /// field imm).
166 AssertEqEI(Ext<C::F, C::EF>, C::EF),
167
168 /// Assert that a usize is not zero (usize != 0).
169 AssertNonZero(Usize<C::N>),
170
171 // Memory instructions.
172 /// Allocate (ptr, len, size) a memory slice of length len
173 Alloc(Ptr<C::N>, RVar<C::N>, usize),
174 /// Load variable (var, ptr, index)
175 LoadV(Var<C::N>, Ptr<C::N>, MemIndex<C::N>),
176 /// Load field element (var, ptr, index)
177 LoadF(Felt<C::F>, Ptr<C::N>, MemIndex<C::N>),
178 /// Load extension field
179 LoadE(Ext<C::F, C::EF>, Ptr<C::N>, MemIndex<C::N>),
180 /// Load heap pointer into a stack variable. ASM only.
181 LoadHeapPtr(Ptr<C::N>),
182 /// Store variable at address
183 StoreV(Var<C::N>, Ptr<C::N>, MemIndex<C::N>),
184 /// Store field element at address
185 StoreF(Felt<C::F>, Ptr<C::N>, MemIndex<C::N>),
186 /// Store extension field at address
187 StoreE(Ext<C::F, C::EF>, Ptr<C::N>, MemIndex<C::N>),
188 /// Store heap pointer. ASM only.
189 StoreHeapPtr(Ptr<C::N>),
190
191 // Bits.
192 /// Decompose a field element into bits (bits = num2bits(felt)). Should only be used when
193 /// target is a circuit.
194 CircuitNum2BitsF(Felt<C::F>, Vec<Var<C::N>>),
195 /// Decompose a Var into 16-bit limbs.
196 CircuitVarTo64BitsF(Var<C::N>, [Felt<C::F>; 4]),
197
198 // Hashing.
199 /// Permutes an array of baby bear elements using Poseidon2 (output = p2_permute(array)).
200 Poseidon2PermuteBabyBear(Array<C, Felt<C::F>>, Array<C, Felt<C::F>>),
201 /// Compresses two baby bear element arrays using Poseidon2 (output = p2_compress(array1,
202 /// array2)).
203 Poseidon2CompressBabyBear(
204 Array<C, Felt<C::F>>,
205 Array<C, Felt<C::F>>,
206 Array<C, Felt<C::F>>,
207 ),
208 /// Permutes an array of Bn254 elements using Poseidon2 (output = p2_permute(array)). Should
209 /// only be used when target is a circuit.
210 CircuitPoseidon2Permute([Var<C::N>; 3]),
211
212 // Miscellaneous instructions.
213 /// Prints a variable.
214 PrintV(Var<C::N>),
215 /// Prints a field element.
216 PrintF(Felt<C::F>),
217 /// Prints an extension field element.
218 PrintE(Ext<C::F, C::EF>),
219 /// Throws an error.
220 Error(),
221
222 /// Prepare next input vector (preceded by its length) for hinting.
223 HintInputVec(),
224 /// Prepare next felt for hinting
225 HintFelt(),
226 /// Prepare bit decomposition for hinting.
227 HintBitsF(Felt<C::F>, u32),
228
229 StoreHintWord(Ptr<C::N>, MemIndex<C::N>),
230 /// Move data from input stream into hint space
231 HintLoad(),
232
233 /// Witness a variable. Should only be used when target is a circuit.
234 WitnessVar(Var<C::N>, u32),
235 /// Witness a field element. Should only be used when target is a circuit.
236 WitnessFelt(Felt<C::F>, u32),
237 /// Witness an extension field element. Should only be used when target is a circuit.
238 WitnessExt(Ext<C::F, C::EF>, u32),
239 /// Label a field element as the ith public input.
240 Publish(Felt<C::F>, Var<C::N>),
241 /// Operation to halt the program. Should be the last instruction in the program.
242 Halt,
243
244 // Public inputs for circuits.
245 /// Publish a field element as the ith public value. Should only be used when target is a
246 /// circuit.
247 CircuitPublish(Var<C::N>, usize),
248
249 // FRI specific instructions.
250 /// Select's a variable based on a condition. (select(cond, true_val, false_val) => output).
251 /// Should only be used when target is a circuit.
252 CircuitSelectV(Var<C::N>, Var<C::N>, Var<C::N>, Var<C::N>),
253 /// Select's a field element based on a condition. (select(cond, true_val, false_val) =>
254 /// output). Should only be used when target is a circuit.
255 CircuitSelectF(Var<C::N>, Felt<C::F>, Felt<C::F>, Felt<C::F>),
256 /// Select's an extension field element based on a condition. (select(cond, true_val,
257 /// false_val) => output). Should only be used when target is a circuit.
258 CircuitSelectE(
259 Var<C::N>,
260 Ext<C::F, C::EF>,
261 Ext<C::F, C::EF>,
262 Ext<C::F, C::EF>,
263 ),
264 /// Converts an ext to a slice of felts. Should only be used when target is a circuit.
265 CircuitExt2Felt([Felt<C::F>; 4], Ext<C::F, C::EF>),
266 /// Converts a slice of felts to an ext. Should only be used when target is a circuit.
267 CircuitFelts2Ext([Felt<C::F>; 4], Ext<C::F, C::EF>),
268 /// Halo2 only. Reduce a Felt so later computation becomes cheaper.
269 CircuitFeltReduce(Felt<C::F>),
270 /// Halo2 only. Reduce an Ext so later computation becomes cheaper.
271 CircuitExtReduce(Ext<C::F, C::EF>),
272 /// Halo2 only. Asserts that `a, b` both have <= `C::F::bits()` and then asserts `a < b`.
273 /// Assumes that `C::F::bits() < C::N::bits()`.
274 CircuitLessThan(Var<C::N>, Var<C::N>),
275 /// FriReducedOpening(alpha, hint_id, is_init, at_x_array, at_z_array, result)
276 FriReducedOpening(
277 Ext<C::F, C::EF>,
278 Var<C::N>,
279 Var<C::N>,
280 Array<C, Felt<C::F>>,
281 Array<C, Ext<C::F, C::EF>>,
282 Ext<C::F, C::EF>,
283 ),
284 /// VerifyBatch(dim, opened, proof_id, index, commit)
285 /// opened values are Felts
286 VerifyBatchFelt(
287 Array<C, Usize<C::F>>,
288 Array<C, Array<C, Felt<C::F>>>,
289 Var<C::N>,
290 Array<C, Var<C::N>>,
291 Array<C, Felt<C::F>>,
292 ),
293 /// VerifyBatch(dim, opened, proof_id, index, commit)
294 /// opened values are Exts
295 VerifyBatchExt(
296 Array<C, Usize<C::F>>,
297 Array<C, Array<C, Ext<C::F, C::EF>>>,
298 Var<C::N>,
299 Array<C, Var<C::N>>,
300 Array<C, Felt<C::F>>,
301 ),
302 /// RangeCheckV(v, bit)
303 /// Assert that v < 2^bit.
304 RangeCheckV(Var<C::N>, usize),
305
306 /// Start the cycle tracker used by a block of code annotated by the string input. Calling this
307 /// with the same string will end the open cycle tracker instance and start a new one with
308 /// an increasing numeric postfix.
309 CycleTrackerStart(String),
310 /// End the cycle tracker used by a block of code annotated by the string input.
311 CycleTrackerEnd(String),
312}
313
314impl<C: Config> Default for DslIr<C> {
315 fn default() -> Self {
316 Self::Halt
317 }
318}