1
2 #ifndef _HELIB_SPX_H_
3 #define _HELIB_SPX_H_
4 /* SPX.h - A MUX class that implements either GF2X or zz_pX: it keeps both
5 * objects, and decides in runitime to use one or the other as appropriate.
6 *
7 * Modifications:
8 *
9 * Created by Shai Halevi on May 27, 2015
10 */
11 #include <iostream>
12 #include <NTL/version.h>
13 #include <NTL/ZZX.h>
14 #include <NTL/GF2X.h>
15 #include <NTL/lzz_pX.h>
16
17 // A helper class that maintains the NTL context (this is unnecessary
18 // as of NTL version 9.2.0)
19 #if (NTL_MAJOR_VERSION<9 || (NTL_MAJOR_VERSION==9 && NTL_MINOR_VERSION<2))
20 class SPmodulus { // single precision modulus
21 public:
22 long p; // the modulus itself
23 NTL::zz_pContext context; // NTL context, used if !gf2
24
SPmodulus()25 SPmodulus(): p(0) {}
SPmodulus(long _p)26 SPmodulus(long _p): p(_p), context(_p) {}
SPmodulus(long _p,const NTL::zz_pContext & _c)27 SPmodulus(long _p, const NTL::zz_pContext& _c): p(_p), context(_c) {}
28
null()29 bool null() const { return (p==0); }
modulus()30 long modulus() const { return p; }
equals(const SPmodulus & other)31 bool equals(const SPmodulus& other) const
32 { return p==other.p; }
33 };
getContext(const SPmodulus & spm)34 inline const NTL::zz_pContext& getContext(const SPmodulus& spm) { return spm.context; }
35 #else
36 typedef NTL::zz_pContext SPmodulus;
getContext(const SPmodulus & spm)37 inline const NTL::zz_pContext& getContext(const SPmodulus& spm) { return spm; }
38 #endif
isGF2(const SPmodulus & spm)39 inline bool isGF2(const SPmodulus& spm) { return spm.modulus()==2; }
40
41
42
43 // macro for non-const unary operators (e.g., ++SPX)
44 #define sppolyUnary(fnc) SPX& fnc() { \
45 if (isGF2(modulus)) {NTL::fnc(gf2x);} \
46 else {NTL::zz_pPush push(getContext(modulus)); NTL::fnc(zzpx);} \
47 return *this;}
48
49 // macro for non-const binary operators that take a long (SPX += long)
50 #define sppolyBinaryLeft(fnc) SPX fnc(long y) { \
51 if (isGF2(modulus)) { NTL::fnc(gf2x,y); } \
52 else { NTL::zz_pPush push(getContext(modulus)); NTL::fnc(zzpx,y); }\
53 return *this; }
54
55 // macro for non-const binay operators that take another SPX
56 // (SPX += SPX)
57 #define sppolyBinaryBoth(fnc) SPX fnc(const SPX& y) { \
58 ensureConsistency(*this,y); \
59 if (isGF2(modulus)) { NTL::fnc(gf2x,y.gf2x); } \
60 else { NTL::zz_pPush push(getContext(modulus)); NTL::fnc(zzpx,y.zzpx); } \
61 return *this;}
62
63 // The main class SPX, declerations follow GF2X, zz_pX
64 class SPX {
65 public:
66 SPmodulus modulus; // not a reference, the object itself
67 NTL::GF2X gf2x;
68 NTL::zz_pX zzpx;
69
70 // access methods
getMod()71 const SPmodulus& getMod() const { return modulus; }
72
73 // helper functions
makeFromVec(const NTL::Vec<T> & v)74 template <class T> void makeFromVec(const NTL::Vec<T>& v)
75 {
76 if (isGF2(modulus)) {
77 NTL::Vec<NTL::GF2> v2;
78 NTL::conv(v2, v);
79 NTL::conv(gf2x, v2);
80 } else {
81 NTL::zz_pPush push(getContext(modulus));
82 NTL::Vec<NTL::zz_p> vp;
83 NTL::conv(vp, v);
84 NTL::conv(zzpx, vp);
85 }
86 }
87
deg()88 long deg() const
89 { return (isGF2(modulus)? NTL::deg(gf2x): NTL::deg(zzpx)); }
90
91 template <class T> void getCoeffVec(NTL::Vec<T>& v, long n=-1) const
92 {
93 if (n<0) n=deg()+1;
94 if (isGF2(modulus)) {
95 NTL::Vec<NTL::GF2> v2 = NTL::VectorCopy(gf2x, n);
96 NTL::conv(v, v2);
97 } else {
98 NTL::zz_pPush push(getContext(modulus));
99 NTL::Vec<NTL::zz_p> vp = NTL::VectorCopy(zzpx, n);
100 NTL::conv(v, vp);
101 }
102 }
103
104 // internal constructors, useful for debugging
SPX(const NTL::GF2X & p2)105 explicit SPX(const NTL::GF2X& p2): modulus(2), gf2x(p2) {}
SPX(const NTL::zz_pX & pp,const SPmodulus & mod)106 SPX(const NTL::zz_pX& pp, const SPmodulus& mod): modulus(mod) {
107 if (isGF2(mod)) { // need to convert to GF2X
108 NTL::Vec<long> v;
109 NTL::conv(v, pp.rep);
110 makeFromVec(v);
111 }
112 else zzpx = pp;
113 }
114
resetMod(const SPmodulus & mod)115 void resetMod(const SPmodulus& mod)
116 {
117 if (modulus.null()) { // uninititalized object
118 modulus = mod;
119 return;
120 }
121 bool noteq = false;
122 if (isGF2(mod)!=isGF2(modulus)) noteq = true;
123 if (!isGF2(mod) && !mod.equals(modulus)) noteq = true;
124 if (noteq) {
125 gf2x.kill();
126 zzpx.kill();
127 modulus = mod;
128 }
129 }
130
131 void setCoeff(long i, long c=1)
132 {
133 if (isGF2(modulus)) NTL::SetCoeff(gf2x, i, c);
134 else NTL::SetCoeff(zzpx, i, c);
135 }
136
137 // Checking consistency between arguments, T is either SPX or SPXModulus
138 template<class T>
ensureConsistency(const SPX & x,const T & y)139 static void ensureConsistency(const SPX& x, const T& y)
140 { if (isGF2(x.getMod()) && isGF2(y.getMod())) return;
141 if (isGF2(x.getMod()) || isGF2(y.getMod()) || !x.getMod().equals(y.getMod())) {
142 throw std::invalid_argument("mismatched moduli in SPX arguments");
143 }
144 }
145 template<class S, class T>
ensureConsistency(const SPX & x,const S & y,const T & z)146 static void ensureConsistency(const SPX& x, const S& y, const T& z)
147 { ensureConsistency(x,y); ensureConsistency(x,z); }
148
149 // Constructors
150
SPX()151 SPX(){} // empty object
SPX(const SPmodulus & mod)152 explicit SPX(const SPmodulus& mod): modulus(mod) {} // equal to zero
SPX(const NTL::Vec<long> & coefs,const SPmodulus & mod)153 SPX(const NTL::Vec<long>& coefs, const SPmodulus& mod): // initialized
154 modulus(mod) { makeFromVec<long>(coefs); }
SPX(const NTL::ZZX & poly,const SPmodulus & mod)155 SPX(const NTL::ZZX& poly, const SPmodulus& mod):// initialized from ZZX
156 modulus(mod) { makeFromVec<NTL::ZZ>(poly.rep); }
157
158 // Convencience constructors: initialize to X^i or c*X^i
SPX(NTL::INIT_MONO_TYPE,long i,const SPmodulus & mod)159 SPX(NTL::INIT_MONO_TYPE, long i, const SPmodulus& mod):
160 modulus(mod) { setCoeff(i); }
SPX(NTL::INIT_MONO_TYPE,long i,long c,const SPmodulus & mod)161 SPX(NTL::INIT_MONO_TYPE, long i, long c, const SPmodulus& mod):
162 modulus(mod) { setCoeff(i,c); }
163
SPX(NTL::INIT_SIZE_TYPE,long n,const SPmodulus & mod)164 SPX(NTL::INIT_SIZE_TYPE, long n, const SPmodulus& mod):
165 modulus(mod) { setCoeff(n-1,0); }
166 // SPX(INIT_SIZE, n, mod) initializes to zero, but space is
167 // pre-allocated for n coefficients
168
169 // Implicit copy constructor, destructor, and assignment operator
170
171 // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The
172 // polynomial that f represents is unchanged.
SetMaxLength(long n)173 void SetMaxLength(long n)
174 {
175 if (modulus.null()) return; // uninitialized, cannot allocate space
176 if (isGF2(modulus)) gf2x.SetMaxLength(n);
177 else zzpx.SetMaxLength(n);
178 }
179
180 // f.kill() sets f to 0 and frees all memory held by f.
kill()181 void kill()
182 {
183 if (modulus.null()) return; // uninitialized, nothing to do
184 if (isGF2(modulus)) gf2x.kill();
185 else zzpx.kill();
186 }
187
188 sppolyBinaryLeft(operator+=) // SPX += long
189 sppolyBinaryBoth(operator+=) // SPX += SPPoly
190
191 template <class T> SPX operator+(T b) const
192 { SPX tmp=*this; tmp += b; return tmp; }
193
194 sppolyUnary(operator++) // ++SPX
195 void operator++(int) { operator++(); } // SPX++
196
197 sppolyBinaryLeft(operator-=) // SPX -= long
198 sppolyBinaryBoth(operator-=) // SPX -= SPPoly
199
200 template <class T> SPX operator-(T b) const
201 { SPX tmp=*this; tmp -= b; return tmp; }
202
203 sppolyUnary(operator--) // --SPX
204 void operator--(int) { operator--(); } // SPX--
205
negate()206 void negate() {
207 if (isGF2(modulus)) return; // nothing to do, over GF2 we have X == -X
208 else {
209 NTL::zz_pPush push(getContext(modulus));
210 NTL::negate(zzpx, zzpx);
211 }
212 }
213 SPX operator-() const
214 { SPX tmp=*this; tmp.negate(); return tmp; }
215
216
217 sppolyBinaryLeft(operator*=) // SPX *= long
218 sppolyBinaryBoth(operator*=) // SPX *= SPPoly
219
220 template <class T> SPX operator*(T b) const
221 { SPX tmp=*this; tmp *= b; return tmp; }
222
223 sppolyBinaryLeft(operator<<=) // SPX <<= long
224 SPX operator<<(long n) const
225 { SPX tmp=*this; tmp <<= n; return tmp; }
226
227 sppolyBinaryLeft(operator>>=) // SPX >>= long
228 SPX operator>>(long n) const
229 { SPX tmp=*this; tmp >>= n; return tmp; }
230
231 sppolyBinaryBoth(operator/=) // SPX /= SPX
232 sppolyBinaryLeft(operator/=) // SPX /= long
233
234 template <class T> SPX operator/(T b) const
235 { SPX tmp=*this; tmp /= b; return tmp; }
236
237 sppolyBinaryBoth(operator%=) // SPX %= SPX
238
239 SPX operator%(const SPX& b) const
240 { SPX tmp=*this; tmp %= b; return tmp; }
241
242 // SIZE INVARIANT: for any f in SPX, deg(f)+1 < 2^(NTL_BITS_PER_LONG-4).
243 };
244
245 typedef NTL::Vec<SPX> vec_SPX; // a conveneince vector decleration
246
247 // macro for function with signature void fnc(const SPX& x)
248 #define sppolyOnePoly(fnc) fnc(SPX& x) { \
249 if (isGF2(x.getMod())) NTL::fnc(x.gf2x); \
250 else { NTL::zz_pPush push(getContext(x.getMod())); \
251 NTL::fnc(x.zzpx);}}
252
253 // macro for function with signature non-void fnc(const type& x)
254 // type is either SPX or SPXModulus
255 #define sppolyConstOnePoly(fnc, typ) fnc(const typ& x) { \
256 if (isGF2(x.getMod())) return NTL::fnc(x.gf2x); \
257 else { NTL::zz_pPush push(getContext(x.getMod())); \
258 return NTL::fnc(x.zzpx);}}
259
260 // macro for function with signature void fnc(SPX& x, const type& arg)
261 // type is either SPX or SPXModulus
262 #define sppolyTwoPoly(fnc,typ) fnc(SPX& x, typ& y) {\
263 x.resetMod(y.getMod()); \
264 if (isGF2(x.getMod())) NTL::fnc(x.gf2x, y.gf2x); \
265 else { NTL::zz_pPush push(getContext(x.getMod())); \
266 NTL::fnc(x.zzpx, y.zzpx);}}
267
268 // macro for function with signature
269 // void fnc(SPX& x, const SPX& a, const type& b)
270 // type is either SPX or SPXModulus
271 #define sppolyThreePoly(fnc,typ)\
272 fnc(SPX& x, const SPX& a, const typ& b) {\
273 SPX::ensureConsistency(a,b);\
274 x.resetMod(a.getMod()); \
275 if (isGF2(x.getMod())) NTL::fnc(x.gf2x, a.gf2x, b.gf2x);\
276 else { NTL::zz_pPush push(getContext(x.getMod())); \
277 NTL::fnc(x.zzpx, a.zzpx, b.zzpx);}}
278
279 // macro for function with signature
280 // void fnc(SPX& x, const SPX& a, const type& b)
281 // type is either SPX or SPXModulus
282 #define sppolyFourPoly(fnc,typ)\
283 fnc(SPX& x, const SPX& a, const SPX& b, const typ& f) { \
284 SPX::ensureConsistency(a,b,f); \
285 x.resetMod(a.getMod()); \
286 if (isGF2(x.getMod())) \
287 NTL::fnc(x.gf2x, a.gf2x, b.gf2x, f.gf2x); \
288 else { NTL::zz_pPush push(getContext(x.getMod())); \
289 NTL::fnc(x.zzpx, a.zzpx, b.zzpx, f.zzpx);}}
290
291 // macro for function with signature
292 // void fnc(SPX& x, const SPX& a, type b)
293 #define sppolyTwoPolyArg(fnc,typ) \
294 fnc(SPX& x, const SPX& a, typ b) { \
295 x.resetMod(a.getMod()); \
296 if (isGF2(x.getMod())) NTL::fnc(x.gf2x, a.gf2x, b);\
297 else { NTL::zz_pPush push(getContext(x.getMod())); \
298 NTL::fnc(x.zzpx, a.zzpx, b);}}
299
300 // macro for function with signature
301 // void fnc(SPX& x, const SPX& g, const typ& F, long m)
302 #define sppolyThreePolyArg(fnc,typ) \
303 fnc(SPX& x, const SPX& g, const typ& F, long m) {\
304 SPX::ensureConsistency(g,F); \
305 x.resetMod(g.getMod()); \
306 if (isGF2(g.getMod())) NTL::fnc(x.gf2x, g.gf2x, F.gf2x, m);\
307 else { NTL::zz_pPush push(getContext(g.getMod())); \
308 NTL::fnc(x.zzpx, g.zzpx, F.zzpx, m);}}
309
310 /**************************************************************************\
311 Accessing coefficients
312
313 The degree of a polynomial f is obtained as deg(f),
314 where the zero polynomial, by definition, has degree -1.
315
316 A polynomial f is represented as a coefficient vector.
317 Coefficients may be accessed via coeff(f, i) to get the
318 coefficient of X^i in the polynomial f, and SetCoeff(f, i, a)
319 to set the coefficient of X^i in f to the scalar a.
320
321 \**************************************************************************/
322
deg(const SPX & a)323 inline long deg(const SPX& a) { return a.deg(); }
324 // return deg(a); deg(0) == -1.
325
coeff(const SPX & x,long i)326 inline long coeff(const SPX& x, long i)
327 {
328 if (isGF2(x.getMod())) return NTL::conv<long>(NTL::coeff(x.gf2x, i));
329 else {
330 NTL::zz_pPush push(getContext(x.getMod()));
331 return NTL::conv<long>(NTL::coeff(x.zzpx,i));
332 }
333 }
334
335 // const long coeff(const SPX& a, long i);
336 // returns the coefficient of X^i, or zero if i not in range
337
LeadCoeff(const SPX & a)338 inline long LeadCoeff(const SPX& a)
339 { return coeff(a, deg(a)); }
340 // returns leading term of a, or zero if a == 0
341
ConstTerm(const SPX & a)342 const long ConstTerm(const SPX& a)
343 { return coeff(a, 0); }
344 // returns constant term of a, or zero if a == 0
345
SetCoeff(SPX & x,long i,long a)346 void SetCoeff(SPX& x, long i, long a)
347 { x.setCoeff(i,a); }
348 // makes coefficient of X^i equal to a; error is raised if i < 0
349
SetCoeff(SPX & x,long i)350 void SetCoeff(SPX& x, long i)
351 { x.setCoeff(i); }
352
353 // makes coefficient of X^i equal to 1; error is raised if i < 0
354
355 inline void sppolyOnePoly(SetX)
356 // void SetX(SPX& x); // x is set to the monomial X
357
358 inline bool sppolyConstOnePoly(IsX,SPX)
359 // long IsX(const SPX& a); // test if x = X
360
361
362 /**************************************************************************\
363
364 Comparison
365
366 \**************************************************************************/
367
368 bool operator==(const SPX& a, const SPX& b) {
369 if (isGF2(a.getMod())!=isGF2(b.getMod())) return false;
370 if (isGF2(a.getMod())) return (a.gf2x==b.gf2x);
371 else return (a.getMod().equals(b.getMod()) && (a.zzpx==b.zzpx));
372 }
373 bool operator!=(const SPX& a, const SPX& b)
374 { return !(a==b); }
375
376 inline bool sppolyConstOnePoly(IsZero,SPX)
377 // bool IsZero(const SPX& a); // test for 0
378
379 inline bool sppolyConstOnePoly(IsOne,SPX)
380 // bool IsOne(const SPX& a); // test for 1
381
382 // PROMOTIONS: operators ==, != promote {long, long} to SPX on (a, b)
383
384
385 /**************************************************************************\
386
387 Addition
388
389 \**************************************************************************/
390
391 // operator notation:
392
393 inline SPX operator+(long a, const SPX& b)
394 { return (b+a);}
395 //SPX operator-(long, const SPX& b); // not implemented
396
397 // procedural versions:
398
add(SPX & x,const SPX & a,const SPX & b)399 inline void add(SPX& x, const SPX& a, const SPX& b)// x = a + b
400 { x = a; x+= b; }
add(SPX & x,long a,const SPX & b)401 inline void add(SPX& x, long a, const SPX& b) // x = a + b
402 { x = b; x+= a; }
add(SPX & x,const SPX & a,long b)403 inline void add(SPX& x, const SPX& a, long b) // x = a + b
404 { x = a; x+= b; }
sub(SPX & x,const SPX & a,const SPX & b)405 inline void sub(SPX& x, const SPX& a, const SPX& b) // x = a - b
406 { x=a; x-=b; }
407 // void sub(SPX& x, long a, const SPX& b); // x = a - b, not implemented
sub(SPX & x,const SPX & a,long b)408 inline void sub(SPX& x, const SPX& a, long b) // x = a - b
409 { x=a; x-=b; }
negate(SPX & x,const SPX & a)410 inline void negate(SPX& x, const SPX& a) // x = -a
411 { x = a; x.negate(); }
412 //inline void negate(SPX& x, long a) // x = -a, not implemented
413
414
415 /**************************************************************************\
416
417 Multiplication
418
419 \**************************************************************************/
420
421 // operator notation:
422
423 inline SPX operator*(long a, const SPX& b)
424 { return (b*a); }
425
426 // procedural versions:
427
mul(SPX & x,const SPX & a,const SPX & b)428 inline void mul(SPX& x, const SPX& a, const SPX& b) // x = a * b
429 { x=a; x*=b; }
mul(SPX & x,long a,const SPX & b)430 inline void mul(SPX& x, long a, const SPX& b) // x = a * b
431 { x=b; x*=a; }
mul(SPX & x,const SPX & a,long b)432 inline void mul(SPX& x, const SPX& a, long b) // x = a * b
433 { x=a; x*=b; }
434
sppolyTwoPoly(sqr,const SPX)435 inline void sppolyTwoPoly(sqr,const SPX)
436 //void sqr(SPX& x, const SPX& a); // x = a^2
437
438 inline SPX sqr(const SPX& a)
439 { SPX x; sqr(x,a); return x; }
440
441 /**************************************************************************\
442
443 Shift Operations
444
445 LeftShift by n means multiplication by X^n
446 RightShift by n means division by X^n
447
448 A negative shift amount reverses the direction of the shift.
449
450 \**************************************************************************/
451
452 // procedural versions:
453
LeftShift(SPX & x,const SPX & a,long n)454 inline void LeftShift(SPX& x, const SPX& a, long n)
455 { x=a; x <<= n; }
LeftShift(const SPX & a,long n)456 inline SPX LeftShift(const SPX& a, long n)
457 { return a << n; }
458
RightShift(SPX & x,const SPX & a,long n)459 inline void RightShift(SPX& x, const SPX& a, long n)
460 { x=a; x >>= n; }
RightShift(const SPX & a,long n)461 inline SPX RightShift(const SPX& a, long n)
462 { return a >> n; }
463
464 /**************************************************************************\
465
466 Division
467
468 \**************************************************************************/
469
470 // procedural versions:
471
472 // q = a/b, r = a%b (class T is either SPX or SPXModulus)
473 template<class T>
DivRem(SPX & q,SPX & r,const SPX & a,const T & b)474 inline void DivRem(SPX& q, SPX& r, const SPX& a, const T& b)
475 {
476 SPX::ensureConsistency(a,b);
477 q.resetMod(a.getMod());
478 r.resetMod(a.getMod());
479 if (isGF2(a.getMod()))
480 NTL::DivRem(q.gf2x, r.gf2x, a.gf2x, b.gf2x);
481 else {
482 NTL::zz_pPush push(getContext(a.getMod()));
483 NTL::DivRem(q.zzpx, r.zzpx, a.zzpx, b.zzpx);
484 }
485 }
486
487 // q = a/b
sppolyThreePoly(div,SPX)488 inline void sppolyThreePoly(div,SPX)
489 // void div(SPX& q, const SPX& a, const SPX& b);
490
491 // r = a%b
492 inline void sppolyThreePoly(rem,SPX)
493 // void rem(SPX& r, const SPX& a, const SPX& b);
494
495 // if b | a, sets q = a/b and returns 1; otherwise returns 0
496 inline bool divide(SPX& q, const SPX& a, const SPX& b)
497 {
498 if (isGF2(a.getMod())!=isGF2(b.getMod())) return false;
499 if (!isGF2(a.getMod()) && !a.getMod().equals(b.getMod())) return false;
500 q.resetMod(a.getMod());
501 if (isGF2(a.getMod())) return NTL::divide(q.gf2x, a.gf2x, b.gf2x);
502 else {
503 NTL::zz_pPush push(getContext(a.getMod()));
504 return NTL::divide(q.zzpx, a.zzpx, b.zzpx);
505 }
506 }
507
divide(const SPX & a,const SPX & b)508 inline bool divide(const SPX& a, const SPX& b)
509 {
510 if (isGF2(a.getMod())!=isGF2(b.getMod())) return false;
511 if (!isGF2(a.getMod()) && !a.getMod().equals(b.getMod())) return false;
512 if (isGF2(a.getMod())) return NTL::divide(a.gf2x, b.gf2x);
513 else {
514 NTL::zz_pPush push(getContext(a.getMod()));
515 return NTL::divide(a.zzpx, b.zzpx);
516 }
517 }
518 // if b | a returns 1; otherwise returns 0
519
520 /**************************************************************************\
521
522 GCD's
523
524 \**************************************************************************/
525
526
sppolyThreePoly(GCD,SPX)527 inline void sppolyThreePoly(GCD,SPX)
528 //void GCD(SPX& x, const SPX& a, const SPX& b);
529
530 SPX GCD(const SPX& a, const SPX& b)
531 { SPX x; GCD(x, a, b); return x; }
532 // x = GCD(a, b) (zero if a==b==0).
533
534 // d = gcd(a,b), a s + b t = d
XGCD(SPX & d,SPX & s,SPX & t,const SPX & a,const SPX & b)535 inline void XGCD(SPX& d, SPX& s, SPX& t,
536 const SPX& a, const SPX& b)
537 {
538 SPX::ensureConsistency(a,b);
539 d.resetMod(a.getMod());
540 s.resetMod(a.getMod());
541 t.resetMod(a.getMod());
542 if (isGF2(a.getMod()))
543 NTL::XGCD(d.gf2x, s.gf2x, t.gf2x, a.gf2x, b.gf2x);
544 else {
545 NTL::zz_pPush push(getContext(a.getMod()));
546 NTL::XGCD(d.zzpx, s.zzpx, t.zzpx, a.zzpx, b.zzpx);
547 }
548 }
549
550 /**************************************************************************\
551
552 Input/Output
553
554 I/O format:
555
556 [a_0 a_1 ... a_n],
557
558 represents the polynomial a_0 + a_1*X + ... + a_n*X^n.
559
560 On output, all coefficients will be in [0,p-1], and a_n not zero
561 (the zero polynomial is [ ]). On input, the coefficients may be
562 arbitrary integers which are reduced modulo p, and leading zeros
563 stripped.
564
565 x must have the right modulus set before calling these functions
566 \**************************************************************************/
567
568 inline std::istream& operator>>(std::istream& s, SPX& x)
569 {
570 if (isGF2(x.getMod())) return s >> x.gf2x;
571 else {
572 NTL::zz_pPush push(getContext(x.getMod()));
573 return s >> x.gf2x;
574 }
575 }
576
577 inline std::ostream& operator<<(std::ostream& s, const SPX& x)
578 {
579 if (isGF2(x.getMod())) return s << x.gf2x;
580 else {
581 NTL::zz_pPush push(getContext(x.getMod()));
582 return s << x.zzpx;
583 }
584 }
585
586 /**************************************************************************\
587
588 Some utility routines
589
590 \**************************************************************************/
591
592 // x = derivative of a
sppolyTwoPoly(diff,const SPX)593 inline void sppolyTwoPoly(diff,const SPX)
594 // void diff(SPX& x, const SPX& a);
595
596 inline SPX diff(const SPX& a)
597 { SPX x; diff(x,a); return x; }
598
599 inline void reverse(SPX& x, const SPX& a, long hi=-2)
600 {
601 if (hi < -1) hi = deg(a);
602 x.resetMod(a.getMod());
603 if (isGF2(x.getMod())) NTL::reverse(x.gf2x, a.gf2x, hi);
604 else {
605 NTL::zz_pPush push(getContext(x.getMod()));
606 NTL::reverse(x.zzpx, a.zzpx, hi);
607 }
608 }
609
610 inline SPX reverse(const SPX& a, long hi=-2)
611 { SPX x; reverse(x,a,hi); return x; }
612
613 // x = reverse of a[0]..a[hi] (hi >= -1);
614 // hi defaults to deg(a) in second version
615
616
617 /**************************************************************************\
618
619 Random Polynomials
620
621 \**************************************************************************/
622
623 // x = random polynomial of degree < n, with specified modulus
random(SPX & x,long n,const SPmodulus & mod)624 inline void random(SPX& x, long n, const SPmodulus& mod)
625 {
626 x.resetMod(mod);
627 if (isGF2(x.getMod())) NTL::random(x.gf2x, n);
628 else {
629 NTL::zz_pPush push(getContext(x.getMod()));
630 NTL::random(x.zzpx, n);
631 }
632 }
633
random_SPX(long n,const SPmodulus & mod)634 inline SPX random_SPX(long n, const SPmodulus& mod)
635 { SPX x; random(x, n, mod); return x; }
636
637 /**************************************************************************\
638
639 Arithmetic mod X^n
640
641 Required: n >= 0; otherwise, an error is raised.
642
643 \**************************************************************************/
644
sppolyTwoPolyArg(trunc,long)645 inline void sppolyTwoPolyArg(trunc,long)
646 //void trunc(SPX& x, const SPX& a, long n); // x = a % X^n
647
648 inline SPX trunc(const SPX& a, long n)
649 { SPX x; trunc(x,a,n); return x; }
650
651 // x = a * b % X^n
sppolyThreePolyArg(MulTrunc,SPX)652 inline void sppolyThreePolyArg(MulTrunc,SPX)
653 //void MulTrunc(SPX& x, const SPX& a, const SPX& b, long n);
654
655 SPX MulTrunc(const SPX& a, const SPX& b, long n)
656 { SPX x; MulTrunc(x,a,b,n); return x; }
657
658 // x = a^2 % X^n
sppolyTwoPolyArg(SqrTrunc,long)659 inline void sppolyTwoPolyArg(SqrTrunc,long)
660 //void SqrTrunc(SPX& x, const SPX& a, long n);
661
662 inline SPX SqrTrunc(const SPX& a, long n)
663 { SPX x; SqrTrunc(x,a,n); return x; }
664
665 // computes x = a^{-1} % X^n. Must have ConstTerm(a) invertible.
666
sppolyTwoPolyArg(InvTrunc,long)667 inline void sppolyTwoPolyArg(InvTrunc, long)
668 // void InvTrunc(SPX& x, const SPX& a, long n);
669
670 inline SPX InvTrunc(const SPX& a, long n)
671 { SPX x; InvTrunc(x,a,n); return x; }
672
673 /**************************************************************************\
674
675 Modular Arithmetic (without pre-conditioning)
676
677 Arithmetic mod f.
678
679 All inputs and outputs are polynomials of degree less than deg(f), and
680 deg(f) > 0.
681
682 NOTE: if you want to do many computations with a fixed f, use the
683 SPXModulus data structure and associated routines below for better
684 performance.
685
686 \**************************************************************************/
687
688 // x = (a * b) % f
sppolyFourPoly(MulMod,SPX)689 inline void sppolyFourPoly(MulMod,SPX)
690 //void MulMod(SPX& x, const SPX& a, const SPX& b, const SPX& f);
691
692 inline SPX MulMod(const SPX& a, const SPX& b, const SPX& f)
693 { SPX x; MulMod(x,a,b,f); return x; }
694
695
696 // x = a^2 % f
sppolyThreePoly(SqrMod,SPX)697 inline void sppolyThreePoly(SqrMod,SPX)
698 //void SqrMod(SPX& x, const SPX& a, const SPX& f);
699
700 inline SPX SqrMod(const SPX& a, const SPX& f)
701 { SPX x; SqrMod(x,a,f); return x; }
702
703 // x = (a * X) mod f
sppolyThreePoly(MulByXMod,SPX)704 inline void sppolyThreePoly(MulByXMod,SPX)
705 //void MulByXMod(SPX& x, const SPX& a, const SPX& f);
706
707 inline SPX MulByXMod(const SPX& a, const SPX& f)
708 { SPX x; MulByXMod(x,a,f); return x; }
709
710 // x = a^{-1} % f, error is a is not invertible
sppolyThreePoly(InvMod,SPX)711 inline void sppolyThreePoly(InvMod,SPX)
712 //void InvMod(SPX& x, const SPX& a, const SPX& f);
713
714 inline SPX InvMod(const SPX& a, const SPX& f)
715 { SPX x; InvMod(x,a,f); return x; }
716
InvModStatus(SPX & x,const SPX & a,const SPX & f)717 inline bool InvModStatus(SPX& x, const SPX& a, const SPX& f)
718 {
719 SPX::ensureConsistency(a,f);
720 x.resetMod(a.getMod());
721 if (isGF2(a.getMod()))
722 return NTL::InvModStatus(x.gf2x, a.gf2x, f.gf2x);
723 else {
724 NTL::zz_pPush push(getContext(x.getMod()));
725 return NTL::InvModStatus(x.zzpx, a.zzpx, f.zzpx);
726 }
727 }
728 // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
729 // returns 1 and sets x = (a, f)
730
731
732 // for modular exponentiation, see below
733
734
735
736 /**************************************************************************\
737
738 Modular Arithmetic with Pre-Conditioning
739
740 If you need to do a lot of arithmetic modulo a fixed f, build
741 SPXModulus F for f. This pre-computes information about f that
742 speeds up subsequent computations.
743
744 As an example, the following routine computes the product modulo f of a vector
745 of polynomials.
746
747 #include <NTL/SPX.h>
748
749 void product(SPX& x, const vec_SPX& v, const SPX& f)
750 {
751 SPXModulus F(f);
752 SPX res;
753 res = 1;
754 long i;
755 for (i = 0; i < v.length(); i++)
756 MulMod(res, res, v[i], F);
757 x = res;
758 }
759
760
761 Note that automatic conversions are provided so that a SPX can
762 be used wherever a SPXModulus is required, and a SPXModulus
763 can be used wherever a SPX is required.
764
765 The SPXModulus routines optimize several important special cases:
766
767 - f = X^n + X^k + 1, where k <= min((n+1)/2, n-NTL_BITS_PER_LONG)
768
769 - f = X^n + X^{k_3} + X^{k_2} + X^{k_1} + 1,
770 where k_3 <= min((n+1)/2, n-NTL_BITS_PER_LONG)
771
772 - f = X^n + g, where deg(g) is small
773
774
775 \**************************************************************************/
776
777 class SPXModulus {
778 public:
779 SPmodulus modulus; // not a reference, the object itself
780 NTL::GF2XModulus gf2x;
781 NTL::zz_pXModulus zzpx;
SPXModulus()782 SPXModulus() {} // initially in an unusable state
783
784 // access methods
getMod()785 const SPmodulus& getMod() const { return modulus; }
786
SPXModulus(const SPX & f)787 SPXModulus(const SPX& f): // initialize with f, deg(f)>0
788 modulus(f.getMod())
789 {
790 if (isGF2(f.getMod())) gf2x=f.gf2x;
791 else zzpx=f.zzpx;
792 }
793 SPXModulus& operator=(const SPX& f) {
794 modulus = f.getMod();
795 if (isGF2(f.getMod())) gf2x=f.gf2x;
796 else zzpx=f.zzpx;
797 return *this;
798 }
799 };
800
build(SPXModulus & F,const SPX & f)801 inline void build(SPXModulus& F, const SPX& f) { F=f; }
802 // pre-computes information about f and stores it in F; deg(f) > 0.
803 // Note that the declaration SPXModulus F(f) is equivalent to
804 // SPXModulus F; build(F, f).
805
806 // In the following, f refers to the polynomial f supplied to the
807 // build routine, and n = deg(f).
808
sppolyConstOnePoly(deg,SPXModulus)809 inline long sppolyConstOnePoly(deg,SPXModulus)
810 //long deg(const SPXModulus& F); // return deg(f)
811
812 // x = (a * b) % f
813 inline void sppolyFourPoly(MulMod,SPXModulus)
814 //void MulMod(SPX& x, const SPX& a, const SPX& b, const SPXModulus& F);
815
816 inline SPX MulMod(const SPX& a, const SPX& b, const SPXModulus& f)
817 { SPX x; MulMod(x,a,b,f); return x; }
818
819
820 // x = a^2 % f
sppolyThreePoly(SqrMod,SPXModulus)821 inline void sppolyThreePoly(SqrMod,SPXModulus)
822 //void SqrMod(SPX& x, const SPX& a, const SPXModulus& F);
823
824 inline SPX SqrMod(const SPX& a, const SPXModulus& f)
825 { SPX x; SqrMod(x,a,f); return x; }
826
827 // x = (a * X) mod f
sppolyThreePoly(MulByXMod,SPXModulus)828 inline void sppolyThreePoly(MulByXMod,SPXModulus)
829 //void MulByXMod(SPX& x, const SPX& a, const SPXModulus& F);
830
831 inline SPX MulByXMod(const SPX& a, const SPXModulus& f)
832 { SPX x; MulByXMod(x,a,f); return x; }
833
834 /**
835 // x = a^{-1} % f, error is a is not invertible
836 inline void sppolyThreePoly(InvMod,SPXModulus)
837 //void InvMod(SPX& x, const SPX& a, const SPXModulus& f);
838
839 inline SPX InvMod(const SPX& a, const SPXModulus& f)
840 { SPX x; InvMod(x,a,f); return x; }
841 **/
842
843 template <class T>
PowerXMod(SPX & x,T e,const SPXModulus & F)844 void PowerXMod(SPX& x, T e, const SPXModulus& F)
845 {
846 x.resetMod(F.getMod());
847 if (isGF2(x.getMod())) NTL::PowerXMod(x.gf2x, e, F.gf2x);
848 else {
849 NTL::zz_pPush push(getContext(x.getMod()));
850 NTL::PowerXMod(x.zzpx, e, F.zzpx);
851 }
852 }
853
854
855 template <class Z> // Z is either long or const ZZ&
PowerMod(SPX & x,const SPX & a,Z e,const SPXModulus & F)856 void PowerMod(SPX& x, const SPX& a, Z e, const SPXModulus& F)
857 {
858 SPX::ensureConsistency(a,F);
859 x.resetMod(a.getMod());
860 if (isGF2(a.getMod()))
861 NTL::PowerMod(x.gf2x, a.gf2x, e, F.gf2x);
862 else {
863 NTL::zz_pPush push(getContext(a.getMod()));
864 NTL::PowerMod(x.zzpx, a.zzpx, e, F.zzpx);
865 }
866 }
867
868 template <class Z> // Z is either long or const ZZ&
PowerMod(const SPX & a,Z e,const SPXModulus & F)869 SPX PowerMod(const SPX& a, Z e, const SPXModulus& F)
870 { SPX x; PowerMod<Z>(x, a, e, F); return x; }
871
872
873 // q = a/b
874 inline void sppolyThreePoly(div,SPXModulus)
875 //void div(SPX& q, const SPX& a, const SPXModulus& F);
876
877 // r = a%b
878 inline void sppolyThreePoly(rem,SPXModulus)
879 //void rem(SPX& x, const SPX& a, const SPXModulus& F);
880
881
882 // x = a % f
883
884 //void DivRem(SPX& q, SPX& r, const SPX& a, const SPXModulus& F);
885 // q = a/f, r = a%f (defined above in a template)
886
887 // operator notation:
888
889 inline SPX operator/(const SPX& a, const SPXModulus& F)
890 { SPX x; div(x,a,F); return x; }
891 inline SPX operator%(const SPX& a, const SPXModulus& F)
892 { SPX x; rem(x,a,F); return x; }
893
894 inline SPX& operator/=(SPX& x, const SPXModulus& F)
895 {
896 SPX::ensureConsistency(x,F);
897 if (isGF2(x.getMod()))
898 x.gf2x /= F.gf2x;
899 else {
900 NTL::zz_pPush push(getContext(x.getMod()));
901 x.zzpx /= F.zzpx;
902 }
903 return x;
904 }
905
906 inline SPX& operator%=(SPX& x, const SPXModulus& F)
907 {
908 SPX::ensureConsistency(x,F);
909 if (isGF2(x.getMod()))
910 x.gf2x %= F.gf2x;
911 else {
912 NTL::zz_pPush push(getContext(x.getMod()));
913 x.zzpx %= F.zzpx;
914 }
915 return x;
916 }
917
918
919 /**************************************************************************\
920
921 Modular Composition
922
923 Modular composition is the problem of computing g(h) mod f for
924 polynomials f, g, and h.
925
926 The algorithm employed is that of Brent & Kung (Fast algorithms for
927 manipulating formal power series, JACM 25:581-595, 1978), which uses
928 O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
929 operations.
930
931
932
933 \**************************************************************************/
934
935 // x = g(h) mod f; deg(h) < n
sppolyFourPoly(CompMod,SPXModulus)936 inline void sppolyFourPoly(CompMod,SPXModulus)
937 //void CompMod(SPX& x, const SPX& g, const SPX& h, const SPXModulus& F);
938
939 SPX CompMod(const SPX& g, const SPX& h, const SPXModulus& F)
940 { SPX x; CompMod(x,g,h,F); return x; }
941
Comp2Mod(SPX & x1,SPX & x2,const SPX & g1,const SPX & g2,const SPX & h,const SPXModulus & F)942 inline void Comp2Mod(SPX& x1, SPX& x2, const SPX& g1, const SPX& g2,
943 const SPX& h, const SPXModulus& F)
944 {
945 SPX::ensureConsistency(g1,g2,F); SPX::ensureConsistency(h,F);
946 x1.resetMod(g1.getMod());
947 x2.resetMod(g2.getMod());
948 if (isGF2(F.getMod()))
949 NTL::Comp2Mod(x1.gf2x, x2.gf2x,
950 g1.gf2x, g2.gf2x, h.gf2x, F.gf2x);
951 else {
952 NTL::zz_pPush push(getContext(F.getMod()));
953 NTL::Comp2Mod(x1.zzpx, x2.zzpx,
954 g1.zzpx, g2.zzpx, h.zzpx, F.zzpx);
955 }
956 }
957 // xi = gi(h) mod f (i=1,2), deg(h) < n.
958
Comp3Mod(SPX & x1,SPX & x2,SPX & x3,const SPX & g1,const SPX & g2,const SPX & g3,const SPX & h,const SPXModulus & F)959 inline void Comp3Mod(SPX& x1, SPX& x2, SPX& x3,
960 const SPX& g1, const SPX& g2, const SPX& g3,
961 const SPX& h, const SPXModulus& F)
962 {
963 SPX::ensureConsistency(g1,g2,F); SPX::ensureConsistency(g3,h,F);
964 x1.resetMod(g1.getMod());
965 x2.resetMod(g2.getMod());
966 x3.resetMod(g3.getMod());
967 if (isGF2(F.getMod()))
968 NTL::Comp3Mod(x1.gf2x, x2.gf2x, x3.gf2x,
969 g1.gf2x, g2.gf2x, g3.gf2x, h.gf2x, F.gf2x);
970 else {
971 NTL::zz_pPush push(getContext(F.getMod()));
972 NTL::Comp3Mod(x1.zzpx, x2.zzpx, x3.zzpx,
973 g1.zzpx, g2.zzpx, g3.zzpx, h.zzpx, F.zzpx);
974 }
975 }
976
977 // xi = gi(h) mod f (i=1..3), deg(h) < n
978
979
980 /**************************************************************************\
981
982 Composition with Pre-Conditioning
983
984 If a single h is going to be used with many g's then you should build
985 a SPXArgument for h, and then use the compose routine below. The
986 routine build computes and stores h, h^2, ..., h^m mod f. After this
987 pre-computation, composing a polynomial of degree roughly n with h
988 takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus,
989 increasing m increases the space requirement and the pre-computation
990 time, but reduces the composition time.
991
992 \**************************************************************************/
993
994
995 struct SPXArgument {
996 SPmodulus modulus;
997 NTL::GF2XArgument gf2x;
998 NTL::zz_pXArgument zzpx;
999
1000 // access methods
getModSPXArgument1001 const SPmodulus& getMod() const { return modulus; }
1002
resetModSPXArgument1003 void resetMod(const SPmodulus& mod)
1004 {
1005 if (modulus.null()) { // uninititalized object
1006 modulus = mod;
1007 return;
1008 }
1009 bool noteq = false;
1010 if (isGF2(mod)!=isGF2(modulus)) noteq = true;
1011 if (!isGF2(mod) && !mod.equals(modulus)) noteq = true;
1012 if (noteq) {
1013 gf2x.H.kill();
1014 zzpx.H.kill();
1015 modulus = mod;
1016 }
1017 }
1018 };
1019
build(SPXArgument & H,const SPX & h,const SPXModulus & F,long m)1020 inline void build(SPXArgument& H,
1021 const SPX& h, const SPXModulus& F, long m)
1022 {
1023 SPX::ensureConsistency(h,F);
1024 H.resetMod(h.getMod());
1025 if (isGF2(h.getMod()))
1026 NTL::build(H.gf2x, h.gf2x, F.gf2x, m);
1027 else {
1028 NTL::zz_pPush push(getContext(h.getMod()));
1029 NTL::build(H.zzpx, h.zzpx, F.zzpx, m);
1030 }
1031 }
1032 // Pre-Computes information about h. m > 0, deg(h) < n
1033
CompMod(SPX & x,const SPX & g,const SPXArgument & H,const SPXModulus & F)1034 inline void CompMod(SPX& x, const SPX& g,
1035 const SPXArgument& H, const SPXModulus& F)
1036 {
1037 SPX::ensureConsistency(g,H,F);
1038 x.resetMod(F.getMod());
1039 if (isGF2(F.getMod()))
1040 NTL::CompMod(x.gf2x, g.gf2x, H.gf2x, F.gf2x);
1041 else {
1042 NTL::zz_pPush push(getContext(F.getMod()));
1043 NTL::CompMod(x.zzpx, g.zzpx, H.zzpx, F.zzpx);
1044 }
1045 }
1046
CompMod(const SPX & g,const SPXArgument & H,const SPXModulus & F)1047 inline SPX CompMod(const SPX& g, const SPXArgument& H,
1048 const SPXModulus& F)
1049 { SPX x; CompMod(x,g,H,F); return x; }
1050
setPolyArgBound(long B)1051 inline void setPolyArgBound(long B)
1052 {
1053 extern long GF2XArgBound;
1054 extern long zz_pXArgBound;
1055 GF2XArgBound = zz_pXArgBound = B;
1056 }
1057 // Initially the bounds are 0. If this is set to a value greater than
1058 // zero, then composition routines will allocate a table of no than
1059 // about SPXArgBound KB. Setting this value affects all compose
1060 // routines and the power projection and minimal polynomial routines
1061 // below, and indirectly affects many routines in SPXFactoring.
1062
1063 /**************************************************************************\
1064
1065 Power Projection routines
1066
1067 \**************************************************************************/
1068
project(long & x,const NTL::Vec<long> & a,const SPX & b)1069 inline void project(long& x, const NTL::Vec<long>& a, const SPX& b)
1070 {
1071 if (isGF2(b.getMod())) {
1072 NTL::GF2 x2;
1073 NTL::vec_GF2 a2 = NTL::conv<NTL::vec_GF2>(a);
1074 NTL::project(x2, a2, b.gf2x);
1075 NTL::conv(x,x2);
1076 }
1077 else {
1078 NTL::zz_pPush push(getContext(b.getMod()));
1079 NTL::zz_p xp;
1080 NTL::vec_zz_p ap = NTL::conv<NTL::vec_zz_p>(a);
1081 NTL::project(xp, ap, b.zzpx);
1082 NTL::conv(x,xp);
1083 }
1084 }
project(const NTL::Vec<long> & a,const SPX & b)1085 inline long project(const NTL::Vec<long>& a, const SPX& b)
1086 { long x; project(x,a,b); return x; }
1087 // x = inner product of a with coefficient vector of b (conv needed)
1088
1089
1090 // class T is either SPX or SPXArgument
1091 template <class T>
ProjectPowers(NTL::Vec<long> & x,const NTL::Vec<long> & a,long k,const T & h,const SPXModulus & F)1092 inline void ProjectPowers(NTL::Vec<long>& x, const NTL::Vec<long>& a, long k,
1093 const T& h, const SPXModulus& F)
1094 {
1095 SPX::ensureConsistency(h,F);
1096 if (isGF2(F.getMod())) {
1097 NTL::vec_GF2 x2;
1098 NTL::vec_GF2 a2 = NTL::conv<NTL::vec_GF2>(a);
1099 NTL::ProjectPowers(x2, a2, k, h.gf2x, F.gf2x);
1100 NTL::conv(x,x2);
1101 }
1102 else {
1103 NTL::zz_pPush push(getContext(F.getMod()));
1104 NTL::vec_zz_p xp;
1105 NTL::vec_zz_p ap = NTL::conv<NTL::vec_zz_p>(a);
1106 NTL::ProjectPowers(xp, ap, k, h.zzpx, F.zzpx);
1107 NTL::conv(x,xp);
1108 }
1109 }
1110
1111 template <class T>
ProjectPowers(const NTL::Vec<long> & a,long k,const T & h,const SPXModulus & F)1112 inline NTL::Vec<long> ProjectPowers(const NTL::Vec<long>& a, long k,
1113 const T& h, const SPXModulus& F)
1114 { NTL::Vec<long> x; ProjectPowers(x,a,k,h,F); return x; }
1115
1116 // Computes the vector
1117
1118 // (project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).
1119
1120 // Restriction: must have a.length <= deg(F) and deg(h) < deg(F).
1121 // This operation is really the "transpose" of the modular composition
1122 // operation.
1123
1124 /**************************************************************************\
1125
1126 Minimum Polynomials
1127
1128 All of these routines implement the algorithm from [Shoup, J. Symbolic
1129 Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1130 1995], based on transposed modular composition and the
1131 Berlekamp/Massey algorithm.
1132
1133 \**************************************************************************/
1134
1135
1136 inline void
MinPolySeq(SPX & h,const NTL::Vec<long> & a,long m,const SPmodulus & mod)1137 MinPolySeq(SPX& h, const NTL::Vec<long>& a, long m, const SPmodulus& mod)
1138 {
1139 h.resetMod(mod);
1140 if (isGF2(h.getMod())) {
1141 NTL::vec_GF2 a2 = NTL::conv<NTL::vec_GF2>(a);
1142 NTL::MinPolySeq(h.gf2x, a2, m);
1143 }
1144 else {
1145 NTL::zz_pPush push(getContext(h.getMod()));
1146 NTL::vec_zz_p ap = NTL::conv<NTL::vec_zz_p>(a);
1147 NTL::MinPolySeq(h.zzpx, ap, m);
1148 }
1149 }
1150 // computes the minimum polynomial of a linealy generated sequence; m is a
1151 // bound on the degree of the polynomial; required: a.length() >= 2*m
1152
sppolyThreePolyArg(ProbMinPolyMod,SPXModulus)1153 inline void sppolyThreePolyArg(ProbMinPolyMod,SPXModulus)
1154 //void ProbMinPolyMod(SPX& h,const SPX& g,const SPXModulus& F,long m);
1155
1156 inline SPX ProbMinPolyMod(const SPX& g, const SPXModulus& F, long m)
1157 { SPX h; ProbMinPolyMod(h,g,F,m); return h; }
1158
sppolyThreePoly(ProbMinPolyMod,SPXModulus)1159 inline void sppolyThreePoly(ProbMinPolyMod,SPXModulus)
1160 //void ProbMinPolyMod(SPX& h, const SPX& g, const SPXModulus& F);
1161
1162 inline SPX ProbMinPolyMod(const SPX& g, const SPXModulus& F)
1163 { SPX h; ProbMinPolyMod(h,g,F); return h; }
1164
1165 // computes the monic minimal polynomial of (g mod f). m is a bound on
1166 // the degree of the minimal polynomial; in the second version, this
1167 // argument defaults to n. The algorithm is probabilistic; it always
1168 // returns a divisor of the minimal polynomial, possibly a proper divisor.
1169
sppolyThreePolyArg(MinPolyMod,SPXModulus)1170 inline void sppolyThreePolyArg(MinPolyMod,SPXModulus)
1171 //void MinPolyMod(SPX& h, const SPX& g, const SPXModulus& F, long m);
1172
1173 SPX MinPolyMod(const SPX& g, const SPXModulus& F, long m)
1174 { SPX h; MinPolyMod(h,g,F,m); return h; }
1175
sppolyThreePoly(MinPolyMod,SPXModulus)1176 inline void sppolyThreePoly(MinPolyMod,SPXModulus)
1177 //void MinPolyMod(SPX& h, const SPX& g, const SPXModulus& F);
1178
1179 inline SPX MinPolyMod(const SPX& g, const SPXModulus& F)
1180 { SPX h; MinPolyMod(h,g,F); return h; }
1181
1182
1183 // same as above, but guarantees that result is correct
1184
sppolyThreePolyArg(IrredPolyMod,SPXModulus)1185 inline void sppolyThreePolyArg(IrredPolyMod,SPXModulus)
1186 //void IrredPolyMod(SPX& h, const SPX& g, const SPXModulus& F, long m)
1187
1188 inline SPX IrredPolyMod(const SPX& g, const SPXModulus& F, long m)
1189 { SPX h; IrredPolyMod(h,g,F,m); return h; }
1190
sppolyThreePoly(IrredPolyMod,SPXModulus)1191 inline void sppolyThreePoly(IrredPolyMod,SPXModulus)
1192 //void IrredPolyMod(SPX& h, const SPX& g, const SPXModulus& F);
1193
1194 inline SPX IrredPolyMod(const SPX& g, const SPXModulus& F)
1195 { SPX h; IrredPolyMod(h,g,F); return h; }
1196
1197
1198 // same as above, but assumes that F is irreducible, or at least that
1199 // the minimal poly of g is itself irreducible. The algorithm is
1200 // deterministic (and is always correct).
1201
1202
1203 /**************************************************************************\
1204
1205 Traces
1206
1207 \**************************************************************************/
1208
1209 // class T can be either SPX or SPXModulus
1210 template<class T>
TraceMod(long & x,const SPX & a,const T & F)1211 void TraceMod(long& x, const SPX& a, const T& F)
1212 {
1213 SPX::ensureConsistency(a,F);
1214 if (isGF2(a.getMod())) {
1215 NTL::GF2 x2;
1216 NTL::TraceMod(x2, a.gf2x, F.gf2x);
1217 NTL::conv(x,x2);
1218 } else {
1219 NTL::zz_pPush push(getContext(a.getMod()));
1220 NTL::zz_p xp;
1221 NTL::TraceMod(xp, a.zzpx, F.zzpx);
1222 NTL::conv(x,xp);
1223 }
1224 }
1225 template<class T>
TraceMod(const SPX & a,const T & F)1226 long TraceMod(const SPX& a, const T& F)
1227 { long x; TraceMod(x,a,F); return x; }
1228
1229 //void TraceMod(long& x, const SPX& a, const SPX& f);
1230 //long TraceMod(const SPX& a, const SPX& f);
1231 // x = Trace(a mod f); deg(a) < deg(f)
1232
TraceVec(NTL::Vec<long> & S,const SPX & f)1233 inline void TraceVec(NTL::Vec<long>& S, const SPX& f)
1234 {
1235 if (isGF2(f.getMod())) {
1236 NTL::vec_GF2 S2;
1237 TraceVec(S2, f.gf2x);
1238 NTL::conv(S,S2);
1239 }
1240 else {
1241 NTL::zz_pPush push(getContext(f.getMod()));
1242 NTL::vec_zz_p Sp;
1243 TraceVec(Sp, f.zzpx);
1244 NTL::conv(S,Sp);
1245 }
1246 }
1247
TraceVec(const SPX & f)1248 inline NTL::Vec<long> TraceVec(const SPX& f)
1249 { NTL::Vec<long> S; TraceVec(S,f); return S; }
1250 // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)
1251
1252 // The above routines implement the asymptotically fast trace
1253 // algorithm from [von zur Gathen and Shoup, Computational Complexity,
1254 // 1992].
1255
1256
1257 /**************************************************************************\
1258 Miscellany
1259 \**************************************************************************/
1260
1261 inline void sppolyOnePoly(clear)
1262 //void clear(SPX& x); // x = 0
1263
1264 inline void sppolyOnePoly(set)
1265 //void set(SPX& x); // x = 1
1266
1267 inline void sppolyTwoPoly(swap, SPX)
1268 //void swap(SPX& x, SPX& y);
1269 // swap (via "pointer swapping" -- if possible)
1270
1271
1272 /**************************************************************************\
1273 Factoring
1274 \**************************************************************************/
1275 #include <NTL/GF2XFactoring.h>
1276 #include <NTL/pair_GF2X_long.h>
1277 #include <NTL/lzz_pXFactoring.h>
1278 #include <NTL/pair_zz_pX_long.h>
1279
1280 typedef NTL::Pair<SPX,long> pair_SPX_long;
1281 typedef NTL::Vec<pair_SPX_long> vec_pair_SPX_long;
1282 /*
1283 void SquareFreeDecomp(vec_pair_SPX_long& u, const SPX& f);
1284 inline vec_pair_SPX_long SquareFreeDecomp(const SPX& f)
1285 { vec_pair_SPX_long vp; SquareFreeDecomp(vp, f); return vp; }
1286
1287 // Performs square-free decomposition. f must be monic, if f = prod_i gi^ei
1288 // then u is set to a list of pairs (gi,ei). The list is is increasing order
1289 // of ei, with trivial terms (i.e., gi=1) deleted.
1290
1291
1292 void DDF(vec_pair_SPX_long& factors, const SPX& f, long verbose=0);
1293 inline vec_pair_SPX_long DDF(const SPX& f, long verbose=0)
1294 { vec_pair_SPX_long vp; DDF(vp, f, verbose); return vp; }
1295
1296 // This computes a distinct-degree factorization. The input must be
1297 // monic and square-free. factors is set to a list of pairs (g, d),
1298 // where g is the product of all irreducible factors of f of degree d.
1299 // Only nontrivial pairs (i.e., g != 1) are included.
1300 */
1301
1302
1303 inline void EDF(vec_SPX& factors, const SPX& f, long d, long verbose=0)
1304 {
1305 SPX tmp(f.getMod());
1306 factors.kill(); // remove everything from factors (if any)
1307 if (isGF2(f.getMod())) {
1308 NTL::vec_GF2X fac2;
1309 NTL::EDF(fac2, f.gf2x, d, verbose);
1310 factors.SetLength(fac2.length(), tmp); // allocate space
1311 for (long i=0; i<factors.length(); i++)
1312 factors[i].gf2x = fac2[i];
1313 } else {
1314 NTL::zz_pPush push(getContext(f.getMod()));
1315 NTL::vec_zz_pX facp;
1316 NTL::EDF(facp, f.zzpx, PowerXMod(NTL::zz_p::modulus(),f.zzpx), d, verbose);
1317 factors.SetLength(facp.length(), tmp); // allocate space
1318 for (long i=0; i<factors.length(); i++)
1319 factors[i].zzpx = facp[i];
1320 }
1321 }
1322 inline vec_SPX EDF(const SPX& f, long d, long verbose=0)
1323 { vec_SPX factors; EDF(factors, f, d, verbose); return factors; }
1324
1325 // Performs equal-degree factorization. f is monic, square-free,
1326 // and all irreducible factors have same degree. d = degree of
1327 // irreducible factors of f
1328
1329 inline void SFCanZass(vec_SPX& factors, const SPX& f, long verbose=0)
1330 {
1331 SPX tmp(f.getMod());
1332 factors.kill(); // remove everything from factors (if any)
1333 if (isGF2(f.getMod())) {
1334 NTL::vec_GF2X fac2;
1335 NTL::SFCanZass(fac2, f.gf2x, verbose);
1336 factors.SetLength(fac2.length(), tmp); // allocate space
1337 for (long i=0; i<factors.length(); i++)
1338 factors[i].gf2x = fac2[i];
1339 } else {
1340 NTL::zz_pPush push(getContext(f.getMod()));
1341 NTL::vec_zz_pX facp;
1342 NTL::SFCanZass(facp, f.zzpx, verbose);
1343 factors.SetLength(facp.length(), tmp); // allocate space
1344 for (long i=0; i<factors.length(); i++)
1345 factors[i].zzpx = facp[i];
1346 }
1347 }
1348 inline vec_SPX SFCanZass(const SPX& f, long verbose=0)
1349 { vec_SPX factors; SFCanZass(factors, f, verbose); return factors; }
1350
1351 // Assumes f is monic and square-free. returns list of factors of f.
1352
1353
1354 inline void CanZass(vec_pair_SPX_long& factors, const SPX& f, long verbose=0)
1355 {
1356 pair_SPX_long tmp = NTL::Pair<SPX,long>(SPX(f.getMod()),0);
1357 factors.kill(); // remove everything from factors (if any)
1358 if (isGF2(f.getMod())) {
1359 NTL::vec_pair_GF2X_long fac2;
1360 NTL::CanZass(fac2, f.gf2x, verbose);
1361 factors.SetLength(fac2.length(), tmp); // allocate space
1362 for (long i=0; i<factors.length(); i++) {
1363 factors[i].a.gf2x = fac2[i].a;
1364 factors[i].b = fac2[i].b;
1365 }
1366 } else {
1367 NTL::zz_pPush push(getContext(f.getMod()));
1368 NTL::vec_pair_zz_pX_long facp;
1369 NTL::CanZass(facp, f.zzpx, verbose);
1370 factors.SetLength(facp.length(), tmp); // allocate space
1371 for (long i=0; i<factors.length(); i++) {
1372 factors[i].a.zzpx = facp[i].a;
1373 factors[i].b = facp[i].b;
1374 }
1375 }
1376 }
1377 inline vec_pair_SPX_long CanZass(const SPX& f, long verbose=0)
1378 { vec_pair_SPX_long factors; CanZass(factors, f, verbose); return factors; }
1379
1380 // returns a list of factors, with multiplicities. f must be monic.
1381 // Calls SquareFreeDecomp and SFCanZass.
1382
1383
mul(SPX & f,const vec_pair_SPX_long & v,const SPmodulus & mod)1384 inline void mul(SPX& f, const vec_pair_SPX_long& v, const SPmodulus& mod)
1385 {
1386 f.resetMod(mod);
1387 if (isGF2(f.getMod())) {
1388 NTL::vec_pair_GF2X_long v2;
1389 v2.SetLength(v.length());
1390 for (long i=0; i<v2.length(); i++) {
1391 v2[i].a = v[i].a.gf2x;
1392 v2[i].b = v[i].b;
1393 }
1394 NTL::mul(f.gf2x, v2);
1395 } else {
1396 NTL::zz_pPush push(getContext(f.getMod()));
1397 NTL::vec_pair_zz_pX_long vp;
1398 vp.SetLength(v.length());
1399 for (long i=0; i<vp.length(); i++) {
1400 vp[i].a = v[i].a.zzpx;
1401 vp[i].b = v[i].b;
1402 }
1403 NTL::mul(f.zzpx, vp);
1404 }
1405 }
mul(const vec_pair_SPX_long & v,const SPmodulus & mod)1406 inline SPX mul(const vec_pair_SPX_long& v, const SPmodulus& mod)
1407 { SPX f; mul(f,v,mod); return f; }
1408
1409 // multiplies polynomials, with multiplicities
1410
1411
1412 /**************************************************************************\
1413 Irreducible Polynomials
1414 \**************************************************************************/
1415
IterIrredTest(const SPX & f)1416 inline bool IterIrredTest(const SPX& f)
1417 {
1418 if (isGF2(f.getMod()))
1419 return NTL::IterIrredTest(f.gf2x);
1420 else {
1421 NTL::zz_pPush push(getContext(f.getMod()));
1422 return NTL::IterIrredTest(f.zzpx);
1423 }
1424 }
1425
1426 // performs an iterative deterministic irreducibility test, based on
1427 // DDF. Fast on average (when f has a small factor).
1428
1429 /**
1430 inline void BuildSparseIrred(SPX& f, long n, const SPmodulus& mod)
1431 {
1432 f.resetMod(mod);
1433 if (isGF2(mod))
1434 NTL::BuildSparseIrred(f.gf2x, n);
1435 else {
1436 NTL::zz_pPush push(getContext(f.getMod()));
1437 NTL::BuildSparseIrred(f.zzpx, n);
1438 }
1439 }
1440 inline SPX BuildSparseIrred_SPX(long n, const SPmodulus& mod)
1441 { SPX f; BuildSparseIrred(f,n,mod); return f; }
1442 **/
1443
1444 // Builds a monic irreducible polynomial of degree n.
1445 // If there is an irreducible trinomial X^n + X^k + 1,
1446 // then the one with minimal k is chosen.
1447 // Otherwise, if there is an irreducible pentanomial
1448 // X^n + X^k3 + X^k2 + x^k1 + 1, then the one with minimal
1449 // k3 is chosen (minimizing first k2 and then k1).
1450 // Otherwise, if there is niether an irreducible trinomial
1451 // or pentanomial, the routine result from BuildIrred (see below)
1452 // is chosen---this is probably only of academic interest,
1453 // since it a reasonable, but unproved, conjecture that they
1454 // exist for every n > 1.
1455
1456 // For n <= 2048, the polynomial is constructed
1457 // by table lookup in a pre-computed table.
1458
1459 // The SPXModulus data structure and routines (and indirectly GF2E)
1460 // are optimized to deal with the output from BuildSparseIrred.
1461
BuildIrred(SPX & f,long n,const SPmodulus & mod)1462 inline void BuildIrred(SPX& f, long n, const SPmodulus& mod)
1463 {
1464 f.resetMod(mod);
1465 if (isGF2(mod))
1466 NTL::BuildIrred(f.gf2x, n);
1467 else {
1468 NTL::zz_pPush push(getContext(f.getMod()));
1469 NTL::BuildIrred(f.zzpx, n);
1470 }
1471 }
1472
BuildIrred_SPX(long n,const SPmodulus & mod)1473 inline SPX BuildIrred_SPX(long n, const SPmodulus& mod)
1474 { SPX f; BuildIrred(f,n,mod); return f; }
1475
1476 // Build a monic irreducible poly of degree n. The polynomial
1477 // constructed is "canonical" in the sense that it is of the form
1478 // f=X^n + g, where the bits of g are the those of the smallest
1479 // non-negative integer that make f irreducible.
1480
1481 // The SPXModulus data structure and routines (and indirectly GF2E)
1482 // are optimized to deal with the output from BuildIrred.
1483
1484 // Note that the output from BuildSparseIrred will generally yield
1485 // a "better" representation (in terms of efficiency) for
1486 // GF(2^n) than the output from BuildIrred.
1487
1488
1489
BuildRandomIrred(SPX & f,const SPX & g)1490 inline void BuildRandomIrred(SPX& f, const SPX& g)
1491 {
1492 f.resetMod(g.getMod());
1493 if (isGF2(g.getMod()))
1494 NTL::BuildRandomIrred(f.gf2x, g.gf2x);
1495 else {
1496 NTL::zz_pPush push(getContext(g.getMod()));
1497 NTL::BuildRandomIrred(f.zzpx, g.zzpx);
1498 }
1499 }
1500
BuildRandomIrred(const SPX & g)1501 inline SPX BuildRandomIrred(const SPX& g)
1502 { SPX f; BuildRandomIrred(f, g); return f; }
1503
1504 // g is a monic irreducible polynomial. Constructs a random monic
1505 // irreducible polynomial f of the same degree.
1506
1507 #endif // #ifdef _HELIB_SPX_H_
1508