tasm_lib/verifier/master_table/
zerofiers_inverse.rs

1use 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/// Calculate all inverses of the zerofiers. It is the caller's responsibility
10/// to statically allocate memory for the array where the result is stored.
11#[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    /// Return the address needed to write to the inverted zerofiers array
22    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    /// Return the address needed to read from the inverted zerofiers array
29    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            // _ [out_of_domain_point_curr_row] padded_height trace_domain_generator
63
64            dup 4
65            dup 4
66            dup 4
67            push -1
68            add
69            x_invert
70            // _ [out_of_domain_point_curr_row] padded_height trace_domain_generator [initial_zerofier_inv]
71        );
72
73        let calculate_consistency_zerofier_inv = triton_asm!(
74           // _ [out_of_domain_point_curr_row] padded_height trace_domain_generator
75
76           swap 1
77           // _ [out_of_domain_point_curr_row] trace_domain_generator padded_height
78
79           log_2_floor
80
81           dup 4
82           dup 4
83           dup 4
84           // _ [out_of_domain_point_curr_row] trace_domain_generator log2_padded_height [out_of_domain_point_curr_row]
85
86           call {xfe_mod_pow_pow_2}
87           // _ [out_of_domain_point_curr_row] trace_domain_generator [out_of_domain_point_curr_row^{padded_height}]
88
89           push -1
90           add
91           x_invert
92           // _ [out_of_domain_point_curr_row] trace_domain_generator [consistency_zerofier_inv]
93        );
94
95        let calculate_except_last_row = triton_asm!(
96            // _ [out_of_domain_point_curr_row] trace_domain_generator
97
98            invert
99            // _ [out_of_domain_point_curr_row] (1 / trace_domain_generator)
100
101            push -1
102            mul
103            add
104            // _ [except_last_row]
105        );
106
107        let calculate_transition_zerofier_inv = triton_asm!(
108            // _ [except_last_row]
109
110            dup 2
111            dup 2
112            dup 2
113            // _ [except_last_row] [except_last_row]
114
115            push {self.zerofier_inv_read_address(ConstraintType::Consistency)}
116            read_mem {EXTENSION_DEGREE}
117            pop 1
118            // _ [except_last_row] [except_last_row] [consistency_zerofier_inv]
119
120            xx_mul
121            // _ [except_last_row] [transition_zerofier_inv]
122        );
123
124        let calculate_terminal_zerofier_inv = triton_asm!(
125            // _ [except_last_row]
126            x_invert // _ [terminal_zerofier_inv]
127        );
128
129        let entrypoint = self.entrypoint();
130        triton_asm!(
131            {entrypoint}:
132                // _ [out_of_domain_point_curr_row] padded_height trace_domain_generator
133
134                {&calculate_initial_zerofier_inverse}
135                // _ [out_of_domain_point_curr_row] padded_height trace_domain_generator [initial_zerofier_inv]
136
137                push {self.zerofier_inv_write_address(ConstraintType::Initial)}
138                write_mem {EXTENSION_DEGREE}
139                pop 1
140                // _ [out_of_domain_point_curr_row] padded_height trace_domain_generator
141
142                {&calculate_consistency_zerofier_inv}
143                 // _ [out_of_domain_point_curr_row] trace_domain_generator [consistency_zerofier_inv]
144
145                push {self.zerofier_inv_write_address(ConstraintType::Consistency)}
146                write_mem {EXTENSION_DEGREE}
147                pop 1
148                // _ [out_of_domain_point_curr_row] trace_domain_generator
149
150                {&calculate_except_last_row}
151                // _ [except_last_row]
152
153                {&calculate_transition_zerofier_inv}
154                // _ [except_last_row] [transition_zerofier_inv]
155
156                push {self.zerofier_inv_write_address(ConstraintType::Transition)}
157                write_mem {EXTENSION_DEGREE}
158                pop 1
159                 // _ [except_last_row]
160
161                {&calculate_terminal_zerofier_inv}
162                // _ [terminal_zerofier_inv]
163
164                push {self.zerofier_inv_write_address(ConstraintType::Terminal)}
165                write_mem {EXTENSION_DEGREE}
166                pop 1
167                // _
168
169
170                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}