1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
// Copyright 2023 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Polynomial utilities (currently only those used in polynomial evaluation).
use alloc::vec;
use crate::field::ExtElem;
/// Evaluate a polynomial whose coefficients are in the extension field at a
/// point.
pub fn poly_eval<E: ExtElem>(coeffs: &[E], x: E) -> E {
let mut mul = E::ONE;
let mut tot = E::ZERO;
for i in 0..coeffs.len() {
tot += coeffs[i] * mul;
mul *= x;
}
tot
}
/// General purpose polynomial interpolation.
///
/// Given the goal value f(x) at a set of evalation points x, compute
/// coefficients.
pub fn poly_interpolate<E: ExtElem>(out: &mut [E], x: &[E], fx: &[E], size: usize) {
// Special case the very easy ones
if size == 1 {
out[0] = fx[0];
return;
}
if size == 2 {
out[1] = (fx[1] - fx[0]) * (x[1] - x[0]).inv();
out[0] = fx[0] - out[1] * x[0];
return;
}
// Compute ft = product of (x - x_i) for all i
let mut ft = vec![E::ZERO; size + 1];
ft[0] = E::ONE;
for i in 0..size {
for j in (0..i + 1).rev() {
let value = ft[j];
ft[j + 1] += value;
ft[j] *= -x[i];
}
}
// Clear output
for i in 0..size {
out[i] = E::ZERO;
}
for i in 0..size {
// Compute fr = ft / (x - x_i)
let mut fr = ft.clone();
poly_divide(&mut fr, x[i]);
// Evaluate at x[i]
let fr_xi = poly_eval(&fr, x[i]);
// Compute multiplier (fx[i] / fr_xi)
let mul = fx[i] * fr_xi.inv();
// Multiply into output
for j in 0..size {
out[j] += mul * fr[j];
}
}
}
/// In-place polynomial division.
///
/// Take the coefficients in P, and divide by (X - z) for some z, return the
/// remainder.
pub fn poly_divide<E: ExtElem>(p: &mut [E], z: E) -> E {
let mut cur = E::ZERO;
for i in (0..p.len()).rev() {
let next = z * cur + p[i];
p[i] = cur;
cur = next;
}
cur
}