Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Range-check keccak sponge inputs to bytes #1342

Merged
merged 3 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions evm/src/keccak_sponge/columns.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::borrow::{Borrow, BorrowMut};
use std::mem::{size_of, transmute};
use std::ops::Range;

use crate::util::{indices_arr, transmute_no_compile_time_size_checks};

Expand Down Expand Up @@ -72,12 +73,36 @@ pub(crate) struct KeccakSpongeColumnsView<T: Copy> {
/// The first part of the state of the sponge, seen as bytes, after the permutation is applied.
/// This also represents the output digest of the Keccak sponge during the squeezing phase.
pub updated_digest_state_bytes: [T; KECCAK_DIGEST_BYTES],

/// The counter column (used for the range check) starts from 0 and increments.
pub range_counter: T,
/// The frequencies column used in logUp.
pub rc_frequencies: T,
}

// `u8` is guaranteed to have a `size_of` of 1.
/// Number of columns in `KeccakSpongeStark`.
pub const NUM_KECCAK_SPONGE_COLUMNS: usize = size_of::<KeccakSpongeColumnsView<u8>>();

// Indices for LogUp range-check.
// They are on the last registers of this table.
pub(crate) const RC_FREQUENCIES: usize = NUM_KECCAK_SPONGE_COLUMNS - 1;
pub(crate) const RANGE_COUNTER: usize = RC_FREQUENCIES - 1;

pub(crate) const BLOCK_BYTES_START: usize =
6 + KECCAK_RATE_BYTES + KECCAK_RATE_U32S + KECCAK_CAPACITY_U32S;
/// Indices for the range-checked values, i.e. the `block_bytes` section.
// TODO: Find a better way to access those indices
pub(crate) const fn get_block_bytes_range() -> Range<usize> {
BLOCK_BYTES_START..BLOCK_BYTES_START + KECCAK_RATE_BYTES
}

/// Return the index for the targeted `block_bytes` element.
pub(crate) const fn get_single_block_bytes_value(i: usize) -> usize {
debug_assert!(i < KECCAK_RATE_BYTES);
get_block_bytes_range().start + i
}

impl<T: Copy> From<[T; NUM_KECCAK_SPONGE_COLUMNS]> for KeccakSpongeColumnsView<T> {
fn from(value: [T; NUM_KECCAK_SPONGE_COLUMNS]) -> Self {
unsafe { transmute_no_compile_time_size_checks(value) }
Expand Down
57 changes: 50 additions & 7 deletions evm/src/keccak_sponge/keccak_sponge_stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ use plonky2::hash::hash_types::RichField;
use plonky2::iop::ext_target::ExtensionTarget;
use plonky2::timed;
use plonky2::util::timing::TimingTree;
use plonky2::util::transpose;
use plonky2_util::ceil_div_usize;

use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
use crate::cpu::kernel::keccak_util::keccakf_u32s;
use crate::cross_table_lookup::Column;
use crate::evaluation_frame::{StarkEvaluationFrame, StarkFrame};
use crate::keccak_sponge::columns::*;
use crate::lookup::Lookup;
use crate::stark::Stark;
use crate::util::trace_rows_to_poly_values;
use crate::witness::memory::MemoryAddress;

/// Strict upper bound for the individual bytes range-check.
const BYTE_RANGE_MAX: usize = 256;
dvdplm marked this conversation as resolved.
Show resolved Hide resolved

/// Creates the vector of `Columns` corresponding to:
/// - the address in memory of the inputs,
/// - the length of the inputs,
Expand Down Expand Up @@ -246,13 +250,12 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakSpongeStark<F, D> {
self.generate_trace_rows(operations, min_rows)
);

let trace_polys = timed!(
timing,
"convert to PolynomialValues",
trace_rows_to_poly_values(trace_rows)
);
let trace_row_vecs: Vec<_> = trace_rows.into_iter().map(|row| row.to_vec()).collect();

let mut trace_cols = transpose(&trace_row_vecs);
self.generate_range_checks(&mut trace_cols);

trace_polys
trace_cols.into_iter().map(PolynomialValues::new).collect()
}

/// Generates the trace rows given the vector of `KeccakSponge` operations.
Expand Down Expand Up @@ -477,6 +480,38 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakSpongeStark<F, D> {
// indicating that it's a dummy/padding row.
KeccakSpongeColumnsView::default().into()
}

/// Expects input in *column*-major layout
fn generate_range_checks(&self, cols: &mut Vec<Vec<F>>) {
debug_assert!(cols.len() == NUM_KECCAK_SPONGE_COLUMNS);

let n_rows = cols[0].len();
debug_assert!(cols.iter().all(|col| col.len() == n_rows));

for i in 0..BYTE_RANGE_MAX {
cols[RANGE_COUNTER][i] = F::from_canonical_usize(i);
}
for i in BYTE_RANGE_MAX..n_rows {
cols[RANGE_COUNTER][i] = F::from_canonical_usize(BYTE_RANGE_MAX - 1);
}
dvdplm marked this conversation as resolved.
Show resolved Hide resolved

// For each column c in cols, generate the range-check
// permutations and put them in the corresponding range-check
// columns rc_c and rc_c+1.
for col in 0..KECCAK_RATE_BYTES {
let c = get_single_block_bytes_value(col);
for i in 0..n_rows {
let x = cols[c][i].to_canonical_u64() as usize;
assert!(
x < BYTE_RANGE_MAX,
"column value {} exceeds the max range value {}",
x,
BYTE_RANGE_MAX
);
cols[RC_FREQUENCIES][x] += F::ONE;
}
}
}
}

impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for KeccakSpongeStark<F, D> {
Expand Down Expand Up @@ -733,6 +768,14 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for KeccakSpongeS
fn constraint_degree(&self) -> usize {
3
}

fn lookups(&self) -> Vec<Lookup> {
vec![Lookup {
columns: get_block_bytes_range().collect(),
table_column: RANGE_COUNTER,
frequencies_column: RC_FREQUENCIES,
}]
}
}

#[cfg(test)]
Expand Down
Loading