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, instruction};
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 /// Deserializes the bits into a value.
94 DeserializeBits(DeserializeBits<N>),
95 /// Deserializes the raw bits into a value.
96 DeserializeBitsRaw(DeserializeBitsRaw<N>),
97 /// Divides `first` by `second`, storing the outcome in `destination`.
98 Div(Div<N>),
99 /// Divides `first` by `second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
100 DivWrapped(DivWrapped<N>),
101 /// Doubles `first`, storing the outcome in `destination`.
102 Double(Double<N>),
103 /// Computes whether `signature` is valid for the given `signer` and `digest` using ECDSA.
104 ECDSAVerifyDigest(ECDSAVerifyDigest<N>),
105 /// Computes whether `signature` is valid for the given Ethereum `address` and `digest` using ECDSA.
106 ECDSAVerifyDigestEth(ECDSAVerifyDigestEth<N>),
107 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with Keccak256.
108 ECDSAVerifyKeccak256(ECDSAVerifyKeccak256<N>),
109 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with Keccak256 and raw inputs.
110 ECDSAVerifyKeccak256Raw(ECDSAVerifyKeccak256Raw<N>),
111 /// Computes whether `signature` is valid for the given Ethereum `address` and `message` using ECDSA with Keccak256 and raw inputs.
112 ECDSAVerifyKeccak256Eth(ECDSAVerifyKeccak256Eth<N>),
113 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with Keccak384.
114 ECDSAVerifyKeccak384(ECDSAVerifyKeccak384<N>),
115 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with Keccak384 and raw inputs.
116 ECDSAVerifyKeccak384Raw(ECDSAVerifyKeccak384Raw<N>),
117 /// Computes whether `signature` is valid for the given Ethereum `address` and `message` using ECDSA with Keccak384 and raw inputs.
118 ECDSAVerifyKeccak384Eth(ECDSAVerifyKeccak384Eth<N>),
119 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with Keccak512.
120 ECDSAVerifyKeccak512(ECDSAVerifyKeccak512<N>),
121 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with Keccak512 and raw inputs.
122 ECDSAVerifyKeccak512Raw(ECDSAVerifyKeccak512Raw<N>),
123 /// Computes whether `signature` is valid for the given Ethereum `address` and `message` using ECDSA with Keccak512 and raw inputs.
124 ECDSAVerifyKeccak512Eth(ECDSAVerifyKeccak512Eth<N>),
125 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with SHA3-256.
126 ECDSAVerifySha3_256(ECDSAVerifySha3_256<N>),
127 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with SHA3-256 and raw inputs.
128 ECDSAVerifySha3_256Raw(ECDSAVerifySha3_256Raw<N>),
129 /// Computes whether `signature` is valid for the given Ethereum `address` and `message` using ECDSA with SHA3-256 and raw inputs.
130 ECDSAVerifySha3_256Eth(ECDSAVerifySha3_256Eth<N>),
131 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with SHA3-384.
132 ECDSAVerifySha3_384(ECDSAVerifySha3_384<N>),
133 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with SHA3-384 and raw inputs.
134 ECDSAVerifySha3_384Raw(ECDSAVerifySha3_384Raw<N>),
135 /// Computes whether `signature` is valid for the given Ethereum `address` and `message` using ECDSA with SHA3-384 and raw inputs.
136 ECDSAVerifySha3_384Eth(ECDSAVerifySha3_384Eth<N>),
137 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with SHA3-512.
138 ECDSAVerifySha3_512(ECDSAVerifySha3_512<N>),
139 /// Computes whether `signature` is valid for the given `signer` and `message` using ECDSA with SHA3-512 and raw inputs.
140 ECDSAVerifySha3_512Raw(ECDSAVerifySha3_512Raw<N>),
141 /// Computes whether `signature` is valid for the given Ethereum `address` and `message` using ECDSA with SHA3-512 and raw inputs.
142 ECDSAVerifySha3_512Eth(ECDSAVerifySha3_512Eth<N>),
143 /// Computes whether `first` is greater than `second` as a boolean, storing the outcome in `destination`.
144 GreaterThan(GreaterThan<N>),
145 /// Computes whether `first` is greater than or equal to `second` as a boolean, storing the outcome in `destination`.
146 GreaterThanOrEqual(GreaterThanOrEqual<N>),
147 /// Performs a BHP hash on inputs of 256-bit chunks.
148 HashBHP256(HashBHP256<N>),
149 /// Performs a BHP hash on the input's raw bits in 256-bit chunks.
150 HashBHP256Raw(HashBHP256Raw<N>),
151 /// Performs a BHP hash on inputs of 512-bit chunks.
152 HashBHP512(HashBHP512<N>),
153 /// Performs a BHP hash on the input's raw bits in 512-bit chunks.
154 HashBHP512Raw(HashBHP512Raw<N>),
155 /// Performs a BHP hash on inputs of 768-bit chunks.
156 HashBHP768(HashBHP768<N>),
157 /// Performs a BHP hash on the input's raw bits in 768-bit chunks.
158 HashBHP768Raw(HashBHP768Raw<N>),
159 /// Performs a BHP hash on inputs of 1024-bit chunks.
160 HashBHP1024(HashBHP1024<N>),
161 /// Performs a BHP hash on the input's raw bits in 1024-bit chunks.
162 HashBHP1024Raw(HashBHP1024Raw<N>),
163 /// Performs a Keccak hash on the input, outputting 256 bits, hashing the result with BHP256.
164 HashKeccak256(HashKeccak256<N>),
165 /// Performs a Keccak hash on the input's raw bits, hashing the result with BHP256.
166 HashKeccak256Raw(HashKeccak256Raw<N>),
167 /// Performs a Keccak hash on the input, outputting 256 bits.
168 HashKeccak256Native(HashKeccak256Native<N>),
169 /// Performs a Keccak hash on the input's raw bits, outputting 256 bits.
170 HashKeccak256NativeRaw(HashKeccak256NativeRaw<N>),
171 /// Performs a Keccak hash on the input, outputting 384 bits, hashing the result with BHP512.
172 HashKeccak384(HashKeccak384<N>),
173 /// Performs a Keccak hash on the input's raw bits, outputting 384 bits, hashing the result with BHP512.
174 HashKeccak384Raw(HashKeccak384Raw<N>),
175 /// Performs a Keccak hash on the input, outputting 384 bits.
176 HashKeccak384Native(HashKeccak384Native<N>),
177 /// Performs a Keccak hash on the input's raw bits, outputting 384 bits.
178 HashKeccak384NativeRaw(HashKeccak384NativeRaw<N>),
179 /// Performs a Keccak hash on the input, outputting 512 bits, hashing the result with BHP512.
180 HashKeccak512(HashKeccak512<N>),
181 /// Performs a Keccak hash on the input's raw bits, outputting 512 bits, hashing the result with BHP512.
182 HashKeccak512Raw(HashKeccak512Raw<N>),
183 /// Performs a Keccak hash on the input, outputting 512 bits.
184 HashKeccak512Native(HashKeccak512Native<N>),
185 /// Performs a Keccak hash on the input's raw bits, outputting 512 bits.
186 HashKeccak512NativeRaw(HashKeccak512NativeRaw<N>),
187 /// Performs a Pedersen hash on up to a 64-bit input.
188 HashPED64(HashPED64<N>),
189 /// Performs a Pedersen hash on the input's raw bits up to a 64-bit input.
190 HashPED64Raw(HashPED64Raw<N>),
191 /// Performs a Pedersen hash on up to a 128-bit input.
192 HashPED128(HashPED128<N>),
193 /// Performs a Pedersen hash on the input's raw bits up to a 128-bit input.
194 HashPED128Raw(HashPED128Raw<N>),
195 /// Performs a Poseidon hash with an input rate of 2.
196 HashPSD2(HashPSD2<N>),
197 /// Performs a Poseidon hash on the input's raw fields with an input rate of 2.
198 HashPSD2Raw(HashPSD2Raw<N>),
199 /// Performs a Poseidon hash with an input rate of 4.
200 HashPSD4(HashPSD4<N>),
201 /// Performs a Poseidon hash on the input's raw fields with an input rate of 4.
202 HashPSD4Raw(HashPSD4Raw<N>),
203 /// Performs a Poseidon hash with an input rate of 8.
204 HashPSD8(HashPSD8<N>),
205 /// Performs a Poseidon hash on the input's raw fields with an input rate of 8.
206 HashPSD8Raw(HashPSD8Raw<N>),
207 /// Performs a SHA-3 hash on the input, outputting 256 bits, hashing the result with BHP256.
208 HashSha3_256(HashSha3_256<N>),
209 /// Performs a SHA-3 hash on the input's raw bits, outputting 256 bits, hashing the result with BHP256.
210 HashSha3_256Raw(HashSha3_256Raw<N>),
211 /// Performs a SHA-3 hash on the input's bits, outputting 256 bits.
212 HashSha3_256Native(HashSha3_256Native<N>),
213 /// Performs a SHA-3 hash on the input's raw bits, outputting 256 bits.
214 HashSha3_256NativeRaw(HashSha3_256NativeRaw<N>),
215 /// Performs a SHA-3 hash on the input, outputting 384 bits, hashing the result with BHP512.
216 HashSha3_384(HashSha3_384<N>),
217 /// Performs a SHA-3 hash on the input's raw bits, outputting 384 bits, hashing the result with BHP512.
218 HashSha3_384Raw(HashSha3_384Raw<N>),
219 /// Performs a SHA-3 hash on the input's bits, outputting 384 bits.
220 HashSha3_384Native(HashSha3_384Native<N>),
221 /// Performs a SHA-3 hash on the input's raw bits, outputting 384 bits.
222 HashSha3_384NativeRaw(HashSha3_384NativeRaw<N>),
223 /// Performs a SHA-3 hash, outputting 512 bits, hashing the result with BHP512.
224 HashSha3_512(HashSha3_512<N>),
225 /// Performs a SHA-3 hash on the input's raw bits, outputting 512 bits, hashing the result with BHP512.
226 HashSha3_512Raw(HashSha3_512Raw<N>),
227 /// Performs a SHA-3 hash on the input's bits, outputting 512 bits.
228 HashSha3_512Native(HashSha3_512Native<N>),
229 /// Performs a SHA-3 hash on the input's raw bits, outputting 512 bits.
230 HashSha3_512NativeRaw(HashSha3_512NativeRaw<N>),
231 /// Performs a Poseidon hash with an input rate of 2.
232 HashManyPSD2(HashManyPSD2<N>),
233 /// Performs a Poseidon hash with an input rate of 4.
234 HashManyPSD4(HashManyPSD4<N>),
235 /// Performs a Poseidon hash with an input rate of 8.
236 HashManyPSD8(HashManyPSD8<N>),
237 /// Computes the multiplicative inverse of `first`, storing the outcome in `destination`.
238 Inv(Inv<N>),
239 /// Computes whether `first` equals `second` as a boolean, storing the outcome in `destination`.
240 IsEq(IsEq<N>),
241 /// Computes whether `first` does **not** equals `second` as a boolean, storing the outcome in `destination`.
242 IsNeq(IsNeq<N>),
243 /// Computes whether `first` is less than `second` as a boolean, storing the outcome in `destination`.
244 LessThan(LessThan<N>),
245 /// Computes whether `first` is less than or equal to `second` as a boolean, storing the outcome in `destination`.
246 LessThanOrEqual(LessThanOrEqual<N>),
247 /// Computes `first` mod `second`, storing the outcome in `destination`.
248 Modulo(Modulo<N>),
249 /// Multiplies `first` with `second`, storing the outcome in `destination`.
250 Mul(Mul<N>),
251 /// Multiplies `first` with `second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
252 MulWrapped(MulWrapped<N>),
253 /// Returns `false` if `first` and `second` are true, storing the outcome in `destination`.
254 Nand(Nand<N>),
255 /// Negates `first`, storing the outcome in `destination`.
256 Neg(Neg<N>),
257 /// Returns `true` if neither `first` nor `second` is `true`, storing the outcome in `destination`.
258 Nor(Nor<N>),
259 /// Flips each bit in the representation of `first`, storing the outcome in `destination`.
260 Not(Not<N>),
261 /// Performs a bitwise `or` on `first` and `second`, storing the outcome in `destination`.
262 Or(Or<N>),
263 /// Raises `first` to the power of `second`, storing the outcome in `destination`.
264 Pow(Pow<N>),
265 /// Raises `first` to the power of `second`, wrapping around at the boundary of the type, storing the outcome in `destination`.
266 PowWrapped(PowWrapped<N>),
267 /// Divides `first` by `second`, storing the remainder in `destination`.
268 Rem(Rem<N>),
269 /// Divides `first` by `second`, wrapping around at the boundary of the type, storing the remainder in `destination`.
270 RemWrapped(RemWrapped<N>),
271 /// Serializes the bits of the input.
272 SerializeBits(SerializeBits<N>),
273 /// Serializes the raw bits of the input.
274 SerializeBitsRaw(SerializeBitsRaw<N>),
275 /// Shifts `first` left by `second` bits, storing the outcome in `destination`.
276 Shl(Shl<N>),
277 /// Shifts `first` left by `second` bits, wrapping around at the boundary of the type, storing the outcome in `destination`.
278 ShlWrapped(ShlWrapped<N>),
279 /// Shifts `first` right by `second` bits, storing the outcome in `destination`.
280 Shr(Shr<N>),
281 /// Shifts `first` right by `second` bits, wrapping around at the boundary of the type, storing the outcome in `destination`.
282 ShrWrapped(ShrWrapped<N>),
283 /// Computes whether `signature` is valid for the given `address` and `message`.
284 SignVerify(SignVerify<N>),
285 /// Squares 'first', storing the outcome in `destination`.
286 Square(Square<N>),
287 /// Compute the square root of 'first', storing the outcome in `destination`.
288 SquareRoot(SquareRoot<N>),
289 /// Computes `first - second`, storing the outcome in `destination`.
290 Sub(Sub<N>),
291 /// Computes `first - second`, wrapping around at the boundary of the type, and storing the outcome in `destination`.
292 SubWrapped(SubWrapped<N>),
293 /// Selects `first`, if `condition` is true, otherwise selects `second`, storing the result in `destination`.
294 Ternary(Ternary<N>),
295 /// Performs a bitwise `xor` on `first` and `second`, storing the outcome in `destination`.
296 Xor(Xor<N>),
297}
298
299/// Creates a match statement that applies the given operation for each instruction.
300///
301/// ## Example
302/// This example will print the opcode and the instruction to the given stream.
303/// ```rust,ignore
304/// instruction!(self, |instruction| write!(f, "{} {};", self.opcode(), instruction))
305/// ```
306/// The above example is equivalent to the following logic:
307/// ```rust,ignore
308/// match self {
309/// Self::Add(instruction) => write!(f, "{} {};", self.opcode(), instruction),
310/// Self::Sub(instruction) => write!(f, "{} {};", self.opcode(), instruction),
311/// Self::Mul(instruction) => write!(f, "{} {};", self.opcode(), instruction),
312/// Self::Div(instruction) => write!(f, "{} {};", self.opcode(), instruction),
313/// }
314/// ```
315#[macro_export]
316macro_rules! instruction {
317 // A variant **with** curly braces:
318 // i.e. `instruction!(self, |instruction| { operation(instruction) })`.
319 ($object:expr, |$input:ident| $operation:block) => {{ $crate::instruction!(instruction, $object, |$input| $operation) }};
320 // A variant **without** curly braces:
321 // i.e. `instruction!(self, |instruction| operation(instruction))`.
322 ($object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!(instruction, $object, |$input| { $operation }) }};
323 // A variant **with** curly braces:
324 // i.e. `instruction!(custom_macro, self, |instruction| { operation(instruction) })`.
325 ($macro_:ident, $object:expr, |$input:ident| $operation:block) => {
326 $macro_!{$object, |$input| $operation, {
327 // The original opcodes.
328 Abs,
329 AbsWrapped,
330 Add,
331 AddWrapped,
332 And,
333 AssertEq,
334 AssertNeq,
335 Async,
336 Call,
337 Cast,
338 CastLossy,
339 CommitBHP256,
340 CommitBHP512,
341 CommitBHP768,
342 CommitBHP1024,
343 CommitPED64,
344 CommitPED128,
345 Div,
346 DivWrapped,
347 Double,
348 GreaterThan,
349 GreaterThanOrEqual,
350 HashBHP256,
351 HashBHP512,
352 HashBHP768,
353 HashBHP1024,
354 HashKeccak256,
355 HashKeccak384,
356 HashKeccak512,
357 HashPED64,
358 HashPED128,
359 HashPSD2,
360 HashPSD4,
361 HashPSD8,
362 HashSha3_256,
363 HashSha3_384,
364 HashSha3_512,
365 HashManyPSD2,
366 HashManyPSD4,
367 HashManyPSD8,
368 Inv,
369 IsEq,
370 IsNeq,
371 LessThan,
372 LessThanOrEqual,
373 Modulo,
374 Mul,
375 MulWrapped,
376 Nand,
377 Neg,
378 Nor,
379 Not,
380 Or,
381 Pow,
382 PowWrapped,
383 Rem,
384 RemWrapped,
385 Shl,
386 ShlWrapped,
387 Shr,
388 ShrWrapped,
389 SignVerify,
390 Square,
391 SquareRoot,
392 Sub,
393 SubWrapped,
394 Ternary,
395 Xor,
396
397 // New opcodes added in `ConsensusVersion::V11`
398 DeserializeBits,
399 DeserializeBitsRaw,
400 ECDSAVerifyDigest,
401 ECDSAVerifyDigestEth,
402 ECDSAVerifyKeccak256,
403 ECDSAVerifyKeccak256Raw,
404 ECDSAVerifyKeccak256Eth,
405 ECDSAVerifyKeccak384,
406 ECDSAVerifyKeccak384Raw,
407 ECDSAVerifyKeccak384Eth,
408 ECDSAVerifyKeccak512,
409 ECDSAVerifyKeccak512Raw,
410 ECDSAVerifyKeccak512Eth,
411 ECDSAVerifySha3_256,
412 ECDSAVerifySha3_256Raw,
413 ECDSAVerifySha3_256Eth,
414 ECDSAVerifySha3_384,
415 ECDSAVerifySha3_384Raw,
416 ECDSAVerifySha3_384Eth,
417 ECDSAVerifySha3_512,
418 ECDSAVerifySha3_512Raw,
419 ECDSAVerifySha3_512Eth,
420 HashBHP256Raw,
421 HashBHP512Raw,
422 HashBHP768Raw,
423 HashBHP1024Raw,
424 HashKeccak256Raw,
425 HashKeccak256Native,
426 HashKeccak256NativeRaw,
427 HashKeccak384Raw,
428 HashKeccak384Native,
429 HashKeccak384NativeRaw,
430 HashKeccak512Raw,
431 HashKeccak512Native,
432 HashKeccak512NativeRaw,
433 HashPED64Raw,
434 HashPED128Raw,
435 HashPSD2Raw,
436 HashPSD4Raw,
437 HashPSD8Raw,
438 HashSha3_256Raw,
439 HashSha3_256Native,
440 HashSha3_256NativeRaw,
441 HashSha3_384Raw,
442 HashSha3_384Native,
443 HashSha3_384NativeRaw,
444 HashSha3_512Raw,
445 HashSha3_512Native,
446 HashSha3_512NativeRaw,
447 SerializeBits,
448 SerializeBitsRaw,
449
450 // New opcodes should be added here, with a comment on which consensus version they were added in.
451 }}
452 };
453 // A variant **without** curly braces:
454 // i.e. `instruction!(custom_macro, self, |instruction| operation(instruction))`.
455 ($macro_:ident, $object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!($macro_, $object, |$input| { $operation }) }};
456 // A variant invoking a macro internally:
457 // i.e. `instruction!(instruction_to_bytes_le!(self, writer))`.
458 ($macro_:ident!($object:expr, $input:ident)) => {{ $crate::instruction!($macro_, $object, |$input| {}) }};
459
460 ////////////////////
461 // Private Macros //
462 ////////////////////
463
464 // A static variant **with** curly braces:
465 // i.e. `instruction!(self, |InstructionMember| { InstructionMember::opcode() })`.
466 ($object:expr, |InstructionMember| $operation:block, { $( $variant:ident, )+ }) => {{
467 // Build the match cases.
468 match $object {
469 $( Self::$variant(..) => {{
470 // Set the variant to be called `InstructionMember`.
471 type InstructionMember<N> = $variant<N>;
472 // Perform the operation.
473 $operation
474 }} ),+
475 }
476 }};
477 // A static variant **without** curly braces:
478 // i.e. `instruction!(self, |InstructionMember| InstructionMember::opcode())`.
479 ($object:expr, |InstructionMember| $operation:expr, { $( $variant:ident, )+ }) => {{
480 $crate::instruction!($object, |InstructionMember| { $operation }, { $( $variant, )+ })
481 }};
482 // A non-static variant **with** curly braces:
483 // i.e. `instruction!(self, |instruction| { operation(instruction) })`.
484 ($object:expr, |$instruction:ident| $operation:block, { $( $variant:ident, )+ }) => {{
485 // Build the match cases.
486 match $object { $( Self::$variant($instruction) => { $operation } ),+ }
487 }};
488 // A non-static variant **without** curly braces:
489 // i.e. `instruction!(self, |instruction| operation(instruction))`.
490 ($object:expr, |$instruction:ident| $operation:expr, { $( $variant:ident, )+ }) => {{
491 $crate::instruction!($object, |$instruction| { $operation }, { $( $variant, )+ })
492 }};
493}
494
495/// Derives `From<Operation>` for the instruction.
496///
497/// ## Example
498/// ```ignore
499/// derive_from_operation!(Instruction, |None| {}, { Add, Sub, Mul, Div })
500/// ```
501macro_rules! derive_from_operation {
502 ($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => {
503 $(impl<N: Network> From<$variant<N>> for Instruction<N> {
504 #[inline]
505 fn from(operation: $variant<N>) -> Self {
506 Self::$variant(operation)
507 }
508 })+
509 }
510}
511instruction!(derive_from_operation, Instruction, |None| {});
512
513/// Returns a slice of all instruction opcodes.
514///
515/// ## Example
516/// ```ignore
517/// opcodes!(Instruction, |None| {}, { Add, Sub, Mul, Div })
518/// ```
519macro_rules! opcodes {
520 ($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => { [$( $variant::<N>::opcode() ),+] }
521}
522
523impl<N: Network> Instruction<N> {
524 /// The list of all instruction opcodes.
525 pub const OPCODES: &'static [Opcode] = &instruction!(opcodes, Instruction, |None| {});
526
527 /// Returns `true` if the given name is a reserved opcode.
528 pub fn is_reserved_opcode(name: &str) -> bool {
529 // Check if the given name matches any opcode (in its entirety; including past the first '.' if it exists).
530 Instruction::<N>::OPCODES.iter().any(|opcode| **opcode == name)
531 }
532
533 /// Returns the operands of the instruction.
534 #[inline]
535 pub fn operands(&self) -> &[Operand<N>] {
536 instruction!(self, |instruction| instruction.operands())
537 }
538
539 /// Returns the destination registers of the instruction.
540 #[inline]
541 pub fn destinations(&self) -> Vec<Register<N>> {
542 instruction!(self, |instruction| instruction.destinations())
543 }
544
545 /// Returns the `CallOperator` if the instruction is a `call` instruction, otherwise `None`.
546 #[inline]
547 pub fn call_operator(&self) -> Option<&CallOperator<N>> {
548 match self {
549 Self::Call(call) => Some(call.operator()),
550 _ => None,
551 }
552 }
553
554 /// Returns the opcode of the instruction.
555 #[inline]
556 pub const fn opcode(&self) -> Opcode {
557 instruction!(self, |InstructionMember| InstructionMember::<N>::opcode())
558 }
559
560 /// Evaluates the instruction.
561 #[inline]
562 pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersSigner<N>) -> Result<()> {
563 instruction!(self, |instruction| instruction.evaluate(stack, registers))
564 }
565
566 /// Executes the instruction.
567 #[inline]
568 pub fn execute<A: circuit::Aleo<Network = N>>(
569 &self,
570 stack: &impl StackTrait<N>,
571 registers: &mut impl RegistersCircuit<N, A>,
572 ) -> Result<()> {
573 instruction!(self, |instruction| instruction.execute::<A>(stack, registers))
574 }
575
576 /// Finalizes the instruction.
577 #[inline]
578 pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
579 instruction!(self, |instruction| instruction.finalize(stack, registers))
580 }
581
582 /// Returns the output type from the given input types.
583 #[inline]
584 pub fn output_types(
585 &self,
586 stack: &impl StackTrait<N>,
587 input_types: &[RegisterType<N>],
588 ) -> Result<Vec<RegisterType<N>>> {
589 instruction!(self, |instruction| instruction.output_types(stack, input_types))
590 }
591
592 /// Returns `true` if the instruction contains an array type with a size that exceeds the given maximum.
593 pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
594 // Only cast instructions may contain an explicit reference to an array.
595 // Calls may produce them, but they don't explicitly reference the type, and that's
596 // always been allowed.
597 match self {
598 Self::Cast(instruction) => instruction.cast_type().exceeds_max_array_size(max_array_size),
599 Self::SerializeBits(instruction) => instruction.destination_type().exceeds_max_array_size(max_array_size),
600 Self::SerializeBitsRaw(instruction) => {
601 instruction.destination_type().exceeds_max_array_size(max_array_size)
602 }
603 Self::DeserializeBits(instruction) => instruction.operand_type().exceeds_max_array_size(max_array_size),
604 Self::DeserializeBitsRaw(instruction) => instruction.operand_type().exceeds_max_array_size(max_array_size),
605 _ => false,
606 }
607 }
608}
609
610impl<N: Network> Debug for Instruction<N> {
611 /// Prints the instruction as a string.
612 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
613 Display::fmt(self, f)
614 }
615}
616
617impl<N: Network> Display for Instruction<N> {
618 /// Prints the instruction as a string.
619 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
620 instruction!(self, |instruction| write!(f, "{instruction};"))
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627 use console::network::MainnetV0;
628
629 type CurrentNetwork = MainnetV0;
630
631 #[test]
632 fn test_opcodes() {
633 // Sanity check the number of instructions is unchanged.
634 // Note that the number of opcodes **MUST NOT** exceed u16::MAX.
635 assert_eq!(
636 119,
637 Instruction::<CurrentNetwork>::OPCODES.len(),
638 "Update me if the number of instructions changes."
639 );
640 }
641}