2022-06-29 16:23:44 -07:00
|
|
|
use std::borrow::{Borrow, BorrowMut};
|
2022-05-18 09:22:58 +02:00
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
2022-06-23 14:36:14 -07:00
|
|
|
use itertools::Itertools;
|
2022-06-27 07:18:21 -07:00
|
|
|
use plonky2::field::extension::{Extendable, FieldExtension};
|
2022-06-27 15:07:52 -07:00
|
|
|
use plonky2::field::packed::PackedField;
|
2022-06-27 12:24:09 -07:00
|
|
|
use plonky2::field::types::Field;
|
2022-05-18 09:22:58 +02:00
|
|
|
use plonky2::hash::hash_types::RichField;
|
|
|
|
|
|
|
|
|
|
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
2022-06-29 16:23:44 -07:00
|
|
|
use crate::cpu::columns::{CpuColumnsView, COL_MAP, NUM_CPU_COLUMNS};
|
2022-09-10 13:20:30 -07:00
|
|
|
use crate::cpu::{
|
|
|
|
|
bootstrap_kernel, control_flow, decode, jumps, simple_logic, stack_bounds, syscalls,
|
|
|
|
|
};
|
2022-08-23 12:22:54 -07:00
|
|
|
use crate::cross_table_lookup::Column;
|
2022-06-27 16:03:56 -07:00
|
|
|
use crate::memory::NUM_CHANNELS;
|
2022-05-18 09:22:58 +02:00
|
|
|
use crate::stark::Stark;
|
|
|
|
|
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
|
|
|
|
|
2022-06-21 10:28:44 -07:00
|
|
|
pub fn ctl_data_keccak<F: Field>() -> Vec<Column<F>> {
|
2022-07-18 11:50:58 -07:00
|
|
|
let keccak = COL_MAP.general.keccak();
|
|
|
|
|
let mut res: Vec<_> = Column::singles(keccak.input_limbs).collect();
|
|
|
|
|
res.extend(Column::singles(keccak.output_limbs));
|
2022-06-21 10:28:44 -07:00
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-14 16:36:07 -07:00
|
|
|
pub fn ctl_data_keccak_memory<F: Field>() -> Vec<Column<F>> {
|
|
|
|
|
// When executing KECCAK_GENERAL, the memory channels are used as follows:
|
|
|
|
|
// channel 0: instruction
|
|
|
|
|
// channel 1: stack[-1] = context
|
|
|
|
|
// channel 2: stack[-2] = segment
|
|
|
|
|
// channel 3: stack[-3] = virtual
|
2022-08-26 22:05:16 -07:00
|
|
|
let context = Column::single(COL_MAP.mem_channels[1].value[0]);
|
|
|
|
|
let segment = Column::single(COL_MAP.mem_channels[2].value[0]);
|
|
|
|
|
let virt = Column::single(COL_MAP.mem_channels[3].value[0]);
|
2022-08-14 16:36:07 -07:00
|
|
|
|
|
|
|
|
let num_channels = F::from_canonical_usize(NUM_CHANNELS);
|
|
|
|
|
let clock = Column::linear_combination([(COL_MAP.clock, num_channels)]);
|
|
|
|
|
|
|
|
|
|
vec![context, segment, virt, clock]
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-21 10:28:44 -07:00
|
|
|
pub fn ctl_filter_keccak<F: Field>() -> Column<F> {
|
2022-06-29 16:23:44 -07:00
|
|
|
Column::single(COL_MAP.is_keccak)
|
2022-06-21 10:28:44 -07:00
|
|
|
}
|
|
|
|
|
|
2022-08-14 16:36:07 -07:00
|
|
|
pub fn ctl_filter_keccak_memory<F: Field>() -> Column<F> {
|
|
|
|
|
Column::single(COL_MAP.is_keccak_memory)
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-21 10:28:44 -07:00
|
|
|
pub fn ctl_data_logic<F: Field>() -> Vec<Column<F>> {
|
2022-06-29 16:23:44 -07:00
|
|
|
let mut res = Column::singles([COL_MAP.is_and, COL_MAP.is_or, COL_MAP.is_xor]).collect_vec();
|
2022-08-26 22:05:16 -07:00
|
|
|
res.extend(Column::singles(COL_MAP.mem_channels[0].value));
|
|
|
|
|
res.extend(Column::singles(COL_MAP.mem_channels[1].value));
|
|
|
|
|
res.extend(Column::singles(COL_MAP.mem_channels[2].value));
|
2022-06-21 10:28:44 -07:00
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn ctl_filter_logic<F: Field>() -> Column<F> {
|
2022-06-29 16:23:44 -07:00
|
|
|
Column::sum([COL_MAP.is_and, COL_MAP.is_or, COL_MAP.is_xor])
|
2022-06-21 10:28:44 -07:00
|
|
|
}
|
|
|
|
|
|
2022-06-27 16:03:56 -07:00
|
|
|
pub fn ctl_data_memory<F: Field>(channel: usize) -> Vec<Column<F>> {
|
|
|
|
|
debug_assert!(channel < NUM_CHANNELS);
|
2022-08-26 22:05:16 -07:00
|
|
|
let channel_map = COL_MAP.mem_channels[channel];
|
2022-06-23 14:36:14 -07:00
|
|
|
let mut cols: Vec<Column<F>> = Column::singles([
|
2022-08-26 22:05:16 -07:00
|
|
|
channel_map.is_read,
|
|
|
|
|
channel_map.addr_context,
|
|
|
|
|
channel_map.addr_segment,
|
|
|
|
|
channel_map.addr_virtual,
|
2022-06-23 14:36:14 -07:00
|
|
|
])
|
|
|
|
|
.collect_vec();
|
2022-08-26 22:05:16 -07:00
|
|
|
cols.extend(Column::singles(channel_map.value));
|
2022-07-07 09:27:50 -07:00
|
|
|
|
2022-08-23 12:22:54 -07:00
|
|
|
let scalar = F::from_canonical_usize(NUM_CHANNELS);
|
2022-07-07 09:27:50 -07:00
|
|
|
let addend = F::from_canonical_usize(channel);
|
|
|
|
|
cols.push(Column::linear_combination_with_constant(
|
2022-08-14 16:36:07 -07:00
|
|
|
[(COL_MAP.clock, scalar)],
|
2022-07-07 09:27:50 -07:00
|
|
|
addend,
|
|
|
|
|
));
|
2022-07-07 09:52:38 -07:00
|
|
|
|
2022-06-23 14:36:14 -07:00
|
|
|
cols
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-27 16:03:56 -07:00
|
|
|
pub fn ctl_filter_memory<F: Field>(channel: usize) -> Column<F> {
|
2022-08-26 22:05:16 -07:00
|
|
|
Column::single(COL_MAP.mem_channels[channel].used)
|
2022-06-23 14:36:14 -07:00
|
|
|
}
|
|
|
|
|
|
2022-07-04 18:10:03 -07:00
|
|
|
#[derive(Copy, Clone, Default)]
|
2022-05-18 09:22:58 +02:00
|
|
|
pub struct CpuStark<F, const D: usize> {
|
|
|
|
|
pub f: PhantomData<F>,
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-03 19:24:47 -07:00
|
|
|
impl<F: RichField, const D: usize> CpuStark<F, D> {
|
2022-06-29 16:23:44 -07:00
|
|
|
pub fn generate(&self, local_values: &mut [F; NUM_CPU_COLUMNS]) {
|
|
|
|
|
let local_values: &mut CpuColumnsView<_> = local_values.borrow_mut();
|
2022-06-03 19:24:47 -07:00
|
|
|
decode::generate(local_values);
|
2022-06-14 16:55:08 -07:00
|
|
|
simple_logic::generate(local_values);
|
2022-09-10 13:20:30 -07:00
|
|
|
stack_bounds::generate(local_values); // Must come after `decode`.
|
2022-06-03 19:24:47 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D> {
|
2022-06-29 16:23:44 -07:00
|
|
|
const COLUMNS: usize = NUM_CPU_COLUMNS;
|
2022-05-18 09:22:58 +02:00
|
|
|
|
|
|
|
|
fn eval_packed_generic<FE, P, const D2: usize>(
|
|
|
|
|
&self,
|
2022-08-25 12:24:22 -07:00
|
|
|
vars: StarkEvaluationVars<FE, P, { Self::COLUMNS }>,
|
2022-06-03 19:24:47 -07:00
|
|
|
yield_constr: &mut ConstraintConsumer<P>,
|
2022-05-18 09:22:58 +02:00
|
|
|
) where
|
|
|
|
|
FE: FieldExtension<D2, BaseField = F>,
|
|
|
|
|
P: PackedField<Scalar = FE>,
|
|
|
|
|
{
|
2022-06-29 16:23:44 -07:00
|
|
|
let local_values = vars.local_values.borrow();
|
2022-07-28 04:36:33 +10:00
|
|
|
let next_values = vars.next_values.borrow();
|
2022-06-15 09:33:52 -07:00
|
|
|
bootstrap_kernel::eval_bootstrap_kernel(vars, yield_constr);
|
2022-07-28 04:36:33 +10:00
|
|
|
control_flow::eval_packed_generic(local_values, next_values, yield_constr);
|
2022-06-29 16:23:44 -07:00
|
|
|
decode::eval_packed_generic(local_values, yield_constr);
|
2022-08-16 09:46:10 -07:00
|
|
|
jumps::eval_packed(local_values, next_values, yield_constr);
|
2022-06-29 16:23:44 -07:00
|
|
|
simple_logic::eval_packed(local_values, yield_constr);
|
2022-09-10 13:20:30 -07:00
|
|
|
stack_bounds::eval_packed(local_values, yield_constr);
|
2022-08-16 09:46:10 -07:00
|
|
|
syscalls::eval_packed(local_values, next_values, yield_constr);
|
2022-05-18 09:22:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eval_ext_circuit(
|
|
|
|
|
&self,
|
2022-06-03 19:24:47 -07:00
|
|
|
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
2022-08-25 12:24:22 -07:00
|
|
|
vars: StarkEvaluationTargets<D, { Self::COLUMNS }>,
|
2022-06-03 19:24:47 -07:00
|
|
|
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
2022-05-18 09:22:58 +02:00
|
|
|
) {
|
2022-06-29 16:23:44 -07:00
|
|
|
let local_values = vars.local_values.borrow();
|
2022-07-28 04:36:33 +10:00
|
|
|
let next_values = vars.next_values.borrow();
|
2022-06-15 09:33:52 -07:00
|
|
|
bootstrap_kernel::eval_bootstrap_kernel_circuit(builder, vars, yield_constr);
|
2022-07-28 04:36:33 +10:00
|
|
|
control_flow::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
2022-06-29 16:23:44 -07:00
|
|
|
decode::eval_ext_circuit(builder, local_values, yield_constr);
|
2022-08-16 09:46:10 -07:00
|
|
|
jumps::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
2022-06-29 16:23:44 -07:00
|
|
|
simple_logic::eval_ext_circuit(builder, local_values, yield_constr);
|
2022-09-10 13:20:30 -07:00
|
|
|
stack_bounds::eval_ext_circuit(builder, local_values, yield_constr);
|
2022-08-16 09:46:10 -07:00
|
|
|
syscalls::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
2022-05-18 09:22:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn constraint_degree(&self) -> usize {
|
|
|
|
|
3
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-19 11:10:10 +02:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
|
|
|
|
|
|
|
|
|
use crate::cpu::cpu_stark::CpuStark;
|
|
|
|
|
use crate::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree};
|
|
|
|
|
|
|
|
|
|
#[test]
|
2022-05-20 08:34:25 +02:00
|
|
|
fn test_stark_degree() -> Result<()> {
|
2022-05-19 11:10:10 +02:00
|
|
|
const D: usize = 2;
|
|
|
|
|
type C = PoseidonGoldilocksConfig;
|
|
|
|
|
type F = <C as GenericConfig<D>>::F;
|
|
|
|
|
type S = CpuStark<F, D>;
|
|
|
|
|
|
|
|
|
|
let stark = S {
|
|
|
|
|
f: Default::default(),
|
|
|
|
|
};
|
2022-05-20 08:34:25 +02:00
|
|
|
test_stark_low_degree(stark)
|
2022-05-19 11:10:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_stark_circuit() -> Result<()> {
|
|
|
|
|
const D: usize = 2;
|
|
|
|
|
type C = PoseidonGoldilocksConfig;
|
|
|
|
|
type F = <C as GenericConfig<D>>::F;
|
|
|
|
|
type S = CpuStark<F, D>;
|
|
|
|
|
|
|
|
|
|
let stark = S {
|
|
|
|
|
f: Default::default(),
|
|
|
|
|
};
|
|
|
|
|
test_stark_circuit_constraints::<F, C, S, D>(stark)
|
|
|
|
|
}
|
|
|
|
|
}
|