-
Notifications
You must be signed in to change notification settings - Fork 298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add memory checks for prover_input, as well as range_checks for prover_input, syscalls/exceptions #1168
Add memory checks for prover_input, as well as range_checks for prover_input, syscalls/exceptions #1168
Changes from 1 commit
d417b78
f347a57
a5b9f90
e456262
e1082bf
c44e260
2010177
e4e901c
df72352
1e3410d
d038f81
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 |
---|---|---|
|
@@ -22,6 +22,12 @@ use crate::memory::{NUM_CHANNELS, VALUE_LIMBS}; | |
use crate::stark::Stark; | ||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; | ||
|
||
const EXTRA_OPS: [usize; 3] = [ | ||
COL_MAP.op.syscall, | ||
COL_MAP.op.exception, | ||
Nashtare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
COL_MAP.op.prover_input, | ||
]; | ||
|
||
pub fn ctl_data_keccak_sponge<F: Field>() -> Vec<Column<F>> { | ||
// When executing KECCAK_GENERAL, the GP memory channels are used as follows: | ||
// GP channel 0: stack[-1] = context | ||
|
@@ -70,9 +76,14 @@ fn ctl_data_binops<F: Field>(ops: &[usize]) -> Vec<Column<F>> { | |
/// case of shift operations, which will skip the first memory channel and use the | ||
/// next three as ternary inputs. Because both `MUL` and `DIV` are binary operations, | ||
/// the last memory channel used for the inputs will be safely ignored. | ||
fn ctl_data_ternops<F: Field>(ops: &[usize], is_shift: bool) -> Vec<Column<F>> { | ||
fn ctl_data_ternops<F: Field>( | ||
ops: &[usize], | ||
extra_ops: &[usize], | ||
is_shift: bool, | ||
) -> Vec<Column<F>> { | ||
let offset = is_shift as usize; | ||
let mut res = Column::singles(ops).collect_vec(); | ||
res.push(Column::sum(extra_ops)); | ||
res.extend(Column::singles(COL_MAP.mem_channels[offset].value)); | ||
res.extend(Column::singles(COL_MAP.mem_channels[offset + 1].value)); | ||
res.extend(Column::singles(COL_MAP.mem_channels[offset + 2].value)); | ||
|
@@ -82,6 +93,33 @@ fn ctl_data_ternops<F: Field>(ops: &[usize], is_shift: bool) -> Vec<Column<F>> { | |
res | ||
} | ||
|
||
fn ctl_data_sys_exc_range_check<F: Field>(ops: &[usize], extra_ops: &[usize]) -> Vec<Column<F>> { | ||
// All arithmetic flags are 0 when the operation is either a syscall or an exception | ||
let mut res = Column::singles(ops).collect_vec(); | ||
res.push(Column::sum(extra_ops)); | ||
res.push(Column::single( | ||
COL_MAP.mem_channels[NUM_GP_CHANNELS - 1].value[6], | ||
)); | ||
// Since we only need to check one limb, the rest of the columns are 0. | ||
res.extend(vec![Column::zero(); VALUE_LIMBS * 4 - 1]); | ||
res | ||
} | ||
|
||
fn ctl_data_prover_input_range_check<F: Field>( | ||
ops: &[usize], | ||
extra_ops: &[usize], | ||
) -> Vec<Column<F>> { | ||
// All arithmetic flags are 0 when the operation is prover_input | ||
let mut res = Column::singles(ops).collect_vec(); | ||
res.push(Column::sum(extra_ops)); | ||
res.extend(Column::singles( | ||
COL_MAP.mem_channels[NUM_GP_CHANNELS - 1].value, | ||
)); | ||
// Since we only need to check one `U256`'s limbs, the rest of the columns are set to 0. | ||
res.extend(vec![Column::zero(); VALUE_LIMBS * 3]); | ||
res | ||
} | ||
|
||
pub fn ctl_data_logic<F: Field>() -> Vec<Column<F>> { | ||
ctl_data_binops(&[COL_MAP.op.and, COL_MAP.op.or, COL_MAP.op.xor]) | ||
} | ||
|
@@ -90,6 +128,60 @@ pub fn ctl_filter_logic<F: Field>() -> Column<F> { | |
Column::sum([COL_MAP.op.and, COL_MAP.op.or, COL_MAP.op.xor]) | ||
} | ||
|
||
pub fn ctl_sys_exc_check_rows<F: Field>() -> TableWithColumns<F> { | ||
const OPS: [usize; 14] = [ | ||
COL_MAP.op.add, | ||
COL_MAP.op.sub, | ||
COL_MAP.op.mul, | ||
COL_MAP.op.lt, | ||
COL_MAP.op.gt, | ||
COL_MAP.op.addfp254, | ||
COL_MAP.op.mulfp254, | ||
COL_MAP.op.subfp254, | ||
COL_MAP.op.addmod, | ||
COL_MAP.op.mulmod, | ||
COL_MAP.op.submod, | ||
COL_MAP.op.div, | ||
COL_MAP.op.mod_, | ||
COL_MAP.op.byte, | ||
]; | ||
// Create the CPU Table whose columns are the gas value and the rest of the columns are 0. | ||
let filter = Some(Column::sum([COL_MAP.op.syscall, COL_MAP.op.exception])); | ||
|
||
TableWithColumns::new( | ||
Table::Cpu, | ||
ctl_data_sys_exc_range_check(&OPS, &EXTRA_OPS), | ||
filter, | ||
) | ||
} | ||
|
||
pub fn ctl_prover_input_check_rows<F: Field>() -> TableWithColumns<F> { | ||
const OPS: [usize; 14] = [ | ||
COL_MAP.op.add, | ||
COL_MAP.op.sub, | ||
COL_MAP.op.mul, | ||
COL_MAP.op.lt, | ||
COL_MAP.op.gt, | ||
COL_MAP.op.addfp254, | ||
COL_MAP.op.mulfp254, | ||
COL_MAP.op.subfp254, | ||
COL_MAP.op.addmod, | ||
COL_MAP.op.mulmod, | ||
COL_MAP.op.submod, | ||
COL_MAP.op.div, | ||
COL_MAP.op.mod_, | ||
COL_MAP.op.byte, | ||
]; | ||
// Create the CPU Table whose columns are the gas value and the rest of the columns are 0. | ||
let filter = Some(Column::single(COL_MAP.op.prover_input)); | ||
|
||
TableWithColumns::new( | ||
Table::Cpu, | ||
ctl_data_prover_input_range_check(&OPS, &EXTRA_OPS), | ||
filter, | ||
) | ||
} | ||
|
||
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. These can be deleted: we can reuse the base arithmetic CTL. 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. @nbgl The reason why I didn't reuse the base arithmetic CTL here was because I only selected the useful columns in the CPU for |
||
pub fn ctl_arithmetic_base_rows<F: Field>() -> TableWithColumns<F> { | ||
const OPS: [usize; 14] = [ | ||
COL_MAP.op.add, | ||
|
@@ -114,7 +206,7 @@ pub fn ctl_arithmetic_base_rows<F: Field>() -> TableWithColumns<F> { | |
// the third input. | ||
TableWithColumns::new( | ||
Table::Cpu, | ||
ctl_data_ternops(&OPS, false), | ||
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. We want to add This way we don't have to have a separate cross-table lookup just for range checks. |
||
ctl_data_ternops(&OPS, &EXTRA_OPS, false), | ||
Some(Column::sum(OPS)), | ||
) | ||
} | ||
|
@@ -145,7 +237,7 @@ pub fn ctl_arithmetic_shift_rows<F: Field>() -> TableWithColumns<F> { | |
// the third input. | ||
TableWithColumns::new( | ||
Table::Cpu, | ||
ctl_data_ternops(&OPS, true), | ||
ctl_data_ternops(&OPS, &EXTRA_OPS, true), | ||
Some(Column::sum([COL_MAP.op.shl, COL_MAP.op.shr])), | ||
) | ||
} | ||
|
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.
Each of these cross-table lookups adds an extra column to the CPU table, so ideally we'd like to have as few of them as possible. Luckily, we can just use the first CTL (
cpu_stark::ctl_arithmetic_base_rows()
) for range checks.