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