1 //==============================================================================================
2 //
3 // This file is part of LiDIA --- a library for computational number theory
4 //
5 // Copyright (c) 1994--2001 the LiDIA Group. All rights reserved.
6 //
7 // See http://www.informatik.tu-darmstadt.de/TI/LiDIA/
8 //
9 //----------------------------------------------------------------------------------------------
10 //
11 // $Id$
12 //
13 // Author : Thomas Pfahler (TPf)
14 // Changes : See CVS log
15 //
16 //==============================================================================================
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #include "LiDIA/gf_polynomial.h"
23
24
25
26 #ifdef LIDIA_NAMESPACE
27 namespace LiDIA {
28 #endif
29
30
31
32 //******************************************************************
33 // classical arithmetic
34 //******************************************************************
35
plain_power(polynomial<gf_element> & c,const polynomial<gf_element> & a,const bigint & b)36 void plain_power(polynomial< gf_element > & c,
37 const polynomial< gf_element > & a, const bigint & b)
38 {
39 //"classical" version
40 c.ffield = a.ffield;
41 polynomial< gf_element >::build_frame(a.ffield);
42 power(c.pol, a.pol, b);
43 c.delete_frame();
44 }
45
46
47
plain_gcd(polynomial<gf_element> & d,const polynomial<gf_element> & aa,const polynomial<gf_element> & bb)48 void plain_gcd(polynomial< gf_element > &d,
49 const polynomial< gf_element > &aa, const polynomial< gf_element > &bb)
50 {
51 //"classical" version
52 d.ffield = gf_polynomial::common_field(aa.ffield, bb.ffield);
53 polynomial< gf_element >::build_frame(d.ffield);
54 gcd(d.pol, aa.pol, bb.pol);
55 polynomial< gf_element >::delete_frame();
56 if (d.pol.degree() == 0) // if gcd = 1, pol[0] is not
57 d.pol[0].assign_one(d.ffield); // initialized
58 }
59
60
61
plain_multiply(gf_polynomial & c,const gf_polynomial & a,const gf_polynomial & b)62 void plain_multiply(gf_polynomial &c, const gf_polynomial &a,
63 const gf_polynomial &b)
64 {
65 //"classical" version
66 c.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
67 polynomial< gf_element >::build_frame(c.ffield);
68 multiply(c.pol, a.pol, b.pol);
69 polynomial< gf_element >::delete_frame();
70 }
71
72
73
plain_square(polynomial<gf_element> & c,const polynomial<gf_element> & a)74 void plain_square(polynomial< gf_element > & c,
75 const polynomial< gf_element > & a)
76 {
77 //"classical" version
78 c.ffield = a.ffield;
79 polynomial< gf_element >::build_frame(a.ffield);
80 multiply(c.pol, a.pol, a.pol);
81 polynomial< gf_element >::delete_frame();
82 }
83
84
85
plain_div_rem(gf_polynomial & q,gf_polynomial & r,const gf_polynomial & a,const gf_polynomial & b)86 void plain_div_rem(gf_polynomial &q, gf_polynomial &r,
87 const gf_polynomial &a, const gf_polynomial &b)
88 //r = a - q*b, "classical" version
89 {
90 q.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
91 r.ffield = q.ffield;
92 polynomial< gf_element >::build_frame(q.ffield);
93 div_rem(q.pol, r.pol, a.pol, b.pol);
94 polynomial< gf_element >::delete_frame();
95 }
96
97
98
plain_divide(gf_polynomial & q,const gf_polynomial & a,const gf_polynomial & b)99 void plain_divide(gf_polynomial &q,
100 const gf_polynomial &a, const gf_polynomial &b)
101 //r = a - q*b, "classical" version
102 {
103 gf_polynomial r;
104 q.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
105 r.ffield = q.ffield;
106 polynomial< gf_element >::build_frame(q.ffield);
107 div_rem(q.pol, r.pol, a.pol, b.pol);
108 polynomial< gf_element >::delete_frame();
109 }
110
111
112
plain_remainder(gf_polynomial & r,const gf_polynomial & a,const gf_polynomial & b)113 void plain_remainder(gf_polynomial &r,
114 const gf_polynomial &a, const gf_polynomial &b)
115 //r = a - q*b, "classical" version
116 {
117 gf_polynomial q;
118 q.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
119 r.ffield = q.ffield;
120 polynomial< gf_element >::build_frame(q.ffield);
121 div_rem(q.pol, r.pol, (base_polynomial< gf_element > )a.pol,
122 (base_polynomial< gf_element > )b.pol);
123 polynomial< gf_element >::delete_frame();
124 }
125
126
127
128 //******************************************************************
129 // the following 2 functions are the key to our fast multiplication
130 // and division routines :
131 //******************************************************************
132
to_Kronecker(Fp_polynomial & g,const gf_polynomial & f,lidia_size_t lo,lidia_size_t hi)133 void to_Kronecker(Fp_polynomial &g, const gf_polynomial &f,
134 lidia_size_t lo, lidia_size_t hi)
135 //computes Kronecker substitution:
136 //y -> x^(2n-1) for g in GF(p^n)[y], f in Fp[x]
137 //only g[lo..hi] is converted
138 {
139 if (lo < 0)
140 lidia_error_handler("gf_polynomial", "to_Kronecker(...)::bad indices");
141
142 hi = comparator< lidia_size_t >::min(hi, f.degree());
143
144 lidia_size_t m = comparator< lidia_size_t >::max(hi - lo + 1, 0);
145 lidia_size_t n = f.get_field().degree();
146 g.set_modulus(f.get_field().characteristic());
147 g.set_max_degree((2*n-1)*m);
148 //Kronecker substitution:
149 //y -> x^(2n-1)
150 lidia_size_t i, j;
151 //### std::cout<<"to, n = "<<n<<" m = "<<m<<std::endl;
152 for (i = lo; i <= hi; i++) {
153 for (j = 0; j < n; j++) {
154 //### std::cout<<"g["<<(i-lo)*(2*n-1) + j<<"] = f["<<i<<"]["<<j<<"]"<<std::endl;
155 g[(i-lo)*(2*n-1) + j].assign((f[i].polynomial_rep2())[j]);
156 }
157 }
158 }
159
160
161
from_Kronecker(gf_polynomial & f,const Fp_polynomial & g,lidia_size_t lo,lidia_size_t hi)162 void from_Kronecker(gf_polynomial &f, const Fp_polynomial &g,
163 lidia_size_t lo, lidia_size_t hi)
164 //computes "backwards" Kronecker substitution:
165 //X^(2n-1) -> Y for g in GF(p^n)[Y], f in Fp[X]
166 //only coefficients [lo..hi] (in Y) are converted
167 {
168 if (lo < 0)
169 lidia_error_handler("gf_polynomial", "from_Kronecker(...)::bad indices");
170
171 lidia_size_t n = f.get_field().degree();
172 lidia_size_t m = comparator< lidia_size_t >::max(hi - lo + 1, 0);
173 if (m == 0) {
174 f.assign_zero();
175 return;
176 }
177 const bigint &p = f.get_field().characteristic();
178 Fp_polynomial tmp;
179 tmp.set_modulus(p);
180 tmp.set_max_degree(n-1);
181 f.set_degree(m-1);
182 lidia_size_t i, j;
183 //### std::cout<<"from, n = "<<n<<" m = "<<m<<std::endl;
184
185 //Kronecker substitution:
186 //x^(2n-1) -> y
187 for (i = lo; i <= hi; i++) {
188 for (j = 0; j < (2*n-1); j++) {
189 tmp[j] = g[i*(2*n-1) + j];
190 }
191 //### std::cout<<"i-lo = "<<i-lo<<" tmp = "<<tmp<<std::endl;
192 f[i-lo].set_polynomial_rep(tmp);
193 }
194 f.remove_leading_zeros();
195 }
196
197
198
199 //******************************************************************
200 // "Kronecker" based arithmetic
201 //******************************************************************
202
203
copy_reverse(gf_polynomial & x,const gf_polynomial & a,lidia_size_t lo,lidia_size_t hi)204 void copy_reverse(gf_polynomial &x, const gf_polynomial &a,
205 lidia_size_t lo, lidia_size_t hi)
206 // x[0..hi-lo+1] = reverse(a[lo..hi]), with zero fill
207 // input may not alias output
208 {
209 debug_handler("gf_polynomial", "copy_reverse(gf_polynomial&, gf_polynomial&, lidia_size_t, lidia_size_t) ");
210 lidia_size_t i, j, n, m;
211
212 n = hi-lo+1;
213 m = a.degree()+1;
214
215 x.ffield = a.ffield;
216 polynomial< gf_element >::build_frame(a.ffield);
217 x.set_degree(n-1);
218
219 for (i = 0; i < n; i++) {
220 j = hi-i;
221 if (j< 0 || j >= m) x[i].assign_zero();
222 else x[i].assign(a[j]);
223 }
224
225 x.remove_leading_zeros();
226 polynomial< gf_element >::delete_frame();
227 }
228
229
230
231 // x = (1/a) % X^m, input not output, constant term a is nonzero
invert(gf_polynomial & x,const gf_polynomial & a,lidia_size_t m)232 void invert(gf_polynomial& x, const gf_polynomial& a, lidia_size_t m)
233 {
234 debug_handler("gf_polynomial", "invert(gf_polynomial&, gf_polynomial&, lidia_size_t)");
235
236 const galois_field K = a.ffield;
237
238 lidia_size_t i, k, n, lb;
239 gf_element s(K);
240
241 n = a.degree();
242 if (n < 0) lidia_error_handler("gf_polynomial", "invert(gf_polynomial&, gf_polynomial&, lidia_size_t)::division by zero");
243
244 invert(s, a.const_term());
245
246 if (n == 0) {
247 x.assign(s);
248 return;
249 }
250
251 x.ffield = K;
252 polynomial< gf_element >::build_frame(K);
253 x.set_degree(m-1);
254 x[0].assign(s);
255 bool ct_is_one = s.is_one();
256
257 if (K.characteristic() == 2) {
258 gf_element v(K), t(K);
259 for (k = 1; k < m; k++) {
260 v.assign_zero();
261 lb = comparator< lidia_size_t >::max(k-n, 0);
262 for (i = lb; i <= k-1; i++) {
263 multiply(t, x[i], a[k-i]);
264 add(v, v, t);
265 }
266 v.negate();
267 if (!ct_is_one) multiply(v, v, s);
268 x[k].assign(v);
269 }
270 }
271 else {
272 Fp_polynomial v, t;
273 v.set_modulus(K.characteristic());
274 for (k = 1; k < m; k++) {
275 v.assign_zero();
276 lb = comparator< lidia_size_t >::max(k-n, 0);
277 for (i = lb; i <= k-1; i++) {
278 multiply(t, x[i].polynomial_rep(), a[k-i].polynomial_rep());
279 add(v, v, t);
280 }
281 v.negate();
282 if (!ct_is_one) multiply(v, v, s.polynomial_rep());
283 x[k].set_polynomial_rep(v);
284 }
285 }
286 x.remove_leading_zeros();
287 polynomial< gf_element >::delete_frame();
288
289 #if 0
290 // KONTROLLE
291 gf_polynomial w1, w2, w3, w4;
292 w4.build_frame(a.ffield);
293 w4.set_degree(m);
294 w4[m].assign_one();
295 xgcd(w1, w2, w3, w4, a);
296 if (w3 != x) std::cout << "invert: error" << std::endl;
297 else std::cout << "invert: ok" << std::endl;
298 #endif
299 }
300
301
302
div_rem(gf_polynomial & q,gf_polynomial & r,const gf_polynomial & a,const gf_polynomial & b)303 void div_rem(gf_polynomial &q, gf_polynomial &r,
304 const gf_polynomial &a, const gf_polynomial &b)
305 //r = a - q*b
306 {
307 lidia_size_t deg_b = b.degree(), deg_a = a.degree();
308 if (deg_b < 0)
309 lidia_error_handler("polynomial< gf_element >", "div_rem::division by zero");
310
311 const galois_field &K = gf_polynomial::common_field(a.ffield, b.ffield);
312 if (deg_a < deg_b) {
313 q.assign_zero(K);
314 r.assign(a);
315 return;
316 }
317
318 if (K.characteristic() == 2
319 && (K.degree() > 1 || K.degree() == 1 && deg_a < 2*deg_b))
320 {
321 //"classical" version
322 q.ffield = K;
323 r.ffield = K;
324 gf_polynomial::build_frame(K);
325 div_rem(q.pol, r.pol, a.pol, b.pol);
326 gf_polynomial::delete_frame();
327 return;
328 }
329
330 gf_polynomial p1, p2, p3;
331 Fp_polynomial r1, r2;
332 copy_reverse(p3, b, 0, deg_b);
333 invert(p2, p3, deg_a-deg_b+1);
334 copy_reverse(p1, p2, 0, deg_a-deg_b);
335
336 to_Kronecker(r1, p1, 0, p1.degree());
337 to_Kronecker(r2, a, deg_b, deg_a);
338 //### std::cout<<"p1:\n"<<p1<<std::endl<<r1<<std::endl;
339 //### std::cout<<"a: db="<<deg_b<<" da="<<deg_a<<std::endl<<a<<std::endl<<r2<<std::endl;
340 multiply(r1, r1, r2);
341 from_Kronecker(p1, r1, deg_a-deg_b, 2*(deg_a-deg_b));
342
343 #if 0
344 // KONTROLLE
345 gf_polynomial tmp, tmp2;
346 tmp.build_frame(a.ffield);
347 tmp.set_degree(deg_a-deg_b);
348 for (lidia_size_t i = deg_b; i <= deg_a; i++)
349 tmp[i-deg_b] = a[i];
350 multiply(tmp2, tmp, p1);
351 std::cout << "tmp:\n" << tmp << std::endl << "tmp2:\n" << tmp2 << std::endl;
352 #endif
353
354 multiply(p2, b, p1);
355 subtract(r, a, p2);
356 q.assign(p1);
357 }
358
359
360
divide(gf_polynomial & q,const gf_polynomial & a,const gf_polynomial & b)361 void divide(gf_polynomial &q, const gf_polynomial &a, const gf_polynomial &b)
362 //q = a / b
363 {
364 lidia_size_t deg_b = b.degree(), deg_a = a.degree();
365 if (deg_b < 0)
366 lidia_error_handler("polynomial< gf_element >", "divide::division by zero");
367 q.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
368 gf_polynomial::build_frame(q.ffield);
369 if (deg_a < deg_b) {
370 q.assign_zero();
371 gf_polynomial::delete_frame();
372 return;
373 }
374
375 if (q.ffield.characteristic() == 2 && q.ffield.degree() > 1) {
376 //"classical" version
377 divide(q.pol, a.pol, b.pol);
378 gf_polynomial::delete_frame();
379 return;
380 }
381
382 gf_polynomial r;
383
384 gf_polynomial p1, p2, p3;
385 Fp_polynomial r1, r2;
386 copy_reverse(p3, b, 0, deg_b);
387 invert(p2, p3, deg_a-deg_b+1);
388 copy_reverse(p1, p2, 0, deg_a-deg_b);
389
390 to_Kronecker(r1, p1, 0, p1.degree());
391 to_Kronecker(r2, a, deg_b, deg_a);
392 multiply(r1, r1, r2);
393 from_Kronecker(q, r1, deg_a-deg_b, 2*(deg_a-deg_b));
394 polynomial< gf_element >::delete_frame();
395 }
396
397
398
remainder(gf_polynomial & r,const gf_polynomial & a,const gf_polynomial & b)399 void remainder(gf_polynomial &r, const gf_polynomial &a, const gf_polynomial &b)
400 //r = a - (a/b)*b
401 {
402 lidia_size_t deg_b = b.degree(), deg_a = a.degree();
403 if (deg_b < 0)
404 lidia_error_handler("polynomial< gf_element >", "remainder::division by zero");
405 gf_polynomial q;
406 q.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
407 gf_polynomial::build_frame(q.ffield);
408 if (deg_a < deg_b) {
409 q.assign_zero();
410 r.assign(a);
411 gf_polynomial::delete_frame();
412 return;
413 }
414
415 if (q.ffield.characteristic() == 2 && q.ffield.degree() > 1) {
416 //"classical" version
417 r.ffield = q.ffield;
418 remainder(r.pol, a.pol, b.pol);
419 gf_polynomial::delete_frame();
420 return;
421 }
422
423 gf_polynomial p1, p2, p3;
424 Fp_polynomial r1, r2;
425 copy_reverse(p3, b, 0, deg_b);
426 invert(p2, p3, deg_a-deg_b+1);
427 copy_reverse(p1, p2, 0, deg_a-deg_b);
428
429 to_Kronecker(r1, p1, 0, p1.degree());
430 to_Kronecker(r2, a, deg_b, deg_a);
431 multiply(r1, r1, r2);
432 from_Kronecker(q, r1, deg_a-deg_b, 2*(deg_a-deg_b));
433 polynomial< gf_element >::delete_frame();
434
435 multiply(p1, b, q);
436 subtract(r, a, p1);
437 }
438
439
440
multiply(gf_polynomial & c,const gf_polynomial & a,const gf_polynomial & b)441 void multiply(gf_polynomial &c, const gf_polynomial &a,
442 const gf_polynomial &b)
443 {
444 c.ffield = gf_polynomial::common_field(a.ffield, b.ffield);
445 polynomial< gf_element >::build_frame(c.ffield);
446
447 if (c.ffield.characteristic() == 2 && c.ffield.degree() > 2) {
448 //"classical" version
449 multiply(c.pol, a.pol, b.pol);
450 }
451 else {
452 Fp_polynomial r1, r2, r3;
453
454 to_Kronecker(r1, a, 0, a.degree());
455 to_Kronecker(r2, b, 0, b.degree());
456 multiply(r3, r1, r2);
457 from_Kronecker(c, r3, 0, a.degree()+b.degree());
458 }
459
460 polynomial< gf_element >::delete_frame();
461 }
462
463
464
square(polynomial<gf_element> & c,const polynomial<gf_element> & a)465 void square(polynomial< gf_element > & c,
466 const polynomial< gf_element > & a)
467 {
468 c.ffield = a.ffield;
469 polynomial< gf_element >::build_frame(a.ffield);
470
471 if (c.ffield.characteristic() == 2 && c.ffield.degree() > 2) {
472 //"classical" version
473 multiply(c.pol, a.pol, a.pol);
474 }
475 else {
476 Fp_polynomial r1, r2;
477
478 to_Kronecker(r1, a, 0, a.degree());
479 square(r2, r1);
480 from_Kronecker(c, r2, 0, 2*a.degree());
481 }
482
483 polynomial< gf_element >::delete_frame();
484 }
485
486
487
gcd(polynomial<gf_element> & d,const polynomial<gf_element> & aa,const polynomial<gf_element> & bb)488 void gcd(polynomial< gf_element > &d,
489 const polynomial< gf_element > &aa, const polynomial< gf_element > &bb)
490 {
491 debug_handler("gf_polynomial", "gcd(...)");
492
493 if (bb.is_zero())
494 d.assign(aa);
495 else if (aa.is_zero())
496 d.assign(bb);
497 else {
498 gf_polynomial r, a(aa), b(bb);
499 do
500 {
501 remainder(a, a, b);
502 swap(a, b);
503 } while (!b.is_zero());
504 d.assign(a);
505 }
506
507 if (d.is_zero())
508 return;
509
510 if (d.degree() == 0) {
511 d.assign_one();
512 return;
513 }
514
515 if (!d.lead_coeff().is_one()) {
516 gf_element lc_inv;
517 invert(lc_inv, d.lead_coeff());
518 multiply(d, d, lc_inv);
519 }
520 }
521
522
523
power(polynomial<gf_element> & c,const polynomial<gf_element> & a,const bigint & b)524 void power(polynomial< gf_element > & c,
525 const polynomial< gf_element > & a, const bigint & b)
526 {
527 bigint exponent;
528 gf_polynomial multiplier;
529 if (b.is_negative())
530 lidia_error_handler("gf_polynomial", "power(...)::negative exponent");
531
532 c.assign_one(a.get_field());
533 if (b.is_zero() || a.is_one())
534 return;
535
536 exponent.assign(b);
537 multiplier.assign(a);
538 while (exponent.is_gt_zero()) {
539 if (!exponent.is_even())
540 multiply(c, c, multiplier);
541 square(multiplier, multiplier);
542 exponent.divide_by_2();
543 }
544 }
545
546
547
548 //***************************************************************
549 //
550 // Modular Arithmetic without pre-conditioning
551 //
552 //***************************************************************
553
554 // arithmetic mod f.
555 // all inputs and outputs are polynomials of degree less than deg(f).
556 // ASSUMPTION: f is assumed monic, and deg(f) > 0.
557 // ALIAS RESTRICTIONS: f (and exponent e) can not alias an output.
558
559
560 void
multiply_mod(gf_polynomial & x,const gf_polynomial & a,const gf_polynomial & b,const gf_polynomial & f)561 multiply_mod(gf_polynomial & x, const gf_polynomial & a, const gf_polynomial & b, const gf_polynomial & f)
562 {
563 debug_handler_l("gf_polynomial", "mul_mod(gf_polynomial&, gf_polynomial&, gf_polynomial&, gf_polynomial&)", 6);
564
565 gf_polynomial t;
566 multiply(t, a, b);
567 remainder(x, t, f);
568 }
569
570
571
572 void
square_mod(gf_polynomial & x,const gf_polynomial & a,const gf_polynomial & f)573 square_mod(gf_polynomial & x, const gf_polynomial & a, const gf_polynomial & f)
574 {
575 debug_handler_l("gf_polynomial", "sqr_mod(gf_polynomial&, gf_polynomial&, gf_polynomial&)", 6);
576
577 gf_polynomial t;
578 square(t, a);
579 remainder(x, t, f);
580 }
581
582
583
584 void
multiply_by_x_mod(gf_polynomial & h,const gf_polynomial & a,const gf_polynomial & f)585 multiply_by_x_mod(gf_polynomial & h, const gf_polynomial & a, const gf_polynomial & f)
586 {
587 debug_handler_l("gf_polynomial", "mul_by_x_mod(gf_polynomial&, gf_polynomial&, gf_polynomial&)", 6);
588
589 h.ffield = gf_polynomial::common_field(a.ffield, f.ffield);
590 polynomial< gf_element >::build_frame(h.ffield);
591
592 lidia_size_t i, n, m;
593 gf_element t, z;
594
595 n = f.degree();
596 m = a.degree();
597
598 if (m < n - 1) {
599 h.set_degree(m + 1);
600 for (i = m + 1; i >= 1; i--)
601 h[i].assign(a[i - 1]);
602 h[0].assign_zero(f.get_field());
603 }
604 else {
605 if (&f == &h) {
606 //allows f to alias output
607
608 h.assign_zero();
609 h.delete_frame();
610 return;
611 }
612 if (m >= n || !f.is_monic()) {
613 gf_polynomial tmp;
614 tmp.assign_x(f.get_field());
615 multiply(h, a, tmp);
616 remainder(h, h, f);
617 h.delete_frame();
618 return;
619 }
620 //now, m = n-1
621
622 h.set_degree(n - 1);
623 negate(z, a[n - 1]);
624 for (i = n - 1; i >= 1; i--) {
625 multiply(t, z, f[i]);
626 add(h[i], a[i - 1], t);
627 }
628 multiply(h[0], z, f[0]);
629 h.remove_leading_zeros();
630 }
631 polynomial< gf_element >::delete_frame();
632 }
633
634
635
636 void
invert_mod(gf_polynomial & x,const gf_polynomial & a,const gf_polynomial & f)637 invert_mod(gf_polynomial & x, const gf_polynomial & a, const gf_polynomial & f)
638 {
639 debug_handler_l("gf_polynomial", "inv_mod(gf_polynomial&, gf_polynomial&, gf_polynomial&)", 6);
640
641 gf_polynomial d, t;
642 xgcd(d, x, t, a, f);
643 if (!d.is_one())
644 lidia_error_handler_c("gf_polynomial", "inv_mod(...)::"
645 "can't compute multiplicative inverse",
646 std::cout << "d = " << d << "a = " << a << "f = " << f << std::endl;
647 );
648 }
649
650
651
652 bool
invert_mod_status(gf_polynomial & x,const gf_polynomial & a,const gf_polynomial & f)653 invert_mod_status(gf_polynomial & x, const gf_polynomial & a, const gf_polynomial & f)
654 {
655 debug_handler_l("gf_polynomial", "inv_mod_status(gf_polynomial&, gf_polynomial&, gf_polynomial&)", 6);
656
657 gf_polynomial d, t;
658 xgcd(d, x, t, a, f);
659 if (!d.is_one())
660 x.assign(d);
661 return (d.is_one());
662 }
663
664
665
666 void
power_mod(gf_polynomial & h,const gf_polynomial & g,const bigint & e,const gf_polynomial & f)667 power_mod(gf_polynomial & h, const gf_polynomial & g, const bigint & e, const gf_polynomial & f)
668 {
669 debug_handler_l("gf_polynomial", "power_mod(gf_polynomial&, gf_polynomial&, bigint&, gf_polynomial&)", 6);
670
671 gf_polynomial lg(g);
672 lidia_size_t n = e.bit_length();
673
674 h.ffield = gf_polynomial::common_field(g.ffield, f.ffield);
675 polynomial< gf_element >::build_frame(h.ffield);
676 h.assign_one();
677
678 for (lidia_size_t i = n - 1; i >= 0; i--) {
679 square_mod(h, h, f);
680 if (e.bit(i))
681 multiply_mod(h, h, lg, f);
682 }
683 polynomial< gf_element >::delete_frame();
684 }
685
686
687
688 void
power_x_mod(gf_polynomial & h,const bigint & e,const gf_polynomial & f)689 power_x_mod(gf_polynomial & h, const bigint & e, const gf_polynomial & f)
690 {
691 debug_handler_l("gf_polynomial", "power_x_mod(gf_polynomial&, bigint&, gf_polynomial&)", 6);
692
693 if (&h == &f)
694 lidia_error_handler("gf_polynomial", "power_x_mod(gf_polynomial&, bigint&, gf_polynomial&)::no alias allowed");
695
696 h.ffield = f.ffield;
697 polynomial< gf_element >::build_frame(f.ffield);
698 h.set_degree(-1);
699
700 lidia_size_t n;
701 if (e < f.degree()) {
702 e.sizetify(n);
703 h.set_degree(n);
704 h[n] = 1;
705 //### std::cout<<"1) X^"<<e<<" mod "<<f<<" = "<<h<<std::endl;
706 }
707 else {
708 n = e.bit_length();
709 h.assign_one();
710
711 for (lidia_size_t i = n - 1; i >= 0; i--) {
712 square_mod(h, h, f);
713 if (e.bit(i))
714 multiply_by_x_mod(h, h, f);
715 }
716 //### std::cout<<"2) X^"<<e<<" mod "<<f<<" = "<<h<<std::endl;
717 }
718
719 polynomial< gf_element >::delete_frame();
720 }
721
722
723
724 // WARNING: obsolete. Use power_mod with Fp_poly_modulus (see below).
725 void
power_x_plus_a_mod(gf_polynomial & h,const gf_element & a,const bigint & e,const gf_polynomial & f)726 power_x_plus_a_mod(gf_polynomial & h, const gf_element & a, const bigint & e, const gf_polynomial & f)
727 {
728 debug_handler_l("gf_polynomial", "power_x_plus_a_mod(gf_polynomial&, bigint&, bigint&, gf_polynomial&)", 6);
729
730 h.ffield = f.ffield;
731 polynomial< gf_element >::build_frame(f.ffield);
732
733 lidia_size_t i;
734 gf_polynomial t1, t2;
735 gf_element la(a);
736 lidia_size_t n = e.bit_length();
737
738 h.assign_one();
739
740 for (i = n - 1; i >= 0; i--) {
741 square_mod(h, h, f);
742 if (e.bit(i)) {
743 multiply_by_x_mod(t1, h, f);
744 multiply(t2, h, la);
745 add(h, t1, t2);
746 }
747 }
748
749 polynomial< gf_element >::delete_frame();
750 }
751
752
753
754 // computes x = a mod X^m-1
755 void
cyclic_reduce(gf_polynomial & x,const gf_polynomial & a,lidia_size_t m)756 cyclic_reduce(gf_polynomial & x, const gf_polynomial & a, lidia_size_t m)
757 {
758 debug_handler_l("gf_polynomial", "cyclic_reduce(gf_polynomial&, gf_polynomial&, lidia_size_t)", 6);
759
760
761 lidia_size_t n = a.degree();
762 lidia_size_t i, j;
763 gf_element accum; //static
764
765 if (n < m) {
766 x.assign(a);
767 return;
768 }
769
770 if (&x == &a) {
771 x.set_degree(m - 1);
772 return;
773 }
774
775 x.ffield = a.ffield;
776 polynomial< gf_element >::build_frame(a.ffield);
777 x.set_degree(m - 1);
778
779 for (i = 0; i < m; i++) {
780 accum.assign(a[i]);
781 for (j = i + m; j <= n; j += m)
782 add(accum, accum, a[j]);
783 x[i].assign(accum);
784 }
785
786 x.remove_leading_zeros();
787 polynomial< gf_element >::delete_frame();
788 }
789
790
791
792 #ifdef LIDIA_NAMESPACE
793 } // end of namespace LiDIA
794 #endif
795