snarkvm_synthesizer_program/logic/instruction/operation/
sign_verify.rs

1// Copyright 2024-2025 Aleo Network Foundation
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    traits::{RegistersLoad, RegistersLoadCircuit, RegistersStore, RegistersStoreCircuit, StackMatches, StackProgram},
20};
21use circuit::prelude::ToFields as CircuitToFields;
22use console::{
23    network::prelude::*,
24    program::{Literal, LiteralType, PlaintextType, Register, RegisterType, ToFields as ConsoleToFields},
25    types::Boolean,
26};
27
28/// Computes whether `signature` is valid for the given `address` and `message`.
29#[derive(Clone, PartialEq, Eq, Hash)]
30pub struct SignVerify<N: Network> {
31    /// The operands.
32    operands: Vec<Operand<N>>,
33    /// The destination register.
34    destination: Register<N>,
35}
36
37impl<N: Network> SignVerify<N> {
38    /// Initializes a new `sign.verify` instruction.
39    #[inline]
40    pub fn new(operands: Vec<Operand<N>>, destination: Register<N>) -> Result<Self> {
41        // Sanity check the number of operands.
42        ensure!(operands.len() == 3, "Instruction '{}' must have three operands", Self::opcode());
43        // Return the instruction.
44        Ok(Self { operands, destination })
45    }
46
47    /// Returns the opcode.
48    #[inline]
49    pub const fn opcode() -> Opcode {
50        Opcode::Sign
51    }
52
53    /// Returns the operands in the operation.
54    #[inline]
55    pub fn operands(&self) -> &[Operand<N>] {
56        // Sanity check that there are exactly three operands.
57        debug_assert!(self.operands.len() == 3, "Instruction '{}' must have three operands", Self::opcode());
58        // Return the operands.
59        &self.operands
60    }
61
62    /// Returns the destination register.
63    #[inline]
64    pub fn destinations(&self) -> Vec<Register<N>> {
65        vec![self.destination.clone()]
66    }
67}
68
69impl<N: Network> SignVerify<N> {
70    /// Evaluates the instruction.
71    #[inline]
72    pub fn evaluate(
73        &self,
74        stack: &(impl StackMatches<N> + StackProgram<N>),
75        registers: &mut (impl RegistersLoad<N> + RegistersStore<N>),
76    ) -> Result<()> {
77        // Ensure the number of operands is correct.
78        if self.operands.len() != 3 {
79            bail!("Instruction '{}' expects 3 operands, found {} operands", Self::opcode(), self.operands.len())
80        }
81
82        // Retrieve the inputs.
83        let signature = match registers.load_literal(stack, &self.operands[0])? {
84            Literal::Signature(signature) => signature,
85            _ => bail!("Expected the first operand to be a signature."),
86        };
87        let address = match registers.load_literal(stack, &self.operands[1])? {
88            Literal::Address(address) => address,
89            _ => bail!("Expected the second operand to be an address."),
90        };
91        let message = registers.load(stack, &self.operands[2])?;
92
93        // Verify the signature.
94        let output = Literal::Boolean(Boolean::new(signature.verify(&address, &message.to_fields()?)));
95
96        // Store the output.
97        registers.store_literal(stack, &self.destination, output)
98    }
99
100    /// Executes the instruction.
101    #[inline]
102    pub fn execute<A: circuit::Aleo<Network = N>>(
103        &self,
104        stack: &(impl StackMatches<N> + StackProgram<N>),
105        registers: &mut (impl RegistersLoadCircuit<N, A> + RegistersStoreCircuit<N, A>),
106    ) -> Result<()> {
107        // Ensure the number of operands is correct.
108        if self.operands.len() != 3 {
109            bail!("Instruction '{}' expects 3 operands, found {} operands", Self::opcode(), self.operands.len())
110        }
111
112        // Retrieve the inputs.
113        let signature = match registers.load_literal_circuit(stack, &self.operands[0])? {
114            circuit::Literal::Signature(signature) => signature,
115            _ => bail!("Expected the first operand to be a signature."),
116        };
117        let address = match registers.load_literal_circuit(stack, &self.operands[1])? {
118            circuit::Literal::Address(address) => address,
119            _ => bail!("Expected the second operand to be an address."),
120        };
121        let message = registers.load_circuit(stack, &self.operands[2])?;
122
123        // Verify the signature.
124        let output = circuit::Literal::Boolean(signature.verify(&address, &message.to_fields()));
125
126        // Store the output.
127        registers.store_literal_circuit(stack, &self.destination, output)
128    }
129
130    /// Finalizes the instruction.
131    #[inline]
132    pub fn finalize(
133        &self,
134        stack: &(impl StackMatches<N> + StackProgram<N>),
135        registers: &mut (impl RegistersLoad<N> + RegistersStore<N>),
136    ) -> Result<()> {
137        self.evaluate(stack, registers)
138    }
139
140    /// Returns the output type from the given program and input types.
141    #[inline]
142    pub fn output_types(
143        &self,
144        _stack: &impl StackProgram<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() != 3 {
149            bail!("Instruction '{}' expects 3 inputs, found {} inputs", Self::opcode(), input_types.len())
150        }
151
152        // Ensure the first operand is a signature.
153        if input_types[0] != RegisterType::Plaintext(PlaintextType::Literal(LiteralType::Signature)) {
154            bail!(
155                "Instruction '{}' expects the first input to be a 'signature'. Found input of type '{}'",
156                Self::opcode(),
157                input_types[0]
158            )
159        }
160
161        // Ensure the second operand is an address.
162        if input_types[1] != RegisterType::Plaintext(PlaintextType::Literal(LiteralType::Address)) {
163            bail!(
164                "Instruction '{}' expects the second input to be an 'address'. Found input of type '{}'",
165                Self::opcode(),
166                input_types[1]
167            )
168        }
169
170        Ok(vec![RegisterType::Plaintext(PlaintextType::Literal(LiteralType::Boolean))])
171    }
172}
173
174impl<N: Network> Parser for SignVerify<N> {
175    /// Parses a string into an operation.
176    #[inline]
177    fn parse(string: &str) -> ParserResult<Self> {
178        // Parse the opcode from the string.
179        let (string, _) = tag(*Self::opcode())(string)?;
180        // Parse the whitespace from the string.
181        let (string, _) = Sanitizer::parse_whitespaces(string)?;
182        // Parse the first operand from the string.
183        let (string, first) = Operand::parse(string)?;
184        // Parse the whitespace from the string.
185        let (string, _) = Sanitizer::parse_whitespaces(string)?;
186        // Parse the second operand from the string.
187        let (string, second) = Operand::parse(string)?;
188        // Parse the whitespace from the string.
189        let (string, _) = Sanitizer::parse_whitespaces(string)?;
190        // Parse the third operand from the string.
191        let (string, third) = Operand::parse(string)?;
192        // Parse the whitespace from the string.
193        let (string, _) = Sanitizer::parse_whitespaces(string)?;
194        // Parse the "into" from the string.
195        let (string, _) = tag("into")(string)?;
196        // Parse the whitespace from the string.
197        let (string, _) = Sanitizer::parse_whitespaces(string)?;
198        // Parse the destination register from the string.
199        let (string, destination) = Register::parse(string)?;
200
201        Ok((string, Self { operands: vec![first, second, third], destination }))
202    }
203}
204
205impl<N: Network> FromStr for SignVerify<N> {
206    type Err = Error;
207
208    /// Parses a string into an operation.
209    #[inline]
210    fn from_str(string: &str) -> Result<Self> {
211        match Self::parse(string) {
212            Ok((remainder, object)) => {
213                // Ensure the remainder is empty.
214                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
215                // Return the object.
216                Ok(object)
217            }
218            Err(error) => bail!("Failed to parse string. {error}"),
219        }
220    }
221}
222
223impl<N: Network> Debug for SignVerify<N> {
224    /// Prints the operation as a string.
225    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
226        Display::fmt(self, f)
227    }
228}
229
230impl<N: Network> Display for SignVerify<N> {
231    /// Prints the operation to a string.
232    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
233        // Ensure the number of operands is 3.
234        if self.operands.len() != 3 {
235            return Err(fmt::Error);
236        }
237        // Print the operation.
238        write!(f, "{} ", Self::opcode())?;
239        self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
240        write!(f, "into {}", self.destination)
241    }
242}
243
244impl<N: Network> FromBytes for SignVerify<N> {
245    /// Reads the operation from a buffer.
246    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
247        // Initialize the vector for the operands.
248        let mut operands = Vec::with_capacity(3);
249        // Read the operands.
250        for _ in 0..3 {
251            operands.push(Operand::read_le(&mut reader)?);
252        }
253        // Read the destination register.
254        let destination = Register::read_le(&mut reader)?;
255
256        // Return the operation.
257        Ok(Self { operands, destination })
258    }
259}
260
261impl<N: Network> ToBytes for SignVerify<N> {
262    /// Writes the operation to a buffer.
263    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
264        // Ensure the number of operands is 3.
265        if self.operands.len() != 3 {
266            return Err(error(format!("The number of operands must be 3, found {}", self.operands.len())));
267        }
268        // Write the operands.
269        self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
270        // Write the destination register.
271        self.destination.write_le(&mut writer)
272    }
273}
274
275#[cfg(test)]
276mod tests {
277    use super::*;
278    use console::network::MainnetV0;
279
280    type CurrentNetwork = MainnetV0;
281
282    #[test]
283    fn test_parse() {
284        let (string, is) = SignVerify::<CurrentNetwork>::parse("sign.verify r0 r1 r2 into r3").unwrap();
285        assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
286        assert_eq!(is.operands.len(), 3, "The number of operands is incorrect");
287        assert_eq!(is.operands[0], Operand::Register(Register::Locator(0)), "The first operand is incorrect");
288        assert_eq!(is.operands[1], Operand::Register(Register::Locator(1)), "The second operand is incorrect");
289        assert_eq!(is.operands[2], Operand::Register(Register::Locator(2)), "The third operand is incorrect");
290        assert_eq!(is.destination, Register::Locator(3), "The destination register is incorrect");
291    }
292}