From b643edcc4b81ed78374d5cd53a8eabce61ad7461 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 15:56:20 +0100 Subject: [PATCH 1/9] optimizing 244 columns, and reducing by ~300 constraints the KeccakRound --- .../polynomials/keccak/circuitgates.rs | 93 ++++++++----------- kimchi/src/tests/keccak.rs | 81 ++++++---------- 2 files changed, 70 insertions(+), 104 deletions(-) diff --git a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs index cd33263c67..04a18cb426 100644 --- a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs @@ -51,7 +51,7 @@ macro_rules! from_shifts { } //~ -//~ | `KeccakRound` | [0...440) | [440...1540) | [1540...2344) | +//~ | `KeccakRound` | [0...300) | [300...1300) | [1300...2100) | //~ | ------------- | --------- | ------------ | ------------- | //~ | Curr | theta | pirho | chi | //~ @@ -61,17 +61,17 @@ macro_rules! from_shifts { //~ //~ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- //~ -//~ | Columns | [0...100) | [100...120) | [120...200) | [200...220) | [220...240) | [240...260) | [260...280) | [280...300) | [300...320) | [320...340) | [340...440) | -//~ | -------- | --------- | ----------- | ----------- | ----------- | ----------- | ------------ | ----------- | ------------ | ------------ | ----------- | ----------- | -//~ | theta | state_a | state_c | shifts_c | dense_c | quotient_c | remainder_c | bound_c | dense_rot_c | expand_rot_c | state_d | state_e | +//~ | Columns | [0...100) | [100...180) | [180...200) | [200...220) | [220...240) | [240...260) | [260...280) | [280...300) | +//~ | -------- | --------- | ----------- | ----------- | ----------- | ------------ | ----------- | ------------ | ------------ | +//~ | theta | state_a | shifts_c | dense_c | quotient_c | remainder_c | bound_c | dense_rot_c | expand_rot_c | //~ -//~ | Columns | [440...840) | [840...940) | [940...1040) | [1040...1140) | [1140...1240) | [1240...1340) | [1340...1440) | [1440...1540) | -//~ | -------- | ----------- | ----------- | ------------ | ------------- | ------------- | ------------- | ------------- | ------------- | -//~ | pirho | shifts_e | dense_e | quotient_e | remainder_e | bound_e | dense_rot_e | expand_rot_e | state_b | +//~ | Columns | [300...700) | [700...800) | [800...900) | [900...1000) | [1000...1100) | [1100...1200) | [1200...1300) | +//~ | -------- | ----------- | ----------- | ------------ | ----------- | ------------- | ------------- | ------------- | +//~ | pirho | shifts_e | dense_e | quotient_e | remainder_e | bound_e | dense_rot_e | expand_rot_e | //~ -//~ | Columns | [1540...1940) | [1940...2340) | [2340...2344 | -//~ | -------- | ------------- | ------------- | ------------ | -//~ | chi | shifts_b | shifts_sum | f00 | +//~ | Columns | [1300...1700) | [1700...2100) | +//~ | -------- | ------------- | ------------- | +//~ | chi | shifts_b | shifts_sum | //~ //~ | Columns | [0...4) | [4...100) | //~ | -------- | ------- | --------- | @@ -85,13 +85,10 @@ where F: PrimeField, { const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::KeccakRound); - const CONSTRAINTS: u32 = 754; + const CONSTRAINTS: u32 = 414; // Constraints for one round of the Keccak permutation function - fn constraint_checks, const COLUMNS: usize>( - env: &ArgumentEnv, - _cache: &mut Cache, - ) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { let mut constraints = vec![]; // DEFINE ROUND CONSTANT @@ -100,7 +97,6 @@ where // LOAD STATES FROM WITNESS LAYOUT // THETA let state_a = grid!(100, env.witness_curr_chunk(0, 100)); - let state_c = grid!(20, env.witness_curr_chunk(100, 120)); let shifts_c = grid!(80, env.witness_curr_chunk(120, 200)); let dense_c = grid!(20, env.witness_curr_chunk(200, 220)); let quotient_c = grid!(20, env.witness_curr_chunk(220, 240)); @@ -108,8 +104,6 @@ where let bound_c = grid!(20, env.witness_curr_chunk(260, 280)); let dense_rot_c = grid!(20, env.witness_curr_chunk(280, 300)); let expand_rot_c = grid!(20, env.witness_curr_chunk(300, 320)); - let state_d = grid!(20, env.witness_curr_chunk(320, 340)); - let state_e = grid!(100, env.witness_curr_chunk(340, 440)); // PI-RHO let shifts_e = grid!(400, env.witness_curr_chunk(440, 840)); let dense_e = grid!(100, env.witness_curr_chunk(840, 940)); @@ -118,21 +112,20 @@ where let bound_e = grid!(100, env.witness_curr_chunk(1140, 1240)); let dense_rot_e = grid!(100, env.witness_curr_chunk(1240, 1340)); let expand_rot_e = grid!(100, env.witness_curr_chunk(1340, 1440)); - let state_b = grid!(100, env.witness_curr_chunk(1440, 1540)); // CHI let shifts_b = grid!(400, env.witness_curr_chunk(1540, 1940)); let shifts_sum = grid!(400, env.witness_curr_chunk(1940, 2340)); - let mut state_f: Vec = env.witness_curr_chunk(2340, 2344); - let mut tail = env.witness_next_chunk(4, 100); - state_f.append(&mut tail); - let state_f = grid!(100, state_f); // IOTA - let mut state_g = env.witness_next_chunk(0, 4); - let mut tail = env.witness_next_chunk(4, 100); - state_g.append(&mut tail); - let state_g = grid!(100, state_g); + let state_g = grid!(100, env.witness_next_chunk(0, 100)); - // STEP theta: 5 * ( 3 + 4 * (3 + 5 * 1) ) = 175 constraints + // Define vectors containing witness expressions which are not in the layout for efficiency + let mut state_c: Vec> = vec![vec![T::zero(); QUARTERS]; DIM]; + let mut state_d: Vec> = vec![vec![T::zero(); QUARTERS]; DIM]; + let mut state_e: Vec>> = vec![vec![vec![T::zero(); QUARTERS]; DIM]; DIM]; + let mut state_b: Vec>> = vec![vec![vec![T::zero(); QUARTERS]; DIM]; DIM]; + let mut state_f: Vec>> = vec![vec![vec![T::zero(); QUARTERS]; DIM]; DIM]; + + // STEP theta: 5 * ( 3 + 4 * 1 ) = 35 constraints for x in 0..DIM { let word_c = from_quarters!(dense_c, x); let quo_c = from_quarters!(quotient_c, x); @@ -145,27 +138,23 @@ where constraints.push(bnd_c - (quo_c + T::two_pow(64) - T::two_pow(1))); for q in 0..QUARTERS { - constraints.push( - state_c(x, q) - - (state_a(0, x, q) - + state_a(1, x, q) - + state_a(2, x, q) - + state_a(3, x, q) - + state_a(4, x, q)), - ); - constraints.push(state_c(x, q) - from_shifts!(shifts_c, x, q)); - constraints.push( - state_d(x, q) - - (shifts_c(0, (x + DIM - 1) % DIM, q) + expand_rot_c((x + 1) % DIM, q)), - ); + state_c[x][q] = state_a(0, x, q) + + state_a(1, x, q) + + state_a(2, x, q) + + state_a(3, x, q) + + state_a(4, x, q); + constraints.push(state_c[x][q].clone() - from_shifts!(shifts_c, x, q)); + + state_d[x][q] = + shifts_c(0, (x + DIM - 1) % DIM, q) + expand_rot_c((x + 1) % DIM, q); for y in 0..DIM { - constraints.push(state_e(y, x, q) - (state_a(y, x, q) + state_d(x, q))); + state_e[y][x][q] = state_a(y, x, q) + state_d[x][q].clone(); } } } // END theta - // STEP pirho: 5 * 5 * (3 + 4 * 2) = 275 constraints + // STEP pirho: 5 * 5 * (3 + 4 * 1) = 175 constraints for (y, col) in OFF.iter().enumerate() { for (x, off) in col.iter().enumerate() { let word_e = from_quarters!(dense_e, y, x); @@ -181,13 +170,13 @@ where constraints.push(bnd_e - (quo_e + T::two_pow(64) - T::two_pow(*off))); for q in 0..QUARTERS { - constraints.push(state_e(y, x, q) - from_shifts!(shifts_e, y, x, q)); - constraints.push(state_b((2 * x + 3 * y) % DIM, y, q) - expand_rot_e(y, x, q)); + constraints.push(state_e[y][x][q].clone() - from_shifts!(shifts_e, y, x, q)); + state_b[(2 * x + 3 * y) % DIM][y][q] = expand_rot_e(y, x, q); } } } // END pirho - // STEP chi: 4 * 5 * 5 * 3 = 300 constraints + // STEP chi: 4 * 5 * 5 * 2 = 200 constraints for q in 0..QUARTERS { for x in 0..DIM { for y in 0..DIM { @@ -195,16 +184,17 @@ where - shifts_b(0, y, (x + 1) % DIM, q); let sum = not + shifts_b(0, y, (x + 2) % DIM, q); let and = shifts_sum(1, y, x, q); - constraints.push(state_b(y, x, q) - from_shifts!(shifts_b, y, x, q)); + + constraints.push(state_b[y][x][q].clone() - from_shifts!(shifts_b, y, x, q)); constraints.push(sum - from_shifts!(shifts_sum, y, x, q)); - constraints.push(state_f(y, x, q) - (shifts_b(0, y, x, q) + and)); + state_f[y][x][q] = shifts_b(0, y, x, q) + and; } } } // END chi // STEP iota: 4 constraints for (q, c) in rc.iter().enumerate() { - constraints.push(state_g(0, 0, q) - (state_f(0, 0, q) + c.clone())); + constraints.push(state_g(0, 0, q) - (state_f[0][0][q].clone() + c.clone())); } // END iota constraints @@ -228,10 +218,7 @@ where const CONSTRAINTS: u32 = 568; // Constraints for one round of the Keccak permutation function - fn constraint_checks, const COLUMNS: usize>( - env: &ArgumentEnv, - _cache: &mut Cache, - ) -> Vec { + fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { let mut constraints = vec![]; // LOAD WITNESS diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index 9f921c583f..e51674c589 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -105,21 +105,6 @@ fn print_witness(witness: &[Vec; KECCAK_COLS], round: usize) { println!("ROUND {}", round); println!("State A:"); print_matrix(&row[0..100]); - println!("State C:"); - print_line(&row[100..120]); - println!("State D:"); - print_line(&row[320..340]); - println!("State E:"); - print_matrix(&row[340..440]); - println!("State B:"); - print_matrix(&row[1440..1540]); - - let mut state_f = row[2340..2344].to_vec(); - let mut tail = next[4..100].to_vec(); - state_f.append(&mut tail); - - println!("State F:"); - print_matrix(&state_f); println!("State G:"); print_matrix(&next[0..100]); } @@ -137,7 +122,7 @@ fn test_keccak_n( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let messages = vec![rng.gen_biguint_below(&BigUint::from(2u32).pow(1080)); n]; @@ -160,15 +145,17 @@ where } } - let runner: TestRunner = TestFramework::::default() + let runner: TestRunner<2344, G> = TestFramework::::default() .gates(gates.clone()) .setup(); let cs = runner.clone().prover_index().cs.clone(); // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); - result?; + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + if result.is_err() { + return result; + } } assert_eq!( runner @@ -189,12 +176,11 @@ fn test_keccak( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let bytelength = message.to_bytes_be().len(); - let padded_len = padded_length(bytelength); - let gates = create_test_gates::(padded_len); + let gates = create_test_gates::(bytelength); let witness: [Vec<<::Projective as ProjectiveCurve>::ScalarField>; KECCAK_COLS] = create_keccak_witness::(message); @@ -217,7 +203,7 @@ where let runner = if full { // Create prover index with test framework Some( - TestFramework::::default() + TestFramework::::default() .gates(gates.clone()) .setup(), ) @@ -234,7 +220,7 @@ where // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, hash); } @@ -321,19 +307,15 @@ fn test_bitwise_sparse_representation() { #[test] // Test hash of message zero with 1 byte fn test_dummy() { - stacker::grow(30 * 1024 * 1024, || { - // guaranteed to have at least 30MB of stack - - let (_, claim1) = test_keccak::( - BigUint::from_bytes_be(&[0x00]), - true, - ); - let hash1 = - BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); - assert_eq!(claim1, hash1); - }); + let (_, claim1) = test_keccak::( + BigUint::from_bytes_be(&[0x00]), + true, + ); + let hash1 = + BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); + assert_eq!(claim1, hash1); } - +/* #[test] // Tests a random block of 1080 bits fn test_random_block() { @@ -348,24 +330,21 @@ fn test_random_block() { #[test] // Test hash of message zero with 1 byte fn test_blocks() { - stacker::grow(30 * 1024 * 1024, || { - let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); - let hash_3blocks = - BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); - assert_eq!(claim_3blocks, hash_3blocks); - }); + let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); + let hash_3blocks = + BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); + assert_eq!(claim_3blocks, hash_3blocks); } #[test] // Test hash of message zero with 1 byte fn test_1000_hashes() { - stacker::grow(30 * 1024 * 1024, || { - assert_eq!( - Ok(()), - test_keccak_n::( - 1000, - &mut StdRng::from_seed(RNG_SEED), - ) - ); - }); + assert_eq!( + Ok(()), + test_keccak_n::( + 1000, + &mut StdRng::from_seed(RNG_SEED), + ) + ); } +*/ From 299d675a1b80f190ccfb9ee58edcf7f8fb3c7e3e Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 15:58:38 +0100 Subject: [PATCH 2/9] optimize 1bit rotation witness layout --- .../polynomials/keccak/circuitgates.rs | 57 ++++++++++--------- kimchi/src/circuits/polynomials/keccak/mod.rs | 3 + kimchi/src/tests/keccak.rs | 12 +--- 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs index 04a18cb426..c3d1bbfefa 100644 --- a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs @@ -4,7 +4,10 @@ use crate::{ auto_clone, auto_clone_array, circuits::{ argument::{Argument, ArgumentEnv, ArgumentType}, - expr::{constraints::ExprOps, Cache}, + expr::{ + constraints::{boolean, ExprOps}, + Cache, + }, gate::GateType, }, grid, @@ -51,7 +54,7 @@ macro_rules! from_shifts { } //~ -//~ | `KeccakRound` | [0...300) | [300...1300) | [1300...2100) | +//~ | `KeccakRound` | [0...265) | [265...1265) | [1265...2065) | //~ | ------------- | --------- | ------------ | ------------- | //~ | Curr | theta | pirho | chi | //~ @@ -61,15 +64,15 @@ macro_rules! from_shifts { //~ //~ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- //~ -//~ | Columns | [0...100) | [100...180) | [180...200) | [200...220) | [220...240) | [240...260) | [260...280) | [280...300) | -//~ | -------- | --------- | ----------- | ----------- | ----------- | ------------ | ----------- | ------------ | ------------ | -//~ | theta | state_a | shifts_c | dense_c | quotient_c | remainder_c | bound_c | dense_rot_c | expand_rot_c | +//~ | Columns | [0...100) | [100...180) | [180...200) | [200...205) | [205...225) | [225...245) | [245...265) | +//~ | -------- | --------- | ----------- | ----------- | ----------- | ------------ | ------------ | ------------ | +//~ | theta | state_a | shifts_c | dense_c | quotient_c | remainder_c | dense_rot_c | expand_rot_c | //~ -//~ | Columns | [300...700) | [700...800) | [800...900) | [900...1000) | [1000...1100) | [1100...1200) | [1200...1300) | +//~ | Columns | [265...665) | [665...765) | [765...865) | [865...965) | [965...1065) | [1065...1165) | [1165...1265) | //~ | -------- | ----------- | ----------- | ------------ | ----------- | ------------- | ------------- | ------------- | //~ | pirho | shifts_e | dense_e | quotient_e | remainder_e | bound_e | dense_rot_e | expand_rot_e | //~ -//~ | Columns | [1300...1700) | [1700...2100) | +//~ | Columns | [1265...1665) | [1665...2065) | //~ | -------- | ------------- | ------------- | //~ | chi | shifts_b | shifts_sum | //~ @@ -97,24 +100,23 @@ where // LOAD STATES FROM WITNESS LAYOUT // THETA let state_a = grid!(100, env.witness_curr_chunk(0, 100)); - let shifts_c = grid!(80, env.witness_curr_chunk(120, 200)); - let dense_c = grid!(20, env.witness_curr_chunk(200, 220)); - let quotient_c = grid!(20, env.witness_curr_chunk(220, 240)); - let remainder_c = grid!(20, env.witness_curr_chunk(240, 260)); - let bound_c = grid!(20, env.witness_curr_chunk(260, 280)); - let dense_rot_c = grid!(20, env.witness_curr_chunk(280, 300)); - let expand_rot_c = grid!(20, env.witness_curr_chunk(300, 320)); + let shifts_c = grid!(80, env.witness_curr_chunk(100, 180)); + let dense_c = grid!(20, env.witness_curr_chunk(180, 200)); + let quotient_c = grid!(5, env.witness_curr_chunk(200, 205)); + let remainder_c = grid!(20, env.witness_curr_chunk(205, 225)); + let dense_rot_c = grid!(20, env.witness_curr_chunk(225, 245)); + let expand_rot_c = grid!(20, env.witness_curr_chunk(245, 265)); // PI-RHO - let shifts_e = grid!(400, env.witness_curr_chunk(440, 840)); - let dense_e = grid!(100, env.witness_curr_chunk(840, 940)); - let quotient_e = grid!(100, env.witness_curr_chunk(940, 1040)); - let remainder_e = grid!(100, env.witness_curr_chunk(1040, 1140)); - let bound_e = grid!(100, env.witness_curr_chunk(1140, 1240)); - let dense_rot_e = grid!(100, env.witness_curr_chunk(1240, 1340)); - let expand_rot_e = grid!(100, env.witness_curr_chunk(1340, 1440)); + let shifts_e = grid!(400, env.witness_curr_chunk(265, 665)); + let dense_e = grid!(100, env.witness_curr_chunk(665, 765)); + let quotient_e = grid!(100, env.witness_curr_chunk(765, 865)); + let remainder_e = grid!(100, env.witness_curr_chunk(865, 965)); + let bound_e = grid!(100, env.witness_curr_chunk(965, 1065)); + let dense_rot_e = grid!(100, env.witness_curr_chunk(1065, 1165)); + let expand_rot_e = grid!(100, env.witness_curr_chunk(1165, 1265)); // CHI - let shifts_b = grid!(400, env.witness_curr_chunk(1540, 1940)); - let shifts_sum = grid!(400, env.witness_curr_chunk(1940, 2340)); + let shifts_b = grid!(400, env.witness_curr_chunk(1265, 1665)); + let shifts_sum = grid!(400, env.witness_curr_chunk(1665, 2065)); // IOTA let state_g = grid!(100, env.witness_next_chunk(0, 100)); @@ -128,14 +130,13 @@ where // STEP theta: 5 * ( 3 + 4 * 1 ) = 35 constraints for x in 0..DIM { let word_c = from_quarters!(dense_c, x); - let quo_c = from_quarters!(quotient_c, x); let rem_c = from_quarters!(remainder_c, x); - let bnd_c = from_quarters!(bound_c, x); let rot_c = from_quarters!(dense_rot_c, x); + constraints - .push(word_c * T::two_pow(1) - (quo_c.clone() * T::two_pow(64) + rem_c.clone())); - constraints.push(rot_c - (quo_c.clone() + rem_c)); - constraints.push(bnd_c - (quo_c + T::two_pow(64) - T::two_pow(1))); + .push(word_c * T::two_pow(1) - (quotient_c(x) * T::two_pow(64) + rem_c.clone())); + constraints.push(rot_c - (quotient_c(x) + rem_c)); + constraints.push(boolean("ient_c(x))); for q in 0..QUARTERS { state_c[x][q] = state_a(0, x, q) diff --git a/kimchi/src/circuits/polynomials/keccak/mod.rs b/kimchi/src/circuits/polynomials/keccak/mod.rs index 3cd8bcdf30..970346e099 100644 --- a/kimchi/src/circuits/polynomials/keccak/mod.rs +++ b/kimchi/src/circuits/polynomials/keccak/mod.rs @@ -15,6 +15,9 @@ use ark_ff::PrimeField; #[macro_export] macro_rules! grid { + (5, $v:expr) => {{ + |x: usize| $v[x].clone() + }}; (20, $v:expr) => {{ |x: usize, q: usize| $v[q + QUARTERS * x].clone() }}; diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index e51674c589..06805b91a7 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -71,15 +71,6 @@ fn print_witness(witness: &[Vec; KECCAK_COLS], round: usize) { bytes.reverse(); bytes.iter().fold(0, |acc: u64, x| (acc << 8) + *x as u64) } - fn print_line(state: &[u64]) { - print!(" "); - for x in 0..5 { - let quarters = &state[4 * x..4 * (x + 1)]; - let word = compose(&collapse(&reset(&shift(quarters)))); - print!("{:016x} ", word); - } - println!(); - } fn print_matrix(state: &[u64]) { for x in 0..5 { print!(" "); @@ -315,7 +306,7 @@ fn test_dummy() { BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); assert_eq!(claim1, hash1); } -/* + #[test] // Tests a random block of 1080 bits fn test_random_block() { @@ -347,4 +338,3 @@ fn test_1000_hashes() { ) ); } -*/ From 02c0127530a762074db308da25380e09f4fef3b7 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 15:59:35 +0100 Subject: [PATCH 3/9] update witness code to ~300 less columns --- .../circuits/polynomials/keccak/witness.rs | 71 +++++++------------ 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/kimchi/src/circuits/polynomials/keccak/witness.rs b/kimchi/src/circuits/polynomials/keccak/witness.rs index a22713039f..71b8a0ca72 100644 --- a/kimchi/src/circuits/polynomials/keccak/witness.rs +++ b/kimchi/src/circuits/polynomials/keccak/witness.rs @@ -19,36 +19,30 @@ use super::{ RATE, }; -type Layout = Vec, COLUMNS>>>; +type Layout = Vec>>>; -fn layout_round() -> [Layout; 1] { +fn layout_round() -> [Layout; 1] { [vec![ IndexCell::create("state_a", 0, 100), - IndexCell::create("state_c", 100, 120), - IndexCell::create("shifts_c", 120, 200), - IndexCell::create("dense_c", 200, 220), - IndexCell::create("quotient_c", 220, 240), - IndexCell::create("remainder_c", 240, 260), - IndexCell::create("bound_c", 260, 280), - IndexCell::create("dense_rot_c", 280, 300), - IndexCell::create("expand_rot_c", 300, 320), - IndexCell::create("state_d", 320, 340), - IndexCell::create("state_e", 340, 440), - IndexCell::create("shifts_e", 440, 840), - IndexCell::create("dense_e", 840, 940), - IndexCell::create("quotient_e", 940, 1040), - IndexCell::create("remainder_e", 1040, 1140), - IndexCell::create("bound_e", 1140, 1240), - IndexCell::create("dense_rot_e", 1240, 1340), - IndexCell::create("expand_rot_e", 1340, 1440), - IndexCell::create("state_b", 1440, 1540), - IndexCell::create("shifts_b", 1540, 1940), - IndexCell::create("shifts_sum", 1940, 2340), - IndexCell::create("f00", 2340, 2344), + IndexCell::create("shifts_c", 100, 180), + IndexCell::create("dense_c", 180, 200), + IndexCell::create("quotient_c", 200, 205), + IndexCell::create("remainder_c", 205, 225), + IndexCell::create("dense_rot_c", 225, 245), + IndexCell::create("expand_rot_c", 245, 265), + IndexCell::create("shifts_e", 265, 665), + IndexCell::create("dense_e", 665, 765), + IndexCell::create("quotient_e", 765, 865), + IndexCell::create("remainder_e", 865, 965), + IndexCell::create("bound_e", 965, 1065), + IndexCell::create("dense_rot_e", 1065, 1165), + IndexCell::create("expand_rot_e", 1165, 1265), + IndexCell::create("shifts_b", 1265, 1665), + IndexCell::create("shifts_sum", 1665, 2065), ]] } -fn layout_sponge() -> [Layout; 1] { +fn layout_sponge() -> [Layout; 1] { [vec![ IndexCell::create("old_state", 0, 100), IndexCell::create("new_state", 100, 200), @@ -132,15 +126,12 @@ impl Rotation { } struct Theta { - state_c: Vec, shifts_c: Vec, dense_c: Vec, quotient_c: Vec, remainder_c: Vec, - bound_c: Vec, dense_rot_c: Vec, expand_rot_c: Vec, - state_d: Vec, state_e: Vec, } @@ -152,16 +143,20 @@ impl Theta { let rotation_c = Rotation::many(&dense_c, &[1; DIM]); let state_d = Self::compute_state_d(&shifts_c, &rotation_c.expand_rot); let state_e = Self::compute_state_e(state_a, &state_d); + let quotient_c = vec![ + rotation_c.quotient[0], + rotation_c.quotient[4], + rotation_c.quotient[8], + rotation_c.quotient[12], + rotation_c.quotient[16], + ]; Self { - state_c, shifts_c, dense_c, - quotient_c: rotation_c.quotient, + quotient_c, remainder_c: rotation_c.remainder, - bound_c: rotation_c.bound, dense_rot_c: rotation_c.dense_rot, expand_rot_c: rotation_c.expand_rot, - state_d, state_e, } } @@ -373,12 +368,6 @@ pub fn extend_keccak_witness(witness: &mut [Vec; KECCAK_COLS], // Chi let chi = Chi::create(&pirho.state_b); - let f00 = chi - .state_f - .clone() - .into_iter() - .take(QUARTERS) - .collect::>(); // Iota let iota = Iota::create(chi.state_f, round); @@ -390,16 +379,12 @@ pub fn extend_keccak_witness(witness: &mut [Vec; KECCAK_COLS], &layout_round(), &variable_map![ "state_a" => field(&ini_state), - "state_c" => field(&theta.state_c), "shifts_c" => field(&theta.shifts_c), "dense_c" => field(&theta.dense_c), "quotient_c" => field(&theta.quotient_c), "remainder_c" => field(&theta.remainder_c), - "bound_c" => field(&theta.bound_c), "dense_rot_c" => field(&theta.dense_rot_c), "expand_rot_c" => field(&theta.expand_rot_c), - "state_d" => field(&theta.state_d), - "state_e" => field(&theta.state_e), "shifts_e" => field(&pirho.shifts_e), "dense_e" => field(&pirho.dense_e), "quotient_e" => field(&pirho.quotient_e), @@ -407,10 +392,8 @@ pub fn extend_keccak_witness(witness: &mut [Vec; KECCAK_COLS], "bound_e" => field(&pirho.bound_e), "dense_rot_e" => field(&pirho.dense_rot_e), "expand_rot_e" => field(&pirho.expand_rot_e), - "state_b" => field(&pirho.state_b), "shifts_b" => field(&chi.shifts_b), - "shifts_sum" => field(&chi.shifts_sum), - "f00" => field(&f00) + "shifts_sum" => field(&chi.shifts_sum) ], ); row += 1; From af29b1ad343bd5eea7c0738c197f207bf7c614bd Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 16:00:08 +0100 Subject: [PATCH 4/9] update keccak round pattern columns --- kimchi/src/circuits/lookup/lookups.rs | 121 ++++++-------------------- 1 file changed, 26 insertions(+), 95 deletions(-) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index d8694c19d4..2f0f821da0 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -4,7 +4,7 @@ use crate::circuits::{ lookup::index::LookupSelectors, lookup::tables::{ combine_table_entry, get_table, GateLookupTable, LookupTable, RANGE_CHECK_TABLE_ID, - XOR_TABLE_ID, + SPARSE_TABLE_ID, XOR_TABLE_ID, }, }; use ark_ff::{Field, One, PrimeField, Zero}; @@ -15,6 +15,8 @@ use std::collections::HashSet; use std::ops::{Mul, Neg}; use strum_macros::EnumIter; +use super::tables::{BITS16_TABLE_ID, RESET_TABLE_ID}; + type Evaluations = E>; //~ Lookups patterns are extremely flexible and can be configured in a number of ways. @@ -42,7 +44,6 @@ fn max_lookups_per_row(kinds: LookupPatterns) -> usize { feature = "ocaml_types", derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct) )] -#[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupPatterns { pub xor: bool, pub lookup: bool, @@ -148,7 +149,6 @@ impl LookupPatterns { feature = "ocaml_types", derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct) )] -#[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupFeatures { /// A single lookup constraint is a vector of lookup constraints to be applied at a row. pub patterns: LookupPatterns, @@ -174,7 +174,6 @@ impl LookupFeatures { /// Describes the desired lookup configuration. #[derive(Copy, Clone, Serialize, Deserialize, Debug)] -#[cfg_attr(feature = "wasm_types", wasm_bindgen::prelude::wasm_bindgen)] pub struct LookupInfo { /// The maximum length of an element of `kinds`. This can be computed from `kinds`. pub max_per_row: usize, @@ -214,7 +213,7 @@ impl LookupInfo { /// Each entry in `kinds` has a corresponding selector polynomial that controls whether that /// lookup kind should be enforced at a given row. This computes those selector polynomials. - pub fn selector_polynomials_and_tables( + pub fn selector_polynomials_and_tables( &self, domain: &EvaluationDomains, gates: &[CircuitGate], @@ -415,7 +414,7 @@ impl LookupPattern { /// Returns the maximum number of lookups per row that are used by the pattern. pub fn max_lookups_per_row(&self) -> usize { match self { - //LookupPattern::KeccakRound => 1760, + //LookupPattern::KeccakRound => 1720, //LookupPattern::KeccakSponge => 800, LookupPattern::Xor | LookupPattern::RangeCheck | LookupPattern::ForeignFieldMul => 4, LookupPattern::Lookup => 3, @@ -523,23 +522,23 @@ impl LookupPattern { // Theta for i in 0..20 { // 2-column lookups - let shift0_c = curr_row(120 + i); - let dense_c = curr_row(200 + i); + let shift0_c = curr_row(100 + i); + let dense_c = curr_row(180 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(RESET_TABLE_ID), entry: vec![l(dense_c), l(shift0_c)], }); - let dense_rot_c = curr_row(280 + i); - let expand_rot_c = curr_row(300 + i); + let dense_rot_c = curr_row(225 + i); + let expand_rot_c = curr_row(245 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(RESET_TABLE_ID), entry: vec![l(dense_rot_c), l(expand_rot_c)], }); // Second column lookups - let shift1_c = curr_row(140 + i); - let shift2_c = curr_row(160 + i); - let shift3_c = curr_row(180 + i); + let shift1_c = curr_row(120 + i); + let shift2_c = curr_row(140 + i); + let shift3_c = curr_row(160 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(SPARSE_TABLE_ID), @@ -555,43 +554,34 @@ impl LookupPattern { }); // First column lookups - let quotient_c = curr_row(220 + i); - let remainder_c = curr_row(240 + i); - let bound_c = curr_row(260 + i); + let remainder_c = curr_row(205 + i); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(quotient_c)], - }); lookups.push(JointLookup { table_id: LookupTableID::Constant(BITS16_TABLE_ID), entry: vec![l(remainder_c)], }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(bound_c)], - }); + } // PiRho for i in 0..100 { // 2-column lookups - let shift0_e = curr_row(440 + i); - let dense_e = curr_row(840 + i); + let shift0_e = curr_row(265 + i); + let dense_e = curr_row(665 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(RESET_TABLE_ID), entry: vec![l(dense_e), l(shift0_e)], }); - let dense_rot_e = curr_row(1240 + i); - let expand_rot_e = curr_row(1340 + i); + let dense_rot_e = curr_row(1065 + i); + let expand_rot_e = curr_row(1165 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(SPARSE_TABLE_ID), entry: vec![l(dense_rot_e), l(expand_rot_e)], }); // Second column lookups - let shift1_e = curr_row(540 + i); - let shift2_e = curr_row(640 + i); - let shift3_e = curr_row(740 + i); + let shift1_e = curr_row(365 + i); + let shift2_e = curr_row(465 + i); + let shift3_e = curr_row(565 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(SPARSE_TABLE_ID), @@ -607,9 +597,9 @@ impl LookupPattern { }); // First column lookups - let quotient_e = curr_row(940 + i); - let remainder_e = curr_row(1040 + i); - let bound_e = curr_row(1140 + i); + let quotient_e = curr_row(765 + i); + let remainder_e = curr_row(865 + i); + let bound_e = curr_row(965 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(BITS16_TABLE_ID), @@ -627,8 +617,8 @@ impl LookupPattern { // Chi for i in 0..400 { // Second column lookups - let shift_b: LocalPosition = curr_row(1540 + i); - let shift_sum = curr_row(1940 + i); + let shift_b: LocalPosition = curr_row(1265 + i); + let shift_sum = curr_row(1665 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(SPARSE_TABLE_ID), @@ -767,62 +757,3 @@ fn lookup_pattern_constants_correct() { assert_eq!((pat, pat.max_joint_size()), (pat, max_joint_size as u32)); } } - -#[cfg(feature = "wasm_types")] -pub mod wasm { - use super::*; - - #[wasm_bindgen::prelude::wasm_bindgen] - impl LookupPatterns { - #[wasm_bindgen::prelude::wasm_bindgen(constructor)] - pub fn new( - xor: bool, - lookup: bool, - range_check: bool, - foreign_field_mul: bool, - keccak_round: bool, - keccak_sponge: bool, - ) -> LookupPatterns { - LookupPatterns { - xor, - lookup, - range_check, - foreign_field_mul, - keccak_round, - keccak_sponge, - } - } - } - - #[wasm_bindgen::prelude::wasm_bindgen] - impl LookupFeatures { - #[wasm_bindgen::prelude::wasm_bindgen(constructor)] - pub fn new( - patterns: LookupPatterns, - joint_lookup_used: bool, - uses_runtime_tables: bool, - ) -> LookupFeatures { - LookupFeatures { - patterns, - joint_lookup_used, - uses_runtime_tables, - } - } - } - - #[wasm_bindgen::prelude::wasm_bindgen] - impl LookupInfo { - #[wasm_bindgen::prelude::wasm_bindgen(constructor)] - pub fn new( - max_per_row: usize, - max_joint_size: u32, - features: LookupFeatures, - ) -> LookupInfo { - LookupInfo { - max_per_row, - max_joint_size, - features, - } - } - } -} From a48ce4fb34e92bc52d2ca618810a7c37266a127e Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 16:00:53 +0100 Subject: [PATCH 5/9] update value of keccak cols to be 2065 --- kimchi/src/circuits/polynomials/keccak/mod.rs | 2 +- kimchi/src/tests/keccak.rs | 46 +++++++++++-------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/kimchi/src/circuits/polynomials/keccak/mod.rs b/kimchi/src/circuits/polynomials/keccak/mod.rs index 970346e099..e7e624e782 100644 --- a/kimchi/src/circuits/polynomials/keccak/mod.rs +++ b/kimchi/src/circuits/polynomials/keccak/mod.rs @@ -8,7 +8,7 @@ pub const QUARTERS: usize = 4; pub const ROUNDS: usize = 24; pub const RATE: usize = 1088 / 8; pub const CAPACITY: usize = 512 / 8; -pub const KECCAK_COLS: usize = 2344; +pub const KECCAK_COLS: usize = 2065; use crate::circuits::expr::constraints::ExprOps; use ark_ff::PrimeField; diff --git a/kimchi/src/tests/keccak.rs b/kimchi/src/tests/keccak.rs index 06805b91a7..5acb55e180 100644 --- a/kimchi/src/tests/keccak.rs +++ b/kimchi/src/tests/keccak.rs @@ -136,7 +136,7 @@ where } } - let runner: TestRunner<2344, G> = TestFramework::::default() + let runner: TestRunner = TestFramework::::default() .gates(gates.clone()) .setup(); let cs = runner.clone().prover_index().cs.clone(); @@ -298,13 +298,17 @@ fn test_bitwise_sparse_representation() { #[test] // Test hash of message zero with 1 byte fn test_dummy() { - let (_, claim1) = test_keccak::( - BigUint::from_bytes_be(&[0x00]), - true, - ); - let hash1 = - BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); - assert_eq!(claim1, hash1); + stacker::grow(30 * 1024 * 1024, || { + // guaranteed to have at least 30MB of stack + + let (_, claim1) = test_keccak::( + BigUint::from_bytes_be(&[0x00]), + true, + ); + let hash1 = + BigUint::from_hex("bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"); + assert_eq!(claim1, hash1); + }); } #[test] @@ -321,20 +325,24 @@ fn test_random_block() { #[test] // Test hash of message zero with 1 byte fn test_blocks() { - let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); - let hash_3blocks = - BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); - assert_eq!(claim_3blocks, hash_3blocks); + stacker::grow(30 * 1024 * 1024, || { + let (_,claim_3blocks) = test_keccak::(BigUint::from_hex("832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f423423a214325d13523aadb21414124aaadf32523126832588523900cca2ea9b8c0395d295aa39f9a9285a982b71cc8475067a8175f38f235a2234abc982a2dfaaddff2895a28598021895206a733a22bccd21f124df1413858a8f9a1134df285a888b099a8c2235eecdf2345f3afd32f3ae323526689172850672938104892357aad32523523f"), true); + let hash_3blocks = + BigUint::from_hex("7e369e1a4362148fca24c67c76f14dbe24b75c73e9b0efdb8c46056c8514287e"); + assert_eq!(claim_3blocks, hash_3blocks); + }); } #[test] // Test hash of message zero with 1 byte fn test_1000_hashes() { - assert_eq!( - Ok(()), - test_keccak_n::( - 1000, - &mut StdRng::from_seed(RNG_SEED), - ) - ); + stacker::grow(30 * 1024 * 1024, || { + assert_eq!( + Ok(()), + test_keccak_n::( + 1000, + &mut StdRng::from_seed(RNG_SEED), + ) + ); + }); } From e42456b0d488148406f8de799c2e047ac16fad99 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 16:02:22 +0100 Subject: [PATCH 6/9] remove bound_e --- kimchi/src/circuits/lookup/lookups.rs | 19 +++----- .../polynomials/keccak/circuitgates.rs | 25 +++++----- kimchi/src/circuits/polynomials/keccak/mod.rs | 2 +- .../circuits/polynomials/keccak/witness.rs | 46 +++++-------------- 4 files changed, 29 insertions(+), 63 deletions(-) diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 2f0f821da0..f14c68342d 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -4,7 +4,7 @@ use crate::circuits::{ lookup::index::LookupSelectors, lookup::tables::{ combine_table_entry, get_table, GateLookupTable, LookupTable, RANGE_CHECK_TABLE_ID, - SPARSE_TABLE_ID, XOR_TABLE_ID, + XOR_TABLE_ID, }, }; use ark_ff::{Field, One, PrimeField, Zero}; @@ -15,8 +15,6 @@ use std::collections::HashSet; use std::ops::{Mul, Neg}; use strum_macros::EnumIter; -use super::tables::{BITS16_TABLE_ID, RESET_TABLE_ID}; - type Evaluations = E>; //~ Lookups patterns are extremely flexible and can be configured in a number of ways. @@ -414,7 +412,7 @@ impl LookupPattern { /// Returns the maximum number of lookups per row that are used by the pattern. pub fn max_lookups_per_row(&self) -> usize { match self { - //LookupPattern::KeccakRound => 1720, + //LookupPattern::KeccakRound => 1620, //LookupPattern::KeccakSponge => 800, LookupPattern::Xor | LookupPattern::RangeCheck | LookupPattern::ForeignFieldMul => 4, LookupPattern::Lookup => 3, @@ -571,8 +569,8 @@ impl LookupPattern { table_id: LookupTableID::Constant(RESET_TABLE_ID), entry: vec![l(dense_e), l(shift0_e)], }); - let dense_rot_e = curr_row(1065 + i); - let expand_rot_e = curr_row(1165 + i); + let dense_rot_e = curr_row(965 + i); + let expand_rot_e = curr_row(1065 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(SPARSE_TABLE_ID), entry: vec![l(dense_rot_e), l(expand_rot_e)], @@ -599,7 +597,6 @@ impl LookupPattern { // First column lookups let quotient_e = curr_row(765 + i); let remainder_e = curr_row(865 + i); - let bound_e = curr_row(965 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(BITS16_TABLE_ID), @@ -609,16 +606,12 @@ impl LookupPattern { table_id: LookupTableID::Constant(BITS16_TABLE_ID), entry: vec![l(remainder_e)], }); - lookups.push(JointLookup { - table_id: LookupTableID::Constant(BITS16_TABLE_ID), - entry: vec![l(bound_e)], - }); } // Chi for i in 0..400 { // Second column lookups - let shift_b: LocalPosition = curr_row(1265 + i); - let shift_sum = curr_row(1665 + i); + let shift_b: LocalPosition = curr_row(1165 + i); + let shift_sum = curr_row(1565 + i); lookups.push(JointLookup { table_id: LookupTableID::Constant(SPARSE_TABLE_ID), diff --git a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs index c3d1bbfefa..2f433052df 100644 --- a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs @@ -54,7 +54,7 @@ macro_rules! from_shifts { } //~ -//~ | `KeccakRound` | [0...265) | [265...1265) | [1265...2065) | +//~ | `KeccakRound` | [0...265) | [265...1165) | [1165...1965) | //~ | ------------- | --------- | ------------ | ------------- | //~ | Curr | theta | pirho | chi | //~ @@ -68,11 +68,11 @@ macro_rules! from_shifts { //~ | -------- | --------- | ----------- | ----------- | ----------- | ------------ | ------------ | ------------ | //~ | theta | state_a | shifts_c | dense_c | quotient_c | remainder_c | dense_rot_c | expand_rot_c | //~ -//~ | Columns | [265...665) | [665...765) | [765...865) | [865...965) | [965...1065) | [1065...1165) | [1165...1265) | -//~ | -------- | ----------- | ----------- | ------------ | ----------- | ------------- | ------------- | ------------- | -//~ | pirho | shifts_e | dense_e | quotient_e | remainder_e | bound_e | dense_rot_e | expand_rot_e | +//~ | Columns | [265...665) | [665...765) | [765...865) | [865...965) | [965...1065) | [1065...1165) | +//~ | -------- | ----------- | ----------- | ------------ | ----------- | ------------ | ------------- | +//~ | pirho | shifts_e | dense_e | quotient_e | remainder_e | dense_rot_e | expand_rot_e | //~ -//~ | Columns | [1265...1665) | [1665...2065) | +//~ | Columns | [1165...1565) | [1565...1965) | //~ | -------- | ------------- | ------------- | //~ | chi | shifts_b | shifts_sum | //~ @@ -88,7 +88,7 @@ where F: PrimeField, { const ARGUMENT_TYPE: ArgumentType = ArgumentType::Gate(GateType::KeccakRound); - const CONSTRAINTS: u32 = 414; + const CONSTRAINTS: u32 = 389; // Constraints for one round of the Keccak permutation function fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { @@ -111,12 +111,11 @@ where let dense_e = grid!(100, env.witness_curr_chunk(665, 765)); let quotient_e = grid!(100, env.witness_curr_chunk(765, 865)); let remainder_e = grid!(100, env.witness_curr_chunk(865, 965)); - let bound_e = grid!(100, env.witness_curr_chunk(965, 1065)); - let dense_rot_e = grid!(100, env.witness_curr_chunk(1065, 1165)); - let expand_rot_e = grid!(100, env.witness_curr_chunk(1165, 1265)); + let dense_rot_e = grid!(100, env.witness_curr_chunk(965, 1065)); + let expand_rot_e = grid!(100, env.witness_curr_chunk(1065, 1165)); // CHI - let shifts_b = grid!(400, env.witness_curr_chunk(1265, 1665)); - let shifts_sum = grid!(400, env.witness_curr_chunk(1665, 2065)); + let shifts_b = grid!(400, env.witness_curr_chunk(1165, 1565)); + let shifts_sum = grid!(400, env.witness_curr_chunk(1565, 1965)); // IOTA let state_g = grid!(100, env.witness_next_chunk(0, 100)); @@ -155,20 +154,18 @@ where } } // END theta - // STEP pirho: 5 * 5 * (3 + 4 * 1) = 175 constraints + // STEP pirho: 5 * 5 * (2 + 4 * 1) = 150 constraints for (y, col) in OFF.iter().enumerate() { for (x, off) in col.iter().enumerate() { let word_e = from_quarters!(dense_e, y, x); let quo_e = from_quarters!(quotient_e, y, x); let rem_e = from_quarters!(remainder_e, y, x); - let bnd_e = from_quarters!(bound_e, y, x); let rot_e = from_quarters!(dense_rot_e, y, x); constraints.push( word_e * T::two_pow(*off) - (quo_e.clone() * T::two_pow(64) + rem_e.clone()), ); constraints.push(rot_e - (quo_e.clone() + rem_e)); - constraints.push(bnd_e - (quo_e + T::two_pow(64) - T::two_pow(*off))); for q in 0..QUARTERS { constraints.push(state_e[y][x][q].clone() - from_shifts!(shifts_e, y, x, q)); diff --git a/kimchi/src/circuits/polynomials/keccak/mod.rs b/kimchi/src/circuits/polynomials/keccak/mod.rs index e7e624e782..b89c21df20 100644 --- a/kimchi/src/circuits/polynomials/keccak/mod.rs +++ b/kimchi/src/circuits/polynomials/keccak/mod.rs @@ -8,7 +8,7 @@ pub const QUARTERS: usize = 4; pub const ROUNDS: usize = 24; pub const RATE: usize = 1088 / 8; pub const CAPACITY: usize = 512 / 8; -pub const KECCAK_COLS: usize = 2065; +pub const KECCAK_COLS: usize = 1965; use crate::circuits::expr::constraints::ExprOps; use ark_ff::PrimeField; diff --git a/kimchi/src/circuits/polynomials/keccak/witness.rs b/kimchi/src/circuits/polynomials/keccak/witness.rs index 71b8a0ca72..0b416f9369 100644 --- a/kimchi/src/circuits/polynomials/keccak/witness.rs +++ b/kimchi/src/circuits/polynomials/keccak/witness.rs @@ -34,11 +34,10 @@ fn layout_round() -> [Layout; 1] { IndexCell::create("dense_e", 665, 765), IndexCell::create("quotient_e", 765, 865), IndexCell::create("remainder_e", 865, 965), - IndexCell::create("bound_e", 965, 1065), - IndexCell::create("dense_rot_e", 1065, 1165), - IndexCell::create("expand_rot_e", 1165, 1265), - IndexCell::create("shifts_b", 1265, 1665), - IndexCell::create("shifts_sum", 1665, 2065), + IndexCell::create("dense_rot_e", 965, 1065), + IndexCell::create("expand_rot_e", 1065, 1165), + IndexCell::create("shifts_b", 1165, 1565), + IndexCell::create("shifts_sum", 1565, 1965), ]] } @@ -61,41 +60,24 @@ fn field(input: &[u64]) -> Vec { struct Rotation { quotient: Vec, remainder: Vec, - bound: Vec, dense_rot: Vec, expand_rot: Vec, } impl Rotation { - // Returns rotation of 0 bits - fn none(dense: &[u64]) -> Self { - Self { - quotient: vec![0; QUARTERS], - remainder: dense.to_vec(), - bound: vec![0xFFFF; QUARTERS], - dense_rot: dense.to_vec(), - expand_rot: dense.iter().map(|x| expand(*x)).collect(), - } - } - // On input the dense quarters of a word, rotate the word offset bits to the left fn new(dense: &[u64], offset: u32) -> Self { - if offset == 0 { - return Self::none(dense); - } let word = compose(dense); - let rem = (word as u128 * 2u128.pow(offset) % 2u128.pow(64)) as u64; - let quo = word / 2u64.pow(64 - offset); - let bnd = (quo as u128) + 2u128.pow(64) - 2u128.pow(offset); + let rem = word as u128 * 2u128.pow(offset) % 2u128.pow(64); + let quo = (word as u128) / 2u128.pow(64 - offset); let rot = rem + quo; - assert!(rot == word.rotate_left(offset)); + assert!(rot as u64 == word.rotate_left(offset)); Self { - quotient: decompose(quo), - remainder: decompose(rem), - bound: decompose(bnd as u64), - dense_rot: decompose(rot), - expand_rot: decompose(rot).iter().map(|x| expand(*x)).collect(), + quotient: decompose(quo as u64), + remainder: decompose(rem as u64), + dense_rot: decompose(rot as u64), + expand_rot: decompose(rot as u64).iter().map(|x| expand(*x)).collect(), } } @@ -104,21 +86,18 @@ impl Rotation { assert!(words.len() == QUARTERS * offsets.len()); let mut quotient = vec![]; let mut remainder = vec![]; - let mut bound = vec![]; let mut dense_rot = vec![]; let mut expand_rot = vec![]; for (word, offset) in words.chunks(QUARTERS).zip(offsets.iter()) { let mut rot = Self::new(word, *offset); quotient.append(&mut rot.quotient); remainder.append(&mut rot.remainder); - bound.append(&mut rot.bound); dense_rot.append(&mut rot.dense_rot); expand_rot.append(&mut rot.expand_rot); } Self { quotient, remainder, - bound, dense_rot, expand_rot, } @@ -210,7 +189,6 @@ struct PiRho { dense_e: Vec, quotient_e: Vec, remainder_e: Vec, - bound_e: Vec, dense_rot_e: Vec, expand_rot_e: Vec, state_b: Vec, @@ -244,7 +222,6 @@ impl PiRho { dense_e, quotient_e: rotation_e.quotient, remainder_e: rotation_e.remainder, - bound_e: rotation_e.bound, dense_rot_e: rotation_e.dense_rot, expand_rot_e: rotation_e.expand_rot, state_b, @@ -389,7 +366,6 @@ pub fn extend_keccak_witness(witness: &mut [Vec; KECCAK_COLS], "dense_e" => field(&pirho.dense_e), "quotient_e" => field(&pirho.quotient_e), "remainder_e" => field(&pirho.remainder_e), - "bound_e" => field(&pirho.bound_e), "dense_rot_e" => field(&pirho.dense_rot_e), "expand_rot_e" => field(&pirho.expand_rot_e), "shifts_b" => field(&chi.shifts_b), From 72ba91e20d432e7f2ca2e0c6d366a5ef5f379039 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 16:07:38 +0100 Subject: [PATCH 7/9] update order of generics --- kimchi/src/circuits/berkeley_columns.rs | 2 +- kimchi/src/circuits/lookup/lookups.rs | 2 +- .../polynomials/keccak/circuitgates.rs | 10 ++++++-- .../circuits/polynomials/keccak/witness.rs | 6 ++--- kimchi/src/linearization.rs | 4 ++-- kimchi/src/tests/keccak.rs | 12 +++++----- kimchi/src/verifier.rs | 24 +++++++++---------- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/kimchi/src/circuits/berkeley_columns.rs b/kimchi/src/circuits/berkeley_columns.rs index f756fe4c66..8534221b3c 100644 --- a/kimchi/src/circuits/berkeley_columns.rs +++ b/kimchi/src/circuits/berkeley_columns.rs @@ -156,7 +156,7 @@ impl ColumnEvaluations .runtime_lookup_table_selector .ok_or(ExprError::MissingIndexEvaluation(col)), Index(_) => Err(ExprError::MissingIndexEvaluation(col)), - LookupKindIndex(_) => Err(ExprError::MissingIndexEvaluation(col)), + //LookupKindIndex(_) => Err(ExprError::MissingIndexEvaluation(col)), } } } diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index f14c68342d..64e9749eb6 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -211,7 +211,7 @@ impl LookupInfo { /// Each entry in `kinds` has a corresponding selector polynomial that controls whether that /// lookup kind should be enforced at a given row. This computes those selector polynomials. - pub fn selector_polynomials_and_tables( + pub fn selector_polynomials_and_tables( &self, domain: &EvaluationDomains, gates: &[CircuitGate], diff --git a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs index 2f433052df..87f975807c 100644 --- a/kimchi/src/circuits/polynomials/keccak/circuitgates.rs +++ b/kimchi/src/circuits/polynomials/keccak/circuitgates.rs @@ -91,7 +91,10 @@ where const CONSTRAINTS: u32 = 389; // Constraints for one round of the Keccak permutation function - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { let mut constraints = vec![]; // DEFINE ROUND CONSTANT @@ -216,7 +219,10 @@ where const CONSTRAINTS: u32 = 568; // Constraints for one round of the Keccak permutation function - fn constraint_checks>(env: &ArgumentEnv, _cache: &mut Cache) -> Vec { + fn constraint_checks, const COLUMNS: usize>( + env: &ArgumentEnv, + _cache: &mut Cache, + ) -> Vec { let mut constraints = vec![]; // LOAD WITNESS diff --git a/kimchi/src/circuits/polynomials/keccak/witness.rs b/kimchi/src/circuits/polynomials/keccak/witness.rs index 0b416f9369..cc575d1f38 100644 --- a/kimchi/src/circuits/polynomials/keccak/witness.rs +++ b/kimchi/src/circuits/polynomials/keccak/witness.rs @@ -19,9 +19,9 @@ use super::{ RATE, }; -type Layout = Vec>>>; +type Layout = Vec, COLUMNS>>>; -fn layout_round() -> [Layout; 1] { +fn layout_round() -> [Layout; 1] { [vec![ IndexCell::create("state_a", 0, 100), IndexCell::create("shifts_c", 100, 180), @@ -41,7 +41,7 @@ fn layout_round() -> [Layout; 1] { ]] } -fn layout_sponge() -> [Layout; 1] { +fn layout_sponge() -> [Layout; 1] { [vec![ IndexCell::create("old_state", 0, 100), IndexCell::create("new_state", 100, 200), diff --git a/kimchi/src/linearization.rs b/kimchi/src/linearization.rs index 51e37a5313..0f556e87ee 100644 --- a/kimchi/src/linearization.rs +++ b/kimchi/src/linearization.rs @@ -375,8 +375,8 @@ pub fn linearization_columns( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let messages = vec![rng.gen_biguint_below(&BigUint::from(2u32).pow(1080)); n]; @@ -136,14 +136,14 @@ where } } - let runner: TestRunner = TestFramework::::default() + let runner: TestRunner = TestFramework::::default() .gates(gates.clone()) .setup(); let cs = runner.clone().prover_index().cs.clone(); // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return result; } @@ -167,7 +167,7 @@ fn test_keccak( where G::BaseField: PrimeField, EFqSponge: Clone + FqSponge, - EFrSponge: FrSponge, + EFrSponge: FrSponge, { let bytelength = message.to_bytes_be().len(); @@ -194,7 +194,7 @@ where let runner = if full { // Create prover index with test framework Some( - TestFramework::::default() + TestFramework::::default() .gates(gates.clone()) .setup(), ) @@ -211,7 +211,7 @@ where // Perform witness verification that everything is ok before invalidation (quick checks) for (row, gate) in gates.iter().enumerate().take(witness[0].len()) { let result = - gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); + gate.verify_witness::(row, &witness, &cs, &witness[0][0..cs.public]); if result.is_err() { return (result, hash); } diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 97522df4a8..431baa9b07 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -570,16 +570,16 @@ where .chain(self.evals.foreign_field_mul_lookup_selector.as_ref().map( |_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul), )) - .chain( - self.evals.keccak_round_lookup_selector.as_ref().map(|_| { - Column::LookupKindIndex(LookupPattern::KeccakRound) - }), - ) - .chain( - self.evals.keccak_sponge_lookup_selector.as_ref().map(|_| { - Column::LookupKindIndex(LookupPattern::KeccakSponge) - }), - ) + /* .chain( + self.evals.keccak_round_lookup_selector.as_ref().map(|_| { + Column::LookupKindIndex(LookupPattern::KeccakRound) + }), + ) + .chain( + self.evals.keccak_sponge_lookup_selector.as_ref().map(|_| { + Column::LookupKindIndex(LookupPattern::KeccakSponge) + }), + )*/ }) .into_iter() .flatten(), @@ -1164,7 +1164,7 @@ where .as_ref() .map(|_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul)), ) - .chain( + /* .chain( li.lookup_selectors .keccak_round .as_ref() @@ -1175,7 +1175,7 @@ where .keccak_sponge .as_ref() .map(|_| Column::LookupKindIndex(LookupPattern::KeccakSponge)), - ) + )*/ }) .into_iter() .flatten() From 6128078e889d63c2c648768dc3a574d386a354cf Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 16:41:28 +0100 Subject: [PATCH 8/9] remove lookup selectors of keccak sponge inside ocamltypes as they are disabled now --- kimchi/src/proof.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/kimchi/src/proof.rs b/kimchi/src/proof.rs index be4c6f019a..726c5b4357 100644 --- a/kimchi/src/proof.rs +++ b/kimchi/src/proof.rs @@ -998,8 +998,6 @@ pub mod caml { foreign_field_mul_lookup_selector: cpe .foreign_field_mul_lookup_selector .map(|x| x.map(&|x| x.iter().map(|x| x.clone().into()).collect())), - keccak_round_lookup_selector: None, - keccak_sponge_lookup_selector: None, } } } From ff9405b82f2aad5b567c47192fbe4259838aed22 Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 1 Nov 2023 17:22:25 +0100 Subject: [PATCH 9/9] fmt --- kimchi/src/verifier.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kimchi/src/verifier.rs b/kimchi/src/verifier.rs index 431baa9b07..e88fc42c97 100644 --- a/kimchi/src/verifier.rs +++ b/kimchi/src/verifier.rs @@ -570,7 +570,8 @@ where .chain(self.evals.foreign_field_mul_lookup_selector.as_ref().map( |_| Column::LookupKindIndex(LookupPattern::ForeignFieldMul), )) - /* .chain( + /* + .chain( self.evals.keccak_round_lookup_selector.as_ref().map(|_| { Column::LookupKindIndex(LookupPattern::KeccakRound) }), @@ -579,7 +580,8 @@ where self.evals.keccak_sponge_lookup_selector.as_ref().map(|_| { Column::LookupKindIndex(LookupPattern::KeccakSponge) }), - )*/ + ) + */ }) .into_iter() .flatten(),