Constrain next row's stack length

This commit is contained in:
Hamy Ratoanina 2023-08-28 16:32:04 -04:00
parent a0b2b48992
commit 8beba56903
No known key found for this signature in database
GPG Key ID: 054683A21827F7C4
5 changed files with 46 additions and 12 deletions

View File

@ -247,8 +247,8 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
pc::eval_packed(local_values, yield_constr); pc::eval_packed(local_values, yield_constr);
push0::eval_packed(local_values, yield_constr); push0::eval_packed(local_values, yield_constr);
shift::eval_packed(local_values, yield_constr); shift::eval_packed(local_values, yield_constr);
simple_logic::eval_packed(local_values, yield_constr); simple_logic::eval_packed(local_values, next_values, yield_constr);
stack::eval_packed(local_values, yield_constr); stack::eval_packed(local_values, next_values, yield_constr);
stack_bounds::eval_packed(local_values, yield_constr); stack_bounds::eval_packed(local_values, yield_constr);
syscalls_exceptions::eval_packed(local_values, next_values, yield_constr); syscalls_exceptions::eval_packed(local_values, next_values, yield_constr);
} }
@ -274,8 +274,8 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
pc::eval_ext_circuit(builder, local_values, yield_constr); pc::eval_ext_circuit(builder, local_values, yield_constr);
push0::eval_ext_circuit(builder, local_values, yield_constr); push0::eval_ext_circuit(builder, local_values, yield_constr);
shift::eval_ext_circuit(builder, local_values, yield_constr); shift::eval_ext_circuit(builder, local_values, yield_constr);
simple_logic::eval_ext_circuit(builder, local_values, yield_constr); simple_logic::eval_ext_circuit(builder, local_values, next_values, yield_constr);
stack::eval_ext_circuit(builder, local_values, yield_constr); stack::eval_ext_circuit(builder, local_values, next_values, yield_constr);
stack_bounds::eval_ext_circuit(builder, local_values, yield_constr); stack_bounds::eval_ext_circuit(builder, local_values, yield_constr);
syscalls_exceptions::eval_ext_circuit(builder, local_values, next_values, yield_constr); syscalls_exceptions::eval_ext_circuit(builder, local_values, next_values, yield_constr);
} }

View File

@ -75,8 +75,8 @@ pub fn eval_packed_jump_jumpi<P: PackedField>(
let is_jumpi = filter * lv.opcode_bits[0]; let is_jumpi = filter * lv.opcode_bits[0];
// Stack constraints. // Stack constraints.
stack::eval_packed_one(lv, is_jump, stack::JUMP_OP.unwrap(), yield_constr); stack::eval_packed_one(lv, nv, is_jump, stack::JUMP_OP.unwrap(), yield_constr);
stack::eval_packed_one(lv, is_jumpi, stack::JUMPI_OP.unwrap(), yield_constr); stack::eval_packed_one(lv, nv, is_jumpi, stack::JUMPI_OP.unwrap(), yield_constr);
// If `JUMP`, re-use the `JUMPI` logic, but setting the second input (the predicate) to be 1. // If `JUMP`, re-use the `JUMPI` logic, but setting the second input (the predicate) to be 1.
// In other words, we implement `JUMP(dst)` as `JUMPI(dst, cond=1)`. // In other words, we implement `JUMP(dst)` as `JUMPI(dst, cond=1)`.
@ -151,10 +151,18 @@ pub fn eval_ext_circuit_jump_jumpi<F: RichField + Extendable<D>, const D: usize>
let is_jumpi = builder.mul_extension(filter, lv.opcode_bits[0]); let is_jumpi = builder.mul_extension(filter, lv.opcode_bits[0]);
// Stack constraints. // Stack constraints.
stack::eval_ext_circuit_one(builder, lv, is_jump, stack::JUMP_OP.unwrap(), yield_constr);
stack::eval_ext_circuit_one( stack::eval_ext_circuit_one(
builder, builder,
lv, lv,
nv,
is_jump,
stack::JUMP_OP.unwrap(),
yield_constr,
);
stack::eval_ext_circuit_one(
builder,
lv,
nv,
is_jumpi, is_jumpi,
stack::JUMPI_OP.unwrap(), stack::JUMPI_OP.unwrap(),
yield_constr, yield_constr,

View File

@ -51,6 +51,7 @@ pub fn generate_pinv_diff<F: Field>(val0: U256, val1: U256, lv: &mut CpuColumnsV
pub fn eval_packed<P: PackedField>( pub fn eval_packed<P: PackedField>(
lv: &CpuColumnsView<P>, lv: &CpuColumnsView<P>,
nv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>, yield_constr: &mut ConstraintConsumer<P>,
) { ) {
let logic = lv.general.logic(); let logic = lv.general.logic();
@ -94,9 +95,10 @@ pub fn eval_packed<P: PackedField>(
yield_constr.constraint(eq_or_iszero_filter * (dot - unequal)); yield_constr.constraint(eq_or_iszero_filter * (dot - unequal));
// Stack constraints. // Stack constraints.
stack::eval_packed_one(lv, eq_filter, EQ_STACK_BEHAVIOR.unwrap(), yield_constr); stack::eval_packed_one(lv, nv, eq_filter, EQ_STACK_BEHAVIOR.unwrap(), yield_constr);
stack::eval_packed_one( stack::eval_packed_one(
lv, lv,
nv,
iszero_filter, iszero_filter,
IS_ZERO_STACK_BEHAVIOR.unwrap(), IS_ZERO_STACK_BEHAVIOR.unwrap(),
yield_constr, yield_constr,
@ -106,6 +108,7 @@ pub fn eval_packed<P: PackedField>(
pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>( pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>, builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
lv: &CpuColumnsView<ExtensionTarget<D>>, lv: &CpuColumnsView<ExtensionTarget<D>>,
nv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>, yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) { ) {
let zero = builder.zero_extension(); let zero = builder.zero_extension();
@ -173,6 +176,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
stack::eval_ext_circuit_one( stack::eval_ext_circuit_one(
builder, builder,
lv, lv,
nv,
eq_filter, eq_filter,
EQ_STACK_BEHAVIOR.unwrap(), EQ_STACK_BEHAVIOR.unwrap(),
yield_constr, yield_constr,
@ -180,6 +184,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
stack::eval_ext_circuit_one( stack::eval_ext_circuit_one(
builder, builder,
lv, lv,
nv,
iszero_filter, iszero_filter,
IS_ZERO_STACK_BEHAVIOR.unwrap(), IS_ZERO_STACK_BEHAVIOR.unwrap(),
yield_constr, yield_constr,

View File

@ -11,17 +11,19 @@ use crate::cpu::columns::CpuColumnsView;
pub fn eval_packed<P: PackedField>( pub fn eval_packed<P: PackedField>(
lv: &CpuColumnsView<P>, lv: &CpuColumnsView<P>,
nv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>, yield_constr: &mut ConstraintConsumer<P>,
) { ) {
not::eval_packed(lv, yield_constr); not::eval_packed(lv, yield_constr);
eq_iszero::eval_packed(lv, yield_constr); eq_iszero::eval_packed(lv, nv, yield_constr);
} }
pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>( pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>, builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
lv: &CpuColumnsView<ExtensionTarget<D>>, lv: &CpuColumnsView<ExtensionTarget<D>>,
nv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>, yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) { ) {
not::eval_ext_circuit(builder, lv, yield_constr); not::eval_ext_circuit(builder, lv, yield_constr);
eq_iszero::eval_ext_circuit(builder, lv, yield_constr); eq_iszero::eval_ext_circuit(builder, lv, nv, yield_constr);
} }

View File

@ -140,6 +140,7 @@ pub(crate) const IS_ZERO_STACK_BEHAVIOR: Option<StackBehavior> = BASIC_UNARY_OP;
pub(crate) fn eval_packed_one<P: PackedField>( pub(crate) fn eval_packed_one<P: PackedField>(
lv: &CpuColumnsView<P>, lv: &CpuColumnsView<P>,
nv: &CpuColumnsView<P>,
filter: P, filter: P,
stack_behavior: StackBehavior, stack_behavior: StackBehavior,
yield_constr: &mut ConstraintConsumer<P>, yield_constr: &mut ConstraintConsumer<P>,
@ -185,15 +186,21 @@ pub(crate) fn eval_packed_one<P: PackedField>(
yield_constr.constraint(filter * channel.used); yield_constr.constraint(filter * channel.used);
} }
} }
// Constrain new stack length.
let num_pops = P::Scalar::from_canonical_usize(stack_behavior.num_pops);
let push = P::Scalar::from_canonical_usize(stack_behavior.pushes as usize);
yield_constr.constraint_transition(filter * (nv.stack_len - (lv.stack_len - num_pops + push)));
} }
pub fn eval_packed<P: PackedField>( pub fn eval_packed<P: PackedField>(
lv: &CpuColumnsView<P>, lv: &CpuColumnsView<P>,
nv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>, yield_constr: &mut ConstraintConsumer<P>,
) { ) {
for (op, stack_behavior) in izip!(lv.op.into_iter(), STACK_BEHAVIORS.into_iter()) { for (op, stack_behavior) in izip!(lv.op.into_iter(), STACK_BEHAVIORS.into_iter()) {
if let Some(stack_behavior) = stack_behavior { if let Some(stack_behavior) = stack_behavior {
eval_packed_one(lv, op, stack_behavior, yield_constr); eval_packed_one(lv, nv, op, stack_behavior, yield_constr);
} }
} }
} }
@ -201,6 +208,7 @@ pub fn eval_packed<P: PackedField>(
pub(crate) fn eval_ext_circuit_one<F: RichField + Extendable<D>, const D: usize>( pub(crate) fn eval_ext_circuit_one<F: RichField + Extendable<D>, const D: usize>(
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>, builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
lv: &CpuColumnsView<ExtensionTarget<D>>, lv: &CpuColumnsView<ExtensionTarget<D>>,
nv: &CpuColumnsView<ExtensionTarget<D>>,
filter: ExtensionTarget<D>, filter: ExtensionTarget<D>,
stack_behavior: StackBehavior, stack_behavior: StackBehavior,
yield_constr: &mut RecursiveConstraintConsumer<F, D>, yield_constr: &mut RecursiveConstraintConsumer<F, D>,
@ -298,16 +306,27 @@ pub(crate) fn eval_ext_circuit_one<F: RichField + Extendable<D>, const D: usize>
yield_constr.constraint(builder, constr); yield_constr.constraint(builder, constr);
} }
} }
// Constrain new stack length.
let diff = builder.constant_extension(
F::Extension::from_canonical_usize(stack_behavior.num_pops)
- F::Extension::from_canonical_usize(stack_behavior.pushes as usize),
);
let diff = builder.sub_extension(lv.stack_len, diff);
let diff = builder.sub_extension(nv.stack_len, diff);
let constr = builder.mul_extension(filter, diff);
yield_constr.constraint_transition(builder, constr);
} }
pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>( pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>, builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
lv: &CpuColumnsView<ExtensionTarget<D>>, lv: &CpuColumnsView<ExtensionTarget<D>>,
nv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>, yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) { ) {
for (op, stack_behavior) in izip!(lv.op.into_iter(), STACK_BEHAVIORS.into_iter()) { for (op, stack_behavior) in izip!(lv.op.into_iter(), STACK_BEHAVIORS.into_iter()) {
if let Some(stack_behavior) = stack_behavior { if let Some(stack_behavior) = stack_behavior {
eval_ext_circuit_one(builder, lv, op, stack_behavior, yield_constr); eval_ext_circuit_one(builder, lv, nv, op, stack_behavior, yield_constr);
} }
} }
} }