snarkvm_synthesizer_process/stack/helpers/
synthesize.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> Stack<N> {
19    /// Synthesizes the proving key and verifying key for the given function name.
20    #[inline]
21    pub fn synthesize_key<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
22        &self,
23        function_name: &Identifier<N>,
24        rng: &mut R,
25    ) -> Result<()> {
26        // If the proving and verifying key already exist, skip the synthesis for this function.
27        if self.contains_proving_key(function_name) && self.contains_verifying_key(function_name) {
28            return Ok(());
29        }
30
31        // Retrieve the program ID.
32        let program_id = self.program_id();
33        // Retrieve the function input types.
34        let input_types = self.get_function(function_name)?.input_types();
35        // Retrieve the program checksum, if the program has a constructor.
36        let program_checksum = match self.program().contains_constructor() {
37            true => Some(self.program_checksum_as_field()?),
38            false => None,
39        };
40
41        // Initialize a burner private key.
42        let burner_private_key = PrivateKey::new(rng)?;
43        // Compute the burner address.
44        let burner_address = Address::try_from(&burner_private_key)?;
45        // Sample the inputs.
46        let inputs = input_types
47            .iter()
48            .map(|input_type| match input_type {
49                ValueType::ExternalRecord(locator) => {
50                    // Retrieve the external stack.
51                    let stack = self.get_external_stack(locator.program_id())?;
52                    // Sample the input.
53                    stack.sample_value(&burner_address, &ValueType::Record(*locator.resource()).into(), rng)
54                }
55                _ => self.sample_value(&burner_address, &input_type.into(), rng),
56            })
57            .collect::<Result<Vec<_>>>()?;
58        // Sample a dummy 'is_root'.
59        let is_root = true;
60        // Sample a dummy `root_tvk` for circuit synthesis.
61        let root_tvk = None;
62        // Sample a dummy `caller` for circuit synthesis.
63        let caller = None;
64
65        // Compute the request, with a burner private key.
66        let request = Request::sign(
67            &burner_private_key,
68            *program_id,
69            *function_name,
70            inputs.into_iter(),
71            &input_types,
72            root_tvk,
73            is_root,
74            program_checksum,
75            rng,
76        )?;
77        // Initialize the authorization.
78        let authorization = Authorization::new(request.clone());
79        // Initialize the call stack.
80        let call_stack = CallStack::Synthesize(vec![request], burner_private_key, authorization);
81        // Synthesize the circuit.
82        let _response = self.execute_function::<A, R>(call_stack, caller, root_tvk, rng)?;
83
84        // Ensure the proving key exists.
85        ensure!(self.contains_proving_key(function_name), "Function '{function_name}' is missing a proving key.");
86        // Ensure the verifying key exists.
87        ensure!(self.contains_verifying_key(function_name), "Function '{function_name}' is missing a verifying key.");
88        Ok(())
89    }
90
91    /// Synthesizes and stores the `(proving_key, verifying_key)` for the given function name and assignment.
92    #[inline]
93    pub fn synthesize_from_assignment(
94        &self,
95        function_name: &Identifier<N>,
96        assignment: &circuit::Assignment<N::Field>,
97    ) -> Result<()> {
98        // If the proving and verifying key already exist, skip the synthesis for this function.
99        if self.contains_proving_key(function_name) && self.contains_verifying_key(function_name) {
100            return Ok(());
101        }
102
103        // Synthesize the proving and verifying key.
104        let (proving_key, verifying_key) = self.universal_srs.to_circuit_key(&function_name.to_string(), assignment)?;
105        // Insert the proving key.
106        self.insert_proving_key(function_name, proving_key)?;
107        // Insert the verifying key.
108        self.insert_verifying_key(function_name, verifying_key)
109    }
110}