1use std::fmt::Debug;
2
3use scalarff::FieldElement;
4
5use crate::Vector;
6
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[derive(Clone, Debug, Eq)]
13pub struct Polynomial<T>
14where
15 T: FieldElement,
16{
17 pub coefficients: Vec<T>, }
19
20impl<T: FieldElement> Polynomial<T> {
21 pub fn new(coefficients: Vec<T>) -> Self {
22 Self { coefficients }
23 }
24
25 pub fn zero() -> Self {
27 Self {
28 coefficients: vec![],
29 }
30 }
31
32 pub fn identity() -> Self {
34 Self {
35 coefficients: vec![T::one()],
36 }
37 }
38
39 pub fn is_zero(&self) -> bool {
41 if self.coefficients.is_empty() {
42 return true;
43 }
44 for v in &self.coefficients {
45 if *v != T::zero() {
46 return false;
47 }
48 }
49 true
50 }
51
52 pub fn mul_scalar(&mut self, v: &T) {
54 for i in 0..self.coefficients.len() {
55 self.coefficients[i] *= v.clone();
56 }
57 }
58
59 pub fn constant_term(&self) -> T {
62 if self.coefficients.is_empty() {
63 T::zero()
64 } else {
65 self.coefficients[0].clone()
66 }
67 }
68
69 pub fn coef_vec(&self) -> Vector<T> {
74 let mut out = Vector::new();
75 for i in 0..(self.degree() + 1) {
76 out.push(self.coefficients[i].clone());
77 }
78 out
79 }
80
81 pub fn term(&mut self, coef: &T, exp: usize) {
83 if self.coefficients.len() < exp + 1 {
84 self.coefficients.resize(exp + 1, T::zero());
85 }
86 self.coefficients[exp] += coef.clone();
87 }
88
89 pub fn pop_term(&mut self) -> (T, usize) {
91 for i in 0..self.coefficients.len() {
92 let index = self.coefficients.len() - (i + 1);
93 let v = self.coefficients[index].clone();
94 if v != T::zero() {
95 self.coefficients[index] = T::zero();
96 return (v, index);
97 }
98 }
99 (T::zero(), 0)
100 }
101
102 pub fn degree(&self) -> usize {
105 for i in 0..self.coefficients.len() {
106 let index = self.coefficients.len() - (i + 1);
107 if self.coefficients[index] != T::zero() {
108 return index;
109 }
110 }
111 0
112 }
113
114 pub fn shift_and_clone(&self, degree: usize) -> Self {
118 let mut shifted_coefs = vec![T::zero(); degree];
119 shifted_coefs.extend(self.coefficients.clone());
120 Self {
121 coefficients: shifted_coefs,
122 }
123 }
124
125 pub fn div(&self, divisor: &Self) -> (Self, Self) {
128 if divisor.is_zero() {
129 panic!("divide by zero");
130 }
131 if self.degree() < divisor.degree() {
132 return (Self::zero(), self.clone());
133 }
134 let mut dclone = divisor.clone();
135 let mut quotient = Self::zero();
136 let (divisor_term, divisor_term_exp) = dclone.pop_term();
137 let divisor_term_inv = T::one() / divisor_term.clone();
138 let mut remainder = self.clone();
139 while !remainder.is_zero() && remainder.degree() >= divisor.degree() {
140 let (largest_term, largest_term_exp) = remainder.clone().pop_term();
141 let new_coef = largest_term * divisor_term_inv.clone();
142 let new_exp = largest_term_exp - divisor_term_exp;
143 quotient.term(&new_coef, new_exp);
144 let mut t = divisor.shift_and_clone(new_exp);
145 t.mul_scalar(&new_coef);
146 remainder = remainder - t;
147 }
148 (quotient, remainder)
149 }
150}
151
152impl<T: FieldElement> std::fmt::Display for Polynomial<T> {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 if self.is_zero() {
155 write!(f, "0")
156 } else {
157 write!(
158 f,
159 "{}",
160 self.coefficients
161 .iter()
162 .enumerate()
163 .map(|(i, v)| {
164 if *v == T::zero() && i > 0 {
165 return "".to_string();
166 }
167 if i > 0 {
168 format!("{}x^{i}", v.to_string())
169 } else {
170 v.to_string()
171 }
172 })
173 .filter(|x| x.len() > 0)
174 .collect::<Vec<_>>()
175 .join(" + ")
176 )
177 }
178 }
179}
180
181impl<T: FieldElement> std::ops::Add for Polynomial<T> {
182 type Output = Self;
183
184 fn add(self, other: Self) -> Self {
185 let max_len = if self.coefficients.len() > other.coefficients.len() {
186 self.coefficients.len()
187 } else {
188 other.coefficients.len()
189 };
190 let mut coefficients = vec![T::zero(); max_len];
191 for x in 0..max_len {
192 if x < self.coefficients.len() {
193 coefficients[x] += self.coefficients[x].clone();
194 }
195 if x < other.coefficients.len() {
196 coefficients[x] += other.coefficients[x].clone();
197 }
198 }
199 Polynomial { coefficients }
200 }
201}
202
203impl<T: FieldElement> std::ops::Sub for Polynomial<T> {
204 type Output = Self;
205
206 fn sub(self, other: Self) -> Self {
207 let max_len = if self.coefficients.len() > other.coefficients.len() {
208 self.coefficients.len()
209 } else {
210 other.coefficients.len()
211 };
212 let mut coefficients = vec![T::zero(); max_len];
213 for x in 0..max_len {
214 if x < self.coefficients.len() {
215 coefficients[x] += self.coefficients[x].clone();
216 }
217 if x < other.coefficients.len() {
218 coefficients[x] -= other.coefficients[x].clone();
219 }
220 }
221 Polynomial { coefficients }
222 }
223}
224
225impl<T: FieldElement> std::ops::Mul for Polynomial<T> {
226 type Output = Self;
227
228 fn mul(self, other: Self) -> Self {
229 let mut coefficients = vec![T::zero(); self.coefficients.len() + other.coefficients.len()];
230 for i in 0..other.coefficients.len() {
231 for j in 0..self.coefficients.len() {
232 let e = j + i;
234 coefficients[e] += self.coefficients[j].clone() * other.coefficients[i].clone();
236 }
237 }
238 let mut max = coefficients.len();
242 for i in (0..coefficients.len()).rev() {
243 if coefficients[i] != T::zero() {
244 break;
245 }
246 max = i;
247 }
248 Polynomial {
249 coefficients: coefficients[0..max].to_vec(),
250 }
251 }
252}
253
254impl<T: FieldElement> std::ops::Neg for Polynomial<T> {
255 type Output = Self;
256
257 fn neg(self) -> Self {
258 Polynomial {
259 coefficients: self.coefficients.iter().map(|v| -v.clone()).collect(),
260 }
261 }
262}
263
264impl<T: FieldElement> std::cmp::PartialEq for Polynomial<T> {
265 fn eq(&self, other: &Self) -> bool {
266 if self.degree() != other.degree() {
267 return false;
268 }
269 for i in 0..self.degree() {
270 if self.coefficients[i] != other.coefficients[i] {
271 return false;
272 }
273 }
274 true
275 }
276}
277
278impl<T: FieldElement> std::hash::Hash for Polynomial<T> {
279 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
280 for i in 0..self.degree() {
282 self.coefficients[i].hash(state);
283 }
284 }
285}
286
287#[cfg(test)]
288mod test {
289 use super::Polynomial;
290 use scalarff::FieldElement;
291 use scalarff::OxfoiFieldElement;
292
293 #[test]
294 #[cfg(feature = "rand")]
295 fn mul_div() {
296 for _ in 0..100 {
297 let mut r = rand::thread_rng();
298 let p1 = Polynomial {
299 coefficients: vec![
300 OxfoiFieldElement::sample_uniform(&mut r),
301 OxfoiFieldElement::sample_uniform(&mut r),
302 OxfoiFieldElement::sample_uniform(&mut r),
303 OxfoiFieldElement::sample_uniform(&mut r),
304 OxfoiFieldElement::sample_uniform(&mut r),
305 ],
306 };
307 let p2 = Polynomial {
308 coefficients: vec![
309 OxfoiFieldElement::sample_uniform(&mut r),
310 OxfoiFieldElement::sample_uniform(&mut r),
311 OxfoiFieldElement::sample_uniform(&mut r),
312 ],
313 };
314 let (q, r) = p1.div(&p2);
315 assert!(!q.is_zero());
316 assert!(!p1.is_zero());
317 assert!(!p2.is_zero());
318 assert_eq!(q * p2 + r, p1);
319 }
320 }
321}