Skip to content
This repository has been archived by the owner on Jan 9, 2025. It is now read-only.

Fix possible overflow in decode_raw #1383

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
14 changes: 11 additions & 3 deletions src/utils/rlp.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ namespace RLP {
if (is_le_191 != FALSE) {
local len_bytes_count = prefix - 0xb7;
let string_len = Helpers.bytes_to_felt(len_bytes_count, data + 1);
assert [range_check_ptr] = string_len;
let range_check_ptr = range_check_ptr + 1;
return (TYPE_STRING, 1 + len_bytes_count, string_len);
}

Expand All @@ -60,7 +62,11 @@ namespace RLP {

local len_bytes_count = prefix - 0xf7;
let list_len = Helpers.bytes_to_felt(len_bytes_count, data + 1);
return (TYPE_LIST, 1 + len_bytes_count, list_len);
tempvar offset = 1 + len_bytes_count;
assert [range_check_ptr] = offset;
assert [range_check_ptr + 1] = list_len;
let range_check_ptr = range_check_ptr + 2;
return (TYPE_LIST, offset, list_len);
obatirou marked this conversation as resolved.
Show resolved Hide resolved
}

// @notice Decodes a Recursive Length Prefix (RLP) encoded data.
Expand All @@ -82,9 +88,11 @@ namespace RLP {
return 0;
}

let (rlp_type, offset, len) = decode_type(data);
local remaining_data_len = data_len - len - offset;
with_attr error_message("RLP data too short for declared length") {
let (rlp_type, offset, len) = decode_type(data);
assert [range_check_ptr] = offset + len;
local remaining_data_len = data_len - [range_check_ptr];
let range_check_ptr = range_check_ptr + 1;
assert_nn(remaining_data_len);
}

Expand Down
7 changes: 7 additions & 0 deletions tests/src/utils/test_rlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from hypothesis import given
from hypothesis.strategies import binary, lists, recursive
from rlp import codec, decode, encode
from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME

from tests.utils.constants import TRANSACTIONS
from tests.utils.errors import cairo_error
Expand Down Expand Up @@ -40,6 +41,12 @@ def test_should_raise_when_malicious_prover_fills_data(self, cairo_run, data):
data=list(encode(data)),
)

def test_should_raise_when_decoded_params_overflow(self, cairo_run):
size = bytes.fromhex(f"{DEFAULT_PRIME - 1:064x}")
data = [len(size) + 0xF7] + list(size)
with cairo_error("RLP data too short for declared length"):
cairo_run("test__decode_raw", data=data)

class TestDecode:
@given(data=recursive(binary(), lists))
def test_should_match_decode_reference_implementation(self, cairo_run, data):
Expand Down
11 changes: 11 additions & 0 deletions tests/src/utils/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,14 @@ func test__split_word_little{range_check_ptr}() -> felt* {
Helpers.split_word_little(value, len, dst);
return dst;
}

func test__bytes_to_felt() -> felt {
tempvar len;
let (ptr) = alloc();
%{
ids.len = len(program_input["data"])
segments.write_arg(ids.ptr, program_input["data"])
%}
let res = Helpers.bytes_to_felt(len, ptr);
return res;
}
9 changes: 9 additions & 0 deletions tests/src/utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ethereum.cancun.vm.runtime import get_valid_jump_destinations
from hypothesis import given, settings
from hypothesis import strategies as st
from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME

from kakarot_scripts.utils.kakarot import get_contract
from tests.utils.errors import cairo_error
Expand Down Expand Up @@ -232,3 +233,11 @@ def test_should_raise_when_len_ge_32_split_word_little(
):
with cairo_error("len must be < 32"):
cairo_run("test__split_word_little", value=value, length=length)


class TestBytesToFelt:

@given(data=st.binary(min_size=0, max_size=35))
def test_should_convert_bytes_to_felt_with_overflow(self, cairo_run, data):
output = cairo_run("test__bytes_to_felt", data=list(data))
assert output == int.from_bytes(data, byteorder="big") % DEFAULT_PRIME
Loading