mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-09 17:23:08 +00:00
Merge pull request #561 from mir-protocol/keccak_input_registers
Keccak input registers
This commit is contained in:
commit
d256044a19
@ -64,7 +64,7 @@ mod tests {
|
||||
use crate::cpu;
|
||||
use crate::cpu::cpu_stark::CpuStark;
|
||||
use crate::cross_table_lookup::CrossTableLookup;
|
||||
use crate::keccak::keccak_stark::{KeccakStark, INPUT_LIMBS, NUM_ROUNDS};
|
||||
use crate::keccak::keccak_stark::{KeccakStark, NUM_INPUTS, NUM_ROUNDS};
|
||||
use crate::proof::AllProof;
|
||||
use crate::prover::prove;
|
||||
use crate::recursive_verifier::{
|
||||
@ -93,7 +93,7 @@ mod tests {
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let num_inputs = 2;
|
||||
let keccak_inputs = (0..num_inputs)
|
||||
.map(|_| [0u64; INPUT_LIMBS].map(|_| rng.gen()))
|
||||
.map(|_| [0u64; NUM_INPUTS].map(|_| rng.gen()))
|
||||
.collect_vec();
|
||||
let keccak_trace = keccak_stark.generate_trace(keccak_inputs);
|
||||
let column_to_copy: Vec<_> = keccak_trace[keccak_looked_col].values[..].into();
|
||||
|
||||
@ -17,7 +17,7 @@ use crate::keccak::logic::{
|
||||
};
|
||||
use crate::keccak::registers::{
|
||||
reg_a, reg_a_prime, reg_a_prime_prime, reg_a_prime_prime_0_0_bit, reg_a_prime_prime_prime,
|
||||
reg_b, reg_c, reg_c_partial, reg_step, NUM_REGISTERS,
|
||||
reg_b, reg_c, reg_c_partial, reg_input_limb, reg_step, NUM_REGISTERS,
|
||||
};
|
||||
use crate::keccak::round_flags::{eval_round_flags, eval_round_flags_recursively};
|
||||
use crate::stark::Stark;
|
||||
@ -27,8 +27,8 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
/// Number of rounds in a Keccak permutation.
|
||||
pub(crate) const NUM_ROUNDS: usize = 24;
|
||||
|
||||
/// Number of 64-bit limbs in a preimage of the Keccak permutation.
|
||||
pub(crate) const INPUT_LIMBS: usize = 25;
|
||||
/// Number of 64-bit elements in the Keccak permutation input.
|
||||
pub(crate) const NUM_INPUTS: usize = 25;
|
||||
|
||||
pub(crate) const NUM_PUBLIC_INPUTS: usize = 0;
|
||||
|
||||
@ -42,7 +42,7 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakStark<F, D> {
|
||||
/// in our lookup arguments, as those are computed after transposing to column-wise form.
|
||||
pub(crate) fn generate_trace_rows(
|
||||
&self,
|
||||
inputs: Vec<[u64; INPUT_LIMBS]>,
|
||||
inputs: Vec<[u64; NUM_INPUTS]>,
|
||||
) -> Vec<[F; NUM_REGISTERS]> {
|
||||
let num_rows = (inputs.len() * NUM_ROUNDS).next_power_of_two();
|
||||
info!("{} rows", num_rows);
|
||||
@ -51,20 +51,18 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakStark<F, D> {
|
||||
rows.extend(self.generate_trace_rows_for_perm(*input));
|
||||
}
|
||||
|
||||
// Pad rows to power of two.
|
||||
for i in rows.len()..num_rows {
|
||||
let mut row = [F::ZERO; NUM_REGISTERS];
|
||||
self.copy_output_to_input(rows[i - 1], &mut row);
|
||||
self.generate_trace_row_for_round(&mut row, i % NUM_ROUNDS);
|
||||
rows.push(row);
|
||||
let pad_rows = self.generate_trace_rows_for_perm([0; NUM_INPUTS]);
|
||||
while rows.len() < num_rows {
|
||||
rows.extend(&pad_rows);
|
||||
}
|
||||
|
||||
rows.drain(num_rows..);
|
||||
rows
|
||||
}
|
||||
|
||||
fn generate_trace_rows_for_perm(&self, input: [u64; INPUT_LIMBS]) -> Vec<[F; NUM_REGISTERS]> {
|
||||
fn generate_trace_rows_for_perm(&self, input: [u64; NUM_INPUTS]) -> Vec<[F; NUM_REGISTERS]> {
|
||||
let mut rows = vec![[F::ZERO; NUM_REGISTERS]; NUM_ROUNDS];
|
||||
|
||||
self.copy_input(input, &mut rows[0]);
|
||||
for x in 0..5 {
|
||||
for y in 0..5 {
|
||||
let input_xy = input[x * 5 + y];
|
||||
@ -76,6 +74,7 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakStark<F, D> {
|
||||
|
||||
self.generate_trace_row_for_round(&mut rows[0], 0);
|
||||
for round in 1..24 {
|
||||
self.copy_input(input, &mut rows[round]);
|
||||
self.copy_output_to_input(rows[round - 1], &mut rows[round]);
|
||||
self.generate_trace_row_for_round(&mut rows[round], round);
|
||||
}
|
||||
@ -188,7 +187,15 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakStark<F, D> {
|
||||
row[out_reg_hi] = F::from_canonical_u64(row[in_reg_hi].to_canonical_u64() ^ rc_hi);
|
||||
}
|
||||
|
||||
pub fn generate_trace(&self, inputs: Vec<[u64; INPUT_LIMBS]>) -> Vec<PolynomialValues<F>> {
|
||||
fn copy_input(&self, input: [u64; NUM_INPUTS], row: &mut [F; NUM_REGISTERS]) {
|
||||
for i in 0..NUM_INPUTS {
|
||||
let (low, high) = (input[i] as u32, input[i] >> 32);
|
||||
row[reg_input_limb(2 * i)] = F::from_canonical_u32(low);
|
||||
row[reg_input_limb(2 * i + 1)] = F::from_canonical_u64(high);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_trace(&self, inputs: Vec<[u64; NUM_INPUTS]>) -> Vec<PolynomialValues<F>> {
|
||||
let mut timing = TimingTree::new("generate trace", log::Level::Debug);
|
||||
|
||||
// Generate the witness, except for permuted columns in the lookup argument.
|
||||
@ -223,6 +230,23 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for KeccakStark<F
|
||||
{
|
||||
eval_round_flags(vars, yield_constr);
|
||||
|
||||
for i in 0..2 * NUM_INPUTS {
|
||||
let local_input_limb = vars.local_values[reg_input_limb(i)];
|
||||
let next_input_limb = vars.next_values[reg_input_limb(i)];
|
||||
let is_last_round = vars.local_values[reg_step(NUM_ROUNDS - 1)];
|
||||
// Constrain the input registers to be equal throughout the rounds of a permutation.
|
||||
yield_constr.constraint_transition(
|
||||
(P::ONES - is_last_round) * (next_input_limb - local_input_limb),
|
||||
);
|
||||
|
||||
// Verify that the bit decomposition is done correctly.
|
||||
let range = if i % 2 == 0 { 0..32 } else { 32..64 };
|
||||
let bits = range.map(|j| vars.local_values[reg_a((i / 2) / 5, (i / 2) % 5, j)]);
|
||||
let expected_input_limb = bits.rev().fold(P::ZEROS, |acc, b| acc.doubles() + b);
|
||||
let is_first_round = vars.local_values[reg_step(0)];
|
||||
yield_constr.constraint(is_first_round * (local_input_limb - expected_input_limb));
|
||||
}
|
||||
|
||||
// C_partial[x] = xor(A[x, 0], A[x, 1], A[x, 2])
|
||||
for x in 0..5 {
|
||||
for z in 0..64 {
|
||||
@ -366,6 +390,25 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for KeccakStark<F
|
||||
|
||||
eval_round_flags_recursively(builder, vars, yield_constr);
|
||||
|
||||
for i in 0..2 * NUM_INPUTS {
|
||||
let local_input_limb = vars.local_values[reg_input_limb(i)];
|
||||
let next_input_limb = vars.next_values[reg_input_limb(i)];
|
||||
let is_last_round = vars.local_values[reg_step(NUM_ROUNDS - 1)];
|
||||
let diff = builder.sub_extension(local_input_limb, next_input_limb);
|
||||
let constraint = builder.mul_sub_extension(is_last_round, diff, diff);
|
||||
yield_constr.constraint_transition(builder, constraint);
|
||||
|
||||
let range = if i % 2 == 0 { 0..32 } else { 32..64 };
|
||||
let bits = range
|
||||
.map(|j| vars.local_values[reg_a((i / 2) / 5, (i / 2) % 5, j)])
|
||||
.collect::<Vec<_>>();
|
||||
let expected_input_limb = reduce_with_powers_ext_circuit(builder, &bits, two);
|
||||
let is_first_round = vars.local_values[reg_step(0)];
|
||||
let diff = builder.sub_extension(local_input_limb, expected_input_limb);
|
||||
let constraint = builder.mul_extension(is_first_round, diff);
|
||||
yield_constr.constraint(builder, constraint);
|
||||
}
|
||||
|
||||
// C_partial[x] = xor(A[x, 0], A[x, 1], A[x, 2])
|
||||
for x in 0..5 {
|
||||
for z in 0..64 {
|
||||
@ -520,8 +563,8 @@ mod tests {
|
||||
use plonky2::field::field_types::Field;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
use crate::keccak::keccak_stark::{KeccakStark, INPUT_LIMBS, NUM_ROUNDS};
|
||||
use crate::keccak::registers::reg_a_prime_prime_prime;
|
||||
use crate::keccak::keccak_stark::{KeccakStark, NUM_INPUTS, NUM_ROUNDS};
|
||||
use crate::keccak::registers::reg_output_limb;
|
||||
use crate::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree};
|
||||
|
||||
#[test]
|
||||
@ -552,7 +595,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn keccak_correctness_test() -> Result<()> {
|
||||
let input: [u64; INPUT_LIMBS] = rand::random();
|
||||
let input: [u64; NUM_INPUTS] = rand::random();
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
@ -565,16 +608,10 @@ mod tests {
|
||||
|
||||
let rows = stark.generate_trace_rows(vec![input.try_into().unwrap()]);
|
||||
let last_row = rows[NUM_ROUNDS - 1];
|
||||
let mut output = Vec::new();
|
||||
let base = F::from_canonical_u64(1 << 32);
|
||||
for x in 0..5 {
|
||||
for y in 0..5 {
|
||||
output.push(
|
||||
last_row[reg_a_prime_prime_prime(x, y)]
|
||||
+ base * last_row[reg_a_prime_prime_prime(x, y) + 1],
|
||||
);
|
||||
}
|
||||
}
|
||||
let output = (0..NUM_INPUTS)
|
||||
.map(|i| last_row[reg_output_limb(2 * i)] + base * last_row[reg_output_limb(2 * i + 1)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut keccak_input: [[u64; 5]; 5] = [
|
||||
input[0..5].try_into().unwrap(),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::keccak::keccak_stark::NUM_ROUNDS;
|
||||
use crate::keccak::keccak_stark::{NUM_INPUTS, NUM_ROUNDS};
|
||||
|
||||
/// A register which is set to 1 if we are in the `i`th round, otherwise 0.
|
||||
pub(crate) const fn reg_step(i: usize) -> usize {
|
||||
@ -6,6 +6,30 @@ pub(crate) const fn reg_step(i: usize) -> usize {
|
||||
i
|
||||
}
|
||||
|
||||
/// Registers to hold permutation inputs.
|
||||
/// `reg_input_limb(2*i) -> input[i] as u32`
|
||||
/// `reg_input_limb(2*i+1) -> input[i] >> 32`
|
||||
pub(crate) const fn reg_input_limb(i: usize) -> usize {
|
||||
debug_assert!(i < 2 * NUM_INPUTS);
|
||||
NUM_ROUNDS + i
|
||||
}
|
||||
|
||||
/// Registers to hold permutation outputs.
|
||||
/// `reg_output_limb(2*i) -> output[i] as u32`
|
||||
/// `reg_output_limb(2*i+1) -> output[i] >> 32`
|
||||
#[allow(dead_code)] // TODO: Remove once it is used.
|
||||
pub(crate) const fn reg_output_limb(i: usize) -> usize {
|
||||
debug_assert!(i < 2 * NUM_INPUTS);
|
||||
let ii = i / 2;
|
||||
let x = ii / 5;
|
||||
let y = ii % 5;
|
||||
if i % 2 == 0 {
|
||||
reg_a_prime_prime_prime(x, y)
|
||||
} else {
|
||||
reg_a_prime_prime_prime(x, y) + 1
|
||||
}
|
||||
}
|
||||
|
||||
const R: [[u8; 5]; 5] = [
|
||||
[0, 36, 3, 41, 18],
|
||||
[1, 44, 10, 45, 2],
|
||||
@ -14,7 +38,7 @@ const R: [[u8; 5]; 5] = [
|
||||
[27, 20, 39, 8, 14],
|
||||
];
|
||||
|
||||
const START_A: usize = NUM_ROUNDS;
|
||||
const START_A: usize = NUM_ROUNDS + 2 * NUM_INPUTS;
|
||||
pub(crate) const fn reg_a(x: usize, y: usize, z: usize) -> usize {
|
||||
debug_assert!(x < 5);
|
||||
debug_assert!(y < 5);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user