Skip to main content

snarkvm_synthesizer_process/stack/helpers/
synthesize.rs

1// Copyright (c) 2019-2026 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 console::program::{DynamicRecord, ToFields};
17
18use crate::{TranslationAssignment, compute_console_dynamic_or_external_record_id};
19
20use super::*;
21
22impl<N: Network> Stack<N> {
23    /// Synthesizes the proving key and verifying key for the given function name.
24    #[inline]
25    pub fn synthesize_key<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
26        &self,
27        function_name: &Identifier<N>,
28        rng: &mut R,
29    ) -> Result<()> {
30        // If the proving and verifying key already exist, skip the synthesis for this function.
31        if self.contains_proving_key(function_name) && self.contains_verifying_key(function_name) {
32            return Ok(());
33        }
34
35        // Retrieve the program ID.
36        let program_id = self.program_id();
37        // Retrieve the function input types.
38        let input_types = self.get_function(function_name)?.input_types();
39        // Retrieve the program checksum, if the program has a constructor.
40        let program_checksum = match self.program().contains_constructor() {
41            true => Some(self.program_checksum_as_field()?),
42            false => None,
43        };
44
45        // Initialize a burner private key.
46        let burner_private_key = PrivateKey::new(rng)?;
47        // Compute the burner address.
48        let burner_address = Address::try_from(&burner_private_key)?;
49        // Sample the inputs.
50        let inputs = input_types
51            .iter()
52            .map(|input_type| match input_type {
53                ValueType::ExternalRecord(locator) => {
54                    // Retrieve the external stack.
55                    let stack = self.get_external_stack(locator.program_id())?;
56                    // Sample the input.
57                    stack.sample_value(&burner_address, &ValueType::Record(*locator.resource()).into(), rng)
58                }
59                _ => self.sample_value(&burner_address, &input_type.into(), rng),
60            })
61            .collect::<Result<Vec<_>>>()?;
62        // Sample a dummy 'is_root'.
63        let is_root = true;
64        // Sample a dummy `root_tvk` for circuit synthesis.
65        let root_tvk = None;
66        // Sample a dummy `caller` for circuit synthesis.
67        let caller = None;
68
69        // Compute the request, with a burner private key.
70        let request = Request::sign(
71            &burner_private_key,
72            *program_id,
73            *function_name,
74            inputs.into_iter(),
75            &input_types,
76            root_tvk,
77            is_root,
78            program_checksum,
79            false,
80            rng,
81        )?;
82
83        // Initialize the authorization.
84        let authorization = Authorization::new(request.clone());
85        // Initialize the call stack.
86        let call_stack = CallStack::Synthesize(vec![request], burner_private_key, authorization);
87        // Synthesize the circuit.
88        let _response = self.execute_function::<A, R>(call_stack, caller, root_tvk, rng)?;
89
90        // Ensure the proving key exists.
91        ensure!(self.contains_proving_key(function_name), "Function '{function_name}' is missing a proving key.");
92        // Ensure the verifying key exists.
93        ensure!(self.contains_verifying_key(function_name), "Function '{function_name}' is missing a verifying key.");
94        Ok(())
95    }
96
97    /// Synthesizes and stores the `(proving_key, verifying_key)` for the given function name and assignment.
98    #[inline]
99    pub fn synthesize_from_assignment(
100        &self,
101        function_name: &Identifier<N>,
102        assignment: &circuit::Assignment<N::Field>,
103    ) -> Result<()> {
104        // If the proving and verifying key already exist, skip the synthesis for this function.
105        if self.contains_proving_key(function_name) && self.contains_verifying_key(function_name) {
106            return Ok(());
107        }
108
109        // Synthesize the proving and verifying key.
110        let (proving_key, verifying_key) = self.universal_srs.to_circuit_key(&function_name.to_string(), assignment)?;
111        // Insert the proving key.
112        self.insert_proving_key(function_name, proving_key)?;
113        // Insert the verifying key.
114        self.insert_verifying_key(function_name, verifying_key)
115    }
116
117    /// Synthesizes the proving key and verifying key for the translation circuit of the record with the given name.
118    #[inline]
119    pub fn synthesize_translation_key<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
120        &self,
121        record_name: &Identifier<N>,
122        rng: &mut R,
123    ) -> Result<()> {
124        // If the translation proving and verifying key already exist, skip the synthesis for this record.
125        if self.contains_proving_key(record_name) && self.contains_verifying_key(record_name) {
126            return Ok(());
127        }
128
129        // Construct a TranslationAssignment:
130        let private_key = PrivateKey::new(rng)?;
131        let address = Address::try_from(&private_key)?;
132        let program_id = *self.program_id();
133        let function_id = Field::<N>::from_u64(Uniform::rand(rng));
134        let record_name = *record_name;
135        let record_static = self.sample_record(&address, &record_name, Group::rand(rng), rng)?;
136        let record_dynamic = DynamicRecord::<N>::from_record(&record_static)?;
137        let translation_index: u16 = Uniform::rand(rng);
138        let tvk = Uniform::rand(rng);
139        let record_register_index = Uniform::rand(rng);
140        let record_view_key = UniformExt::rand_option(rng);
141        let gamma = UniformExt::rand_option(rng);
142        // Compute the dynamic ID for external or dynamic record inputs/outputs.
143        let id_dynamic = compute_console_dynamic_or_external_record_id(
144            function_id,
145            record_dynamic.to_fields()?,
146            tvk,
147            U16::new(record_register_index),
148        )?;
149        let is_to_static = Uniform::rand(rng);
150        let is_external_record = Uniform::rand(rng);
151        let id_static = Uniform::rand(rng);
152
153        let translation_assignment = TranslationAssignment::new(
154            record_static,
155            record_dynamic,
156            program_id,
157            function_id,
158            record_name,
159            is_to_static,
160            is_external_record,
161            tvk,
162            record_view_key,
163            gamma,
164            record_register_index,
165            id_dynamic,
166            id_static,
167        );
168
169        // Construct the translation circuit.
170        let circuit_assignment = translation_assignment.to_circuit_assignment::<A>(translation_index)?;
171
172        // Synthesize the proving and verifying key.
173        let (proving_key, verifying_key) =
174            self.universal_srs.to_circuit_key(&record_name.to_string(), &circuit_assignment)?;
175        // Insert the proving key.
176        self.insert_proving_key(&record_name, proving_key)?;
177        // Insert the verifying key.
178        self.insert_verifying_key(&record_name, verifying_key)
179    }
180}