snarkvm_synthesizer_program/logic/instruction/mod.rs
1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16mod opcode;
17pub use opcode::*;
18
19mod operand;
20pub use operand::*;
21
22mod operation;
23pub use operation::*;
24
25mod bytes;
26mod parse;
27
28use crate::{RegistersCircuit, RegistersSigner, RegistersTrait, StackTrait};
29use console::{
30 network::Network,
31 prelude::{
32 Debug,
33 Display,
34 Error,
35 Formatter,
36 FromBytes,
37 FromStr,
38 IoResult,
39 Parser,
40 ParserResult,
41 Read,
42 Result,
43 Sanitizer,
44 ToBytes,
45 Write,
46 alt,
47 bail,
48 ensure,
49 error,
50 fmt,
51 map,
52 tag,
53 },
54 program::{Register, RegisterType},
55};
56
57#[derive(Clone, PartialEq, Eq, Hash)]
58pub enum Instruction<N: Network> {
59 /// Compute the absolute value of `first`, checking for overflow, and storing the outcome in `destination`.
60 Abs(Abs<N>),
61 /// Compute the absolute value of `first`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
62 AbsWrapped(AbsWrapped<N>),
63 /// Adds `first` with `second`, storing the outcome in `destination`.
64 Add(Add<N>),
65 /// Adds `first` with `second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
66 AddWrapped(AddWrapped<N>),
67 /// Performs a bitwise `and` operation on `first` and `second`, storing the outcome in `destination`.
68 And(And<N>),
69 /// Asserts `first` and `second` are equal.
70 AssertEq(AssertEq<N>),
71 /// Asserts `first` and `second` are **not** equal.
72 AssertNeq(AssertNeq<N>),
73 /// Calls a finalize asynchronously on the operands.
74 Async(Async<N>),
75 /// Calls a closure or function on the operands.
76 Call(Call<N>),
77 /// Casts the operands into the declared type.
78 Cast(Cast<N>),
79 /// Casts the operands into the declared type, with lossy truncation if applicable.
80 CastLossy(CastLossy<N>),
81 /// Performs a BHP commitment on inputs of 256-bit chunks.
82 CommitBHP256(CommitBHP256<N>),
83 /// Performs a BHP commitment on inputs of 512-bit chunks.
84 CommitBHP512(CommitBHP512<N>),
85 /// Performs a BHP commitment on inputs of 768-bit chunks.
86 CommitBHP768(CommitBHP768<N>),
87 /// Performs a BHP commitment on inputs of 1024-bit chunks.
88 CommitBHP1024(CommitBHP1024<N>),
89 /// Performs a Pedersen commitment on up to a 64-bit input.
90 CommitPED64(CommitPED64<N>),
91 /// Performs a Pedersen commitment on up to a 128-bit input.
92 CommitPED128(CommitPED128<N>),
93 /// Divides `first` by `second`, storing the outcome in `destination`.
94 Div(Div<N>),
95 /// Divides `first` by `second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
96 DivWrapped(DivWrapped<N>),
97 /// Doubles `first`, storing the outcome in `destination`.
98 Double(Double<N>),
99 /// Computes whether `first` is greater than `second` as a boolean, storing the outcome in `destination`.
100 GreaterThan(GreaterThan<N>),
101 /// Computes whether `first` is greater than or equal to `second` as a boolean, storing the outcome in `destination`.
102 GreaterThanOrEqual(GreaterThanOrEqual<N>),
103 /// Performs a BHP hash on inputs of 256-bit chunks.
104 HashBHP256(HashBHP256<N>),
105 /// Performs a BHP hash on inputs of 512-bit chunks.
106 HashBHP512(HashBHP512<N>),
107 /// Performs a BHP hash on inputs of 768-bit chunks.
108 HashBHP768(HashBHP768<N>),
109 /// Performs a BHP hash on inputs of 1024-bit chunks.
110 HashBHP1024(HashBHP1024<N>),
111 /// Performs a Keccak hash, outputting 256 bits.
112 HashKeccak256(HashKeccak256<N>),
113 /// Performs a Keccak hash, outputting 384 bits.
114 HashKeccak384(HashKeccak384<N>),
115 /// Performs a Keccak hash, outputting 512 bits.
116 HashKeccak512(HashKeccak512<N>),
117 /// Performs a Pedersen hash on up to a 64-bit input.
118 HashPED64(HashPED64<N>),
119 /// Performs a Pedersen hash on up to a 128-bit input.
120 HashPED128(HashPED128<N>),
121 /// Performs a Poseidon hash with an input rate of 2.
122 HashPSD2(HashPSD2<N>),
123 /// Performs a Poseidon hash with an input rate of 4.
124 HashPSD4(HashPSD4<N>),
125 /// Performs a Poseidon hash with an input rate of 8.
126 HashPSD8(HashPSD8<N>),
127 /// Performs a SHA-3 hash, outputting 256 bits.
128 HashSha3_256(HashSha3_256<N>),
129 /// Performs a SHA-3 hash, outputting 384 bits.
130 HashSha3_384(HashSha3_384<N>),
131 /// Performs a SHA-3 hash, outputting 512 bits.
132 HashSha3_512(HashSha3_512<N>),
133 /// Performs a Poseidon hash with an input rate of 2.
134 HashManyPSD2(HashManyPSD2<N>),
135 /// Performs a Poseidon hash with an input rate of 4.
136 HashManyPSD4(HashManyPSD4<N>),
137 /// Performs a Poseidon hash with an input rate of 8.
138 HashManyPSD8(HashManyPSD8<N>),
139 /// Computes the multiplicative inverse of `first`, storing the outcome in `destination`.
140 Inv(Inv<N>),
141 /// Computes whether `first` equals `second` as a boolean, storing the outcome in `destination`.
142 IsEq(IsEq<N>),
143 /// Computes whether `first` does **not** equals `second` as a boolean, storing the outcome in `destination`.
144 IsNeq(IsNeq<N>),
145 /// Computes whether `first` is less than `second` as a boolean, storing the outcome in `destination`.
146 LessThan(LessThan<N>),
147 /// Computes whether `first` is less than or equal to `second` as a boolean, storing the outcome in `destination`.
148 LessThanOrEqual(LessThanOrEqual<N>),
149 /// Computes `first` mod `second`, storing the outcome in `destination`.
150 Modulo(Modulo<N>),
151 /// Multiplies `first` with `second`, storing the outcome in `destination`.
152 Mul(Mul<N>),
153 /// Multiplies `first` with `second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
154 MulWrapped(MulWrapped<N>),
155 /// Returns `false` if `first` and `second` are true, storing the outcome in `destination`.
156 Nand(Nand<N>),
157 /// Negates `first`, storing the outcome in `destination`.
158 Neg(Neg<N>),
159 /// Returns `true` if neither `first` nor `second` is `true`, storing the outcome in `destination`.
160 Nor(Nor<N>),
161 /// Flips each bit in the representation of `first`, storing the outcome in `destination`.
162 Not(Not<N>),
163 /// Performs a bitwise `or` on `first` and `second`, storing the outcome in `destination`.
164 Or(Or<N>),
165 /// Raises `first` to the power of `second`, storing the outcome in `destination`.
166 Pow(Pow<N>),
167 /// Raises `first` to the power of `second`, wrapping around at the boundary of the type, storing the outcome in `destination`.
168 PowWrapped(PowWrapped<N>),
169 /// Divides `first` by `second`, storing the remainder in `destination`.
170 Rem(Rem<N>),
171 /// Divides `first` by `second`, wrapping around at the boundary of the type, storing the remainder in `destination`.
172 RemWrapped(RemWrapped<N>),
173 /// Shifts `first` left by `second` bits, storing the outcome in `destination`.
174 Shl(Shl<N>),
175 /// Shifts `first` left by `second` bits, wrapping around at the boundary of the type, storing the outcome in `destination`.
176 ShlWrapped(ShlWrapped<N>),
177 /// Shifts `first` right by `second` bits, storing the outcome in `destination`.
178 Shr(Shr<N>),
179 /// Shifts `first` right by `second` bits, wrapping around at the boundary of the type, storing the outcome in `destination`.
180 ShrWrapped(ShrWrapped<N>),
181 /// Computes whether `signature` is valid for the given `address` and `message`.
182 SignVerify(SignVerify<N>),
183 /// Squares 'first', storing the outcome in `destination`.
184 Square(Square<N>),
185 /// Compute the square root of 'first', storing the outcome in `destination`.
186 SquareRoot(SquareRoot<N>),
187 /// Computes `first - second`, storing the outcome in `destination`.
188 Sub(Sub<N>),
189 /// Computes `first - second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
190 SubWrapped(SubWrapped<N>),
191 /// Selects `first`, if `condition` is true, otherwise selects `second`, storing the result in `destination`.
192 Ternary(Ternary<N>),
193 /// Performs a bitwise `xor` on `first` and `second`, storing the outcome in `destination`.
194 Xor(Xor<N>),
195}
196
197/// Creates a match statement that applies the given operation for each instruction.
198///
199/// ## Example
200/// This example will print the opcode and the instruction to the given stream.
201/// ```rust,ignore
202/// instruction!(self, |instruction| write!(f, "{} {};", self.opcode(), instruction))
203/// ```
204/// The above example is equivalent to the following logic:
205/// ```rust,ignore
206/// match self {
207/// Self::Add(instruction) => write!(f, "{} {};", self.opcode(), instruction),
208/// Self::Sub(instruction) => write!(f, "{} {};", self.opcode(), instruction),
209/// Self::Mul(instruction) => write!(f, "{} {};", self.opcode(), instruction),
210/// Self::Div(instruction) => write!(f, "{} {};", self.opcode(), instruction),
211/// }
212/// ```
213#[macro_export]
214macro_rules! instruction {
215 // A variant **with** curly braces:
216 // i.e. `instruction!(self, |instruction| { operation(instruction) })`.
217 ($object:expr, |$input:ident| $operation:block) => {{ $crate::instruction!(instruction, $object, |$input| $operation) }};
218 // A variant **without** curly braces:
219 // i.e. `instruction!(self, |instruction| operation(instruction))`.
220 ($object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!(instruction, $object, |$input| { $operation }) }};
221 // A variant **with** curly braces:
222 // i.e. `instruction!(custom_macro, self, |instruction| { operation(instruction) })`.
223 ($macro_:ident, $object:expr, |$input:ident| $operation:block) => {
224 $macro_!{$object, |$input| $operation, {
225 Abs,
226 AbsWrapped,
227 Add,
228 AddWrapped,
229 And,
230 AssertEq,
231 AssertNeq,
232 Async,
233 Call,
234 Cast,
235 CastLossy,
236 CommitBHP256,
237 CommitBHP512,
238 CommitBHP768,
239 CommitBHP1024,
240 CommitPED64,
241 CommitPED128,
242 Div,
243 DivWrapped,
244 Double,
245 GreaterThan,
246 GreaterThanOrEqual,
247 HashBHP256,
248 HashBHP512,
249 HashBHP768,
250 HashBHP1024,
251 HashKeccak256,
252 HashKeccak384,
253 HashKeccak512,
254 HashPED64,
255 HashPED128,
256 HashPSD2,
257 HashPSD4,
258 HashPSD8,
259 HashSha3_256,
260 HashSha3_384,
261 HashSha3_512,
262 HashManyPSD2,
263 HashManyPSD4,
264 HashManyPSD8,
265 Inv,
266 IsEq,
267 IsNeq,
268 LessThan,
269 LessThanOrEqual,
270 Modulo,
271 Mul,
272 MulWrapped,
273 Nand,
274 Neg,
275 Nor,
276 Not,
277 Or,
278 Pow,
279 PowWrapped,
280 Rem,
281 RemWrapped,
282 Shl,
283 ShlWrapped,
284 Shr,
285 ShrWrapped,
286 SignVerify,
287 Square,
288 SquareRoot,
289 Sub,
290 SubWrapped,
291 Ternary,
292 Xor,
293 }}
294 };
295 // A variant **without** curly braces:
296 // i.e. `instruction!(custom_macro, self, |instruction| operation(instruction))`.
297 ($macro_:ident, $object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!($macro_, $object, |$input| { $operation }) }};
298 // A variant invoking a macro internally:
299 // i.e. `instruction!(instruction_to_bytes_le!(self, writer))`.
300 ($macro_:ident!($object:expr, $input:ident)) => {{ $crate::instruction!($macro_, $object, |$input| {}) }};
301
302 ////////////////////
303 // Private Macros //
304 ////////////////////
305
306 // A static variant **with** curly braces:
307 // i.e. `instruction!(self, |InstructionMember| { InstructionMember::opcode() })`.
308 ($object:expr, |InstructionMember| $operation:block, { $( $variant:ident, )+ }) => {{
309 // Build the match cases.
310 match $object {
311 $( Self::$variant(..) => {{
312 // Set the variant to be called `InstructionMember`.
313 type InstructionMember<N> = $variant<N>;
314 // Perform the operation.
315 $operation
316 }} ),+
317 }
318 }};
319 // A static variant **without** curly braces:
320 // i.e. `instruction!(self, |InstructionMember| InstructionMember::opcode())`.
321 ($object:expr, |InstructionMember| $operation:expr, { $( $variant:ident, )+ }) => {{
322 $crate::instruction!($object, |InstructionMember| { $operation }, { $( $variant, )+ })
323 }};
324 // A non-static variant **with** curly braces:
325 // i.e. `instruction!(self, |instruction| { operation(instruction) })`.
326 ($object:expr, |$instruction:ident| $operation:block, { $( $variant:ident, )+ }) => {{
327 // Build the match cases.
328 match $object { $( Self::$variant($instruction) => { $operation } ),+ }
329 }};
330 // A non-static variant **without** curly braces:
331 // i.e. `instruction!(self, |instruction| operation(instruction))`.
332 ($object:expr, |$instruction:ident| $operation:expr, { $( $variant:ident, )+ }) => {{
333 $crate::instruction!($object, |$instruction| { $operation }, { $( $variant, )+ })
334 }};
335}
336
337/// Derives `From<Operation>` for the instruction.
338///
339/// ## Example
340/// ```ignore
341/// derive_from_operation!(Instruction, |None| {}, { Add, Sub, Mul, Div })
342/// ```
343macro_rules! derive_from_operation {
344 ($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => {
345 $(impl<N: Network> From<$variant<N>> for Instruction<N> {
346 #[inline]
347 fn from(operation: $variant<N>) -> Self {
348 Self::$variant(operation)
349 }
350 })+
351 }
352}
353instruction!(derive_from_operation, Instruction, |None| {});
354
355/// Returns a slice of all instruction opcodes.
356///
357/// ## Example
358/// ```ignore
359/// opcodes!(Instruction, |None| {}, { Add, Sub, Mul, Div })
360/// ```
361macro_rules! opcodes {
362 ($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => { [$( $variant::<N>::opcode() ),+] }
363}
364
365impl<N: Network> Instruction<N> {
366 /// The list of all instruction opcodes.
367 pub const OPCODES: &'static [Opcode] = &instruction!(opcodes, Instruction, |None| {});
368
369 /// Returns `true` if the given name is a reserved opcode.
370 pub fn is_reserved_opcode(name: &str) -> bool {
371 // Check if the given name matches any opcode (in its entirety; including past the first '.' if it exists).
372 Instruction::<N>::OPCODES.iter().any(|opcode| **opcode == name)
373 }
374
375 /// Returns the operands of the instruction.
376 #[inline]
377 pub fn operands(&self) -> &[Operand<N>] {
378 instruction!(self, |instruction| instruction.operands())
379 }
380
381 /// Returns the destination registers of the instruction.
382 #[inline]
383 pub fn destinations(&self) -> Vec<Register<N>> {
384 instruction!(self, |instruction| instruction.destinations())
385 }
386
387 /// Returns the `CallOperator` if the instruction is a `call` instruction, otherwise `None`.
388 #[inline]
389 pub fn call_operator(&self) -> Option<&CallOperator<N>> {
390 match self {
391 Self::Call(call) => Some(call.operator()),
392 _ => None,
393 }
394 }
395
396 /// Returns the opcode of the instruction.
397 #[inline]
398 pub const fn opcode(&self) -> Opcode {
399 instruction!(self, |InstructionMember| InstructionMember::<N>::opcode())
400 }
401
402 /// Evaluates the instruction.
403 #[inline]
404 pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersSigner<N>) -> Result<()> {
405 instruction!(self, |instruction| instruction.evaluate(stack, registers))
406 }
407
408 /// Executes the instruction.
409 #[inline]
410 pub fn execute<A: circuit::Aleo<Network = N>>(
411 &self,
412 stack: &impl StackTrait<N>,
413 registers: &mut impl RegistersCircuit<N, A>,
414 ) -> Result<()> {
415 instruction!(self, |instruction| instruction.execute::<A>(stack, registers))
416 }
417
418 /// Finalizes the instruction.
419 #[inline]
420 pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
421 instruction!(self, |instruction| instruction.finalize(stack, registers))
422 }
423
424 /// Returns the output type from the given input types.
425 #[inline]
426 pub fn output_types(
427 &self,
428 stack: &impl StackTrait<N>,
429 input_types: &[RegisterType<N>],
430 ) -> Result<Vec<RegisterType<N>>> {
431 instruction!(self, |instruction| instruction.output_types(stack, input_types))
432 }
433}
434
435impl<N: Network> Debug for Instruction<N> {
436 /// Prints the instruction as a string.
437 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
438 Display::fmt(self, f)
439 }
440}
441
442impl<N: Network> Display for Instruction<N> {
443 /// Prints the instruction as a string.
444 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
445 instruction!(self, |instruction| write!(f, "{instruction};"))
446 }
447}
448
449#[cfg(test)]
450mod tests {
451 use super::*;
452 use console::network::MainnetV0;
453
454 type CurrentNetwork = MainnetV0;
455
456 #[test]
457 fn test_opcodes() {
458 // Sanity check the number of instructions is unchanged.
459 // Note that the number of opcodes **MUST NOT** exceed u16::MAX.
460 assert_eq!(
461 68,
462 Instruction::<CurrentNetwork>::OPCODES.len(),
463 "Update me if the number of instructions changes."
464 );
465 }
466}