2023-06-07 18:27:23 -07:00
|
|
|
//! Checks for stack overflow.
|
2022-09-10 13:20:30 -07:00
|
|
|
//!
|
2023-06-07 18:27:23 -07:00
|
|
|
//! The constraints defined herein validate that stack overflow did not occur. For example, if `dup`
|
|
|
|
|
//! is set but the copy would overflow would underflow, these constraints would make the proof
|
|
|
|
|
//! unverifiable.
|
2022-09-10 13:20:30 -07:00
|
|
|
//!
|
2023-06-07 18:27:23 -07:00
|
|
|
//! Faults are handled under a separate operation flag, `exception` , which traps to the kernel. The
|
|
|
|
|
//! kernel then handles the exception. However, before it may do so, it must verify in software that
|
|
|
|
|
//! an exception did in fact occur (i.e. the trap was warranted) and `PANIC` otherwise; this
|
|
|
|
|
//! prevents the prover from faking an exception on a valid operation.
|
2022-09-10 13:20:30 -07:00
|
|
|
|
|
|
|
|
use plonky2::field::extension::Extendable;
|
|
|
|
|
use plonky2::field::packed::PackedField;
|
|
|
|
|
use plonky2::field::types::Field;
|
|
|
|
|
use plonky2::hash::hash_types::RichField;
|
|
|
|
|
use plonky2::iop::ext_target::ExtensionTarget;
|
|
|
|
|
|
|
|
|
|
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
2023-06-07 18:27:23 -07:00
|
|
|
use crate::cpu::columns::CpuColumnsView;
|
2022-09-10 13:20:30 -07:00
|
|
|
|
2022-11-30 17:45:31 -08:00
|
|
|
pub const MAX_USER_STACK_SIZE: usize = 1024;
|
2022-09-10 13:20:30 -07:00
|
|
|
|
|
|
|
|
pub fn eval_packed<P: PackedField>(
|
|
|
|
|
lv: &CpuColumnsView<P>,
|
|
|
|
|
yield_constr: &mut ConstraintConsumer<P>,
|
|
|
|
|
) {
|
2023-06-07 18:27:23 -07:00
|
|
|
// If we're in user mode, ensure that the stack length is not 1025. Note that a stack length of
|
|
|
|
|
// 1024 is valid. 1025 means we've gone one over, which is necessary for overflow, as an EVM
|
|
|
|
|
// opcode increases the stack length by at most one.
|
2022-09-10 13:20:30 -07:00
|
|
|
|
2023-06-07 18:27:23 -07:00
|
|
|
let filter = lv.is_cpu_cycle;
|
|
|
|
|
let diff = lv.stack_len - P::Scalar::from_canonical_usize(MAX_USER_STACK_SIZE + 1);
|
|
|
|
|
let lhs = diff * lv.stack_len_bounds_aux;
|
|
|
|
|
let rhs = P::ONES - lv.is_kernel_mode;
|
2022-09-10 13:20:30 -07:00
|
|
|
|
2023-06-07 18:27:23 -07:00
|
|
|
yield_constr.constraint(filter * (lhs - rhs));
|
2022-09-10 13:20:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
|
|
|
|
lv: &CpuColumnsView<ExtensionTarget<D>>,
|
|
|
|
|
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
|
|
|
|
) {
|
2023-06-07 18:27:23 -07:00
|
|
|
// If we're in user mode, ensure that the stack length is not 1025. Note that a stack length of
|
|
|
|
|
// 1024 is valid. 1025 means we've gone one over, which is necessary for overflow, as an EVM
|
|
|
|
|
// opcode increases the stack length by at most one.
|
|
|
|
|
|
|
|
|
|
let filter = lv.is_cpu_cycle;
|
|
|
|
|
|
|
|
|
|
let lhs = builder.arithmetic_extension(
|
|
|
|
|
F::ONE,
|
|
|
|
|
-F::from_canonical_usize(MAX_USER_STACK_SIZE + 1),
|
|
|
|
|
lv.stack_len,
|
|
|
|
|
lv.stack_len_bounds_aux,
|
|
|
|
|
lv.stack_len_bounds_aux,
|
|
|
|
|
);
|
|
|
|
|
let constr = builder.add_extension(lhs, lv.is_kernel_mode);
|
|
|
|
|
let constr = builder.mul_sub_extension(filter, constr, filter);
|
2022-09-10 13:20:30 -07:00
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|