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