diff --git a/Cargo.lock b/Cargo.lock index 50892d98ff3..8aca450c6cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,7 @@ dependencies = [ "blake2", "blake3", "k256", + "keccak", "p256", "sha2", "sha3", diff --git a/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/acvm-repo/acvm/src/pwg/blackbox/hash.rs index bbf7dd43bd9..1ada397fc59 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/hash.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -86,82 +86,3 @@ fn write_digest_to_outputs( Ok(()) } - -const ROUNDS: usize = 24; - -const RC: [u64; ROUNDS] = [ - 1u64, - 0x8082u64, - 0x800000000000808au64, - 0x8000000080008000u64, - 0x808bu64, - 0x80000001u64, - 0x8000000080008081u64, - 0x8000000000008009u64, - 0x8au64, - 0x88u64, - 0x80008009u64, - 0x8000000au64, - 0x8000808bu64, - 0x800000000000008bu64, - 0x8000000000008089u64, - 0x8000000000008003u64, - 0x8000000000008002u64, - 0x8000000000000080u64, - 0x800au64, - 0x800000008000000au64, - 0x8000000080008081u64, - 0x8000000000008080u64, - 0x80000001u64, - 0x8000000080008008u64, -]; - -const RHO: [u32; 24] = - [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]; - -const PI: [usize; 24] = - [10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1]; - -const KECCAK_LANES: usize = 25; - -pub(crate) fn keccakf1600(state: &mut [u64; KECCAK_LANES]) { - for rc in RC { - let mut array: [u64; 5] = [0; 5]; - - // Theta - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - array[x] ^= state[x + y]; - } - } - - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - state[y + x] ^= array[(x + 4) % 5] ^ array[(x + 1) % 5].rotate_left(1); - } - } - - // Rho and pi - let mut last = state[1]; - for x in 0..24 { - array[0] = state[PI[x]]; - state[PI[x]] = last.rotate_left(RHO[x]); - last = array[0]; - } - - // Chi - for y_step in 0..5 { - let y = y_step * 5; - array[..5].copy_from_slice(&state[y..(5 + y)]); - - for x in 0..5 { - state[y + x] = array[x] ^ ((!array[(x + 1) % 5]) & (array[(x + 2) % 5])); - } - } - - // Iota - state[0] ^= rc; - } -} diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index f752924ac18..c18a97733b8 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -3,9 +3,9 @@ use acir::{ native_types::{Witness, WitnessMap}, FieldElement, }; -use acvm_blackbox_solver::{blake2s, blake3, keccak256, sha256}; +use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256}; -use self::{hash::keccakf1600, pedersen::pedersen_hash}; +use self::pedersen::pedersen_hash; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; @@ -119,7 +119,7 @@ pub(crate) fn solve( let lane = witness_assignment.try_to_u64(); state[i] = lane.unwrap(); } - keccakf1600(&mut state); + let state = keccakf1600(state)?; for (output_witness, value) in outputs.iter().zip(state.into_iter()) { insert_value(output_witness, FieldElement::from(value as u128), initial_witness)?; } diff --git a/acvm-repo/blackbox_solver/Cargo.toml b/acvm-repo/blackbox_solver/Cargo.toml index 258321d8ef4..749ef8f289a 100644 --- a/acvm-repo/blackbox_solver/Cargo.toml +++ b/acvm-repo/blackbox_solver/Cargo.toml @@ -20,6 +20,7 @@ blake2 = "0.10.6" blake3 = "1.5.0" sha2 = "0.10.6" sha3 = "0.10.6" +keccak = "0.1.4" k256 = { version = "0.11.0", features = [ "ecdsa", "ecdsa-core", diff --git a/acvm-repo/blackbox_solver/src/lib.rs b/acvm-repo/blackbox_solver/src/lib.rs index ede648ef75e..9518854de8e 100644 --- a/acvm-repo/blackbox_solver/src/lib.rs +++ b/acvm-repo/blackbox_solver/src/lib.rs @@ -68,6 +68,15 @@ pub fn keccak256(inputs: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError> { .map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Keccak256, err)) } +const KECCAK_LANES: usize = 25; + +pub fn keccakf1600( + mut state: [u64; KECCAK_LANES], +) -> Result<[u64; KECCAK_LANES], BlackBoxResolutionError> { + keccak::f1600(&mut state); + Ok(state) +} + pub fn ecdsa_secp256k1_verify( hashed_msg: &[u8], public_key_x: &[u8; 32], @@ -229,6 +238,79 @@ fn verify_secp256r1_ecdsa_signature( } } +#[cfg(test)] +mod keccakf1600_tests { + use crate::keccakf1600; + + #[test] + fn sanity_check() { + // Test vectors are copied from XKCP (eXtended Keccak Code Package) + // https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-1600-IntermediateValues.txt + let zero_state = [0u64; 25]; + + let expected_state_first = [ + 0xF1258F7940E1DDE7, + 0x84D5CCF933C0478A, + 0xD598261EA65AA9EE, + 0xBD1547306F80494D, + 0x8B284E056253D057, + 0xFF97A42D7F8E6FD4, + 0x90FEE5A0A44647C4, + 0x8C5BDA0CD6192E76, + 0xAD30A6F71B19059C, + 0x30935AB7D08FFC64, + 0xEB5AA93F2317D635, + 0xA9A6E6260D712103, + 0x81A57C16DBCF555F, + 0x43B831CD0347C826, + 0x01F22F1A11A5569F, + 0x05E5635A21D9AE61, + 0x64BEFEF28CC970F2, + 0x613670957BC46611, + 0xB87C5A554FD00ECB, + 0x8C3EE88A1CCF32C8, + 0x940C7922AE3A2614, + 0x1841F924A2C509E4, + 0x16F53526E70465C2, + 0x75F644E97F30A13B, + 0xEAF1FF7B5CECA249, + ]; + let expected_state_second = [ + 0x2D5C954DF96ECB3C, + 0x6A332CD07057B56D, + 0x093D8D1270D76B6C, + 0x8A20D9B25569D094, + 0x4F9C4F99E5E7F156, + 0xF957B9A2DA65FB38, + 0x85773DAE1275AF0D, + 0xFAF4F247C3D810F7, + 0x1F1B9EE6F79A8759, + 0xE4FECC0FEE98B425, + 0x68CE61B6B9CE68A1, + 0xDEEA66C4BA8F974F, + 0x33C43D836EAFB1F5, + 0xE00654042719DBD9, + 0x7CF8A9F009831265, + 0xFD5449A6BF174743, + 0x97DDAD33D8994B40, + 0x48EAD5FC5D0BE774, + 0xE3B8C8EE55B7B03C, + 0x91A0226E649E42E9, + 0x900E3129E7BADD7B, + 0x202A9EC5FAA3CCE8, + 0x5B3402464E1C3DB6, + 0x609F4E62A44C1059, + 0x20D06CD26A8FBF5C, + ]; + + let state_first = keccakf1600(zero_state).unwrap(); + let state_second = keccakf1600(state_first).unwrap(); + + assert_eq!(state_first, expected_state_first); + assert_eq!(state_second, expected_state_second); + } +} + #[cfg(test)] mod secp256k1_tests { use super::verify_secp256k1_ecdsa_signature; diff --git a/cspell.json b/cspell.json index 8e3f248acfa..a44cdc88e56 100644 --- a/cspell.json +++ b/cspell.json @@ -86,6 +86,7 @@ "jsdoc", "Jubjub", "keccak", + "keccakf", "krate", "lvalue", "mathbb",