Skip to main content

ps_ecc/polynomial/implementations/
mul_assign.rs

1use std::ops::MulAssign;
2
3use crate::{finite_field::mul, Polynomial};
4
5impl MulAssign<u8> for Polynomial {
6    /// Multiplies all coefficients by a scalar in GF(2^8).
7    ///
8    /// If `scalar` is zero, the result is the zero polynomial.
9    /// Otherwise, the degree is preserved since GF(2^8) has no zero divisors.
10    fn mul_assign(&mut self, scalar: u8) {
11        if scalar == 0 {
12            self.coefficients.fill(0);
13            self.degree = 0;
14
15            return;
16        }
17
18        for coef in &mut self.coefficients[..=self.degree as usize] {
19            *coef = mul(*coef, scalar);
20        }
21    }
22}
23
24#[cfg(test)]
25#[allow(clippy::expect_used)]
26mod tests {
27    use crate::Polynomial;
28
29    #[test]
30    fn mul_assign_by_one() {
31        let mut p = Polynomial::try_from(&[5u8, 10, 15][..]).expect("valid polynomial");
32        let original = p;
33
34        p *= 1;
35
36        assert_eq!(p, original);
37    }
38
39    #[test]
40    fn mul_assign_by_zero() {
41        let mut p = Polynomial::try_from(&[5u8, 10, 15][..]).expect("valid polynomial");
42
43        p *= 0;
44
45        assert_eq!(p.degree(), 0);
46        assert_eq!(p.coefficients(), &[0]);
47    }
48
49    #[test]
50    fn mul_assign_by_two() {
51        // In GF(2^8), 2 * x is just a field multiplication
52        let mut p = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
53
54        p *= 2;
55
56        // GF(2^8) multiplication: 1*2=2, 2*2=4, 3*2=6
57        assert_eq!(p.coefficients(), &[2, 4, 6]);
58    }
59
60    #[test]
61    fn mul_assign_preserves_degree() {
62        let mut p = Polynomial::try_from(&[1u8, 0, 0, 5][..]).expect("valid polynomial");
63
64        assert_eq!(p.degree(), 3);
65
66        p *= 7;
67
68        assert_eq!(p.degree(), 3);
69    }
70
71    #[test]
72    fn mul_assign_zero_polynomial() {
73        let mut p = Polynomial::default();
74
75        p *= 42;
76
77        assert_eq!(p.degree(), 0);
78        assert_eq!(p.coefficients(), &[0]);
79    }
80
81    #[test]
82    fn mul_assign_by_inverse_roundtrip() {
83        use crate::finite_field::inv;
84
85        let original = Polynomial::try_from(&[3u8, 7, 11][..]).expect("valid polynomial");
86        let mut p = original;
87
88        let scale = 5u8;
89        let scale_inv = inv(scale).expect("5 is invertible").get();
90
91        p *= scale;
92        p *= scale_inv;
93
94        assert_eq!(p, original);
95    }
96
97    #[test]
98    fn mul_assign_distributive() {
99        // (a + b) * c = a*c + b*c
100        let a = Polynomial::try_from(&[1u8, 2][..]).expect("valid polynomial");
101        let b = Polynomial::try_from(&[3u8, 4][..]).expect("valid polynomial");
102        let c = 5u8;
103
104        let mut sum = (a + b).expect("addition succeeds");
105
106        sum *= c;
107
108        let mut a_scaled = a;
109
110        a_scaled *= c;
111
112        let mut b_scaled = b;
113
114        b_scaled *= c;
115
116        let sum_of_scaled = (a_scaled + b_scaled).expect("addition succeeds");
117
118        assert_eq!(sum, sum_of_scaled);
119    }
120
121    #[test]
122    fn mul_assign_associative_with_field() {
123        // (p * a) * b = p * (a * b) where a, b are field elements
124        use crate::finite_field::mul;
125
126        let original = Polynomial::try_from(&[2u8, 4, 6][..]).expect("valid polynomial");
127        let a = 3u8;
128        let b = 7u8;
129
130        let mut left = original;
131
132        left *= a;
133        left *= b;
134
135        let mut right = original;
136
137        right *= mul(a, b);
138
139        assert_eq!(left, right);
140    }
141
142    #[test]
143    fn mul_assign_high_degree() {
144        let mut coeffs = [0u8; 255];
145
146        coeffs[0] = 1;
147        coeffs[254] = 1;
148
149        let mut p = Polynomial::try_from(&coeffs[..]).expect("valid polynomial");
150
151        assert_eq!(p.degree(), 254);
152
153        p *= 3;
154
155        assert_eq!(p.degree(), 254);
156        assert_eq!(p[0u8], 3);
157        assert_eq!(p[254u8], 3);
158    }
159
160    #[test]
161    fn mul_assign_idempotent_with_one() {
162        let mut p = Polynomial::try_from(&[7u8, 13, 19][..]).expect("valid polynomial");
163
164        p *= 1;
165        p *= 1;
166        p *= 1;
167
168        assert_eq!(p.coefficients(), &[7, 13, 19]);
169    }
170}