Skip to main content

snarkvm_synthesizer_program/logic/instruction/operation/
literals.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
16use crate::{Opcode, Operand, Operation, RegistersCircuit, RegistersTrait, StackTrait};
17use console::{
18    network::prelude::*,
19    program::{Literal, LiteralType, PlaintextType, Register, RegisterType},
20};
21
22use core::marker::PhantomData;
23
24/// A unary literal operation.
25pub type UnaryLiteral<N, O> = Literals<N, O, 1>;
26/// A binary literal operation.
27pub type BinaryLiteral<N, O> = Literals<N, O, 2>;
28/// A ternary literal operation.
29pub type TernaryLiteral<N, O> = Literals<N, O, 3>;
30
31#[derive(Clone, PartialEq, Eq, Hash)]
32pub struct Literals<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> {
33    /// The operands.
34    operands: Vec<Operand<N>>,
35    /// The destination register.
36    destination: Register<N>,
37    /// PhantomData.
38    _phantom: PhantomData<O>,
39}
40
41impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize>
42    Literals<N, O, NUM_OPERANDS>
43{
44    /// Returns the opcode.
45    #[inline]
46    pub const fn opcode() -> Opcode {
47        O::OPCODE
48    }
49
50    /// Returns the operands in the operation.
51    #[inline]
52    pub fn operands(&self) -> &[Operand<N>] {
53        &self.operands
54    }
55
56    /// Returns the destination register.
57    #[inline]
58    pub fn destinations(&self) -> Vec<Register<N>> {
59        vec![self.destination.clone()]
60    }
61
62    /// Returns whether this instruction refers to an external struct.
63    #[inline]
64    pub fn contains_external_struct(&self) -> bool {
65        false
66    }
67}
68
69impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize>
70    Literals<N, O, NUM_OPERANDS>
71{
72    /// Evaluates the instruction.
73    pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
74        // Ensure the number of operands is correct.
75        if self.operands.len() != NUM_OPERANDS {
76            bail!("Instruction '{}' expects {NUM_OPERANDS} operands, found {} operands", O::OPCODE, self.operands.len())
77        }
78
79        // Load the operands literals.
80        let inputs: Vec<_> =
81            self.operands.iter().map(|operand| registers.load_literal(stack, operand)).try_collect()?;
82        // Compute the operands register types.
83        let input_types: Vec<_> =
84            inputs.iter().map(|input| RegisterType::Plaintext(PlaintextType::from(input.to_type()))).collect();
85
86        // Prepare the inputs.
87        let inputs: [Literal<N>; NUM_OPERANDS] =
88            inputs.try_into().map_err(|_| anyhow!("Failed to prepare operands in evaluate"))?;
89
90        // Evaluate the operation.
91        let output = O::evaluate(&inputs)?;
92
93        // Compute the output type.
94        let output_type = RegisterType::Plaintext(PlaintextType::from(output.to_type()));
95
96        // Retrieve the expected output type.
97        let expected_types = self.output_types(stack, &input_types)?;
98        // Ensure there is exactly one output.
99        ensure!(expected_types.len() == 1, "Expected 1 output type, found {}", expected_types.len());
100        // Ensure the output type is correct.
101        ensure!(expected_types[0] == output_type, "Expected output type '{}', found {output_type}", expected_types[0]);
102
103        // Evaluate the operation and store the output.
104        registers.store_literal(stack, &self.destination, output)
105    }
106
107    /// Executes the instruction.
108    pub fn execute<A: circuit::Aleo<Network = N>>(
109        &self,
110        stack: &impl StackTrait<N>,
111        registers: &mut impl RegistersCircuit<N, A>,
112    ) -> Result<()> {
113        // Ensure the number of operands is correct.
114        if self.operands.len() != NUM_OPERANDS {
115            bail!("Instruction '{}' expects {NUM_OPERANDS} operands, found {} operands", O::OPCODE, self.operands.len())
116        }
117
118        // Load the operands literals.
119        let inputs: Vec<_> =
120            self.operands.iter().map(|operand| registers.load_literal_circuit(stack, operand)).try_collect()?;
121        // Compute the operands register types.
122        let input_types: Vec<_> =
123            inputs.iter().map(|input| RegisterType::Plaintext(PlaintextType::from(input.to_type()))).collect();
124
125        // Compute the operation.
126        let output = O::execute(&inputs.try_into().map_err(|_| anyhow!("Failed to prepare operands in execute"))?)?;
127        // Compute the output type.
128        let output_type = RegisterType::Plaintext(PlaintextType::from(output.to_type()));
129
130        // Retrieve the expected output type.
131        let expected_types = self.output_types(stack, &input_types)?;
132        // Ensure there is exactly one output.
133        ensure!(expected_types.len() == 1, "Expected 1 output type, found {}", expected_types.len());
134        // Ensure the output type is correct.
135        ensure!(expected_types[0] == output_type, "Expected output type '{}', found {output_type}", expected_types[0]);
136
137        // Evaluate the operation and store the output.
138        registers.store_literal_circuit(stack, &self.destination, output)
139    }
140
141    /// Finalizes the instruction.
142    #[inline]
143    pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
144        self.evaluate(stack, registers)
145    }
146
147    /// Returns the output type from the given program and input types.
148    pub fn output_types(
149        &self,
150        _stack: &impl StackTrait<N>,
151        input_types: &[RegisterType<N>],
152    ) -> Result<Vec<RegisterType<N>>> {
153        // Ensure the number of input types is correct.
154        if input_types.len() != NUM_OPERANDS {
155            bail!("Instruction '{}' expects {NUM_OPERANDS} inputs, found {} inputs", O::OPCODE, input_types.len())
156        }
157        // Ensure the number of operands is correct.
158        if self.operands.len() != NUM_OPERANDS {
159            bail!("Instruction '{}' expects {NUM_OPERANDS} operands, found {} operands", O::OPCODE, self.operands.len())
160        }
161
162        // Convert all input types into `LiteralType`s. If any are not a `LiteralType`, return an error.
163        let input_types = input_types
164            .iter()
165            .map(|input_type| match input_type {
166                RegisterType::Plaintext(PlaintextType::Literal(literal_type)) => Ok(*literal_type),
167                RegisterType::Plaintext(PlaintextType::Struct(..))
168                | RegisterType::Plaintext(PlaintextType::ExternalStruct(..))
169                | RegisterType::Plaintext(PlaintextType::Array(..))
170                | RegisterType::Record(..)
171                | RegisterType::ExternalRecord(..)
172                | RegisterType::Future(..) => bail!("Expected literal type, found '{input_type}'"),
173            })
174            .collect::<Result<Vec<_>>>()?;
175
176        // Compute the output type.
177        let output = O::output_type(&input_types.try_into().map_err(|_| anyhow!("Failed to prepare operand types"))?)?;
178
179        // Return the output type.
180        Ok(vec![RegisterType::Plaintext(PlaintextType::Literal(output))])
181    }
182}
183
184impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> Parser
185    for Literals<N, O, NUM_OPERANDS>
186{
187    /// Parses a string into an operation.
188    fn parse(string: &str) -> ParserResult<Self> {
189        // Parse the opcode from the string.
190        let (string, _) = tag(*O::OPCODE)(string)?;
191        // Parse the whitespace from the string.
192        let (string, _) = Sanitizer::parse_whitespaces(string)?;
193
194        // Ensure the number of operands is within the bounds.
195        if NUM_OPERANDS > N::MAX_OPERANDS {
196            return map_res(fail, |_: ParserResult<Self>| {
197                Err(format!("The number of operands must be <= {}", N::MAX_OPERANDS))
198            })(string);
199        }
200
201        // Initialize a vector to store the operands.
202        let mut operands = Vec::with_capacity(NUM_OPERANDS);
203        // Initialize a tracker for the string.
204        let mut string_tracker = string;
205        // Parse the operands from the string.
206        for _ in 0..NUM_OPERANDS {
207            // Parse the operand from the string.
208            let (string, operand) = Operand::parse(string_tracker)?;
209            // Parse the whitespace from the string.
210            let (string, _) = Sanitizer::parse_whitespaces(string)?;
211            // Add the operand to the vector.
212            operands.push(operand);
213            // Update the string tracker.
214            string_tracker = string;
215        }
216        // Set the string to the tracker.
217        let string = string_tracker;
218
219        // Parse the "into " from the string.
220        let (string, _) = tag("into")(string)?;
221        // Parse the whitespace from the string.
222        let (string, _) = Sanitizer::parse_whitespaces(string)?;
223        // Parse the destination register from the string.
224        let (string, destination) = Register::parse(string)?;
225
226        Ok((string, Self { operands, destination, _phantom: PhantomData }))
227    }
228}
229
230impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> FromStr
231    for Literals<N, O, NUM_OPERANDS>
232{
233    type Err = Error;
234
235    /// Parses a string into an operation.
236    fn from_str(string: &str) -> Result<Self> {
237        match Self::parse(string) {
238            Ok((remainder, object)) => {
239                // Ensure the remainder is empty.
240                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
241                // Return the object.
242                Ok(object)
243            }
244            Err(error) => bail!("Failed to parse string. {error}"),
245        }
246    }
247}
248
249impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> Debug
250    for Literals<N, O, NUM_OPERANDS>
251{
252    /// Prints the operation as a string.
253    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
254        Display::fmt(self, f)
255    }
256}
257
258impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> Display
259    for Literals<N, O, NUM_OPERANDS>
260{
261    /// Prints the operation to a string.
262    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
263        // Ensure the number of operands is within the bounds.
264        if NUM_OPERANDS > N::MAX_OPERANDS {
265            return Err(fmt::Error);
266        }
267        // Ensure the number of operands is correct.
268        if self.operands.len() > NUM_OPERANDS {
269            return Err(fmt::Error);
270        }
271        // Print the operation.
272        write!(f, "{} ", O::OPCODE)?;
273        self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
274        write!(f, "into {}", self.destination)
275    }
276}
277
278impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> FromBytes
279    for Literals<N, O, NUM_OPERANDS>
280{
281    /// Reads the operation from a buffer.
282    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
283        // Ensure the number of operands is within the bounds.
284        if NUM_OPERANDS > N::MAX_OPERANDS {
285            return Err(error(format!("The number of operands must be <= {}", N::MAX_OPERANDS)));
286        }
287
288        // Initialize the vector for the operands.
289        let mut operands = Vec::with_capacity(NUM_OPERANDS);
290        // Read the operands.
291        for _ in 0..NUM_OPERANDS {
292            operands.push(Operand::read_le(&mut reader)?);
293        }
294
295        // Read the destination register.
296        let destination = Register::read_le(&mut reader)?;
297        // Return the operation.
298        Ok(Self { operands, destination, _phantom: PhantomData })
299    }
300}
301
302impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> ToBytes
303    for Literals<N, O, NUM_OPERANDS>
304{
305    /// Writes the operation to a buffer.
306    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
307        // Ensure the number of operands is within the bounds.
308        if NUM_OPERANDS > N::MAX_OPERANDS {
309            return Err(error(format!("The number of operands must be <= {}", N::MAX_OPERANDS)));
310        }
311        // Ensure the number of operands is correct.
312        if self.operands.len() > NUM_OPERANDS {
313            return Err(error(format!("The number of operands must be {NUM_OPERANDS}")));
314        }
315        // Write the operands.
316        self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
317        // Write the destination register.
318        self.destination.write_le(&mut writer)
319    }
320}