snarkvm_synthesizer_process/stack/helpers/
sample.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 super::*;
17
18impl<N: Network> Stack<N> {
19    /// Samples a plaintext value according to the given plaintext type.
20    pub fn sample_plaintext<R: Rng + CryptoRng>(
21        &self,
22        plaintext_type: &PlaintextType<N>,
23        rng: &mut R,
24    ) -> Result<Plaintext<N>> {
25        // Sample a plaintext value.
26        let plaintext = self.sample_plaintext_internal(plaintext_type, 0, rng)?;
27        // Ensure the plaintext value matches the plaintext type.
28        self.matches_plaintext(&plaintext, plaintext_type)?;
29        // Return the plaintext value.
30        Ok(plaintext)
31    }
32
33    /// Samples a future value according to the given future type.
34    pub fn sample_future<R: Rng + CryptoRng>(&self, locator: &Locator<N>, rng: &mut R) -> Result<Future<N>> {
35        // Sample a future value.
36        let future = self.sample_future_internal(locator, 0, rng)?;
37        // Ensure the future value matches the future type.
38        self.matches_future(&future, locator)?;
39        // Return the future value.
40        Ok(future)
41    }
42
43    /// Returns a record for the given record name.
44    pub(crate) fn sample_record_internal<R: Rng + CryptoRng>(
45        &self,
46        burner_address: &Address<N>,
47        record_name: &Identifier<N>,
48        nonce: Group<N>,
49        depth: usize,
50        rng: &mut R,
51    ) -> Result<Record<N, Plaintext<N>>> {
52        // If the depth exceeds the maximum depth, then the plaintext type is invalid.
53        ensure!(depth <= N::MAX_DATA_DEPTH, "Plaintext exceeded maximum depth of {}", N::MAX_DATA_DEPTH);
54
55        // Retrieve the record type from the program.
56        let record_type = self.program.get_record(record_name)?;
57
58        // Initialize the owner based on the visibility.
59        let owner = match record_type.owner().is_public() {
60            true => RecordOwner::Public(*burner_address),
61            false => RecordOwner::Private(Plaintext::Literal(Literal::Address(*burner_address), Default::default())),
62        };
63
64        // Initialize the record data according to the defined type.
65        let data = record_type
66            .entries()
67            .iter()
68            .map(|(entry_name, entry_type)| {
69                // Sample the entry value.
70                let entry = self.sample_entry_internal(entry_type, depth + 1, rng)?;
71                // Return the entry.
72                Ok((*entry_name, entry))
73            })
74            .collect::<Result<IndexMap<_, _>>>()?;
75
76        // Set the record version.
77        let version = U8::<N>::rand(rng);
78
79        // Return the record.
80        Record::<N, Plaintext<N>>::from_plaintext(owner, data, nonce, version)
81    }
82
83    /// Samples an entry according to the given entry type.
84    fn sample_entry_internal<R: Rng + CryptoRng>(
85        &self,
86        entry_type: &EntryType<N>,
87        depth: usize,
88        rng: &mut R,
89    ) -> Result<Entry<N, Plaintext<N>>> {
90        // If the depth exceeds the maximum depth, then the entry type is invalid.
91        ensure!(depth <= N::MAX_DATA_DEPTH, "Entry exceeded maximum depth of {}", N::MAX_DATA_DEPTH);
92
93        match entry_type {
94            EntryType::Constant(plaintext_type)
95            | EntryType::Public(plaintext_type)
96            | EntryType::Private(plaintext_type) => {
97                // Sample the plaintext value.
98                let plaintext = self.sample_plaintext_internal(plaintext_type, depth, rng)?;
99                // Return the entry.
100                match entry_type {
101                    EntryType::Constant(..) => Ok(Entry::Constant(plaintext)),
102                    EntryType::Public(..) => Ok(Entry::Public(plaintext)),
103                    EntryType::Private(..) => Ok(Entry::Private(plaintext)),
104                }
105            }
106        }
107    }
108
109    /// Samples a plaintext value according to the given plaintext type.
110    fn sample_plaintext_internal<R: Rng + CryptoRng>(
111        &self,
112        plaintext_type: &PlaintextType<N>,
113        depth: usize,
114        rng: &mut R,
115    ) -> Result<Plaintext<N>> {
116        // If the depth exceeds the maximum depth, then the plaintext type is invalid.
117        ensure!(depth <= N::MAX_DATA_DEPTH, "Plaintext exceeded maximum depth of {}", N::MAX_DATA_DEPTH);
118
119        // Sample the plaintext value.
120        let plaintext = match plaintext_type {
121            // Sample a literal.
122            PlaintextType::Literal(literal_type) => {
123                Plaintext::Literal(Literal::sample(*literal_type, rng), Default::default())
124            }
125            // Sample a struct.
126            PlaintextType::Struct(struct_name) => {
127                // Retrieve the struct.
128                let struct_ = self.program.get_struct(struct_name)?;
129                // Sample each member of the struct.
130                let members = struct_
131                    .members()
132                    .iter()
133                    .map(|(member_name, member_type)| {
134                        // Sample the member value.
135                        let member = self.sample_plaintext_internal(member_type, depth + 1, rng)?;
136                        // Return the member.
137                        Ok((*member_name, member))
138                    })
139                    .collect::<Result<IndexMap<_, _>>>()?;
140
141                Plaintext::Struct(members, Default::default())
142            }
143            // Sample an array.
144            PlaintextType::Array(array_type) => {
145                // Sample each element of the array.
146                let elements = (0..**array_type.length())
147                    .map(|_| {
148                        // Sample the element value.
149                        self.sample_plaintext_internal(array_type.next_element_type(), depth + 1, rng)
150                    })
151                    .collect::<Result<Vec<_>>>()?;
152
153                Plaintext::Array(elements, Default::default())
154            }
155        };
156        // Return the plaintext.
157        Ok(plaintext)
158    }
159
160    /// Samples a future value according to the given locator.
161    fn sample_future_internal<R: Rng + CryptoRng>(
162        &self,
163        locator: &Locator<N>,
164        depth: usize,
165        rng: &mut R,
166    ) -> Result<Future<N>> {
167        // Retrieve the external stack, if needed.
168        let external_stack = match locator.program_id() == self.program_id() {
169            true => None,
170            // Attention - This method must fail here and early return if the external program is missing.
171            // Otherwise, this method will proceed to look for the requested function in its own program.
172            false => Some(self.get_external_stack(locator.program_id())?),
173        };
174        // Retrieve the associated function.
175        let function = match &external_stack {
176            Some(external_stack) => external_stack.get_function_ref(locator.resource())?,
177            None => self.get_function_ref(locator.resource())?,
178        };
179
180        // Retrieve the finalize inputs.
181        let inputs = match function.finalize_logic() {
182            Some(finalize_logic) => finalize_logic.inputs(),
183            None => bail!("Function '{locator}' does not have a finalize block"),
184        };
185
186        let arguments = inputs
187            .into_iter()
188            .map(|input| {
189                match input.finalize_type() {
190                    FinalizeType::Plaintext(plaintext_type) => {
191                        // Sample the plaintext value.
192                        let plaintext = self.sample_plaintext_internal(plaintext_type, depth + 1, rng)?;
193                        // Return the argument.
194                        Ok(Argument::Plaintext(plaintext))
195                    }
196                    FinalizeType::Future(locator) => {
197                        // Sample the future value.
198                        let future = self.sample_future_internal(locator, depth + 1, rng)?;
199                        // Return the argument.
200                        Ok(Argument::Future(future))
201                    }
202                }
203            })
204            .collect::<Result<Vec<_>>>()?;
205
206        Ok(Future::new(*locator.program_id(), *locator.resource(), arguments))
207    }
208}