Skip to main content

snarkvm_synthesizer_program/logic/instruction/operation/
literals.rs

1// Copyright (c) 2019-2026 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(..)
173                | RegisterType::DynamicRecord
174                | RegisterType::DynamicFuture => bail!("Expected literal type, found '{input_type}'"),
175            })
176            .collect::<Result<Vec<_>>>()?;
177
178        // Compute the output type.
179        let output = O::output_type(&input_types.try_into().map_err(|_| anyhow!("Failed to prepare operand types"))?)?;
180
181        // Return the output type.
182        Ok(vec![RegisterType::Plaintext(PlaintextType::Literal(output))])
183    }
184}
185
186impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> Parser
187    for Literals<N, O, NUM_OPERANDS>
188{
189    /// Parses a string into an operation.
190    fn parse(string: &str) -> ParserResult<Self> {
191        // Parse the opcode from the string.
192        let (string, _) = tag(*O::OPCODE)(string)?;
193        // Parse the whitespace from the string.
194        let (string, _) = Sanitizer::parse_whitespaces(string)?;
195
196        // Ensure the number of operands is within the bounds.
197        if NUM_OPERANDS > N::MAX_OPERANDS {
198            return map_res(fail, |_: ParserResult<Self>| {
199                Err(format!("The number of operands must be <= {}", N::MAX_OPERANDS))
200            })(string);
201        }
202
203        // Initialize a vector to store the operands.
204        let mut operands = Vec::with_capacity(NUM_OPERANDS);
205        // Initialize a tracker for the string.
206        let mut string_tracker = string;
207        // Parse the operands from the string.
208        for _ in 0..NUM_OPERANDS {
209            // Parse the operand from the string.
210            let (string, operand) = Operand::parse(string_tracker)?;
211            // Parse the whitespace from the string.
212            let (string, _) = Sanitizer::parse_whitespaces(string)?;
213            // Add the operand to the vector.
214            operands.push(operand);
215            // Update the string tracker.
216            string_tracker = string;
217        }
218        // Set the string to the tracker.
219        let string = string_tracker;
220
221        // Parse the "into " from the string.
222        let (string, _) = tag("into")(string)?;
223        // Parse the whitespace from the string.
224        let (string, _) = Sanitizer::parse_whitespaces(string)?;
225        // Parse the destination register from the string.
226        let (string, destination) = Register::parse(string)?;
227
228        Ok((string, Self { operands, destination, _phantom: PhantomData }))
229    }
230}
231
232impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> FromStr
233    for Literals<N, O, NUM_OPERANDS>
234{
235    type Err = Error;
236
237    /// Parses a string into an operation.
238    fn from_str(string: &str) -> Result<Self> {
239        match Self::parse(string) {
240            Ok((remainder, object)) => {
241                // Ensure the remainder is empty.
242                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
243                // Return the object.
244                Ok(object)
245            }
246            Err(error) => bail!("Failed to parse string. {error}"),
247        }
248    }
249}
250
251impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> Debug
252    for Literals<N, O, NUM_OPERANDS>
253{
254    /// Prints the operation as a string.
255    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
256        Display::fmt(self, f)
257    }
258}
259
260impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> Display
261    for Literals<N, O, NUM_OPERANDS>
262{
263    /// Prints the operation to a string.
264    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
265        // Ensure the number of operands is within the bounds.
266        if NUM_OPERANDS > N::MAX_OPERANDS {
267            return Err(fmt::Error);
268        }
269        // Ensure the number of operands is correct.
270        if self.operands.len() > NUM_OPERANDS {
271            return Err(fmt::Error);
272        }
273        // Print the operation.
274        write!(f, "{} ", O::OPCODE)?;
275        self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
276        write!(f, "into {}", self.destination)
277    }
278}
279
280impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> FromBytes
281    for Literals<N, O, NUM_OPERANDS>
282{
283    /// Reads the operation from a buffer.
284    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
285        // Ensure the number of operands is within the bounds.
286        if NUM_OPERANDS > N::MAX_OPERANDS {
287            return Err(error(format!("The number of operands must be <= {}", N::MAX_OPERANDS)));
288        }
289
290        // Initialize the vector for the operands.
291        let mut operands = Vec::with_capacity(NUM_OPERANDS);
292        // Read the operands.
293        for _ in 0..NUM_OPERANDS {
294            operands.push(Operand::read_le(&mut reader)?);
295        }
296
297        // Read the destination register.
298        let destination = Register::read_le(&mut reader)?;
299        // Return the operation.
300        Ok(Self { operands, destination, _phantom: PhantomData })
301    }
302}
303
304impl<N: Network, O: Operation<N, Literal<N>, LiteralType, NUM_OPERANDS>, const NUM_OPERANDS: usize> ToBytes
305    for Literals<N, O, NUM_OPERANDS>
306{
307    /// Writes the operation to a buffer.
308    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
309        // Ensure the number of operands is within the bounds.
310        if NUM_OPERANDS > N::MAX_OPERANDS {
311            return Err(error(format!("The number of operands must be <= {}", N::MAX_OPERANDS)));
312        }
313        // Ensure the number of operands is correct.
314        if self.operands.len() > NUM_OPERANDS {
315            return Err(error(format!("The number of operands must be {NUM_OPERANDS}")));
316        }
317        // Write the operands.
318        self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
319        // Write the destination register.
320        self.destination.write_le(&mut writer)
321    }
322}