Skip to content

Commit

Permalink
Softcloud/program (#174)
Browse files Browse the repository at this point in the history
* ADD: trace length print in executor test.

* MOD: benchmark hash method.

* MOD: op selector of and, or, xor combined into s_bitwise.

* MOD: cpu combined simple arithmatic operations.

* MOD: unify test db.

* FIX: tstore constraints.

* FIX: poseidon_chunk generate trace.

* MOD: trace for program

* ADD: ctl for cpu and program.

* ADD: ctl for program and program_chunk.

* ADD: ctl prog_chunk to poseidon.

* ADD: ctl prog_chunk to storage.

* MOD: program trace

* ADD: prog starks and ctls.

* MOD: test vm exec for circuit.

* ADD: ctl print.

* ADD: ProgChunk Hash in PoseidonTable.

* ADD: ctl test cpu-program.

* FIX: cpu and prog generate trace.

* FIX: cpu-prog ctl data.

* FIX: generate program trace.

* ADD: set challenge for program in verifier.

* FIX: prog_chunk ctl data to program.

* MOD: program degree.

* MOD: tape tx_idx.

---------

Co-authored-by: web3Softcloud <renzhexin@web3.com>
Co-authored-by: Pierre Hong <hongyuanyang2019@163.com>
  • Loading branch information
3 people authored Dec 4, 2023
1 parent 531ca9d commit 0f64d7b
Show file tree
Hide file tree
Showing 26 changed files with 993 additions and 100 deletions.
12 changes: 5 additions & 7 deletions circuits/src/builtins/poseidon/poseidon_stark.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use core::util::poseidon_utils::{
constant_layer_field, mds_layer_field, mds_partial_layer_fast_field, mds_partial_layer_init,
partial_first_constant_layer, sbox_layer_field, sbox_monomial, POSEIDON_STATE_WIDTH,
};
use core::vm::opcodes::OlaOpcode;
use std::marker::PhantomData;

use crate::builtins::poseidon::columns::*;
use crate::stark::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
use crate::stark::cross_table_lookup::Column;
use crate::stark::stark::Stark;
use crate::stark::vars::{StarkEvaluationTargets, StarkEvaluationVars};
use core::util::poseidon_utils::{
constant_layer_field, mds_layer_field, mds_partial_layer_fast_field, mds_partial_layer_init,
partial_first_constant_layer, sbox_layer_field, sbox_monomial, POSEIDON_STATE_WIDTH,
};
use itertools::Itertools;
use plonky2::field::extension::{Extendable, FieldExtension};
use plonky2::field::goldilocks_field::GoldilocksField;
Expand All @@ -18,6 +15,7 @@ use plonky2::field::types::Field;
use plonky2::hash::poseidon::Poseidon;
use plonky2::hash::{hash_types::RichField, poseidon};
use plonky2::plonk::circuit_builder::CircuitBuilder;
use std::marker::PhantomData;

#[derive(Copy, Clone, Default)]
pub struct PoseidonStark<F, const D: usize> {
Expand Down
7 changes: 6 additions & 1 deletion circuits/src/builtins/storage/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ pub(crate) const COL_ST_IS_LAYER_256: usize = COL_ST_IS_LAYER_192 + 1;
pub(crate) const COL_ST_ACC_LAYER_MARKER: usize = COL_ST_IS_LAYER_256 + 1;
pub(crate) const COL_ST_FILTER_IS_HASH_BIT_0: usize = COL_ST_ACC_LAYER_MARKER + 1;
pub(crate) const COL_ST_FILTER_IS_HASH_BIT_1: usize = COL_ST_FILTER_IS_HASH_BIT_0 + 1;
pub(crate) const COL_ST_IS_PADDING: usize = COL_ST_FILTER_IS_HASH_BIT_1 + 1;
pub(crate) const COL_ST_FILTER_IS_FOR_PROG: usize = COL_ST_FILTER_IS_HASH_BIT_1 + 1;
pub(crate) const COL_ST_IS_PADDING: usize = COL_ST_FILTER_IS_FOR_PROG + 1;
pub(crate) const NUM_COL_ST: usize = COL_ST_IS_PADDING + 1;

pub(crate) fn get_storage_access_col_name_map() -> BTreeMap<usize, String> {
Expand Down Expand Up @@ -85,6 +86,10 @@ pub(crate) fn get_storage_access_col_name_map() -> BTreeMap<usize, String> {
COL_ST_FILTER_IS_HASH_BIT_1,
String::from("FILTER_IS_HASH_BIT_1"),
);
m.insert(
COL_ST_FILTER_IS_FOR_PROG,
String::from("FILTER_IS_FOR_PROG"),
);
m.insert(COL_ST_IS_PADDING, String::from("IS_PADDING"));
m
}
38 changes: 28 additions & 10 deletions circuits/src/builtins/storage/storage_access_stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,30 @@ use crate::stark::{

use super::columns::*;

pub fn ctl_data_for_prog_chunk<F: Field>() -> Vec<Column<F>> {
let mut res = Column::singles([COL_ST_IS_WRITE]).collect_vec();
res.extend(Column::singles(COL_ST_ADDR_RANGE.chain(COL_ST_PATH_RANGE)));
res
}

pub fn ctl_filter_for_prog_chunk<F: Field>() -> Column<F> {
Column::single(COL_ST_FILTER_IS_FOR_PROG)
}

pub fn ctl_data_with_cpu<F: Field>() -> Vec<Column<F>> {
let mut res = Column::singles([COL_ST_ACCESS_IDX, COL_ST_IS_WRITE]).collect_vec();
res.extend(Column::singles(COL_ST_ADDR_RANGE.chain(COL_ST_PATH_RANGE)));
res
}

pub fn ctl_filter_with_cpu_sstore<F: Field>() -> Column<F> {
Column::single(COL_ST_IS_LAYER_256)
Column::linear_combination_with_constant(
[
(COL_ST_IS_LAYER_256, F::ONE),
(COL_ST_FILTER_IS_FOR_PROG, F::NEG_ONE),
],
F::ZERO,
)
}

pub fn ctl_data_with_poseidon_bit0<F: Field>() -> Vec<Column<F>> {
Expand Down Expand Up @@ -109,6 +125,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for StorageAccess
let nv_st_access_idx = nv[COL_ST_ACCESS_IDX];
let lv_layer = lv[COL_ST_LAYER];
let nv_layer = nv[COL_ST_LAYER];

// is_padding binary and change from 0 to 1 once.
yield_constr.constraint((P::ONES - lv_is_padding) * lv_is_padding);
yield_constr.constraint_transition(
Expand Down Expand Up @@ -299,6 +316,9 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for StorageAccess
);
yield_constr.constraint(lv_is_padding * lv[COL_ST_FILTER_IS_HASH_BIT_0]);
yield_constr.constraint(lv_is_padding * lv[COL_ST_FILTER_IS_HASH_BIT_1]);
yield_constr.constraint(lv[COL_ST_FILTER_IS_FOR_PROG] * lv[COL_ST_IS_WRITE]);
yield_constr
.constraint(lv[COL_ST_FILTER_IS_FOR_PROG] * (P::ONES - lv[COL_ST_IS_LAYER_256]));
}

fn eval_ext_circuit(
Expand All @@ -323,19 +343,17 @@ mod tests {
},
generation::storage::generate_storage_access_trace,
stark::stark::Stark,
test_utils::simple_test_stark,
};
use core::{
trace::trace::{StorageHashRow, Trace},
trace::trace::Trace,
types::{Field, GoldilocksField},
};
use std::path::PathBuf;

use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};

use crate::{
stark::{constraint_consumer::ConstraintConsumer, vars::StarkEvaluationVars},
test_utils::test_stark_with_asm_path,
};
use crate::stark::{constraint_consumer::ConstraintConsumer, vars::StarkEvaluationVars};

#[test]
fn test_storage_with_program() {
Expand All @@ -360,8 +378,9 @@ mod tests {
type S = StorageAccessStark<F, D>;
let stark = S::default();

let get_trace_rows = |trace: Trace| trace.builtin_storage_hash;
let generate_trace = |rows: &Vec<StorageHashRow>| generate_storage_access_trace(rows);
let generate_trace = |trace: Trace| {
generate_storage_access_trace(&trace.builtin_storage_hash, &trace.builtin_program_hash)
};
let eval_packed_generic =
|vars: StarkEvaluationVars<GoldilocksField, GoldilocksField, NUM_COL_ST>,
constraint_consumer: &mut ConstraintConsumer<GoldilocksField>| {
Expand All @@ -379,9 +398,8 @@ mod tests {
println!("{:>32}\t{:>22}\t{:>22}", name, lv, nv);
}
};
test_stark_with_asm_path(
simple_test_stark(
program_path.to_string(),
get_trace_rows,
generate_trace,
eval_packed_generic,
Some(error_hook),
Expand Down
7 changes: 6 additions & 1 deletion circuits/src/cpu/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ pub(crate) const COL_FILTER_TAPE_LOOKING: usize = COL_IS_NEXT_LINE_SAME_TX + 1;
pub(crate) const IS_SCCALL_EXT_LINE: usize = COL_FILTER_TAPE_LOOKING + 1;
pub(crate) const COL_IS_STORAGE_EXT_LINE: usize = IS_SCCALL_EXT_LINE + 1;
pub(crate) const COL_FILTER_SCCALL_END: usize = COL_IS_STORAGE_EXT_LINE + 1;
pub(crate) const COL_IS_PADDING: usize = COL_FILTER_SCCALL_END + 1;
pub(crate) const COL_FILTER_LOOKING_PROG_IMM: usize = COL_FILTER_SCCALL_END + 1;
pub(crate) const COL_IS_PADDING: usize = COL_FILTER_LOOKING_PROG_IMM + 1;

pub(crate) const NUM_CPU_COLS: usize = COL_IS_PADDING + 1;

Expand Down Expand Up @@ -205,6 +206,10 @@ pub(crate) fn get_cpu_col_name_map() -> BTreeMap<usize, String> {
m.insert(IS_SCCALL_EXT_LINE, "is_sccall_ext_line".to_string());
m.insert(COL_IS_STORAGE_EXT_LINE, "is_storage_ext_line".to_string());
m.insert(COL_FILTER_SCCALL_END, "filter_sccall_end".to_string());
m.insert(
COL_FILTER_LOOKING_PROG_IMM,
"filter_looking_prog_imm".to_string(),
);
m.insert(COL_IS_PADDING, "is_padding".to_string());
m
}
Expand Down
43 changes: 34 additions & 9 deletions circuits/src/cpu/cpu_stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,29 @@ pub fn ctl_filter_cpu_sccall_end<F: Field>() -> Column<F> {
}

// get the data source for Rangecheck in Cpu table
pub fn ctl_data_with_program<F: Field>() -> Vec<Column<F>> {
Column::singles([COL_PC, COL_INST, COL_IMM_VAL]).collect_vec()
pub fn ctl_data_inst_to_program<F: Field>() -> Vec<Column<F>> {
Column::singles(COL_ADDR_CODE_RANGE.chain([COL_PC, COL_INST])).collect_vec()
}

pub fn ctl_filter_with_program<F: Field>() -> Column<F> {
Column::single(COL_INST)
pub fn ctl_data_imm_to_program<F: Field>() -> Vec<Column<F>> {
let mut res = Column::singles(COL_ADDR_CODE_RANGE).collect_vec();
res.push(Column::linear_combination_with_constant(
[(COL_PC, F::ONE)],
F::ONE,
));
res.push(Column::single(COL_IMM_VAL));
res
}

pub fn ctl_filter_with_program_inst<F: Field>() -> Column<F> {
Column::linear_combination_with_constant(
[(COL_IS_EXT_LINE, F::NEG_ONE), (COL_IS_PADDING, F::NEG_ONE)],
F::ONE,
)
}

pub fn ctl_filter_with_program_imm<F: Field>() -> Column<F> {
Column::single(COL_FILTER_LOOKING_PROG_IMM)
}

pub(crate) fn ctl_data_cpu_tape_sccall_caller<F: Field>(i: usize) -> Vec<Column<F>> {
Expand Down Expand Up @@ -828,6 +845,7 @@ impl<
+ lv[COL_S_SSTORE]
+ lv[COL_S_TLOAD] * (lv[COL_OP0] * lv[COL_OP1] + (P::ONES - lv[COL_OP0]))
+ lv[COL_S_TSTORE] * lv[COL_OP1]
+ lv[COL_S_TSTORE] * lv[COL_OP1]
+ lv[COL_S_CALL_SC]
+ lv[COL_S_END] * (P::ONES - lv_is_entry_sc);
let is_crossing_inst = lv[COL_IS_NEXT_LINE_DIFF_INST];
Expand Down Expand Up @@ -896,6 +914,17 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
- wrapper.lv[COL_ADDR_CODE_RANGE.start + ctx_reg_idx]),
);
}
// filter imm to prog
yield_constr.constraint(
(P::ONES - wrapper.lv[COL_IS_PADDING] - wrapper.lv[COL_IS_EXT_LINE])
* wrapper.lv[COL_OP1_IMM]
* (P::ONES - wrapper.lv[COL_FILTER_LOOKING_PROG_IMM]),
);
yield_constr.constraint(
(P::ONES - wrapper.lv[COL_IS_PADDING] - wrapper.lv[COL_IS_EXT_LINE])
* (wrapper.lv[COL_S_MLOAD] + wrapper.lv[COL_S_MSTORE])
* (P::ONES - wrapper.lv[COL_FILTER_LOOKING_PROG_IMM]),
);

Self::constraint_ext_lines(&wrapper, yield_constr);
Self::constraint_env_idx(&wrapper, yield_constr);
Expand Down Expand Up @@ -1013,11 +1042,7 @@ mod tests {
.iter()
.map(|v| GoldilocksField::from_canonical_u64(*v))
.collect_vec();
test_cpu_with_asm_file_name(
"vote.json".to_string(),
Some(init_calldata),
Some(db_name),
);
test_cpu_with_asm_file_name("vote.json".to_string(), Some(init_calldata), Some(db_name));
}

#[allow(unused)]
Expand Down
11 changes: 11 additions & 0 deletions circuits/src/generation/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@ pub fn generate_cpu_trace<F: RichField>(steps: &Vec<Step>) -> [Vec<F>; cpu::NUM_
} else {
F::ZERO
};
trace[cpu::COL_FILTER_LOOKING_PROG_IMM][i] = if s.is_ext_line.0 == 1 {
F::ZERO
} else if s.opcode.0 == OlaOpcode::MLOAD.binary_bit_mask()
|| s.opcode.0 == OlaOpcode::MSTORE.binary_bit_mask()
{
F::ONE
} else if s.op1_imm.0 == 1 {
F::ONE
} else {
F::ZERO
};
}
// fill in padding.
let inst_end = if trace_len == 0 {
Expand Down
76 changes: 76 additions & 0 deletions circuits/src/generation/ctl_test/chunk_poseidon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use core::types::{merkle_tree::decode_addr, Field, GoldilocksField};

use crate::{
builtins::poseidon::columns::*,
generation::{
poseidon::generate_poseidon_trace, poseidon_chunk::generate_poseidon_chunk_trace,
prog::generate_prog_chunk_trace,
},
program::columns::*,
};

use super::debug_trace_print::{get_exec_trace, get_rows_vec_from_trace, print_title_data};

#[test]
fn print_chunk_poseidon_ctl_info() {
let program_file_name: String = "storage_u32.json".to_string();
let call_data = vec![
GoldilocksField::from_canonical_u64(0),
GoldilocksField::from_canonical_u64(2364819430),
];

let trace = get_exec_trace(program_file_name, Some(call_data), None);
let poseidon_chunk_cols = generate_poseidon_chunk_trace(&trace.builtin_poseidon_chunk);
let poseidon_chunk_rows = get_rows_vec_from_trace(poseidon_chunk_cols);

let progs = trace
.addr_program_hash
.into_iter()
.map(|(addr, hash)| (decode_addr(addr), hash))
.collect::<Vec<_>>();
let prog_chunk_cols = generate_prog_chunk_trace(progs);
let prog_chunk_rows = get_rows_vec_from_trace(prog_chunk_cols);

let poseidon_cols = generate_poseidon_trace::<GoldilocksField>(&trace.builtin_poseidon);
let poseidon_rows = get_rows_vec_from_trace(poseidon_cols);

let psdn_chunk_looking_cols: Vec<usize> = COL_POSEIDON_CHUNK_VALUE_RANGE
.chain(COL_POSEIDON_CHUNK_CAP_RANGE)
.chain(COL_POSEIDON_CHUNK_HASH_RANGE)
.collect();
let prog_chunk_looking_cols: Vec<usize> = COL_PROG_CHUNK_INST_RANGE
.chain(COL_PROG_CHUNK_CAP_RANGE)
.chain(COL_PROG_CHUNK_HASH_RANGE)
.collect();
let poseidon_looked_cols: Vec<usize> = COL_POSEIDON_INPUT_RANGE
.chain(COL_POSEIDON_OUTPUT_RANGE)
.collect();

print_title_data(
"psdn_chunk",
get_poseidon_chunk_col_name_map(),
&poseidon_chunk_rows,
psdn_chunk_looking_cols,
|row: &[GoldilocksField], _| row[COL_POSEIDON_CHUNK_FILTER_LOOKING_POSEIDON].is_one(),
0,
None,
);
print_title_data(
"prog_chunk",
get_prog_chunk_col_name_map(),
&prog_chunk_rows,
prog_chunk_looking_cols,
|row: &[GoldilocksField], _| row[COL_PROG_CHUNK_IS_PADDING_LINE].is_zero(),
0,
None,
);
print_title_data(
"poseidon",
get_poseidon_col_name_map(),
&poseidon_rows,
poseidon_looked_cols,
|row: &[GoldilocksField], _| row[FILTER_LOOKED_NORMAL].is_one(),
0,
None,
);
}
Loading

0 comments on commit 0f64d7b

Please sign in to comment.