Skip to main content

ps_ecc/polynomial/implementations/
rem.rs

1use std::ops::Rem;
2
3use crate::{error::PolynomialDivError, Polynomial};
4
5impl<D: AsRef<[u8]>> Rem<D> for &Polynomial {
6    type Output = Result<Polynomial, PolynomialDivError>;
7
8    /// Computes the remainder of polynomial division over GF(256).
9    ///
10    /// # Errors
11    ///
12    /// Returns `ZeroDivisor` if the divisor is the zero polynomial.
13    fn rem(self, rhs: D) -> Self::Output {
14        let (_quot, rem) = self.div_rem(rhs)?;
15
16        Ok(rem)
17    }
18}
19
20impl<D: AsRef<[u8]>> Rem<D> for Polynomial {
21    type Output = Result<Self, PolynomialDivError>;
22
23    fn rem(self, rhs: D) -> Self::Output {
24        let (_quot, rem) = self.div_rem(rhs)?;
25
26        Ok(rem)
27    }
28}
29
30#[cfg(test)]
31#[allow(clippy::expect_used)]
32mod tests {
33    use std::ops::{Div, Mul, Rem};
34
35    use crate::{error::PolynomialDivError, Polynomial};
36
37    #[test]
38    fn rem_returns_remainder() {
39        // (x^2 + x + 1) % (x + 1) has a non-zero remainder
40        let a = Polynomial::try_from(&[1u8, 1, 1][..]).expect("valid polynomial");
41        let b = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
42
43        let rem = a.rem(&b).expect("division succeeds");
44
45        // Verify via div_rem
46        let (_quot, expected_rem) = a.div_rem(b).expect("division succeeds");
47
48        assert_eq!(rem, expected_rem);
49    }
50
51    #[test]
52    fn rem_zero_when_divisible() {
53        // (x^2 + 1) % (x + 1) = 0 in GF(256)
54        let a = Polynomial::try_from(&[1u8, 0, 1][..]).expect("valid polynomial");
55        let b = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
56
57        let rem = a.rem(&b).expect("division succeeds");
58
59        assert_eq!(rem.coefficients(), &[0]);
60    }
61
62    #[test]
63    fn rem_by_slice() {
64        let a = Polynomial::try_from(&[1u8, 1, 1][..]).expect("valid polynomial");
65        let b: &[u8] = &[1, 1];
66
67        let rem = a.rem(b).expect("division succeeds");
68        let (_quot, expected_rem) = a.div_rem(b).expect("division succeeds");
69
70        assert_eq!(rem, expected_rem);
71    }
72
73    #[test]
74    fn rem_by_array() {
75        let a = Polynomial::try_from(&[1u8, 1, 1][..]).expect("valid polynomial");
76
77        let rem = a.rem([1u8, 1]).expect("division succeeds");
78        let (_quot, expected_rem) = a.div_rem([1u8, 1]).expect("division succeeds");
79
80        assert_eq!(rem, expected_rem);
81    }
82
83    #[test]
84    fn rem_by_zero() {
85        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
86        let zero = Polynomial::default();
87
88        let result = a.rem(&zero);
89
90        assert_eq!(result, Err(PolynomialDivError::ZeroDivisor));
91    }
92
93    #[test]
94    fn rem_ref_lhs() {
95        let a = Polynomial::try_from(&[1u8, 1, 1][..]).expect("valid polynomial");
96        let b = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
97
98        let rem = (&a).rem(&b).expect("division succeeds");
99        let (_quot, expected_rem) = a.div_rem(b).expect("division succeeds");
100
101        assert_eq!(rem, expected_rem);
102    }
103
104    #[test]
105    fn rem_smaller_than_divisor() {
106        // When dividend degree < divisor degree, remainder = dividend
107        let a = Polynomial::try_from(&[1u8, 2][..]).expect("valid polynomial");
108        let b = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
109
110        let rem = a.rem(&b).expect("division succeeds");
111
112        assert_eq!(rem.coefficients(), &[1, 2]);
113    }
114
115    #[test]
116    fn div_rem_identity() {
117        // Verify: (a / b) * b + (a % b) = a
118        let a = Polynomial::try_from(&[3u8, 5, 7, 11][..]).expect("valid polynomial");
119        let b = Polynomial::try_from(&[2u8, 4][..]).expect("valid polynomial");
120
121        let quot = (&a).div(&b).expect("division succeeds");
122        let rem = (&a).rem(&b).expect("division succeeds");
123
124        let product = quot.mul(&b).expect("multiplication succeeds");
125        let reconstructed = (product + rem).expect("addition succeeds");
126
127        assert_eq!(reconstructed, a);
128    }
129}