174 lines
2.7 KiB
C
174 lines
2.7 KiB
C
#include "os.h"
|
|
#include <mp.h>
|
|
#include "dat.h"
|
|
|
|
/*
|
|
* fast reduction for generalized mersenne numbers (GM)
|
|
* using a series of additions and subtractions.
|
|
*/
|
|
|
|
enum {
|
|
MAXDIG = 1024/Dbits,
|
|
};
|
|
|
|
typedef struct GMfield GMfield;
|
|
struct GMfield
|
|
{
|
|
Mfield;
|
|
|
|
mpint m2[1];
|
|
|
|
int nadd;
|
|
int nsub;
|
|
int indx[256];
|
|
};
|
|
|
|
static int
|
|
gmreduce(Mfield *m, mpint *a, mpint *r)
|
|
{
|
|
GMfield *g = (GMfield*)m;
|
|
mpdigit d0, t[MAXDIG];
|
|
int i, j, d, *x;
|
|
|
|
if(mpmagcmp(a, g->m2) >= 0)
|
|
return -1;
|
|
|
|
if(a != r)
|
|
mpassign(a, r);
|
|
|
|
d = g->top;
|
|
mpbits(r, (d+1)*Dbits*2);
|
|
jehanne_memmove(t+d, r->p+d, d*Dbytes);
|
|
|
|
r->sign = 1;
|
|
r->top = d;
|
|
r->p[d] = 0;
|
|
|
|
if(g->nsub > 0)
|
|
mpvecdigmuladd(g->p, d, g->nsub, r->p);
|
|
|
|
x = g->indx;
|
|
for(i=0; i<g->nadd; i++){
|
|
t[0] = 0;
|
|
d0 = t[*x++];
|
|
for(j=1; j<d; j++)
|
|
t[j] = t[*x++];
|
|
t[0] = d0;
|
|
|
|
mpvecadd(r->p, d+1, t, d, r->p);
|
|
}
|
|
|
|
for(i=0; i<g->nsub; i++){
|
|
t[0] = 0;
|
|
d0 = t[*x++];
|
|
for(j=1; j<d; j++)
|
|
t[j] = t[*x++];
|
|
t[0] = d0;
|
|
|
|
mpvecsub(r->p, d+1, t, d, r->p);
|
|
}
|
|
|
|
mpvecdigmulsub(g->p, d, r->p[d], r->p);
|
|
r->p[d] = 0;
|
|
|
|
mpvecsub(r->p, d+1, g->p, d, r->p+d+1);
|
|
d0 = r->p[2*d+1];
|
|
for(j=0; j<d; j++)
|
|
r->p[j] = (r->p[j] & d0) | (r->p[j+d+1] & ~d0);
|
|
|
|
mpnorm(r);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Mfield*
|
|
gmfield(mpint *N)
|
|
{
|
|
int i,j,d, s, *C, *X, *x, *e;
|
|
mpint *M, *T;
|
|
GMfield *g;
|
|
|
|
d = N->top;
|
|
if(d <= 2 || d > MAXDIG/2 || (mpsignif(N) % Dbits) != 0)
|
|
return nil;
|
|
g = nil;
|
|
T = mpnew(0);
|
|
M = mpcopy(N);
|
|
C = jehanne_malloc(sizeof(int)*(d+1));
|
|
X = jehanne_malloc(sizeof(int)*(d*d));
|
|
if(C == nil || X == nil)
|
|
goto out;
|
|
|
|
for(i=0; i<=d; i++){
|
|
if((M->p[i]>>8) != 0 && (~M->p[i]>>8) != 0)
|
|
goto out;
|
|
j = M->p[i];
|
|
C[d - i] = -j;
|
|
itomp(j, T);
|
|
mpleft(T, i*Dbits, T);
|
|
mpsub(M, T, M);
|
|
}
|
|
for(j=0; j<d; j++)
|
|
X[j] = C[d-j];
|
|
for(i=1; i<d; i++){
|
|
X[d*i] = X[d*(i-1) + d-1]*C[d];
|
|
for(j=1; j<d; j++)
|
|
X[d*i + j] = X[d*(i-1) + j-1] + X[d*(i-1) + d-1]*C[d-j];
|
|
}
|
|
g = jehanne_mallocz(sizeof(GMfield) + (d+1)*sizeof(mpdigit)*2, 1);
|
|
if(g == nil)
|
|
goto out;
|
|
|
|
g->m2->p = (mpdigit*)&g[1];
|
|
g->m2->size = d*2+1;
|
|
mpmul(N, N, g->m2);
|
|
mpassign(N, g);
|
|
g->reduce = gmreduce;
|
|
g->flags |= MPfield;
|
|
|
|
s = 0;
|
|
x = g->indx;
|
|
e = x + nelem(g->indx) - d;
|
|
for(g->nadd=0; x <= e; x += d, g->nadd++){
|
|
s = 0;
|
|
for(i=0; i<d; i++){
|
|
for(j=0; j<d; j++){
|
|
if(X[d*i+j] > 0 && x[j] == 0){
|
|
X[d*i+j]--;
|
|
x[j] = d+i;
|
|
s = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(s == 0)
|
|
break;
|
|
}
|
|
for(g->nsub=0; x <= e; x += d, g->nsub++){
|
|
s = 0;
|
|
for(i=0; i<d; i++){
|
|
for(j=0; j<d; j++){
|
|
if(X[d*i+j] < 0 && x[j] == 0){
|
|
X[d*i+j]++;
|
|
x[j] = d+i;
|
|
s = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(s == 0)
|
|
break;
|
|
}
|
|
if(s != 0){
|
|
mpfree(g);
|
|
g = nil;
|
|
}
|
|
out:
|
|
jehanne_free(C);
|
|
jehanne_free(X);
|
|
mpfree(M);
|
|
mpfree(T);
|
|
return g;
|
|
}
|
|
|