Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
compute next_fingerprints logic in witness block
Browse files Browse the repository at this point in the history
  • Loading branch information
hero78119 committed Oct 5, 2023
1 parent 43ed90e commit 69680b8
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 136 deletions.
132 changes: 70 additions & 62 deletions gadgets/src/permutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,90 +46,64 @@ impl<F: Field> PermutationChipConfig<F> {
alpha: Value<F>,
gamma: Value<F>,
prev_continuous_fingerprint: Value<F>,
_next_continuous_fingerprint: Value<F>,
col_values: &Vec<Vec<Value<F>>>,
next_continuous_fingerprint: Value<F>,
col_values: &[Vec<Value<F>>],
) -> Result<PermutationAssignedCells<F>, Error> {
self.annotate_columns_in_region(region, "state_circuit");
let mut offset = 0;
let alpha_first_cell = region.assign_advice(
|| format!("alpha at index {}", offset),
self.alpha,
offset,
|| alpha,
)?;
let gamma_first_cell = region.assign_advice(
|| format!("gamma at index {}", offset),
self.gamma,
offset,
|| gamma,
)?;
let prev_continuous_fingerprint_cell = region.assign_advice(
|| format!("fingerprint at index {}", offset),
self.fingerprints,
offset,
|| prev_continuous_fingerprint,
)?;

let power_of_gamma = {
let num_of_col = col_values.get(0).map(|x| x.len()).unwrap_or_default();
std::iter::successors(Some(Value::known(F::ONE)), |prev| (*prev * gamma).into())
.take(num_of_col)
.collect::<Vec<Value<F>>>()
};

offset += 1;

let mut fingerprints = prev_continuous_fingerprint;

// get accumulated fingerprints of each row
let fingerprints =
get_permutation_fingerprints(col_values, alpha, gamma, prev_continuous_fingerprint, 1);

// debug: internal computed fingerprint should match with external fingerprint
next_continuous_fingerprint
.zip(*fingerprints.last().unwrap())
.map(|(a, b)| debug_assert!(a == b, "{:?} != {:?}", a, b));

let mut last_fingerprint_cell = None;
for (_, row) in col_values.iter().enumerate() {
self.q_row_non_first.enable(region, offset)?;

let perf_term = {
let tmp = row
.iter()
.zip_eq(power_of_gamma.iter())
.map(|(a, b)| a.zip(*b).map(|(a, b)| a * b))
.fold(Value::known(F::ZERO), |prev, cur| {
prev.zip(cur).map(|(a, b)| a + b)
});
alpha.zip(tmp).map(|(alpha, tmp)| alpha - tmp)
};

fingerprints = fingerprints.zip(perf_term).map(|(prev, cur)| prev * cur);
let mut alpha_first_cell = None;
let mut gamma_first_cell = None;
let mut prev_continuous_fingerprint_cell = None;
for (offset, row_fingerprint) in fingerprints.iter().enumerate() {
// skip first fingerprint for its prev_fingerprint
if offset != 0 {
self.q_row_non_first.enable(region, offset)?;
}

let fingerprint_cell = region.assign_advice(
|| format!("fingerprint at index {}", offset),
self.fingerprints,
offset,
|| fingerprints,
|| *row_fingerprint,
)?;
// last offset (with one padding)
if offset == col_values.len() {
// TODO debug: internal computed fingerprint should match with external fingerprint
// next_continuous_fingerprint
// .zip(fingerprints)
// .map(|(a, b)| debug_assert!(a == b, "{:?} != {:?}", a, b));
last_fingerprint_cell = Some(fingerprint_cell);
}
region.assign_advice(
let alpha_cell = region.assign_advice(
|| format!("alpha at index {}", offset),
self.alpha,
offset,
|| alpha,
)?;
region.assign_advice(
let gamma_cell = region.assign_advice(
|| format!("gamma at index {}", offset),
self.gamma,
offset,
|| gamma,
)?;

offset += 1;
if offset == 0 {
alpha_first_cell = Some(alpha_cell);
gamma_first_cell = Some(gamma_cell);
prev_continuous_fingerprint_cell = Some(fingerprint_cell.clone());
}
// last offset
if offset == fingerprints.len() - 1 {
last_fingerprint_cell = Some(fingerprint_cell);
}
}

Ok((
alpha_first_cell,
gamma_first_cell,
prev_continuous_fingerprint_cell,
alpha_first_cell.unwrap(),
gamma_first_cell.unwrap(),
prev_continuous_fingerprint_cell.unwrap(),
last_fingerprint_cell.unwrap(),
))
}
Expand Down Expand Up @@ -219,3 +193,37 @@ impl<F: Field> PermutationChip<F> {
}

impl<F: Field> PermutationChip<F> {}

/// get permutation fingerprint of rows
pub fn get_permutation_fingerprints<F: Field>(
col_values: &[Vec<Value<F>>],
alpha: Value<F>,
gamma: Value<F>,
prev_continuous_fingerprint: Value<F>,
row_skip: usize,
) -> Vec<Value<F>> {
let power_of_gamma = {
let num_of_col = col_values.get(0).map(|row| row.len()).unwrap_or_default();
std::iter::successors(Some(Value::known(F::ONE)), |prev| (*prev * gamma).into())
.take(num_of_col)
.collect::<Vec<Value<F>>>()
};
let mut fingerprints = vec![prev_continuous_fingerprint];
col_values
.iter()
.skip(row_skip)
.map(|row| {
let tmp = row
.iter()
.zip_eq(power_of_gamma.iter())
.map(|(a, b)| a.zip(*b).map(|(a, b)| a * b))
.fold(Value::known(F::ZERO), |prev, cur| {
prev.zip(cur).map(|(a, b)| a + b)
});
alpha.zip(tmp).map(|(alpha, tmp)| alpha - tmp)
})
.for_each(|value| {
fingerprints.push(fingerprints[fingerprints.len() - 1] * value);
});
fingerprints
}
82 changes: 45 additions & 37 deletions zkevm-circuits/src/evm_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub(crate) mod util;

#[cfg(test)]
pub(crate) mod test;
use self::step::HasExecutionState;
#[cfg(feature = "test-circuits")]
pub use self::EvmCircuit as TestEvmCircuit;
use self::{step::HasExecutionState, witness::rw::ToVec};

pub use crate::witness;
use crate::{
Expand All @@ -26,6 +26,7 @@ use crate::{
UXTable,
},
util::{Challenges, SubCircuit, SubCircuitConfig},
witness::RwMap,
};
use bus_mapping::evm::OpcodeId;
use eth_types::Field;
Expand Down Expand Up @@ -302,7 +303,10 @@ impl<F: Field> SubCircuit<F> for EvmCircuit<F> {

config.execution.assign_block(layouter, block, challenges)?;

let rw_rows = block.rws.table_assignments(true);
let (rw_rows_padding, _) = RwMap::table_assignments_prepad(
&block.rws.table_assignments(true),
block.circuits_params.max_rws,
);
let (
(rw_table_row_first, rw_table_row_last),
(
Expand All @@ -314,31 +318,26 @@ impl<F: Field> SubCircuit<F> for EvmCircuit<F> {
) = layouter.assign_region(
|| "evm circuit",
|mut region| {
let rw_table_first_n_last_cells =
config
.rw_table
.load_with_region(&mut region, &rw_rows, rw_rows.len())?;
region.name_column(|| "EVM_pi_pre_continuity", config.pi_pre_continuity);
region.name_column(|| "EVM_pi_next_continuity", config.pi_next_continuity);
region.name_column(
|| "EVM_pi_permutation_challenges",
config.pi_permutation_challenges,
);
let rw_table_first_n_last_cells = config.rw_table.load_with_region(
&mut region,
// pass non-padding rws to `load_with_region` since it will be padding inside
&block.rws.table_assignments(true),
// align with state circuit to padding to same max_rws
block.circuits_params.max_rws,
)?;
let permutation_cells = config.rw_permutation_config.assign(
&mut region,
Value::known(block.permu_alpha),
Value::known(block.permu_gamma),
Value::known(block.permu_prev_continuous_fingerprint),
Value::known(block.permu_next_continuous_fingerprint),
&block
.rws
.table_assignments(true)
.iter()
.skip(1) // skip first row since it's used for permutation
.map(|row| {
row.table_assignment::<F>()
.unwrap()
.values()
.to_vec()
.iter()
.map(|f| Value::known(*f))
.collect::<Vec<Value<F>>>()
})
.collect::<Vec<Vec<Value<F>>>>(),
Value::known(block.permu_chronological_rwtable_prev_continuous_fingerprint),
Value::known(block.permu_chronological_rwtable_next_continuous_fingerprint),
&rw_rows_padding.to2dvec(),
)?;
Ok((rw_table_first_n_last_cells, permutation_cells))
},
Expand Down Expand Up @@ -372,29 +371,34 @@ impl<F: Field> SubCircuit<F> for EvmCircuit<F> {
/// Compute the public inputs for this circuit.
fn instance(&self) -> Vec<Vec<F>> {
let block = self.block.as_ref().unwrap();
let rws_assignments = block.rws.table_assignments(true);

assert!(!rws_assignments.is_empty());
let (rws_assignments_padding, _) = RwMap::table_assignments_prepad(
&block.rws.table_assignments(true),
block.circuits_params.max_rws,
);

let rws_values = [0, rws_assignments.len() - 1] // get first/last row and concat
.iter()
.map(|i| {
rws_assignments
.get(*i)
.map(|row| row.table_assignment().unwrap().values())
.unwrap_or_default()
.to_vec()
})
.collect::<Vec<Vec<F>>>();
assert!(!rws_assignments_padding.is_empty());

let rws_values = [
rws_assignments_padding.first(),
rws_assignments_padding.last(),
] // get first/last row and concat
.iter()
.map(|row| {
row.map(|row| row.table_assignment().unwrap().values())
.unwrap_or_default()
.to_vec()
})
.collect::<Vec<Vec<F>>>();
vec![
vec![
rws_values[0].clone(),
vec![block.permu_prev_continuous_fingerprint],
vec![block.permu_chronological_rwtable_prev_continuous_fingerprint],
]
.concat(),
vec![
rws_values[1].clone(),
vec![block.permu_next_continuous_fingerprint],
vec![block.permu_chronological_rwtable_next_continuous_fingerprint],
]
.concat(),
vec![block.permu_alpha, block.permu_gamma],
Expand Down Expand Up @@ -480,6 +484,10 @@ pub(crate) mod cached {
pub(crate) fn get_test_circuit_from_block(block: Block<Fr>) -> Self {
Self(EvmCircuit::<Fr>::get_test_circuit_from_block(block))
}

pub(crate) fn instance(&self) -> Vec<Vec<Fr>> {
self.0.instance()
}
}
}

Expand Down
38 changes: 16 additions & 22 deletions zkevm-circuits/src/state_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use self::{
use crate::{
table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable, UXTable},
util::{word, Challenges, Expr, SubCircuit, SubCircuitConfig},
witness::{self, MptUpdates, Rw, RwMap},
witness::{self, rw::ToVec, MptUpdates, Rw, RwMap},
};
use constraint_builder::{ConstraintBuilder, Queries};
use eth_types::{Address, Field, Word};
Expand Down Expand Up @@ -423,6 +423,12 @@ impl<F: Field> StateCircuitConfig<F> {
region.name_column(|| "STATE_mpt_proof_type", self.mpt_proof_type);
region.name_column(|| "STATE_state_root lo", self.state_root.lo());
region.name_column(|| "STATE_state_root hi", self.state_root.hi());
region.name_column(|| "STATE_pi_pre_continuity", self.pi_pre_continuity);
region.name_column(|| "STATE_pi_next_continuity", self.pi_next_continuity);
region.name_column(
|| "STATE_pi_permutation_challenges",
self.pi_permutation_challenges,
);
}
}

Expand Down Expand Up @@ -504,8 +510,8 @@ impl<F: Field> SubCircuit<F> for StateCircuit<F> {
block.circuits_params.max_rws,
block.permu_alpha,
block.permu_gamma,
block.permu_prev_continuous_fingerprint,
block.permu_next_continuous_fingerprint,
block.permu_rwtable_prev_continuous_fingerprint,
block.permu_rwtable_next_continuous_fingerprint,
)
}

Expand Down Expand Up @@ -546,8 +552,7 @@ impl<F: Field> SubCircuit<F> for StateCircuit<F> {
) = layouter.assign_region(
|| "state circuit",
|mut region| {
// TODO Below RwMap::table_assignments_prepad call 3 times, refactor to be more
// efficient
// TODO optimimise RwMap::table_assignments_prepad calls from 3 times -> 1
let rw_table_first_n_last_cells =
config
.rw_table
Expand All @@ -563,18 +568,7 @@ impl<F: Field> SubCircuit<F> for StateCircuit<F> {
Value::known(self.permu_gamma),
Value::known(self.permu_prev_continuous_fingerprint),
Value::known(self.permu_next_continuous_fingerprint),
&rows
.iter()
.skip(1) // skip first row since it's used for permutation
.map(|row| {
row.table_assignment::<F>()
.unwrap()
.values()
.iter()
.map(|f| Value::known(*f))
.collect::<Vec<Value<F>>>()
})
.collect::<Vec<Vec<Value<F>>>>(),
&rows.to2dvec(),
)?;
#[cfg(test)]
{
Expand Down Expand Up @@ -630,12 +624,12 @@ impl<F: Field> SubCircuit<F> for StateCircuit<F> {
fn instance(&self) -> Vec<Vec<F>> {
assert!(!self.rows.is_empty());

let rws_values = [0, self.rows.len() - 1] // get first/last row and concat
let (rows, _) = RwMap::table_assignments_prepad(&self.rows, self.n_rows);

let rws_values = [rows.first(), rows.last()] // get first/last row and concat
.iter()
.map(|i| {
self.rows
.get(*i)
.map(|row| row.table_assignment().unwrap().values())
.map(|row| {
row.map(|row| row.table_assignment().unwrap().values())
.unwrap_or_default()
.to_vec()
})
Expand Down
Loading

0 comments on commit 69680b8

Please sign in to comment.