File: ec_ap.c

package info (click to toggle)
sympow 2.023.7-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 496 kB
  • sloc: ansic: 3,871; sh: 687; makefile: 17
file content (137 lines) | stat: -rw-r--r-- 6,289 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "sympow.h"
#define DEBUG (FALSE || GLOBAL_DEBUG)

#define QD_split(a,hi,lo)\
{double xt=134217729.0*a,t1; t1=xt-a; hi=xt-t1; lo=a-hi;}
#define QD_prod(a,b,d,e)\
{double ah,al,bh,bl,u1,u2,u3; d=a*b; QD_split(a,ah,al); QD_split(b,bh,bl);\
 u1=ah*bh; u2=u1-d; u3=ah*bl; u1=u2+u3; u2=al*bh; u3=u1+u2; u2=al*bl; e=u2+u3;}
#define BIG_FLOAT 6755399441055744.0 /* 2^52+2^51 */
#define ROUND(x,r) {double y=(x),w1;  w1=y+BIG_FLOAT; r=w1-BIG_FLOAT;}
#define MUL(x,y,z,p)\
{double zhi,zlo,thi,tlo,fl,v1,v2; QD_prod((x),(y),zhi,zlo); ROUND(zhi/p,fl);\
 QD_prod(p,fl,thi,tlo); v1=zhi-thi; v2=zlo-tlo; z=v1+v2;}
#define INV(x,i,p)\
{double rr=0.0,ss=1.0,cc,aa=p,bb=x; while (1)\
 {ROUND(aa/bb,cc); aa-=bb*cc;\
  if (aa==0.0) {if (bb>0.0) i=ss; else i=-ss; break;} rr-=cc*ss;\
  ROUND(bb/aa,cc); bb-=aa*cc;\
  if (bb==0.0) {if (aa>0.0) i=rr; else i=-rr; break;} ss-=cc*rr;}}
#define NORMALISE(x,p) while ((x)>=(p)) (x)-=(p); while ((x)<0) (x)+=(p)

typedef struct {llint U; llint V;} PERALTA;

static void PMUL(PERALTA i1,PERALTA i2,PERALTA *o,llint d,llint p)
{double A,B,P=(double) p,D=(double) d,E,x,y; llint rU,rV;
 if (DEBUG>=2) printf("PMUL %lli %lli %lli %lli\n",i1.U,i1.V,i2.U,i2.V);
 x=(double) i1.V; y=(double) i2.U; MUL(x,y,A,P);
 x=(double) i2.V; y=(double) i1.U; MUL(x,y,B,P);
 rV=(llint) (A+B); while (rV<0) rV+=p; while (rV>=p) rV-=p;
 x=(double) i2.U; y=(double) i1.U; MUL(x,y,A,P);
 x=(double) i1.V; y=(double) i2.V; MUL(x,y,B,P); MUL(B,D,E,P);
 rU=(llint) (A+E); while (rU<0) rU+=p; while (rU>=p) rU-=p;
 (*o).U=rU; (*o).V=rV; if (DEBUG>=2) printf("RET %lli %lli\n",rU,rV);}

static void mod_exp_peralta(llint r,llint d,llint p,llint e,llint* u,llint *v)
{PERALTA c,m,o; llint le; o.U=r; o.V=1; m.U=1; m.V=0; c=o;
 le=e; for (e>>=1;e>0;e>>=1) {PMUL(c,c,&c,d,p); if (e&1) PMUL(m,c,&m,d,p);}
 if (le&1) PMUL(m,o,&m,d,p); (*u)=m.U; (*v)=m.V;}

static llint mod_sqrt_peralta(int d,llint p)
{llint r=314159,u,v; QD P,R,S; double V,i;
 if (DEBUG>=2) printf("mod_sqrt_peralta %i %lli\n",d,p);
 QD_copy(wmax,QD_zero,P); P[0]=(double) p;
 while (1)
 {r=(r+1)%p; R[0]=(double) r; QD_sqr(wmax,R,S);
  if (QD_modll(S,p)==p-d) return r; mod_exp_peralta(r,d,p,(p-1)/2,&u,&v);
  if (u==0) {V=(double) v; INV(V,i,P[0]); return (llint) i;}}}

static llint mod_sqrt(int d,llint p)
{QD P,M; QD_copy(wmax,QD_zero,P); P[0]=(double) p;
 if ((p&3)==3)
 {modular_exponentiation(d,P,(p+1)/4,M); return (llint) Round(M[0]);}
 else return mod_sqrt_peralta(d,p);}

static void cornaccia2(int d,llint p,llint *x,llint *y) /* x^2+d*y^2=4p */
{llint a,b,L,r; if (DEBUG>=2) printf("cornaccia2 %i %lli\n",d,p);
 a=p+p; b=mod_sqrt(-d,p); if ((b&1)!=(d&1)) b-=p;
 L=(llint) Floor(2.0*Sqrt((double) p));
 while ((b>L) || (b<-L)) {r=a%b; a=b; b=r;}
 *y=(llint) Round(Sqrt((((p<<2)-b*b)/d))); *x=b;
 if (*x<0) *x=-(*x); if (*y<0) *y=-(*y);}

static llint ap_j0(QD C6,llint pr)
{llint x,y,d,ap; QD P,R; if ((pr%3)!=1) return 0; cornaccia2(27,pr,&x,&y);
 if ((x%3)==1) x=-x;
 d=(8*QD_modll(C6,pr))%pr; QD_copy(wmax,QD_zero,P); P[0]=(double) pr;
 modular_exponentiation(d,P,(pr-1)/6,R);
 P[0]=(double) x; QD_mul(wmax,R,P,R); ap=QD_modll(R,pr);
 if (ap>pr/2) ap-=pr; return ap;}

static llint ap_j1728(QD C4,llint pr)
{llint x,y,d,ap; QD P,R; if ((pr&3)!=1) return 0; cornaccia2(4,pr,&x,&y);
 if ((x&3)==0) x=y; if ((x&1)==1) x=(x<<1); if ((x&7)==6) x=-x;
 d=(-27*QD_modll(C4,pr))%pr; QD_copy(wmax,QD_zero,P); P[0]=(double) pr;
 modular_exponentiation(d,P,(pr-1)/4,R);
 P[0]=(double) x; QD_mul(wmax,R,P,R); ap=QD_modll(R,pr);
 if (ap>pr/2) ap-=pr; return ap;}

static llint ap_j8000(llint pr)
{llint x,y; if (((pr&7)==5) || ((pr&7)==7)) return 0; cornaccia2(8,pr,&x,&y);
 if (((x&15)==2) || ((x&15)==6)) {if ((y&3)!=0) x=-x;}
 if (((x&15)==10) || ((x&15)==14)) {if ((y&3)==0) x=-x;}
 if (kronll(CM_TWIST,pr)==-1) x=-x; return x;}

static llint ap_j287496(llint pr)
{llint x,y; if ((pr&3)!=1) return 0; cornaccia2(4,pr,&x,&y);
 if ((x&3)==0) x=y; if ((x&1)==1) x=(x<<1); if ((x&7)==6) x=-x;
 if (kronll(2,pr)==-1) x=-x; if (kronll(CM_TWIST,pr)==-1) x=-x; return x;}

static llint ap_cm(int CM,llint pr)
{llint x,y; if (kronll((llint) CM,pr)!=1) return 0; cornaccia2(-CM,pr,&x,&y);
 if ((CM&3)==0) CM>>=2; if ((kronll(x,(llint) -CM)>0)^(CM==-7)) x=-x;
 if (kronll(CM_TWIST,pr)==-1) x=-x; return x;}

static llint ec_ap_cm(QD C4,QD C6,llint pr)
{switch (CM_CASE)
 {case -3: return ap_j0(C6,pr); case -4: return ap_j1728(C4,pr);
  case -8: return ap_j8000(pr); case -16: return ap_j287496(pr);
  case -28: return ap_cm(-7,pr); default: return ap_cm(CM_CASE,pr);}}

static llint ec_ap2(QD C4,QD C6)
{int a1,a2,a3,a4,a6,b2,b4,b6,c4,c6,ap; if (DEBUG) printf("ec_ap2\n");
 c4=QD_modi(C4,10077696); c6=QD_modi(C6,10077696);
 b2=-(c6%12); if (b2<-5) b2+=12; b4=(b2*b2-c4)/24;
 b6=(-b2*b2*b2+36*b2*b4-c6)/216;
 a1=b2%2; if (a1<0) a1=-a1; a2=(b2-a1)/4;
 a3=(b6%2); if (a3<0) a3=-a3; a4=(b4-a1*a3)/2; a6=(b6-a3)/4;
 a2=a2%2; if (a2<0) a2=-a2; a4=a4%2; if (a4<0) a4=-a4;
 a6=a6%2; if (a6<0) a6=-a6; ap=a1;
 if (DEBUG) printf("ec_ap2: %i %i %i %i %i\n",a1,a2,a3,a4,a6);
 if (a1==a3) ap=-ap; else if (a2!=a4) ap-=2; if (a6!=0) ap=-ap; return ap;}

static llint ec_ap3(QD C4,QD C6)
{int b2,b4,b6,c4,c6; if (DEBUG) printf("ec_ap3\n");
 c4=QD_modi(C4,10077696); c6=QD_modi(C6,10077696);
 b2=-(c6%12); if (b2<-5) b2+=12; b4=(b2*b2-c4)/24;
 b6=(-b2*b2*b2+36*b2*b4-c6)/216; b2=b2%3; b4=b4%3; b6=b6%3;
 if (DEBUG) printf("ec_ap3: %i %i %i\n",b2,b4,b6);
 return -(kron(b6,3)+kron(1+b2-b4+b6,3)+kron(-1+b2+b4+b6,3));}

static llint ec_ap_kron(QD C4,QD C6,llint pr)
{llint ap=0; int a4,a6,x; if (DEBUG) printf("ec_ap_kron %lli\n",pr);
 if (pr==2) return ec_ap2(C4,C6); if (pr==3) return ec_ap3(C4,C6);
 a4=(-27*QD_modi(C4,(double) pr))%pr; a6=(-54*QD_modi(C6,(double) pr))%pr;
 for (x=0;x<pr;x++) ap+=kron(x*x*x+a4*x+a6,(int) pr); return -ap;}

llint ec_ap(QD C4,QD C6,llint pr)
{QD D,T; if (DEBUG) printf("ec_ap %lli\n",pr);
 if (pr<500) return ec_ap_kron(C4,C6,pr);
 QD_powi(wmax,C4,3,T); QD_sqr(wmax,C6,D);
 QD_sub(wmax,T,D,T); QD_div1(wmax,T,1728.0,D); QD_round(wmax,D,D);
 return ec_ap_with_disc(C4,C6,D,pr);}

llint ec_ap_with_disc(QD C4,QD C6,QD D,llint pr)
{QD T; if (QD_valuation(D,(double) pr)!=0)
 {QD_neg(wmax,C6,T); return kronll(QD_modll(T,(double) pr),pr);}
 if (CM_CASE) return ec_ap_cm(C4,C6,pr); return ec_bsgs_ap(C4,C6,pr);}