use std::iter;
use super::{
rw::{RwFingerprints, ToVec},
Block, ExecStep, Rw, RwMap, RwRow,
};
use crate::util::unwrap_value;
use bus_mapping::{
circuit_input_builder::{self, Call, ChunkContext, FixedCParams},
operation::Target,
Error,
};
use eth_types::Field;
use gadgets::permutation::get_permutation_fingerprints;
use halo2_proofs::circuit::Value;
use itertools::Itertools;
#[derive(Debug, Clone)]
pub struct Chunk<F> {
pub begin_chunk: Option<ExecStep>,
pub end_chunk: Option<ExecStep>,
pub padding: Option<ExecStep>,
pub chunk_context: ChunkContext,
pub chrono_rws: RwMap,
pub by_address_rws: RwMap,
pub permu_alpha: F,
pub permu_gamma: F,
pub by_address_rw_fingerprints: RwFingerprints<F>,
pub chrono_rw_fingerprints: RwFingerprints<F>,
pub fixed_param: FixedCParams,
pub prev_last_call: Option<Call>,
pub prev_chunk_last_chrono_rw: Option<Rw>,
pub prev_chunk_last_by_address_rw: Option<Rw>,
}
impl<F: Field> Default for Chunk<F> {
fn default() -> Self {
Self {
begin_chunk: None,
end_chunk: None,
padding: None,
chunk_context: ChunkContext::default(),
chrono_rws: RwMap::default(),
by_address_rws: RwMap::default(),
permu_alpha: F::from(1),
permu_gamma: F::from(1),
by_address_rw_fingerprints: RwFingerprints::default(),
chrono_rw_fingerprints: RwFingerprints::default(),
fixed_param: FixedCParams::default(),
prev_last_call: None,
prev_chunk_last_chrono_rw: None,
prev_chunk_last_by_address_rw: None,
}
}
}
pub fn chunk_convert<F: Field>(
block: &Block<F>,
builder: &circuit_input_builder::CircuitInputBuilder<FixedCParams>,
) -> Result<Vec<Chunk<F>>, Error> {
let (by_address_rws, padding_meta) = (&block.by_address_rws, &block.rw_padding_meta);
let alpha = F::from(103);
let gamma = F::from(101);
let mut chunks: Vec<Chunk<F>> = Vec::with_capacity(builder.chunks.len());
for (i, (prev_chunk, chunk)) in iter::once(None) .chain(builder.chunks.iter().map(Some))
.tuple_windows()
.enumerate()
{
let chunk = chunk.unwrap(); let prev_chunk_last_chrono_rw = prev_chunk.map(|prev_chunk| {
assert!(builder.circuits_params.max_rws > 0);
let chunk_inner_rwc = prev_chunk.ctx.rwc.0;
if chunk_inner_rwc.saturating_sub(1) == builder.circuits_params.max_rws {
RwMap::get_rw(&builder.block.container, prev_chunk.ctx.end_rwc - 1)
.expect("Rw does not exist")
} else {
Rw::Padding {
rw_counter: builder.circuits_params.max_rws - 1,
}
}
});
let chrono_rws = {
let mut chrono_rws = RwMap::from(&builder.block.container);
if let Some(padding_vec) = chrono_rws.0.get_mut(&Target::Padding) {
padding_vec.clear()
}
chrono_rws.take_rw_counter_range(chunk.ctx.initial_rwc, chunk.ctx.end_rwc)
};
let (prev_chunk_last_by_address_rw, by_address_rws) = {
let start = chunk.ctx.idx * builder.circuits_params.max_rws;
let size = builder.circuits_params.max_rws;
let skipped = by_address_rws
.iter()
.filter(|rw| rw.tag() != Target::Padding)
.cloned() .chain(padding_meta.iter().flat_map(|(k, v)| {
vec![
Rw::Padding { rw_counter: *k };
<i32 as TryInto<usize>>::try_into(*v).unwrap()
]
}));
if start == 0 {
(None, RwMap::from(skipped.take(size).collect::<Vec<_>>()))
} else {
let mut skipped = skipped.skip(start - 1 - (chunk.ctx.idx - 1));
let prev_chunk_last_by_address_rw = skipped.next();
(
prev_chunk_last_by_address_rw,
RwMap::from(skipped.take(size).collect::<Vec<_>>()),
)
}
};
let by_address_rw_fingerprints = get_permutation_fingerprint_of_rwmap(
&by_address_rws,
chunk.fixed_param.max_rws,
alpha,
gamma,
if i == 0 {
F::from(1)
} else {
chunks[i - 1].by_address_rw_fingerprints.mul_acc
},
false,
prev_chunk_last_by_address_rw,
);
let chrono_rw_fingerprints = get_permutation_fingerprint_of_rwmap(
&chrono_rws,
chunk.fixed_param.max_rws,
alpha,
gamma,
if i == 0 {
F::from(1)
} else {
chunks[i - 1].chrono_rw_fingerprints.mul_acc
},
true,
prev_chunk_last_chrono_rw,
);
chunks.push(Chunk {
permu_alpha: alpha,
permu_gamma: gamma,
by_address_rw_fingerprints,
chrono_rw_fingerprints,
begin_chunk: chunk.begin_chunk.clone(),
end_chunk: chunk.end_chunk.clone(),
padding: chunk.padding.clone(),
chunk_context: chunk.ctx.clone(),
chrono_rws,
by_address_rws,
fixed_param: chunk.fixed_param,
prev_last_call: chunk.prev_last_call.clone(),
prev_chunk_last_chrono_rw,
prev_chunk_last_by_address_rw,
});
}
if log::log_enabled!(log::Level::Debug) {
chunks
.iter()
.enumerate()
.for_each(|(i, chunk)| log::debug!("{}th chunk context {:?}", i, chunk,));
}
Ok(chunks)
}
pub fn get_rwtable_fingerprints<F: Field>(
alpha: F,
gamma: F,
prev_continuous_fingerprint: F,
rows: &Vec<Rw>,
) -> RwFingerprints<F> {
let x = rows.to2dvec();
let fingerprints = get_permutation_fingerprints(
&x,
Value::known(alpha),
Value::known(gamma),
Value::known(prev_continuous_fingerprint),
);
fingerprints
.first()
.zip(fingerprints.last())
.map(|((first_acc, first_row), (last_acc, last_row))| {
RwFingerprints::new(
unwrap_value(*first_row),
unwrap_value(*last_row),
unwrap_value(*first_acc),
unwrap_value(*last_acc),
)
})
.unwrap_or_default()
}
pub fn get_permutation_fingerprint_of_rwmap<F: Field>(
rwmap: &RwMap,
max_row: usize,
alpha: F,
gamma: F,
prev_continuous_fingerprint: F,
is_chrono: bool,
padding_start_rw: Option<Rw>,
) -> RwFingerprints<F> {
get_permutation_fingerprint_of_rwvec(
&rwmap.table_assignments(is_chrono),
max_row,
alpha,
gamma,
prev_continuous_fingerprint,
padding_start_rw,
)
}
pub fn get_permutation_fingerprint_of_rwvec<F: Field>(
rwvec: &[Rw],
max_row: usize,
alpha: F,
gamma: F,
prev_continuous_fingerprint: F,
padding_start_rw: Option<Rw>,
) -> RwFingerprints<F> {
get_permutation_fingerprint_of_rwrowvec(
&rwvec
.iter()
.map(|row| row.table_assignment())
.collect::<Vec<RwRow<Value<F>>>>(),
max_row,
alpha,
gamma,
prev_continuous_fingerprint,
padding_start_rw.map(|r| r.table_assignment()),
)
}
pub fn get_permutation_fingerprint_of_rwrowvec<F: Field>(
rwrowvec: &[RwRow<Value<F>>],
max_row: usize,
alpha: F,
gamma: F,
prev_continuous_fingerprint: F,
padding_start_rwrow: Option<RwRow<Value<F>>>,
) -> RwFingerprints<F> {
let (rows, _) = RwRow::padding(rwrowvec, max_row, padding_start_rwrow);
let x = rows.to2dvec();
let fingerprints = get_permutation_fingerprints(
&x,
Value::known(alpha),
Value::known(gamma),
Value::known(prev_continuous_fingerprint),
);
fingerprints
.first()
.zip(fingerprints.last())
.map(|((first_acc, first_row), (last_acc, last_row))| {
RwFingerprints::new(
unwrap_value(*first_row),
unwrap_value(*last_row),
unwrap_value(*first_acc),
unwrap_value(*last_acc),
)
})
.unwrap_or_default()
}
pub fn get_permutation_randomness<F: Field>() -> (F, F) {
(F::from(1), F::from(1))
}