snarkvm_synthesizer_program/logic/instruction/operation/
sign_verify.rs1use crate::{Opcode, Operand, RegistersCircuit, RegistersTrait, StackTrait};
17use circuit::prelude::ToFields as CircuitToFields;
18use console::{
19 network::prelude::*,
20 program::{
21 Address,
22 Literal,
23 LiteralType,
24 PlaintextType,
25 Register,
26 RegisterType,
27 Signature,
28 ToFields as ConsoleToFields,
29 Value,
30 },
31 types::Boolean,
32};
33
34pub type SignVerify<N> = SignatureVerification<N>;
36
37#[derive(Clone, PartialEq, Eq, Hash)]
39pub struct SignatureVerification<N: Network> {
40 operands: Vec<Operand<N>>,
42 destination: Register<N>,
44}
45
46impl<N: Network> SignatureVerification<N> {
47 #[inline]
49 pub fn new(operands: Vec<Operand<N>>, destination: Register<N>) -> Result<Self> {
50 ensure!(operands.len() == 3, "Instruction '{}' must have three operands", Self::opcode());
52 Ok(Self { operands, destination })
54 }
55
56 #[inline]
58 pub const fn opcode() -> Opcode {
59 Opcode::Sign("sign.verify")
60 }
61
62 #[inline]
64 pub fn operands(&self) -> &[Operand<N>] {
65 debug_assert!(self.operands.len() == 3, "Instruction '{}' must have three operands", Self::opcode());
67 &self.operands
69 }
70
71 #[inline]
73 pub fn destinations(&self) -> Vec<Register<N>> {
74 vec![self.destination.clone()]
75 }
76}
77
78pub fn evaluate_schnorr_verification<N: Network>(
83 signature: &Signature<N>,
84 address: &Address<N>,
85 message: &Value<N>,
86) -> Result<bool> {
87 Ok(signature.verify(address, &message.to_fields()?))
89}
90
91impl<N: Network> SignatureVerification<N> {
92 #[inline]
94 pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
95 if self.operands.len() != 3 {
97 bail!("Instruction '{}' expects 3 operands, found {} operands", Self::opcode(), self.operands.len())
98 }
99
100 let signature = match registers.load_literal(stack, &self.operands[0])? {
102 Literal::Signature(signature) => signature,
103 _ => bail!("Expected the first operand to be a signature."),
104 };
105 let address = match registers.load_literal(stack, &self.operands[1])? {
106 Literal::Address(address) => address,
107 _ => bail!("Expected the second operand to be an address."),
108 };
109 let message = registers.load(stack, &self.operands[2])?;
110
111 let output = evaluate_schnorr_verification(&signature, &address, &message)?;
113 let output = Literal::Boolean(Boolean::new(output));
114
115 registers.store_literal(stack, &self.destination, output)
117 }
118
119 #[inline]
121 pub fn execute<A: circuit::Aleo<Network = N>>(
122 &self,
123 stack: &impl StackTrait<N>,
124 registers: &mut impl RegistersCircuit<N, A>,
125 ) -> Result<()> {
126 if self.operands.len() != 3 {
128 bail!("Instruction '{}' expects 3 operands, found {} operands", Self::opcode(), self.operands.len())
129 }
130
131 let signature = match registers.load_literal_circuit(stack, &self.operands[0])? {
133 circuit::Literal::Signature(signature) => signature,
134 _ => bail!("Expected the first operand to be a signature."),
135 };
136 let address = match registers.load_literal_circuit(stack, &self.operands[1])? {
137 circuit::Literal::Address(address) => address,
138 _ => bail!("Expected the second operand to be an address."),
139 };
140 let message = registers.load_circuit(stack, &self.operands[2])?;
141
142 let output = circuit::Literal::Boolean(signature.verify(&address, &message.to_fields()));
144
145 registers.store_literal_circuit(stack, &self.destination, output)
147 }
148
149 #[inline]
151 pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
152 self.evaluate(stack, registers)
153 }
154
155 #[inline]
157 pub fn output_types(
158 &self,
159 _stack: &impl StackTrait<N>,
160 input_types: &[RegisterType<N>],
161 ) -> Result<Vec<RegisterType<N>>> {
162 if input_types.len() != 3 {
164 bail!("Instruction '{}' expects 3 inputs, found {} inputs", Self::opcode(), input_types.len())
165 }
166
167 if input_types[0] != RegisterType::Plaintext(PlaintextType::Literal(LiteralType::Signature)) {
169 bail!(
170 "Instruction '{}' expects the first input to be a 'signature'. Found input of type '{}'",
171 Self::opcode(),
172 input_types[0]
173 )
174 }
175
176 if input_types[1] != RegisterType::Plaintext(PlaintextType::Literal(LiteralType::Address)) {
178 bail!(
179 "Instruction '{}' expects the second input to be an 'address'. Found input of type '{}'",
180 Self::opcode(),
181 input_types[1]
182 )
183 }
184
185 Ok(vec![RegisterType::Plaintext(PlaintextType::Literal(LiteralType::Boolean))])
186 }
187}
188
189impl<N: Network> Parser for SignatureVerification<N> {
190 #[inline]
192 fn parse(string: &str) -> ParserResult<Self> {
193 let (string, _) = tag(*Self::opcode())(string)?;
195 let (string, _) = Sanitizer::parse_whitespaces(string)?;
197 let (string, first) = Operand::parse(string)?;
199 let (string, _) = Sanitizer::parse_whitespaces(string)?;
201 let (string, second) = Operand::parse(string)?;
203 let (string, _) = Sanitizer::parse_whitespaces(string)?;
205 let (string, third) = Operand::parse(string)?;
207 let (string, _) = Sanitizer::parse_whitespaces(string)?;
209 let (string, _) = tag("into")(string)?;
211 let (string, _) = Sanitizer::parse_whitespaces(string)?;
213 let (string, destination) = Register::parse(string)?;
215
216 Ok((string, Self { operands: vec![first, second, third], destination }))
217 }
218}
219
220impl<N: Network> FromStr for SignatureVerification<N> {
221 type Err = Error;
222
223 #[inline]
225 fn from_str(string: &str) -> Result<Self> {
226 match Self::parse(string) {
227 Ok((remainder, object)) => {
228 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
230 Ok(object)
232 }
233 Err(error) => bail!("Failed to parse string. {error}"),
234 }
235 }
236}
237
238impl<N: Network> Debug for SignatureVerification<N> {
239 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
241 Display::fmt(self, f)
242 }
243}
244
245impl<N: Network> Display for SignatureVerification<N> {
246 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
248 if self.operands.len() != 3 {
250 return Err(fmt::Error);
251 }
252 write!(f, "{} ", Self::opcode())?;
254 self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
255 write!(f, "into {}", self.destination)
256 }
257}
258
259impl<N: Network> FromBytes for SignatureVerification<N> {
260 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
262 let mut operands = Vec::with_capacity(3);
264 for _ in 0..3 {
266 operands.push(Operand::read_le(&mut reader)?);
267 }
268 let destination = Register::read_le(&mut reader)?;
270
271 Ok(Self { operands, destination })
273 }
274}
275
276impl<N: Network> ToBytes for SignatureVerification<N> {
277 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
279 if self.operands.len() != 3 {
281 return Err(error(format!("The number of operands must be 3, found {}", self.operands.len())));
282 }
283 self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
285 self.destination.write_le(&mut writer)
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293 use console::network::MainnetV0;
294
295 type CurrentNetwork = MainnetV0;
296
297 #[test]
298 fn test_parse() {
299 let (string, is) = SignVerify::<CurrentNetwork>::parse("sign.verify r0 r1 r2 into r3").unwrap();
300 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
301 assert_eq!(is.operands.len(), 3, "The number of operands is incorrect");
302 assert_eq!(is.operands[0], Operand::Register(Register::Locator(0)), "The first operand is incorrect");
303 assert_eq!(is.operands[1], Operand::Register(Register::Locator(1)), "The second operand is incorrect");
304 assert_eq!(is.operands[2], Operand::Register(Register::Locator(2)), "The third operand is incorrect");
305 assert_eq!(is.destination, Register::Locator(3), "The destination register is incorrect");
306 }
307}