Polygon zkEVM FFT和多项式evaluate计算的circom约束

Posted mutourend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Polygon zkEVM FFT和多项式evaluate计算的circom约束相关的知识,希望对你有一定的参考价值。

1. 引言

前序博客:

代码见:

2. FFT运算的circom约束

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=264232+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^\\textnBits-1 2nBits1 degree多项式。eSize表示每个元素的宽度。shift表示偏移。

template FFT(nBits, eSize, inv , shift) 
    var n = 1<<nBits;

    signal input in[n][eSize];
    signal output out[n][eSize];

    assert( (1 << nBits) == n);
    assert(nBits <= 32);

    signal buffers[nBits-1][n][eSize];

    var shifts[n];
    var ss = inv ? 1/shift : shift;
    shifts[0] = 1;
    for (var i=1; i<n; i++) 
        shifts[i] = shifts[i-1] * ss;
    

    var m, wm, w, mdiv2;
    var i1 =0;
    var i2=0;
    var s1=0;
    var s2=0;
    var twoinv = 1/n;
    for (var s=1; s<=nBits; s++) 
        m = 1 << s;
        mdiv2 = m >> 1;
        wm = roots(s);
        for (var k=0; k<n; k+= m) 
            w = 1;
            for (var j=0; j<mdiv2; j++) 
                for (var e=0; e<eSize; e++) 
                    if (s==1) 
                        i1 =rev(k+j, nBits);
                        i2 = rev(k+j+mdiv2, nBits);
                        if (inv == 1) 
                            s1 = 1;
                            s2 = 1;
                         else 
                            s1 = shifts[i1];
                            s2 = shifts[i2];
                        
                        buffers[s-1][k+j][e] <== s1*in[i1][e] + s2*w*in[i2][e];
                        buffers[s-1][k+j+mdiv2][e] <== s1*in[i1][e] - s2*w*in[i2][e];
                     else if (s<nBits) 
                        buffers[s-1][k+j][e] <== buffers[s-2][k+j][e] + w*buffers[s-2][k+j+mdiv2][e];
                        buffers[s-1][k+j+mdiv2][e] <== buffers[s-2][k+j][e] - w*buffers[s-2][k+j+mdiv2][e];
                     else 
                        if (inv) 
                            i1 = (n-k-j)%n;
                            i2 = (n-k-j-mdiv2)%n;
                            s1 = shifts[i1]*twoinv;
                            s2 = shifts[i2]*twoinv;
                         else 
                            i1 = k+j;
                            i2 = k+j+mdiv2;
                            s1 = 1;
                            s2 = 1;
                        
                        out[i1][e] <== s1*buffers[s-2][k+j][e] + s1*w*buffers[s-2][k+j+mdiv2][e];
                        out[i2][e] <== s2*buffers[s-2][k+j][e] - s2*w*buffers[s-2][k+j+mdiv2][e];
                    
                
                w=w*wm;
            
        
    


3. 多项式evaluate计算circom约束

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<n; i++) 
        cmul[i-1] = CMul();
        cmul[i-1].ina[0] <== acc[i-1][0];
        cmul[i-1].ina[1] <== acc[i-1][1];
        cmul[i-1].ina[2] <== acc[i-1][2];
        cmul[i-1].inb[0] <== x[0];
        cmul[i-1].inb[1] <== x[1];
        cmul[i-1].inb[2] <== x[2];
        acc[i][0] <== cmul[i-1].out[0] + pol[n-1-i][0];
        acc[i][1] <== cmul[i-1].out[1] + pol[n-1-i][1];
        acc[i][2] <== cmul[i-1].out[2] + pol[n-1-i][2];
    

    out[0] <== acc[n-1][0];
    out[1] <== acc[n-1][1];
    out[2] <== acc[n-1][2];

附录:Polygon Hermez 2.0 zkEVM系列博客

以上是关于Polygon zkEVM FFT和多项式evaluate计算的circom约束的主要内容,如果未能解决你的问题,请参考以下文章

Polygon zkEVM Binary状态机

Polygon zkEVM公式梳理

Polygon zkEVM哈希状态机——Keccak-256和Poseidon

Polygon zkEVM zkASM语法

Polygon zkEVM Memory状态机

Polygon zkEVM Memory Align状态机