... | ... | @@ -215,105 +215,210 @@ CONCAT_RLC = R^5 RLC[0] + R^4 RLC[1] + R^3 RLC[2] + R^2 RLC[3] + R^1 RLC[4] + RL |
|
|
|
|
|
#### 值assign
|
|
|
|
|
|
原始值为:`tag`、`block_tx_id`、`value0`、`value1`、`value2`、`value3`
|
|
|
原始值为:`tag`、`block_tx_id`、`value0`、`value1`、`value2`、`value3
|
|
|
|
|
|
原始值以u8展示`tag_u8`、`block_tx_id_u8`、`value0_u8`、`value1_u8`、`value2_u8`、`value3_u8`,因为原始值都是U256类型且都不超过U128,拆分为u8之后即16个u8(这里的拆分方式需要与计算keccak传入的u8列表顺序一致,暂定使用大端顺)
|
|
|
原始值以u8展示`tag_u8`、`block_tx_id_u8`、`value0_u8`、`value1_u8`、`value2_u8`、`value3_u8`,因为原始值都是U256类型且都不超过U128,拆分为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的计算持续到整张表结束
|
|
|
以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的计算持续到整张表结束, rlc_acc只能在assign value到电路中时才能够计算,因为要获取challenge的值
|
|
|
|
|
|
length: 整个表格的长度,一列的值都相等
|
|
|
|
|
|
cnt: 从0开始,持续自增,直到length-1, cnt==0是第一行,cnt==length-1是最后一行
|
|
|
cnt: 从1开始,持续自增,直到length, cnt==1是第一行,cnt==length是最后一行, 为什么从1开始,需要一行的padding行(cnt=0,q_enable不开启)
|
|
|
|
|
|
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
|
|
|
|
|
|
challenge: 用来存放 random^5, random^4, random^3, random^2, random
|
|
|
|
|
|
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`
|
|
|
|
|
|
注:这里不再以单独的列存放concat_rlc_acc,直接在lookup时进行concat_rlc_acc的计算
|
|
|
|
|
|
Hash: `Column<Advice>`类型,只有在length-1和length两行有值,分别为`public_hash_hi`和`public_hash_lo`
|
|
|
|
|
|
#### 约束
|
|
|
|
|
|
1. public整张表的约束:
|
|
|
1. Random
|
|
|
|
|
|
1)lookup keccak table: <length, concat_rlc_acc, public_hash_hi, public_hash_lo> (在整张表的最后一行进lookup)
|
|
|
1列challenge和五列random<random, random_pow_2, random_pow_3, random_4, random_5>
|
|
|
|
|
|
2)使用equal约束, public_hash_hi, public_hash_lo的值与 `Column<Instance>`中的hash相等
|
|
|
challenge的约束:
|
|
|
|
|
|
2. rlc_acc约束:
|
|
|
```shell
|
|
|
如果cnt==0
|
|
|
challenge_cur == challenges_expr.keccak_input()
|
|
|
如果cnt != 0
|
|
|
challenge_cur == challenge_prev * challenges_expr.keccak_input()
|
|
|
```
|
|
|
|
|
|
表格的第一行rlc_acc=cur_value_u8
|
|
|
random约束
|
|
|
|
|
|
rlc_acc = rlc_acc_prev*random + cur_value_u8
|
|
|
```
|
|
|
每一行都有:
|
|
|
random^2 = random * random
|
|
|
random^3 = random^2 * random
|
|
|
random^4 = random^3 * random
|
|
|
random^5 = random^4 * random
|
|
|
|
|
|
最后一个有效行(cnt==length-1)
|
|
|
random = challenge (即random值为challenges_expr.keccak_input()^length)
|
|
|
```
|
|
|
|
|
|
1中的lookup同时也保证了rlc_acc计算的正确性,如果计算正确就可以lookup到
|
|
|
2. length
|
|
|
|
|
|
3. 原始值
|
|
|
length = length_prev(从cnt=0开始约束)
|
|
|
|
|
|
每一个原始值被展开为了16行u8,即1行有效值和15行无效值tag==nil的行为无效值,即如果以0~15计数的话,0行为有效值所在的行,tag != nil,1~15行为无效值所在行,即tag==nil
|
|
|
最后一行,length = cnt+1
|
|
|
|
|
|
对于一行中的`tag`、`block_tx_id`、`value0`、`value1`、`value2`、`value3`6个值,只有16行中的第一行是有值的,其他15行都是默认值,tag的默认值为nil, 其他五个值的默认值为0
|
|
|
3. cnt
|
|
|
|
|
|
当tag_cur != nil && 当前行为第一行 则有 tag_next == nil
|
|
|
cnt = cat_prev+1(从cnt=0开始约束)
|
|
|
|
|
|
当tag_cur != nil && 当前行不是第一行 则有 tag_prev == nil && tag_next == nil
|
|
|
最后一个有效行:last_valid_row为length-1
|
|
|
|
|
|
~~当tag_cur == nil && tag_next == nil 则有 tag_cur = tag_next (有些无意义已经知道都是nil,因为无法确认当前行是否为0-15行的第0行还是第15行)~~ (不需要关系临界值)
|
|
|
4. rlc_acc约束:
|
|
|
|
|
|
`block_tx_id`、`value0`、`value1`、`value2`、`value3`与tag类似,如果tag == nil,则value_cur == value_prev (无效值所在行是填充0,witness中填充的是None)
|
|
|
cnt=1的行,rlc_acc=cur_value_u8
|
|
|
|
|
|
根据tag进行判断
|
|
|
cnt=1..=length, rlc_acc = rlc_acc_prev*random + cur_value_u8
|
|
|
|
|
|
- 非TxCalldata 或 TxLogData
|
|
|
assign value时并没有避开cnt=0的这个填充行,因为填充的为0, 所以对于cnt=1的行来说:
|
|
|
|
|
|
进行上面的约束
|
|
|
rlc_acc_cur = rlc_acc_prev(cnt=0, value is zero) * challenge + value_cur,
|
|
|
|
|
|
- TxCalldata 或 TxLogData
|
|
|
所以 rlc_acc_cur = value_cur
|
|
|
|
|
|
对于TxCalldata或者TxLogData开始行(idx=0)
|
|
|
5. U8和value,以及idx
|
|
|
|
|
|
如果TxCalldata或者TxLogData的idx !=0
|
|
|
如果 tag_cur !=nil && tag_cur != TxCalldata && tag_cur != TxLogData,贼有0-15行的u8的值,等于第15行的value的值
|
|
|
|
|
|
  同时是每一个value(0-15行)的第一行(0行,tag != nil),则idx_cur = idx_prev+1,~~且tag_cur = tag.Rotation(-16) (不需要约束这个tag)~~
|
|
|
```rust
|
|
|
let v1 = value0_u8.Rotation(0);
|
|
|
let v2 = value0_u8.Rotation(-1) * pow_of_two::<F>(8));
|
|
|
let v3 = value0_u8.Rotation(-2) * pow_of_two::<F>(16));
|
|
|
let v4 = value0_u8.Rotation(-3) * pow_of_two::<F>(24));
|
|
|
let v5 = value0_u8.Rotation(-4) * pow_of_two::<F>(32));
|
|
|
let v6 = value0_u8.Rotation(-5) * pow_of_two::<F>(40));
|
|
|
let v7 = value0_u8.Rotation(-6) * pow_of_two::<F>(48));
|
|
|
let v8 = value0_u8.Rotation(-7) * pow_of_two::<F>(56));
|
|
|
let v9 = value0_u8.Rotation(-8) * pow_of_two::<F>(64));
|
|
|
let v10 = value0_u8.Rotation(-9) * pow_of_two::<F>(72));
|
|
|
let v11 = value0_u8.Rotation(-10) * pow_of_two::<F>(80));
|
|
|
let v12 = value0_u8.Rotation(-11) * pow_of_two::<F>(88));
|
|
|
let v13 = value0_u8.Rotation(-12) * pow_of_two::<F>(96));
|
|
|
let v14 = value0_u8.Rotation(-13) * pow_of_two::<F>(104));
|
|
|
let v15 = value0_u8.Rotation(-14) * pow_of_two::<F>(112));
|
|
|
let v16 = value0_u8.Rotation(-15) * pow_of_two::<F>(120));
|
|
|
```
|
|
|
|
|
|
  其他行(1-15行,tag==nil)则有idx_cur = idx_prev, byte_cur == u8_cur
|
|
|
```
|
|
|
pub fn expr_from_be_bytes<F: Field, E: Expr<F>>(bytes: &[E]) -> Expression<F> {
|
|
|
let mut value = 0.expr();
|
|
|
for byte in bytes.iter() {
|
|
|
value = value * F::from(256) + byte.expr();
|
|
|
}
|
|
|
value
|
|
|
}
|
|
|
```
|
|
|
|
|
|
4. u8
|
|
|
```shell
|
|
|
let v_original = value0.Rotation::cur()
|
|
|
```
|
|
|
|
|
|
每一个原始值被展开为了16行u8
|
|
|
约束有:` v_final == v_original`
|
|
|
|
|
|
对于u8的来说,当tag_cur != nil && 当前行不是第一行,以value0为例,则有(TxLog和TxData不需要进行约束)
|
|
|
其他五个原始值同理
|
|
|
|
|
|
可以使用`expr_from_bytes`函数
|
|
|
如果tag != nil && (tag==TxCalldata || tag_cur == TxLogData) 则
|
|
|
|
|
|
`value1 == value1_u8`, `value0_u8 == 0`, `value2_u8 == 0`,` value3_u8 == 0`,` tag_u8 == 0`, ` block_tx_idx == 0`
|
|
|
|
|
|
6. tag和value约束
|
|
|
|
|
|
如果tag_cur !=nil && tag_cur != TxCalldata && tag_cur != TxLogData,则有
|
|
|
|
|
|
```shell
|
|
|
# tag约束
|
|
|
tag.Rotation(-1) == nil
|
|
|
tag.Rotation(-2) == nil
|
|
|
tag.Rotation(-3) == nil
|
|
|
tag.Rotation(-4) == nil
|
|
|
tag.Rotation(-5) == nil
|
|
|
tag.Rotation(-6) == nil
|
|
|
tag.Rotation(-7) == nil
|
|
|
tag.Rotation(-8) == nil
|
|
|
tag.Rotation(-9) == nil
|
|
|
tag.Rotation(-11) == nil
|
|
|
tag.Rotation(-12) == nil
|
|
|
tag.Rotation(-13) == nil
|
|
|
tag.Rotation(-14) == nil
|
|
|
tag.Rotation(-15) == nil
|
|
|
```
|
|
|
|
|
|
```rust
|
|
|
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;
|
|
|
如果tag != nil && (tag==TxCalldata || tag_cur == TxLogData) && idx(value0) != 0则
|
|
|
|
|
|
```shell
|
|
|
value0_cur(idx_cur) == value0_prev+1 (idx_cur+1)
|
|
|
tag_cur == tag_prev
|
|
|
block_tx_idx_cur == block_tx_idx_prev
|
|
|
value2 == value_prev
|
|
|
value3 == 0 (是否约束, 目前value未填值)
|
|
|
```
|
|
|
|
|
|
```rust
|
|
|
let v_original = value0.Rotation(-16)
|
|
|
如果 tag==nil
|
|
|
|
|
|
```shell
|
|
|
block_tx_idx_cur == 0
|
|
|
value0_cur == 0
|
|
|
value1_cur == 0
|
|
|
value2_cur == 0
|
|
|
value3_cur == 0
|
|
|
```
|
|
|
|
|
|
约束有:` v_final == v_original`
|
|
|
7. hash约束
|
|
|
|
|
|
其他五个原始值同理
|
|
|
1)lookup keccak table: <length, concat_rlc_acc, public_hash_hi, public_hash_lo> (在整张表的最后一行进lookup)
|
|
|
|
|
|
当cnt == length-1时,即最后一行进行lookup
|
|
|
|
|
|
```rust
|
|
|
let length = length.Rotation::cur();
|
|
|
let public_hash_hi = hash.Rotation::prev();
|
|
|
let public_hash_lo = hashRotation::cur();
|
|
|
let random_pow_5 = challenge.Rotation(-4);
|
|
|
let random_pow_4 = challenge.Rotation(-3);
|
|
|
let random_pow_3 = challenge.Rotation(-2);
|
|
|
let random_pow_2 = challenge.Rotation(-1);
|
|
|
let random = challenge.Rotation::cur();
|
|
|
let tag_final_rlc_acc = tag_u8_rlc_acc.Rotation::cur();
|
|
|
let block_tx_id_u8_final_rlc_acc = block_tx_id_u8_rlc_acc.Rotation::cur();
|
|
|
let value0_u8_final_rlc_acc = value0_u8_rlc_acc.Rotation::cur();
|
|
|
let value1_u8_final_rlc_acc = value1_u8_rlc_acc.Rotation::cur();
|
|
|
let value2_u8_final_rlc_acc = value2_u8_rlc_acc.Rotation::cur();
|
|
|
let value3_u8_final_rlc_acc = value3_u8_rlc_acc.Rotation::cur();
|
|
|
```
|
|
|
|
|
|
```rust
|
|
|
let concat_rlc_acc = tag_final_rlc_acc * random_pow_5 + block_tx_id_u8_final_rlc_acc * random_pow_4 + value0_u8_final_rlc_acc * random_pow_3 + value1_u8_final_rlc_acc * random_pow_2 + value2_u8_final_rlc_acc * random + value3_u8_final_rlc_acc
|
|
|
```
|
|
|
|
|
|
注:电路运行前,public整张表在拆分u8的计算hash(instance)的时候也需要按照tag、block_tx_id、value0、value1、value2、value3这个顺序
|
|
|
|
|
|
2)copy约束
|
|
|
|
|
|
hash有两列,hash_hi, hash_lo
|
|
|
|
|
|
cnt=0位置的hash_hi=instance_hash[row=0]
|
|
|
|
|
|
cnt=0位置的hash_lo=instance_hash[row=1]
|
|
|
|
|
|
每一列的值都是相等的,赋值时使用的copy
|
|
|
|
|
|
```shell
|
|
|
hash_hi_prev = hash_hi_prev.copy_advice(hash_hi_cur);
|
|
|
hash_lo_prev = hash_lo_prev.copy_advice(hash_hi_cur);
|
|
|
```
|
|
|
|
|
|
#### 问题:
|
|
|
|
... | ... | @@ -323,7 +428,7 @@ Hash: `Column<Advice>`类型,只有在length-1和length两行有值,分别 |
|
|
|
|
|
2. 如何判断表格当前行为第一行
|
|
|
|
|
|
cnt==0,即第一行
|
|
|
cnt==1,即第一行
|
|
|
|
|
|
3. 如何判断TxCalldata或者TxLogData开始行开始行
|
|
|
|
... | ... | @@ -369,5 +474,7 @@ v16, rlc16=rlc15*random+v16 |
|
|
|
|
|
rlc= v<sub>1</sub> * random^(len-1) + v<sub>2 </sub>* random^(len-2) + ... + v<sub>len-1 </sub>* random + v<sub>len</sub>
|
|
|
|
|
|
|
|
|
```shell
|
|
|
cargo 'test' '--' 'tests::erc20_test::tests::test_erc20_t02_a_transfer_b_200' '--exact' '--nocapture' '--ignored' > output.log
|
|
|
```
|
|
|
|