Skip to main content

ps_ecc/polynomial/implementations/
bitxor.rs

1use std::{borrow::Borrow, ops::BitXor};
2
3use crate::{error::PolynomialXorError, finite_field::add, Polynomial};
4
5impl<B: Borrow<u8>, I: IntoIterator<Item = B>> BitXor<I> for Polynomial {
6    type Output = Result<Self, PolynomialXorError>;
7
8    /// XORs coefficients from an iterator into this polynomial.
9    ///
10    /// # Errors
11    ///
12    /// Returns `TooManyCoefficients` if the iterator yields more than 255 elements.
13    fn bitxor(self, rhs: I) -> Self::Output {
14        let mut result = self;
15
16        for (idx, coef) in rhs.into_iter().enumerate() {
17            if idx >= Self::MAX_COEFFICIENTS as usize {
18                return Err(PolynomialXorError::TooManyCoefficients);
19            }
20
21            result.coefficients[idx] = add(result.coefficients[idx], *coef.borrow());
22
23            #[allow(clippy::cast_possible_truncation)]
24            let idx_u8 = idx as u8;
25
26            result.degree = result.degree.max(idx_u8);
27        }
28
29        result.trim_degree();
30
31        Ok(result)
32    }
33}
34
35impl<B: Borrow<u8>, I: IntoIterator<Item = B>> BitXor<I> for &Polynomial {
36    type Output = Result<Polynomial, PolynomialXorError>;
37
38    fn bitxor(self, rhs: I) -> Self::Output {
39        *self ^ rhs
40    }
41}
42
43#[cfg(test)]
44#[allow(clippy::expect_used)]
45mod tests {
46    use std::ops::BitXor;
47
48    use crate::{error::PolynomialXorError, Polynomial};
49
50    #[test]
51    fn xor_two_polynomials() {
52        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
53        let b = Polynomial::try_from(&[4u8, 5, 6][..]).expect("valid polynomial");
54
55        let result = a.bitxor(b).expect("polynomials are bounded");
56
57        assert_eq!(result.coefficients(), &[1 ^ 4, 2 ^ 5, 3 ^ 6]);
58    }
59
60    #[test]
61    fn xor_different_degrees() {
62        let a = Polynomial::try_from(&[1u8, 2][..]).expect("valid polynomial");
63        let b = Polynomial::try_from(&[3u8, 4, 5, 6][..]).expect("valid polynomial");
64
65        let result = a.bitxor(b).expect("polynomials are bounded");
66
67        assert_eq!(result.coefficients(), &[1 ^ 3, 2 ^ 4, 5, 6]);
68    }
69
70    #[test]
71    fn xor_cancels_to_zero() {
72        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
73        let b = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
74
75        let result = a.bitxor(b).expect("polynomials are bounded");
76
77        assert_eq!(result.degree(), 0);
78        assert_eq!(result.coefficients(), &[0]);
79    }
80
81    #[test]
82    fn xor_with_references() {
83        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
84        let b = Polynomial::try_from(&[4u8, 5, 6][..]).expect("valid polynomial");
85
86        let result = (&a).bitxor(&b).expect("polynomials are bounded");
87
88        assert_eq!(result.coefficients(), &[1 ^ 4, 2 ^ 5, 3 ^ 6]);
89    }
90
91    #[test]
92    fn xor_slice_via_iter() {
93        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
94        let slice: &[u8] = &[4, 5, 6];
95
96        let result = a.bitxor(slice.iter()).expect("valid slice");
97
98        assert_eq!(result.coefficients(), &[1 ^ 4, 2 ^ 5, 3 ^ 6]);
99    }
100
101    #[test]
102    fn xor_vec() {
103        let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
104        let vec = vec![4u8, 5, 6, 7];
105
106        let result = a.bitxor(vec).expect("valid vec");
107
108        assert_eq!(result.coefficients(), &[1 ^ 4, 2 ^ 5, 3 ^ 6, 7]);
109    }
110
111    #[test]
112    fn xor_iterator_too_long_returns_error() {
113        let a = Polynomial::default();
114        let iter = std::iter::repeat_n(1u8, 256);
115
116        let result = a.bitxor(iter);
117
118        assert_eq!(result, Err(PolynomialXorError::TooManyCoefficients));
119    }
120}