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