snarkvm_synthesizer_program/logic/instruction/mod.rs
1// Copyright 2024-2025 Aleo Network Foundation
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/// ```ignore
212/// instruction!(self, |instruction| write!(f, "{} {};", self.opcode(), instruction))
213/// ```
214/// The above example is equivalent to the following logic:
215/// ```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/// ```
224#[macro_export]
225macro_rules! instruction {
226 // A variant **with** curly braces:
227 // i.e. `instruction!(self, |instruction| { operation(instruction) })`.
228 ($object:expr, |$input:ident| $operation:block) => {{ $crate::instruction!(instruction, $object, |$input| $operation) }};
229 // A variant **without** curly braces:
230 // i.e. `instruction!(self, |instruction| operation(instruction))`.
231 ($object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!(instruction, $object, |$input| { $operation }) }};
232 // A variant **with** curly braces:
233 // i.e. `instruction!(custom_macro, self, |instruction| { operation(instruction) })`.
234 ($macro_:ident, $object:expr, |$input:ident| $operation:block) => {
235 $macro_!{$object, |$input| $operation, {
236 Abs,
237 AbsWrapped,
238 Add,
239 AddWrapped,
240 And,
241 AssertEq,
242 AssertNeq,
243 Async,
244 Call,
245 Cast,
246 CastLossy,
247 CommitBHP256,
248 CommitBHP512,
249 CommitBHP768,
250 CommitBHP1024,
251 CommitPED64,
252 CommitPED128,
253 Div,
254 DivWrapped,
255 Double,
256 GreaterThan,
257 GreaterThanOrEqual,
258 HashBHP256,
259 HashBHP512,
260 HashBHP768,
261 HashBHP1024,
262 HashKeccak256,
263 HashKeccak384,
264 HashKeccak512,
265 HashPED64,
266 HashPED128,
267 HashPSD2,
268 HashPSD4,
269 HashPSD8,
270 HashSha3_256,
271 HashSha3_384,
272 HashSha3_512,
273 HashManyPSD2,
274 HashManyPSD4,
275 HashManyPSD8,
276 Inv,
277 IsEq,
278 IsNeq,
279 LessThan,
280 LessThanOrEqual,
281 Modulo,
282 Mul,
283 MulWrapped,
284 Nand,
285 Neg,
286 Nor,
287 Not,
288 Or,
289 Pow,
290 PowWrapped,
291 Rem,
292 RemWrapped,
293 Shl,
294 ShlWrapped,
295 Shr,
296 ShrWrapped,
297 SignVerify,
298 Square,
299 SquareRoot,
300 Sub,
301 SubWrapped,
302 Ternary,
303 Xor,
304 }}
305 };
306 // A variant **without** curly braces:
307 // i.e. `instruction!(custom_macro, self, |instruction| operation(instruction))`.
308 ($macro_:ident, $object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!($macro_, $object, |$input| { $operation }) }};
309 // A variant invoking a macro internally:
310 // i.e. `instruction!(instruction_to_bytes_le!(self, writer))`.
311 ($macro_:ident!($object:expr, $input:ident)) => {{ $crate::instruction!($macro_, $object, |$input| {}) }};
312
313 ////////////////////
314 // Private Macros //
315 ////////////////////
316
317 // A static variant **with** curly braces:
318 // i.e. `instruction!(self, |InstructionMember| { InstructionMember::opcode() })`.
319 ($object:expr, |InstructionMember| $operation:block, { $( $variant:ident, )+ }) => {{
320 // Build the match cases.
321 match $object {
322 $( Self::$variant(..) => {{
323 // Set the variant to be called `InstructionMember`.
324 type InstructionMember<N> = $variant<N>;
325 // Perform the operation.
326 $operation
327 }} ),+
328 }
329 }};
330 // A static variant **without** curly braces:
331 // i.e. `instruction!(self, |InstructionMember| InstructionMember::opcode())`.
332 ($object:expr, |InstructionMember| $operation:expr, { $( $variant:ident, )+ }) => {{
333 $crate::instruction!($object, |InstructionMember| { $operation }, { $( $variant, )+ })
334 }};
335 // A non-static variant **with** curly braces:
336 // i.e. `instruction!(self, |instruction| { operation(instruction) })`.
337 ($object:expr, |$instruction:ident| $operation:block, { $( $variant:ident, )+ }) => {{
338 // Build the match cases.
339 match $object { $( Self::$variant($instruction) => { $operation } ),+ }
340 }};
341 // A non-static variant **without** curly braces:
342 // i.e. `instruction!(self, |instruction| operation(instruction))`.
343 ($object:expr, |$instruction:ident| $operation:expr, { $( $variant:ident, )+ }) => {{
344 $crate::instruction!($object, |$instruction| { $operation }, { $( $variant, )+ })
345 }};
346}
347
348/// Derives `From<Operation>` for the instruction.
349///
350/// ## Example
351/// ```ignore
352/// derive_from_operation!(Instruction, |None| {}, { Add, Sub, Mul, Div })
353/// ```
354macro_rules! derive_from_operation {
355 ($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => {
356 $(impl<N: Network> From<$variant<N>> for Instruction<N> {
357 #[inline]
358 fn from(operation: $variant<N>) -> Self {
359 Self::$variant(operation)
360 }
361 })+
362 }
363}
364instruction!(derive_from_operation, Instruction, |None| {});
365
366/// Returns a slice of all instruction opcodes.
367///
368/// ## Example
369/// ```ignore
370/// opcodes!(Instruction, |None| {}, { Add, Sub, Mul, Div })
371/// ```
372macro_rules! opcodes {
373 ($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => { [$( $variant::<N>::opcode() ),+] }
374}
375
376impl<N: Network> InstructionTrait<N> for Instruction<N> {
377 /// Returns the destination registers of the instruction.
378 #[inline]
379 fn destinations(&self) -> Vec<Register<N>> {
380 instruction!(self, |instruction| instruction.destinations())
381 }
382
383 /// Returns `true` if the given name is a reserved opcode.
384 #[inline]
385 fn is_reserved_opcode(name: &str) -> bool {
386 // Check if the given name matches any opcode (in its entirety; including past the first '.' if it exists).
387 Instruction::<N>::OPCODES.iter().any(|opcode| **opcode == name)
388 }
389}
390
391impl<N: Network> Instruction<N> {
392 /// The list of all instruction opcodes.
393 pub const OPCODES: &'static [Opcode] = &instruction!(opcodes, Instruction, |None| {});
394
395 /// Returns the opcode of the instruction.
396 #[inline]
397 pub const fn opcode(&self) -> Opcode {
398 instruction!(self, |InstructionMember| InstructionMember::<N>::opcode())
399 }
400
401 /// Returns the operands of the instruction.
402 #[inline]
403 pub fn operands(&self) -> &[Operand<N>] {
404 instruction!(self, |instruction| instruction.operands())
405 }
406
407 /// Evaluates the instruction.
408 #[inline]
409 pub fn evaluate(
410 &self,
411 stack: &(impl StackMatches<N> + StackProgram<N>),
412 registers: &mut (impl RegistersSigner<N> + RegistersLoad<N> + RegistersStore<N>),
413 ) -> Result<()> {
414 instruction!(self, |instruction| instruction.evaluate(stack, registers))
415 }
416
417 /// Executes the instruction.
418 #[inline]
419 pub fn execute<A: circuit::Aleo<Network = N>>(
420 &self,
421 stack: &(impl StackMatches<N> + StackProgram<N>),
422 registers: &mut (impl RegistersSignerCircuit<N, A> + RegistersLoadCircuit<N, A> + RegistersStoreCircuit<N, A>),
423 ) -> Result<()> {
424 instruction!(self, |instruction| instruction.execute::<A>(stack, registers))
425 }
426
427 /// Finalizes the instruction.
428 #[inline]
429 pub fn finalize(
430 &self,
431 stack: &(impl StackMatches<N> + StackProgram<N>),
432 registers: &mut (impl RegistersLoad<N> + RegistersStore<N>),
433 ) -> Result<()> {
434 instruction!(self, |instruction| instruction.finalize(stack, registers))
435 }
436
437 /// Returns the output type from the given input types.
438 #[inline]
439 pub fn output_types(
440 &self,
441 stack: &impl StackProgram<N>,
442 input_types: &[RegisterType<N>],
443 ) -> Result<Vec<RegisterType<N>>> {
444 instruction!(self, |instruction| instruction.output_types(stack, input_types))
445 }
446}
447
448impl<N: Network> Debug for Instruction<N> {
449 /// Prints the instruction as a string.
450 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
451 Display::fmt(self, f)
452 }
453}
454
455impl<N: Network> Display for Instruction<N> {
456 /// Prints the instruction as a string.
457 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
458 instruction!(self, |instruction| write!(f, "{instruction};"))
459 }
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465 use console::network::MainnetV0;
466
467 type CurrentNetwork = MainnetV0;
468
469 #[test]
470 fn test_opcodes() {
471 // Sanity check the number of instructions is unchanged.
472 // Note that the number of opcodes **MUST NOT** exceed u16::MAX.
473 assert_eq!(
474 68,
475 Instruction::<CurrentNetwork>::OPCODES.len(),
476 "Update me if the number of instructions changes."
477 );
478 }
479}