Skip to content

Commit 0270cea

Browse files
committed
Polynomial division done
1 parent 8bc1bb6 commit 0270cea

File tree

7 files changed

+699
-22
lines changed

7 files changed

+699
-22
lines changed

aux/calculate2roots.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
const bigInt = require("../src/bigint.js");
3+
const ZqField = require("../src/zqfield.js");
4+
5+
6+
const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
7+
const s = 28;
8+
const nqr_to_t = bigInt("19103219067921713944291392827692070036145651957329286315305642004821462161904");
9+
const t_minus_1_over_2 = bigInt("40770029410420498293352137776570907027550720424234931066070132305055");
10+
const root_unity = bigInt("19103219067921713944291392827692070036145651957329286315305642004821462161904");
11+
const t = bigInt("81540058820840996586704275553141814055101440848469862132140264610111");
12+
13+
const F = new ZqField(r);
14+
15+
function sqrt(a) {
16+
17+
let v = s;
18+
let z = nqr_to_t;
19+
let w = F.exp(a, t_minus_1_over_2);
20+
let x = F.mul(a, w);
21+
let b = F.mul(x, w);
22+
23+
24+
// compute square root with Tonelli--Shanks
25+
// (does not terminate if not a square!)
26+
27+
while (!F.equals(b, F.one))
28+
{
29+
let m = 0;
30+
let b2m = b;
31+
while (!F.equals(b2m, F.one))
32+
{
33+
/* invariant: b2m = b^(2^m) after entering this loop */
34+
b2m = F.square(b2m);
35+
m += 1;
36+
}
37+
38+
let j = v-m-1;
39+
w = z;
40+
while (j > 0)
41+
{
42+
w = F.square(w);
43+
--j;
44+
} // w = z^2^(v-m-1)
45+
46+
z = F.square(w);
47+
b = F.mul(b, z);
48+
x = F.mul(x, w);
49+
v = m;
50+
}
51+
52+
return x;
53+
}
54+
55+
const p_minus1= F.sub(r,bigInt(1));
56+
const gen = bigInt(bigInt(5));
57+
const twoto28= F.exp(bigInt(2), bigInt(28));
58+
const rem = F.div(p_minus1, twoto28);
59+
const w28 = F.exp(gen, rem);
60+
61+
const one = F.exp(w28, twoto28);
62+
63+
64+
console.log(F.toString(w28));
65+
console.log(w28.toString(10));
66+
console.log(F.toString(one));
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
/*
2+
This library do operations on polinomials where their coefficients are in field F
3+
4+
The polynomial P(x) = p0 + p1 * x + p2 * x^2 + p3 * x^3, ...
5+
is represented by the array [ p0, p1, p2, p3, ... ]
6+
*/
7+
8+
const bigInt = require("./bigInt");
9+
const ZqField = require("./zqfield");
10+
11+
class PolFieldZq {
12+
constructor (q) {
13+
this.F = new ZqField(q);
14+
15+
let rem = q.sub(bigInt(1));
16+
let s = 0;
17+
while (!rem.isOdd()) {
18+
s ++;
19+
rem = rem.shiftRight(1);
20+
}
21+
22+
this.w = new Array(s+1);
23+
this.wi = new Array(s+1);
24+
this.w[s] = this.F.exp(bigInt(5), rem);
25+
this.wi[s] = this.F.inverse(this.w[s]);
26+
27+
let n=s-1;
28+
while (n>=0) {
29+
this.w[n] = this.F.square(this.w[n+1]);
30+
this.wi[n] = this.F.square(this.wi[n+1]);
31+
n--;
32+
}
33+
34+
}
35+
36+
add(a, b) {
37+
const m = Math.max(a.length, b.length);
38+
const res = new Array(m);
39+
for (let i=0; i<m; i++) {
40+
res[i] = this.F.add(a[i] || this.F.zero, b[i] || this.F.zero);
41+
}
42+
return this.reduce(res);
43+
}
44+
45+
double(a) {
46+
return this.add(a,a);
47+
}
48+
49+
sub(a, b) {
50+
const m = Math.max(a.length, b.length);
51+
const res = new Array(m);
52+
for (let i=0; i<m; i++) {
53+
res[i] = this.F.sub(a[i] || this.F.zero, b[i] || this.F.zero);
54+
}
55+
return this.reduce(res);
56+
}
57+
58+
mulEscalar(a, b) {
59+
if (this.F.isZero(b)) return [];
60+
const res = new Array(a.length);
61+
for (let i=0; i<a.length; i++) {
62+
res[i] = this.F.mul(a[i], b);
63+
}
64+
return res;
65+
}
66+
67+
mul(a, b) {
68+
if (a.length == 0) return [];
69+
if (b.length == 0) return [];
70+
if (a.length == 1) return this.mulEscalar(b, a[0]);
71+
if (b.length == 1) return this.mulEscalar(a, b[0]);
72+
73+
const longestN = Math.max(a.length, b.length);
74+
const bitsResult = log2(longestN-1)+2;
75+
const m = 1 << bitsResult;
76+
const ea = this.extend(a,m);
77+
const eb = this.extend(b,m);
78+
79+
const ta = this._fft(ea, bitsResult, 0, 1, false);
80+
const tb = this._fft(eb, bitsResult, 0, 1, false);
81+
82+
const tres = new Array(m);
83+
84+
for (let i=0; i<m; i++) {
85+
tres[i] = this.F.mul(ta[i], tb[i]);
86+
}
87+
88+
const res = this._fft(tres, bitsResult, 0, 1, true);
89+
90+
const twoinvm = this.F.inverse(bigInt(m));
91+
const resn = new Array(m);
92+
for (let i=0; i<m; i++) {
93+
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
94+
}
95+
96+
return this.reduce(this.affine(resn));
97+
}
98+
99+
square(a) {
100+
return this.mul(a,a);
101+
}
102+
103+
scaleX(p, n) {
104+
if (n==0) {
105+
return p;
106+
} else if (n>0) {
107+
const z = new Array(n).fill(this.F.zero);
108+
return z.concat(p);
109+
} else {
110+
return p.slice(-n);
111+
}
112+
}
113+
114+
div(a, b) {
115+
throw new Error("Not Implementted");
116+
}
117+
118+
eval(p, x) {
119+
let v = this.F.zero;
120+
let ix = this.F.one;
121+
for (let i=0; i<p.length; i++) {
122+
v = this.F.add(v, this.F.mul(p[i], ix));
123+
ix = this.F.mul(ix, x);
124+
}
125+
return v;
126+
}
127+
128+
lagrange(points) {
129+
throw new Error("Not Implementted");
130+
}
131+
132+
_fft(pall, bits, offset, step) {
133+
134+
const n = 1 << bits;
135+
if (n==1) {
136+
return [ pall[offset] ];
137+
}
138+
139+
const ndiv2 = n >> 1;
140+
const p1 = this._fft(pall, bits-1, offset, step*2);
141+
const p2 = this._fft(pall, bits-1, offset+step, step*2);
142+
143+
const out = new Array(n);
144+
145+
let m= bigInt(1);
146+
for (let i=0; i<ndiv2; i++) {
147+
out[i] = this.F.add(p1[i], this.F.mul(m, p2[i]));
148+
out[i+ndiv2] = this.F.sub(p1[i], this.F.mul(m, p2[i]));
149+
m = this.F.mul(m, this.w[bits]);
150+
}
151+
152+
return out;
153+
}
154+
155+
extend(p, e) {
156+
if (e == p.length) return p;
157+
const z = new Array(e-p.length).fill(this.F.zero);
158+
159+
return p.concat(z);
160+
}
161+
162+
reduce(p) {
163+
if (p.length == 0) return p;
164+
if (! this.F.isZero(p[p.length-1]) ) return p;
165+
let i=p.length-1;
166+
while( i>0 && this.F.isZero(p[i]) ) i--;
167+
return p.slice(0, i+1);
168+
}
169+
170+
affine(p) {
171+
for (let i=0; i<p.length; i++) {
172+
p[i] = this.F.affine(p[i]);
173+
}
174+
return p;
175+
}
176+
177+
equals(a, b) {
178+
const pa = this.reduce(this.affine(a));
179+
const pb = this.reduce(this.affine(b));
180+
181+
if (pa.length != pb.length) return false;
182+
for (let i=0; i<pb.length; i++) {
183+
if (!this.F.equals(pa[i], pb[i])) return false;
184+
}
185+
186+
return true;
187+
}
188+
189+
_next2Power(v) {
190+
v--;
191+
v |= v >> 1;
192+
v |= v >> 2;
193+
v |= v >> 4;
194+
v |= v >> 8;
195+
v |= v >> 16;
196+
v++;
197+
return v;
198+
}
199+
200+
toString(p) {
201+
const ap = this.affine(p);
202+
let S = "";
203+
for (let i=ap.length-1; i>=0; i--) {
204+
if (!this.F.isZero(p[i])) {
205+
if (S!="") S += " + ";
206+
S = S + p[i].toString(10);
207+
if (i>0) {
208+
S = S + "x";
209+
if (i>1) {
210+
S = S + "^" +i;
211+
}
212+
}
213+
}
214+
}
215+
return S;
216+
}
217+
218+
219+
_reciprocal(p, bits) {
220+
const k = 1 << bits;
221+
if (k==1) {
222+
return [ this.F.inverse(p[0]) ];
223+
}
224+
const np = this.scaleX(p, -k/2);
225+
const q = this._reciprocal(np, bits-1);
226+
const a = this.scaleX(this.double(q), 3*k/2-2);
227+
const b = this.mul( this.square(q), p);
228+
229+
return this.scaleX(this.sub(a,b), -(k-2));
230+
}
231+
232+
// divides x^m / v
233+
_div2(m, v) {
234+
const kbits = log2(v.length-1)+1;
235+
const k = 1 << kbits;
236+
237+
const scaleV = k - v.length;
238+
239+
// rec = x^(k - 2) / v* x^scaleV =>
240+
// rec = x^(k-2-scaleV)/ v
241+
//
242+
// res = x^m/v = x^(m +(2k-2-scaleV) -(2k-2-scaleV)) /v =>
243+
// res = rec * x^(m - (2k-2-scaleV)) =>
244+
// res = rec * x^(m - 2k +2 + scaleV)
245+
246+
const rec = this._reciprocal(this.scaleX(v, scaleV), kbits);
247+
const res = this.scaleX(rec, m - k*2 +2+scaleV);
248+
249+
return res;
250+
251+
}
252+
253+
}
254+
255+
function log2( V )
256+
{
257+
return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) );
258+
}
259+
260+
module.exports = PolFieldZq;

src/bigint.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ const bigInt = require("big-integer");
33

44
let wBigInt;
55

6-
console.log("XXX");
7-
86
if (typeof(BigInt) != "undefined") {
97
wBigInt = BigInt;
108
wBigInt.one = wBigInt(1);

0 commit comments

Comments
 (0)