Skip to main content

tasm_lib/verifier/challenges/
new_generic_dyn_claim.rs

1use num::One;
2use triton_vm::air::challenge_id::ChallengeId;
3use triton_vm::air::cross_table_argument::CrossTableArg;
4use triton_vm::air::cross_table_argument::EvalArg;
5use triton_vm::challenges::Challenges;
6use triton_vm::prelude::*;
7use twenty_first::math::x_field_element::EXTENSION_DEGREE;
8
9use crate::hashing::algebraic_hasher::sample_scalars_static_length_static_pointer::SampleScalarsStaticLengthStaticPointer;
10use crate::prelude::*;
11use crate::verifier::challenges::shared::challenges_data_type;
12use crate::verifier::claim::shared::claim_type;
13use crate::verifier::eval_arg::compute_terminal_const_sized_static_symbols::ComputeTerminalConstSizedStaticSymbols;
14use crate::verifier::eval_arg::compute_terminal_dyn_sized_dynamic_symbols::ComputeTerminalDynSizedDynamicSymbols;
15use crate::verifier::eval_arg::compute_terminal_from_digest::ComputeTerminalFromDigestInitialIsOne;
16
17/// Calculate a `Challenges` structure from a claim that is only known at runtime
18#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
19pub struct NewGenericDynClaim {
20    num_of_fiat_shamir_challenges: usize,
21    num_of_claim_derived_challenges: usize,
22
23    /// Memory address to store the challenges
24    pub challenges_pointer: BFieldElement,
25}
26
27impl NewGenericDynClaim {
28    /// An instantiation of this snippet that contains the same number of
29    /// challenges that TVM uses in its STARK engine
30    pub fn tvm_challenges(challenges_pointer: BFieldElement) -> Self {
31        Self {
32            num_of_fiat_shamir_challenges: Challenges::SAMPLE_COUNT,
33            num_of_claim_derived_challenges: ChallengeId::NUM_DERIVED_CHALLENGES,
34            challenges_pointer,
35        }
36    }
37
38    pub fn new(
39        num_challenges_to_sample: usize,
40        num_challenges_to_compute: usize,
41        challenges_pointer: BFieldElement,
42    ) -> Self {
43        Self {
44            num_of_fiat_shamir_challenges: num_challenges_to_sample,
45            num_of_claim_derived_challenges: num_challenges_to_compute,
46            challenges_pointer,
47        }
48    }
49
50    fn total_number_of_challenges_returned(&self) -> usize {
51        self.num_of_fiat_shamir_challenges + self.num_of_claim_derived_challenges
52    }
53
54    fn sample_scalars_snippet(&self) -> SampleScalarsStaticLengthStaticPointer {
55        SampleScalarsStaticLengthStaticPointer {
56            num_elements_to_sample: self.num_of_fiat_shamir_challenges,
57            extra_capacity: self.num_of_claim_derived_challenges,
58            scalars_pointer: self.challenges_pointer,
59        }
60    }
61}
62
63impl BasicSnippet for NewGenericDynClaim {
64    fn parameters(&self) -> Vec<(DataType, String)> {
65        vec![(DataType::StructRef(claim_type()), "*claim".to_owned())]
66    }
67
68    fn return_values(&self) -> Vec<(DataType, String)> {
69        vec![(
70            challenges_data_type(self.total_number_of_challenges_returned()),
71            "challenges".to_owned(),
72        )]
73    }
74
75    fn entrypoint(&self) -> String {
76        format!(
77            "tasmlib_verifier_challenges_new_generic_dyn_claim_{}_{}",
78            self.num_of_fiat_shamir_challenges, self.num_of_claim_derived_challenges,
79        )
80    }
81
82    fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
83        let entrypoint = self.entrypoint();
84        let sample_scalars_snippet = self.sample_scalars_snippet();
85        let sample_scalars = library.import(Box::new(sample_scalars_snippet));
86        let compute_compressed_digest =
87            library.import(Box::new(ComputeTerminalFromDigestInitialIsOne));
88        let calculate_lookup_terminal =
89            library.import(Box::new(ComputeTerminalConstSizedStaticSymbols {
90                symbols: tip5::LOOKUP_TABLE.map(|i| BFieldElement::new(i as u64)),
91                initial: XFieldElement::one(),
92            }));
93        let calculate_io_terminal = library.import(Box::new(ComputeTerminalDynSizedDynamicSymbols));
94
95        let scalars_pointer = self.challenges_pointer;
96        let scalar_write_index = |i: ChallengeId| {
97            scalars_pointer.value() + u64::try_from(i.index() * EXTENSION_DEGREE).unwrap()
98        };
99        let scalar_read_index =
100            |i: ChallengeId| scalar_write_index(i) + u64::try_from(EXTENSION_DEGREE - 1).unwrap();
101
102        let default_initial = EvalArg::default_initial();
103
104        triton_asm!(
105            {entrypoint}:
106                // _ *claim
107                call {sample_scalars}
108                // _ *claim
109
110                // Calculate and store `output_terminal`:
111                push {scalar_read_index(ChallengeId::StandardOutputIndeterminate)}
112                read_mem {EXTENSION_DEGREE}
113                pop 1
114                // _ *claim [standard_output_indeterminate; 3]
115
116                push {default_initial.coefficients[2]}
117                push {default_initial.coefficients[1]}
118                push {default_initial.coefficients[0]}
119                // _ *claim [standard_output_indeterminate; 3] [initial; 3]
120
121                dup 6
122                push 1
123                add
124                // _ *claim [standard_output_indeterminate; 3] [initial; 3] *outputs
125
126                call {calculate_io_terminal}
127                // _ *claim [standard_output_terminal; 3]
128
129                push {scalar_write_index(ChallengeId::StandardOutputTerminal)}
130                write_mem {EXTENSION_DEGREE}
131                pop 1
132                // _ *claim
133
134                // Calculate and store `input_terminal`:
135                push {scalar_read_index(ChallengeId::StandardInputIndeterminate)}
136                read_mem {EXTENSION_DEGREE}
137                pop 1
138                // _ *claim [standard_input_indeterminate; 3]
139
140                push {default_initial.coefficients[2]}
141                push {default_initial.coefficients[1]}
142                push {default_initial.coefficients[0]}
143                // _ *claim [standard_input_indeterminate; 3] [initial; 3]
144
145                dup 6
146                read_mem 1
147                push 3
148                add
149                add
150                // _ *claim [standard_input_indeterminate; 3] [initial; 3] *inputs
151
152                dup 0
153                swap 8
154                pop 1
155                // _ *inputs [standard_input_indeterminate; 3] [initial; 3] *inputs
156
157                call {calculate_io_terminal}
158                // _ *inputs [standard_input_terminal; 3]
159
160                push {scalar_write_index(ChallengeId::StandardInputTerminal)}
161                write_mem {EXTENSION_DEGREE}
162                pop 1
163                // _ *inputs
164
165                read_mem 1
166                // _ inputs_len (*inputs-1)
167
168                addi {1 + 1 + Digest::LEN} // skip field `version` (of length 1)
169                add
170                // _ *digest_last_word
171
172                push {scalar_read_index(ChallengeId::CompressProgramDigestIndeterminate)}
173                read_mem {EXTENSION_DEGREE}
174                pop 1
175                // _ *digest_last_word [compress_program_digest_indeterminate; 3]
176
177                dup 3
178                read_mem {Digest::LEN}
179                pop 1
180                // _ *digest_last_word [compress_program_digest_indeterminate; 3] [program_digest; 5]
181
182                call {compute_compressed_digest}
183                // _ *digest_last_word [compressed_digest; 3]
184
185                // **** Write compressed_digest to challenges array ****
186                push {scalar_write_index(ChallengeId::CompressedProgramDigest)}
187                write_mem {EXTENSION_DEGREE}
188                pop 2
189                // _
190
191                // **** Calculate lookup_terminal ****
192                push {scalar_read_index(ChallengeId::LookupTablePublicIndeterminate)}
193                read_mem {EXTENSION_DEGREE}
194                pop 1
195                // _ [lookup_table_public_indeterminate]
196
197                call {calculate_lookup_terminal}
198                // _ [lookup_terminal]
199
200                // **** Write lookup_terminal to challenges array ****
201                push {scalar_write_index(ChallengeId::LookupTablePublicTerminal)}
202                write_mem {EXTENSION_DEGREE}
203                pop 1
204
205                // _
206
207                push {scalars_pointer}
208                // _ *scalars
209
210                return
211        )
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use triton_vm::challenges::Challenges;
218    use twenty_first::math::other::random_elements;
219
220    use super::*;
221    use crate::rust_shadowing_helper_functions::array::insert_as_array;
222    use crate::rust_shadowing_helper_functions::claim::load_claim_from_memory;
223    use crate::test_prelude::*;
224    use crate::verifier::challenges::shared::conventional_challenges_pointer;
225
226    impl Procedure for NewGenericDynClaim {
227        fn rust_shadow(
228            &self,
229            stack: &mut Vec<BFieldElement>,
230            memory: &mut HashMap<BFieldElement, BFieldElement>,
231            _nondeterminism: &NonDeterminism,
232            _public_input: &[BFieldElement],
233            sponge: &mut Option<Tip5>,
234        ) -> Result<Vec<BFieldElement>, RustShadowError> {
235            let Some(sponge) = sponge.as_mut() else {
236                return Err(RustShadowError::SpongeUninitialized);
237            };
238            let claim_pointer = stack.pop().ok_or(RustShadowError::StackUnderflow)?;
239            let claim = load_claim_from_memory(claim_pointer, memory);
240            let challenges = sponge.sample_scalars(self.num_of_fiat_shamir_challenges);
241            let challenges = Challenges::new(challenges, &claim);
242
243            let challenges_pointer = self.challenges_pointer;
244            stack.push(challenges_pointer);
245
246            insert_as_array(challenges_pointer, memory, challenges.challenges.to_vec());
247
248            Ok(Vec::new())
249        }
250
251        fn pseudorandom_initial_state(
252            &self,
253            seed: [u8; 32],
254            bench_case: Option<BenchmarkCase>,
255        ) -> ProcedureInitialState {
256            let mut rng = StdRng::from_seed(seed);
257            let (input_length, output_length) = match bench_case {
258                Some(BenchmarkCase::CommonCase) => (0, 0),
259                Some(BenchmarkCase::WorstCase) => (100, 100),
260                None => (rng.random_range(0..1000), rng.random_range(0..1000)),
261            };
262
263            let claim = Claim::new(rng.random())
264                .with_input(random_elements(input_length))
265                .with_output(random_elements(output_length));
266
267            let mut memory = HashMap::default();
268
269            let claim_pointer = rng.random();
270            encode_to_memory(&mut memory, claim_pointer, &claim);
271
272            let stack = [self.init_stack_for_isolated_run(), vec![claim_pointer]].concat();
273            let sponge = Tip5 {
274                state: rng.random(),
275            };
276
277            ProcedureInitialState {
278                stack,
279                sponge: Some(sponge),
280                nondeterminism: NonDeterminism::default().with_ram(memory),
281                public_input: vec![],
282            }
283        }
284    }
285
286    #[macro_rules_attr::apply(test)]
287    fn new_challenges_pbt() {
288        ShadowedProcedure::new(NewGenericDynClaim::tvm_challenges(
289            conventional_challenges_pointer(),
290        ))
291        .test();
292    }
293}
294
295#[cfg(test)]
296mod benches {
297    use super::*;
298    use crate::test_prelude::*;
299    use crate::verifier::challenges::shared::conventional_challenges_pointer;
300
301    #[macro_rules_attr::apply(test)]
302    fn bench_for_challenges_calc_for_recufier() {
303        ShadowedProcedure::new(NewGenericDynClaim::tvm_challenges(
304            conventional_challenges_pointer(),
305        ))
306        .bench();
307    }
308}