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