use crate::{
finite_field::{add, mul},
Polynomial,
};
impl Polynomial {
#[must_use]
pub fn eval_coefficients_derivative_at(coefficients: &[u8], x: u8) -> u8 {
let mut result = 0u8;
let x_sq = mul(x, x);
let mut x_pow = 1u8;
for k in 0..=coefficients.len() / 2 {
let idx = 2 * k + 1;
if idx < coefficients.len() {
result = add(result, mul(coefficients[idx], x_pow));
x_pow = mul(x_pow, x_sq);
}
}
result
}
}
#[cfg(test)]
mod tests {
use crate::{
finite_field::{add, mul},
Polynomial,
};
fn naive_eval_deriv(coefficients: &[u8], x: u8) -> u8 {
let mut result = 0u8;
let x_sq = mul(x, x);
let mut x_pow = 1u8;
for k in 0..=coefficients.len() / 2 {
let idx = 2 * k + 1;
if idx < coefficients.len() {
result = add(result, mul(coefficients[idx], x_pow));
x_pow = mul(x_pow, x_sq);
}
}
result
}
fn assert_exhaustive(coefficients: &[u8]) {
for x in 0..=255u8 {
assert_eq!(
Polynomial::eval_coefficients_derivative_at(coefficients, x),
naive_eval_deriv(coefficients, x)
);
}
}
#[test]
fn empty_slice() {
assert_exhaustive(&[]);
}
#[test]
fn zero_polynomial() {
assert_exhaustive(&[0]);
}
#[test]
fn constant_polynomial_has_zero_derivative() {
for c in [1u8, 42, 128, 255] {
for x in 0..=255u8 {
assert_eq!(Polynomial::eval_coefficients_derivative_at(&[c], x), 0);
}
}
}
#[test]
fn linear_polynomial() {
for x in 0..=255u8 {
assert_eq!(Polynomial::eval_coefficients_derivative_at(&[5, 3], x), 3);
assert_eq!(Polynomial::eval_coefficients_derivative_at(&[0, 1], x), 1);
assert_eq!(
Polynomial::eval_coefficients_derivative_at(&[255, 255], x),
255
);
}
}
#[test]
fn quadratic_polynomial() {
assert_exhaustive(&[1, 0, 1]);
assert_exhaustive(&[0, 5, 1]);
assert_exhaustive(&[255, 128, 64]);
}
#[test]
fn cubic_polynomial() {
assert_exhaustive(&[0x12, 0x34, 0x56, 0x78]);
assert_exhaustive(&[1, 1, 1, 1]);
assert_exhaustive(&[0, 0, 0, 1]);
}
#[test]
fn high_degree_polynomial() {
assert_exhaustive(&[1, 2, 3, 4, 5, 6, 7, 8]);
assert_exhaustive(&[0, 0, 0, 0, 0, 0, 0, 1]);
}
#[test]
fn only_even_powers() {
for x in 0..=255u8 {
assert_eq!(
Polynomial::eval_coefficients_derivative_at(&[1, 0, 1, 0, 1], x),
0
);
}
}
#[test]
fn only_odd_powers() {
let coefficients = [0u8, 1, 0, 1];
for x in 0..=255u8 {
let x2 = mul(x, x);
let expected = add(1, x2);
assert_eq!(
Polynomial::eval_coefficients_derivative_at(&coefficients, x),
expected
);
}
}
#[test]
fn max_degree_polynomial() {
let mut coefficients = [0u8; Polynomial::MAX_COEFFICIENTS as usize];
coefficients[Polynomial::MAX_DEGREE as usize] = 1;
assert_exhaustive(&coefficients);
}
#[test]
fn matches_naive_eval_deriv() {
let coefficients = [0x12u8, 0x34, 0x56, 0x78, 0x9A];
for x in 0..=255u8 {
assert_eq!(
Polynomial::eval_coefficients_derivative_at(&coefficients, x),
naive_eval_deriv(&coefficients, x)
);
}
}
}