Skip to content

Commit

Permalink
feat(hints): NewHint#67 cairo_keccak.json _block_permutation (#1046)
Browse files Browse the repository at this point in the history
* feat(hint): implement whitelisted hint #67

* Fix typo

* Fix CHANGELOG

* Fix test
  • Loading branch information
Oppen authored Apr 26, 2023
1 parent 5ff1a1d commit 1feaba0
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 30 deletions.
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

#### Upcoming Changes

* Implement hint for `starkware.cairo.common.cairo_keccak.keccak._block_permutation` as described by whitelist `starknet/security/whitelists/cairo_keccak.json` [#1046](https://github.com/lambdaclass/cairo-rs/pull/1046)

`BuiltinHintProcessor` now supports the following hint:

```python
%{
from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
assert 0 <= _keccak_state_size_felts < 100
output_values = keccak_func(memory.get_range(
ids.keccak_ptr_start, _keccak_state_size_felts))
segments.write_arg(ids.output, output_values)
%}
```

* Implement hint on cairo_blake2s whitelist [#1040](https://github.com/lambdaclass/cairo-rs/pull/1040)

`BuiltinHintProcessor` now supports the following hint:
Expand Down Expand Up @@ -1089,4 +1104,4 @@
* `pub fn from_vm_error(runner: &CairoRunner, error: VirtualMachineError, pc: usize) -> Self` is now `pub fn from_vm_error(runner: &CairoRunner, vm: &VirtualMachine, error: VirtualMachineError) -> Self`
* `pub fn get_location(pc: &usize, runner: &CairoRunner) -> Option<Location>` is now `pub fn get_location(pc: usize, runner: &CairoRunner) -> Option<Location>`
* `pub fn decode_instruction(encoded_instr: i64, mut imm: Option<BigInt>) -> Result<instruction::Instruction, VirtualMachineError>` is now `pub fn decode_instruction(encoded_instr: i64, mut imm: Option<&BigInt>) -> Result<instruction::Instruction, VirtualMachineError>`
* `VmExcepion` field's string format now mirror their cairo-lang conterparts.
* `VmException` fields' string format now mirrors their cairo-lang counterparts.
80 changes: 63 additions & 17 deletions cairo_programs/_keccak_alternative_hint.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.serialize import serialize_word

func _keccak{range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: felt*}(
func _keccak_0_10_3{range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: felt*}(
inputs: felt*, n_bytes: felt, state: felt*
) -> (output: felt*) {
alloc_locals;
if (nondet %{ ids.n_bytes >= ids.KECCAK_FULL_RATE_IN_BYTES %} != 0) {
_prepare_block(inputs=inputs, n_bytes=KECCAK_FULL_RATE_IN_BYTES, state=state);
_block_permutation();
_block_permutation_0_10_3();

return _keccak(
return _keccak_0_10_3(
inputs=inputs + KECCAK_FULL_RATE_IN_WORDS,
n_bytes=n_bytes - KECCAK_FULL_RATE_IN_BYTES,
state=keccak_ptr - KECCAK_STATE_SIZE_FELTS,
Expand All @@ -29,12 +29,12 @@ func _keccak{range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: felt*}(
assert_nn_le(n_bytes, KECCAK_FULL_RATE_IN_BYTES - 1);

_prepare_block(inputs=inputs, n_bytes=n_bytes, state=state);
_block_permutation();
_block_permutation_0_10_3();

return (output=keccak_ptr - KECCAK_STATE_SIZE_FELTS);
}

func _block_permutation{keccak_ptr: felt*}() {
func _block_permutation_0_10_3{keccak_ptr: felt*}() {
%{
from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
Expand All @@ -49,17 +49,7 @@ func _block_permutation{keccak_ptr: felt*}() {
return ();
}

func fill_array(array: felt*, base: felt, array_length: felt, iterator: felt) {
if (iterator == array_length) {
return ();
}

assert array[iterator] = base;

return fill_array(array, base, array_length, iterator + 1);
}

func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
func run_0_10_3{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;

let (output: felt*) = alloc();
Expand All @@ -75,7 +65,7 @@ func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {

let n_bytes = 24;

let (res: felt*) = _keccak{keccak_ptr=keccak_output}(
let (res: felt*) = _keccak_0_10_3{keccak_ptr=keccak_output}(
inputs=inputs_start, n_bytes=n_bytes, state=state_start
);

Expand All @@ -86,3 +76,59 @@ func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {

return ();
}

func _block_permutation_cairo_keccak{output_ptr: felt*, keccak_ptr: felt*}() {
alloc_locals;
let output = output_ptr;
let keccak_ptr_start = keccak_ptr - KECCAK_STATE_SIZE_FELTS;
%{
from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
assert 0 <= _keccak_state_size_felts < 100
output_values = keccak_func(memory.get_range(
ids.keccak_ptr_start, _keccak_state_size_felts))
segments.write_arg(ids.output, output_values)
%}
let keccak_ptr = keccak_ptr + KECCAK_STATE_SIZE_FELTS;

return ();
}

func run_cairo_keccak{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;

let (output: felt*) = alloc();
let keccak_output = output;

let (inputs: felt*) = alloc();
let inputs_start = inputs;
fill_array(inputs, 9, 3, 0);

let (state: felt*) = alloc();
let state_start = state;
fill_array(state, 5, 25, 0);

let n_bytes = 24;

_prepare_block{keccak_ptr=output_ptr}(inputs=inputs, n_bytes=n_bytes, state=state);
_block_permutation_cairo_keccak{keccak_ptr=output_ptr}();

return ();
}

func fill_array(array: felt*, base: felt, array_length: felt, iterator: felt) {
if (iterator == array_length) {
return ();
}

assert array[iterator] = base;

return fill_array(array, base, array_length, iterator + 1);
}

func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
run_0_10_3();
run_cairo_keccak();

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use crate::{
blake2s_add_uint256, blake2s_add_uint256_bigend, compute_blake2s, finalize_blake2s,
},
cairo_keccak::keccak_hints::{
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,
block_permutation_v1, block_permutation_v2, 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,
Expand Down Expand Up @@ -530,8 +530,11 @@ impl HintProcessor for BuiltinHintProcessor {
constants,
)
}
hint_code::BLOCK_PERMUTATION | hint_code::BLOCK_PERMUTATION_WHITELIST => {
block_permutation(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants)
hint_code::BLOCK_PERMUTATION | hint_code::BLOCK_PERMUTATION_WHITELIST_V1 => {
block_permutation_v1(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants)
}
hint_code::BLOCK_PERMUTATION_WHITELIST_V2 => {
block_permutation_v2(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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::stdlib::{
prelude::*,
};
use crate::{
felt::Felt252,
hint_processor::{
builtin_hint_processor::hint_utils::{
get_integer_from_var_name, get_ptr_from_var_name, insert_value_into_ap,
Expand All @@ -17,7 +18,6 @@ use crate::{
vm_core::VirtualMachine,
},
};
use felt::Felt252;
use num_traits::{ToPrimitive, Zero};

// Constants in package "starkware.cairo.common.cairo_keccak.keccak".
Expand Down Expand Up @@ -123,7 +123,16 @@ pub fn compare_keccak_full_rate_in_bytes_nondet(
}

/*
Implements hint:
Implements hints:
%{
from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
assert 0 <= _keccak_state_size_felts < 100
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)
%}
%{
from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
Expand All @@ -134,7 +143,7 @@ Implements hint:
segments.write_arg(ids.keccak_ptr, output_values)
%}
*/
pub fn block_permutation(
pub(crate) fn block_permutation_v1(
vm: &mut VirtualMachine,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
Expand All @@ -143,7 +152,6 @@ pub fn block_permutation(
let keccak_state_size_felts = constants
.get(KECCAK_STATE_SIZE_FELTS)
.ok_or(HintError::MissingConstant(KECCAK_STATE_SIZE_FELTS))?;

if keccak_state_size_felts >= &Felt252::new(100_i32) {
return Err(HintError::InvalidKeccakStateSizeFelt252s(
keccak_state_size_felts.clone(),
Expand All @@ -157,7 +165,6 @@ pub fn block_permutation(
(keccak_ptr - keccak_state_size_felts)?,
keccak_state_size_felts,
);

let mut u64_values = maybe_reloc_vec_to_u64_array(&values)?
.try_into()
.map_err(|_| VirtualMachineError::SliceToArrayError)?;
Expand All @@ -174,6 +181,53 @@ pub fn block_permutation(
Ok(())
}

/*
Implements hint:
%{
from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
assert 0 <= _keccak_state_size_felts < 100
output_values = keccak_func(memory.get_range(
ids.keccak_ptr_start, _keccak_state_size_felts))
segments.write_arg(ids.output, output_values)
%}
*/
pub(crate) fn block_permutation_v2(
vm: &mut VirtualMachine,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
constants: &HashMap<String, Felt252>,
) -> Result<(), HintError> {
let keccak_state_size_felts = constants
.get(KECCAK_STATE_SIZE_FELTS)
.ok_or(HintError::MissingConstant(KECCAK_STATE_SIZE_FELTS))?;
if keccak_state_size_felts >= &Felt252::from(100_i32) {
return Err(HintError::InvalidKeccakStateSizeFelt252s(
keccak_state_size_felts.clone(),
));
}

let keccak_ptr = get_ptr_from_var_name("keccak_ptr_start", vm, ids_data, ap_tracking)?;

let keccak_state_size_felts = keccak_state_size_felts.to_usize().unwrap();
let values = vm.get_range(keccak_ptr, keccak_state_size_felts);
let mut u64_values = maybe_reloc_vec_to_u64_array(&values)?
.try_into()
.map_err(|_| VirtualMachineError::SliceToArrayError)?;

// this function of the keccak crate is the one used instead of keccak_func from
// keccak_utils.py
keccak::f1600(&mut u64_values);

let bigint_values = u64_array_to_mayberelocatable_vec(&u64_values);

let output = get_ptr_from_var_name("output", vm, ids_data, ap_tracking)?;
vm.write_arg(output, &bigint_values)
.map_err(HintError::Memory)?;

Ok(())
}

fn cairo_keccak_finalize(
vm: &mut VirtualMachine,
ids_data: &HashMap<String, HintReference>,
Expand Down
9 changes: 8 additions & 1 deletion src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,14 +735,21 @@ segments.write_arg(ids.keccak_ptr, output_values)"#;

// The 0.10.3 whitelist uses this variant (instead of the one used by the common library), but both hints have the same behaviour
// We should check for future refactors that may discard one of the variants
pub const BLOCK_PERMUTATION_WHITELIST: &str = r#"from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
pub const BLOCK_PERMUTATION_WHITELIST_V1: &str = r#"from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
assert 0 <= _keccak_state_size_felts < 100
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 BLOCK_PERMUTATION_WHITELIST_V2: &str = r#"from starkware.cairo.common.cairo_keccak.keccak_utils import keccak_func
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
assert 0 <= _keccak_state_size_felts < 100
output_values = keccak_func(memory.get_range(
ids.keccak_ptr_start, _keccak_state_size_felts))
segments.write_arg(ids.output, output_values)"#;

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)
Expand Down
2 changes: 1 addition & 1 deletion src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ fn mul_s_inv() {
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn keccak_alternative_hint() {
let program_data = include_bytes!("../../cairo_programs/_keccak_alternative_hint.json");
run_program_simple_with_memory_holes(program_data.as_slice(), 23);
run_program_simple_with_memory_holes(program_data.as_slice(), 24);
}

#[test]
Expand Down

1 comment on commit 1feaba0

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.

Benchmark suite Current: 1feaba0 Previous: 5ff1a1d Ratio
parse program 24922640 ns/iter (± 679713) 18726885 ns/iter (± 100227) 1.33
build runner 3536217 ns/iter (± 140502) 2498968 ns/iter (± 1236) 1.42

This comment was automatically generated by workflow using github-action-benchmark.

CC: @unbalancedparentheses

Please sign in to comment.