From 7f9e9ab4693050467b38e3d25987ada6a41b9ee8 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Mon, 24 Apr 2023 12:51:48 -0300 Subject: [PATCH] feat(hint): support hint #68 for keccak_finalize Version from whitelist `starknet/security/whitelists/cairo_keccak.json`, differs from the current one in bounds for `_block_size`, `1000` instead of `10`. --- CHANGELOG.md | 17 +++++ ...o_finalize_keccak_block_size_too_big.cairo | 62 +++++++++++++++++++ ...airo_finalize_keccak_block_size_1000.cairo | 60 ++++++++++++++++++ .../builtin_hint_processor_definition.rs | 12 ++-- .../cairo_keccak/keccak_hints.rs | 61 +++++++++++++----- .../builtin_hint_processor/hint_code.rs | 11 +++- src/tests/cairo_run_test.rs | 10 ++- 7 files changed, 212 insertions(+), 21 deletions(-) create mode 100644 cairo_programs/bad_programs/cairo_finalize_keccak_block_size_too_big.cairo create mode 100644 cairo_programs/cairo_finalize_keccak_block_size_1000.cairo diff --git a/CHANGELOG.md b/CHANGELOG.md index d842c2f619..9bdf1d8403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ #### Upcoming Changes +* Implement hint for `starkware.cairo.common.cairo_keccak.keccak.finalize_keccak` as described by whitelist `starknet/security/whitelists/cairo_keccak.json` [#1041](https://github.com/lambdaclass/cairo-rs/pull/1041) + + `BuiltinHintProcessor` now supports the following hint: + + ```python + %{ + # Add dummy pairs of input and output. + _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) + _block_size = int(ids.BLOCK_SIZE) + assert 0 <= _keccak_state_size_felts < 100 + assert 0 <= _block_size < 1000 + inp = [0] * _keccak_state_size_felts + padding = (inp + keccak_func(inp)) * _block_size + segments.write_arg(ids.keccak_ptr_end, padding) + %} + ``` + * Implement hint on ec_recover.json whitelist [#1036](https://github.com/lambdaclass/cairo-rs/pull/1036): `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/bad_programs/cairo_finalize_keccak_block_size_too_big.cairo b/cairo_programs/bad_programs/cairo_finalize_keccak_block_size_too_big.cairo new file mode 100644 index 0000000000..0e7a2fa51a --- /dev/null +++ b/cairo_programs/bad_programs/cairo_finalize_keccak_block_size_too_big.cairo @@ -0,0 +1,62 @@ +%builtins range_check bitwise + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.cairo_keccak.keccak import _finalize_keccak_inner, cairo_keccak, KECCAK_STATE_SIZE_FELTS +from starkware.cairo.common.math import unsigned_div_rem +from starkware.cairo.common.uint256 import Uint256 + +const BLOCK_SIZE = 0x800000000000011000000000000000000000000000000000000000000000000; + +// Verifies that the results of cairo_keccak() are valid. For optimization, this can be called only +// once after all the keccak calculations are completed. +// Version copied from starknet/security/whitelists/cairo_keccak.json +func finalize_keccak{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + keccak_ptr_start: felt*, keccak_ptr_end: felt* +) { + alloc_locals; + + tempvar n = (keccak_ptr_end - keccak_ptr_start) / (2 * KECCAK_STATE_SIZE_FELTS); + if (n == 0) { + return (); + } + + %{ + # Add dummy pairs of input and output. + _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) + _block_size = int(ids.BLOCK_SIZE) + assert 0 <= _keccak_state_size_felts < 100 + assert 0 <= _block_size < 1000 + inp = [0] * _keccak_state_size_felts + padding = (inp + keccak_func(inp)) * _block_size + segments.write_arg(ids.keccak_ptr_end, padding) + %} + + // Compute the amount of blocks (rounded up). + let (local q, r) = unsigned_div_rem(n + BLOCK_SIZE - 1, BLOCK_SIZE); + _finalize_keccak_inner(keccak_ptr_start, n=q); + return (); +} + +func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { + alloc_locals; + + let (keccak_ptr: felt*) = alloc(); + let keccak_ptr_start = keccak_ptr; + + let (inputs: felt*) = alloc(); + + assert inputs[0] = 8031924123371070792; + assert inputs[1] = 560229490; + + let n_bytes = 16; + + let (res: Uint256) = cairo_keccak{keccak_ptr=keccak_ptr}(inputs=inputs, n_bytes=n_bytes); + + assert res.low = 293431514620200399776069983710520819074; + assert res.high = 317109767021952548743448767588473366791; + + finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr); + + return (); +} diff --git a/cairo_programs/cairo_finalize_keccak_block_size_1000.cairo b/cairo_programs/cairo_finalize_keccak_block_size_1000.cairo new file mode 100644 index 0000000000..30e7d74962 --- /dev/null +++ b/cairo_programs/cairo_finalize_keccak_block_size_1000.cairo @@ -0,0 +1,60 @@ +%builtins range_check bitwise + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.cairo_keccak.keccak import _finalize_keccak_inner, cairo_keccak, BLOCK_SIZE, KECCAK_STATE_SIZE_FELTS +from starkware.cairo.common.math import unsigned_div_rem +from starkware.cairo.common.uint256 import Uint256 + +// Verifies that the results of cairo_keccak() are valid. For optimization, this can be called only +// once after all the keccak calculations are completed. +// Version copied from starknet/security/whitelists/cairo_keccak.json +func finalize_keccak{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + keccak_ptr_start: felt*, keccak_ptr_end: felt* +) { + alloc_locals; + + tempvar n = (keccak_ptr_end - keccak_ptr_start) / (2 * KECCAK_STATE_SIZE_FELTS); + if (n == 0) { + return (); + } + + %{ + # Add dummy pairs of input and output. + _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) + _block_size = int(ids.BLOCK_SIZE) + assert 0 <= _keccak_state_size_felts < 100 + assert 0 <= _block_size < 1000 + inp = [0] * _keccak_state_size_felts + padding = (inp + keccak_func(inp)) * _block_size + segments.write_arg(ids.keccak_ptr_end, padding) + %} + + // Compute the amount of blocks (rounded up). + let (local q, r) = unsigned_div_rem(n + BLOCK_SIZE - 1, BLOCK_SIZE); + _finalize_keccak_inner(keccak_ptr_start, n=q); + return (); +} + +func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { + alloc_locals; + + let (keccak_ptr: felt*) = alloc(); + let keccak_ptr_start = keccak_ptr; + + let (inputs: felt*) = alloc(); + + assert inputs[0] = 8031924123371070792; + assert inputs[1] = 560229490; + + let n_bytes = 16; + + let (res: Uint256) = cairo_keccak{keccak_ptr=keccak_ptr}(inputs=inputs, n_bytes=n_bytes); + + assert res.low = 293431514620200399776069983710520819074; + assert res.high = 317109767021952548743448767588473366791; + + finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr); + + return (); +} diff --git a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index b4a0d811d5..655ee63845 100644 --- a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -6,8 +6,9 @@ use crate::{ blake2s_add_uint256, blake2s_add_uint256_bigend, compute_blake2s, finalize_blake2s, }, cairo_keccak::keccak_hints::{ - block_permutation, cairo_keccak_finalize, compare_bytes_in_word_nondet, - compare_keccak_full_rate_in_bytes_nondet, keccak_write_args, + block_permutation, cairo_keccak_finalize_v1, cairo_keccak_finalize_v2, + compare_bytes_in_word_nondet, compare_keccak_full_rate_in_bytes_nondet, + keccak_write_args, }, dict_hint_utils::{ default_dict_new, dict_new, dict_read, dict_squash_copy_dict, @@ -484,8 +485,11 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::BLOCK_PERMUTATION | hint_code::BLOCK_PERMUTATION_WHITELIST => { block_permutation(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants) } - hint_code::CAIRO_KECCAK_FINALIZE => { - cairo_keccak_finalize(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants) + hint_code::CAIRO_KECCAK_FINALIZE_V1 => { + cairo_keccak_finalize_v1(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants) + } + hint_code::CAIRO_KECCAK_FINALIZE_V2 => { + cairo_keccak_finalize_v2(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants) } hint_code::FAST_EC_ADD_ASSIGN_NEW_X => fast_ec_add_assign_new_x( vm, diff --git a/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs b/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs index dbd789ae30..9cde0c0f31 100644 --- a/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs +++ b/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs @@ -174,23 +174,12 @@ pub fn block_permutation( Ok(()) } -/* Implements hint: - %{ - # Add dummy pairs of input and output. - _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) - _block_size = int(ids.BLOCK_SIZE) - assert 0 <= _keccak_state_size_felts < 100 - assert 0 <= _block_size < 10 - inp = [0] * _keccak_state_size_felts - padding = (inp + keccak_func(inp)) * _block_size - segments.write_arg(ids.keccak_ptr_end, padding) - %} -*/ -pub fn cairo_keccak_finalize( +fn cairo_keccak_finalize( vm: &mut VirtualMachine, ids_data: &HashMap, ap_tracking: &ApTracking, constants: &HashMap, + block_size_limit: usize, ) -> Result<(), HintError> { let keccak_state_size_felts = constants .get(KECCAK_STATE_SIZE_FELTS) @@ -205,9 +194,9 @@ pub fn cairo_keccak_finalize( )); } - if block_size >= &Felt252::new(10_i32) { + if block_size >= &Felt252::new(block_size_limit) { return Err(HintError::InvalidBlockSize(block_size.clone())); - } + }; let keccak_state_size_felts = keccak_state_size_felts.to_usize().unwrap(); let block_size = block_size.to_usize().unwrap(); @@ -234,6 +223,48 @@ pub fn cairo_keccak_finalize( Ok(()) } +/* Implements hint: + %{ + # Add dummy pairs of input and output. + _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) + _block_size = int(ids.BLOCK_SIZE) + assert 0 <= _keccak_state_size_felts < 100 + assert 0 <= _block_size < 10 + inp = [0] * _keccak_state_size_felts + padding = (inp + keccak_func(inp)) * _block_size + segments.write_arg(ids.keccak_ptr_end, padding) + %} +*/ +pub(crate) fn cairo_keccak_finalize_v1( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, + constants: &HashMap, +) -> Result<(), HintError> { + cairo_keccak_finalize(vm, ids_data, ap_tracking, constants, 10) +} + +/* Implements hint: + %{ + # Add dummy pairs of input and output. + _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) + _block_size = int(ids.BLOCK_SIZE) + assert 0 <= _keccak_state_size_felts < 100 + assert 0 <= _block_size < 1000 + inp = [0] * _keccak_state_size_felts + padding = (inp + keccak_func(inp)) * _block_size + segments.write_arg(ids.keccak_ptr_end, padding) + %} +*/ +pub(crate) fn cairo_keccak_finalize_v2( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, + constants: &HashMap, +) -> Result<(), HintError> { + cairo_keccak_finalize(vm, ids_data, ap_tracking, constants, 1000) +} + // Helper function to transform a vector of MaybeRelocatables into a vector // of u64. Raises error if there are None's or if MaybeRelocatables are not Bigints. pub(crate) fn maybe_reloc_vec_to_u64_array( diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 2df3602b8c..cea257e281 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -661,7 +661,7 @@ output_values = keccak_func(memory.get_range( ids.keccak_ptr - _keccak_state_size_felts, _keccak_state_size_felts)) segments.write_arg(ids.keccak_ptr, output_values)"#; -pub const CAIRO_KECCAK_FINALIZE: &str = r#"# Add dummy pairs of input and output. +pub const CAIRO_KECCAK_FINALIZE_V1: &str = r#"# Add dummy pairs of input and output. _keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) _block_size = int(ids.BLOCK_SIZE) assert 0 <= _keccak_state_size_felts < 100 @@ -670,6 +670,15 @@ inp = [0] * _keccak_state_size_felts padding = (inp + keccak_func(inp)) * _block_size segments.write_arg(ids.keccak_ptr_end, padding)"#; +pub const CAIRO_KECCAK_FINALIZE_V2: &str = r#"# Add dummy pairs of input and output. +_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS) +_block_size = int(ids.BLOCK_SIZE) +assert 0 <= _keccak_state_size_felts < 100 +assert 0 <= _block_size < 1000 +inp = [0] * _keccak_state_size_felts +padding = (inp + keccak_func(inp)) * _block_size +segments.write_arg(ids.keccak_ptr_end, padding)"#; + pub const FAST_EC_ADD_ASSIGN_NEW_X: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack slope = pack(ids.slope, PRIME) diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index a118bf7587..d6765c7db6 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -458,11 +458,19 @@ fn keccak_copy_inputs() { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn cairo_finalize_keccak() { +fn cairo_finalize_keccak_v1() { let program_data = include_bytes!("../../cairo_programs/cairo_finalize_keccak.json"); run_program_simple_with_memory_holes(program_data.as_slice(), 50); } +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn cairo_finalize_keccak_v2() { + let program_data = + include_bytes!("../../cairo_programs/cairo_finalize_keccak_block_size_1000.json"); + run_program_simple_with_memory_holes(program_data.as_slice(), 50); +} + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn operations_with_data_structures() {