Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hints): NewHint#67 cairo_keccak.json _block_permutation #1046

Merged
merged 5 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1076,4 +1091,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 @@ -18,9 +18,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 @@ -519,8 +519,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 @@ -728,14 +728,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