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}