前序博客:
代码见:
const pgroup_c = F.ifft(pgroup_e);
// Adjustable parametees
const maxBlockBits = 16;
const minBlockBits = 12;
//const maxBlockBits = 2;
//const minBlockBits = 2;
const blocksPerThread = 8;
async function _fft(buffSrc, nPols, nBits, buffDst, inverse) {
const n = 1 << nBits;
const tmpBuff = new BigBuffer(n*nPols);
const outBuff = buffDst;
let bIn, bOut;
const pool = workerpool.pool(__dirname + '/fft_worker.js');
const idealNBlocks = pool.maxWorkers*blocksPerThread;
let blockBits = log2(n*nPols/idealNBlocks);
if (blockBits < minBlockBits) blockBits = minBlockBits;
if (blockBits > maxBlockBits) blockBits = maxBlockBits;
blockBits = Math.min(nBits, blockBits);
const blockSize = 1 << blockBits;
const nBlocks = n / blockSize;
let nTrasposes;
if (nBits == blockBits) {
nTrasposes = 0;
} else {
nTrasposes = Math.floor((nBits-1) / blockBits)+1;
}
if (nTrasposes & 1) {
bOut = tmpBuff;
bIn = outBuff;
} else {
bOut = outBuff;
bIn = tmpBuff;
}
if (inverse) {
await invBitReverse(bOut, buffSrc, nPols, nBits);
} else {
await bitReverse(bOut, buffSrc, nPols, nBits);
}
[bIn, bOut] = [bOut, bIn];
for (let i=0; i<nBits; i+= blockBits) {
const sInc = Math.min(blockBits, nBits-i);
const promisesFFT = [];
// let results = [];
for (j=0; j<nBlocks; j++) {
const bb = bIn.slice(j*blockSize*nPols, (j+1)*blockSize*nPols);
promisesFFT.push(pool.exec("fft_block", [bb, j*blockSize, nPols, nBits, i+sInc, blockBits, sInc]));
// results[j] = await fft_block(bb, j*blockSize, nPols, nBits, i+sInc, blockBits, sInc);
}
const results = await Promise.all(promisesFFT);
for (let i=0; i<results.length; i++) {
bIn.set(results[i], i*blockSize*nPols)
}
if (sInc < nBits) { // Do not transpose if it's the same
await traspose(bOut, bIn, nPols, nBits, sInc);
[bIn, bOut] = [bOut, bIn];
}
}
await pool.terminate();
}
async function fft(buffSrc, nPols, nBits, buffDst) {
await _fft(buffSrc, nPols, nBits, buffDst, false)
}
async function ifft(buffSrc, nPols, nBits, buffDst) {
await _fft(buffSrc, nPols, nBits, buffDst, true)
}
Goldilocks域 p = 2 64 − 2 32 + 1 p= 2^{64} - 2^{32} + 1 p=264−232+1。其支持最大FFT运算degree为32:【roots[i]
对应为 2 i 2^i 2i-th root of unity。】
var roots[33] = [
1, // 2^0-th root of unity
18446744069414584320, // 2^1-th root of unity
281474976710656, // 2^2-th root of unity
18446744069397807105,
17293822564807737345,
70368744161280,
549755813888,
17870292113338400769,
13797081185216407910,
1803076106186727246,
11353340290879379826,
455906449640507599,
17492915097719143606,
1532612707718625687,
16207902636198568418,
17776499369601055404,
6115771955107415310,
12380578893860276750,
9306717745644682924,
18146160046829613826,
3511170319078647661,
17654865857378133588,
5416168637041100469,
16905767614792059275,
9713644485405565297,
5456943929260765144,
17096174751763063430,
1213594585890690845,
6414415596519834757,
16116352524544190054,
9123114210336311365,
4614640910117430873,
1753635133440165772 // 2^{32}-th root of unity
];
FFT(nBits, eSize, inv , shift)
中inv
为1表示iFFT,为0表示FFT。nBits
表示对应 2 nBits − 1 2^{\text{nBits}}-1 2nBits−1 degree多项式。eSize
表示每个元素的宽度。shift
表示偏移。
template FFT(nBits, eSize, inv , shift) {
var n = 1<> 1;
wm = roots(s);
for (var k=0; k
const ev = evalPol(F, pgroup_c, F.mul(special_x[si], sinv));
module.exports.evalPol = function evalPol(F, p, x) {
if (p.length == 0) return F.zero;
let res = p[p.length-1];
for (let i=p.length-2; i>=0; i--) {
res = F.add(F.mul(res, x), p[i]);
}
return res;
}
template EvalPol(n) {
signal input pol[n][3];
signal input x[3];
signal output out[3];
signal acc[n][3];
component cmul[n-1];
for (var e=0; e<3; e++) {
acc[0][e] <== pol[n-1][e];
}
for (var i=1; i