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