snarkvm_synthesizer_process/stack/
deploy.rs1use super::*;
17
18impl<N: Network> Stack<N> {
19 #[inline]
21 pub fn deploy<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(&self, rng: &mut R) -> Result<Deployment<N>> {
22 let timer = timer!("Stack::deploy");
23
24 ensure!(!self.program.functions().is_empty(), "Program '{}' has no functions", self.program.id());
26
27 let mut verifying_keys = Vec::with_capacity(self.program.functions().len() + self.program.records().len());
29
30 for function_name in self.program.functions().keys() {
32 self.synthesize_key::<A, R>(function_name, rng)?;
34 lap!(timer, "Synthesize key for {function_name}");
35
36 let proving_key = self.get_proving_key(function_name)?;
38 let verifying_key = self.get_verifying_key(function_name)?;
40 lap!(timer, "Retrieve the keys for {function_name}");
41
42 let certificate = Certificate::certify(&function_name.to_string(), &proving_key, &verifying_key)?;
44 lap!(timer, "Certify the circuit");
45
46 verifying_keys.push((*function_name, (verifying_key, certificate)));
48 }
49
50 for record_name in self.program.records().keys() {
52 self.synthesize_translation_key::<A, R>(record_name, rng)?;
54 lap!(timer, "Synthesize key for translation circuit for {record_name}");
55
56 let proving_key = self.get_proving_key(record_name)?;
58
59 let verifying_key = self.get_verifying_key(record_name)?;
61 lap!(timer, "Retrieve the keys for translation circuit for {record_name}");
62
63 let certificate = Certificate::certify(&record_name.to_string(), &proving_key, &verifying_key)?;
65 lap!(timer, "Certify the circuit");
66
67 verifying_keys.push((*record_name, (verifying_key, certificate)));
69 }
70
71 finish!(timer);
72
73 Deployment::new(
78 *self.program_edition,
79 self.program.clone(),
80 verifying_keys,
81 Some(self.program.to_checksum()),
82 Some(Address::zero()),
83 )
84 }
85
86 #[inline]
88 pub fn verify_deployment<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
89 &self,
90 _consensus_version: ConsensusVersion,
91 deployment: &Deployment<N>,
92 rng: &mut R,
93 ) -> Result<()> {
94 let timer = timer!("Stack::verify_deployment");
95
96 if cfg!(all(feature = "dev_skip_checks", feature = "test_consensus_heights")) {
100 return Ok(());
101 }
102
103 deployment.check_is_ordered()?;
107
108 ensure!(&self.program == deployment.program(), "The stack program does not match the deployment program");
110 if let Some(program_checksum) = deployment.program_checksum() {
112 ensure!(
113 program_checksum == self.program_checksum,
114 "The deployment checksum does not match the stack checksum"
115 );
116 }
117
118 let program_id = self.program.id();
122
123 ensure!(deployment.num_combined_variables()? <= N::MAX_DEPLOYMENT_VARIABLES);
125 ensure!(deployment.num_combined_constraints()? <= N::MAX_DEPLOYMENT_CONSTRAINTS);
127
128 let mut call_stacks = Vec::with_capacity(deployment.function_verifying_keys().len());
130
131 let root_tvk = None;
133 let caller = None;
135
136 ensure!(
138 deployment.program().functions().len() == deployment.function_verifying_keys().len(),
139 "The number of functions in the program does not match the number of function verifying keys"
140 );
141
142 #[cfg(not(any(test, feature = "test")))]
143 if (ConsensusVersion::V1..=ConsensusVersion::V7).contains(&_consensus_version) {
146 finish!(timer);
147 return Ok(());
148 }
149
150 let seed = u64::from_bytes_le(&deployment.to_deployment_id()?.to_bytes_le()?[0..8])?;
154 let mut seeded_rng = rand_chacha::ChaChaRng::seed_from_u64(seed);
155
156 for (function, (_, (verifying_key, _))) in
158 deployment.program().functions().values().zip_eq(deployment.function_verifying_keys())
159 {
160 let burner_private_key = PrivateKey::new(rng)?;
162 let burner_address = Address::try_from(&burner_private_key)?;
164 let input_types = function.input_types();
166 let program_checksum = match self.program().contains_constructor() {
168 true => Some(self.program_checksum_as_field()?),
169 false => None,
170 };
171 let inputs = input_types
173 .iter()
174 .map(|input_type| match input_type {
175 ValueType::ExternalRecord(locator) => {
176 let stack = self.get_external_stack(locator.program_id())?;
178 stack.sample_value(
180 &burner_address,
181 &ValueType::Record(*locator.resource()).into(),
182 &mut seeded_rng,
183 )
184 }
185 _ => self.sample_value(&burner_address, &input_type.into(), &mut seeded_rng),
186 })
187 .collect::<Result<Vec<_>>>()?;
188 lap!(timer, "Sample the inputs");
189 let is_root = true;
191
192 let request = Request::sign(
194 &burner_private_key,
195 *program_id,
196 *function.name(),
197 inputs.into_iter(),
198 &input_types,
199 root_tvk,
200 is_root,
201 program_checksum,
202 false,
203 rng,
204 )?;
205 lap!(timer, "Compute the request for {}", function.name());
206 let assignments = Assignments::<N>::default();
208 let Some(constraint_limit) = verifying_key.circuit_info.num_constraints.checked_sub(1) else {
210 bail!("The constraint limit of 0 for function '{}' is invalid", function.name());
212 };
213 let variable_limit = verifying_key.num_variables();
215 let call_stack = CallStack::CheckDeployment(
217 vec![request],
218 burner_private_key,
219 assignments.clone(),
220 Some(constraint_limit as u64),
221 Some(variable_limit),
222 );
223 call_stacks.push((function.name(), call_stack, assignments));
225 }
226
227 let rngs = (0..call_stacks.len()).map(|_| StdRng::from_seed(seeded_rng.random())).collect::<Vec<_>>();
229 cfg_into_iter!(call_stacks).zip_eq(deployment.function_verifying_keys()).zip_eq(rngs).try_for_each(
230 |(((function_name, call_stack, assignments), (_, (verifying_key, certificate))), mut rng)| {
231 if let Err(err) = self.execute_function::<A, _>(call_stack, caller, root_tvk, &mut rng) {
233 bail!("Failed to synthesize the circuit for '{function_name}': {err}")
234 }
235 match assignments.read().last() {
237 None => bail!("The assignment for function '{function_name}' is missing in '{program_id}'"),
238 Some((assignment, _metrics)) => {
239 if !certificate.verify(&function_name.to_string(), assignment, verifying_key) {
241 bail!("The certificate for function '{function_name}' is invalid in '{program_id}'")
242 }
243 }
244 };
245 Ok(())
246 },
247 )?;
248
249 if let Some(translation_verifying_keys) = deployment.translation_verifying_keys() {
251 ensure!(
253 deployment.program().records().len() == translation_verifying_keys.len(),
254 "The number of records in the program does not match the number of translation verifying keys"
255 );
256 let translation_names_assignments = deployment
257 .program()
258 .records()
259 .iter()
260 .map(|(record_name, _record_type)| {
261 let program_id = *self.program_id();
263 let function_id = Field::<N>::from_u64(Uniform::rand(rng));
264 let record_name = *record_name;
265 let record_static = self.sample_record(&Address::rand(rng), &record_name, Group::rand(rng), rng)?;
266 let record_dynamic = DynamicRecord::<N>::from_record(&record_static)?;
267 let translation_index: u16 = Uniform::rand(rng);
268 let tvk = Uniform::rand(rng);
269 let record_register_index = Uniform::rand(rng);
270 let record_view_key: Option<Field<N>> = UniformExt::rand_option(rng);
271 let gamma: Option<Group<N>> = UniformExt::rand_option(rng);
272 let id_dynamic = compute_console_dynamic_or_external_record_id(
273 function_id,
274 record_dynamic.to_fields()?,
275 tvk,
276 U16::new(record_register_index),
277 )?;
278 let is_to_static = Uniform::rand(rng);
279 let is_external_record = Uniform::rand(rng);
280 let id_static = Uniform::rand(rng);
281
282 lap!(timer, "Sample the inputs to the translation circuit for record {record_name}");
283
284 Ok((
285 record_name,
286 translation_index,
287 TranslationAssignment::new(
288 record_static,
289 record_dynamic,
290 program_id,
291 function_id,
292 record_name,
293 is_to_static,
294 is_external_record,
295 tvk,
296 record_view_key,
297 gamma,
298 record_register_index,
299 id_dynamic,
300 id_static,
301 ),
302 ))
303 })
304 .collect::<Result<Vec<_>>>()?;
305
306 cfg_into_iter!(translation_names_assignments).zip_eq(translation_verifying_keys).try_for_each(
311 |((record_name, translation_index, translation_assignment), (_, (verifying_key, certificate)))| {
312 match translation_assignment.to_circuit_assignment::<A>(translation_index) {
314 Err(err) => Err(anyhow!("Failed to synthesize the circuit for '{record_name}': {err}")),
315 Ok(circuit_assignment) => {
316 ensure!(
318 certificate.verify(&record_name.to_string(), &circuit_assignment, verifying_key),
319 "The translation-circuit certificate for record '{record_name}' is invalid in '{program_id}'"
320 );
321 Ok(())
322 },
323 }
324 })?;
325 }
326
327 finish!(timer);
328
329 Ok(())
330 }
331}