Skip to main content

ps_ecc/polynomial/implementations/mul/
polynomial.rs

1use std::ops::Mul;
2
3use crate::{error::PolynomialMulError, Polynomial};
4
5use super::mul_coefficient_slices;
6
7impl Mul<&Polynomial> for &Polynomial {
8    type Output = Result<Polynomial, PolynomialMulError>;
9
10    /// Multiplies two polynomials over GF(256).
11    ///
12    /// # Errors
13    ///
14    /// Returns `DegreeOverflow` if the result degree exceeds 254.
15    fn mul(self, rhs: &Polynomial) -> Self::Output {
16        mul_coefficient_slices(self.coefficients(), rhs.coefficients())
17    }
18}
19
20impl Mul<&Self> for Polynomial {
21    type Output = Result<Self, PolynomialMulError>;
22
23    fn mul(self, rhs: &Self) -> Self::Output {
24        (&self).mul(rhs)
25    }
26}
27
28impl Mul<Self> for Polynomial {
29    type Output = Result<Self, PolynomialMulError>;
30
31    fn mul(self, rhs: Self) -> Self::Output {
32        (&self).mul(&rhs)
33    }
34}
35
36impl Mul<Polynomial> for &Polynomial {
37    type Output = Result<Polynomial, PolynomialMulError>;
38
39    fn mul(self, rhs: Polynomial) -> Self::Output {
40        self.mul(&rhs)
41    }
42}
43
44#[cfg(test)]
45#[allow(clippy::expect_used)]
46mod tests {
47    use std::ops::Mul;
48
49    use crate::{error::PolynomialMulError, Polynomial};
50
51    #[test]
52    fn mul_two_polynomials() {
53        // (1 + 2x) * (3 + 4x) = 3 + 4x + 6x + 8x^2 = 3 + (4^6)x + 8x^2
54        // In GF(256): 4 ^ 6 = 2
55        let a = Polynomial::try_from(&[1u8, 2][..]).expect("valid polynomial");
56        let b = Polynomial::try_from(&[3u8, 4][..]).expect("valid polynomial");
57
58        let result = a.mul(&b).expect("degree fits");
59
60        // a[0]*b[0] = 1*3 = 3
61        // a[0]*b[1] + a[1]*b[0] = 1*4 + 2*3 = 4 ^ 6 = 2
62        // a[1]*b[1] = 2*4 = 8
63        assert_eq!(result.coefficients(), &[3, 2, 8]);
64    }
65
66    #[test]
67    fn mul_by_zero() {
68        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
69        let zero = Polynomial::default();
70
71        let result = a.mul(&zero).expect("degree fits");
72
73        assert_eq!(result.degree(), 0);
74        assert_eq!(result.coefficients(), &[0]);
75    }
76
77    #[test]
78    fn mul_by_one() {
79        let a = Polynomial::try_from(&[5u8, 10, 15][..]).expect("valid polynomial");
80        let one = Polynomial::try_from(&[1u8][..]).expect("valid polynomial");
81
82        let result = a.mul(&one).expect("degree fits");
83
84        assert_eq!(result.coefficients(), &[5, 10, 15]);
85    }
86
87    #[test]
88    fn mul_by_x() {
89        // Multiplying by x shifts coefficients
90        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
91        let x = Polynomial::try_from(&[0u8, 1][..]).expect("valid polynomial");
92
93        let result = a.mul(&x).expect("degree fits");
94
95        assert_eq!(result.coefficients(), &[0, 1, 2, 3]);
96    }
97
98    #[test]
99    fn mul_degree_overflow() {
100        // Create two polynomials whose product exceeds max degree
101        let mut coeffs = [0u8; 200];
102
103        coeffs[199] = 1; // degree 199
104
105        let a = Polynomial::try_from(&coeffs[..]).expect("valid polynomial");
106
107        // 199 + 199 = 398 > 254
108        let result = a.mul(&a);
109
110        assert_eq!(result, Err(PolynomialMulError::DegreeOverflow));
111    }
112
113    #[test]
114    fn mul_with_references() {
115        let a = Polynomial::try_from(&[1u8, 2][..]).expect("valid polynomial");
116        let b = Polynomial::try_from(&[3u8, 4][..]).expect("valid polynomial");
117
118        // All four combinations
119        let r1 = (&a).mul(&b).expect("degree fits");
120        let r2 = (&a).mul(b).expect("degree fits");
121        let r3 = a.mul(&b).expect("degree fits");
122        let r4 = a.mul(b).expect("degree fits");
123
124        assert_eq!(r1, r2);
125        assert_eq!(r2, r3);
126        assert_eq!(r3, r4);
127    }
128
129    #[test]
130    fn mul_max_degree_exactly() {
131        // 127 + 127 = 254, which is exactly MAX_DEGREE
132        let mut coeffs = [0u8; 128];
133
134        coeffs[127] = 1;
135
136        let a = Polynomial::try_from(&coeffs[..]).expect("valid polynomial");
137
138        let result = a.mul(&a).expect("should succeed at boundary");
139
140        assert_eq!(result.degree(), 254);
141    }
142
143    #[test]
144    fn mul_is_commutative() {
145        let a = Polynomial::try_from(&[1u8, 2, 3, 4][..]).expect("valid polynomial");
146        let b = Polynomial::try_from(&[5u8, 6, 7][..]).expect("valid polynomial");
147
148        let ab = (&a).mul(&b).expect("degree fits");
149        let ba = (&b).mul(&a).expect("degree fits");
150
151        assert_eq!(ab, ba);
152    }
153}