2022-06-27 07:18:21 -07:00
|
|
|
use plonky2::field::extension::Extendable;
|
2022-06-27 15:07:52 -07:00
|
|
|
use plonky2::field::packed::PackedField;
|
2022-06-14 17:38:42 -07:00
|
|
|
use plonky2::hash::hash_types::RichField;
|
|
|
|
|
use plonky2::iop::ext_target::ExtensionTarget;
|
|
|
|
|
|
|
|
|
|
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
|
|
|
|
use crate::cpu::columns;
|
|
|
|
|
|
|
|
|
|
const LIMB_SIZE: usize = 16;
|
|
|
|
|
|
|
|
|
|
pub fn generate<F: RichField>(lv: &mut [F; columns::NUM_CPU_COLUMNS]) {
|
|
|
|
|
let eq_filter = lv[columns::IS_EQ].to_canonical_u64();
|
|
|
|
|
let iszero_filter = lv[columns::IS_ISZERO].to_canonical_u64();
|
|
|
|
|
assert!(eq_filter <= 1);
|
|
|
|
|
assert!(iszero_filter <= 1);
|
|
|
|
|
assert!(eq_filter + iszero_filter <= 1);
|
|
|
|
|
|
|
|
|
|
if eq_filter != 1 && iszero_filter != 1 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let diffs = if eq_filter == 1 {
|
2022-06-17 11:57:14 -07:00
|
|
|
columns::LOGIC_INPUT0
|
|
|
|
|
.zip(columns::LOGIC_INPUT1)
|
2022-06-14 17:38:42 -07:00
|
|
|
.map(|(in0_col, in1_col)| {
|
|
|
|
|
let in0 = lv[in0_col];
|
|
|
|
|
let in1 = lv[in1_col];
|
|
|
|
|
assert_eq!(in0.to_canonical_u64() >> LIMB_SIZE, 0);
|
|
|
|
|
assert_eq!(in1.to_canonical_u64() >> LIMB_SIZE, 0);
|
|
|
|
|
let diff = in0 - in1;
|
|
|
|
|
diff.square()
|
|
|
|
|
})
|
|
|
|
|
.sum()
|
|
|
|
|
} else if iszero_filter == 1 {
|
2022-06-17 11:57:14 -07:00
|
|
|
columns::LOGIC_INPUT0.map(|i| lv[i]).sum()
|
2022-06-14 17:38:42 -07:00
|
|
|
} else {
|
|
|
|
|
panic!()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
lv[columns::SIMPLE_LOGIC_DIFF] = diffs;
|
|
|
|
|
lv[columns::SIMPLE_LOGIC_DIFF_INV] = diffs.try_inverse().unwrap_or(F::ZERO);
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
lv[columns::LOGIC_OUTPUT.start] = F::from_bool(diffs == F::ZERO);
|
|
|
|
|
for i in columns::LOGIC_OUTPUT.start + 1..columns::LOGIC_OUTPUT.end {
|
2022-06-14 17:38:42 -07:00
|
|
|
lv[i] = F::ZERO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn eval_packed<P: PackedField>(
|
|
|
|
|
lv: &[P; columns::NUM_CPU_COLUMNS],
|
|
|
|
|
yield_constr: &mut ConstraintConsumer<P>,
|
|
|
|
|
) {
|
|
|
|
|
let eq_filter = lv[columns::IS_EQ];
|
|
|
|
|
let iszero_filter = lv[columns::IS_ISZERO];
|
|
|
|
|
let eq_or_iszero_filter = eq_filter + iszero_filter;
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
let ls_bit = lv[columns::LOGIC_OUTPUT.start];
|
2022-06-14 17:38:42 -07:00
|
|
|
|
|
|
|
|
// Handle EQ and ISZERO. Most limbs of the output are 0, but the least-significant one is
|
|
|
|
|
// either 0 or 1.
|
|
|
|
|
yield_constr.constraint(eq_or_iszero_filter * ls_bit * (ls_bit - P::ONES));
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
for bit_col in columns::LOGIC_OUTPUT.start + 1..columns::LOGIC_OUTPUT.end {
|
2022-06-14 17:38:42 -07:00
|
|
|
let bit = lv[bit_col];
|
|
|
|
|
yield_constr.constraint(eq_or_iszero_filter * bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check SIMPLE_LOGIC_DIFF
|
|
|
|
|
let diffs = lv[columns::SIMPLE_LOGIC_DIFF];
|
|
|
|
|
let diffs_inv = lv[columns::SIMPLE_LOGIC_DIFF_INV];
|
|
|
|
|
{
|
2022-06-17 11:57:14 -07:00
|
|
|
let input0_sum: P = columns::LOGIC_INPUT0.map(|i| lv[i]).sum();
|
2022-06-14 17:38:42 -07:00
|
|
|
yield_constr.constraint(iszero_filter * (diffs - input0_sum));
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
let sum_squared_diffs: P = columns::LOGIC_INPUT0
|
|
|
|
|
.zip(columns::LOGIC_INPUT1)
|
2022-06-14 17:38:42 -07:00
|
|
|
.map(|(in0_col, in1_col)| {
|
|
|
|
|
let in0 = lv[in0_col];
|
|
|
|
|
let in1 = lv[in1_col];
|
|
|
|
|
let diff = in0 - in1;
|
|
|
|
|
diff.square()
|
|
|
|
|
})
|
|
|
|
|
.sum();
|
|
|
|
|
yield_constr.constraint(eq_filter * (diffs - sum_squared_diffs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// diffs != 0 => ls_bit == 0
|
|
|
|
|
yield_constr.constraint(eq_or_iszero_filter * diffs * ls_bit);
|
|
|
|
|
// ls_bit == 0 => diffs != 0 (we provide a diffs_inv)
|
|
|
|
|
yield_constr.constraint(eq_or_iszero_filter * (diffs * diffs_inv + ls_bit - P::ONES));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
|
|
|
|
lv: &[ExtensionTarget<D>; columns::NUM_CPU_COLUMNS],
|
|
|
|
|
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
|
|
|
|
) {
|
|
|
|
|
let eq_filter = lv[columns::IS_EQ];
|
|
|
|
|
let iszero_filter = lv[columns::IS_ISZERO];
|
|
|
|
|
let eq_or_iszero_filter = builder.add_extension(eq_filter, iszero_filter);
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
let ls_bit = lv[columns::LOGIC_OUTPUT.start];
|
2022-06-14 17:38:42 -07:00
|
|
|
|
|
|
|
|
// Handle EQ and ISZERO. Most limbs of the output are 0, but the least-significant one is
|
|
|
|
|
// either 0 or 1.
|
|
|
|
|
{
|
|
|
|
|
let constr = builder.mul_sub_extension(ls_bit, ls_bit, ls_bit);
|
|
|
|
|
let constr = builder.mul_extension(eq_or_iszero_filter, constr);
|
|
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
for bit_col in columns::LOGIC_OUTPUT.start + 1..columns::LOGIC_OUTPUT.end {
|
2022-06-14 17:38:42 -07:00
|
|
|
let bit = lv[bit_col];
|
|
|
|
|
let constr = builder.mul_extension(eq_or_iszero_filter, bit);
|
|
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check SIMPLE_LOGIC_DIFF
|
|
|
|
|
let diffs = lv[columns::SIMPLE_LOGIC_DIFF];
|
|
|
|
|
let diffs_inv = lv[columns::SIMPLE_LOGIC_DIFF_INV];
|
|
|
|
|
{
|
2022-06-17 11:57:14 -07:00
|
|
|
let input0_sum = builder.add_many_extension(columns::LOGIC_INPUT0.map(|i| lv[i]));
|
2022-06-14 17:38:42 -07:00
|
|
|
{
|
|
|
|
|
let constr = builder.sub_extension(diffs, input0_sum);
|
|
|
|
|
let constr = builder.mul_extension(iszero_filter, constr);
|
|
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 11:57:14 -07:00
|
|
|
let sum_squared_diffs = columns::LOGIC_INPUT0.zip(columns::LOGIC_INPUT1).fold(
|
|
|
|
|
builder.zero_extension(),
|
|
|
|
|
|acc, (in0_col, in1_col)| {
|
2022-06-14 17:38:42 -07:00
|
|
|
let in0 = lv[in0_col];
|
|
|
|
|
let in1 = lv[in1_col];
|
|
|
|
|
let diff = builder.sub_extension(in0, in1);
|
|
|
|
|
builder.mul_add_extension(diff, diff, acc)
|
2022-06-17 11:57:14 -07:00
|
|
|
},
|
|
|
|
|
);
|
2022-06-14 17:38:42 -07:00
|
|
|
{
|
|
|
|
|
let constr = builder.sub_extension(diffs, sum_squared_diffs);
|
|
|
|
|
let constr = builder.mul_extension(eq_filter, constr);
|
|
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// diffs != 0 => ls_bit == 0
|
|
|
|
|
let constr = builder.mul_extension(diffs, ls_bit);
|
|
|
|
|
let constr = builder.mul_extension(eq_or_iszero_filter, constr);
|
|
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// ls_bit == 0 => diffs != 0 (we provide a diffs_inv)
|
|
|
|
|
let constr = builder.mul_add_extension(diffs, diffs_inv, ls_bit);
|
|
|
|
|
let constr = builder.mul_sub_extension(eq_or_iszero_filter, constr, eq_or_iszero_filter);
|
|
|
|
|
yield_constr.constraint(builder, constr);
|
|
|
|
|
}
|
|
|
|
|
}
|