Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
zkevm-circuits
zkevm-circuits
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge Requests 0
    • Merge Requests 0
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Package Registry
  • Analytics
    • Analytics
    • CI / CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar

新注册的用户请输入邮箱并保存,随后登录邮箱激活账号。后续可直接使用邮箱登录!

  • zkp
  • zkevm-circuitszkevm-circuits
  • Wiki
    • Zkevm docs
  • 10 public

Last edited by gzxu Aug 07, 2024
Page history
This is an old version of this page. You can view the most recent version or browse the history.

10 public

总体布局

本段介绍结构体PublicCircuitConfig的列及其含义。

单功能列 Single-purpose columns

下面是public子电路中的单功能的列:

    /// various public information tag, e.g. BlockNumber, TxFrom
    tag: Column<Instance>,
     /// tx_id (start from 1), except for tag=BlockHash, means recent block number diff (1...256)
    block_tx_idx: Column<Instance>,
  • tag 指该行数据的类别, 其具体类型为:
    pub enum Tag {
        #[default]
        ChainId
        BlockCoinbase,
        BlockTimestamp,
        BlockNumber,
        BlockDifficulty,
        BlockGasLimit,
        BlockBaseFee,
        BlockHash,
        TxStatus,
        // combine From and Value together to reduce number of lookups
        TxFromValue,
        // combine To and CallDataLength together to reduce number of lookups
        TxToCallDataSize,
        TxIsCreate,
        TxGasLimit,
        TxGasPrice,
        TxCalldata, //TODO make sure this equals copy tag PublicCalldata
        TxLog,
        TxLogSize,
        CodeSize,
    }
  • block_tx_idx 指交易id;当该行数据为BlockHash的时候指的是最近的block number

多功能列 Versatile columns

为了减少列的使用,缩减电路规模,设计了多功能的列。在不同的行数据类别下,这些列存放不同的数据。目前设计有4个多功能列,代码里呈现为:

values: [Column<Instance>; NUM_VALUES],

表设计

区块公共数据存放

tag为ChainId时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
ChainId 0 chain_id[..16] chain_id[16..] 0 0

tag为BlockCoinbase时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockCoinbase 0 coinbase[..4] coinbase[4..] 0 0

tag为BlockTimeStamp时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockTimestamp 0 BlockTimestamp[..16] BlockTimestamp[16..] 0 0

tag为BlockNumber时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockNumber 0 0 BlockNumber 0 0

tag为BlockDifficulty时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockDifficulty 0 BlockDifficulty[..16] BlockDifficulty[16..] 0 0

tag为BlockGasLimit时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockGasLimit 0 BlockGasLimit[..16] BlockGasLimit[16..] 0 0

tag为BlockBaseFee时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockBaseFee 0 BlockBaseFee[..16] BlockBaseFee[16..] 0 0

tag为BlockHash的时候,遍历最近的history_hash,每行存放数据值如下,其中index代表在history_hash中的次序(也是当前区块number-此区块number的差值),hash为该次序对应的hash值:

tag block_tx_idx value[0] values[1] values[2] values[3]
BlockHash index hash[..16] hash[16..] 0 0

区块交易相关数据存放

对区块中的每一笔交易遍历存放如下数据类型,其中tx_idx为该交易在区块中的交易列表中的序号(从1开始)

tag为TxFromValue时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxFromValue tx_idx from[..4] from[4..] value[..16] value[16..]

tag为TxToCallDataSize时,该行数据值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxToCallDataSize tx_idx to_hi to_lo 0 tx.input.len

tag为TxIsCreate时,该行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxIsCreate tx_idx 0 1/0(创建合约为1,普通合约调用为0) 0 0

tag为TxGasLimit时,该行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxGasLimit tx_idx gas[..16] gas[16..] 0 0

tag为TxGasPrice时,该行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxGasPrice tx_idx gas_price[..16] gas_price[16..] 0 0

将合约的输入数据按byte遍历, 每个byte存放进TxCalldata的数据行,其中idx为该byte在合约的输入数据中的次序,byte为该次序对应的byte数据,该行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxCalldata tx_idx idx byte 0 0

区块log数据存放

区块中每笔交易可以产生多条log,遍历区块中每笔交易的每个log,其中topic_num为该log中topics的数目(不超过4);tx_idx为该log所属的transaction_index;log_index为该log的log_index;address为该log所属的地址;如果topic_num为0的话,log_tag为AddrWith0Topic;如果topic_num为1/2/3/4的话,log_tag为AddrWith1/2/3/4Topic。

tag为TxLog,该行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxLog tx_idx log_index log_tag address[..4] address[4..]

tag为TxLog的时候,根据topic的数目,依次存放topic1/2/3/4的数据,其中topic_hash为该topic对应的hash,topic_log_tag为Topic1/2/3/4,每行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxLog tx_idx log_index topic_log_tag topic_hash[..16] topic_hash[16..]

tag为TxLog时候,记录了log的data长度(data_len),该行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxLog tx_idx log_index log_tag=DataSize 0 data_len

将log中的数据按照byte便利,每个byte存放一行,其中data_idx为该byte在数据块中的次序,其中LogTag::Data为该数据类型,每行数值为:

tag block_tx_idx value[0] values[1] values[2] values[3]
TxLog tx_idx log_index LogTag::Data byte data_idx

合约公共数据存放

tag为CodeSize时,该行数据值为:

code_size hi的值应该为0,因为EVM的硬性要求(code size均不超过约4万)

tag block_tx_idx value[0] values[1] values[2] values[3]
CodeSize 0 code_addr hi code_addr lo code_size hi code_size lo

2024年5月更新

上述所有列都变为 Column<Advice> 。

问题1

如何输入公开数据到zk电路里?

解决方法:将上述所有列所有行进行哈希。将哈希值作为 Column<Instance>,仅需1列。2行,存hash_hi,lo。

问题2

上述有6列,怎么做哈希?

解决方法:假设6列的值都是u8,那将6列按列连接起来成为一个u8的数组进行哈希。我们的KeccakTable是用输入的RLC进行lookup的。注意到,连接起来的数组的RLC(CONCAT_RLC)有如下等式

CONCAT_RLC = R^5 RLC[0] + R^4 RLC[1] + R^3 RLC[2] + R^2 RLC[3] + R^1 RLC[4] + RLC[5]

其中RLC[]是六列分别的RLC。R是用于RLC的随机数r的length次方。length是整个Public table的有效数据在u8表示下的长度。

因此步骤是:

  1. 将原来table的数值转化成u8(见下段)
  2. 建一列cnt,从0开始数。建一列length,所有值都是最终的length。
  3. 求得6列的RLC(需要新一列记录rlc累加值)
  4. 求得随机数r的length次方(需要新一列记录次方的累计值)
  5. 求CONCAT_RLC
  6. 使用length,CONCAT_RLC向KeccakTable进行lookup,得到hash的hi,lo(在新建的一个或两个Column<Advice>中,新建的两个列,可以每行都是hash的hi,lo). lookup条件cnt==length-1
  7. 使用equal约束,Column<Advice>中的hash和Column<Instance>中的hash相等。

问题3

怎么将原来table的数值转化成u8?

解决方法:上述的value都是在U128范围内的,因此,原来table的一个数值可以变为16个u8数值。那么原来table的一列就要新建一列,原来的一列中的一行的value,在新列中要占用16行。

再新建一列ring_16,以15,14...1,0这样循环。在ring_16==0时,对新列中16行和原来列的1行的value进行约束,证明16个u8拼成了一个value。

当Tag 不是Nil时,不是TxCalldata,不是TxLogData时,我们要约束Rotation 0到-15的行,约束1:他们的Tag要是Nil(除了当前行)。约束2:16行的16个u8拼成了一个value。

这样,原来table的两行之间,要插入15行的填充行(tag为Nil),填充行在value的地方没有任何意义,只在u8的地方有意义。lookup也要加上ring_16,且lookup时ring_16=0。

当Tag是 TxCalldata 或 TxLogData 时,因为每一行之间有大量重复数据,例如Tag、block_tx_idx、value_3都是相同的,因此仅对于第一行(idx==0),进行类似约束:约束Rotation 0到-15的行,约束1:他们的Tag要是Nil(除了当前行)。约束2:16行的16个u8拼成了一个value。

对于第二行及以后(idx!=0),仅对于Rotation 0的行约束,约束byte(本来就是u8)等于相应的u8那列的值。同时还要约束tag等于tag_prev,idx=idx_prev+1等等。

这样,原来table的idx==0的行上边,要插入15行的填充行(tag为Nil)。idx!=0的行上边,不需要插入。

我们原来table有6列,因此对于每列,都要进行这样的约束。

约束梳理

首先新表的列有以下几列,Column<Advice>:

tag、block_tx_id、value0、value1、value2、value3、

tag_u8、block_tx_id_u8、value0_u8、value1_u8、value2_u8、value3_u8、

tag_u8_rlc_acc、block_tx_id_u8_rlc_acc、value0_u8_rlc_acc、value1_u8_rlc_acc、value2_u8_rlc_acc、value3_u8_rlc_acc、

length, concat_rlc_acc、hash

Column<Instance>: hash

值assign

原始值为:tag、block_tx_id、value0、value1、value2、value3

原始值以u8展示tag_u8、block_tx_id_u8、value0_u8、value1_u8、value2_u8、value3_u8,因为原始值都是U256类型,拆分为u8之后即16个u8(这里的拆分方式需要与计算keccak传入的u8列表顺序一致,暂定使用大端顺)

以u8计算rlc_acc: tag_u8_rlc_acc、block_tx_id_u8_rlc_acc、value0_u8_rlc_acc、value1_u8_rlc_acc、value2_u8_rlc_acc、value3_u8_rlc_acc,计算公式:rlc_acc = rlc_acc_prev*random + cur_value, 起始rlc_acc=cur_value, 即表格的第一行的值都为起始rlc_acc,所有的rlc_acc的计算持续到整张表结束

length: 整个表格的长度,从1开始计数,持续累加

final_rlc_acc:当表格结束时,最后一行的tag_u8_rlc_acc、block_tx_id_u8_rlc_acc、value0_u8_rlc_acc、value1_u8_rlc_acc、value2_u8_rlc_acc、value3_u8_rlc_acc的值即为整个public表的六列原始值的rlc_acc,暂称为final_rlc_acc

concat_rlc_acc: 整个public表中所有数据的rlc_acc, 计算方式为:

tag_u8_final_rlc_acc*random^5 + block_tx_id_u8_final_rlc_acc*random^4 + value0_u8_final_rlc_acc*random^3 + value1_u8_final_rlc_acc*random^2 + value3_u8_rlc_final_acc*random + value3_u8_final_rlc_acc

Hash: Column<Advice>类型,只有在length-1和length两行有值,分别为public_hash_hi和public_hash_lo

约束

  1. public整张表的约束:

    1)lookup keccak table: <length, concat_rlc_acc, public_hash_hi, public_hash_lo> (在整张表的最后一行进lookup)

    2)使用equal约束, public_hash_hi, public_hash_lo的值与 Column<Instance>中的hash相等

  2. rlc_acc约束:

    表格的第一行rlc_acc=cur_value_u8

    rlc_acc = rlc_acc_prev*random + cur_value_u8

    1中的lookup同时也保证了rlc_acc计算的正确性,如果计算正确就可以lookup到

  3. 原始值

    每一个原始值被展开为了16行u8

    对于一行中的tag、block_tx_id、value0、value1、value2、value36个值,只有16行中的第一行是有值的,其他15行都是默认值,tag的默认值为nil, 其他五个值的默认值为0

    当tag_cur != nil && 当前行为第一行 则有 tag_next == nil

    当tag_cur != nil && 当前行不是第一行 则有 tag_prev == nil && tag_next == nil

    当tag_cur == nil && tag_next == nil 则有 tag_cur = tag_next (有些无意义已经知道都是nil,因为无法确认当前行是否为0-15行的第0行还是第15行)

    block_tx_id、value0、value1、value2、value3与tag类似,如果tag == nil,则value_cur == value_prev

    根据tag进行判断

    • 非TxCalldata 或 TxLogData

      进行上面的约束

    • TxCalldata 或 TxLogData

      对于TxCalldata或者TxLogData开始行,idx=0

      如果不是TxCalldata或者TxLogData开始行

        同时是每一个value(0-15行)的第一行(0行,tag != nil),则idx_cur = idx_prev+1,且tag_cur = tag.Rotation(-16)

        其他行(1-15行,tag==nil)则有idx_cur = idx_prev, byte_cur == u8_cur (还不确定byte是否为大端序)

      (如何判断TxCalldata或者TxLogData开始行开始行)

  4. u8

    每一个原始值被展开为了16行u8

    对于u8的来说,当tag_cur != nil && 当前行不是第一行,则有

    let v1 =  value0_u8.Rotation(-1);
    let v2 =  value0_u8.Rotation(-2) * pow_of_two::<F>(8));
    let v3 =  value0_u8.Rotation(-3) * pow_of_two::<F>(16));
    let v4 =  value0_u8.Rotation(-4) * pow_of_two::<F>(24));
    let v5 =  value0_u8.Rotation(-5) * pow_of_two::<F>(32));
    let v6 =  value0_u8.Rotation(-6) * pow_of_two::<F>(40));
    let v7 =  value0_u8.Rotation(-7) * pow_of_two::<F>(48));
    let v8 =  value0_u8.Rotation(-8) * pow_of_two::<F>(56));
    let v9 =  value0_u8.Rotation(-9) * pow_of_two::<F>(64));
    let v10 =  value0_u8.Rotation(-10) * pow_of_two::<F>(72));
    let v11 =  value0_u8.Rotation(-11) * pow_of_two::<F>(80));
    let v12 =  value0_u8.Rotation(-12) * pow_of_two::<F>(88));
    let v13 =  value0_u8.Rotation(-13) * pow_of_two::<F>(96));
    let v14 =  value0_u8.Rotation(-14) * pow_of_two::<F>(104));
    let v15 =  value0_u8.Rotation(-15) * pow_of_two::<F>(112));
    let v16 =  value0_u8.Rotation(-16) * pow_of_two::<F>(120));
    let v_final = v16+v15+v14+v13+...+v3+v2+v1;
    let v_original = value0.Rotation(-16)

    约束有: v_final == v_original

    其他五个原始值同理

问题:

  1. 如何判断当前行是最后一行
  2. 如何判断表格当前行为第一行
  3. 如何判断TxCalldata或者TxLogData开始行开始行
  4. LogIndex之间是否需要约束,每一个当前一条的log与上一条log之间的index值是递增的,但是每一条log又被拆分称了多个(logTopic,logSize,logData)
Clone repository
  • basics
    • evm
    • halo2
  • code notes
    • binary_number_with_real_selector
    • how to use macro
    • simple_lt
    • simple_lt_word
  • Home
  • image
  • zkevm docs
    • 1 introduction
    • 10 public
    • 11 fixed
    • 12 exp
    • 13 keccak
    • 14 comparisons
    • 15 differences
View All Pages

Copyright © 2024 ChainWeaver Org. All Rights Reserved. 版权所有。

京ICP备2023035722号-3

京公网安备 11010802044225号