snarkvm_synthesizer_program/traits/
stack_and_registers.rs

1// Copyright 2024-2025 Aleo Network Foundation
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 std::sync::Arc;
17
18use crate::{FinalizeGlobalState, Function, Operand, Program};
19use console::{
20    account::Group,
21    network::Network,
22    prelude::{Result, bail},
23    program::{
24        Future,
25        Identifier,
26        Literal,
27        Locator,
28        Plaintext,
29        PlaintextType,
30        ProgramID,
31        Record,
32        Register,
33        RegisterType,
34        Value,
35        ValueType,
36    },
37    types::{Address, Field},
38};
39use rand::{CryptoRng, Rng};
40use synthesizer_snark::{ProvingKey, VerifyingKey};
41
42pub trait StackKeys<N: Network> {
43    /// Returns `true` if the proving key for the given function name exists.
44    fn contains_proving_key(&self, function_name: &Identifier<N>) -> bool;
45
46    /// Returns the proving key for the given function name.
47    fn get_proving_key(&self, function_name: &Identifier<N>) -> Result<ProvingKey<N>>;
48
49    /// Inserts the proving key for the given function name.
50    fn insert_proving_key(&self, function_name: &Identifier<N>, proving_key: ProvingKey<N>) -> Result<()>;
51
52    /// Removes the proving key for the given function name.
53    fn remove_proving_key(&self, function_name: &Identifier<N>);
54
55    /// Returns `true` if the verifying key for the given function name exists.
56    fn contains_verifying_key(&self, function_name: &Identifier<N>) -> bool;
57
58    /// Returns the verifying key for the given function name.
59    fn get_verifying_key(&self, function_name: &Identifier<N>) -> Result<VerifyingKey<N>>;
60
61    /// Inserts the verifying key for the given function name.
62    fn insert_verifying_key(&self, function_name: &Identifier<N>, verifying_key: VerifyingKey<N>) -> Result<()>;
63
64    /// Removes the verifying key for the given function name.
65    fn remove_verifying_key(&self, function_name: &Identifier<N>);
66}
67
68pub trait StackMatches<N: Network> {
69    /// Checks that the given value matches the layout of the value type.
70    fn matches_value_type(&self, value: &Value<N>, value_type: &ValueType<N>) -> Result<()>;
71
72    /// Checks that the given stack value matches the layout of the register type.
73    fn matches_register_type(&self, stack_value: &Value<N>, register_type: &RegisterType<N>) -> Result<()>;
74
75    /// Checks that the given record matches the layout of the external record type.
76    fn matches_external_record(&self, record: &Record<N, Plaintext<N>>, locator: &Locator<N>) -> Result<()>;
77
78    /// Checks that the given record matches the layout of the record type.
79    fn matches_record(&self, record: &Record<N, Plaintext<N>>, record_name: &Identifier<N>) -> Result<()>;
80
81    /// Checks that the given plaintext matches the layout of the plaintext type.
82    fn matches_plaintext(&self, plaintext: &Plaintext<N>, plaintext_type: &PlaintextType<N>) -> Result<()>;
83
84    /// Checks that the given future matches the layout of the future type.
85    fn matches_future(&self, future: &Future<N>, locator: &Locator<N>) -> Result<()>;
86}
87
88pub trait StackProgram<N: Network> {
89    /// Returns the program.
90    fn program(&self) -> &Program<N>;
91
92    /// Returns the program ID.
93    fn program_id(&self) -> &ProgramID<N>;
94
95    /// Returns the program depth.
96    fn program_depth(&self) -> usize;
97
98    /// Returns the program address.
99    fn program_address(&self) -> &Address<N>;
100
101    /// Returns the external stack for the given program ID.
102    fn get_external_stack(&self, program_id: &ProgramID<N>) -> Result<Arc<Self>>;
103
104    /// Returns the expected finalize cost for the given function name.
105    fn get_finalize_cost(&self, function_name: &Identifier<N>) -> Result<u64>;
106
107    /// Returns the function with the given function name.
108    fn get_function(&self, function_name: &Identifier<N>) -> Result<Function<N>>;
109
110    /// Returns a reference to the function with the given function name.
111    fn get_function_ref(&self, function_name: &Identifier<N>) -> Result<&Function<N>>;
112
113    /// Returns the expected number of calls for the given function name.
114    fn get_number_of_calls(&self, function_name: &Identifier<N>) -> Result<usize>;
115
116    /// Samples a value for the given value_type.
117    fn sample_value<R: Rng + CryptoRng>(
118        &self,
119        burner_address: &Address<N>,
120        value_type: &ValueType<N>,
121        rng: &mut R,
122    ) -> Result<Value<N>>;
123
124    /// Returns a record for the given record name, with the given burner address and nonce.
125    fn sample_record<R: Rng + CryptoRng>(
126        &self,
127        burner_address: &Address<N>,
128        record_name: &Identifier<N>,
129        record_nonce: Group<N>,
130        rng: &mut R,
131    ) -> Result<Record<N, Plaintext<N>>>;
132
133    /// Returns a record for the given record name, deriving the nonce from tvk and index.
134    fn sample_record_using_tvk<R: Rng + CryptoRng>(
135        &self,
136        burner_address: &Address<N>,
137        record_name: &Identifier<N>,
138        tvk: Field<N>,
139        index: Field<N>,
140        rng: &mut R,
141    ) -> Result<Record<N, Plaintext<N>>>;
142}
143
144pub trait FinalizeRegistersState<N: Network> {
145    /// Returns the global state for the finalize scope.
146    fn state(&self) -> &FinalizeGlobalState;
147
148    /// Returns the transition ID for the finalize scope.
149    fn transition_id(&self) -> &N::TransitionID;
150
151    /// Returns the function name for the finalize scope.
152    fn function_name(&self) -> &Identifier<N>;
153
154    /// Returns the nonce for the finalize registers.
155    fn nonce(&self) -> u64;
156}
157
158pub trait RegistersSigner<N: Network> {
159    /// Returns the transition signer.
160    fn signer(&self) -> Result<Address<N>>;
161
162    /// Sets the transition signer.
163    fn set_signer(&mut self, signer: Address<N>);
164
165    /// Returns the root transition view key.
166    fn root_tvk(&self) -> Result<Field<N>>;
167
168    /// Sets the root transition view key.
169    fn set_root_tvk(&mut self, root_tvk: Field<N>);
170
171    /// Returns the transition caller.
172    fn caller(&self) -> Result<Address<N>>;
173
174    /// Sets the transition caller.
175    fn set_caller(&mut self, caller: Address<N>);
176
177    /// Returns the transition view key.
178    fn tvk(&self) -> Result<Field<N>>;
179
180    /// Sets the transition view key.
181    fn set_tvk(&mut self, tvk: Field<N>);
182}
183
184pub trait RegistersSignerCircuit<N: Network, A: circuit::Aleo<Network = N>> {
185    /// Returns the transition signer, as a circuit.
186    fn signer_circuit(&self) -> Result<circuit::Address<A>>;
187
188    /// Sets the transition signer, as a circuit.
189    fn set_signer_circuit(&mut self, signer_circuit: circuit::Address<A>);
190
191    /// Returns the root transition view key, as a circuit.
192    fn root_tvk_circuit(&self) -> Result<circuit::Field<A>>;
193
194    /// Sets the root transition view key, as a circuit.
195    fn set_root_tvk_circuit(&mut self, root_tvk_circuit: circuit::Field<A>);
196
197    /// Returns the transition caller, as a circuit.
198    fn caller_circuit(&self) -> Result<circuit::Address<A>>;
199
200    /// Sets the transition caller, as a circuit.
201    fn set_caller_circuit(&mut self, caller_circuit: circuit::Address<A>);
202
203    /// Returns the transition view key, as a circuit.
204    fn tvk_circuit(&self) -> Result<circuit::Field<A>>;
205
206    /// Sets the transition view key, as a circuit.
207    fn set_tvk_circuit(&mut self, tvk_circuit: circuit::Field<A>);
208}
209
210pub trait RegistersLoad<N: Network> {
211    /// Loads the value of a given operand.
212    ///
213    /// # Errors
214    /// This method should halt if the register locator is not found.
215    /// In the case of register members, this method should halt if the member is not found.
216    fn load(&self, stack: &(impl StackMatches<N> + StackProgram<N>), operand: &Operand<N>) -> Result<Value<N>>;
217
218    /// Loads the literal of a given operand.
219    ///
220    /// # Errors
221    /// This method should halt if the given operand is not a literal.
222    /// This method should halt if the register locator is not found.
223    /// In the case of register members, this method should halt if the member is not found.
224    #[inline]
225    fn load_literal(
226        &self,
227        stack: &(impl StackMatches<N> + StackProgram<N>),
228        operand: &Operand<N>,
229    ) -> Result<Literal<N>> {
230        match self.load(stack, operand)? {
231            Value::Plaintext(Plaintext::Literal(literal, ..)) => Ok(literal),
232            Value::Plaintext(Plaintext::Struct(..))
233            | Value::Plaintext(Plaintext::Array(..))
234            | Value::Record(..)
235            | Value::Future(..) => {
236                bail!("Operand must be a literal")
237            }
238        }
239    }
240
241    /// Loads the plaintext of a given operand.
242    ///
243    /// # Errors
244    /// This method should halt if the given operand is not a plaintext.
245    /// This method should halt if the register locator is not found.
246    /// In the case of register members, this method should halt if the member is not found.
247    #[inline]
248    fn load_plaintext(
249        &self,
250        stack: &(impl StackMatches<N> + StackProgram<N>),
251        operand: &Operand<N>,
252    ) -> Result<Plaintext<N>> {
253        match self.load(stack, operand)? {
254            Value::Plaintext(plaintext) => Ok(plaintext),
255            Value::Record(..) | Value::Future(..) => bail!("Operand must be a plaintext"),
256        }
257    }
258}
259
260pub trait RegistersLoadCircuit<N: Network, A: circuit::Aleo<Network = N>> {
261    /// Loads the value of a given operand.
262    ///
263    /// # Errors
264    /// This method should halt if the register locator is not found.
265    /// In the case of register members, this method should halt if the member is not found.
266    fn load_circuit(
267        &self,
268        stack: &(impl StackMatches<N> + StackProgram<N>),
269        operand: &Operand<N>,
270    ) -> Result<circuit::Value<A>>;
271
272    /// Loads the literal of a given operand.
273    ///
274    /// # Errors
275    /// This method should halt if the given operand is not a literal.
276    /// This method should halt if the register locator is not found.
277    /// In the case of register members, this method should halt if the member is not found.
278    #[inline]
279    fn load_literal_circuit(
280        &self,
281        stack: &(impl StackMatches<N> + StackProgram<N>),
282        operand: &Operand<N>,
283    ) -> Result<circuit::Literal<A>> {
284        match self.load_circuit(stack, operand)? {
285            circuit::Value::Plaintext(circuit::Plaintext::Literal(literal, ..)) => Ok(literal),
286            circuit::Value::Plaintext(circuit::Plaintext::Struct(..))
287            | circuit::Value::Plaintext(circuit::Plaintext::Array(..))
288            | circuit::Value::Record(..)
289            | circuit::Value::Future(..) => bail!("Operand must be a literal"),
290        }
291    }
292
293    /// Loads the plaintext of a given operand.
294    ///
295    /// # Errors
296    /// This method should halt if the given operand is not a plaintext.
297    /// This method should halt if the register locator is not found.
298    /// In the case of register members, this method should halt if the member is not found.
299    #[inline]
300    fn load_plaintext_circuit(
301        &self,
302        stack: &(impl StackMatches<N> + StackProgram<N>),
303        operand: &Operand<N>,
304    ) -> Result<circuit::Plaintext<A>> {
305        match self.load_circuit(stack, operand)? {
306            circuit::Value::Plaintext(plaintext) => Ok(plaintext),
307            circuit::Value::Record(..) | circuit::Value::Future(..) => bail!("Operand must be a plaintext"),
308        }
309    }
310}
311
312pub trait RegistersStore<N: Network> {
313    /// Assigns the given value to the given register, assuming the register is not already assigned.
314    ///
315    /// # Errors
316    /// This method should halt if the given register is a register member.
317    /// This method should halt if the given register is an input register.
318    /// This method should halt if the register is already used.
319    fn store(
320        &mut self,
321        stack: &(impl StackMatches<N> + StackProgram<N>),
322        register: &Register<N>,
323        stack_value: Value<N>,
324    ) -> Result<()>;
325
326    /// Assigns the given literal to the given register, assuming the register is not already assigned.
327    ///
328    /// # Errors
329    /// This method should halt if the given register is a register member.
330    /// This method should halt if the given register is an input register.
331    /// This method should halt if the register is already used.
332    #[inline]
333    fn store_literal(
334        &mut self,
335        stack: &(impl StackMatches<N> + StackProgram<N>),
336        register: &Register<N>,
337        literal: Literal<N>,
338    ) -> Result<()> {
339        self.store(stack, register, Value::Plaintext(Plaintext::from(literal)))
340    }
341}
342
343pub trait RegistersStoreCircuit<N: Network, A: circuit::Aleo<Network = N>> {
344    /// Assigns the given value to the given register, assuming the register is not already assigned.
345    ///
346    /// # Errors
347    /// This method should halt if the given register is a register member.
348    /// This method should halt if the given register is an input register.
349    /// This method should halt if the register is already used.
350    fn store_circuit(
351        &mut self,
352        stack: &(impl StackMatches<N> + StackProgram<N>),
353        register: &Register<N>,
354        stack_value: circuit::Value<A>,
355    ) -> Result<()>;
356
357    /// Assigns the given literal to the given register, assuming the register is not already assigned.
358    ///
359    /// # Errors
360    /// This method should halt if the given register is a register member.
361    /// This method should halt if the given register is an input register.
362    /// This method should halt if the register is already used.
363    #[inline]
364    fn store_literal_circuit(
365        &mut self,
366        stack: &(impl StackMatches<N> + StackProgram<N>),
367        register: &Register<N>,
368        literal: circuit::Literal<A>,
369    ) -> Result<()> {
370        self.store_circuit(stack, register, circuit::Value::Plaintext(circuit::Plaintext::from(literal)))
371    }
372}