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