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}