1#![no_std]
4
5extern crate alloc;
6
7use alloc::vec::Vec;
8
9use p3_field::coset::TwoAdicMultiplicativeCoset;
10use p3_field::{
11 ExtensionField, TwoAdicField, batch_multiplicative_inverse, scale_slice_in_place_single_core,
12};
13use p3_matrix::Matrix;
14use p3_maybe_rayon::prelude::*;
15use p3_util::log2_strict_usize;
16
17pub fn interpolate_subgroup<F, EF, Mat>(subgroup_evals: &Mat, point: EF) -> Vec<EF>
22where
23 F: TwoAdicField,
24 EF: ExtensionField<F>,
25 Mat: Matrix<F>,
26{
27 interpolate_coset(subgroup_evals, F::ONE, point)
28}
29
30pub fn interpolate_coset<F, EF, Mat>(coset_evals: &Mat, shift: F, point: EF) -> Vec<EF>
37where
38 F: TwoAdicField,
39 EF: ExtensionField<F>,
40 Mat: Matrix<F>,
41{
42 let height = coset_evals.height();
43 let log_height = log2_strict_usize(height);
44
45 let coset = TwoAdicMultiplicativeCoset::new(shift, log_height)
46 .unwrap()
47 .iter()
48 .collect();
49
50 let diffs: Vec<_> = coset.par_iter().map(|&g| point - g).collect();
52 let diff_invs = batch_multiplicative_inverse(&diffs);
53
54 interpolate_coset_with_precomputation(coset_evals, shift, point, &coset, &diff_invs)
55}
56
57pub fn interpolate_coset_with_precomputation<F, EF, Mat>(
70 coset_evals: &Mat,
71 shift: F,
72 point: EF,
73 coset: &[F],
74 diff_invs: &[EF],
75) -> Vec<EF>
76where
77 F: TwoAdicField,
78 EF: ExtensionField<F>,
79 Mat: Matrix<F>,
80{
81 debug_assert_eq!(coset.len(), diff_invs.len());
83 debug_assert_eq!(coset.len(), coset_evals.height());
84
85 let height = coset_evals.height();
101 let log_height = log2_strict_usize(height);
102
103 let col_scale: Vec<_> = coset
105 .par_iter()
106 .zip(diff_invs)
107 .map(|(&sg, &diff_inv)| diff_inv * sg)
108 .collect();
109
110 let point_pow_height = point.exp_power_of_2(log_height);
111 let shift_pow_height = shift.exp_power_of_2(log_height);
112
113 let vanishing_polynomial = point_pow_height - shift_pow_height;
115
116 let denominator = shift_pow_height.mul_2exp_u64(log_height as u64);
118
119 let scaling_factor = vanishing_polynomial * denominator.inverse();
121
122 let mut evals = coset_evals.columnwise_dot_product(&col_scale);
125 scale_slice_in_place_single_core(&mut evals, scaling_factor);
126 evals
127}
128
129#[cfg(test)]
130mod tests {
131 use alloc::vec;
132 use alloc::vec::Vec;
133
134 use p3_baby_bear::BabyBear;
135 use p3_field::extension::BinomialExtensionField;
136 use p3_field::{Field, PrimeCharacteristicRing, TwoAdicField, batch_multiplicative_inverse};
137 use p3_matrix::dense::RowMajorMatrix;
138 use p3_util::log2_strict_usize;
139
140 use crate::{interpolate_coset, interpolate_coset_with_precomputation, interpolate_subgroup};
141
142 #[test]
143 fn test_interpolate_subgroup() {
144 type F = BabyBear;
146 let evals = [
147 6, 886605102, 1443543107, 708307799, 2, 556938009, 569722818, 1874680944,
148 ]
149 .map(F::from_u32);
150 let evals_mat = RowMajorMatrix::new(evals.to_vec(), 1);
151 let point = F::from_u16(100);
152 let result = interpolate_subgroup(&evals_mat, point);
153 assert_eq!(result, vec![F::from_u16(10203)]);
154 }
155
156 #[test]
157 fn test_interpolate_coset() {
158 type F = BabyBear;
160 let shift = F::GENERATOR;
161 let evals = [
162 1026, 129027310, 457985035, 994890337, 902, 1988942953, 1555278970, 913671254,
163 ]
164 .map(F::from_u32);
165 let evals_mat = RowMajorMatrix::new(evals.to_vec(), 1);
166 let point = F::from_u16(100);
167 let result = interpolate_coset(&evals_mat, shift, point);
168 assert_eq!(result, vec![F::from_u16(10203)]);
169
170 let n = evals.len();
171 let k = log2_strict_usize(n);
172
173 let coset = F::two_adic_generator(k).shifted_powers(shift).collect_n(n);
174
175 let denom: Vec<_> = coset.iter().map(|&w| point - w).collect();
176
177 let denom = batch_multiplicative_inverse(&denom);
178 let result =
179 interpolate_coset_with_precomputation(&evals_mat, shift, point, &coset, &denom);
180 assert_eq!(result, vec![F::from_u16(10203)]);
181 }
182
183 #[test]
184 fn test_interpolate_coset_single_point_identity() {
185 type F = BabyBear;
186
187 let c = F::from_u32(42); let evals = vec![c; 8];
191 let evals_mat = RowMajorMatrix::new(evals, 1);
192
193 let shift = F::GENERATOR;
194 let point = F::from_u16(1337);
195
196 let result = interpolate_coset(&evals_mat, shift, point);
197 assert_eq!(result, vec![c]); }
199
200 #[test]
201 fn test_interpolate_subgroup_degree_3_correctness() {
202 type F = BabyBear;
203 type EF4 = BinomialExtensionField<BabyBear, 4>;
204
205 let poly = |x: EF4| x * x * x + x * x * F::TWO + x * F::from_u32(3) + F::from_u32(4);
208
209 let subgroup = EF4::two_adic_generator(2).powers().collect_n(4);
210 let evals: Vec<_> = subgroup.iter().map(|&x| poly(x)).collect();
211
212 let evals_mat = RowMajorMatrix::new(evals, 1);
213 let point = EF4::from_u16(5);
214
215 let result = interpolate_subgroup(&evals_mat, point);
216 let expected = poly(point);
217
218 assert_eq!(result[0], expected);
219 }
220
221 #[test]
222 fn test_interpolate_coset_multiple_polynomials() {
223 type F = BabyBear;
224 type EF4 = BinomialExtensionField<BabyBear, 4>;
225
226 let shift = EF4::GENERATOR;
232 let coset = EF4::two_adic_generator(3)
233 .shifted_powers(shift)
234 .collect_n(8);
235
236 let f1 = |x: EF4| x * x + x * F::TWO + F::from_u32(3);
237 let f2 = |x: EF4| x * x * F::from_u32(4) + x * F::from_u32(5) + F::from_u32(6);
238
239 let evals: Vec<_> = coset.iter().flat_map(|&x| vec![f1(x), f2(x)]).collect();
240 let evals_mat = RowMajorMatrix::new(evals, 2);
241
242 let point = EF4::from_u32(77);
243 let result = interpolate_coset(&evals_mat, shift, point);
244
245 let expected_f1 = f1(point);
247 let expected_f2 = f2(point);
248
249 assert_eq!(result[0], expected_f1);
250 assert_eq!(result[1], expected_f2);
251 }
252
253 #[test]
254 fn test_interpolate_subgroup_multiple_columns() {
255 type F = BabyBear;
256 type EF4 = BinomialExtensionField<BabyBear, 4>;
257
258 let f1 = |x: EF4| x * x + x * F::TWO + F::from_u32(3);
260 let f2 = |x: EF4| x * x * F::from_u32(4) + x * F::from_u32(5) + F::from_u32(6);
261
262 let subgroup_iter = EF4::two_adic_generator(3).powers().take(8);
264
265 let evals: Vec<_> = subgroup_iter.flat_map(|x| vec![f1(x), f2(x)]).collect();
267
268 let evals_mat = RowMajorMatrix::new(evals, 2);
270
271 let point = EF4::from_u32(77);
273
274 let result = interpolate_subgroup(&evals_mat, point);
276
277 let expected_f1 = f1(point);
279 let expected_f2 = f2(point);
280
281 assert_eq!(result, vec![expected_f1, expected_f2]);
282 }
283}