-
Notifications
You must be signed in to change notification settings - Fork 856
[CREATE Part A] Modification to Copy Circuit #1356
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,8 @@ pub struct CopyCircuitConfig<F> { | |
pub is_last: Column<Advice>, | ||
/// The value copied in this copy step. | ||
pub value: Column<Advice>, | ||
/// Random linear combination accumulator value. | ||
pub value_acc: Column<Advice>, | ||
/// Whether the row is padding. | ||
pub is_pad: Column<Advice>, | ||
/// In case of a bytecode tag, this denotes whether or not the copied byte | ||
|
@@ -105,6 +107,7 @@ impl<F: Field> SubCircuitConfig<F> for CopyCircuitConfig<F> { | |
let q_step = meta.complex_selector(); | ||
let is_last = meta.advice_column(); | ||
let value = meta.advice_column_in(SecondPhase); | ||
let value_acc = meta.advice_column_in(SecondPhase); | ||
let is_code = meta.advice_column(); | ||
let is_pad = meta.advice_column(); | ||
let is_first = copy_table.is_first; | ||
|
@@ -222,23 +225,48 @@ impl<F: Field> SubCircuitConfig<F> for CopyCircuitConfig<F> { | |
rw_diff, | ||
); | ||
}); | ||
cb.condition( | ||
and::expr([ | ||
meta.query_advice(is_last, Rotation::cur()), | ||
tag.value_equals(CopyDataType::RlcAcc, Rotation::cur())(meta), | ||
]), | ||
|cb| { | ||
cb.require_equal( | ||
"value == rlc_acc at the last row for RlcAcc", | ||
meta.query_advice(value, Rotation::cur()), | ||
meta.query_advice(rlc_acc, Rotation::cur()), | ||
); | ||
}, | ||
); | ||
|
||
cb.gate(meta.query_fixed(q_enable, Rotation::cur())) | ||
}); | ||
|
||
meta.create_gate( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems this gate and next gate can be combine into just 1 gate ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed in 55aebf9 |
||
"Last Step (check value accumulator) Memory => Bytecode", | ||
|meta| { | ||
let mut cb = BaseConstraintBuilder::default(); | ||
|
||
cb.require_equal( | ||
"value_acc == rlc_acc on the last row", | ||
meta.query_advice(value_acc, Rotation::next()), | ||
meta.query_advice(rlc_acc, Rotation::next()), | ||
); | ||
|
||
cb.gate(and::expr([ | ||
meta.query_fixed(q_enable, Rotation::cur()), | ||
meta.query_advice(is_last, Rotation::next()), | ||
and::expr([ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here nested There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree, I don't think we need it, but it has better readability for me. I prefer to keep the way it is. How do you think? |
||
tag.value_equals(CopyDataType::Memory, Rotation::cur())(meta), | ||
tag.value_equals(CopyDataType::Bytecode, Rotation::next())(meta), | ||
]), | ||
])) | ||
}, | ||
); | ||
|
||
meta.create_gate("Last Step (check value accumulator) RlcAcc", |meta| { | ||
let mut cb = BaseConstraintBuilder::default(); | ||
|
||
cb.require_equal( | ||
"value_acc == rlc_acc on the last row", | ||
meta.query_advice(value_acc, Rotation::next()), | ||
meta.query_advice(rlc_acc, Rotation::next()), | ||
); | ||
|
||
cb.gate(and::expr([ | ||
meta.query_fixed(q_enable, Rotation::cur()), | ||
meta.query_advice(is_last, Rotation::next()), | ||
tag.value_equals(CopyDataType::RlcAcc, Rotation::next())(meta), | ||
])) | ||
}); | ||
|
||
meta.create_gate("verify step (q_step == 1)", |meta| { | ||
let mut cb = BaseConstraintBuilder::default(); | ||
|
||
|
@@ -262,25 +290,30 @@ impl<F: Field> SubCircuitConfig<F> for CopyCircuitConfig<F> { | |
); | ||
}, | ||
); | ||
cb.require_equal( | ||
"write value == read value", | ||
meta.query_advice(value, Rotation::cur()), | ||
meta.query_advice(value, Rotation::next()), | ||
); | ||
cb.require_equal( | ||
"value_acc is same for read-write rows", | ||
meta.query_advice(value_acc, Rotation::cur()), | ||
meta.query_advice(value_acc, Rotation::next()), | ||
); | ||
cb.condition( | ||
not::expr(tag.value_equals(CopyDataType::RlcAcc, Rotation::next())( | ||
meta, | ||
)), | ||
and::expr([ | ||
not::expr(meta.query_advice(is_last, Rotation::next())), | ||
not::expr(meta.query_advice(is_pad, Rotation::cur())), | ||
]), | ||
|cb| { | ||
cb.require_equal( | ||
"write value == read value (if not rlc acc)", | ||
meta.query_advice(value, Rotation::cur()), | ||
meta.query_advice(value, Rotation::next()), | ||
"value_acc(2) == value_acc(0) * r + value(2)", | ||
meta.query_advice(value_acc, Rotation(2)), | ||
meta.query_advice(value_acc, Rotation::cur()) * challenges.keccak_input() | ||
+ meta.query_advice(value, Rotation(2)), | ||
); | ||
}, | ||
); | ||
cb.condition(meta.query_advice(is_first, Rotation::cur()), |cb| { | ||
cb.require_equal( | ||
"write value == read value (is_first == 1)", | ||
meta.query_advice(value, Rotation::cur()), | ||
meta.query_advice(value, Rotation::next()), | ||
); | ||
}); | ||
cb.require_zero( | ||
"value == 0 when is_pad == 1 for read", | ||
and::expr([ | ||
|
@@ -298,25 +331,9 @@ impl<F: Field> SubCircuitConfig<F> for CopyCircuitConfig<F> { | |
meta.query_advice(is_pad, Rotation::next()), | ||
); | ||
|
||
cb.gate(meta.query_selector(q_step)) | ||
}); | ||
|
||
meta.create_gate("verify_step (q_step == 0)", |meta| { | ||
let mut cb = BaseConstraintBuilder::default(); | ||
|
||
cb.require_equal( | ||
"rows[2].value == rows[0].value * r + rows[1].value", | ||
meta.query_advice(value, Rotation(2)), | ||
meta.query_advice(value, Rotation::cur()) * challenges.keccak_input() | ||
+ meta.query_advice(value, Rotation::next()), | ||
); | ||
|
||
cb.gate(and::expr([ | ||
meta.query_fixed(q_enable, Rotation::cur()), | ||
not::expr(meta.query_selector(q_step)), | ||
not::expr(meta.query_advice(is_last, Rotation::cur())), | ||
tag.value_equals(CopyDataType::RlcAcc, Rotation::cur())(meta), | ||
not::expr(meta.query_advice(is_pad, Rotation::cur())), | ||
meta.query_selector(q_step), | ||
])) | ||
}); | ||
|
||
|
@@ -402,6 +419,7 @@ impl<F: Field> SubCircuitConfig<F> for CopyCircuitConfig<F> { | |
q_step, | ||
is_last, | ||
value, | ||
value_acc, | ||
is_pad, | ||
is_code, | ||
q_enable, | ||
|
@@ -463,9 +481,15 @@ impl<F: Field> CopyCircuitConfig<F> { | |
)?; | ||
|
||
// is_last, value, is_pad, is_code | ||
for (column, &(value, label)) in [self.is_last, self.value, self.is_pad, self.is_code] | ||
.iter() | ||
.zip_eq(circuit_row) | ||
for (column, &(value, label)) in [ | ||
self.is_last, | ||
self.value, | ||
self.value_acc, | ||
self.is_pad, | ||
self.is_code, | ||
] | ||
.iter() | ||
.zip_eq(circuit_row) | ||
{ | ||
region.assign_advice( | ||
|| format!("{} at row: {}", label, *offset), | ||
|
@@ -616,6 +640,13 @@ impl<F: Field> CopyCircuitConfig<F> { | |
*offset, | ||
|| Value::known(F::zero()), | ||
)?; | ||
// value_acc | ||
region.assign_advice( | ||
|| format!("assign value_acc {}", *offset), | ||
self.value_acc, | ||
*offset, | ||
|| Value::known(F::zero()), | ||
)?; | ||
// rlc_acc | ||
region.assign_advice( | ||
|| format!("assign rlc_acc {}", *offset), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ pub(crate) struct ReturnRevertGadget<F> { | |
opcode: Cell<F>, | ||
|
||
range: MemoryAddressGadget<F>, | ||
init_code_rlc: Cell<F>, | ||
|
||
is_success: Cell<F>, | ||
restore_context: RestoreContextGadget<F>, | ||
|
@@ -94,11 +95,12 @@ impl<F: Field> ExecutionGadget<F> for ReturnRevertGadget<F> { | |
|
||
let is_contract_deployment = | ||
is_create.clone() * is_success.expr() * not::expr(copy_rw_increase_is_zero.expr()); | ||
let (caller_id, address, reversion_info, code_hash) = | ||
let (caller_id, address, reversion_info, code_hash, init_code_rlc) = | ||
han0110 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
cb.condition(is_contract_deployment.clone(), |cb| { | ||
// We don't need to place any additional constraints on code_hash because the | ||
// copy circuit enforces that it is the hash of the bytes in the copy lookup. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since intruduce There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what comment I should add. Could you provide an example? |
||
let code_hash = cb.query_cell_phase2(); | ||
let init_code_rlc = cb.query_cell_phase2(); | ||
cb.copy_table_lookup( | ||
cb.curr.state.call_id.expr(), | ||
CopyDataType::Memory.expr(), | ||
|
@@ -108,7 +110,7 @@ impl<F: Field> ExecutionGadget<F> for ReturnRevertGadget<F> { | |
range.address(), | ||
0.expr(), | ||
range.length(), | ||
0.expr(), | ||
init_code_rlc.expr(), | ||
copy_rw_increase.expr(), | ||
); | ||
|
||
|
@@ -127,7 +129,7 @@ impl<F: Field> ExecutionGadget<F> for ReturnRevertGadget<F> { | |
Some(&mut reversion_info), | ||
); | ||
|
||
(caller_id, address, reversion_info, code_hash) | ||
(caller_id, address, reversion_info, code_hash, init_code_rlc) | ||
}); | ||
|
||
// Case B in the specs. | ||
|
@@ -218,6 +220,7 @@ impl<F: Field> ExecutionGadget<F> for ReturnRevertGadget<F> { | |
Self { | ||
opcode, | ||
range, | ||
init_code_rlc, | ||
is_success, | ||
copy_length, | ||
copy_rw_increase, | ||
|
@@ -276,6 +279,11 @@ impl<F: Field> ExecutionGadget<F> for ReturnRevertGadget<F> { | |
let values: Vec<_> = (3..3 + length.as_usize()) | ||
.map(|i| block.rws[step.rw_indices[i]].memory_value()) | ||
.collect(); | ||
self.init_code_rlc.assign( | ||
region, | ||
offset, | ||
region.keccak_rlc(&values.iter().rev().cloned().collect::<Vec<u8>>()), | ||
)?; | ||
let mut code_hash = CodeDB::hash(&values).to_fixed_bytes(); | ||
code_hash.reverse(); | ||
self.code_hash.assign( | ||
|
@@ -617,10 +625,8 @@ mod test { | |
PUSH1(0) // dest offset | ||
RETURNDATACOPY | ||
}); | ||
|
||
let block: GethData = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode.clone()) | ||
.unwrap() | ||
.into(); | ||
let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode.clone()).unwrap(); | ||
let block: GethData = test_ctx.clone().into(); | ||
|
||
// collect return opcode, retrieve next step, assure both contract create | ||
// successfully | ||
|
@@ -651,7 +657,6 @@ mod test { | |
.iter() | ||
.for_each(|size| assert_eq!(size, &Word::zero())); | ||
|
||
let text_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(); | ||
CircuitTestBuilder::new_from_test_ctx(text_ctx).run(); | ||
CircuitTestBuilder::new_from_test_ctx(test_ctx).run(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename
value_acc
intovalue_keccak_acc
for more self-explanationThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to rename to
value_acc_rlc
. Most of our code and docs are using_rlc
as suffix to represent rlc variables and it looks good to me without keyword,keccak
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in 55aebf9