tasm_lib/verifier/master_table/
zerofiers_inverse.rs1use strum::EnumCount;
2use triton_vm::prelude::*;
3use triton_vm::table::ConstraintType;
4use twenty_first::math::x_field_element::EXTENSION_DEGREE;
5
6use crate::arithmetic::xfe::to_the_power_of_power_of_2::ToThePowerOfPowerOf2;
7use crate::prelude::*;
8
9#[derive(Debug, Copy, Clone)]
12pub struct ZerofiersInverse {
13 pub zerofiers_inverse_write_address: BFieldElement,
14}
15
16impl ZerofiersInverse {
17 pub(super) fn array_size() -> usize {
18 EXTENSION_DEGREE * ConstraintType::COUNT
19 }
20
21 fn zerofier_inv_write_address(&self, constraint_type: ConstraintType) -> BFieldElement {
23 let constraint_type_offset =
24 u64::try_from(EXTENSION_DEGREE * constraint_type as usize).unwrap();
25 self.zerofiers_inverse_write_address + bfe!(constraint_type_offset)
26 }
27
28 pub(super) fn zerofier_inv_read_address(
30 &self,
31 constraint_type: ConstraintType,
32 ) -> BFieldElement {
33 self.zerofier_inv_write_address(constraint_type)
34 + BFieldElement::new((EXTENSION_DEGREE - 1).try_into().unwrap())
35 }
36}
37
38impl BasicSnippet for ZerofiersInverse {
39 fn inputs(&self) -> Vec<(DataType, String)> {
40 vec![
41 (
42 DataType::Xfe,
43 "out_of_domain_point_curr_row_point".to_owned(),
44 ),
45 (DataType::U32, "padded_height".to_owned()),
46 (DataType::Bfe, "trace_domain_generator".to_owned()),
47 ]
48 }
49
50 fn outputs(&self) -> Vec<(DataType, String)> {
51 vec![]
52 }
53
54 fn entrypoint(&self) -> String {
55 "tasmlib_verifier_master_table_zerofiers_inverse".to_owned()
56 }
57
58 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
59 let xfe_mod_pow_pow_2 = library.import(Box::new(ToThePowerOfPowerOf2));
60
61 let calculate_initial_zerofier_inverse = triton_asm!(
62 dup 4
65 dup 4
66 dup 4
67 push -1
68 add
69 x_invert
70 );
72
73 let calculate_consistency_zerofier_inv = triton_asm!(
74 swap 1
77 log_2_floor
80
81 dup 4
82 dup 4
83 dup 4
84 call {xfe_mod_pow_pow_2}
87 push -1
90 add
91 x_invert
92 );
94
95 let calculate_except_last_row = triton_asm!(
96 invert
99 push -1
102 mul
103 add
104 );
106
107 let calculate_transition_zerofier_inv = triton_asm!(
108 dup 2
111 dup 2
112 dup 2
113 push {self.zerofier_inv_read_address(ConstraintType::Consistency)}
116 read_mem {EXTENSION_DEGREE}
117 pop 1
118 xx_mul
121 );
123
124 let calculate_terminal_zerofier_inv = triton_asm!(
125 x_invert );
128
129 let entrypoint = self.entrypoint();
130 triton_asm!(
131 {entrypoint}:
132 {&calculate_initial_zerofier_inverse}
135 push {self.zerofier_inv_write_address(ConstraintType::Initial)}
138 write_mem {EXTENSION_DEGREE}
139 pop 1
140 {&calculate_consistency_zerofier_inv}
143 push {self.zerofier_inv_write_address(ConstraintType::Consistency)}
146 write_mem {EXTENSION_DEGREE}
147 pop 1
148 {&calculate_except_last_row}
151 {&calculate_transition_zerofier_inv}
154 push {self.zerofier_inv_write_address(ConstraintType::Transition)}
157 write_mem {EXTENSION_DEGREE}
158 pop 1
159 {&calculate_terminal_zerofier_inv}
162 push {self.zerofier_inv_write_address(ConstraintType::Terminal)}
165 write_mem {EXTENSION_DEGREE}
166 pop 1
167 return
171 )
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use num::One;
178 use twenty_first::math::traits::ModPowU32;
179 use twenty_first::math::traits::PrimitiveRootOfUnity;
180
181 use super::*;
182 use crate::rust_shadowing_helper_functions::array::insert_as_array;
183 use crate::test_prelude::*;
184
185 #[test]
186 fn zerofiers_inverse_pbt() {
187 let mem_address_if_first_static_malloc =
188 -BFieldElement::new(ZerofiersInverse::array_size() as u64) - BFieldElement::one();
189 ShadowedFunction::new(ZerofiersInverse {
190 zerofiers_inverse_write_address: mem_address_if_first_static_malloc,
191 })
192 .test()
193 }
194
195 impl Function for ZerofiersInverse {
196 fn rust_shadow(
197 &self,
198 stack: &mut Vec<BFieldElement>,
199 memory: &mut HashMap<BFieldElement, BFieldElement>,
200 ) {
201 let trace_domain_generator = stack.pop().unwrap();
202 let padded_height: u32 = stack.pop().unwrap().value().try_into().unwrap();
203 let out_of_domain_point_curr_row = XFieldElement::new([
204 stack.pop().unwrap(),
205 stack.pop().unwrap(),
206 stack.pop().unwrap(),
207 ]);
208 let initial_zerofier_inv =
209 (out_of_domain_point_curr_row - BFieldElement::one()).inverse();
210 let consistency_zerofier_inv =
211 (out_of_domain_point_curr_row.mod_pow_u32(padded_height) - BFieldElement::one())
212 .inverse();
213 let except_last_row = out_of_domain_point_curr_row - trace_domain_generator.inverse();
214 let transition_zerofier_inv = except_last_row * consistency_zerofier_inv;
215 let terminal_zerofier_inv = except_last_row.inverse();
216
217 insert_as_array(
218 self.zerofiers_inverse_write_address,
219 memory,
220 vec![
221 initial_zerofier_inv,
222 consistency_zerofier_inv,
223 transition_zerofier_inv,
224 terminal_zerofier_inv,
225 ],
226 );
227 }
228
229 fn pseudorandom_initial_state(
230 &self,
231 seed: [u8; 32],
232 _bench_case: Option<BenchmarkCase>,
233 ) -> FunctionInitialState {
234 let mut rng = StdRng::from_seed(seed);
235 let ood_current_row: XFieldElement = rng.random();
236 let log_2_padded_height: u32 = rng.random_range(8..32);
237 let padded_height = 2u32.pow(log_2_padded_height);
238 let trace_domain_generator =
239 BFieldElement::primitive_root_of_unity(padded_height as u64).unwrap();
240
241 FunctionInitialState {
242 stack: [
243 self.init_stack_for_isolated_run(),
244 ood_current_row.coefficients.into_iter().rev().collect_vec(),
245 vec![
246 BFieldElement::new(padded_height as u64),
247 trace_domain_generator,
248 ],
249 ]
250 .concat(),
251 memory: HashMap::default(),
252 }
253 }
254 }
255}