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}