# copy circuit memory to memory
### current copy circuit behavior
current copy event consists of field `bytes`
CopyEvent {
rw_counter_start,
src_type: CopyDataType::Memory,
src_id: NumberOrHash::Number(source.id),
src_addr: source.offset.try_into().unwrap(),
src_addr_end: (source.offset + source.length).try_into().unwrap(),
dst_type: CopyDataType::Memory,
dst_id: NumberOrHash::Number(destination.id),
dst_addr: destination.offset.try_into().unwrap(),
log_id: None,
bytes: copy_steps,
},
this field generate two steps for each byte: read step, write step。 copy circuit do the following two key constraints base on this two adjacement steps(rows).
1. constrain read_step_value = write_step_value
2. lookup read/write records in rw table, ensure read/write oepration occurs.
for read step, look up input is tuple of (src_addr, src_id, src_tag, value). for write step, it is tuple of (dst_addr, dst_id, dst_tag, value).
### memory to memory adaption
for copy memory --> memory cases, after padding read and write bytes to multiple of 32, there are two different bytes sequence in the copy event.
1. first add new `aux_bytes` in the copy event (buss mapping)
`
CopyEvent {
rw_counter_start,
src_type: CopyDataType::Memory,
src_id: NumberOrHash::Number(source.id),
src_addr: source.offset.try_into().unwrap(),
src_addr_end: (source.offset + source.length).try_into().unwrap(),
dst_type: CopyDataType::Memory,
dst_id: NumberOrHash::Number(destination.id),
dst_addr: destination.offset.try_into().unwrap(),
log_id: None,
bytes: read_steps,
**aux_bytes: Option(write_steps)**
},
2. copy circuit changes
modify copy circuit to generate write steps with aux_bytes. read steps remains the same. but this will break copy circuit first key constrain: `read_step_value = write_step_value`
for this problem, walk around is do rlc for only real copy bytes against both read and write steps, compare rlc_read_bytes == rlc_write_bytes.
padding bytes won't be involved.

the table looks like as following:
| q_step | tag | mask | Value | word_index | memory_word_rlc | slot_addr| rlc_acc_read |rlc_acc_write|
|---|--|--|---|---| ---| --| -- | -- |
| 1 |Memory| 1 | src_slot_byte0| 0 |rlc0 | 0 | 0 | 0 |
| 0 |Memory| 0 | dst_slot_byte0| 0 |rlc1 | 0 | 0 | 0
| 1 |Memory| 0 | src_slot_byte1| 0 |rlc2 | 0 | src_slot_byte1 | 0
| 0 |Memory| 0 | dst_slot_byte1| 0 |rlc2 | 0 | 0 | dst_slot_byte1
| 1 |Memory| 0 | src_slot_byte2| 0 |rlc3 | 0 | src_slot_byte1*r + src_slot_byte2 | 0
| 0 |Memory| 0 | dst_slot_byte2| 0 |rlc3 | 0 | 0 | dst_slot_byte1 * r + dst_slot_byte2
| 0 |Memory| ..| ...| .. | .. | .. | .. |
| 1 |Memory| 0 | src_slot_byte31 |31|rlc0_31| 0 | src_slot_byte30*r + src_slot_byte31| 0 |
| 1 |Memory| 0 | src_slot_byte31 |31|rlc0_31| 0 | 0| dst_slot_byte30 * r + dst_slot_byte31 |
| .. |..| ..| ...| .. | ..
at the end of copy event,
assert rlc_acc_read == rlc_acc_write.
memory_word_rlc is lookup RW input.
mask: indicates whether it is a real copy byte or pad byte.