Polygon zkEVM中Goldilocks域元素circom约束

1. 引言

前序博客有:

  • Goldilocks域

Goldilocks域 p = 2 64 − 2 32 + 1 p= 2^{64} - 2^{32} + 1 p=264232+1

Polygon zkEVM中Goldilock域元素circom约束,代码见:

  • https://github.com/0xPolygonHermez/pil-stark/tree/main/circuits.gl

2. Goldilocks域元素转换为二进制

将Goldilocks域元素转换为64位二进制表示:

//本质为`getPermutations`,获取nQueries个查询位置index
//Fibonacci例子中,查询位置index ys[0]~ys[7]的取值范围为0~(2^{11}-1)【即以11个bit来表示】

//以transcript中获取的challenge为输入,获得相应的二进制表示
component tcN2b_0 = Num2Bits_strict();
tcN2b_0.in <== tcHahs_8.out[0];
//以transcript中获取的challenge为输入,获得相应的二进制表示
component tcN2b_1 = Num2Bits_strict();
tcN2b_1.in <== tcHahs_8.out[1];

其中:【CompConstant(-1) 用于约束输入为有效Goldilocks域元素: [ 0 , p − 1 ] [0,p-1] [0,p1]。】

template Num2Bits_strict() {
    signal input in; //输入为Goldilocks域元素
    signal output out[64]; //输出为64位二进制值

    component aliasCheck = AliasCheck();
    component n2b = Num2Bits(64); //将Goldilocks域元素转换为64位二进制值
    in ==> n2b.in;

    for (var i=0; i<64; i++) {
        n2b.out[i] ==> out[i];
        n2b.out[i] ==> aliasCheck.in[i]; //将每个二进制bit给AliasCheck
    }
}
template AliasCheck() {

    signal input in[64]; //输入为64位二进制值
	//约束64位二进制值 <= -1
	//即 约束Goldilocks域元素转换后的64位二进制值 仍为 0~(p-1)
    component  compConstant = CompConstant(-1);

    for (var i=0; i<64; i++) in[i] ==> compConstant.in[i]; //将每个二进制bit给CompConstant

    compConstant.out === 0;//约束CompConstant输出恒为0
}

template Num2Bits(n) {//将Goldilocks域元素转换为64位二进制值
    signal input in;
    signal output out[n];
    var lc1=0;

    var e2=1;
    for (var i = 0; i> i) & 1;
        out[i] * (out[i] -1 ) === 0;
        lc1 += out[i] * e2;
        e2 = e2+e2;
    }

    lc1 === in;
}
/*
cm cl sm sl   res
0  0  0  0      0
      0  1      1
      1  0      1
      1  1      1        sm + sl - sm*sl

0  1  0  0     -1
      0  1      0
      1  0      1
      1  1      1        -1 + sl + 2*sm - sm*sl

1  0  0  0     -1
      0  1     -1
      1  0      0
      1  1      1        sm*sl -1  +sm

1  1  0  0     -1
      0  1     -1
      1  0     -1
      1  1      0        sm*sl -1

*/
// Returns 1 if in (in binary) > ct
template CompConstant(ct) { //ct值为-1
    signal input in[64]; //输入为64位二进制值
    signal output out;

    signal parts[32]; //中间值
    signal sout; //中间值
	//变量
    var clsb;
    var cmsb;
    var sl;
    var sm;

    signal sum[32]; //中间值

    var e = 1;
    var i;

    for (i=0;i<32; i++) {
        clsb = (ct >> (i*2)) & 1;
        cmsb = (ct >> (i*2+1)) & 1;
        sl = in[i*2];
        sm = in[i*2+1];

        if ((cmsb==0)&&(clsb==0)) {
            parts[i] <== sm*e + sl*e -sm*sl*e;
        } else if ((cmsb==0)&&(clsb==1)) {
            parts[i] <== -e + e*sl + e*2*sm - e*sm*sl;
        } else if ((cmsb==1)&&(clsb==0)) {
            parts[i] <== e*sm*sl -e  +e*sm;
        } else {
            parts[i] <== e*sm*sl -e;
        }

        if (i==0) {
            sum[i] <== (1<<32)-1 + parts[i];
        } else {
            sum[i] <== sum[i-1] + parts[i];
        }

        e = e*2;
    }

    component num2bits = Num2Bits(33);

    num2bits.in <== sum[31];

    out <== num2bits.out[32];
}

3. Goldilocks extension 3 域元素运算

3.1 Goldilocks extension 3 域元素乘法运算

Goldilocks域元素乘法运算为:

	mul(a, b) {
        if (typeof(a) == "bigint") {
            if (typeof(b) == "bigint") { //2个基域元素相乘
                return (a*b) % this.p;
            } else { //基域元素 * extension 3域元素
                return [(a*b[0]) % this.p,  (a*b[1]) % this.p, (a*b[2]) % this.p];
            }
        } else if (typeof(b) == "bigint") { //extension 3域元素 * extension 3域元素
            return [(a[0]*b) % this.p,  (a[1]*b) % this.p, (a[2]*b) % this.p];
        } else { //2个extension 3域元素相乘
            const A = (a[0] + a[1])  * (b[0] + b[1]);
            const B = (a[0] + a[2])  * (b[0] + b[2]);
            const C = (a[1] + a[2])  * (b[1] + b[2]);
            const D = a[0]*b[0];
            const E = a[1]*b[1];
            const F = a[2]*b[2];
            const G = D - E;

            return [ (C + G - F)%this.p,  (A + C - E -E - D )%this.p,(B-G)%this.p ];
        }
    }

2个Goldilocks extension 3 域元素相乘的circom约束为:【事实上是只计算,未约束】

template custom CMul() { // 计算out = ina * inb
    signal input ina[3];
    signal input inb[3];
    signal output out[3];

    var A = (ina[0] + ina[1])  * (inb[0] + inb[1]);
    var B = (ina[0] + ina[2])  * (inb[0] + inb[2]);
    var C = (ina[1] + ina[2])  * (inb[1] + inb[2]);
    var D = ina[0]*inb[0];
    var E = ina[1]*inb[1];
    var F = ina[2]*inb[2];
    var G = D-E;

    out[0] <-- C+G-F; //只赋值,未约束
    out[1] <-- A+C-E-E-D; //只赋值,未约束
    out[2] <-- B-G; //只赋值,未约束
}

3.2 Goldilocks extension 3 域元素倒数运算

Goldilocks域元素倒数运算为:

	/*
        Formula deducted here: https://www.polymathlove.com/polymonials/midpoint-of-a-line/symbolic-equation-solving.html#c=solve_algstepsequationsolvesystem&v247=d%252Ce%252Cf&v248=3&v249=f*a%2Bb*e%2Bd*c%2B%2520c*f%2520%253D%25200&v250=d*b%2Be*a%2Bc*f%2Bb*f%2Be*c%253D0&v251=a*d%2Bb*f%2Be*c%253D1
    */
    inv(a) {
        if (typeof(a) == "bigint") { //Goldilocks基域求倒数
            return this._inv1(a);
        } else { //Goldilocks extension 3 域求倒数
            const aa = a[0] * a[0];
            const ac = a[0] * a[2];
            const ba = a[1] * a[0];
            const bb = a[1] * a[1];
            const bc = a[1] * a[2];
            const cc = a[2] * a[2];

            const aaa = aa * a[0];
            const aac = aa * a[2];
            const abc = ba * a[2];
            const abb = ba * a[1];
            const acc = ac * a[2];
            const bbb = bb * a[1];
            const bcc = bc * a[2];
            const ccc = cc * a[2];

            let t = (-aaa -aac-aac +abc+abc+abc + abb - acc - bbb + bcc - ccc)%this.p;

            if (t<0n) t = t + this.p;

            const tinv = this._inv1(t);

            let i1 = ((-aa -ac-ac +bc + bb - cc)*tinv) % this.p;
            let i2 = ((ba -cc)*tinv) % this.p;
            let i3 = ((-bb +ac + cc)*tinv) % this.p;

            if (i1<0) i1 = this.p+i1;
            if (i2<0) i2 = this.p+i2;
            if (i3<0) i3 = this.p+i3;

            return [i1, i2, i3];
        }
    }

    _inv1(a) {
        if (!a) throw new Error("Division by zero");

        let t = this.zero;
        let r = this.p;
        let newt = this.one;
        let newr = a % this.p;
        while (newr) {
            let q = r/newr;
            [t, newt] = [newt, t-q*newt];
            [r, newr] = [newr, r-q*newr];
        }
        if (t<this.zero) t += this.p;
        return t;
    }

相应的约束为:

template CInv() { //计算out=1/in
    signal input in[3];
    signal output out[3];

    var aa = in[0] * in[0];
    var ac = in[0] * in[2];
    var ba = in[1] * in[0];
    var bb = in[1] * in[1];
    var bc = in[1] * in[2];
    var cc = in[2] * in[2];

    var aaa = aa * in[0];
    var aac = aa * in[2];
    var abc = ba * in[2];
    var abb = ba * in[1];
    var acc = ac * in[2];
    var bbb = bb * in[1];
    var bcc = bc * in[2];
    var ccc = cc * in[2];

    var t = -aaa -aac-aac +abc+abc+abc + abb - acc - bbb + bcc - ccc;
    var tinv = 1/t;

    out[0] <--  (-aa -ac-ac +bc + bb - cc)*tinv; //只赋值,未约束
    out[1] <--  (ba -cc)*tinv; //只赋值,未约束
    out[2] <--  (-bb +ac + cc)*tinv; //只赋值,未约束

    component check = CMul(); //约束in*out=1
    check.ina[0] <== in[0];
    check.ina[1] <== in[1];
    check.ina[2] <== in[2];
    check.inb[0] <== out[0];
    check.inb[1] <== out[1];
    check.inb[2] <== out[2];
    check.out[0] === 1;
    check.out[1] === 0;
    check.out[2] === 0;
}

参考资料

[1] Circom 2 文档——Basic Operators

附录:Polygon Hermez 2.0 zkEVM系列博客

  • ZK-Rollups工作原理
  • Polygon zkEVM——Hermez 2.0简介
  • Polygon zkEVM网络节点
  • Polygon zkEVM 基本概念
  • Polygon zkEVM Prover
  • Polygon zkEVM工具——PIL和CIRCOM
  • Polygon zkEVM节点代码解析
  • Polygon zkEVM的pil-stark Fibonacci状态机初体验
  • Polygon zkEVM的pil-stark Fibonacci状态机代码解析
  • Polygon zkEVM PIL编译器——pilcom 代码解析
  • Polygon zkEVM Arithmetic状态机
  • Polygon zkEVM中的常量多项式
  • Polygon zkEVM Binary状态机
  • Polygon zkEVM Memory状态机
  • Polygon zkEVM Memory Align状态机
  • Polygon zkEVM zkASM编译器——zkasmcom
  • Polygon zkEVM哈希状态机——Keccak-256和Poseidon
  • Polygon zkEVM zkASM语法
  • Polygon zkEVM可验证计算简单状态机示例
  • Polygon zkEVM zkASM 与 以太坊虚拟机opcode 对应集合
  • Polygon zkEVM zkROM代码解析(1)
  • Polygon zkEVM zkASM中的函数集合
  • Polygon zkEVM zkROM代码解析(2)
  • Polygon zkEVM zkROM代码解析(3)
  • Polygon zkEVM公式梳理
  • Polygon zkEVM中的Merkle tree

你可能感兴趣的:(零知识证明,circom)