Skip to main content

ps_ecc/polynomial/methods/
eval_derivative_at.rs

1use crate::Polynomial;
2
3impl Polynomial {
4    /// Evaluates the formal derivative of this polynomial at the given point.
5    ///
6    /// In characteristic 2, only odd-degree terms contribute to the derivative.
7    #[must_use]
8    pub fn eval_derivative_at(&self, x: u8) -> u8 {
9        Self::eval_coefficients_derivative_at(self.coefficients(), x)
10    }
11}
12
13#[cfg(test)]
14mod tests {
15    use crate::{
16        finite_field::{add, mul},
17        Polynomial,
18    };
19
20    /// Asserts that `eval_derivative_at` matches `eval_coefficients_derivative_at` for all x.
21    fn assert_exhaustive(p: &Polynomial) {
22        for x in 0..=255u8 {
23            assert_eq!(
24                p.eval_derivative_at(x),
25                Polynomial::eval_coefficients_derivative_at(p.coefficients(), x)
26            );
27        }
28    }
29
30    #[test]
31    fn zero_polynomial() {
32        assert_exhaustive(&Polynomial::default());
33    }
34
35    #[test]
36    fn constant_polynomial() {
37        let mut p = Polynomial::default();
38
39        p.set(0, 42);
40
41        assert_exhaustive(&p);
42    }
43
44    #[test]
45    fn linear_polynomial() {
46        let mut p = Polynomial::default();
47
48        p.set(0, 5);
49        p.set(1, 3);
50
51        assert_exhaustive(&p);
52    }
53
54    #[test]
55    fn quadratic_polynomial() {
56        let mut p = Polynomial::default();
57
58        p.set(0, 1);
59        p.set(1, 7);
60        p.set(2, 1);
61
62        assert_exhaustive(&p);
63    }
64
65    #[test]
66    fn cubic_polynomial() {
67        let mut p = Polynomial::default();
68
69        p.set(0, 0x12);
70        p.set(1, 0x34);
71        p.set(2, 0x56);
72        p.set(3, 0x78);
73
74        assert_exhaustive(&p);
75    }
76
77    #[test]
78    fn high_degree_polynomial() {
79        let mut p = Polynomial::default();
80
81        for i in 0..8 {
82            p.set(i, i + 1);
83        }
84
85        assert_exhaustive(&p);
86    }
87
88    #[test]
89    fn max_degree_polynomial() {
90        let mut p = Polynomial::default();
91
92        p.set(Polynomial::MAX_DEGREE, 1);
93
94        assert_exhaustive(&p);
95    }
96
97    #[test]
98    fn only_even_powers() {
99        // p(x) = 1 + x² + x⁴, p'(x) = 0
100        let mut p = Polynomial::default();
101
102        p.set(0, 1);
103        p.set(2, 1);
104        p.set(4, 1);
105
106        for x in 0..=255u8 {
107            assert_eq!(p.eval_derivative_at(x), 0);
108        }
109    }
110
111    #[test]
112    fn only_odd_powers() {
113        // p(x) = x + x³, p'(x) = 1 + x²
114        let mut p = Polynomial::default();
115
116        p.set(1, 1);
117        p.set(3, 1);
118
119        for x in 0..=255u8 {
120            let x2 = mul(x, x);
121            let expected = add(1, x2);
122
123            assert_eq!(p.eval_derivative_at(x), expected);
124        }
125    }
126
127    #[test]
128    fn derivative_computed_correctly() {
129        // p(x) = 0x12 + 0x34*x + 0x56*x² + 0x78*x³ + 0x9A*x⁴
130        // p'(x) = 0x34 + 0x78*x² (only odd-degree terms contribute)
131        let mut p = Polynomial::default();
132
133        p.set(0, 0x12);
134        p.set(1, 0x34);
135        p.set(2, 0x56);
136        p.set(3, 0x78);
137        p.set(4, 0x9A);
138
139        for x in 0..=255u8 {
140            let x2 = mul(x, x);
141            let expected = add(0x34, mul(0x78, x2));
142
143            assert_eq!(p.eval_derivative_at(x), expected);
144        }
145    }
146}