Skip to main content

ps_ecc/polynomial/methods/
eval_coefficient_slices_at.rs

1use crate::Polynomial;
2
3impl Polynomial {
4    /// Evaluates a polynomial from multiple coefficient slices at the given point.
5    ///
6    /// Slices are concatenated in order, with the first slice containing the lowest degree terms.
7    #[must_use]
8    pub fn eval_coefficient_slices_at(slices: &[&[u8]], x: u8) -> u8 {
9        let iter = slices.iter().flat_map(|s| s.iter()).copied();
10
11        Self::eval_coefficient_iter_at(iter, x)
12    }
13}
14
15#[cfg(test)]
16mod tests {
17    use crate::{
18        finite_field::{add, mul},
19        Polynomial,
20    };
21
22    /// Computes expected value using naive polynomial evaluation.
23    fn naive_eval(coefficients: impl Iterator<Item = u8>, x: u8) -> u8 {
24        let mut result = 0u8;
25        let mut x_pow = 1u8;
26
27        for c in coefficients {
28            result = add(result, mul(c, x_pow));
29            x_pow = mul(x_pow, x);
30        }
31
32        result
33    }
34
35    /// Asserts that `eval_coefficient_slices_at` matches naive evaluation for all x in 0..=255.
36    fn assert_exhaustive(slices: &[&[u8]]) {
37        for x in 0..=255u8 {
38            let iter = slices.iter().flat_map(|s| s.iter()).copied();
39
40            assert_eq!(
41                Polynomial::eval_coefficient_slices_at(slices, x),
42                naive_eval(iter, x)
43            );
44        }
45    }
46
47    #[test]
48    fn empty_slice_list() {
49        assert_exhaustive(&[]);
50    }
51
52    #[test]
53    fn single_empty_slice() {
54        assert_exhaustive(&[&[]]);
55    }
56
57    #[test]
58    fn single_slice() {
59        assert_exhaustive(&[&[1, 2, 3, 4]]);
60        assert_exhaustive(&[&[255, 128, 64]]);
61    }
62
63    #[test]
64    fn two_slices() {
65        assert_exhaustive(&[&[1, 2, 3], &[4, 5, 6]]);
66        assert_exhaustive(&[&[0, 0, 0], &[0, 0, 1]]);
67        assert_exhaustive(&[&[255, 255], &[255, 255]]);
68    }
69
70    #[test]
71    fn three_slices() {
72        assert_exhaustive(&[&[1, 2], &[3, 4], &[5, 6]]);
73    }
74
75    #[test]
76    fn mixed_empty_slices() {
77        assert_exhaustive(&[&[], &[1, 2, 3], &[]]);
78        assert_exhaustive(&[&[1], &[], &[2]]);
79    }
80
81    #[test]
82    fn unequal_lengths() {
83        assert_exhaustive(&[&[1], &[2, 3, 4, 5]]);
84        assert_exhaustive(&[&[1, 2, 3, 4], &[5]]);
85    }
86
87    #[test]
88    fn matches_eval_coefficients_at() {
89        let coefficients = [0x12u8, 0x34, 0x56, 0x78];
90
91        for x in 0..=255u8 {
92            assert_eq!(
93                Polynomial::eval_coefficient_slices_at(&[&coefficients], x),
94                Polynomial::eval_coefficients_at(&coefficients, x)
95            );
96        }
97    }
98
99    #[test]
100    fn matches_eval_coefficient_iter_at() {
101        let low = [1u8, 2, 3];
102        let high = [4u8, 5, 6];
103
104        for x in 0..=255u8 {
105            assert_eq!(
106                Polynomial::eval_coefficient_slices_at(&[&low, &high], x),
107                Polynomial::eval_coefficient_iter_at(low.iter().chain(high.iter()).copied(), x)
108            );
109        }
110    }
111}