1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the snarkVM library.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::*;

impl<N: Network> Stack<N> {
    /// Synthesizes the proving key and verifying key for the given function name.
    #[inline]
    pub fn synthesize_key<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
        &self,
        function_name: &Identifier<N>,
        rng: &mut R,
    ) -> Result<()> {
        // If the proving and verifying key already exist, skip the synthesis for this function.
        if self.contains_proving_key(function_name) && self.contains_verifying_key(function_name) {
            return Ok(());
        }

        // Retrieve the program ID.
        let program_id = self.program_id();
        // Retrieve the function input types.
        let input_types = self.get_function(function_name)?.input_types();

        // Initialize a burner private key.
        let burner_private_key = PrivateKey::new(rng)?;
        // Compute the burner address.
        let burner_address = Address::try_from(&burner_private_key)?;
        // Sample the inputs.
        let inputs = input_types
            .iter()
            .map(|input_type| match input_type {
                ValueType::ExternalRecord(locator) => {
                    // Retrieve the external stack.
                    let stack = self.get_external_stack(locator.program_id())?;
                    // Sample the input.
                    stack.sample_value(&burner_address, &ValueType::Record(*locator.resource()), rng)
                }
                _ => self.sample_value(&burner_address, input_type, rng),
            })
            .collect::<Result<Vec<_>>>()?;

        // Compute the request, with a burner private key.
        let request =
            Request::sign(&burner_private_key, *program_id, *function_name, inputs.into_iter(), &input_types, rng)?;
        // Initialize the authorization.
        let authorization = Authorization::new(request.clone());
        // Initialize the call stack.
        let call_stack = CallStack::Synthesize(vec![request], burner_private_key, authorization);
        // Synthesize the circuit.
        let _response = self.execute_function::<A, R>(call_stack, None, rng)?;

        // Ensure the proving key exists.
        ensure!(self.contains_proving_key(function_name), "Function '{function_name}' is missing a proving key.");
        // Ensure the verifying key exists.
        ensure!(self.contains_verifying_key(function_name), "Function '{function_name}' is missing a verifying key.");
        Ok(())
    }

    /// Synthesizes and stores the `(proving_key, verifying_key)` for the given function name and assignment.
    #[inline]
    pub fn synthesize_from_assignment(
        &self,
        function_name: &Identifier<N>,
        assignment: &circuit::Assignment<N::Field>,
    ) -> Result<()> {
        // If the proving and verifying key already exist, skip the synthesis for this function.
        if self.contains_proving_key(function_name) && self.contains_verifying_key(function_name) {
            return Ok(());
        }

        // Synthesize the proving and verifying key.
        let (proving_key, verifying_key) = self.universal_srs.to_circuit_key(&function_name.to_string(), assignment)?;
        // Insert the proving key.
        self.insert_proving_key(function_name, proving_key)?;
        // Insert the verifying key.
        self.insert_verifying_key(function_name, verifying_key)
    }
}