Polygon zkEVM Merkle tree的circom约束

Posted mutourend

tags:

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

1. 引言

前序博客有:

代码见:

2. Poseidon哈希circom约束

3. LinearHash circom约束

template LinearHash(nInputs, eSize) 

    signal input in[nInputs][eSize]; //输入in元素数为nInputs*eSize
    signal output out[4];


    var nHashes;

    if (nInputs*eSize <= 4) 
        nHashes = 0;
     else 
        nHashes = (nInputs*eSize - 1)\\8 +1;
    

    component hash[nHashes];

    if (nInputs*eSize <= 4) 
        var curI=0;
        var curE=0;
        for (var i=0; i<4; i++) 
            if (i<nInputs*eSize) 
                out[i] <== in[curI][curE];
                curE = curE +1;
                if (curE == eSize) 
                    curE =0;
                    curI ++;
                
            
        
     else 

        var curInput=0;
        var curC=0;

        for (var i=0; i<nHashes; i++) 
            hash[i] = Poseidon(4);
            for (var k=0; k<8; k++) 
                if (curInput<nInputs) 
                    hash[i].in[k] <== in[curInput][curC];
                    curC++;
                    if (curC == eSize) 
                        curC =0;
                        curInput += 1;
                    
                 else 
                    hash[i].in[k] <== 0;
                
            
            for (var k=0; k<4; k++) 
                if (i>0) 
                    hash[i].capacity[k] <== hash[i-1].out[k];
                 else 
                    hash[i].capacity[k] <== 0;
                
            
        

        for (var k=0; k<4; k++) 
            out[k] <== hash[nHashes-1].out[k];
        
    

4. Merkle tree circom约束

template Merkle(nLevels)  //nLevels表示树高度

    signal input value[4]; //叶子节点数据对应4个Goldilocks元素
    signal input siblings[nLevels][4]; //每个节点哈希值对应4个Goldilocks元素
    signal input key[nLevels]; //key数组表示所在各层的位置
    signal output root[4];

    component hash[nLevels];

    for (var i=0; i<nLevels; i++) 
        hash[i] = Poseidon(4);
        for (var k=0; k<4; k++) 
            if (i>0) 
                hash[i].in[k  ] <== key[i]*(siblings[i][k]   - hash[i-1].out[k]) + hash[i-1].out[k];
                hash[i].in[k+4] <== key[i]*(hash[i-1].out[k] - siblings[i][k]  ) + siblings[i][k];
             else 
                hash[i].in[k] <== key[i]*(siblings[i][k]   - value[k]        ) + value[k];
                hash[i].in[k+4] <== key[i]*(value[k]         - siblings[i][k]  ) + siblings[i][k];
            
            hash[i].capacity[k] <== 0;
        
    

    for (var k=0; k<4; k++) 
        root[k] <== hash[nLevels-1].out[k];
    


5. MerkleHash circom约束

MerkleHash本质为:以values、siblings、key为输入,以root为输出,验证相应的Merkle证明与root是否匹配。
s0_merkle1[q] = MerkleHash(1, 2, 2048)=MerkleHash(eSize, elementsInLinear, nLinears) 为例:

  • 1)eSize:表示单个数据所需的Goldilocks元素数
  • 2)elementsInLinear:表示叶子节点对应的数据数
  • 3)nLinears:表示Merkle树中总的节点树
template MerkleHash(eSize, elementsInLinear, nLinears) 
    var nBits = log2(nLinears); //2^11=2048,nBits为Merkle树高度
    assert(1 << nBits == nLinears); //要求nLinears为2的某幂次运算
    signal input values[elementsInLinear][eSize]; //values[2][1]
    signal input siblings[nBits][4]; //Merkle证明路径,每个节点为哈希值对应4个Goldilocks元素。
    signal input key[nBits];  //key数组表示所在各层的位置
    signal output root[4];
	
	 //对 叶子节点下原始数据进行处理,为4个Goldilocks元素。
    component linearHash = LinearHash(elementsInLinear, eSize);

    for (var i=0; i<elementsInLinear; i++) 
        for (var e=0; e<eSize; e++) 
            linearHash.in[i][e] <== values[i][e];
        
    

    component merkle = Merkle(nBits); //nBits为树高度

    for (var i=0; i<4; i++)  //LinearHash处理后的数据作为Merkle树的叶子节点源数据
        merkle.value[i] <== linearHash.out[i];
    
    for (var i=0; i<nBits; i++) 
        merkle.key[i] <== key[i];
        for (var j=0; j<4; j++) 
            merkle.siblings[i][j] <== siblings[i][j];
        
    
    for (var i=0; i<4; i++) 
        root[i] <== merkle.root[i];
    

6. TreeSelector

		s0_lowValues[q] = TreeSelector(4, 3) ; //对应get3(proof[si+1].polQueries[i][0], groupIdx)
		//signal input s1_vals[8][48]; // fri 1 tree对应查询点的叶子节点(针对Goldilocks extension 3域),48为对应叶子width, 
                                 // 即: (1 << (starkStruct.steps[s-1].nBits -   starkStruct.steps[s].nBits))*3
        for (var i=0; i<16; i++) 
            for (var e=0; e<3; e++) 
                s0_lowValues[q].values[i][e] <== s1_vals[q][i*3+e];//即FRI下一层的叶子节点数据内容
            
        
        // 取FRI下一层的查询位置
        for (var i=0; i<4; i++) //key数组表示所在各层的位置
            s0_lowValues[q].key[i] <== ys[q][i + 7]; //表示的即为const groupIdx  =Math.floor(ys[i] / nextNGroups);
        
        // 对应约束F.eq(get3(proof[si+1].polQueries[i][0], groupIdx), ev)
        for (var e=0; e<3; e++) 
            s0_lowValues[q].out[e] === verifyQueries[q].out[e];
        

其中verifyQueries对应VerifyQuery模板,用于验证FRI中step0的各Merkle tree中查询位置约束关系,对应starkInfo.verifierQueryCode中计算。

s0_lowValues[q] = TreeSelector(4, 3) ;为例,表示:

template TreeSelector(nLevels, eSize) 

    var n = 1 << nLevels;
    signal input values[n][eSize];
    signal input key[nLevels];
    signal output out[eSize];

    signal im[n-1][eSize];

    var levelN = n\\2;
    var o = 0;
    var lo = 0;
    for (var i=0; i<nLevels; i++) 
        for (var j=0; j<levelN; j++) 
            for (var k=0; k<eSize; k++) 
                if (i==0) 
                    im[o+j][k] <== key[i]*(values[2*j+1][k]  - values[2*j][k])  + values[2*j][k];
                 else 
                    im[o+j][k] <== key[i]*(im[lo + 2*j+1][k] - im[lo + 2*j][k]) + im[lo + 2*j][k];
                
            
        
        lo = o;
        o = o + levelN;
        levelN = levelN\\2;
    

    for (var k=0; k<eSize; k++) 
        out[k] <== im[n-2][k];
    


附录:Polygon Hermez 2.0 zkEVM系列博客

以上是关于Polygon zkEVM Merkle tree的circom约束的主要内容,如果未能解决你的问题,请参考以下文章

Polygon zkEVM zkROM代码解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM中Goldilock域元素circom约束

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

Polygon zkEVM交易解析