📄 gf2ex.cpp
字号:
x.rep.SetLength(n);
for (i = 0; i < n; i++)
random(x.rep[i]);
x.normalize();
}
void CopyReverse(GF2EX& x, const GF2EX& a, long hi)
// x[0..hi] = reverse(a[0..hi]), with zero fill
// input may not alias output
{
long i, j, n, m;
n = hi+1;
m = a.rep.length();
x.rep.SetLength(n);
const GF2E* ap = a.rep.elts();
GF2E* xp = x.rep.elts();
for (i = 0; i < n; i++) {
j = hi-i;
if (j < 0 || j >= m)
clear(xp[i]);
else
xp[i] = ap[j];
}
x.normalize();
}
void trunc(GF2EX& x, const GF2EX& a, long m)
// x = a % X^m, output may alias input
{
if (m < 0) Error("trunc: bad args");
if (&x == &a) {
if (x.rep.length() > m) {
x.rep.SetLength(m);
x.normalize();
}
}
else {
long n;
long i;
GF2E* xp;
const GF2E* ap;
n = min(a.rep.length(), m);
x.rep.SetLength(n);
xp = x.rep.elts();
ap = a.rep.elts();
for (i = 0; i < n; i++) xp[i] = ap[i];
x.normalize();
}
}
void NewtonInvTrunc(GF2EX& c, const GF2EX& a, long e)
{
GF2E x;
inv(x, ConstTerm(a));
if (e == 1) {
conv(c, x);
return;
}
static vec_long E;
E.SetLength(0);
append(E, e);
while (e > 1) {
e = (e+1)/2;
append(E, e);
}
long L = E.length();
GF2EX g, g0, g1, g2;
g.rep.SetMaxLength(e);
g0.rep.SetMaxLength(e);
g1.rep.SetMaxLength((3*e+1)/2);
g2.rep.SetMaxLength(e);
conv(g, x);
long i;
for (i = L-1; i > 0; i--) {
// lift from E[i] to E[i-1]
long k = E[i];
long l = E[i-1]-E[i];
trunc(g0, a, k+l);
mul(g1, g0, g);
RightShift(g1, g1, k);
trunc(g1, g1, l);
mul(g2, g1, g);
trunc(g2, g2, l);
LeftShift(g2, g2, k);
add(g, g, g2);
}
c = g;
}
void InvTrunc(GF2EX& c, const GF2EX& a, long e)
{
if (e < 0) Error("InvTrunc: bad args");
if (e == 0) {
clear(c);
return;
}
if (e >= (1L << (NTL_BITS_PER_LONG-4)))
Error("overflow in InvTrunc");
NewtonInvTrunc(c, a, e);
}
const long GF2EX_MOD_PLAIN = 0;
const long GF2EX_MOD_MUL = 1;
void build(GF2EXModulus& F, const GF2EX& f)
{
long n = deg(f);
if (n <= 0) Error("build(GF2EXModulus,GF2EX): deg(f) <= 0");
if (n >= (1L << (NTL_BITS_PER_LONG-4))/GF2E::degree())
Error("build(GF2EXModulus,GF2EX): overflow");
F.tracevec.SetLength(0);
F.f = f;
F.n = n;
if (F.n < GF2E::ModCross()) {
F.method = GF2EX_MOD_PLAIN;
}
else {
F.method = GF2EX_MOD_MUL;
GF2EX P1;
GF2EX P2;
CopyReverse(P1, f, n);
InvTrunc(P2, P1, n-1);
CopyReverse(P1, P2, n-2);
trunc(F.h0, P1, n-2);
trunc(F.f0, f, n);
F.hlc = ConstTerm(P2);
}
}
GF2EXModulus::GF2EXModulus()
{
n = -1;
method = GF2EX_MOD_PLAIN;
}
GF2EXModulus::GF2EXModulus(const GF2EX& ff)
{
n = -1;
method = GF2EX_MOD_PLAIN;
build(*this, ff);
}
void UseMulRem21(GF2EX& r, const GF2EX& a, const GF2EXModulus& F)
{
GF2EX P1;
GF2EX P2;
RightShift(P1, a, F.n);
mul(P2, P1, F.h0);
RightShift(P2, P2, F.n-2);
if (!IsOne(F.hlc)) mul(P1, P1, F.hlc);
add(P2, P2, P1);
mul(P1, P2, F.f0);
trunc(P1, P1, F.n);
trunc(r, a, F.n);
add(r, r, P1);
}
void UseMulDivRem21(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F)
{
GF2EX P1;
GF2EX P2;
RightShift(P1, a, F.n);
mul(P2, P1, F.h0);
RightShift(P2, P2, F.n-2);
if (!IsOne(F.hlc)) mul(P1, P1, F.hlc);
add(P2, P2, P1);
mul(P1, P2, F.f0);
trunc(P1, P1, F.n);
trunc(r, a, F.n);
add(r, r, P1);
q = P2;
}
void UseMulDiv21(GF2EX& q, const GF2EX& a, const GF2EXModulus& F)
{
GF2EX P1;
GF2EX P2;
RightShift(P1, a, F.n);
mul(P2, P1, F.h0);
RightShift(P2, P2, F.n-2);
if (!IsOne(F.hlc)) mul(P1, P1, F.hlc);
add(P2, P2, P1);
q = P2;
}
void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F)
{
if (F.method == GF2EX_MOD_PLAIN) {
PlainRem(x, a, F.f);
return;
}
long da = deg(a);
long n = F.n;
if (da <= 2*n-2) {
UseMulRem21(x, a, F);
return;
}
GF2EX buf(INIT_SIZE, 2*n-1);
long a_len = da+1;
while (a_len > 0) {
long old_buf_len = buf.rep.length();
long amt = min(2*n-1-old_buf_len, a_len);
buf.rep.SetLength(old_buf_len+amt);
long i;
for (i = old_buf_len+amt-1; i >= amt; i--)
buf.rep[i] = buf.rep[i-amt];
for (i = amt-1; i >= 0; i--)
buf.rep[i] = a.rep[a_len-amt+i];
buf.normalize();
UseMulRem21(buf, buf, F);
a_len -= amt;
}
x = buf;
}
void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F)
{
if (F.method == GF2EX_MOD_PLAIN) {
PlainDivRem(q, r, a, F.f);
return;
}
long da = deg(a);
long n = F.n;
if (da <= 2*n-2) {
UseMulDivRem21(q, r, a, F);
return;
}
GF2EX buf(INIT_SIZE, 2*n-1);
GF2EX qbuf(INIT_SIZE, n-1);
GF2EX qq;
qq.rep.SetLength(da-n+1);
long a_len = da+1;
long q_hi = da-n+1;
while (a_len > 0) {
long old_buf_len = buf.rep.length();
long amt = min(2*n-1-old_buf_len, a_len);
buf.rep.SetLength(old_buf_len+amt);
long i;
for (i = old_buf_len+amt-1; i >= amt; i--)
buf.rep[i] = buf.rep[i-amt];
for (i = amt-1; i >= 0; i--)
buf.rep[i] = a.rep[a_len-amt+i];
buf.normalize();
UseMulDivRem21(qbuf, buf, buf, F);
long dl = qbuf.rep.length();
a_len = a_len - amt;
for(i = 0; i < dl; i++)
qq.rep[a_len+i] = qbuf.rep[i];
for(i = dl+a_len; i < q_hi; i++)
clear(qq.rep[i]);
q_hi = a_len;
}
r = buf;
qq.normalize();
q = qq;
}
void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F)
{
if (F.method == GF2EX_MOD_PLAIN) {
PlainDiv(q, a, F.f);
return;
}
long da = deg(a);
long n = F.n;
if (da <= 2*n-2) {
UseMulDiv21(q, a, F);
return;
}
GF2EX buf(INIT_SIZE, 2*n-1);
GF2EX qbuf(INIT_SIZE, n-1);
GF2EX qq;
qq.rep.SetLength(da-n+1);
long a_len = da+1;
long q_hi = da-n+1;
while (a_len > 0) {
long old_buf_len = buf.rep.length();
long amt = min(2*n-1-old_buf_len, a_len);
buf.rep.SetLength(old_buf_len+amt);
long i;
for (i = old_buf_len+amt-1; i >= amt; i--)
buf.rep[i] = buf.rep[i-amt];
for (i = amt-1; i >= 0; i--)
buf.rep[i] = a.rep[a_len-amt+i];
buf.normalize();
a_len = a_len - amt;
if (a_len > 0)
UseMulDivRem21(qbuf, buf, buf, F);
else
UseMulDiv21(qbuf, buf, F);
long dl = qbuf.rep.length();
for(i = 0; i < dl; i++)
qq.rep[a_len+i] = qbuf.rep[i];
for(i = dl+a_len; i < q_hi; i++)
clear(qq.rep[i]);
q_hi = a_len;
}
qq.normalize();
q = qq;
}
void MulMod(GF2EX& c, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F)
{
if (deg(a) >= F.n || deg(b) >= F.n) Error("MulMod: bad args");
GF2EX t;
mul(t, a, b);
rem(c, t, F);
}
void SqrMod(GF2EX& c, const GF2EX& a, const GF2EXModulus& F)
{
if (deg(a) >= F.n) Error("MulMod: bad args");
GF2EX t;
sqr(t, a);
rem(c, t, F);
}
static
long OptWinSize(long n)
// finds k that minimizes n/(k+1) + 2^{k-1}
{
long k;
double v, v_new;
v = n/2.0 + 1.0;
k = 1;
for (;;) {
v_new = n/(double(k+2)) + double(1L << k);
if (v_new >= v) break;
v = v_new;
k++;
}
return k;
}
void PowerMod(GF2EX& h, const GF2EX& g, const ZZ& e, const GF2EXModulus& F)
// h = g^e mod f using "sliding window" algorithm
{
if (deg(g) >= F.n) Error("PowerMod: bad args");
if (e == 0) {
set(h);
return;
}
if (e == 1) {
h = g;
return;
}
if (e == -1) {
InvMod(h, g, F);
return;
}
if (e == 2) {
SqrMod(h, g, F);
return;
}
if (e == -2) {
SqrMod(h, g, F);
InvMod(h, h, F);
return;
}
long n = NumBits(e);
GF2EX res;
res.SetMaxLength(F.n);
set(res);
long i;
if (n < 16) {
// plain square-and-multiply algorithm
for (i = n - 1; i >= 0; i--) {
SqrMod(res, res, F);
if (bit(e, i))
MulMod(res, res, g, F);
}
if (e < 0) InvMod(res, res, F);
h = res;
return;
}
long k = OptWinSize(n);
k = min(k, 5);
vec_GF2EX v;
v.SetLength(1L << (k-1));
v[0] = g;
if (k > 1) {
GF2EX t;
SqrMod(t, g, F);
for (i = 1; i < (1L << (k-1)); i++)
MulMod(v[i], v[i-1], t, F);
}
long val;
long cnt;
long m;
val = 0;
for (i = n-1; i >= 0; i--) {
val = (val << 1) | bit(e, i);
if (val == 0)
SqrMod(res, res, F);
else if (val >= (1L << (k-1)) || i == 0) {
cnt = 0;
while ((val & 1) == 0) {
val = val >> 1;
cnt++;
}
m = val;
while (m > 0) {
SqrMod(res, res, F);
m = m >> 1;
}
MulMod(res, res, v[val >> 1], F);
while (cnt > 0) {
SqrMod(res, res, F);
cnt--;
}
val = 0;
}
}
if (e < 0) InvMod(res, res, F);
h = res;
}
void PowerXMod(GF2EX& hh, const ZZ& e, const GF2EXModulus& F)
{
if (F.n < 0) Error("PowerXMod: uninitialized modulus");
if (IsZero(e)) {
set(hh);
return;
}
long n = NumBits(e);
long i;
GF2EX h;
h.SetMaxLength(F.n+1);
set(h);
for (i = n - 1; i >= 0; i--) {
SqrMod(h, h, F);
if (bit(e, i)) {
MulByXMod(h, h, F.f);
}
}
if (e < 0) InvMod(h, h, F);
hh = h;
}
void UseMulRem(GF2EX& r, const GF2EX& a, const GF2EX& b)
{
GF2EX P1;
GF2EX P2;
long da = deg(a);
long db = deg(b);
CopyReverse(P1, b, db);
InvTrunc(P2, P1, da-db+1);
CopyReverse(P1, P2, da-db);
RightShift(P2, a, db);
mul(P2, P1, P2);
RightShift(P2, P2, da-db);
mul(P1, P2, b);
add(P1, P1, a);
r = P1;
}
void UseMulDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b)
{
GF2EX P1;
GF2EX P2;
long da = deg(a);
long db = deg(b);
CopyReverse(P1, b, db);
InvTrunc(P2, P1, da-db+1);
CopyReverse(P1, P2, da-db);
RightShift(P2, a, db);
mul(P2, P1, P2);
RightShift(P2, P2, da-db);
mul(P1, P2, b);
add(P1, P1, a);
r = P1;
q = P2;
}
void UseMulDiv(GF2EX& q, const GF2EX& a, const GF2EX& b)
{
GF2EX P1;
GF2EX P2;
long da = deg(a);
long db = deg(b);
CopyReverse(P1, b, db);
InvTrunc(P2, P1, da-db+1);
CopyReverse(P1, P2, da-db);
RightShift(P2, a, db);
mul(P2, P1, P2);
RightShift(P2, P2, da-db);
q = P2;
}
void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b)
{
long sa = a.rep.length();
long sb = b.rep.length();
if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross())
PlainDivRem(q, r, a, b);
else if (sa < 4*sb)
UseMulDivRem(q, r, a, b);
else {
GF2EXModulus B;
build(B, b);
DivRem(q, r, a, B);
}
}
void div(GF2EX& q, const GF2EX& a, const GF2EX& b)
{
long sa = a.rep.length();
long sb = b.rep.length();
if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross())
PlainDiv(q, a, b);
else if (sa < 4*sb)
UseMulDiv(q, a, b);
else {
GF2EXModulus B;
build(B, b);
div(q, a, B);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -