Delete opcode column (#672)

This commit is contained in:
Jacqueline Nabaglo 2022-08-25 11:56:25 -05:00 committed by GitHub
parent f0a23a7f07
commit f1a5b7b2d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 62 deletions

View File

@ -205,6 +205,19 @@ mod tests {
(trace, num_ops)
}
fn bits_from_opcode(opcode: u8) -> [F; 8] {
[
F::from_bool(opcode & (1 << 0) != 0),
F::from_bool(opcode & (1 << 1) != 0),
F::from_bool(opcode & (1 << 2) != 0),
F::from_bool(opcode & (1 << 3) != 0),
F::from_bool(opcode & (1 << 4) != 0),
F::from_bool(opcode & (1 << 5) != 0),
F::from_bool(opcode & (1 << 6) != 0),
F::from_bool(opcode & (1 << 7) != 0),
]
}
fn make_cpu_trace(
num_keccak_perms: usize,
num_logic_rows: usize,
@ -263,16 +276,21 @@ mod tests {
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.is_kernel_mode = F::ONE;
// Since these are the first cycle rows, we must start with PC=route_txn then increment.
row.program_counter = F::from_canonical_usize(KERNEL.global_labels["route_txn"] + i);
row.opcode = [
(logic::columns::IS_AND, 0x16),
(logic::columns::IS_OR, 0x17),
(logic::columns::IS_XOR, 0x18),
]
.into_iter()
.map(|(col, opcode)| logic_trace[col].values[i] * F::from_canonical_u64(opcode))
.sum();
row.opcode_bits = bits_from_opcode(
if logic_trace[logic::columns::IS_AND].values[i] != F::ZERO {
0x16
} else if logic_trace[logic::columns::IS_OR].values[i] != F::ZERO {
0x17
} else if logic_trace[logic::columns::IS_XOR].values[i] != F::ZERO {
0x18
} else {
panic!()
},
);
let logic = row.general.logic_mut();
let input0_bit_cols = logic::columns::limb_bit_cols_for_input(logic::columns::INPUT0);
@ -330,7 +348,7 @@ mod tests {
let last_row: cpu::columns::CpuColumnsView<F> =
cpu_trace_rows[cpu_trace_rows.len() - 1].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0x0a); // `EXP` is implemented in software
row.opcode_bits = bits_from_opcode(0x0a); // `EXP` is implemented in software
row.is_kernel_mode = F::ONE;
row.program_counter = last_row.program_counter + F::ONE;
row.general.syscalls_mut().output = [
@ -352,7 +370,7 @@ mod tests {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0xf9);
row.opcode_bits = bits_from_opcode(0xf9);
row.is_kernel_mode = F::ONE;
row.program_counter = F::from_canonical_usize(KERNEL.global_labels["sys_exp"]);
row.general.jumps_mut().input0 = [
@ -374,7 +392,7 @@ mod tests {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0x56);
row.opcode_bits = bits_from_opcode(0x56);
row.is_kernel_mode = F::ONE;
row.program_counter = F::from_canonical_u16(15682);
row.general.jumps_mut().input0 = [
@ -411,7 +429,7 @@ mod tests {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0xf9);
row.opcode_bits = bits_from_opcode(0xf9);
row.is_kernel_mode = F::ONE;
row.program_counter = F::from_canonical_u16(15106);
row.general.jumps_mut().input0 = [
@ -433,7 +451,7 @@ mod tests {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0x56);
row.opcode_bits = bits_from_opcode(0x56);
row.is_kernel_mode = F::ZERO;
row.program_counter = F::from_canonical_u16(63064);
row.general.jumps_mut().input0 = [
@ -471,7 +489,7 @@ mod tests {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0x57);
row.opcode_bits = bits_from_opcode(0x57);
row.is_kernel_mode = F::ZERO;
row.program_counter = F::from_canonical_u16(3754);
row.general.jumps_mut().input0 = [
@ -509,7 +527,7 @@ mod tests {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0x57);
row.opcode_bits = bits_from_opcode(0x57);
row.is_kernel_mode = F::ZERO;
row.program_counter = F::from_canonical_u16(37543);
row.general.jumps_mut().input0 = [
@ -538,7 +556,7 @@ mod tests {
let last_row: cpu::columns::CpuColumnsView<F> =
cpu_trace_rows[cpu_trace_rows.len() - 1].into();
row.is_cpu_cycle = F::ONE;
row.opcode = F::from_canonical_u8(0x56);
row.opcode_bits = bits_from_opcode(0x56);
row.is_kernel_mode = F::ZERO;
row.program_counter = last_row.program_counter + F::ONE;
row.general.jumps_mut().input0 = [
@ -575,7 +593,7 @@ mod tests {
for i in 0..cpu_trace_rows.len().next_power_of_two() - cpu_trace_rows.len() {
let mut row: cpu::columns::CpuColumnsView<F> =
[F::ZERO; CpuStark::<F, D>::COLUMNS].into();
row.opcode = F::from_canonical_u8(0xff);
row.opcode_bits = bits_from_opcode(0xff);
row.is_cpu_cycle = F::ONE;
row.is_kernel_mode = F::ONE;
row.program_counter =

View File

@ -27,9 +27,6 @@ pub struct CpuColumnsView<T: Copy> {
/// If CPU cycle: We're in kernel (privileged) mode.
pub is_kernel_mode: T,
/// If CPU cycle: The opcode being decoded, in {0, ..., 255}.
pub opcode: T,
// If CPU cycle: flags for EVM instructions. PUSHn, DUPn, and SWAPn only get one flag each.
// Invalid opcodes are split between a number of flags for practical reasons. Exactly one of
// these flags must be 1.

View File

@ -1,6 +1,5 @@
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;
@ -158,13 +157,16 @@ pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
// This assert is not _strictly_ necessary, but I include it as a sanity check.
assert_eq!(cycle_filter, F::ONE, "cycle_filter should be 0 or 1");
let opcode = lv.opcode.to_canonical_u64();
assert!(opcode < 256, "opcode should be in {{0, ..., 255}}");
let opcode = opcode as u8;
for (i, bit) in lv.opcode_bits.iter_mut().enumerate() {
*bit = F::from_bool(opcode & (1 << i) != 0);
// Validate all opcode bits.
for bit in lv.opcode_bits.into_iter() {
assert!(bit.to_canonical_u64() <= 1);
}
let opcode = lv
.opcode_bits
.into_iter()
.enumerate()
.map(|(i, bit)| bit.to_canonical_u64() << i)
.sum::<u64>() as u8;
let top_bits: [u8; 9] = [
0,
@ -217,23 +219,10 @@ pub fn eval_packed_generic<P: PackedField>(
let kernel_mode = lv.is_kernel_mode;
yield_constr.constraint(cycle_filter * kernel_mode * (kernel_mode - P::ONES));
// Ensure that the opcode bits are valid: each has to be either 0 or 1, and they must match
// the opcode. Note that this also implicitly range-checks the opcode.
let bits = lv.opcode_bits;
// First check that the bits are either 0 or 1.
for bit in bits {
// Ensure that the opcode bits are valid: each has to be either 0 or 1.
for bit in lv.opcode_bits {
yield_constr.constraint(cycle_filter * bit * (bit - P::ONES));
}
// Now check that they match the opcode.
{
let opcode = lv.opcode;
let reconstructed_opcode: P = bits
.into_iter()
.enumerate()
.map(|(i, bit)| bit * P::Scalar::from_canonical_u64(1 << i))
.sum();
yield_constr.constraint(cycle_filter * (opcode - reconstructed_opcode));
}
// Check that the instruction flags are valid.
// First, check that they are all either 0 or 1.
@ -258,7 +247,8 @@ pub fn eval_packed_generic<P: PackedField>(
Kernel => P::ONES - kernel_mode,
};
// 0 if all the opcode bits match, and something in {1, ..., 8}, otherwise.
let opcode_mismatch: P = bits
let opcode_mismatch: P = lv
.opcode_bits
.into_iter()
.zip(bits_from_opcode(oc))
.rev()
@ -294,28 +284,12 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
yield_constr.constraint(builder, constr);
}
// Ensure that the opcode bits are valid: each has to be either 0 or 1, and they must match
// the opcode. Note that this also implicitly range-checks the opcode.
let bits = lv.opcode_bits;
// First check that the bits are either 0 or 1.
for bit in bits {
// Ensure that the opcode bits are valid: each has to be either 0 or 1.
for bit in lv.opcode_bits {
let constr = builder.mul_sub_extension(bit, bit, bit);
let constr = builder.mul_extension(cycle_filter, constr);
yield_constr.constraint(builder, constr);
}
// Now check that they match the opcode.
{
let opcode = lv.opcode;
let reconstructed_opcode =
bits.into_iter()
.enumerate()
.fold(builder.zero_extension(), |cumul, (i, bit)| {
builder.mul_const_add_extension(F::from_canonical_u64(1 << i), bit, cumul)
});
let diff = builder.sub_extension(opcode, reconstructed_opcode);
let constr = builder.mul_extension(cycle_filter, diff);
yield_constr.constraint(builder, constr);
}
// Check that the instruction flags are valid.
// First, check that they are all either 0 or 1.
@ -346,7 +320,8 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
Kernel => builder.sub_extension(one, kernel_mode),
};
// 0 if all the opcode bits match, and something in {1, ..., 8}, otherwise.
let opcode_mismatch = bits
let opcode_mismatch = lv
.opcode_bits
.into_iter()
.zip(bits_from_opcode(oc))
.rev()