snarkvm_console_account/signature/
verify.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 super::*;
17
18impl<N: Network> Signature<N> {
19    /// Verifies (challenge == challenge') && (address == address') where:
20    ///     challenge' := HashToScalar(G^response pk_sig^challenge, pk_sig, pr_sig, address, message)
21    pub fn verify(&self, address: &Address<N>, message: &[Field<N>]) -> bool {
22        // Ensure the number of field elements does not exceed the maximum allowed size.
23        if message.len() > N::MAX_DATA_SIZE_IN_FIELDS as usize {
24            eprintln!("Cannot sign the signature: the signed message exceeds maximum allowed size");
25            return false;
26        }
27
28        // Retrieve pk_sig.
29        let pk_sig = self.compute_key.pk_sig();
30        // Retrieve pr_sig.
31        let pr_sig = self.compute_key.pr_sig();
32
33        // Compute `g_r` := (response * G) + (challenge * pk_sig).
34        let g_r = N::g_scalar_multiply(&self.response) + (pk_sig * self.challenge);
35
36        // Construct the hash input as (r * G, pk_sig, pr_sig, address, message).
37        let mut preimage = Vec::with_capacity(4 + message.len());
38        preimage.extend([g_r, pk_sig, pr_sig, **address].map(|point| point.to_x_coordinate()));
39        preimage.extend(message);
40
41        // Hash to derive the verifier challenge, and return `false` if this operation fails.
42        let candidate_challenge = match N::hash_to_scalar_psd8(&preimage) {
43            // Output the computed candidate challenge.
44            Ok(candidate_challenge) => candidate_challenge,
45            // Return `false` if the challenge errored.
46            Err(_) => return false,
47        };
48
49        // Derive the address from the compute key, and return `false` if this operation fails.
50        let candidate_address = match Address::try_from(self.compute_key) {
51            // Output the computed candidate address.
52            Ok(candidate_address) => candidate_address,
53            // Return `false` if the address errored.
54            Err(_) => return false,
55        };
56
57        // Return `true` if the candidate challenge and address are correct.
58        self.challenge == candidate_challenge && *address == candidate_address
59    }
60
61    /// Verifies a signature for the given address and message (as bytes).
62    pub fn verify_bytes(&self, address: &Address<N>, message: &[u8]) -> bool {
63        // Convert the message into bits, and verify the signature.
64        self.verify_bits(address, &message.to_bits_le())
65    }
66
67    /// Verifies a signature for the given address and message (as bits).
68    pub fn verify_bits(&self, address: &Address<N>, message: &[bool]) -> bool {
69        // Pack the bits into field elements.
70        match message.chunks(Field::<N>::size_in_data_bits()).map(Field::from_bits_le).collect::<Result<Vec<_>>>() {
71            Ok(fields) => self.verify(address, &fields),
72            Err(error) => {
73                eprintln!("Failed to verify signature: {error}");
74                false
75            }
76        }
77    }
78}
79
80#[cfg(test)]
81#[cfg(feature = "private_key")]
82mod tests {
83    use super::*;
84    use snarkvm_console_network::MainnetV0;
85
86    type CurrentNetwork = MainnetV0;
87
88    const ITERATIONS: u64 = 100;
89
90    #[test]
91    fn test_sign_and_verify() -> Result<()> {
92        let rng = &mut TestRng::default();
93
94        for i in 0..ITERATIONS {
95            // Sample an address and a private key.
96            let private_key = PrivateKey::<CurrentNetwork>::new(rng)?;
97            let address = Address::try_from(&private_key)?;
98
99            // Check that the signature is valid for the message.
100            let message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
101            let signature = Signature::sign(&private_key, &message, rng)?;
102            assert!(signature.verify(&address, &message));
103
104            // Check that the signature is invalid for an incorrect message.
105            let failure_message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
106            if message != failure_message {
107                assert!(!signature.verify(&address, &failure_message));
108            }
109        }
110        Ok(())
111    }
112
113    #[test]
114    fn test_sign_and_verify_bytes() -> Result<()> {
115        let rng = &mut TestRng::default();
116
117        for i in 0..ITERATIONS {
118            // Sample an address and a private key.
119            let private_key = PrivateKey::<CurrentNetwork>::new(rng)?;
120            let address = Address::try_from(&private_key)?;
121
122            // Check that the signature is valid for the message.
123            let message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
124            let signature = Signature::sign_bytes(&private_key, &message, rng)?;
125            assert!(signature.verify_bytes(&address, &message));
126
127            // Check that the signature is invalid for an incorrect message.
128            let failure_message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
129            if message != failure_message {
130                assert!(!signature.verify_bytes(&address, &failure_message));
131            }
132        }
133        Ok(())
134    }
135
136    #[test]
137    fn test_sign_and_verify_bits() -> Result<()> {
138        let rng = &mut TestRng::default();
139
140        for i in 0..ITERATIONS {
141            // Sample an address and a private key.
142            let private_key = PrivateKey::<CurrentNetwork>::new(rng)?;
143            let address = Address::try_from(&private_key)?;
144
145            // Check that the signature is valid for the message.
146            let message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
147            let signature = Signature::sign_bits(&private_key, &message, rng)?;
148            assert!(signature.verify_bits(&address, &message));
149
150            // Check that the signature is invalid for an incorrect message.
151            let failure_message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
152            if message != failure_message {
153                assert!(!signature.verify_bits(&address, &failure_message));
154            }
155        }
156        Ok(())
157    }
158}