Polygon zkEVM中的Merkle tree

Posted mutourend

tags:

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

1. 引言

https://github.com/0xPolygonHermez/pil-stark为例,Polygon zkEVM中实现了2种Merkle tree(二者均采用Poseidon 哈希函数):

  • 1)基于Goldilocks域的Merkle tree:
  • 2)基于BN128域的Merkle tree:
    • 2.1)其Poseidon hash采用circomlibjs中的poseidon实现。
	if (starkStruct.verificationHashType == "GL") 
		// 借鉴了https://github.com/filecoin-project/neptune 中的优化策略
        const poseidon = await buildPoseidonGL();
        MH = await buildMerklehashGL();
        transcript = new Transcript(poseidon);
     else if (starkStruct.verificationHashType == "BN128") 
        const poseidonBN128 = await buildPoseidonBN128();
        MH = await buildMerklehashBN128();
        transcript = new TranscriptBN128(poseidonBN128);
     else 
        throw new Error("Invalid Hash Type: "+ starkStruct.verificationHashType);
    

2. Polygon zkEVM中基于Goldilocks域的Merkle tree

2.1 基于Goldilocks域的Poseidon hash实现

前序博客有:

基于Goldilocks域的Merkle tree,其Poseidon hash实现借鉴了https://github.com/filecoin-project/neptune(Poseidon hashing over BLS12-381)中的优化策略,其基于的是Goldilocks extension 3 field。
详细代码实现见pil-Stark项目中的poseidon.js。

2.2 基于Goldilocks域的LinearHash

pil-stark项目中的 linearhash.js中,LinearHash类中,主要实现了hash函数:【将输入vals铺平展开为flatVals:若展开后的flatVals长度小于等于4,则补零为长度为4的结果返回;否则,将flatVals补齐为最近的8的整数倍,以8个元素为一组inHash,递归调用poseidon,返回最后一次调用poseidon函数的结果。】

module.exports = class LinearHash 

    constructor(poseidon) 
        this.H = poseidon; //基于Goldilocks域的Poseidon hash
    

    hash(vals)  //输入为vals数组,每个元素也可能是数组
        const flatVals = [];//将输入vals展开铺平存入flatVals中。
        for (let i=0; i<vals.length; i++) 
            if (Array.isArray(vals[i])) 
                for (let j=0; j<vals[i].length; j++) 
                    flatVals.push(vals[i][j]);
                
             else 
                flatVals.push(vals[i]);
            
        
        let st = [0n, 0n, 0n, 0n];
        //若flatVals长度小于4,则在其后补零到长度为4.
        if (flatVals.length <= 4)  
            for (let i=0; i<flatVals.length;i++)  
                st[i] = flatVals[i];
            
            return st;
        
        let inHash = [];
        for (let i=0; i<flatVals.length;i++) 
            inHash.push(flatVals[i]);
            //将铺平后的flatVals,每8个元素为一组inHash,递归调用poseidon函数
            if (inHash.length == 8) 
                st = this.H(inHash, st);//递归调用,st为输入和输入
                inHash.length = 0;
            
        
        //若铺平后的flatVals长度不是8的整数倍,则后续补零到为最近的8的整数倍。
        if (inHash.length>0) 
            while (inHash.length<8) inHash.push(0n);
            //对补零后的inHash块,递归调用poseidon
            st = this.H(inHash, st);
        
        //返回最后一次调用poseidon的结果
        return st;
    

linearHash函数功能为:

  • 1)将输入buffIn以width列,height行矩阵表示;(每列元素为Goldilocks基域元素)
  • 2)若width列数小于等于4,则之间将以width列,height行矩阵表示的buffIn赋值给buffOut,返回buffOut。
    if (width <=4) 
        for (let i=0; i<heigth; i++) 
            for (let j=0; j<width; j++) 
                buffOut[i*4+j] = buffIn[width*i + j];
            
        
        return buffOut;
    
    
  • 3)接下来为width列数大于4的情况:
    调用buildWasm,会实现wasm代码,公开基于Goldilocks域的add/mul/square/poseidon/multiLinearHash/merkelizeLevel函数。
    调用glwasm.multiLinearHash(pIn, width, heigth, pOut);,其中pIn以矩阵表示,具有width列,height行。(每列元素为Goldilocks基域元素)。multiLinearHash是指将每8个元素为一组调用poseidon函数进行运算。pOut的大小为:height*4。【为所有的叶子节点】
    将返回的pOut(res)值更新到tree.nodes中:
    for (let i=0; i<res.length; i++)  //设置所有叶子节点
    	tree.nodes.set(res[i], i*nPerThreadF*4);
    
    
  • 4)构建叶子节点之上的中间节点:
    	let pIn = 0;
        let n64 = height*4;
        let nextN64 = (Math.floor((n64-1)/8)+1)*4;
        let pOut = pIn + nextN64*2*8;
        while (n64>4) 
            // FIll with zeros if n nodes in the leve is not even
            await _merkelizeLevel(tree.nodes, pIn, nextN64/4, pOut);
    
            n64 = nextN64;
            nextN64 = (Math.floor((n64-1)/8)+1)*4;
            pIn = pOut;
            pOut = pIn + nextN64*2*8;
        
    

2.3 基于Goldilocks域的Merkle tree

基于Goldilocks域的Merkle tree的基本结构为:

		const tree = 
			//为待Merkle化的所有元素,以矩阵表示,具有w列h行。
			//buff每个元素基于Goldilocks extension 3 域,
			//所以,buff每个元素由3个Goldilocks基域元素组成。
            elements: buff, 
             //若h=2^n,则nodes总数为: (2^n+1-1)*4,即每个节点可存放4个Goldilocks基域元素。
            nodes: new BigUint64Array(this._getNNodes(height*4)),
            width: width, //为待Merkle化元素矩阵表示的列数w * 3(因基于Goldilocks extension 3 域)。
            height: height //为待Merkle化元素矩阵表示的行数h,假设h=2^n
        ;

在将某输入Merkle化(merkelize)的过程中:

  • 1)分组从待Merkle化buff取输入bb(以矩阵表示,width列和curN行个元素(每3个列元素组成一个val)),调用linearHash函数:
    	for (let i=0; i< height; i+=nPerThreadF) 
            const curN = Math.min(nPerThreadF, height-i);
            console.log("slicing buff "+i);
            const bb = tree.elements.slice(i*width, (i+curN)*width);
    	    // const bb = new BigUint64Array(tree.elements.buffer, tree.elements.byteOffset + i*width*8, curN*width);
            if (self.useThreads) 
                console.log("creating thread "+i);
                promisesLH.push(pool.exec("linearHash", [bb, width, i, height]));
             else  //详细的linearHash实现见上一节分析。
                res.push(await linearHash(bb, width, i, curN));
            
        
    
  • 2)更新tree.nodes的所有叶子节点:
    	for (let i=0; i<res.length; i++) 
            tree.nodes.set(res[i], i*nPerThreadF*4);
        
    
  • 3)构建叶子节点之上的中间节点(包括root节点):
    	let pIn = 0;
        let n64 = height*4;
        let nextN64 = (Math.floor((n64-1)/8)+1)*4;
        let pOut = pIn + nextN64*2*8;
        while (n64>4) 
            // FIll with zeros if n nodes in the leve is not even
            await _merkelizeLevel(tree.nodes, pIn, nextN64/4, pOut);
    
            n64 = nextN64;
            nextN64 = (Math.floor((n64-1)/8)+1)*4;
            pIn = pOut;
            pOut = pIn + nextN64*2*8;
        
    

3. Polygon zkEVM中基于BN128域的Merkle tree

附录:Polygon Hermez 2.0 zkEVM系列博客

附录A:wasmbuilder

https://github.com/iden3/wasmbuilder——wasmbuilder:为手写构造wasm代码的javascript库。

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

Polygon zkEVM中的子约束系统

Polygon zkEVM中的Recursive STARKs

Polygon zkEVM中的常量多项式

Polygon zkEVM网络节点

Polygon zkEVM zkASM中的函数集合

Polygon zkEVM zkROM代码解析