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
    • 4 core
  • core extcodecopy

core extcodecopy · Changes

Page history
restyle docs authored Aug 07, 2024 by gzxu's avatar gzxu
Hide whitespace changes
Inline Side-by-side
Showing with 477 additions and 494 deletions
+477 -494
  • zkevm-docs/4-core/core-extcodecopy.markdown zkevm-docs/4-core/core-extcodecopy.markdown +477 -494
  • No files found.
zkevm-docs/4-core/core-extcodecopy.markdown
View page @ 695280b6
## EXTCODECOPY 指令 ## EXTCODECOPY 指令
### 概述 ### 概述
#### CODECOPY #### CODECOPY
概述:该操作通常用于在智能合约中实现一些动态代码加载或代码复制的逻辑,将合约中字节码复制到Memory中,即将合约代码复制到内存的操作。 概述:该操作通常用于在智能合约中实现一些动态代码加载或代码复制的逻辑,将合约中字节码复制到Memory中,即将合约代码复制到内存的操作。
具体操作:从栈顶弹出三个值,分别为:destOffset、offset、length,根据当前三个值进行操作:`memory[destOffset:destOffset+length] = address(this).code[offset:offset+length]`,即从code中以offset的位置开始,复制长度为length的字节码到Memory以destOffset为起始的位置(都是以字节为单位进行操作) 具体操作:从栈顶弹出三个值,分别为:destOffset、offset、length,根据当前三个值进行操作:`memory[destOffset:destOffset+length] = address(this).code[offset:offset+length]`,即从code中以offset的位置开始,复制长度为length的字节码到Memory以destOffset为起始的位置(都是以字节为单位进行操作)
trace示例:CODECOPY指令执行时,会从栈顶弹出三个值:destOffset、offset、length,然后根据这三个值进行合约代码的复制 trace示例:CODECOPY指令执行时,会从栈顶弹出三个值:destOffset、offset、length,然后根据这三个值进行合约代码的复制
```shell ```shell
PUSH1 0xa PUSH1 0xa
PUSH30 0x02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f PUSH30 0x02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
ADD ADD
PUSH1 0x1E PUSH1 0x1E
PUSH1 0x03 PUSH1 0x03
PUSH1 0x00 PUSH1 0x00
CODECOPY CODECOPY
STOP STOP
``` ```
此操作会从合约代码第3个字节开始复制,长度为30,复制到Memory以00起始的位置,即将`02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f` 复制到Memory中 此操作会从合约代码第3个字节开始复制,长度为30,复制到Memory以00起始的位置,即将`02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f` 复制到Memory中
#### EXTCODECOPY #### EXTCODECOPY
EXTCODECOPY操作码类似于CODECOPY,但不同之处在于它可以通过参数指定合约源码地址。具体操作是从栈顶弹出一个地址,然后找到该地址对应的合约代码并复制到内存中。 EXTCODECOPY操作码类似于CODECOPY,但不同之处在于它可以通过参数指定合约源码地址。具体操作是从栈顶弹出一个地址,然后找到该地址对应的合约代码并复制到内存中。
### Witness Core Row ### Witness Core Row
Witness Core Row的表格设计如下: Witness Core Row的表格设计如下:
- `cnt=2, vers[0]~vers[8]`为正常copy row进行LookUp的值。 - `cnt=2, vers[0]~vers[8]`为正常copy row进行LookUp的值。
- `cnt=2, vers[8]~vers[17]`为padding copy row进行LookUp的值。 - `cnt=2, vers[8]~vers[17]`为padding copy row进行LookUp的值。
```shell ```shell
/// +---+-------+-------+-------+----------+ /// +---+-------+-------+-------+----------+
/// |cnt| 8 col | 8 col | 8 col | 8 col | /// |cnt| 8 col | 8 col | 8 col | 8 col |
/// +---+-------+-------+-------+----------+ /// +---+-------+-------+-------+----------+
/// | 2 | COPY(9) | ZEROCOPY(9)| /// | 2 | COPY(9) | ZEROCOPY(9)|
/// | 1 | STATE | STATE | STATE | STATE | /// | 1 | STATE | STATE | STATE | STATE |
/// | 0 | DYNA_SELECTOR | AUX | /// | 0 | DYNA_SELECTOR | AUX |
/// +---+-------+-------+-------+----------+ /// +---+-------+-------+-------+----------+
``` ```
#### 解释 #### 解释
当进行code copy时,offset表示要复制的合约代码的起始位置,length表示复制的长度。需要注意的是在进行copy操作时可能会出现边界问题,例如: 当进行code copy时,offset表示要复制的合约代码的起始位置,length表示复制的长度。需要注意的是在进行copy操作时可能会出现边界问题,例如:
1. `offset <= len(code)`, `copy_len > 0`, `offset + copy_len <= len(code)`:无需进行0填充。 1. `offset <= len(code)`, `copy_len > 0`, `offset + copy_len <= len(code)`:无需进行0填充。
2. `offset <= len(code)`, `copy_len == 0`, `offset + copy_len <= len(code)`:无需0填充,也无需拷贝。 2. `offset <= len(code)`, `copy_len == 0`, `offset + copy_len <= len(code)`:无需0填充,也无需拷贝。
3. `offset <= len(code)`, `copy_len > 0`, `offset + copy_len > len(code)`:需要进行0填充。 3. `offset <= len(code)`, `copy_len > 0`, `offset + copy_len > len(code)`:需要进行0填充。
4. `offset > len(code)`, `copy_len >= 0`, `offset + copy_len > len(code)`:需要进行0填充。 4. `offset > len(code)`, `copy_len >= 0`, `offset + copy_len > len(code)`:需要进行0填充。
此外,当`offset`大于`u64`时,会对`offset`进行特殊处理为`u64`的最大值。 此外,当`offset`大于`u64`时,会对`offset`进行特殊处理为`u64`的最大值。
对于Padding的值也会被放到内存中,Padding的值,Src部分都是默认值,dst部分正常填充。 对于Padding的值也会被放到内存中,Padding的值,Src部分都是默认值,dst部分正常填充。
padding中的dst部分在进行赋值时需要注意:dst_pointer和dst_stamp,因为在Copy子电路中,memory_addr=dst_pointer+cnt,memory_stamp=dst_stamp+cnt,而Padding和正常的Copy是分成两部分的(Padding在Copy子电路中的Type为Zero),即Padding在Copy子电路中的cnt也是从0开始计数的。 padding中的dst部分在进行赋值时需要注意:dst_pointer和dst_stamp,因为在Copy子电路中,memory_addr=dst_pointer+cnt,memory_stamp=dst_stamp+cnt,而Padding和正常的Copy是分成两部分的(Padding在Copy子电路中的Type为Zero),即Padding在Copy子电路中的cnt也是从0开始计数的。
举例如下: 举例如下:
> 合约代码长度:len(code)=5 > 合约代码长度:len(code)=5
> 进行CodeCopy操作: > 进行CodeCopy操作:
> offset: 0 > offset: 0
> copy_len: 8 > copy_len: 8
> destOffset: 0 > destOffset: 0
> 进行CodeCopy, 因为offset+copy_len > len(code) 所以需要填充0,填充长度为offset+copy_len - len(code) = 3, 所以整体CopyRow的生成就分成了两部分:正常的CopyRow5行,PaddingCopyRow3行。 > 进行CodeCopy, 因为offset+copy_len > len(code) 所以需要填充0,填充长度为offset+copy_len - len(code) = 3, 所以整体CopyRow的生成就分成了两部分:正常的CopyRow5行,PaddingCopyRow3行。
> 加入在生成Copy时的stamp为1记为OriginalStamp > 加入在生成Copy时的stamp为1记为OriginalStamp
> 则NoPaddingCopyRow的Stamp都为1(OriginalStamp),dest_pointer为destOffset+{0..4}, cnt为0~4 > 则NoPaddingCopyRow的Stamp都为1(OriginalStamp),dest_pointer为destOffset+{0..4}, cnt为0~4
> 则PaddingCopyRow的Stamp为6(OriginalStamp+len(code)), dest_pointer为destOffset+len(code)+{0..2}, cnt为0~2 > 则PaddingCopyRow的Stamp为6(OriginalStamp+len(code)), dest_pointer为destOffset+len(code)+{0..2}, cnt为0~2
> 因为是分为两部分的,所以stamp、dest_pointer不是相同的 > 因为是分为两部分的,所以stamp、dest_pointer不是相同的
代码如下: 代码如下:
```rust ```rust
pub fn get_code_copy_rows_new( pub fn get_code_copy_rows_new(
&mut self, &mut self,
address: U256, address: U256,
dst: U256, dst: U256,
src: U256, src: U256,
len: U256, len: U256,
) -> (Vec<copy::Row>, Vec<state::Row>, u64, u64, u64) { ) -> (Vec<copy::Row>, Vec<state::Row>, u64, u64, u64) {
//... //...
// NoPaddingCopyRow赋值 // NoPaddingCopyRow赋值
let codecopy_stamp = self.state_stamp; let codecopy_stamp = self.state_stamp;
if code_copy_length > 0 { if code_copy_length > 0 {
for i in 0..code_copy_length { for i in 0..code_copy_length {
let code = self.bytecode.get(&address).unwrap(); let code = self.bytecode.get(&address).unwrap();
let byte = code.get((src_offset + i) as usize).unwrap().value; let byte = code.get((src_offset + i) as usize).unwrap().value;
copy_rows.push(copy::Row { copy_rows.push(copy::Row {
byte: byte.into(), byte: byte.into(),
src_type: copy::Type::Bytecode, src_type: copy::Type::Bytecode,
src_id: address, src_id: address,
src_pointer: src_offset.into(), src_pointer: src_offset.into(),
src_stamp: None, src_stamp: None,
dst_type: copy::Type::Memory, dst_type: copy::Type::Memory,
dst_id: self.call_id.into(), dst_id: self.call_id.into(),
dst_pointer: dst_offset.into(), dst_pointer: dst_offset.into(),
dst_stamp: codecopy_stamp.into(), dst_stamp: codecopy_stamp.into(),
cnt: i.into(), cnt: i.into(),
len: code_copy_length.into(), len: code_copy_length.into(),
}); });
state_rows.push(self.get_memory_write_row((dst_offset + i) as usize, byte)); state_rows.push(self.get_memory_write_row((dst_offset + i) as usize, byte));
} }
} }
// PaddingCopyRow赋值 // PaddingCopyRow赋值
let codecopy_padding_stamp = self.state_stamp; let codecopy_padding_stamp = self.state_stamp;
if padding_length > 0 { if padding_length > 0 {
for i in 0..padding_length { for i in 0..padding_length {
state_rows.push( state_rows.push(
self.get_memory_write_row( self.get_memory_write_row(
(dst_offset + code_copy_length + i) as usize, (dst_offset + code_copy_length + i) as usize,
0 as u8, 0 as u8,
), ),
); );
copy_rows.push(copy::Row { copy_rows.push(copy::Row {
byte: 0.into(), byte: 0.into(),
src_type: copy::Type::default(), src_type: copy::Type::default(),
src_id: 0.into(), src_id: 0.into(),
src_pointer: 0.into(), src_pointer: 0.into(),
src_stamp: None, src_stamp: None,
dst_type: copy::Type::Memory, dst_type: copy::Type::Memory,
dst_id: self.call_id.into(), dst_id: self.call_id.into(),
dst_pointer: (dst_offset + code_copy_length).into(), dst_pointer: (dst_offset + code_copy_length).into(),
dst_stamp: codecopy_padding_stamp.into(), dst_stamp: codecopy_padding_stamp.into(),
cnt: i.into(), cnt: i.into(),
len: U256::from(padding_length), len: U256::from(padding_length),
}) })
} }
} }
// ... // ...
} }
``` ```
此外还需要注意**copy_len为0**的特殊值,当copy_len为0时,NoPaddingCopyRow行数等于0, PaddingCopyRow行数等于0,则CoreRow cnt=2的值会存放两个全是默认值的CopyRow(即全为0的值)放在vers[0]~vers[17],当NoPaddingCopyRow行数大于0,PaddingCopyRow行数等于0时,vers[8]~vers[17]会存放全是默认值当CopyRow(即全为0的值) 此外还需要注意**copy_len为0**的特殊值,当copy_len为0时,NoPaddingCopyRow行数等于0, PaddingCopyRow行数等于0,则CoreRow cnt=2的值会存放两个全是默认值的CopyRow(即全为0的值)放在vers[0]~vers[17],当NoPaddingCopyRow行数大于0,PaddingCopyRow行数等于0时,vers[8]~vers[17]会存放全是默认值当CopyRow(即全为0的值)
并且行数为0的情况并不会放到State和Copy子电路的表中,因为copy_len为0,理应该不做任何操作,代码示例如下: 并且行数为0的情况并不会放到State和Copy子电路的表中,因为copy_len为0,理应该不做任何操作,代码示例如下:
```rust ```rust
fn gen_witness(&self, trace: &GethExecStep, current_state: &mut WitnessExecHelper) -> Witness { fn gen_witness(&self, trace: &GethExecStep, current_state: &mut WitnessExecHelper) -> Witness {
let (stack_pop_0, address) = current_state.get_pop_stack_row_value(&trace); let (stack_pop_0, address) = current_state.get_pop_stack_row_value(&trace);
assert!(address.leading_zeros() >= ADDRESS_ZERO_COUNT); assert!(address.leading_zeros() >= ADDRESS_ZERO_COUNT);
//let address_code = current_state.bytecode.get(&address).unwrap(); //let address_code = current_state.bytecode.get(&address).unwrap();
// ... // ...
let (copy_rows, mem_rows, input_length, padding_length, code_copy_length) = let (copy_rows, mem_rows, input_length, padding_length, code_copy_length) =
current_state.get_code_copy_rows_new(address, mem_offset, code_offset, size); current_state.get_code_copy_rows_new(address, mem_offset, code_offset, size);
let mut default_copy_row = &current_state.get_none_copy_row(); let mut default_copy_row = &current_state.get_none_copy_row();
if input_length > 0 && code_copy_length > 0 { if input_length > 0 && code_copy_length > 0 {
default_copy_row = &copy_rows[0]; default_copy_row = &copy_rows[0];
} }
let mut default_padding_row = &current_state.get_none_padding_copy_row(); let mut default_padding_row = &current_state.get_none_padding_copy_row();
if input_length > 0 && padding_length > 0 { if input_length > 0 && padding_length > 0 {
default_padding_row = &copy_rows[code_copy_length as usize] default_padding_row = &copy_rows[code_copy_length as usize]
} }
// ... // ...
if input_length > 0 { if input_length > 0 {
Witness { Witness {
copy: copy_rows, copy: copy_rows,
core: vec![core_row_2, core_row_1, core_row_0], core: vec![core_row_2, core_row_1, core_row_0],
state: state_vec, state: state_vec,
..Default::default() ..Default::default()
} }
} else { } else {
Witness { Witness {
core: vec![core_row_2, core_row_1, core_row_0], core: vec![core_row_2, core_row_1, core_row_0],
state: state_vec, state: state_vec,
..Default::default() ..Default::default()
} }
} }
} }
``` ```
### 门约束 ### 门约束
**1. 当前的OPCODE一致** **1. 当前的OPCODE一致**
这是确保我们正在处理的操作码是EXTCODECOPY操作码。 这是确保我们正在处理的操作码是EXTCODECOPY操作码。
**2. Stack Value约束** **2. Stack Value约束**
约束包括 `tag`, `state_stamp`, `call_id`, `stack_pointer`, `is_write`,确保这些值在执行EXTCODECOPY操作时的一致性和正确性。 约束包括 `tag`, `state_stamp`, `call_id`, `stack_pointer`, `is_write`,确保这些值在执行EXTCODECOPY操作时的一致性和正确性。
**3. Auxiliary字段约束** **3. Auxiliary字段约束**
包括 `state_stamp`, `stack_pointer`, `log_stamp`, `read_only`,特别是要注意`state_stamp`在拷贝长度为0的情况下的处理。 包括 `state_stamp`, `stack_pointer`, `log_stamp`, `read_only`,特别是要注意`state_stamp`在拷贝长度为0的情况下的处理。
**4. next_pc=stack_top_value_lo** **4. next_pc=stack_top_value_lo**
表示从栈顶获取的值作为跳转的地址,由于PC范围在u64内,只取value_lo部分即可。 表示从栈顶获取的值作为跳转的地址,由于PC范围在u64内,只取value_lo部分即可。
**5. lookup_value约束** **5. lookup_value约束**
确保拷贝操作中的各种值的一致性和正确性: 确保拷贝操作中的各种值的一致性和正确性:
1. `copy_lookup_len * (copy_lookup_src_type - Bytecode)`:当真实发生代码拷贝时,`src_type`必然是Bytecode类型。 1. `copy_lookup_len * (copy_lookup_src_type - Bytecode)`:当真实发生代码拷贝时,`src_type`必然是Bytecode类型。
2. `copy_lookup_len * (copy_lookup_dst_type - Memory)`:当真实发生代码拷贝时,`dst_type`必然是Memory类型。 2. `copy_lookup_len * (copy_lookup_dst_type - Memory)`:当真实发生代码拷贝时,`dst_type`必然是Memory类型。
3. `copy_lookup_len * (copy_lookup_dst_id - call_id)`:当真实发生代码拷贝时,`dst_id`必然是当前的`call_id`。 3. `copy_lookup_len * (copy_lookup_dst_id - call_id)`:当真实发生代码拷贝时,`dst_id`必然是当前的`call_id`。
4. `copy_lookup_len * (copy_lookup_dst_stamp - copy_code_stamp_start - 1)`:当真实发生代码拷贝时,拷贝代码行开始处必然在最后一个出栈元素的下一行。 4. `copy_lookup_len * (copy_lookup_dst_stamp - copy_code_stamp_start - 1)`:当真实发生代码拷贝时,拷贝代码行开始处必然在最后一个出栈元素的下一行。
5. `copy_lookup_len * (copy_lookup_src_id - address)`:当真实发生代码拷贝时,`src_id`必然是代码块的地址。 5. `copy_lookup_len * (copy_lookup_src_id - address)`:当真实发生代码拷贝时,`src_id`必然是代码块的地址。
6. `copy_lookup_len * (copy_lookup_dst_pointer - mem_offset)`:当真实发生代码拷贝时,`dst_pointer`必然是内存偏移量。 6. `copy_lookup_len * (copy_lookup_dst_pointer - mem_offset)`:当真实发生代码拷贝时,`dst_pointer`必然是内存偏移量。
7. `copy_lookup_len * (copy_lookup_src_pointer - code_offset)`:当真实发生代码拷贝时,`src_pointer`必然是代码偏移量。 7. `copy_lookup_len * (copy_lookup_src_pointer - code_offset)`:当真实发生代码拷贝时,`src_pointer`必然是代码偏移量。
8. `copy_lookup_len + copy_padding_lookup_len - length`:代码拷贝长度加上padding的长度必然等于指定的拷贝长度。 8. `copy_lookup_len + copy_padding_lookup_len - length`:代码拷贝长度加上padding的长度必然等于指定的拷贝长度。
9. `copy_padding_lookup_src_type - Zero`:padding的`src_type`为Zero类型,即默认类型。 9. `copy_padding_lookup_src_type - Zero`:padding的`src_type`为Zero类型,即默认类型。
10. `copy_padding_lookup_len * (copy_padding_lookup_dst_type - Memory)`:当真实有padding数据时,`dst_type`应该是Memory。 10. `copy_padding_lookup_len * (copy_padding_lookup_dst_type - Memory)`:当真实有padding数据时,`dst_type`应该是Memory。
11. `copy_padding_lookup_src_id - 0`:padding的`src_id`为默认值0。 11. `copy_padding_lookup_src_id - 0`:padding的`src_id`为默认值0。
12. `copy_padding_lookup_src_pointer - 0`:padding的`src_pointer`为默认值0。 12. `copy_padding_lookup_src_pointer - 0`:padding的`src_pointer`为默认值0。
13. `copy_padding_lookup_len * (copy_padding_lookup_dst_pointer - copy_lookup_dst_pointer - copy_lookup_len)`:当真实有padding数据时,`padding`的`dst_pointer`与`copy`的`dst_pointer`相差拷贝的代码长度。 13. `copy_padding_lookup_len * (copy_padding_lookup_dst_pointer - copy_lookup_dst_pointer - copy_lookup_len)`:当真实有padding数据时,`padding`的`dst_pointer`与`copy`的`dst_pointer`相差拷贝的代码长度。
14. `copy_padding_lookup_len * (copy_padding_lookup_dst_stamp - copy_code_stamp_start - copy_lookup_len - 1)`:当真实有padding数据时,`padding`的`dst_stamp`与栈中最后一个元素所处的`stamp`相差真实拷贝的代码长度加1。 14. `copy_padding_lookup_len * (copy_padding_lookup_dst_stamp - copy_code_stamp_start - copy_lookup_len - 1)`:当真实有padding数据时,`padding`的`dst_stamp`与栈中最后一个元素所处的`stamp`相差真实拷贝的代码长度加1。
可参考如下示例代码: 可参考如下示例代码:
```rust ```rust
fn get_constraints( fn get_constraints(
&self, &self,
config: &ExecutionConfig<F, NUM_STATE_HI_COL, NUM_STATE_LO_COL>, config: &ExecutionConfig<F, NUM_STATE_HI_COL, NUM_STATE_LO_COL>,
meta: &mut VirtualCells<F>, meta: &mut VirtualCells<F>,
) -> Vec<(String, Expression<F>)> { ) -> Vec<(String, Expression<F>)> {
let opcode = meta.query_advice(config.opcode, Rotation::cur()); let opcode = meta.query_advice(config.opcode, Rotation::cur());
let pc_cur = meta.query_advice(config.pc, Rotation::cur()); let pc_cur = meta.query_advice(config.pc, Rotation::cur());
let call_id = meta.query_advice(config.call_id, Rotation::cur()); let call_id = meta.query_advice(config.call_id, Rotation::cur());
let pc_next = meta.query_advice(config.pc, Rotation::next()); let pc_next = meta.query_advice(config.pc, Rotation::next());
let ( let (
copy_lookup_src_type, copy_lookup_src_type,
copy_lookup_src_id, copy_lookup_src_id,
copy_lookup_src_pointer, copy_lookup_src_pointer,
_, _,
copy_lookup_dst_type, copy_lookup_dst_type,
copy_lookup_dst_id, copy_lookup_dst_id,
copy_lookup_dst_pointer, copy_lookup_dst_pointer,
copy_lookup_dst_stamp, copy_lookup_dst_stamp,
copy_lookup_len, copy_lookup_len,
) = extract_lookup_expression!(copy, config.get_copy_lookup(meta)); ) = extract_lookup_expression!(copy, config.get_copy_lookup(meta));
let ( let (
copy_padding_lookup_src_type, copy_padding_lookup_src_type,
copy_padding_lookup_src_id, copy_padding_lookup_src_id,
copy_padding_lookup_src_pointer, copy_padding_lookup_src_pointer,
_, _,
copy_padding_lookup_dst_type, copy_padding_lookup_dst_type,
copy_padding_lookup_dst_id, copy_padding_lookup_dst_id,
copy_padding_lookup_dst_pointer, copy_padding_lookup_dst_pointer,
copy_padding_lookup_dst_stamp, copy_padding_lookup_dst_stamp,
copy_padding_lookup_len, copy_padding_lookup_len,
) = extract_lookup_expression!(copy, config.get_copy_padding_lookup(meta)); ) = extract_lookup_expression!(copy, config.get_copy_padding_lookup(meta));
let delta = AuxiliaryDelta { let delta = AuxiliaryDelta {
state_stamp: STATE_STAMP_DELTA.expr() state_stamp: STATE_STAMP_DELTA.expr()
+ copy_lookup_len.clone() + copy_lookup_len.clone()
+ copy_padding_lookup_len.clone(), + copy_padding_lookup_len.clone(),
stack_pointer: STACK_POINTER_DELTA.expr(), stack_pointer: STACK_POINTER_DELTA.expr(),
..Default::default() ..Default::default()
}; };
// auxiliary constraints ... // auxiliary constraints ...
// stack constraints ... // stack constraints ...
// copy lookup constraints // copy lookup constraints
constraints.extend([ constraints.extend([
( (
"etxcodecopy src_type".into(), "etxcodecopy src_type".into(),
copy_lookup_len.clone() copy_lookup_len.clone()
* (copy_lookup_src_type.clone() - (copy::Type::Bytecode as u8).expr()), * (copy_lookup_src_type.clone() - (copy::Type::Bytecode as u8).expr()),
), ),
( (
"extcodecopy dst_type".into(), "extcodecopy dst_type".into(),
copy_lookup_len.clone() copy_lookup_len.clone()
* (copy_lookup_dst_type.clone() - (copy::Type::Memory as u8).expr()), * (copy_lookup_dst_type.clone() - (copy::Type::Memory as u8).expr()),
), ),
( (
"extcodecopy dst_id".into(), "extcodecopy dst_id".into(),
copy_lookup_len.clone() * (copy_lookup_dst_id.clone() - call_id.clone()), copy_lookup_len.clone() * (copy_lookup_dst_id.clone() - call_id.clone()),
), ),
( (
"extcodecopy dst_stamp".into(), "extcodecopy dst_stamp".into(),
copy_lookup_len.clone() copy_lookup_len.clone()
* (copy_lookup_dst_stamp.clone() - copy_code_stamp_start.clone() - 1.expr()), * (copy_lookup_dst_stamp.clone() - copy_code_stamp_start.clone() - 1.expr()),
), ),
( (
"extcodecopy src_id".into(), "extcodecopy src_id".into(),
copy_lookup_len.clone() copy_lookup_len.clone()
* (copy_lookup_src_id * (copy_lookup_src_id
- copy_operands[0][0].clone() * pow_of_two::<F>(128) - copy_operands[0][0].clone() * pow_of_two::<F>(128)
- copy_operands[0][1].clone()), - copy_operands[0][1].clone()),
), ),
( (
"extcodecopy dst_pointer value_hi = 0".into(), "extcodecopy dst_pointer value_hi = 0".into(),
copy_operands[1][0].clone() - 0.expr(), copy_operands[1][0].clone() - 0.expr(),
), ),
( (
"extcodecopy dst_pointer".into(), "extcodecopy dst_pointer".into(),
copy_lookup_len.clone() copy_lookup_len.clone()
* (copy_lookup_dst_pointer.clone() - copy_operands[1][1].clone()), * (copy_lookup_dst_pointer.clone() - copy_operands[1][1].clone()),
), ),
( (
"extcodecopy src_pointer value_hi = 0".into(), "extcodecopy src_pointer value_hi = 0".into(),
copy_operands[2][0].clone() - 0.expr(), copy_operands[2][0].clone() - 0.expr(),
), ),
( (
"extcodecopy src_pointer".into(), "extcodecopy src_pointer".into(),
copy_lookup_len.clone() copy_lookup_len.clone()
* (copy_lookup_src_pointer.clone() - copy_operands[2][1].clone()), * (copy_lookup_src_pointer.clone() - copy_operands[2][1].clone()),
), ),
( (
"extcodecopy len value_hi = 0".into(), "extcodecopy len value_hi = 0".into(),
copy_operands[3][0].clone() - 0.expr(), copy_operands[3][0].clone() - 0.expr(),
), ),
( (
"extcodecopy len".into(), "extcodecopy len".into(),
copy_lookup_len.clone() + copy_padding_lookup_len.clone() copy_lookup_len.clone() + copy_padding_lookup_len.clone()
- copy_operands[3][1].clone(), - copy_operands[3][1].clone(),
), ),
( (
"extcodecopy padding src_type".into(), "extcodecopy padding src_type".into(),
copy_padding_lookup_src_type.clone() - (copy::Type::default() as u8).expr(), copy_padding_lookup_src_type.clone() - (copy::Type::default() as u8).expr(),
), ),
( (
"extcodecopy padding dst_type".into(), "extcodecopy padding dst_type".into(),
copy_padding_lookup_len.clone() copy_padding_lookup_len.clone()
* (copy_padding_lookup_dst_type.clone() - (copy::Type::Memory as u8).expr()), * (copy_padding_lookup_dst_type.clone() - (copy::Type::Memory as u8).expr()),
), ),
( (
"extcodecopy padding src_id".into(), "extcodecopy padding src_id".into(),
copy_padding_lookup_src_id.clone() - 0.expr(), copy_padding_lookup_src_id.clone() - 0.expr(),
), ),
( (
"extcodecopy padding src_pointer".into(), "extcodecopy padding src_pointer".into(),
copy_padding_lookup_src_pointer.clone() - 0.expr(), copy_padding_lookup_src_pointer.clone() - 0.expr(),
), ),
( (
"extcodecopy padding dst_id".into(), "extcodecopy padding dst_id".into(),
copy_padding_lookup_len.clone() copy_padding_lookup_len.clone()
* (copy_padding_lookup_dst_id.clone() - call_id.clone()), * (copy_padding_lookup_dst_id.clone() - call_id.clone()),
), ),
( (
"extcodecopy padding dst_pointer".into(), "extcodecopy padding dst_pointer".into(),
copy_padding_lookup_len.clone() copy_padding_lookup_len.clone()
* (copy_padding_lookup_dst_pointer.clone() * (copy_padding_lookup_dst_pointer.clone()
- copy_lookup_dst_pointer.clone() - copy_lookup_dst_pointer.clone()
- copy_lookup_len.clone()), - copy_lookup_len.clone()),
), ),
( (
"extcodecopy padding copy_padding_lookup_dst_stamp".into(), "extcodecopy padding copy_padding_lookup_dst_stamp".into(),
copy_padding_lookup_len.clone() copy_padding_lookup_len.clone()
* (copy_padding_lookup_dst_stamp.clone() * (copy_padding_lookup_dst_stamp.clone()
- copy_code_stamp_start.clone() - copy_code_stamp_start.clone()
- copy_lookup_len.clone() - copy_lookup_len.clone()
- 1.expr()), - 1.expr()),
), ),
]); ]);
// pc & opcode constrains ... // pc & opcode constrains ...
constraints constraints
} }
``` ```
### LookUp约束 ### LookUp约束
LookUp约束被放在 `cnt=2` 的 CopyRow,分为两种约束:NoPaddingCopy的约束和PaddingCopy约束,各占9列:vers[0]~vers[8] 和 vers[9]~vers[17]。 LookUp约束被放在 `cnt=2` 的 CopyRow,分为两种约束:NoPaddingCopy的约束和PaddingCopy约束,各占9列:vers[0]~vers[8] 和 vers[9]~vers[17]。
当 `offset + copy_len > len(code)` 时,需要填充0,填充长度为 `offset + copy_len - len(code)`。 当 `offset + copy_len > len(code)` 时,需要填充0,填充长度为 `offset + copy_len - len(code)`。
- **来源**:Core - **来源**:Core
- **去向**:Copy - **去向**:Copy
特别注意:当 `copy_len` 为0或者 `padding_len` 为0时,CopyRow的所有值都是默认值(全为零值)也是需要进行LookUp的(LookUp Copy中全为默认值行)。 特别注意:当 `copy_len` 为0或者 `padding_len` 为0时,CopyRow的所有值都是默认值(全为零值)也是需要进行LookUp的(LookUp Copy中全为默认值行)。
#### insert_copy_lookup #### insert_copy_lookup
在copy row cnt=2的位置分别NoPaddingCopyRow(vers[0]~vers[8])和PaddingCopyRow(vers[9]~vers[17])要lookUp的值 在copy row cnt=2的位置分别NoPaddingCopyRow(vers[0]~vers[8])和PaddingCopyRow(vers[9]~vers[17])要lookUp的值
```rust ```rust
fn gen_witness(&self, trace: &GethExecStep, current_state: &mut WitnessExecHelper) -> Witness { fn gen_witness(&self, trace: &GethExecStep, current_state: &mut WitnessExecHelper) -> Witness {
// ... // ...
// 生成copy_rows // 生成copy_rows
let (copy_rows, mem_rows, input_length, padding_length, code_copy_length) = let (copy_rows, mem_rows, input_length, padding_length, code_copy_length) =
current_state.get_code_copy_rows_new(address, mem_offset, code_offset, size); current_state.get_code_copy_rows_new(address, mem_offset, code_offset, size);
// default_copy_row:全为默认值的CopyRow // default_copy_row:全为默认值的CopyRow
let mut default_copy_row = &current_state.get_none_copy_row(); let mut default_copy_row = &current_state.get_none_copy_row();
if input_length > 0 && code_copy_length > 0 { if input_length > 0 && code_copy_length > 0 {
default_copy_row = &copy_rows[0]; default_copy_row = &copy_rows[0];
} }
// default_padding_row:全为默认值的CopyRow // default_padding_row:全为默认值的CopyRow
let mut default_padding_row = &current_state.get_none_copy_row(); let mut default_padding_row = &current_state.get_none_copy_row();
if input_length > 0 && padding_length > 0 { if input_length > 0 && padding_length > 0 {
default_padding_row = &copy_rows[code_copy_length as usize] default_padding_row = &copy_rows[code_copy_length as usize]
} }
core_row_2.insert_copy_lookup_new( core_row_2.insert_copy_lookup_new(
default_copy_row, default_copy_row,
default_padding_row, default_padding_row,
code_copy_length, code_copy_length,
padding_length, padding_length,
); );
// ... // ...
} }
pub fn insert_copy_lookup_new( pub fn insert_copy_lookup_new(
&mut self, &mut self,
copy: &copy::Row, copy: &copy::Row,
padding_copy: &copy::Row, padding_copy: &copy::Row,
copy_length: u64, copy_length: u64,
padding_length: u64, padding_length: u64,
) { ) {
// //
assert_eq!(self.cnt, 2.into()); assert_eq!(self.cnt, 2.into());
for (cell, value) in [ for (cell, value) in [
// code copy // code copy
(&mut self.vers_0, Some((copy.src_type as u8).into())), (&mut self.vers_0, Some((copy.src_type as u8).into())),
(&mut self.vers_1, Some(copy.src_id)), (&mut self.vers_1, Some(copy.src_id)),
(&mut self.vers_2, Some(copy.src_pointer)), (&mut self.vers_2, Some(copy.src_pointer)),
(&mut self.vers_3, copy.src_stamp), (&mut self.vers_3, copy.src_stamp),
(&mut self.vers_4, Some((copy.dst_type as u8).into())), (&mut self.vers_4, Some((copy.dst_type as u8).into())),
(&mut self.vers_5, Some(copy.dst_id)), (&mut self.vers_5, Some(copy.dst_id)),
(&mut self.vers_6, Some(copy.dst_pointer)), (&mut self.vers_6, Some(copy.dst_pointer)),
(&mut self.vers_7, Some(copy.dst_stamp)), (&mut self.vers_7, Some(copy.dst_stamp)),
(&mut self.vers_8, Some(copy.len)), (&mut self.vers_8, Some(copy.len)),
// padding copy // padding copy
(&mut self.vers_9, Some((padding_copy.src_type as u8).into())), (&mut self.vers_9, Some((padding_copy.src_type as u8).into())),
(&mut self.vers_10, Some(padding_copy.src_id)), (&mut self.vers_10, Some(padding_copy.src_id)),
(&mut self.vers_11, Some(padding_copy.src_pointer)), (&mut self.vers_11, Some(padding_copy.src_pointer)),
(&mut self.vers_12, padding_copy.src_stamp), (&mut self.vers_12, padding_copy.src_stamp),
( (
&mut self.vers_13, &mut self.vers_13,
Some((padding_copy.dst_type as u8).into()), Some((padding_copy.dst_type as u8).into()),
), ),
(&mut self.vers_14, Some(padding_copy.dst_id)), (&mut self.vers_14, Some(padding_copy.dst_id)),
(&mut self.vers_15, Some(padding_copy.dst_pointer)), (&mut self.vers_15, Some(padding_copy.dst_pointer)),
(&mut self.vers_16, Some(padding_copy.dst_stamp)), (&mut self.vers_16, Some(padding_copy.dst_stamp)),
(&mut self.vers_17, Some(padding_copy.len)), (&mut self.vers_17, Some(padding_copy.len)),
// (&mut self.vers_18, Some(U256::from(copy_length))), // (&mut self.vers_18, Some(U256::from(copy_length))),
// (&mut self.vers_19, Some(U256::from(padding_length))), // (&mut self.vers_19, Some(U256::from(padding_length))),
// //
] { ] {
// before inserting, these columns must be none // before inserting, these columns must be none
assert!(cell.is_none()); assert!(cell.is_none());
*cell = value; *cell = value;
} }
// .... // ....
} }
``` ```
#### get_lookups #### get_lookups
从copy row cnt=2的位置分别去NoPaddingCopyRow: vers[0]~vers[8],PaddingCopyRow: vers[9]~vers[17] 这里除了四个 state lookup 外
```rust - [5-state](../5-state.markdown)
fn get_lookups(
&self,
config: &ExecutionConfig<F, NUM_STATE_HI_COL, NUM_STATE_LO_COL>, 还需要copy lookup,从copy row cnt=2的位置分别去NoPaddingCopyRow: vers[0]~vers[8],PaddingCopyRow: vers[9]~vers[17],参考:
meta: &mut ConstraintSystem<F>,
) -> Vec<(String, LookupEntry<F>)> { - [7-copy](../7-copy.markdown)
let stack_lookup_0 = query_expression(meta, |meta| config.get_state_lookup(meta, 0));
let stack_lookup_1 = query_expression(meta, |meta| config.get_state_lookup(meta, 1));
let stack_lookup_2 = query_expression(meta, |meta| config.get_state_lookup(meta, 2));
let stack_lookup_3 = query_expression(meta, |meta| config.get_state_lookup(meta, 3));
let copy_lookup = query_expression(meta, |meta| config.get_copy_lookup(meta));
let padding_copy_lookup =
query_expression(meta, |meta| config.get_copy_padding_lookup(meta));
vec![
("stack pop account address".into(), stack_lookup_0),
("stack pop mem offset".into(), stack_lookup_1),
("stack pop code offset".into(), stack_lookup_2),
("stack pop length".into(), stack_lookup_3),
("copy look up".into(), copy_lookup),
("padding look up".into(), padding_copy_lookup),
]
}
```
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号