ps_ecc/polynomial/methods/
mul_xor_assign.rs1use crate::{finite_field::mul, Polynomial, PolynomialMulError};
2
3impl Polynomial {
4 #[inline]
16 pub fn mul_xor_assign(&mut self, a: &Self, b: &Self) -> Result<(), PolynomialMulError> {
17 let a_deg = a.degree as usize;
18 let b_deg = b.degree as usize;
19
20 if a.coefficients[a_deg] == 0 || b.coefficients[b_deg] == 0 {
22 return Ok(());
23 }
24
25 let product_deg = a_deg + b_deg;
26
27 if product_deg > usize::from(Self::MAX_DEGREE) {
28 return Err(PolynomialMulError::DegreeOverflow);
29 }
30
31 for i in 0..=a_deg {
33 let a_coef = a.coefficients[i];
34
35 if a_coef == 0 {
36 continue;
37 }
38
39 for j in 0..=b_deg {
40 let b_coef = b.coefficients[j];
41
42 if b_coef == 0 {
43 continue;
44 }
45
46 self.coefficients[i + j] ^= mul(a_coef, b_coef);
47 }
48 }
49
50 #[allow(clippy::cast_possible_truncation)] if product_deg > self.degree as usize {
53 self.degree = product_deg as u8;
54 }
55
56 self.trim_degree();
57
58 Ok(())
59 }
60}
61
62#[cfg(test)]
63#[allow(clippy::expect_used)]
64mod tests {
65 use crate::{Polynomial, PolynomialMulError};
66
67 #[test]
68 fn mul_xor_assign_max_product_degree() {
69 let mut dest = Polynomial::default();
71 let mut a = Polynomial::default();
72 let mut b = Polynomial::default();
73
74 a.set(127, 1);
75 b.set(127, 1);
76
77 dest.mul_xor_assign(&a, &b).expect("product degree fits");
78
79 assert_eq!(dest.degree(), 254);
80 }
81
82 #[test]
83 fn mul_xor_assign_rejects_degree_overflow() {
84 let mut dest = Polynomial::try_from(&[7u8][..]).expect("valid polynomial");
87 let mut a = Polynomial::default();
88 let mut b = Polynomial::default();
89
90 a.set(128, 1);
91 b.set(127, 1);
92
93 let original = dest;
94 let result = dest.mul_xor_assign(&a, &b);
95
96 assert_eq!(result, Err(PolynomialMulError::DegreeOverflow));
97 assert_eq!(dest, original);
98 }
99
100 #[test]
101 fn mul_xor_assign_basic() {
102 let mut dest = Polynomial::try_from(&[1u8][..]).expect("valid polynomial");
106 let a = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
107 let b = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
108
109 dest.mul_xor_assign(&a, &b).expect("product degree fits");
110
111 assert_eq!(dest.coefficients(), &[0, 0, 1]);
112 }
113
114 #[test]
115 fn mul_xor_assign_with_zero_a() {
116 let mut dest = Polynomial::try_from(&[5u8, 3][..]).expect("valid polynomial");
117 let a = Polynomial::default(); let b = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
119
120 dest.mul_xor_assign(&a, &b).expect("product degree fits");
121
122 assert_eq!(dest.coefficients(), &[5, 3]);
124 }
125
126 #[test]
127 fn mul_xor_assign_with_zero_b() {
128 let mut dest = Polynomial::try_from(&[5u8, 3][..]).expect("valid polynomial");
129 let a = Polynomial::try_from(&[1u8, 2, 3][..]).expect("valid polynomial");
130 let b = Polynomial::default(); dest.mul_xor_assign(&a, &b).expect("product degree fits");
133
134 assert_eq!(dest.coefficients(), &[5, 3]);
136 }
137
138 #[test]
139 fn mul_xor_assign_accumulates() {
140 let mut dest = Polynomial::try_from(&[1u8, 0, 1][..]).expect("valid polynomial");
142 let a = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
143 let b = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial");
144
145 dest.mul_xor_assign(&a, &b).expect("product degree fits");
148
149 assert_eq!(dest.coefficients(), &[0]);
150 }
151
152 #[test]
153 fn mul_xor_assign_extends_degree() {
154 let mut dest = Polynomial::try_from(&[5u8][..]).expect("valid polynomial");
156 let a = Polynomial::try_from(&[1u8, 0, 1][..]).expect("valid polynomial"); let b = Polynomial::try_from(&[1u8, 1][..]).expect("valid polynomial"); dest.mul_xor_assign(&a, &b).expect("product degree fits");
162
163 assert_eq!(dest.coefficients(), &[4, 1, 1, 1]);
164 }
165}