Skip to content

Commit

Permalink
fix: finalize dictionary in RIPEMD160 (#191)
Browse files Browse the repository at this point in the history
Closes #147

Finalize dict and set the pointer start to the correct value

Note to reviewer: this is a fix imported from C4 mitigation, ensure the
fix was correctly ported by looking at the corresponding issue and PR.
  • Loading branch information
obatirou authored Dec 3, 2024
1 parent c8657fb commit e9fe89d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 1 deletion.
2 changes: 2 additions & 0 deletions cairo/src/precompiles/ripemd160.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,10 @@ func finish{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
let (local arr_x: felt*) = alloc();
dict_to_array{dict_ptr=x}(arr_x, 16);
let (buf, bufsize) = compress(buf, bufsize, arr_x, 16);
default_dict_finalize(start, x, 0);
// reset dict to all 0.
let (x) = default_dict_new(0);
tempvar start = x;

dict_write{dict_ptr=x}(14, val);
dict_write{dict_ptr=x}(15, val_15);
Expand Down
20 changes: 20 additions & 0 deletions cairo/tests/src/precompiles/test_ripemd160.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from hypothesis import given, settings
from hypothesis.strategies import binary

from tests.utils.errors import cairo_error
from tests.utils.hints import insert_hint


@pytest.mark.slow
class TestRIPEMD160:
Expand All @@ -17,3 +20,20 @@ def test_ripemd160_should_return_correct_hash(self, cairo_run, msg_bytes):
expected_hash = ripemd160_crypto.hexdigest()

assert expected_hash.rjust(64, "0") == bytes(precompile_hash).hex()

def test_finalized_dict_ripemd160(self, cairo_program, cairo_run):
msg_bytes = bytes([0x00] * 57)
with (
insert_hint(
cairo_program,
"ripemd160.cairo:154",
"try:\n"
" dict_tracker = __dict_manager.get_tracker(ids.dict_ptr)\n"
" dict_tracker.data[ids.index_4] = 1\n"
"except Exception: pass\n",
),
cairo_error(
message="An ASSERT_EQ instruction failed"
), # fails with an assertion error from default_dict_finalize_inner
):
cairo_run("test__ripemd160", msg=list(msg_bytes))
2 changes: 1 addition & 1 deletion cairo/tests/utils/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ def cairo_error(message=None):
return
error = re.search(r"Error message: (.*)", str(e.value))
error = error.group(1) if error else str(e.value)
assert message == error, f"Expected {message}, got {error}"
assert message in error, f"Expected {message}, got {error}"
finally:
pass
30 changes: 30 additions & 0 deletions cairo/tests/utils/hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,36 @@ def patch_hint(program, hint, new_hint, scope: Optional[str] = None):
yield


@contextmanager
def insert_hint(program, location: str, hint):
"""
Insert a hint at a given location in the program.
The location should be file_name:line_number.
"""
instructions = {
index: loc
for index, loc in program.debug_info.instruction_locations.items()
if location in str(loc.inst)
}
if not instructions:
raise ValueError(f"Location {location} not found in program.")
pc, instruction = list(instructions.items())[0]
hint = CairoHint(
accessible_scopes=instruction.accessible_scopes,
flow_tracking_data=instruction.flow_tracking_data,
code=hint,
)
new_hints = program.hints.copy()
new_hints[pc] = [*new_hints.get(pc, []), hint]
with (
patch.object(instruction, "hints", new=new_hints.get(pc, [])),
patch.object(program, "hints", new=new_hints),
):
yield


def oracle(program, serde, main_path, gen_arg):

def _factory(ids, reference: Optional[str] = None):
Expand Down

0 comments on commit e9fe89d

Please sign in to comment.