use super::*;
#[derive(Clone, Debug)]
pub struct KeccakTable {
pub is_enabled: Column<Advice>,
pub input_rlc: Column<Advice>, pub input_len: Column<Advice>,
pub output: WordLoHi<Column<Advice>>,
}
impl<F: Field> LookupTable<F> for KeccakTable {
fn columns(&self) -> Vec<Column<Any>> {
vec![
self.is_enabled.into(),
self.input_rlc.into(),
self.input_len.into(),
self.output.lo().into(),
self.output.hi().into(),
]
}
fn annotations(&self) -> Vec<String> {
vec![
String::from("is_enabled"),
String::from("input_rlc"),
String::from("input_len"),
String::from("output_lo"),
String::from("output_hi"),
]
}
}
impl KeccakTable {
pub fn construct<F: Field>(meta: &mut ConstraintSystem<F>) -> Self {
Self {
is_enabled: meta.advice_column(),
input_rlc: meta.advice_column_in(SecondPhase),
input_len: meta.advice_column(),
output: WordLoHi::new([meta.advice_column(), meta.advice_column()]),
}
}
pub fn assignments<F: Field>(
input: &[u8],
challenges: &Challenges<Value<F>>,
) -> Vec<[Value<F>; 5]> {
let input_rlc = challenges
.keccak_input()
.map(|challenge| rlc::value(input.iter().rev(), challenge));
let input_len = F::from(input.len() as u64);
let output = WordLoHi::from(keccak(input));
vec![[
Value::known(F::ONE),
input_rlc,
Value::known(input_len),
Value::known(output.lo()),
Value::known(output.hi()),
]]
}
pub fn assign_row<F: Field>(
&self,
region: &mut Region<F>,
offset: usize,
values: [Value<F>; 5],
) -> Result<(), Error> {
for (&column, value) in <KeccakTable as LookupTable<F>>::advice_columns(self)
.iter()
.zip(values.iter())
{
region.assign_advice(|| format!("assign {}", offset), column, offset, || *value)?;
}
Ok(())
}
pub fn dev_load<'a, F: Field>(
&self,
layouter: &mut impl Layouter<F>,
inputs: impl IntoIterator<Item = &'a Vec<u8>> + Clone,
challenges: &Challenges<Value<F>>,
) -> Result<(), Error> {
layouter.assign_region(
|| "keccak table",
|mut region| {
let mut offset = 0;
for column in <KeccakTable as LookupTable<F>>::advice_columns(self) {
region.assign_advice(
|| "keccak table all-zero row",
column,
offset,
|| Value::known(F::ZERO),
)?;
}
offset += 1;
let keccak_table_columns = <KeccakTable as LookupTable<F>>::advice_columns(self);
for input in inputs.clone() {
for row in Self::assignments(input, challenges) {
for (&column, value) in keccak_table_columns.iter().zip_eq(row) {
region.assign_advice(
|| format!("keccak table row {}", offset),
column,
offset,
|| value,
)?;
}
offset += 1;
}
}
Ok(())
},
)
}
pub fn match_columns(
&self,
value_rlc: Column<Advice>,
length: Column<Advice>,
code_hash: WordLoHi<Column<Advice>>,
) -> Vec<(Column<Advice>, Column<Advice>)> {
vec![
(value_rlc, self.input_rlc),
(length, self.input_len),
(code_hash.lo(), self.output.lo()),
(code_hash.hi(), self.output.hi()),
]
}
}