📄 gf2x.cpp
字号:
#include <NTL/GF2X.h>
#include <NTL/vec_long.h>
#include <NTL/new.h>
NTL_START_IMPL
long GF2X::HexOutput = 0;
void GF2X::SetMaxLength(long n)
{
if (n < 0) Error("GF2X::SetMaxLength: negative length");
if (n >= (1L << (NTL_BITS_PER_LONG-4)))
Error("GF2X::SetMaxLength: excessive length");
long w = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG;
xrep.SetMaxLength(w);
}
GF2X::GF2X(INIT_SIZE_TYPE, long n)
{
SetMaxLength(n);
}
const GF2X& GF2X::zero()
{
static GF2X z;
return z;
}
void GF2X::normalize()
{
long n;
const _ntl_ulong *p;
n = xrep.length();
if (n == 0) return;
p = xrep.elts() + (n-1);
while (n > 0 && (*p) == 0) {
p--;
n--;
}
xrep.QuickSetLength(n);
}
long IsZero(const GF2X& a)
{ return a.xrep.length() == 0; }
long IsOne(const GF2X& a)
{ return a.xrep.length() == 1 && a.xrep[0] == 1; }
long IsX(const GF2X& a)
{
return a.xrep.length() == 1 && a.xrep[0] == 2;
}
GF2 coeff(const GF2X& a, long i)
{
if (i < 0) return to_GF2(0);
long wi = i/NTL_BITS_PER_LONG;
if (wi >= a.xrep.length()) return to_GF2(0);
long bi = i - wi*NTL_BITS_PER_LONG;
return to_GF2((a.xrep[wi] & (1UL << bi)) != 0);
}
GF2 LeadCoeff(const GF2X& a)
{
if (IsZero(a))
return to_GF2(0);
else
return to_GF2(1);
}
GF2 ConstTerm(const GF2X& a)
{
if (IsZero(a))
return to_GF2(0);
else
return to_GF2((a.xrep[0] & 1) != 0);
}
void set(GF2X& x)
{
x.xrep.SetLength(1);
x.xrep[0] = 1;
}
void SetX(GF2X& x)
{
x.xrep.SetLength(1);
x.xrep[0] = 2;
}
void SetCoeff(GF2X& x, long i)
{
if (i < 0) {
Error("SetCoeff: negative index");
return;
}
long n, j;
n = x.xrep.length();
long wi = i/NTL_BITS_PER_LONG;
if (wi >= n) {
x.xrep.SetLength(wi+1);
for (j = n; j <= wi; j++)
x.xrep[j] = 0;
}
long bi = i - wi*NTL_BITS_PER_LONG;
x.xrep[wi] |= (1UL << bi);
}
void SetCoeff(GF2X& x, long i, long val)
{
if (i < 0) {
Error("SetCoeff: negative index");
return;
}
val = val & 1;
if (val) {
SetCoeff(x, i);
return;
}
// we want to clear position i
long n;
n = x.xrep.length();
long wi = i/NTL_BITS_PER_LONG;
if (wi >= n)
return;
long bi = i - wi*NTL_BITS_PER_LONG;
x.xrep[wi] &= ~(1UL << bi);
if (wi == n-1) x.normalize();
}
void SetCoeff(GF2X& x, long i, GF2 a)
{
SetCoeff(x, i, rep(a));
}
void swap(GF2X& a, GF2X& b)
{
swap(a.xrep, b.xrep);
}
long deg(const GF2X& aa)
{
long n = aa.xrep.length();
if (n == 0)
return -1;
_ntl_ulong a = aa.xrep[n-1];
long i = 0;
if (a == 0) Error("GF2X: unnormalized polynomial detected in deg");
while (a>=256)
i += 8, a >>= 8;
if (a >=16)
i += 4, a >>= 4;
if (a >= 4)
i += 2, a >>= 2;
if (a >= 2)
i += 2;
else if (a >= 1)
i++;
return NTL_BITS_PER_LONG*(n-1) + i - 1;
}
long operator==(const GF2X& a, const GF2X& b)
{
return a.xrep == b.xrep;
}
long operator==(const GF2X& a, long b)
{
if (b & 1)
return IsOne(a);
else
return IsZero(a);
}
long operator==(const GF2X& a, GF2 b)
{
if (b == 1)
return IsOne(a);
else
return IsZero(a);
}
static
long FromHex(long c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return 10 + c - 'A';
if (c >= 'a' && c <= 'f')
return 10 + c - 'a';
Error("FromHex: bad arg");
return 0;
}
static
istream & HexInput(istream& s, GF2X& a)
{
long n;
long c;
long i;
long val;
GF2X ibuf;
n = 0;
clear(ibuf);
c = s.peek();
while ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f'))
{
val = FromHex(c);
for (i = 0; i < 4; i++)
if (val & (1L << i))
SetCoeff(ibuf, n+i);
n += 4;
s.get();
c = s.peek();
}
a = ibuf;
return s;
}
istream & operator>>(istream& s, GF2X& a)
{
static ZZ ival;
long c;
if (!s) Error("bad GF2X input");
c = s.peek();
while (c == ' ' || c == '\n' || c == '\t') {
s.get();
c = s.peek();
}
if (c == '0') {
s.get();
c = s.peek();
if (c == 'x' || c == 'X') {
s.get();
return HexInput(s, a);
}
else {
Error("bad GF2X input");
}
}
if (c != '[') {
Error("bad GF2X input");
}
GF2X ibuf;
long n;
n = 0;
clear(ibuf);
s.get();
c = s.peek();
while (c == ' ' || c == '\n' || c == '\t') {
s.get();
c = s.peek();
}
while (c != ']' && c != EOF) {
if (!(s >> ival)) Error("bad GF2X input");
SetCoeff(ibuf, n, to_GF2(ival));
n++;
c = s.peek();
while (c == ' ' || c == '\n' || c == '\t') {
s.get();
c = s.peek();
}
}
if (c == EOF) Error("bad GF2X input");
s.get();
a = ibuf;
return s;
}
static
char ToHex(long val)
{
if (val >= 0 && val <= 9)
return char('0' + val);
if (val >= 10 && val <= 15)
return char('a' + val - 10);
Error("ToHex: bad arg");
return 0;
}
static
ostream & HexOutput(ostream& s, const GF2X& a)
{
s << "0x";
long da = deg(a);
if (da < 0) {
s << '0';
return s;
}
long i, n, val;
val = 0;
n = 0;
for (i = 0; i <= da; i++) {
val = val | (rep(coeff(a, i)) << n);
n++;
if (n == 4) {
s << ToHex(val);
val = 0;
n = 0;
}
}
if (val)
s << ToHex(val);
return s;
}
ostream& operator<<(ostream& s, const GF2X& a)
{
if (GF2X::HexOutput)
return HexOutput(s, a);
long i, da;
GF2 c;
da = deg(a);
s << '[';
for (i = 0; i <= da; i++) {
c = coeff(a, i);
if (c == 0)
s << "0";
else
s << "1";
if (i < da) s << " ";
}
s << ']';
return s;
}
void random(GF2X& x, long n)
{
if (n < 0) Error("GF2X random: negative length");
if (n >= (1L << (NTL_BITS_PER_LONG-4)))
Error("GF2X random: excessive length");
long wl = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG;
x.xrep.SetLength(wl);
long i;
for (i = 0; i < wl-1; i++) {
x.xrep[i] = RandomWord();
}
if (n > 0) {
long pos = n % NTL_BITS_PER_LONG;
if (pos == 0) pos = NTL_BITS_PER_LONG;
x.xrep[wl-1] = RandomBits_ulong(pos);
}
x.normalize();
}
void add(GF2X& x, const GF2X& a, const GF2X& b)
{
long sa = a.xrep.length();
long sb = b.xrep.length();
long i;
if (sa == sb) {
x.xrep.SetLength(sa);
if (sa == 0) return;
_ntl_ulong *xp = x.xrep.elts();
const _ntl_ulong *ap = a.xrep.elts();
const _ntl_ulong *bp = b.xrep.elts();
for (i = 0; i < sa; i++)
xp[i] = ap[i] ^ bp[i];
i = sa-1;
while (i >= 0 && !xp[i]) i--;
x.xrep.QuickSetLength(i+1);
}
else if (sa < sb) {
x.xrep.SetLength(sb);
_ntl_ulong *xp = x.xrep.elts();
const _ntl_ulong *ap = a.xrep.elts();
const _ntl_ulong *bp = b.xrep.elts();
for (i = 0; i < sa; i++)
xp[i] = ap[i] ^ bp[i];
for (; i < sb; i++)
xp[i] = bp[i];
}
else { // sa > sb
x.xrep.SetLength(sa);
_ntl_ulong *xp = x.xrep.elts();
const _ntl_ulong *ap = a.xrep.elts();
const _ntl_ulong *bp = b.xrep.elts();
for (i = 0; i < sb; i++)
xp[i] = ap[i] ^ bp[i];
for (; i < sa; i++)
xp[i] = ap[i];
}
}
// This mul1 routine (for 32 x 32 bit multiplies)
// was arrived at after a good deal of experimentation.
// Several people have advocated that the "best" way
// is to reduce it via karastuba to 9 8x8 multiplies, implementing
// the latter via table look-up (a huge table). Although such a mul1
// would indeed have fewer machine instructions, my
// experiments on a PowerPC and on a Pentium indicate
// that the memory accesses slow it down. On these machines
// the following mul1 is faster by a factor of about 1.5.
// inlining mul1 seems to help with g++; morever,
// the IBM xlC compiler inlines it anyway.
inline
void mul1(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b)
{
_ntl_ulong hi, lo;
_ntl_ulong A[4];
A[0] = 0;
A[1] = a & ((1UL << (NTL_BITS_PER_LONG-1))-1UL);
A[2] = a << 1;
A[3] = A[1] ^ A[2];
lo = A[b>>(NTL_BITS_PER_LONG-2)];
hi = lo >> (NTL_BITS_PER_LONG-2);
lo = (lo << 2) ^ A[(b >> (NTL_BITS_PER_LONG-4)) & 3];
// The following code is included from mach_desc.h
// and handles *any* word size
NTL_BB_MUL_CODE
hi = (hi << 2)|(lo >> (NTL_BITS_PER_LONG-2));
lo = (lo << 2) ^ A[b & 3];
if (a >> (NTL_BITS_PER_LONG-1)) {
hi = hi ^ (b >> 1);
lo = lo ^ (b << (NTL_BITS_PER_LONG-1));
}
c[0] = lo;
c[1] = hi;
}
inline
void mul_half(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b)
{
_ntl_ulong hi, lo;
_ntl_ulong A[4];
A[0] = 0;
A[1] = a & ((1UL << (NTL_BITS_PER_LONG-1))-1UL);
A[2] = a << 1;
A[3] = A[1] ^ A[2];
lo = A[b>>(NTL_BITS_PER_LONG/2-2)];
hi = lo >> (NTL_BITS_PER_LONG-2);
lo = (lo << 2) ^ A[(b >> (NTL_BITS_PER_LONG/2-4)) & 3];
NTL_BB_HALF_MUL_CODE
hi = (hi << 2)|(lo >> (NTL_BITS_PER_LONG-2));
lo = (lo << 2) ^ A[b & 3];
if (a >> (NTL_BITS_PER_LONG-1)) {
hi = hi ^ (b >> 1);
lo = lo ^ (b << (NTL_BITS_PER_LONG-1));
}
c[0] = lo;
c[1] = hi;
}
// mul2...mul8 hard-code 2x2...8x8 word multiplies.
// I adapted these routines from LiDIA.
// Inlining these seems to hurt, not help.
static
void mul2(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b)
{
_ntl_ulong hs0, hs1;
_ntl_ulong hl2[2];
hs0 = a[0] ^ a[1];
hs1 = b[0] ^ b[1];
mul1(c, a[0], b[0]);
mul1(c+2, a[1], b[1]);
mul1(hl2, hs0, hs1);
hl2[0] = hl2[0] ^ c[0] ^ c[2];
hl2[1] = hl2[1] ^ c[1] ^ c[3];
c[1] ^= hl2[0];
c[2] ^= hl2[1];
}
static
void mul3 (_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b)
{
_ntl_ulong hs0[2], hs1[2];
_ntl_ulong hl2[4];
hs0[0] = a[0] ^ a[2];
hs0[1] = a[1];
hs1[0] = b[0] ^ b[2];
hs1[1] = b[1];
mul2(c, a, b);
mul1(c+4, a[2], b[2]);
mul2(hl2, hs0, hs1);
hl2[0] = hl2[0] ^ c[0] ^ c[4];
hl2[1] = hl2[1] ^ c[1] ^ c[5];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -