source: git/ntl/src/GF2X1.c @ 6ce030f

spielwiese
Last change on this file since 6ce030f was 287cc8, checked in by Hans Schönemann <hannes@…>, 14 years ago
ntl 5.5.2 git-svn-id: file:///usr/local/Singular/svn/trunk@12402 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 68.6 KB
Line 
1
2
3#include <NTL/GF2X.h>
4#include <NTL/vec_long.h>
5
6#include <NTL/new.h>
7
8#if (defined(NTL_WIZARD_HACK) && defined(NTL_GF2X_LIB))
9#undef NTL_GF2X_LIB
10#endif
11
12
13// some crossover points...choice depends
14// if we are using the gf2x lib or not
15
16#ifdef NTL_GF2X_LIB
17
18#define NTL_GF2X_GCD_CROSSOVER (400L*NTL_BITS_PER_LONG)
19#define NTL_GF2X_HalfGCD_CROSSOVER (6L*NTL_BITS_PER_LONG)
20#define NTL_GF2X_BERMASS_CROSSOVER (200L*NTL_BITS_PER_LONG)
21
22#else
23
24#define NTL_GF2X_GCD_CROSSOVER (900L*NTL_BITS_PER_LONG)
25#define NTL_GF2X_HalfGCD_CROSSOVER (6L*NTL_BITS_PER_LONG)
26#define NTL_GF2X_BERMASS_CROSSOVER (450L*NTL_BITS_PER_LONG)
27
28#endif
29
30
31NTL_START_IMPL
32
33/********** data structures for accesss to GF2XRegisters ************/
34
35static GF2X GF2XRegisterVec[32];
36static long GF2XRegisterTop = 0;
37
38
39class GF2XRegisterType {
40public:
41
42GF2X *xrep;
43
44GF2XRegisterType()
45{ xrep = &GF2XRegisterVec[GF2XRegisterTop]; GF2XRegisterTop++; }
46
47~GF2XRegisterType()
48{ xrep->xrep.release();
49  GF2XRegisterTop--; }
50
51operator GF2X& () { return *xrep; }
52
53};
54
55#define GF2XRegister(a) GF2XRegisterType GF2XReg__ ## a ; GF2X& a = GF2XReg__ ## a
56
57
58
59
60
61
62
63static vec_GF2X stab;  // used by PlainDivRem and PlainRem
64
65static WordVector GF2X_rembuf;
66
67
68void PlainDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b)
69{
70   long da, sa, posa, db, sb, posb, dq, sq, posq;
71
72   da = deg(a);
73   db = deg(b);
74
75   if (db < 0) Error("GF2X: division by zero");
76
77   if (da < db) {
78      r = a;
79      clear(q);
80      return;
81   }
82
83   sa = a.xrep.length();
84   posa = da - NTL_BITS_PER_LONG*(sa-1);
85   sb = b.xrep.length();
86   posb = db - NTL_BITS_PER_LONG*(sb-1);
87
88   dq = da - db;
89   sq = dq/NTL_BITS_PER_LONG + 1;
90   posq = dq - NTL_BITS_PER_LONG*(sq-1);
91
92   _ntl_ulong *ap;
93   if (&r == &a)
94      ap = r.xrep.elts();
95   else {
96      GF2X_rembuf = a.xrep;
97      ap = GF2X_rembuf.elts();
98   }
99
100   stab.SetLength(NTL_BITS_PER_LONG);
101   long i;
102
103   stab[posb] = b;
104   for (i = 1; i <= min(dq, NTL_BITS_PER_LONG-1); i++)
105      MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG],
106             stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]);
107
108   _ntl_ulong *stab_ptr[NTL_BITS_PER_LONG];
109   long stab_cnt[NTL_BITS_PER_LONG];
110
111   for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) {
112      WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep;
113      long k = st.length();
114      stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1];
115      stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1;
116   }
117
118   q.xrep.SetLength(sq);
119   _ntl_ulong *qp = q.xrep.elts();
120   for (i = 0; i < sq; i++)
121      qp[i] = 0;
122
123   _ntl_ulong *atop = &ap[sa-1];
124   _ntl_ulong *qtop = &qp[sq-1];
125   _ntl_ulong *stab_top;
126
127   while (1) {
128      if (atop[0] & (1UL << posa)) {
129         qtop[0] |= (1UL << posq);
130         stab_top = stab_ptr[posa];
131         for (i = stab_cnt[posa]; i <= 0; i++)
132            atop[i] ^= stab_top[i];
133      }
134
135      da--;
136      if (da < db) break;
137
138      posa--;
139      if (posa < 0) {
140         posa = NTL_BITS_PER_LONG-1;
141         atop--;
142      }
143
144      posq--;
145      if (posq < 0) {
146         posq = NTL_BITS_PER_LONG-1;
147         qtop--;
148      }
149   }
150
151   if (posb == 0) sb--;
152
153   r.xrep.SetLength(sb);
154   if (&r != &a) {
155      _ntl_ulong *rp = r.xrep.elts();
156      for (i = 0; i < sb; i++)
157         rp[i] = ap[i];
158   }
159   r.normalize();
160
161   GF2X_rembuf.release();
162   for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) {
163      WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep;
164      st.release();
165   }
166}
167
168
169
170void PlainDiv(GF2X& q, const GF2X& a, const GF2X& b)
171{
172   GF2XRegister(r);
173   PlainDivRem(q, r, a, b);
174}
175
176
177void PlainRem(GF2X& r, const GF2X& a, const GF2X& b)
178{
179   long da, sa, posa, db, sb, posb;
180
181   da = deg(a);
182   db = deg(b);
183
184   if (db < 0) Error("GF2X: division by zero");
185
186   if (da < db) {
187      r = a;
188      return;
189   }
190
191   sa = a.xrep.length();
192   posa = da - NTL_BITS_PER_LONG*(sa-1);
193   sb = b.xrep.length();
194   posb = db - NTL_BITS_PER_LONG*(sb-1);
195
196   _ntl_ulong *ap;
197   if (&r == &a)
198      ap = r.xrep.elts();
199   else {
200      GF2X_rembuf = a.xrep;
201      ap = GF2X_rembuf.elts();
202   }
203
204   stab.SetLength(NTL_BITS_PER_LONG);
205   long i;
206
207   stab[posb] = b;
208   for (i = 1; i <= min(da-db, NTL_BITS_PER_LONG-1); i++)
209      MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG],
210             stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]);
211
212   _ntl_ulong *stab_ptr[NTL_BITS_PER_LONG];
213   long stab_cnt[NTL_BITS_PER_LONG];
214
215   for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) {
216      WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep;
217      long k = st.length();
218      stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1];
219      stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1;
220   }
221
222
223   _ntl_ulong *atop = &ap[sa-1];
224   _ntl_ulong *stab_top;
225
226   while (1) {
227      if (atop[0] & (1UL << posa)) {
228         stab_top = stab_ptr[posa];
229         for (i = stab_cnt[posa]; i <= 0; i++)
230            atop[i] ^= stab_top[i];
231      }
232
233      da--;
234      if (da < db) break;
235
236      posa--;
237      if (posa < 0) {
238         posa = NTL_BITS_PER_LONG-1;
239         atop--;
240      }
241   }
242
243   if (posb == 0) sb--;
244
245   r.xrep.SetLength(sb);
246   if (&r != &a) {
247      _ntl_ulong *rp = r.xrep.elts();
248      for (i = 0; i < sb; i++)
249         rp[i] = ap[i];
250   }
251   r.normalize();
252
253   GF2X_rembuf.release();
254   for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) {
255      WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep;
256      st.release();
257   }
258}
259
260#define MASK8 ((1UL << 8)-1UL)
261
262static _ntl_ulong invtab[128] = {
2631UL, 255UL, 85UL, 219UL, 73UL, 151UL, 157UL, 51UL, 17UL, 175UL,
26469UL, 139UL, 89UL, 199UL, 141UL, 99UL, 33UL, 95UL, 117UL, 123UL,
265105UL, 55UL, 189UL, 147UL, 49UL, 15UL, 101UL, 43UL, 121UL, 103UL,
266173UL, 195UL, 65UL, 191UL, 21UL, 155UL, 9UL, 215UL, 221UL, 115UL,
26781UL, 239UL, 5UL, 203UL, 25UL, 135UL, 205UL, 35UL, 97UL, 31UL,
26853UL, 59UL, 41UL, 119UL, 253UL, 211UL, 113UL, 79UL, 37UL, 107UL,
26957UL, 39UL, 237UL, 131UL, 129UL, 127UL, 213UL, 91UL, 201UL, 23UL,
27029UL, 179UL, 145UL, 47UL, 197UL, 11UL, 217UL, 71UL, 13UL, 227UL,
271161UL, 223UL, 245UL, 251UL, 233UL, 183UL, 61UL, 19UL, 177UL, 143UL,
272229UL, 171UL, 249UL, 231UL, 45UL, 67UL, 193UL, 63UL, 149UL, 27UL,
273137UL, 87UL, 93UL, 243UL, 209UL, 111UL, 133UL, 75UL, 153UL, 7UL,
27477UL, 163UL, 225UL, 159UL, 181UL, 187UL, 169UL, 247UL, 125UL, 83UL,
275241UL, 207UL, 165UL, 235UL, 185UL, 167UL, 109UL, 3UL };
276
277
278
279void NewtonInvTrunc(GF2X& c, const GF2X& a, long e)
280{
281   if (e == 1) {
282      set(c);
283      return;
284   }
285
286   static vec_long E;
287   E.SetLength(0);
288   append(E, e);
289   while (e > 8) {
290      e = (e+1)/2;
291      append(E, e);
292   }
293
294   long L = E.length();
295
296   GF2XRegister(g);
297   GF2XRegister(g0);
298   GF2XRegister(g1);
299   GF2XRegister(g2);
300
301   g.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1);
302   g0.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1);
303   g1.xrep.SetMaxLength(((3*E[0]+1)/2+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG+1);
304   g2.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1);
305
306   g.xrep.SetLength(1);
307   g.xrep[0] = invtab[(a.xrep[0] & MASK8) >> 1] & ((1UL<<e)-1UL);
308
309   long i;
310
311   for (i = L-1; i > 0; i--) {
312      // lift from E[i] to E[i-1]
313
314      long k = E[i];
315      long l = E[i-1]-E[i];
316
317      trunc(g0, a, k+l);
318
319      mul(g1, g0, g);
320      RightShift(g1, g1, k);
321      trunc(g1, g1, l);
322
323      mul(g2, g1, g);
324      trunc(g2, g2, l);
325      LeftShift(g2, g2, k);
326
327      add(g, g, g2);
328   }
329
330   c = g;
331}
332
333void InvTrunc(GF2X& c, const GF2X& a, long e)
334{
335   if (ConstTerm(a) == 0 || e < 0)
336      Error("inv: bad args");
337
338   if (NTL_OVERFLOW(e, 1, 0))
339      Error("overflow in InvTrunc");
340
341   if (e == 0) {
342      clear(c);
343      return;
344   }
345
346   NewtonInvTrunc(c, a, e);
347}
348
349
350
351static
352long weight1(_ntl_ulong a)
353{
354   long res = 0;
355   while (a) {
356      if (a & 1) res ++;
357      a >>= 1;
358   }
359   return res;
360}
361
362long weight(const GF2X& a)
363{
364   long wlen = a.xrep.length();
365   long res = 0;
366   long i;
367   for (i = 0; i < wlen; i++)
368      res += weight1(a.xrep[i]);
369
370   return res;
371}
372
373
374
375static
376void SparsityCheck(const GF2X& f, long& k3, long& k2, long& k1)
377{
378   long w = weight(f);
379   if (w != 3 && w != 5) {
380      k3 = 0;
381      return;
382   }
383
384   if (ConstTerm(f) != 1) {
385      k3 = 0;
386      return;
387   }
388
389   GF2X g = f;
390
391   long n = deg(f);
392
393   trunc(g, g, n);
394
395   long t = deg(g);
396
397   if (n-t < NTL_BITS_PER_LONG || t > (n+1)/2) {
398      k3 = 0;
399      return;
400   }
401
402   if (w == 3) {
403      k3 = t;
404      k2 = 0;
405      return;
406   }
407
408   k3 = t;
409   trunc(g, g, t);
410   t = deg(g);
411   k2 = t;
412   trunc(g, g, t);
413   t = deg(g);
414   k1 = t;
415}
416
417
418
419
420const long GF2X_MOD_PLAIN = 0;
421const long GF2X_MOD_MUL = 1;
422const long GF2X_MOD_SPECIAL = 2;
423const long GF2X_MOD_TRI = 3;
424const long GF2X_MOD_PENT = 4;
425
426void build(GF2XModulus& F, const GF2X& f)
427{
428   long n = deg(f);
429   long i;
430
431   if (n <= 0) Error("build(GF2XModulus,GF2X): deg(f) <= 0");
432
433   F.tracevec.SetLength(0);
434
435   F.f = f;
436   F.n = n;
437   F.sn = f.xrep.length();
438
439   long sb = F.sn;
440   long posb = n - NTL_BITS_PER_LONG*(sb-1);
441
442   F.posn = posb;
443
444   if (F.posn > 0) {
445      F.size = F.sn;
446      F.msk = (1UL << F.posn) - 1UL;
447   }
448   else {
449      F.size = F.sn-1;
450      F.msk = ~0UL;
451   }
452
453   SparsityCheck(f, F.k3, F.k2, F.k1);
454
455   if (F.k3 != 0) {
456      if (F.k2 == 0)
457         F.method = GF2X_MOD_TRI;
458      else
459         F.method = GF2X_MOD_PENT;
460
461      return;
462   }
463
464
465   GF2X f0;
466   trunc(f0, f, n);
467   long deg_f0 = deg(f0);
468
469   if (F.sn > 1 && deg_f0 < NTL_BITS_PER_LONG
470       && deg_f0 >= NTL_BITS_PER_LONG/2) {
471      if (F.size >= 6)
472         F.method = GF2X_MOD_MUL;
473      else
474         F.method = GF2X_MOD_SPECIAL;
475   }
476   else if (F.sn > 1 && deg_f0 < NTL_BITS_PER_LONG/2) {
477      if (F.size >= 4)
478         F.method = GF2X_MOD_MUL;
479      else
480         F.method = GF2X_MOD_SPECIAL;
481   }
482   else if (F.size >= 8)
483      F.method = GF2X_MOD_MUL;
484   else
485      F.method = GF2X_MOD_PLAIN;
486
487
488   if (F.method == GF2X_MOD_SPECIAL) {
489      if (!F.stab_cnt) F.stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG];
490      long *stab_cnt = F.stab_cnt;
491      if (!stab_cnt) Error("out of memory");
492
493      if (!F.stab1) F.stab1 = NTL_NEW_OP _ntl_ulong[2*NTL_BITS_PER_LONG];
494      _ntl_ulong *stab1 = F.stab1;
495      if (!stab1) Error("out of memory");
496
497      stab1[posb<<1] = f.xrep[0];
498      stab1[(posb<<1)+1] = 0;
499
500      stab_cnt[posb] = -sb+1;
501
502      for (i = 1; i < NTL_BITS_PER_LONG; i++) {
503         long kk0 = ((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG;
504         long kk1 = ((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG;
505
506         stab1[kk1<<1] = stab1[kk0<<1] << 1;
507         stab1[(kk1<<1)+1] = (stab1[(kk0<<1)+1] << 1)
508                          | (stab1[kk0<<1] >> (NTL_BITS_PER_LONG-1));
509
510         if (kk1 < posb)
511            stab_cnt[kk1] = -sb;
512         else
513            stab_cnt[kk1] = -sb+1;
514      }
515   }
516   else if (F.method == GF2X_MOD_PLAIN) {
517      vec_GF2X& stab = F.stab;
518      stab.SetLength(NTL_BITS_PER_LONG);
519
520
521      if (!F.stab_ptr) F.stab_ptr = NTL_NEW_OP _ntl_ulong_ptr[NTL_BITS_PER_LONG];
522      _ntl_ulong **stab_ptr = F.stab_ptr;
523      if (!stab_ptr) Error("out of memory");
524
525      if (!F.stab_cnt) F.stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG];
526      long *stab_cnt = F.stab_cnt;
527      if (!stab_cnt) Error("out of memory");
528
529
530      stab[posb] = f;
531      for (i = 1; i < NTL_BITS_PER_LONG; i++)
532         MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG],
533                stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]);
534
535
536      for (i = 0; i < NTL_BITS_PER_LONG; i++) {
537         WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep;
538         long k = st.length();
539         stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1];
540         stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1;
541      }
542   }
543   else if (F.method == GF2X_MOD_MUL) {
544      GF2X P1, P2;
545
546      CopyReverse(P1, f, n);
547      InvTrunc(P2, P1, n-1);
548      CopyReverse(P1, P2, n-2);
549      trunc(F.h0, P1, n-2);
550      F.f0 = f0;
551   }
552}
553
554GF2XModulus::GF2XModulus()
555{
556   n = -1;
557   method = GF2X_MOD_PLAIN;
558   stab_ptr = 0;
559   stab_cnt = 0;
560   stab1 = 0;
561}
562
563
564// The following two routines are total spaghetti...unfortunately,
565// cleaning them up would require too much re-coding in other
566// places.
567
568GF2XModulus::GF2XModulus(const GF2XModulus& F) :
569   f(F.f), n(F.n), sn(F.sn), posn(F.posn), k3(F.k3), k2(F.k2), k1(F.k1),
570   size(F.size),
571   msk(F.msk), method(F.method), stab(F.stab), h0(F.h0), f0(F.f0),
572   stab_cnt(0), stab_ptr(0), stab1(0), tracevec(F.tracevec)
573{
574   if (method == GF2X_MOD_SPECIAL) {
575      long i;
576      stab1 = NTL_NEW_OP _ntl_ulong[2*NTL_BITS_PER_LONG];
577      if (!stab1) Error("GF2XModulus: out of memory");
578      for (i = 0; i < 2*NTL_BITS_PER_LONG; i++)
579         stab1[i] = F.stab1[i];
580      stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG];
581      if (!stab_cnt) Error("GF2XModulus: out of memory");
582      for (i = 0; i < NTL_BITS_PER_LONG; i++)
583         stab_cnt[i] = F.stab_cnt[i];
584   }
585   else if (method == GF2X_MOD_PLAIN) {
586      long i;
587
588      if (F.stab_cnt) {
589         stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG];
590         if (!stab_cnt) Error("GF2XModulus: out of memory");
591         for (i = 0; i < NTL_BITS_PER_LONG; i++)
592            stab_cnt[i] = F.stab_cnt[i];
593      }
594
595      if (F.stab_ptr) {
596         stab_ptr = NTL_NEW_OP _ntl_ulong_ptr[NTL_BITS_PER_LONG];
597         if (!stab_ptr) Error("GF2XModulus: out of memory");
598
599         for (i = 0; i < NTL_BITS_PER_LONG; i++) {
600            WordVector& st = stab[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG].xrep;
601            long k = st.length();
602            stab_ptr[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = &st[k-1];
603            stab_cnt[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = -k+1;
604         }
605      }
606   }
607}
608
609GF2XModulus& GF2XModulus::operator=(const GF2XModulus& F)
610{
611   if (this == &F) return *this;
612
613   f=F.f; n=F.n; sn=F.sn; posn=F.posn;
614   k3=F.k3; k2=F.k2; k1=F.k1;
615   size=F.size;
616   msk=F.msk; method=F.method; stab=F.stab; h0=F.h0; f0 = F.f0;
617   tracevec=F.tracevec;
618
619   if (method == GF2X_MOD_SPECIAL) {
620      long i;
621      if (!stab1) stab1 = NTL_NEW_OP _ntl_ulong[2*NTL_BITS_PER_LONG];
622      if (!stab1) Error("GF2XModulus: out of memory");
623      for (i = 0; i < 2*NTL_BITS_PER_LONG; i++)
624         stab1[i] = F.stab1[i];
625      if (!stab_cnt) stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG];
626      if (!stab_cnt) Error("GF2XModulus: out of memory");
627      for (i = 0; i < NTL_BITS_PER_LONG; i++)
628         stab_cnt[i] = F.stab_cnt[i];
629   }
630   else if (method == GF2X_MOD_PLAIN) {
631      long i;
632
633      if (F.stab_cnt) {
634         if (!stab_cnt) stab_cnt = NTL_NEW_OP long[NTL_BITS_PER_LONG];
635         if (!stab_cnt) Error("GF2XModulus: out of memory");
636         for (i = 0; i < NTL_BITS_PER_LONG; i++)
637            stab_cnt[i] = F.stab_cnt[i];
638      }
639
640      if (F.stab_ptr) {
641         if (!stab_ptr) stab_ptr = NTL_NEW_OP _ntl_ulong_ptr[NTL_BITS_PER_LONG];
642         if (!stab_ptr) Error("GF2XModulus: out of memory");
643
644         for (i = 0; i < NTL_BITS_PER_LONG; i++) {
645            WordVector& st = stab[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG].xrep;
646            long k = st.length();
647            stab_ptr[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = &st[k-1];
648            stab_cnt[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = -k+1;
649         }
650      }
651   }
652
653   return *this;
654}
655
656
657
658GF2XModulus::~GF2XModulus()
659{
660   delete [] stab_ptr;
661   delete [] stab_cnt;
662   delete [] stab1;
663}
664
665
666
667GF2XModulus::GF2XModulus(const GF2X& ff)
668{
669   n = -1;
670   method = GF2X_MOD_PLAIN;
671   stab_ptr = 0;
672   stab_cnt = 0;
673   stab1 = 0;
674
675   build(*this, ff);
676}
677
678
679
680
681
682void UseMulRem21(GF2X& r, const GF2X& a, const GF2XModulus& F)
683{
684   GF2XRegister(P1);
685   GF2XRegister(P2);
686
687   RightShift(P1, a, F.n);
688   mul(P2, P1, F.h0);
689   RightShift(P2, P2, F.n-2);
690   add(P2, P2, P1);
691   mul(P1, P2, F.f0);
692   trunc(P1, P1, F.n);
693   trunc(r, a, F.n);
694   add(r, r, P1);
695}
696
697void UseMulDivRem21(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F)
698{
699   GF2XRegister(P1);
700   GF2XRegister(P2);
701
702   RightShift(P1, a, F.n);
703   mul(P2, P1, F.h0);
704   RightShift(P2, P2, F.n-2);
705   add(P2, P2, P1);
706   mul(P1, P2, F.f0);
707   trunc(P1, P1, F.n);
708   trunc(r, a, F.n);
709   add(r, r, P1);
710   q = P2;
711}
712
713void UseMulDiv21(GF2X& q, const GF2X& a, const GF2XModulus& F)
714{
715   GF2XRegister(P1);
716   GF2XRegister(P2);
717
718   RightShift(P1, a, F.n);
719   mul(P2, P1, F.h0);
720   RightShift(P2, P2, F.n-2);
721   add(P2, P2, P1);
722   q = P2;
723}
724
725
726void UseMulRemX1(GF2X& r, const GF2X& aa, const GF2XModulus& F)
727{
728   GF2XRegister(buf);
729   GF2XRegister(tmp);
730   GF2XRegister(a);
731
732   clear(buf);
733   a = aa;
734
735   long n = F.n;
736   long a_len = deg(a) + 1;
737
738   while (a_len > 0) {
739      long old_buf_len = deg(buf) + 1;
740      long amt = min(2*n-1-old_buf_len, a_len);
741
742      LeftShift(buf, buf, amt);
743      RightShift(tmp, a, a_len-amt);
744      add(buf, buf, tmp);
745      trunc(a, a, a_len-amt);
746
747      UseMulRem21(buf, buf, F);
748      a_len -= amt;
749   }
750
751   r = buf;
752}
753
754
755void UseMulDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, const GF2XModulus& F)
756{
757   GF2XRegister(buf);
758   GF2XRegister(tmp);
759   GF2XRegister(a);
760   GF2XRegister(qq);
761   GF2XRegister(qbuf);
762
763   clear(buf);
764   a = aa;
765   clear(qq);
766
767   long n = F.n;
768   long a_len = deg(a) + 1;
769
770   while (a_len > 0) {
771      long old_buf_len = deg(buf) + 1;
772      long amt = min(2*n-1-old_buf_len, a_len);
773
774      LeftShift(buf, buf, amt);
775      RightShift(tmp, a, a_len-amt);
776      add(buf, buf, tmp);
777      trunc(a, a, a_len-amt);
778
779      UseMulDivRem21(qbuf, buf, buf, F);
780      a_len -= amt;
781
782      ShiftAdd(qq, qbuf, a_len);
783   }
784
785   r = buf;
786   q = qq;
787}
788
789
790void UseMulDivX1(GF2X& q, const GF2X& aa, const GF2XModulus& F)
791{
792   GF2XRegister(buf);
793   GF2XRegister(tmp);
794   GF2XRegister(a);
795   GF2XRegister(qq);
796   GF2XRegister(qbuf);
797
798   clear(buf);
799   a = aa;
800   clear(qq);
801
802   long n = F.n;
803   long a_len = deg(a) + 1;
804
805   while (a_len > 0) {
806      long old_buf_len = deg(buf) + 1;
807      long amt = min(2*n-1-old_buf_len, a_len);
808
809      LeftShift(buf, buf, amt);
810      RightShift(tmp, a, a_len-amt);
811      add(buf, buf, tmp);
812      trunc(a, a, a_len-amt);
813
814      UseMulDivRem21(qbuf, buf, buf, F);
815      a_len -= amt;
816
817      ShiftAdd(qq, qbuf, a_len);
818   }
819
820   q = qq;
821}
822
823static
824void TrinomReduce(GF2X& x, const GF2X& a, long n, long k)
825{
826   long wn = n / NTL_BITS_PER_LONG;
827   long bn = n - wn*NTL_BITS_PER_LONG;
828
829   long wdiff = (n-k)/NTL_BITS_PER_LONG;
830   long bdiff = (n-k) - wdiff*NTL_BITS_PER_LONG;
831
832   long m = a.xrep.length()-1;
833
834   if (wn > m) {
835      x = a;
836      return;
837   }
838
839   GF2XRegister(r);
840
841   r = a;
842
843   _ntl_ulong *p = r.xrep.elts();
844
845   _ntl_ulong *pp;
846
847
848   _ntl_ulong w;
849
850   if (bn == 0) {
851      if (bdiff == 0) {
852         // bn == 0 && bdiff == 0
853
854         while (m >= wn) {
855            w = p[m];
856            p[m-wdiff] ^= w;
857            p[m-wn] ^= w;
858            m--;
859         }
860      }
861      else {
862         // bn == 0 && bdiff != 0
863
864         while (m >= wn) {
865            w = p[m];
866            pp = &p[m-wdiff];
867            *pp ^= (w >> bdiff);
868            *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff));
869            p[m-wn] ^= w;
870            m--;
871         }
872      }
873   }
874   else {
875      if (bdiff == 0) {
876         // bn != 0 && bdiff == 0
877
878         while (m > wn) {
879            w = p[m];
880            p[m-wdiff] ^= w;
881            pp = &p[m-wn];
882            *pp ^= (w >> bn);
883            *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn));
884            m--;
885         }
886
887         w = (p[m] >> bn) << bn;;
888
889         p[m-wdiff] ^= w;
890         p[0] ^= (w >> bn);
891
892         p[m] &= ((1UL<<bn)-1UL);
893      }
894      else {
895         // bn != 0 && bdiff != 0
896
897         while (m > wn) {
898            w = p[m];
899            pp = &p[m-wdiff];
900            *pp ^= (w >> bdiff);;
901            *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff));
902            pp = &p[m-wn];
903            *pp ^= (w >> bn);
904            *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn));
905            m--;
906         }
907
908         w = (p[m] >> bn) << bn;;
909
910         p[m-wdiff] ^= (w >> bdiff);
911         if (m-wdiff-1 >= 0) p[m-wdiff-1] ^= (w << (NTL_BITS_PER_LONG-bdiff));
912         p[0] ^= (w >> bn);
913         p[m] &= ((1UL<<bn)-1UL);
914      }
915   }
916
917   if (bn == 0)
918      wn--;
919
920   while (wn >= 0 && p[wn] == 0)
921      wn--;
922
923   r.xrep.QuickSetLength(wn+1);
924
925   x = r;
926}
927
928static
929void PentReduce(GF2X& x, const GF2X& a, long n, long k3, long k2, long k1)
930{
931   long wn = n / NTL_BITS_PER_LONG;
932   long bn = n - wn*NTL_BITS_PER_LONG;
933
934   long m = a.xrep.length()-1;
935
936   if (wn > m) {
937      x = a;
938      return;
939   }
940
941   long wdiff1 = (n-k1)/NTL_BITS_PER_LONG;
942   long bdiff1 = (n-k1) - wdiff1*NTL_BITS_PER_LONG;
943
944   long wdiff2 = (n-k2)/NTL_BITS_PER_LONG;
945   long bdiff2 = (n-k2) - wdiff2*NTL_BITS_PER_LONG;
946
947   long wdiff3 = (n-k3)/NTL_BITS_PER_LONG;
948   long bdiff3 = (n-k3) - wdiff3*NTL_BITS_PER_LONG;
949
950   GF2XRegister(r);
951   r = a;
952
953   _ntl_ulong *p = r.xrep.elts();
954
955   _ntl_ulong *pp;
956
957   _ntl_ulong w;
958
959   while (m > wn) {
960      w = p[m];
961
962      if (bn == 0)
963         p[m-wn] ^= w;
964      else {
965         pp = &p[m-wn];
966         *pp ^= (w >> bn);
967         *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn));
968      }
969
970      if (bdiff1 == 0)
971         p[m-wdiff1] ^= w;
972      else {
973         pp = &p[m-wdiff1];
974         *pp ^= (w >> bdiff1);
975         *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff1));
976      }
977
978      if (bdiff2 == 0)
979         p[m-wdiff2] ^= w;
980      else {
981         pp = &p[m-wdiff2];
982         *pp ^= (w >> bdiff2);
983         *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff2));
984      }
985
986      if (bdiff3 == 0)
987         p[m-wdiff3] ^= w;
988      else {
989         pp = &p[m-wdiff3];
990         *pp ^= (w >> bdiff3);
991         *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff3));
992      }
993
994      m--;
995   }
996
997   w = (p[m] >> bn) << bn;
998
999   p[0] ^= (w >> bn);
1000
1001   if (bdiff1 == 0)
1002      p[m-wdiff1] ^= w;
1003   else {
1004      p[m-wdiff1] ^= (w >> bdiff1);
1005      if (m-wdiff1-1 >= 0) p[m-wdiff1-1] ^= (w << (NTL_BITS_PER_LONG-bdiff1));
1006   }
1007
1008   if (bdiff2 == 0)
1009      p[m-wdiff2] ^= w;
1010   else {
1011      p[m-wdiff2] ^= (w >> bdiff2);
1012      if (m-wdiff2-1 >= 0) p[m-wdiff2-1] ^= (w << (NTL_BITS_PER_LONG-bdiff2));
1013   }
1014
1015   if (bdiff3 == 0)
1016      p[m-wdiff3] ^= w;
1017   else {
1018      p[m-wdiff3] ^= (w >> bdiff3);
1019      if (m-wdiff3-1 >= 0) p[m-wdiff3-1] ^= (w << (NTL_BITS_PER_LONG-bdiff3));
1020   }
1021
1022   if (bn != 0)
1023      p[m] &= ((1UL<<bn)-1UL);
1024
1025
1026   if (bn == 0)
1027      wn--;
1028
1029   while (wn >= 0 && p[wn] == 0)
1030      wn--;
1031
1032   r.xrep.QuickSetLength(wn+1);
1033
1034   x = r;
1035}
1036
1037
1038
1039
1040static
1041void RightShiftAdd(GF2X& c, const GF2X& a, long n)
1042{
1043   if (n < 0) {
1044      Error("RightShiftAdd: negative shamt");
1045   }
1046
1047   if (n == 0) {
1048      add(c, c, a);
1049      return;
1050   }
1051
1052   long sa = a.xrep.length();
1053   long wn = n/NTL_BITS_PER_LONG;
1054   long bn = n - wn*NTL_BITS_PER_LONG;
1055
1056   if (wn >= sa) {
1057      return;
1058   }
1059
1060   long sc = c.xrep.length();
1061   long i;
1062
1063   if (sa-wn > sc)
1064      c.xrep.SetLength(sa-wn);
1065
1066   _ntl_ulong *cp = c.xrep.elts();
1067   const _ntl_ulong *ap = a.xrep.elts();
1068
1069   for (i = sc; i < sa-wn; i++)
1070      cp[i] = 0;
1071
1072
1073   if (bn == 0) {
1074      for (i = 0; i < sa-wn; i++)
1075         cp[i] ^= ap[i+wn];
1076   }
1077   else {
1078      for (i = 0; i < sa-wn-1; i++)
1079         cp[i] ^= (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn));
1080
1081      cp[sa-wn-1] ^= ap[sa-1] >> bn;
1082   }
1083
1084   c.normalize();
1085}
1086
1087
1088static
1089void TriDiv21(GF2X& q, const GF2X& a, long n, long k)
1090{
1091   GF2XRegister(P1);
1092
1093   RightShift(P1, a, n);
1094   if (k != 1)
1095      RightShiftAdd(P1, P1, n-k);
1096
1097   q = P1;
1098}
1099
1100static
1101void TriDivRem21(GF2X& q, GF2X& r, const GF2X& a, long n, long k)
1102{
1103   GF2XRegister(Q);
1104   TriDiv21(Q, a, n, k);
1105   TrinomReduce(r, a, n, k);
1106   q = Q;
1107}
1108
1109
1110static
1111void PentDiv21(GF2X& q, const GF2X& a, long n, long k3, long k2, long k1)
1112{
1113   if (deg(a) < n) {
1114      clear(q);
1115      return;
1116   }
1117
1118   GF2XRegister(P1);
1119   GF2XRegister(P2);
1120
1121   RightShift(P1, a, n);
1122
1123   RightShift(P2, P1, n-k3);
1124   RightShiftAdd(P2, P1, n-k2);
1125   if (k1 != 1) {
1126      RightShiftAdd(P2, P1, n-k1);
1127   }
1128
1129   add(P2, P2, P1);
1130
1131   q = P2;
1132}
1133
1134static
1135void PentDivRem21(GF2X& q, GF2X& r, const GF2X& a, long n,
1136                  long k3, long k2, long k1)
1137{
1138   GF2XRegister(Q);
1139   PentDiv21(Q, a, n, k3, k2, k1);
1140   PentReduce(r, a, n, k3, k2, k1);
1141   q = Q;
1142}
1143
1144static
1145void TriDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, long n, long k)
1146{
1147   GF2XRegister(buf);
1148   GF2XRegister(tmp);
1149   GF2XRegister(a);
1150   GF2XRegister(qq);
1151   GF2XRegister(qbuf);
1152
1153   clear(buf);
1154   a = aa;
1155   clear(qq);
1156
1157   long a_len = deg(a) + 1;
1158
1159   while (a_len > 0) {
1160      long old_buf_len = deg(buf) + 1;
1161      long amt = min(2*n-1-old_buf_len, a_len);
1162
1163      LeftShift(buf, buf, amt);
1164      RightShift(tmp, a, a_len-amt);
1165      add(buf, buf, tmp);
1166      trunc(a, a, a_len-amt);
1167
1168      TriDivRem21(qbuf, buf, buf, n, k);
1169      a_len -= amt;
1170
1171      ShiftAdd(qq, qbuf, a_len);
1172   }
1173
1174   r = buf;
1175   q = qq;
1176}
1177
1178
1179static
1180void TriDivX1(GF2X& q, const GF2X& aa, long n, long k)
1181{
1182   GF2XRegister(buf);
1183   GF2XRegister(tmp);
1184   GF2XRegister(a);
1185   GF2XRegister(qq);
1186   GF2XRegister(qbuf);
1187
1188   clear(buf);
1189   a = aa;
1190   clear(qq);
1191
1192   long a_len = deg(a) + 1;
1193
1194   while (a_len > 0) {
1195      long old_buf_len = deg(buf) + 1;
1196      long amt = min(2*n-1-old_buf_len, a_len);
1197
1198      LeftShift(buf, buf, amt);
1199      RightShift(tmp, a, a_len-amt);
1200      add(buf, buf, tmp);
1201      trunc(a, a, a_len-amt);
1202
1203      TriDivRem21(qbuf, buf, buf, n, k);
1204      a_len -= amt;
1205
1206      ShiftAdd(qq, qbuf, a_len);
1207   }
1208
1209   q = qq;
1210}
1211
1212static
1213void PentDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, long n,
1214                  long k3, long k2, long k1)
1215{
1216   GF2XRegister(buf);
1217   GF2XRegister(tmp);
1218   GF2XRegister(a);
1219   GF2XRegister(qq);
1220   GF2XRegister(qbuf);
1221
1222   clear(buf);
1223   a = aa;
1224   clear(qq);
1225
1226   long a_len = deg(a) + 1;
1227
1228   while (a_len > 0) {
1229      long old_buf_len = deg(buf) + 1;
1230      long amt = min(2*n-1-old_buf_len, a_len);
1231
1232      LeftShift(buf, buf, amt);
1233      RightShift(tmp, a, a_len-amt);
1234      add(buf, buf, tmp);
1235      trunc(a, a, a_len-amt);
1236
1237      PentDivRem21(qbuf, buf, buf, n, k3, k2, k1);
1238      a_len -= amt;
1239
1240      ShiftAdd(qq, qbuf, a_len);
1241   }
1242
1243   r = buf;
1244   q = qq;
1245}
1246
1247
1248static
1249void PentDivX1(GF2X& q, const GF2X& aa, long n, long k3, long k2, long k1)
1250{
1251   GF2XRegister(buf);
1252   GF2XRegister(tmp);
1253   GF2XRegister(a);
1254   GF2XRegister(qq);
1255   GF2XRegister(qbuf);
1256
1257   clear(buf);
1258   a = aa;
1259   clear(qq);
1260
1261   long a_len = deg(a) + 1;
1262
1263   while (a_len > 0) {
1264      long old_buf_len = deg(buf) + 1;
1265      long amt = min(2*n-1-old_buf_len, a_len);
1266
1267      LeftShift(buf, buf, amt);
1268      RightShift(tmp, a, a_len-amt);
1269      add(buf, buf, tmp);
1270      trunc(a, a, a_len-amt);
1271
1272      PentDivRem21(qbuf, buf, buf, n, k3, k2, k1);
1273      a_len -= amt;
1274
1275      ShiftAdd(qq, qbuf, a_len);
1276   }
1277
1278   q = qq;
1279}
1280
1281
1282
1283void rem(GF2X& r, const GF2X& a, const GF2XModulus& F)
1284{
1285   long n = F.n;
1286
1287   if (n < 0) Error("rem: uninitialized modulus");
1288
1289   if (F.method == GF2X_MOD_TRI) {
1290      TrinomReduce(r, a, n, F.k3);
1291      return;
1292   }
1293
1294   if (F.method == GF2X_MOD_PENT) {
1295      PentReduce(r, a, n, F.k3, F.k2, F.k1);
1296      return;
1297   }
1298
1299   long da = deg(a);
1300
1301
1302   if (da < n) {
1303      r = a;
1304   }
1305   else if (F.method == GF2X_MOD_MUL) {
1306      if (da <= 2*(n-1))
1307         UseMulRem21(r, a, F);
1308      else
1309         UseMulRemX1(r, a, F);
1310   }
1311   else if (F.method == GF2X_MOD_SPECIAL) {
1312      long sa = a.xrep.length();
1313      long posa = da - NTL_BITS_PER_LONG*(sa-1);
1314
1315      _ntl_ulong *ap;
1316      if (&r == &a)
1317         ap = r.xrep.elts();
1318      else {
1319         GF2X_rembuf = a.xrep;
1320         ap = GF2X_rembuf.elts();
1321      }
1322
1323      _ntl_ulong *atop = &ap[sa-1];
1324      _ntl_ulong *stab_top;
1325
1326      long i;
1327
1328      while (1) {
1329         if (atop[0] & (1UL << posa)) {
1330            stab_top = &F.stab1[posa << 1];
1331            i = F.stab_cnt[posa];
1332            atop[i] ^= stab_top[0];
1333            atop[i+1] ^= stab_top[1];
1334         }
1335
1336         da--;
1337         if (da < n) break;
1338
1339         posa--;
1340         if (posa < 0) {
1341            posa = NTL_BITS_PER_LONG-1;
1342            atop--;
1343         }
1344      }
1345
1346      long sn = F.size;
1347      r.xrep.SetLength(sn);
1348      if (&r != &a) {
1349         _ntl_ulong *rp = r.xrep.elts();
1350         for (i = 0; i < sn; i++)
1351            rp[i] = ap[i];
1352      }
1353      r.xrep[sn-1] &= F.msk;
1354      r.normalize();
1355   }
1356   else {
1357      long sa = a.xrep.length();
1358      long posa = da - NTL_BITS_PER_LONG*(sa-1);
1359
1360
1361      _ntl_ulong *ap;
1362      if (&r == &a)
1363         ap = r.xrep.elts();
1364      else {
1365         GF2X_rembuf = a.xrep;
1366         ap = GF2X_rembuf.elts();
1367      }
1368
1369      _ntl_ulong *atop = &ap[sa-1];
1370      _ntl_ulong *stab_top;
1371
1372      long i;
1373
1374      while (1) {
1375         if (atop[0] & (1UL << posa)) {
1376            stab_top = F.stab_ptr[posa];
1377            for (i = F.stab_cnt[posa]; i <= 0; i++)
1378               atop[i] ^= stab_top[i];
1379         }
1380
1381         da--;
1382         if (da < n) break;
1383
1384         posa--;
1385         if (posa < 0) {
1386            posa = NTL_BITS_PER_LONG-1;
1387            atop--;
1388         }
1389      }
1390
1391      long sn = F.size;
1392      r.xrep.SetLength(sn);
1393      if (&r != &a) {
1394         _ntl_ulong *rp = r.xrep.elts();
1395         for (i = 0; i < sn; i++)
1396            rp[i] = ap[i];
1397      }
1398      r.normalize();
1399   }
1400
1401   GF2X_rembuf.release();
1402}
1403
1404void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F)
1405{
1406   long da = deg(a);
1407   long n = F.n;
1408
1409   if (n < 0) Error("DivRem: uninitialized modulus");
1410
1411   if (da < n) {
1412      r = a;
1413      clear(q);
1414   }
1415   else if (F.method == GF2X_MOD_TRI) {
1416      if (da <= 2*(n-1))
1417         TriDivRem21(q, r, a, F.n, F.k3);
1418      else
1419         TriDivRemX1(q, r, a, F.n, F.k3);
1420   }
1421   else if (F.method == GF2X_MOD_PENT) {
1422      if (da <= 2*(n-1))
1423         PentDivRem21(q, r, a, F.n, F.k3, F.k2, F.k1);
1424      else
1425         PentDivRemX1(q, r, a, F.n, F.k3, F.k2, F.k1);
1426   }
1427   else if (F.method == GF2X_MOD_MUL) {
1428      if (da <= 2*(n-1))
1429         UseMulDivRem21(q, r, a, F);
1430      else
1431         UseMulDivRemX1(q, r, a, F);
1432   }
1433   else if (F.method == GF2X_MOD_SPECIAL) {
1434      long sa = a.xrep.length();
1435      long posa = da - NTL_BITS_PER_LONG*(sa-1);
1436
1437      long dq = da - n;
1438      long sq = dq/NTL_BITS_PER_LONG + 1;
1439      long posq = dq - NTL_BITS_PER_LONG*(sq-1);
1440
1441      _ntl_ulong *ap;
1442      if (&r == &a)
1443         ap = r.xrep.elts();
1444      else {
1445         GF2X_rembuf = a.xrep;
1446         ap = GF2X_rembuf.elts();
1447      }
1448
1449      _ntl_ulong *atop = &ap[sa-1];
1450      _ntl_ulong *stab_top;
1451
1452      long i;
1453
1454      q.xrep.SetLength(sq);
1455      _ntl_ulong *qp = q.xrep.elts();
1456      for (i = 0; i < sq; i++)
1457         qp[i] = 0;
1458
1459      _ntl_ulong *qtop = &qp[sq-1];
1460
1461
1462      while (1) {
1463         if (atop[0] & (1UL << posa)) {
1464            qtop[0] |= (1UL << posq);
1465            stab_top = &F.stab1[posa << 1];
1466            i = F.stab_cnt[posa];
1467            atop[i] ^= stab_top[0];
1468            atop[i+1] ^= stab_top[1];
1469         }
1470
1471         da--;
1472         if (da < n) break;
1473
1474         posa--;
1475         if (posa < 0) {
1476            posa = NTL_BITS_PER_LONG-1;
1477            atop--;
1478         }
1479
1480         posq--;
1481         if (posq < 0) {
1482            posq = NTL_BITS_PER_LONG-1;
1483            qtop--;
1484         }
1485      }
1486
1487      long sn = F.size;
1488      r.xrep.SetLength(sn);
1489      if (&r != &a) {
1490         _ntl_ulong *rp = r.xrep.elts();
1491         for (i = 0; i < sn; i++)
1492            rp[i] = ap[i];
1493      }
1494      r.xrep[sn-1] &= F.msk;
1495      r.normalize();
1496   }
1497   else {
1498      long sa = a.xrep.length();
1499      long posa = da - NTL_BITS_PER_LONG*(sa-1);
1500
1501      long dq = da - n;
1502      long sq = dq/NTL_BITS_PER_LONG + 1;
1503      long posq = dq - NTL_BITS_PER_LONG*(sq-1);
1504
1505      _ntl_ulong *ap;
1506      if (&r == &a)
1507         ap = r.xrep.elts();
1508      else {
1509         GF2X_rembuf = a.xrep;
1510         ap = GF2X_rembuf.elts();
1511      }
1512
1513      _ntl_ulong *atop = &ap[sa-1];
1514      _ntl_ulong *stab_top;
1515
1516      long i;
1517
1518      q.xrep.SetLength(sq);
1519      _ntl_ulong *qp = q.xrep.elts();
1520      for (i = 0; i < sq; i++)
1521         qp[i] = 0;
1522
1523      _ntl_ulong *qtop = &qp[sq-1];
1524
1525      while (1) {
1526         if (atop[0] & (1UL << posa)) {
1527            qtop[0] |= (1UL << posq);
1528            stab_top = F.stab_ptr[posa];
1529            for (i = F.stab_cnt[posa]; i <= 0; i++)
1530               atop[i] ^= stab_top[i];
1531         }
1532
1533         da--;
1534         if (da < n) break;
1535
1536         posa--;
1537         if (posa < 0) {
1538            posa = NTL_BITS_PER_LONG-1;
1539            atop--;
1540         }
1541
1542         posq--;
1543         if (posq < 0) {
1544            posq = NTL_BITS_PER_LONG-1;
1545            qtop--;
1546         }
1547      }
1548
1549      long sn = F.size;
1550      r.xrep.SetLength(sn);
1551      if (&r != &a) {
1552         _ntl_ulong *rp = r.xrep.elts();
1553         for (i = 0; i < sn; i++)
1554            rp[i] = ap[i];
1555      }
1556      r.normalize();
1557   }
1558
1559   GF2X_rembuf.release();
1560}
1561
1562
1563
1564void div(GF2X& q, const GF2X& a, const GF2XModulus& F)
1565{
1566   long da = deg(a);
1567   long n = F.n;
1568
1569   if (n < 0) Error("div: uninitialized modulus");
1570
1571
1572   if (da < n) {
1573      clear(q);
1574   }
1575   else if (F.method == GF2X_MOD_TRI) {
1576      if (da <= 2*(n-1))
1577         TriDiv21(q, a, F.n, F.k3);
1578      else
1579         TriDivX1(q, a, F.n, F.k3);
1580   }
1581   else if (F.method == GF2X_MOD_PENT) {
1582      if (da <= 2*(n-1))
1583         PentDiv21(q, a, F.n, F.k3, F.k2, F.k1);
1584      else
1585         PentDivX1(q, a, F.n, F.k3, F.k2, F.k1);
1586   }
1587   else if (F.method == GF2X_MOD_MUL) {
1588      if (da <= 2*(n-1))
1589         UseMulDiv21(q, a, F);
1590      else
1591         UseMulDivX1(q, a, F);
1592   }
1593   else if (F.method == GF2X_MOD_SPECIAL) {
1594      long sa = a.xrep.length();
1595      long posa = da - NTL_BITS_PER_LONG*(sa-1);
1596
1597      long dq = da - n;
1598      long sq = dq/NTL_BITS_PER_LONG + 1;
1599      long posq = dq - NTL_BITS_PER_LONG*(sq-1);
1600
1601      _ntl_ulong *ap;
1602      GF2X_rembuf = a.xrep;
1603      ap = GF2X_rembuf.elts();
1604
1605
1606      _ntl_ulong *atop = &ap[sa-1];
1607      _ntl_ulong *stab_top;
1608
1609      long i;
1610
1611      q.xrep.SetLength(sq);
1612      _ntl_ulong *qp = q.xrep.elts();
1613      for (i = 0; i < sq; i++)
1614         qp[i] = 0;
1615
1616      _ntl_ulong *qtop = &qp[sq-1];
1617
1618      while (1) {
1619         if (atop[0] & (1UL << posa)) {
1620            qtop[0] |= (1UL << posq);
1621            stab_top = &F.stab1[posa << 1];
1622            i = F.stab_cnt[posa];
1623            atop[i] ^= stab_top[0];
1624            atop[i+1] ^= stab_top[1];
1625         }
1626
1627         da--;
1628         if (da < n) break;
1629
1630         posa--;
1631         if (posa < 0) {
1632            posa = NTL_BITS_PER_LONG-1;
1633            atop--;
1634         }
1635
1636         posq--;
1637         if (posq < 0) {
1638            posq = NTL_BITS_PER_LONG-1;
1639            qtop--;
1640         }
1641      }
1642   }
1643   else {
1644      long sa = a.xrep.length();
1645      long posa = da - NTL_BITS_PER_LONG*(sa-1);
1646
1647      long dq = da - n;
1648      long sq = dq/NTL_BITS_PER_LONG + 1;
1649      long posq = dq - NTL_BITS_PER_LONG*(sq-1);
1650
1651      _ntl_ulong *ap;
1652      GF2X_rembuf = a.xrep;
1653      ap = GF2X_rembuf.elts();
1654
1655      _ntl_ulong *atop = &ap[sa-1];
1656      _ntl_ulong *stab_top;
1657
1658      long i;
1659
1660      q.xrep.SetLength(sq);
1661      _ntl_ulong *qp = q.xrep.elts();
1662      for (i = 0; i < sq; i++)
1663         qp[i] = 0;
1664
1665      _ntl_ulong *qtop = &qp[sq-1];
1666
1667      while (1) {
1668         if (atop[0] & (1UL << posa)) {
1669            qtop[0] |= (1UL << posq);
1670            stab_top = F.stab_ptr[posa];
1671            for (i = F.stab_cnt[posa]; i <= 0; i++)
1672               atop[i] ^= stab_top[i];
1673         }
1674
1675         da--;
1676         if (da < n) break;
1677
1678         posa--;
1679         if (posa < 0) {
1680            posa = NTL_BITS_PER_LONG-1;
1681            atop--;
1682         }
1683
1684         posq--;
1685         if (posq < 0) {
1686            posq = NTL_BITS_PER_LONG-1;
1687            qtop--;
1688         }
1689      }
1690   }
1691
1692   GF2X_rembuf.release();
1693}
1694
1695
1696void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2XModulus& F)
1697{
1698   if (F.n < 0) Error("MulMod: uninitialized modulus");
1699
1700   GF2XRegister(t);
1701   mul(t, a, b);
1702   rem(c, t, F);
1703}
1704
1705
1706void SqrMod(GF2X& c, const GF2X& a, const GF2XModulus& F)
1707{
1708   if (F.n < 0) Error("SqrMod: uninitialized modulus");
1709
1710   GF2XRegister(t);
1711   sqr(t, a);
1712   rem(c, t, F);
1713}
1714
1715
1716// we need these two versions to prevent a GF2XModulus
1717// from being constructed.
1718
1719
1720void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2X& f)
1721{
1722   GF2XRegister(t);
1723   mul(t, a, b);
1724   rem(c, t, f);
1725}
1726
1727void SqrMod(GF2X& c, const GF2X& a, const GF2X& f)
1728{
1729   GF2XRegister(t);
1730   sqr(t, a);
1731   rem(c, t, f);
1732}
1733
1734
1735static
1736long OptWinSize(long n)
1737// finds k that minimizes n/(k+1) + 2^{k-1}
1738
1739{
1740   long k;
1741   double v, v_new;
1742
1743
1744   v = n/2.0 + 1.0;
1745   k = 1;
1746
1747   for (;;) {
1748      v_new = n/(double(k+2)) + double(1L << k);
1749      if (v_new >= v) break;
1750      v = v_new;
1751      k++;
1752   }
1753
1754   return k;
1755}
1756
1757
1758
1759void PowerMod(GF2X& h, const GF2X& g, const ZZ& e, const GF2XModulus& F)
1760// h = g^e mod f using "sliding window" algorithm
1761{
1762   if (deg(g) >= F.n) Error("PowerMod: bad args");
1763
1764   if (e == 0) {
1765      set(h);
1766      return;
1767   }
1768
1769   if (e == 1) {
1770      h = g;
1771      return;
1772   }
1773
1774   if (e == -1) {
1775      InvMod(h, g, F);
1776      return;
1777   }
1778
1779   if (e == 2) {
1780      SqrMod(h, g, F);
1781      return;
1782   }
1783
1784   if (e == -2) {
1785      SqrMod(h, g, F);
1786      InvMod(h, h, F);
1787      return;
1788   }
1789
1790
1791   long n = NumBits(e);
1792
1793   GF2X res;
1794   res.SetMaxLength(F.n);
1795   set(res);
1796
1797   long i;
1798
1799   if (n < 16) {
1800      // plain square-and-multiply algorithm
1801
1802      for (i = n - 1; i >= 0; i--) {
1803         SqrMod(res, res, F);
1804         if (bit(e, i))
1805            MulMod(res, res, g, F);
1806      }
1807
1808      if (e < 0) InvMod(res, res, F);
1809
1810      h = res;
1811      return;
1812   }
1813
1814   long k = OptWinSize(n);
1815
1816   k = min(k, 9);
1817
1818   vec_GF2X v;
1819
1820   v.SetLength(1L << (k-1));
1821
1822   v[0] = g;
1823
1824   if (k > 1) {
1825      GF2X t;
1826      SqrMod(t, g, F);
1827
1828      for (i = 1; i < (1L << (k-1)); i++)
1829         MulMod(v[i], v[i-1], t, F);
1830   }
1831
1832
1833   long val;
1834   long cnt;
1835   long m;
1836
1837   val = 0;
1838   for (i = n-1; i >= 0; i--) {
1839      val = (val << 1) | bit(e, i);
1840      if (val == 0)
1841         SqrMod(res, res, F);
1842      else if (val >= (1L << (k-1)) || i == 0) {
1843         cnt = 0;
1844         while ((val & 1) == 0) {
1845            val = val >> 1;
1846            cnt++;
1847         }
1848
1849         m = val;
1850         while (m > 0) {
1851            SqrMod(res, res, F);
1852            m = m >> 1;
1853         }
1854
1855         MulMod(res, res, v[val >> 1], F);
1856
1857         while (cnt > 0) {
1858            SqrMod(res, res, F);
1859            cnt--;
1860         }
1861
1862         val = 0;
1863      }
1864   }
1865
1866   if (e < 0) InvMod(res, res, F);
1867
1868   h = res;
1869}
1870
1871
1872
1873
1874void PowerXMod(GF2X& hh, const ZZ& e, const GF2XModulus& F)
1875{
1876   if (F.n < 0) Error("PowerXMod: uninitialized modulus");
1877
1878   if (IsZero(e)) {
1879      set(hh);
1880      return;
1881   }
1882
1883   long n = NumBits(e);
1884   long i;
1885
1886   GF2X h;
1887
1888   h.SetMaxLength(F.n+1);
1889   set(h);
1890
1891   for (i = n - 1; i >= 0; i--) {
1892      SqrMod(h, h, F);
1893      if (bit(e, i)) {
1894         MulByX(h, h);
1895         if (coeff(h, F.n) != 0)
1896            add(h, h, F.f);
1897      }
1898   }
1899
1900   if (e < 0) InvMod(h, h, F);
1901
1902   hh = h;
1903}
1904
1905
1906
1907
1908
1909void UseMulRem(GF2X& r, const GF2X& a, const GF2X& b)
1910{
1911   GF2XRegister(P1);
1912   GF2XRegister(P2);
1913
1914   long da = deg(a);
1915   long db = deg(b);
1916
1917   CopyReverse(P1, b, db);
1918   InvTrunc(P2, P1, da-db+1);
1919   CopyReverse(P1, P2, da-db);
1920
1921   RightShift(P2, a, db);
1922   mul(P2, P1, P2);
1923   RightShift(P2, P2, da-db);
1924   mul(P1, P2, b);
1925   add(P1, P1, a);
1926
1927   r = P1;
1928}
1929
1930void UseMulDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b)
1931{
1932   GF2XRegister(P1);
1933   GF2XRegister(P2);
1934
1935   long da = deg(a);
1936   long db = deg(b);
1937
1938   CopyReverse(P1, b, db);
1939   InvTrunc(P2, P1, da-db+1);
1940   CopyReverse(P1, P2, da-db);
1941
1942   RightShift(P2, a, db);
1943   mul(P2, P1, P2);
1944   RightShift(P2, P2, da-db);
1945   mul(P1, P2, b);
1946   add(P1, P1, a);
1947
1948   r = P1;
1949   q = P2;
1950}
1951
1952void UseMulDiv(GF2X& q, const GF2X& a, const GF2X& b)
1953{
1954   GF2XRegister(P1);
1955   GF2XRegister(P2);
1956
1957   long da = deg(a);
1958   long db = deg(b);
1959
1960   CopyReverse(P1, b, db);
1961   InvTrunc(P2, P1, da-db+1);
1962   CopyReverse(P1, P2, da-db);
1963
1964   RightShift(P2, a, db);
1965   mul(P2, P1, P2);
1966   RightShift(P2, P2, da-db);
1967
1968   q = P2;
1969}
1970
1971
1972const long GF2X_DIV_CROSS = 100;
1973
1974void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b)
1975{
1976   long sa = a.xrep.length();
1977   long sb = b.xrep.length();
1978
1979   if (sb < GF2X_DIV_CROSS || sa-sb < GF2X_DIV_CROSS)
1980      PlainDivRem(q, r, a, b);
1981   else if (sa < 4*sb)
1982      UseMulDivRem(q, r, a, b);
1983   else {
1984      GF2XModulus B;
1985      build(B, b);
1986      DivRem(q, r, a, B);
1987   }
1988}
1989
1990void div(GF2X& q, const GF2X& a, const GF2X& b)
1991{
1992   long sa = a.xrep.length();
1993   long sb = b.xrep.length();
1994
1995   if (sb < GF2X_DIV_CROSS || sa-sb < GF2X_DIV_CROSS)
1996      PlainDiv(q, a, b);
1997   else if (sa < 4*sb)
1998      UseMulDiv(q, a, b);
1999   else {
2000      GF2XModulus B;
2001      build(B, b);
2002      div(q, a, B);
2003   }
2004}
2005
2006void rem(GF2X& r, const GF2X& a, const GF2X& b)
2007{
2008   long sa = a.xrep.length();
2009   long sb = b.xrep.length();
2010
2011   if (sb < GF2X_DIV_CROSS || sa-sb < GF2X_DIV_CROSS)
2012      PlainRem(r, a, b);
2013   else if (sa < 4*sb)
2014      UseMulRem(r, a, b);
2015   else {
2016      GF2XModulus B;
2017      build(B, b);
2018      rem(r, a, B);
2019   }
2020}
2021
2022
2023static inline
2024void swap(_ntl_ulong_ptr& a, _ntl_ulong_ptr& b)
2025{  _ntl_ulong_ptr t;  t = a; a = b; b = t; }
2026
2027
2028
2029
2030static
2031void BaseGCD(GF2X& d, const GF2X& a_in, const GF2X& b_in)
2032{
2033   GF2XRegister(a);
2034   GF2XRegister(b);
2035
2036   if (IsZero(a_in)) {
2037      d = b_in;
2038      return;
2039   }
2040
2041   if (IsZero(b_in)) {
2042      d = a_in;
2043      return;
2044   }
2045
2046   a.xrep.SetMaxLength(a_in.xrep.length()+1);
2047   b.xrep.SetMaxLength(b_in.xrep.length()+1);
2048
2049   a = a_in;
2050   b = b_in;
2051
2052   _ntl_ulong *ap = a.xrep.elts();
2053   _ntl_ulong *bp = b.xrep.elts();
2054
2055   long da = deg(a);
2056   long wa = da/NTL_BITS_PER_LONG;
2057   long ba = da - wa*NTL_BITS_PER_LONG;
2058
2059   long db = deg(b);
2060   long wb = db/NTL_BITS_PER_LONG;
2061   long bb = db - wb*NTL_BITS_PER_LONG;
2062
2063   long parity = 0;
2064
2065   for (;;) {
2066      if (da < db) {
2067         swap(ap, bp);
2068         swap(da, db);
2069         swap(wa, wb);
2070         swap(ba, bb);
2071         parity = 1 - parity;
2072      }
2073
2074      // da >= db
2075
2076      if (db == -1) break;
2077
2078      ShiftAdd(ap, bp, wb+1, da-db);
2079
2080      _ntl_ulong msk = 1UL << ba;
2081      _ntl_ulong aa = ap[wa];
2082
2083      while ((aa & msk) == 0) {
2084         da--;
2085         msk = msk >> 1;
2086         ba--;
2087         if (!msk) {
2088            wa--;
2089            ba = NTL_BITS_PER_LONG-1;
2090            msk = 1UL << (NTL_BITS_PER_LONG-1);
2091            if (wa < 0) break;
2092            aa = ap[wa];
2093         }
2094      }
2095   }
2096
2097   a.normalize();
2098   b.normalize();
2099
2100   if (!parity) {
2101      d = a;
2102   }
2103   else {
2104      d = b;
2105   }
2106}
2107
2108
2109void OldGCD(GF2X& d, const GF2X& a, const GF2X& b)
2110{
2111   long sa = a.xrep.length();
2112   long sb = b.xrep.length();
2113
2114   if (sb >= 10 && 2*sa > 3*sb) {
2115      GF2XRegister(r);
2116
2117      rem(r, a, b);
2118      BaseGCD(d, b, r);
2119   }
2120   else if (sa >= 10 && 2*sb > 3*sa) {
2121      GF2XRegister(r);
2122
2123      rem(r, b, a);
2124      BaseGCD(d, a, r);
2125   }
2126   else {
2127      BaseGCD(d, a, b);
2128   }
2129}
2130
2131
2132
2133
2134
2135#define XX_STEP(ap,da,wa,ba,rp,sr,bp,db,wb,bb,sp,ss)  \
2136      long delta = da-db;  \
2137  \
2138      if (delta == 0) {  \
2139         long i;  \
2140         for (i = wb; i >= 0; i--) ap[i] ^= bp[i];  \
2141         for (i = ss-1; i >= 0; i--) rp[i] ^= sp[i];  \
2142         if (ss > sr) sr = ss; \
2143      }  \
2144      else if (delta == 1) {  \
2145         long i; \
2146         _ntl_ulong tt, tt1;  \
2147  \
2148         tt = bp[wb] >> (NTL_BITS_PER_LONG-1);  \
2149         if (tt) ap[wb+1] ^= tt;  \
2150         tt = bp[wb];  \
2151         for (i = wb; i >= 1; i--)  \
2152            tt1 = bp[i-1], ap[i] ^= (tt << 1) | (tt1 >> (NTL_BITS_PER_LONG-1)),  \
2153            tt = tt1; \
2154         ap[0] ^= tt << 1;  \
2155  \
2156         if (ss > 0) {  \
2157            long t = ss; \
2158            tt = sp[ss-1] >> (NTL_BITS_PER_LONG-1);  \
2159            if (tt) rp[ss] ^= tt, t++;  \
2160            tt = sp[ss-1]; \
2161            for (i = ss-1; i >= 1; i--)  \
2162               tt1=sp[i-1],  \
2163               rp[i] ^= (tt << 1) | (tt1 >> (NTL_BITS_PER_LONG-1)),  \
2164               tt = tt1; \
2165            rp[0] ^= tt << 1;  \
2166            if (t > sr) sr = t; \
2167         }  \
2168      }  \
2169      else if (delta < NTL_BITS_PER_LONG) {  \
2170         long i; \
2171         _ntl_ulong tt, tt1;  \
2172         long rdelta = NTL_BITS_PER_LONG-delta; \
2173  \
2174         tt = bp[wb] >> rdelta;  \
2175         if (tt) ap[wb+1] ^= tt;  \
2176         tt=bp[wb]; \
2177         for (i = wb; i >= 1; i--)  \
2178            tt1=bp[i-1], ap[i] ^= (tt << delta) | (tt1 >> rdelta),  \
2179            tt=tt1; \
2180         ap[0] ^= tt << delta;  \
2181  \
2182         if (ss > 0) {  \
2183            long t = ss; \
2184            tt = sp[ss-1] >> rdelta;  \
2185            if (tt) rp[ss] ^= tt, t++;  \
2186            tt=sp[ss-1]; \
2187            for (i = ss-1; i >= 1; i--)  \
2188               tt1=sp[i-1], rp[i] ^= (tt << delta) | (tt1 >> rdelta),  \
2189               tt=tt1; \
2190            rp[0] ^= tt << delta;  \
2191            if (t > sr) sr = t; \
2192         }  \
2193      }  \
2194      else {  \
2195         ShiftAdd(ap, bp, wb+1, da-db);  \
2196         ShiftAdd(rp, sp, ss, da-db);  \
2197         long t = ss + (da-db+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG;  \
2198         if (t > sr) {  \
2199            while (t > 0 && rp[t-1] == 0) t--;   \
2200            sr = t;  \
2201         }  \
2202      } \
2203  \
2204      _ntl_ulong msk = 1UL << ba;  \
2205      _ntl_ulong aa = ap[wa];  \
2206  \
2207      while ((aa & msk) == 0) {  \
2208         da--;  \
2209         msk = msk >> 1;  \
2210         ba--;  \
2211         if (!msk) {  \
2212            wa--;  \
2213            ba = NTL_BITS_PER_LONG-1;  \
2214            msk = 1UL << (NTL_BITS_PER_LONG-1);  \
2215            if (wa < 0) break;  \
2216            aa = ap[wa];  \
2217         }  \
2218      }  \
2219
2220
2221
2222
2223static
2224void XXGCD(GF2X& d, GF2X& r_out, const GF2X& a_in, const GF2X& b_in)
2225{
2226   GF2XRegister(a);
2227   GF2XRegister(b);
2228   GF2XRegister(r);
2229   GF2XRegister(s);
2230
2231   if (IsZero(b_in)) {
2232      d = a_in;
2233      set(r_out);
2234      return;
2235   }
2236
2237   if (IsZero(a_in)) {
2238      d = b_in;
2239      clear(r_out);
2240      return;
2241   }
2242
2243   a.xrep.SetMaxLength(a_in.xrep.length()+1);
2244   b.xrep.SetMaxLength(b_in.xrep.length()+1);
2245
2246   long max_sz = max(a_in.xrep.length(), b_in.xrep.length());
2247   r.xrep.SetLength(max_sz+1);
2248   s.xrep.SetLength(max_sz+1);
2249
2250   _ntl_ulong *rp = r.xrep.elts();
2251   _ntl_ulong *sp = s.xrep.elts();
2252
2253   long i;
2254   for (i = 0; i <= max_sz; i++) {
2255      rp[i] = sp[i] = 0;
2256   }
2257
2258   rp[0] = 1;
2259
2260   long sr = 1;
2261   long ss = 0;
2262
2263   a = a_in;
2264   b = b_in;
2265
2266   _ntl_ulong *ap = a.xrep.elts();
2267   _ntl_ulong *bp = b.xrep.elts();
2268
2269   long da = deg(a);
2270   long wa = da/NTL_BITS_PER_LONG;
2271   long ba = da - wa*NTL_BITS_PER_LONG;
2272
2273   long db = deg(b);
2274   long wb = db/NTL_BITS_PER_LONG;
2275   long bb = db - wb*NTL_BITS_PER_LONG;
2276
2277   long parity = 0;
2278
2279
2280   for (;;) {
2281      if (da == -1 || db == -1) break;
2282
2283      if (da < db || (da == db && parity)) {
2284         if (da < db && !parity) parity = 1;
2285         XX_STEP(bp,db,wb,bb,sp,ss,ap,da,wa,ba,rp,sr)
2286
2287      }
2288      else {
2289         parity = 0;
2290         XX_STEP(ap,da,wa,ba,rp,sr,bp,db,wb,bb,sp,ss)
2291      }
2292   }
2293
2294   a.normalize();
2295   b.normalize();
2296   r.normalize();
2297   s.normalize();
2298
2299   if (db == -1) {
2300      d = a;
2301      r_out = r;
2302   }
2303   else {
2304      d = b;
2305      r_out = s;
2306   }
2307}
2308
2309
2310
2311static
2312void BaseXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b)
2313{
2314   if (IsZero(b)) {
2315      d = a;
2316      set(s);
2317      clear(t);
2318   }
2319   else {
2320      GF2XRegister(t1);
2321      GF2XRegister(b1);
2322
2323      b1 = b;
2324      XXGCD(d, s, a, b);
2325      mul(t1, a, s);
2326      add(t1, t1, d);
2327      div(t, t1, b1);
2328   }
2329}
2330
2331
2332
2333
2334void OldXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b)
2335{
2336   long sa = a.xrep.length();
2337   long sb = b.xrep.length();
2338
2339
2340   if (sb >= 10 && 2*sa > 3*sb) {
2341      GF2XRegister(r);
2342      GF2XRegister(q);
2343      GF2XRegister(s1);
2344      GF2XRegister(t1);
2345
2346
2347      DivRem(q, r, a, b);
2348      BaseXGCD(d, s1, t1, b, r);
2349
2350
2351      mul(r, t1, q);
2352      add(r, r, s1);  // r = s1 - t1*q, but sign doesn't matter
2353
2354      s = t1;
2355      t = r;
2356   }
2357   else if (sa >= 10 && 2*sb > 3*sa) {
2358      GF2XRegister(r);
2359      GF2XRegister(q);
2360      GF2XRegister(s1);
2361      GF2XRegister(t1);
2362
2363
2364      DivRem(q, r, b, a);
2365      BaseXGCD(d, s1, t1, a, r);
2366
2367
2368      mul(r, t1, q);
2369      add(r, r, s1);  // r = s1 - t1*q, but sign doesn't matter
2370
2371      t = t1;
2372      s = r;
2373   }
2374   else {
2375      BaseXGCD(d, s, t, a, b);
2376   }
2377
2378}
2379
2380
2381
2382
2383static
2384void BaseInvMod(GF2X& d, GF2X& s, const GF2X& a, const GF2X& f)
2385{
2386   if (deg(a) >= deg(f) || deg(f) == 0) Error("InvMod: bad args");
2387
2388   long sa = a.xrep.length();
2389   long sf = f.xrep.length();
2390
2391   if ((sa >= 10 && 2*sf > 3*sa) ||
2392       sf > NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) {
2393      GF2XRegister(t);
2394
2395      XGCD(d, s, t, a, f);
2396   }
2397   else {
2398      XXGCD(d, s, a, f);
2399   }
2400
2401}
2402
2403
2404
2405void InvMod(GF2X& c, const GF2X& a, const GF2X& f)
2406{
2407   GF2XRegister(d);
2408   GF2XRegister(s);
2409   BaseInvMod(d, s, a, f);
2410
2411   if (!IsOne(d)) Error("InvMod: inverse undefined");
2412
2413   c = s;
2414}
2415
2416
2417
2418long InvModStatus(GF2X& c, const GF2X& a, const GF2X& f)
2419{
2420   GF2XRegister(d);
2421   GF2XRegister(s);
2422   BaseInvMod(d, s, a, f);
2423
2424   if (!IsOne(d)) {
2425      c = d;
2426      return 1;
2427   }
2428
2429   c = s;
2430   return 0;
2431}
2432
2433
2434
2435
2436void diff(GF2X& c, const GF2X& a)
2437{
2438   RightShift(c, a, 1);
2439
2440   // clear odd coeffs
2441
2442   long dc = deg(c);
2443   long i;
2444   for (i = 1; i <= dc; i += 2)
2445      SetCoeff(c, i, 0);
2446}
2447
2448void conv(GF2X& c, long a)
2449{
2450   if (a & 1)
2451      set(c);
2452   else
2453      clear(c);
2454}
2455
2456void conv(GF2X& c, GF2 a)
2457{
2458   if (a == 1)
2459      set(c);
2460   else
2461      clear(c);
2462}
2463
2464void conv(GF2X& x, const vec_GF2& a)
2465{
2466   x.xrep = a.rep;
2467   x.normalize();
2468}
2469
2470void conv(vec_GF2& x, const GF2X& a)
2471{
2472   VectorCopy(x, a, deg(a)+1);
2473}
2474
2475void VectorCopy(vec_GF2& x, const GF2X& a, long n)
2476{
2477   if (n < 0) Error("VectorCopy: negative length");
2478
2479   if (NTL_OVERFLOW(n, 1, 0))
2480      Error("overflow in VectorCopy");
2481
2482   long wa = a.xrep.length();
2483   long wx = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG;
2484
2485   long wmin = min(wa, wx);
2486
2487   x.SetLength(n);
2488
2489   const _ntl_ulong *ap = a.xrep.elts();
2490   _ntl_ulong *xp = x.rep.elts();
2491
2492   long i;
2493   for (i = 0; i < wmin; i++)
2494      xp[i] = ap[i];
2495
2496   if (wa < wx) {
2497      for (i = wa; i < wx; i++)
2498         xp[i] = 0;
2499   }
2500   else {
2501      long p = n % NTL_BITS_PER_LONG;
2502      if (p != 0)
2503         xp[wx-1] &= (1UL << p) - 1UL;
2504   }
2505}
2506
2507
2508void add(GF2X& c, const GF2X& a, long b)
2509{
2510   c = a;
2511   if (b & 1) {
2512      long n = c.xrep.length();
2513      if (n == 0)
2514         set(c);
2515      else {
2516         c.xrep[0] ^= 1;
2517         if (n == 1 && !c.xrep[0]) c.xrep.SetLength(0);
2518      }
2519   }
2520}
2521
2522void add(GF2X& c, const GF2X& a, GF2 b)
2523{
2524   add(c, a, rep(b));
2525}
2526
2527
2528void MulTrunc(GF2X& c, const GF2X& a, const GF2X& b, long n)
2529{
2530   GF2XRegister(t);
2531
2532   mul(t, a, b);
2533   trunc(c, t, n);
2534}
2535
2536void SqrTrunc(GF2X& c, const GF2X& a, long n)
2537{
2538   GF2XRegister(t);
2539
2540   sqr(t, a);
2541   trunc(c, t, n);
2542}
2543
2544
2545long divide(GF2X& q, const GF2X& a, const GF2X& b)
2546{
2547   if (IsZero(b)) {
2548      if (IsZero(a)) {
2549         clear(q);
2550         return 1;
2551      }
2552      else
2553         return 0;
2554   }
2555
2556   GF2XRegister(lq);
2557   GF2XRegister(r);
2558
2559   DivRem(lq, r, a, b);
2560   if (!IsZero(r)) return 0;
2561   q = lq;
2562   return 1;
2563}
2564
2565long divide(const GF2X& a, const GF2X& b)
2566{
2567   if (IsZero(b)) return IsZero(a);
2568   GF2XRegister(r);
2569   rem(r, a, b);
2570   if (!IsZero(r)) return 0;
2571   return 1;
2572}
2573
2574
2575
2576/*** modular composition routines and data structures ***/
2577
2578
2579void InnerProduct(GF2X& x, const GF2X& v, long dv, long low, long high,
2580                   const vec_GF2X& H, long n, WordVector& t)
2581{
2582   long i, j;
2583
2584   _ntl_ulong *tp = t.elts();
2585
2586   for (i = 0; i < n; i++)
2587      tp[i] = 0;
2588
2589
2590   long w_low = low/NTL_BITS_PER_LONG;
2591   long b_low = low - w_low*NTL_BITS_PER_LONG;
2592
2593
2594   const _ntl_ulong *vp = &v.xrep[w_low];
2595   _ntl_ulong msk = 1UL << b_low;
2596   _ntl_ulong vv = *vp;
2597
2598   high = min(high, dv);
2599
2600   i = low;
2601   for (;;) {
2602      if (vv & msk) {
2603         const WordVector& h = H[i-low].xrep;
2604         long m = h.length();
2605         const _ntl_ulong *hp = h.elts();
2606         for (j = 0; j < m; j++)
2607            tp[j] ^= hp[j];
2608      }
2609
2610      i++;
2611      if (i > high) break;
2612
2613      msk = msk << 1;
2614      if (!msk) {
2615         msk = 1UL;
2616         vp++;
2617         vv = *vp;
2618      }
2619   }
2620
2621   x.xrep = t;
2622   x.normalize();
2623}
2624
2625
2626void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& A, const GF2XModulus& F)
2627{
2628   long dg = deg(g);
2629   if (dg <= 0) {
2630      x = g;
2631      return;
2632   }
2633
2634   GF2X s, t;
2635   WordVector scratch(INIT_SIZE, F.size);
2636
2637   long m = A.H.length() - 1;
2638   long l = (((dg+1)+m-1)/m) - 1;
2639
2640   InnerProduct(t, g, dg, l*m, l*m + m - 1, A.H, F.size, scratch);
2641   for (long i = l-1; i >= 0; i--) {
2642      InnerProduct(s, g, dg, i*m, i*m + m - 1, A.H, F.size, scratch);
2643      MulMod(t, t, A.H[m], F);
2644      add(t, t, s);
2645   }
2646
2647   x = t;
2648}
2649
2650void build(GF2XArgument& A, const GF2X& h, const GF2XModulus& F, long m)
2651{
2652   if (m <= 0 || deg(h) >= F.n) Error("build GF2XArgument: bad args");
2653
2654   if (m > F.n) m = F.n;
2655
2656   long i;
2657
2658   A.H.SetLength(m+1);
2659
2660   set(A.H[0]);
2661   A.H[1] = h;
2662   for (i = 2; i <= m; i++)
2663      MulMod(A.H[i], A.H[i-1], h, F);
2664}
2665
2666
2667void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F)
2668   // x = g(h) mod f
2669{
2670   long m = SqrRoot(deg(g)+1);
2671
2672   if (m == 0) {
2673      clear(x);
2674      return;
2675   }
2676
2677   GF2XArgument A;
2678
2679   build(A, h, F, m);
2680
2681   CompMod(x, g, A, F);
2682}
2683
2684
2685
2686
2687void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2,
2688              const GF2X& h, const GF2XModulus& F)
2689
2690{
2691   long m = SqrRoot(deg(g1) + deg(g2) + 2);
2692
2693   if (m == 0) {
2694      clear(x1);
2695      clear(x2);
2696      return;
2697   }
2698
2699   GF2XArgument A;
2700
2701   build(A, h, F, m);
2702
2703   GF2X xx1, xx2;
2704
2705   CompMod(xx1, g1, A, F);
2706   CompMod(xx2, g2, A, F);
2707
2708   x1 = xx1;
2709   x2 = xx2;
2710}
2711
2712void Comp3Mod(GF2X& x1, GF2X& x2, GF2X& x3,
2713              const GF2X& g1, const GF2X& g2, const GF2X& g3,
2714              const GF2X& h, const GF2XModulus& F)
2715
2716{
2717   long m = SqrRoot(deg(g1) + deg(g2) + deg(g3) + 3);
2718
2719   if (m == 0) {
2720      clear(x1);
2721      clear(x2);
2722      clear(x3);
2723      return;
2724   }
2725
2726   GF2XArgument A;
2727
2728   build(A, h, F, m);
2729
2730   GF2X xx1, xx2, xx3;
2731
2732   CompMod(xx1, g1, A, F);
2733   CompMod(xx2, g2, A, F);
2734   CompMod(xx3, g3, A, F);
2735
2736   x1 = xx1;
2737   x2 = xx2;
2738   x3 = xx3;
2739}
2740
2741
2742
2743void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F)
2744{
2745   long db = deg(b);
2746
2747   if (db >= F.n) Error("build TransMultiplier: bad args");
2748
2749   GF2X t;
2750
2751   LeftShift(t, b, F.n-1);
2752   div(t, t, F);
2753
2754   // we optimize for low degree b
2755
2756   long d;
2757
2758   d = deg(t);
2759   if (d < 0)
2760      B.shamt_fbi = 0;
2761   else
2762      B.shamt_fbi = F.n-2 - d;
2763
2764   CopyReverse(B.fbi, t, d);
2765
2766   if (F.method != GF2X_MOD_TRI && F.method != GF2X_MOD_PENT) {
2767
2768      // The following code optimizes the case when
2769      // f = X^n + low degree poly
2770
2771      trunc(t, F.f, F.n);
2772      d = deg(t);
2773      if (d < 0)
2774         B.shamt = 0;
2775      else
2776         B.shamt = d;
2777
2778      CopyReverse(B.f0, t, d);
2779   }
2780
2781
2782   if (db < 0)
2783      B.shamt_b = 0;
2784   else
2785      B.shamt_b = db;
2786
2787   CopyReverse(B.b, b, db);
2788}
2789
2790void TransMulMod(GF2X& x, const GF2X& a, const GF2XTransMultiplier& B,
2791               const GF2XModulus& F)
2792{
2793   if (deg(a) >= F.n) Error("TransMulMod: bad args");
2794
2795   GF2XRegister(t1);
2796   GF2XRegister(t2);
2797   GF2XRegister(t3);
2798
2799   mul(t1, a, B.b);
2800   RightShift(t1, t1, B.shamt_b);
2801
2802   if (F.method == GF2X_MOD_TRI) {
2803      RightShift(t2, a, F.k3);
2804      add(t2, t2, a);
2805   }
2806   else if (F.method == GF2X_MOD_PENT) {
2807      RightShift(t2, a, F.k3);
2808      RightShift(t3, a, F.k2);
2809      add(t2, t2, t3);
2810      RightShift(t3, a, F.k1);
2811      add(t2, t2, t3);
2812      add(t2, t2, a);
2813   }
2814   else {
2815      mul(t2, a, B.f0);
2816      RightShift(t2, t2, B.shamt);
2817   }
2818
2819   trunc(t2, t2, F.n-1);
2820
2821   mul(t2, t2, B.fbi);
2822   if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi);
2823   trunc(t2, t2, F.n-1);
2824   MulByX(t2, t2);
2825
2826   add(x, t1, t2);
2827}
2828
2829void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B,
2830       const GF2XModulus& F)
2831{
2832   GF2XRegister(xx);
2833   GF2XRegister(aa);
2834   conv(aa, a);
2835   TransMulMod(xx, aa, B, F);
2836   conv(x, xx);
2837}
2838
2839
2840void ProjectPowers(GF2X& x, const GF2X& a, long k, const GF2XArgument& H,
2841                   const GF2XModulus& F)
2842{
2843   long n = F.n;
2844
2845   if (deg(a) >= n || k < 0 || NTL_OVERFLOW(k, 1, 0))
2846      Error("ProjectPowers: bad args");
2847
2848   long m = H.H.length()-1;
2849   long l = (k+m-1)/m - 1;
2850
2851   GF2XTransMultiplier M;
2852   build(M, H.H[m], F);
2853
2854   GF2X s;
2855   s = a;
2856
2857   x.SetMaxLength(k);
2858   clear(x);
2859
2860   long i;
2861
2862   for (i = 0; i <= l; i++) {
2863      long m1 = min(m, k-i*m);
2864      for (long j = 0; j < m1; j++)
2865         SetCoeff(x, i*m+j, InnerProduct(H.H[j].xrep, s.xrep));
2866      if (i < l)
2867         TransMulMod(s, s, M, F);
2868   }
2869}
2870
2871
2872void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k,
2873                   const GF2XArgument& H, const GF2XModulus& F)
2874{
2875   GF2X xx;
2876   ProjectPowers(xx, to_GF2X(a), k, H, F);
2877   VectorCopy(x, xx, k);
2878}
2879
2880
2881void ProjectPowers(GF2X& x, const GF2X& a, long k, const GF2X& h,
2882                   const GF2XModulus& F)
2883{
2884   if (deg(a) >= F.n || k < 0) Error("ProjectPowers: bad args");
2885
2886   if (k == 0) {
2887      clear(x);
2888      return;
2889   }
2890
2891   long m = SqrRoot(k);
2892
2893   GF2XArgument H;
2894   build(H, h, F, m);
2895
2896   ProjectPowers(x, a, k, H, F);
2897}
2898
2899void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& H,
2900                   const GF2XModulus& F)
2901{
2902   GF2X xx;
2903   ProjectPowers(xx, to_GF2X(a), k, H, F);
2904   VectorCopy(x, xx, k);
2905}
2906
2907
2908void OldMinPolyInternal(GF2X& h, const GF2X& x, long m)
2909{
2910   GF2X a, b, r, s;
2911   GF2X a_in, b_in;
2912
2913   if (IsZero(x)) {
2914      set(h);
2915      return;
2916   }
2917
2918   clear(a_in);
2919   SetCoeff(a_in, 2*m);
2920
2921   CopyReverse(b_in, x, 2*m-1);
2922
2923   a.xrep.SetMaxLength(a_in.xrep.length()+1);
2924   b.xrep.SetMaxLength(b_in.xrep.length()+1);
2925
2926   long max_sz = max(a_in.xrep.length(), b_in.xrep.length());
2927   r.xrep.SetLength(max_sz+1);
2928   s.xrep.SetLength(max_sz+1);
2929
2930   _ntl_ulong *rp = r.xrep.elts();
2931   _ntl_ulong *sp = s.xrep.elts();
2932
2933   long i;
2934   for (i = 0; i <= max_sz; i++) {
2935      rp[i] = sp[i] = 0;
2936   }
2937
2938   sp[0] = 1;
2939
2940   long sr = 0;
2941   long ss = 1;
2942
2943   a = a_in;
2944   b = b_in;
2945
2946   _ntl_ulong *ap = a.xrep.elts();
2947   _ntl_ulong *bp = b.xrep.elts();
2948
2949   long da = deg(a);
2950   long wa = da/NTL_BITS_PER_LONG;
2951   long ba = da - wa*NTL_BITS_PER_LONG;
2952
2953   long db = deg(b);
2954   long wb = db/NTL_BITS_PER_LONG;
2955   long bb = db - wb*NTL_BITS_PER_LONG;
2956
2957   long parity = 0;
2958
2959   for (;;) {
2960      if (da < db) {
2961         swap(ap, bp);
2962         swap(da, db);
2963         swap(wa, wb);
2964         swap(ba, bb);
2965         parity = 1 - parity;
2966
2967         swap(rp, sp);
2968         swap(sr, ss);
2969      }
2970
2971      // da >= db
2972
2973      if (db < m) break;
2974
2975      ShiftAdd(ap, bp, wb+1, da-db);
2976      ShiftAdd(rp, sp, ss, da-db);
2977      long t = ss + (da-db+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG;
2978      if (t > sr) {
2979         while (t > 0 && rp[t-1] == 0) t--;
2980         sr = t;
2981      }
2982
2983      _ntl_ulong msk = 1UL << ba;
2984      _ntl_ulong aa = ap[wa];
2985
2986      while ((aa & msk) == 0) {
2987         da--;
2988         msk = msk >> 1;
2989         ba--;
2990         if (!msk) {
2991            wa--;
2992            ba = NTL_BITS_PER_LONG-1;
2993            msk = 1UL << (NTL_BITS_PER_LONG-1);
2994            if (wa < 0) break;
2995            aa = ap[wa];
2996         }
2997      }
2998   }
2999
3000   a.normalize();
3001   b.normalize();
3002   r.normalize();
3003   s.normalize();
3004
3005   if (!parity) {
3006      h = s;
3007   }
3008   else {
3009      h = r;
3010   }
3011}
3012
3013
3014void DoMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m,
3015               const GF2X& R)
3016{
3017   GF2X x;
3018
3019   ProjectPowers(x, R, 2*m, g, F);
3020   MinPolyInternal(h, x, m);
3021}
3022
3023void MinPolySeq(GF2X& h, const vec_GF2& a, long m)
3024{
3025   if (m < 0 || NTL_OVERFLOW(m, 1, 0)) Error("MinPoly: bad args");
3026   if (a.length() < 2*m) Error("MinPoly: sequence too short");
3027   GF2X x;
3028   x.xrep = a.rep;
3029   x.normalize();
3030   MinPolyInternal(h, x, m);
3031}
3032
3033void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m)
3034{
3035   long n = F.n;
3036   if (m < 1 || m > n) Error("ProbMinPoly: bad args");
3037
3038   GF2X R;
3039   random(R, n);
3040
3041   DoMinPolyMod(h, g, F, m, R);
3042}
3043
3044void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F)
3045{
3046   ProbMinPolyMod(h, g, F, F.n);
3047}
3048
3049void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m)
3050{
3051   GF2X h, h1;
3052   long n = F.n;
3053   if (m < 1 || m > n) Error("MinPoly: bad args");
3054
3055   /* probabilistically compute min-poly */
3056
3057   ProbMinPolyMod(h, g, F, m);
3058   if (deg(h) == m) { hh = h; return; }
3059   CompMod(h1, h, g, F);
3060   if (IsZero(h1)) { hh = h; return; }
3061
3062   /* not completely successful...must iterate */
3063
3064
3065   GF2X h2, h3;
3066   GF2X R;
3067   GF2XTransMultiplier H1;
3068
3069
3070   for (;;) {
3071      random(R, n);
3072      build(H1, h1, F);
3073      TransMulMod(R, R, H1, F);
3074      DoMinPolyMod(h2, g, F, m-deg(h), R);
3075
3076      mul(h, h, h2);
3077      if (deg(h) == m) { hh = h; return; }
3078      CompMod(h3, h2, g, F);
3079      MulMod(h1, h3, h1, F);
3080      if (IsZero(h1)) { hh = h; return; }
3081   }
3082}
3083
3084void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m)
3085{
3086   if (m < 1 || m > F.n) Error("IrredPoly: bad args");
3087
3088   GF2X R;
3089   set(R);
3090
3091   DoMinPolyMod(h, g, F, m, R);
3092}
3093
3094
3095
3096void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F)
3097{
3098   IrredPolyMod(h, g, F, F.n);
3099}
3100
3101
3102
3103void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F)
3104{
3105   MinPolyMod(hh, g, F, F.n);
3106}
3107
3108
3109
3110void MulByXMod(GF2X& c, const GF2X& a, const GF2XModulus& F)
3111{
3112   long da = deg(a);
3113   long df = deg(F);
3114   if (da >= df) Error("MulByXMod: bad args");
3115
3116   MulByX(c, a);
3117
3118   if (da >= 0 && da == df-1)
3119      add(c, c, F);
3120}
3121
3122static
3123void MulByXModAux(GF2X& c, const GF2X& a, const GF2X& f)
3124{
3125   long da = deg(a);
3126   long df = deg(f);
3127   if (da >= df) Error("MulByXMod: bad args");
3128
3129   MulByX(c, a);
3130
3131   if (da >= 0 && da == df-1)
3132      add(c, c, f);
3133}
3134
3135void MulByXMod(GF2X& h, const GF2X& a, const GF2X& f)
3136{
3137   if (&h == &f) {
3138      GF2X hh;
3139      MulByXModAux(hh, a, f);
3140      h = hh;
3141   }
3142   else
3143      MulByXModAux(h, a, f);
3144}
3145
3146
3147
3148
3149void power(GF2X& x, const GF2X& a, long e)
3150{
3151   if (e < 0) {
3152      Error("power: negative exponent");
3153   }
3154
3155   if (e == 0) {
3156      x = 1;
3157      return;
3158   }
3159
3160   if (a == 0 || a == 1) {
3161      x = a;
3162      return;
3163   }
3164
3165   long da = deg(a);
3166
3167   if (da > (NTL_MAX_LONG-1)/e)
3168      Error("overflow in power");
3169
3170   GF2X res;
3171   res.SetMaxLength(da*e + 1);
3172   res = 1;
3173
3174   long k = NumBits(e);
3175   long i;
3176
3177   for (i = k - 1; i >= 0; i--) {
3178      sqr(res, res);
3179      if (bit(e, i))
3180         mul(res, res, a);
3181   }
3182
3183   x = res;
3184}
3185
3186
3187static
3188void FastTraceVec(vec_GF2& S, const GF2XModulus& f)
3189{
3190   long n = deg(f);
3191
3192   if (n <= 0) Error("TraceVec: bad args");
3193
3194   GF2X x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1);
3195
3196   VectorCopy(S, x, n);
3197   S.put(0, to_GF2(n));
3198}
3199
3200static
3201void PlainTraceVec(vec_GF2& S, const GF2X& f)
3202{
3203   long n = deg(f);
3204
3205   if (n <= 0)
3206      Error("TraceVec: bad args");
3207
3208   if (n == 0) {
3209      S.SetLength(0);
3210      return;
3211   }
3212
3213   GF2X x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1);
3214
3215   VectorCopy(S, x, n);
3216   S.put(0, to_GF2(n));
3217}
3218
3219
3220void TraceVec(vec_GF2& S, const GF2X& f)
3221{
3222   PlainTraceVec(S, f);
3223}
3224
3225static
3226void ComputeTraceVec(const GF2XModulus& F)
3227{
3228   vec_GF2& S = *((vec_GF2 *) &F.tracevec);
3229
3230   if (S.length() > 0)
3231      return;
3232
3233   if (F.method == GF2X_MOD_PLAIN) {
3234      PlainTraceVec(S, F.f);
3235   }
3236   else {
3237      FastTraceVec(S, F);
3238   }
3239}
3240
3241void TraceMod(GF2& x, const GF2X& a, const GF2XModulus& F)
3242{
3243   long n = F.n;
3244
3245   if (deg(a) >= n)
3246      Error("trace: bad args");
3247
3248   if (F.tracevec.length() == 0)
3249      ComputeTraceVec(F);
3250
3251   project(x, F.tracevec, a);
3252}
3253
3254void TraceMod(GF2& x, const GF2X& a, const GF2X& f)
3255{
3256   if (deg(a) >= deg(f) || deg(f) <= 0)
3257      Error("trace: bad args");
3258
3259   project(x, TraceVec(f), a);
3260}
3261
3262
3263
3264// New versions of GCD, XGCD, and MinPolyInternal
3265// and support routines
3266
3267class _NTL_GF2XMatrix {
3268private:
3269
3270   _NTL_GF2XMatrix(const _NTL_GF2XMatrix&);  // disable
3271   GF2X elts[2][2];
3272
3273public:
3274
3275   _NTL_GF2XMatrix() { }
3276   ~_NTL_GF2XMatrix() { }
3277
3278   void operator=(const _NTL_GF2XMatrix&);
3279   GF2X& operator() (long i, long j) { return elts[i][j]; }
3280   const GF2X& operator() (long i, long j) const { return elts[i][j]; }
3281};
3282
3283
3284void _NTL_GF2XMatrix::operator=(const _NTL_GF2XMatrix& M)
3285{
3286   elts[0][0] = M.elts[0][0];
3287   elts[0][1] = M.elts[0][1];
3288   elts[1][0] = M.elts[1][0];
3289   elts[1][1] = M.elts[1][1];
3290}
3291
3292
3293static
3294void mul(GF2X& U, GF2X& V, const _NTL_GF2XMatrix& M)
3295// (U, V)^T = M*(U, V)^T
3296{
3297   GF2X t1, t2, t3;
3298
3299   mul(t1, M(0,0), U);
3300   mul(t2, M(0,1), V);
3301   add(t3, t1, t2);
3302   mul(t1, M(1,0), U);
3303   mul(t2, M(1,1), V);
3304   add(V, t1, t2);
3305   U = t3;
3306}
3307
3308
3309static
3310void mul(_NTL_GF2XMatrix& A, _NTL_GF2XMatrix& B, _NTL_GF2XMatrix& C)
3311// A = B*C, B and C are destroyed
3312{
3313   GF2X t1, t2;
3314
3315   mul(t1, B(0,0), C(0,0));
3316   mul(t2, B(0,1), C(1,0));
3317   add(A(0,0), t1, t2);
3318
3319   mul(t1, B(1,0), C(0,0));
3320   mul(t2, B(1,1), C(1,0));
3321   add(A(1,0), t1, t2);
3322
3323   mul(t1, B(0,0), C(0,1));
3324   mul(t2, B(0,1), C(1,1));
3325   add(A(0,1), t1, t2);
3326
3327   mul(t1, B(1,0), C(0,1));
3328   mul(t2, B(1,1), C(1,1));
3329   add(A(1,1), t1, t2);
3330
3331   long i, j;
3332   for (i = 0; i < 2; i++) {
3333      for (j = 0; j < 2; j++) {
3334          B(i,j).kill();
3335          C(i,j).kill();
3336      }
3337   }
3338}
3339
3340static
3341void IterHalfGCD(_NTL_GF2XMatrix& M_out, GF2X& U, GF2X& V, long d_red)
3342{
3343   M_out(0,0).SetMaxLength(d_red);
3344   M_out(0,1).SetMaxLength(d_red);
3345   M_out(1,0).SetMaxLength(d_red);
3346   M_out(1,1).SetMaxLength(d_red);
3347
3348   set(M_out(0,0));   clear(M_out(0,1));
3349   clear(M_out(1,0)); set(M_out(1,1));
3350
3351   long goal = deg(U) - d_red;
3352
3353   if (deg(V) <= goal)
3354      return;
3355
3356   GF2X Q, t(INIT_SIZE, d_red);
3357
3358   while (deg(V) > goal) {
3359      DivRem(Q, U, U, V);
3360      swap(U, V);
3361
3362      mul(t, Q, M_out(1,0));
3363      sub(t, M_out(0,0), t);
3364      M_out(0,0) = M_out(1,0);
3365      M_out(1,0) = t;
3366
3367      mul(t, Q, M_out(1,1));
3368      sub(t, M_out(0,1), t);
3369      M_out(0,1) = M_out(1,1);
3370      M_out(1,1) = t;
3371   }
3372}
3373
3374
3375
3376static
3377void HalfGCD(_NTL_GF2XMatrix& M_out, const GF2X& U, const GF2X& V, long d_red)
3378{
3379   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
3380      set(M_out(0,0));   clear(M_out(0,1));
3381      clear(M_out(1,0)); set(M_out(1,1));
3382
3383      return;
3384   }
3385
3386
3387   long n = deg(U) - 2*d_red + 2;
3388   if (n < 0) n = 0;
3389
3390   GF2X U1, V1;
3391
3392   RightShift(U1, U, n);
3393   RightShift(V1, V, n);
3394
3395   if (d_red <= NTL_GF2X_HalfGCD_CROSSOVER) {
3396      IterHalfGCD(M_out, U1, V1, d_red);
3397      return;
3398   }
3399
3400   long d1 = (d_red + 1)/2;
3401   if (d1 < 1) d1 = 1;
3402   if (d1 >= d_red) d1 = d_red - 1;
3403
3404   _NTL_GF2XMatrix M1;
3405
3406   HalfGCD(M1, U1, V1, d1);
3407   mul(U1, V1, M1);
3408
3409
3410   long d2 = deg(V1) - deg(U) + n + d_red;
3411
3412   if (IsZero(V1) || d2 <= 0) {
3413      M_out = M1;
3414      return;
3415   }
3416
3417
3418   GF2X Q;
3419   _NTL_GF2XMatrix M2;
3420
3421   DivRem(Q, U1, U1, V1);
3422   swap(U1, V1);
3423
3424   HalfGCD(M2, U1, V1, d2);
3425
3426   GF2X t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1);
3427
3428   mul(t, Q, M1(1,0));
3429   sub(t, M1(0,0), t);
3430   swap(M1(0,0), M1(1,0));
3431   swap(M1(1,0), t);
3432
3433   t.kill();
3434
3435   t.SetMaxLength(deg(M1(1,1))+deg(Q)+1);
3436
3437   mul(t, Q, M1(1,1));
3438   sub(t, M1(0,1), t);
3439   swap(M1(0,1), M1(1,1));
3440   swap(M1(1,1), t);
3441
3442   t.kill();
3443
3444   mul(M_out, M2, M1);
3445}
3446
3447static
3448void HalfGCD(GF2X& U, GF2X& V)
3449{
3450   long d_red = (deg(U)+1)/2;
3451
3452   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
3453      return;
3454   }
3455
3456   long du = deg(U);
3457
3458
3459   long d1 = (d_red + 1)/2;
3460   if (d1 < 1) d1 = 1;
3461   if (d1 >= d_red) d1 = d_red - 1;
3462
3463   _NTL_GF2XMatrix M1;
3464
3465   HalfGCD(M1, U, V, d1);
3466   mul(U, V, M1);
3467
3468   long d2 = deg(V) - du + d_red;
3469
3470   if (IsZero(V) || d2 <= 0) {
3471      return;
3472   }
3473
3474   M1(0,0).kill();
3475   M1(0,1).kill();
3476   M1(1,0).kill();
3477   M1(1,1).kill();
3478
3479
3480   GF2X Q;
3481
3482   DivRem(Q, U, U, V);
3483   swap(U, V);
3484
3485   HalfGCD(M1, U, V, d2);
3486
3487   mul(U, V, M1);
3488}
3489
3490
3491void GCD(GF2X& d, const GF2X& u, const GF2X& v)
3492{
3493   long su = u.xrep.length();
3494   long sv = v.xrep.length();
3495
3496   if (su <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG &&
3497       sv <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) {
3498      OldGCD(d, u, v);
3499      return;
3500   }
3501
3502   GF2X u1, v1;
3503
3504   u1 = u;
3505   v1 = v;
3506
3507   long du1 = deg(u1);
3508   long dv1 = deg(v1);
3509
3510   if (du1 == dv1) {
3511      if (IsZero(u1)) {
3512         clear(d);
3513         return;
3514      }
3515
3516      rem(v1, v1, u1);
3517   }
3518   else if (du1 < dv1) {
3519      swap(u1, v1);
3520      du1 = dv1;
3521   }
3522
3523   // deg(u1) > deg(v1)
3524
3525   while (du1 >= NTL_GF2X_GCD_CROSSOVER && !IsZero(v1)) {
3526      HalfGCD(u1, v1);
3527
3528      if (!IsZero(v1)) {
3529         rem(u1, u1, v1);
3530         swap(u1, v1);
3531      }
3532
3533      du1 = deg(u1);
3534   }
3535
3536   OldGCD(d, u1, v1);
3537}
3538
3539static
3540void XHalfGCD(_NTL_GF2XMatrix& M_out, GF2X& U, GF2X& V, long d_red)
3541{
3542   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
3543      set(M_out(0,0));   clear(M_out(0,1));
3544      clear(M_out(1,0)); set(M_out(1,1));
3545
3546      return;
3547   }
3548
3549   long du = deg(U);
3550
3551   if (d_red <= NTL_GF2X_HalfGCD_CROSSOVER) {
3552      IterHalfGCD(M_out, U, V, d_red);
3553      return;
3554   }
3555
3556   long d1 = (d_red + 1)/2;
3557   if (d1 < 1) d1 = 1;
3558   if (d1 >= d_red) d1 = d_red - 1;
3559
3560   _NTL_GF2XMatrix M1;
3561
3562   HalfGCD(M1, U, V, d1);
3563   mul(U, V, M1);
3564
3565   long d2 = deg(V) - du + d_red;
3566
3567   if (IsZero(V) || d2 <= 0) {
3568      M_out = M1;
3569      return;
3570   }
3571
3572
3573   GF2X Q;
3574   _NTL_GF2XMatrix M2;
3575
3576   DivRem(Q, U, U, V);
3577   swap(U, V);
3578
3579   XHalfGCD(M2, U, V, d2);
3580
3581
3582   GF2X t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1);
3583
3584   mul(t, Q, M1(1,0));
3585   sub(t, M1(0,0), t);
3586   swap(M1(0,0), M1(1,0));
3587   swap(M1(1,0), t);
3588
3589   t.kill();
3590
3591   t.SetMaxLength(deg(M1(1,1))+deg(Q)+1);
3592
3593   mul(t, Q, M1(1,1));
3594   sub(t, M1(0,1), t);
3595   swap(M1(0,1), M1(1,1));
3596   swap(M1(1,1), t);
3597
3598   t.kill();
3599
3600   mul(M_out, M2, M1);
3601}
3602
3603
3604
3605
3606void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b)
3607{
3608   // GF2 w;
3609
3610   long sa = a.xrep.length();
3611   long sb = b.xrep.length();
3612
3613   if (sa <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG &&
3614       sb <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) {
3615      OldXGCD(d, s, t, a, b);
3616      return;
3617   }
3618
3619   GF2X U, V, Q;
3620
3621   U = a;
3622   V = b;
3623
3624   long flag = 0;
3625
3626   if (deg(U) == deg(V)) {
3627      DivRem(Q, U, U, V);
3628      swap(U, V);
3629      flag = 1;
3630   }
3631   else if (deg(U) < deg(V)) {
3632      swap(U, V);
3633      flag = 2;
3634   }
3635
3636   _NTL_GF2XMatrix M;
3637
3638   XHalfGCD(M, U, V, deg(U)+1);
3639
3640   d = U;
3641
3642
3643   if (flag == 0) {
3644      s = M(0,0);
3645      t = M(0,1);
3646   }
3647   else if (flag == 1) {
3648      s = M(0,1);
3649      mul(t, Q, M(0,1));
3650      sub(t, M(0,0), t);
3651   }
3652   else {  /* flag == 2 */
3653      s = M(0,1);
3654      t = M(0,0);
3655   }
3656
3657   // normalize
3658
3659   // inv(w, LeadCoeff(d));
3660   // mul(d, d, w);
3661   // mul(s, s, w);
3662   // mul(t, t, w);
3663}
3664
3665
3666void MinPolyInternal(GF2X& h, const GF2X& x, long m)
3667{
3668   if (m < NTL_GF2X_BERMASS_CROSSOVER) {
3669      OldMinPolyInternal(h, x, m);
3670      return;
3671   }
3672
3673   GF2X a, b;
3674   _NTL_GF2XMatrix M;
3675
3676   SetCoeff(b, 2*m);
3677   CopyReverse(a, x, 2*m-1);
3678   HalfGCD(M, b, a, m+1);
3679
3680   h = M(1,1);
3681}
3682
3683
3684
3685NTL_END_IMPL
Note: See TracBrowser for help on using the repository browser.