Skip to content

Commit

Permalink
refactor: bytes_i_to_uint256 (#1042)
Browse files Browse the repository at this point in the history
<!--- Please provide a general summary of your changes in the title
above -->

<!-- Give an estimate of the time you spent on this PR in terms of work
days.
Did you spend 0.5 days on this PR or rather 2 days?  -->

Time spent on this PR:

## Pull request type

<!-- Please try to limit your pull request to one type,
submit multiple pull requests if needed. -->

Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [x] Code style update (formatting, renaming)
- [x] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying,
or link to a relevant issue. -->

Resolves #897

## What is the new behavior?

<!-- Please describe the behavior or changes that are being added by
this PR. -->

- rename `bytes_i_to_uint256` to `bytes_big_endian_to_uint256`
- simplify boolean condition for `is_bytes_len_16_bytes_or_less`
- follow conventions by having `bytes_len` before `bytes`
- rename `compute_half_uint256` to `compute_half_uint256_from_bytes`
- improved readability for `pow256_rev`
- use `pow256_rev` instead of `pow` from starkware lib: from 2419 to
1261 steps

With `pow` from starkware lib
<img width="452" alt="before opti"
src="https://github.com/kkrt-labs/kakarot/assets/92337658/0c56d88b-834b-4fae-abba-a3e987955164">

With `pow256_rev`
<img width="536" alt="after opti"
src="https://github.com/kkrt-labs/kakarot/assets/92337658/f1489bc3-016d-4303-81f7-2b0e1df00fdd">

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/kkrt-labs/kakarot/1042)
<!-- Reviewable:end -->

---------

Co-authored-by: Clément Walter <clement0walter@gmail.com>
  • Loading branch information
obatirou and ClementWalter authored Apr 5, 2024
1 parent d18b637 commit 1904d37
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 76 deletions.
2 changes: 1 addition & 1 deletion src/kakarot/instructions/push_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace PushOperations {
let out_of_bounds = is_le(evm.message.bytecode_len, pc + i);
local len = (1 - out_of_bounds) * i + out_of_bounds * (evm.message.bytecode_len - pc);

let stack_element = Helpers.bytes_i_to_uint256(evm.message.bytecode + pc, len);
let stack_element = Helpers.bytes_to_uint256(len, evm.message.bytecode + pc);
Stack.push_uint256(stack_element);

let evm = EVM.increment_program_counter(evm, len);
Expand Down
10 changes: 5 additions & 5 deletions src/kakarot/precompiles/modexp.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ namespace PrecompileModExpUint256 {
let b_size: Uint256 = Helpers.bytes32_to_uint256(input);
let e_size: Uint256 = Helpers.bytes32_to_uint256(input + MOD_EXP_BYTES_LEN);
let m_size: Uint256 = Helpers.bytes32_to_uint256(input + MOD_EXP_BYTES_LEN * 2);
let b: Uint256 = Helpers.bytes_i_to_uint256(input + MOD_EXP_BYTES_LEN * 3, b_size.low);
let e: Uint256 = Helpers.bytes_i_to_uint256(
input + MOD_EXP_BYTES_LEN * 3 + b_size.low, e_size.low
let b: Uint256 = Helpers.bytes_to_uint256(b_size.low, input + MOD_EXP_BYTES_LEN * 3);
let e: Uint256 = Helpers.bytes_to_uint256(
e_size.low, input + MOD_EXP_BYTES_LEN * 3 + b_size.low
);
let m: Uint256 = Helpers.bytes_i_to_uint256(
input + MOD_EXP_BYTES_LEN * 3 + b_size.low + e_size.low, m_size.low
let m: Uint256 = Helpers.bytes_to_uint256(
m_size.low, input + MOD_EXP_BYTES_LEN * 3 + b_size.low + e_size.low
);
with_attr error_message("Kakarot: modexp failed") {
let (result) = ModExpHelpersUint256.uint256_mod_exp(b, e, m);
Expand Down
6 changes: 3 additions & 3 deletions src/utils/eth_transaction.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace EthTransaction {
let destination = Helpers.try_parse_destination_from_bytes(
sub_items[3].data_len, sub_items[3].data
);
let amount = Helpers.bytes_i_to_uint256(sub_items[4].data, sub_items[4].data_len);
let amount = Helpers.bytes_to_uint256(sub_items[4].data_len, sub_items[4].data);
let payload_len = sub_items[5].data_len;
let payload = sub_items[5].data;
let chain_id = Helpers.bytes_to_felt(sub_items[6].data_len, sub_items[6].data);
Expand Down Expand Up @@ -89,7 +89,7 @@ namespace EthTransaction {
let destination = Helpers.try_parse_destination_from_bytes(
sub_items[4].data_len, sub_items[4].data
);
let amount = Helpers.bytes_i_to_uint256(sub_items[5].data, sub_items[5].data_len);
let amount = Helpers.bytes_to_uint256(sub_items[5].data_len, sub_items[5].data);
let payload_len = sub_items[6].data_len;
let payload = sub_items[6].data;

Expand Down Expand Up @@ -140,7 +140,7 @@ namespace EthTransaction {
let destination = Helpers.try_parse_destination_from_bytes(
sub_items[5].data_len, sub_items[5].data
);
let amount = Helpers.bytes_i_to_uint256(sub_items[6].data, sub_items[6].data_len);
let amount = Helpers.bytes_to_uint256(sub_items[6].data_len, sub_items[6].data);
let payload_len = sub_items[7].data_len;
let payload = sub_items[7].data;
let (access_list: felt*) = alloc();
Expand Down
70 changes: 28 additions & 42 deletions src/utils/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.math import assert_le, split_felt, assert_nn_le, unsigned_div_rem
from starkware.cairo.common.math_cmp import is_le, is_nn
from starkware.cairo.common.memcpy import memcpy
from starkware.cairo.common.pow import pow
from starkware.cairo.common.uint256 import Uint256, uint256_check
from starkware.cairo.common.registers import get_label_location
from starkware.cairo.common.cairo_secp.bigint import BigInt3, bigint_to_uint256, uint256_to_bigint
Expand Down Expand Up @@ -102,36 +101,32 @@ namespace Helpers {
let res = Uint256(low=low, high=high);
return res;
}
// @notice This function is used to convert a sequence of i bytes to Uint256.
// @param val: pointer to the first byte.
// @param i: sequence size.
// @notice This function is used to convert bytes array in big-endian to Uint256.
// @dev The function is limited to 32 bytes or less.
// @param bytes_len: bytes array length.
// @param bytes: pointer to the first byte of the bytes array.
// @return res: Uint256 representation of the given input in bytes.
func bytes_i_to_uint256{range_check_ptr}(val: felt*, i: felt) -> Uint256 {
func bytes_to_uint256{range_check_ptr}(bytes_len: felt, bytes: felt*) -> Uint256 {
alloc_locals;

if (i == 0) {
if (bytes_len == 0) {
let res = Uint256(0, 0);
return res;
}

let is_sequence_32_bytes_or_less = is_le(i, 32);
with_attr error_message("number must be shorter than 32 bytes") {
assert is_sequence_32_bytes_or_less = 1;
}

let is_sequence_16_bytes_or_less = is_le(i, 16);
let is_bytes_len_16_bytes_or_less = is_le(bytes_len, 16);

// 1 - 16 bytes
if (is_sequence_16_bytes_or_less != FALSE) {
let (low) = compute_half_uint256(val=val, i=i, res=0);
if (is_bytes_len_16_bytes_or_less != FALSE) {
let low = bytes_to_felt(bytes_len, bytes);
let res = Uint256(low=low, high=0);
return res;
}

// 17 - 32 bytes
let (low) = compute_half_uint256(val=val + i - 16, i=16, res=0);
let (high) = compute_half_uint256(val=val, i=i - 16, res=0);
let low = bytes_to_felt(16, bytes + bytes_len - 16);
let high = bytes_to_felt(bytes_len - 16, bytes);
let res = Uint256(low=low, high=high);

return res;
Expand Down Expand Up @@ -169,15 +164,6 @@ namespace Helpers {
return (res=quotient);
}

func compute_half_uint256{range_check_ptr}(val: felt*, i: felt, res: felt) -> (res: felt) {
if (i == 1) {
return (res=res + [val]);
}
let (temp_pow) = pow(256, i - 1);
let (res) = compute_half_uint256(val + 1, i - 1, res + [val] * temp_pow);
return (res=res);
}

// @notice This function is used to convert a sequence of 8 bytes to a felt.
// @param val: pointer to the first byte.
// @return: felt representation of the input.
Expand Down Expand Up @@ -316,23 +302,23 @@ namespace Helpers {
return pow256_rev_address[i];
pow256_rev_table:
dw 340282366920938463463374607431768211456;
dw 1329227995784915872903807060280344576;
dw 5192296858534827628530496329220096;
dw 20282409603651670423947251286016;
dw 79228162514264337593543950336;
dw 309485009821345068724781056;
dw 1208925819614629174706176;
dw 4722366482869645213696;
dw 18446744073709551616;
dw 72057594037927936;
dw 281474976710656;
dw 1099511627776;
dw 4294967296;
dw 16777216;
dw 65536;
dw 256;
dw 1;
dw 256 ** 16;
dw 256 ** 15;
dw 256 ** 14;
dw 256 ** 13;
dw 256 ** 12;
dw 256 ** 11;
dw 256 ** 10;
dw 256 ** 9;
dw 256 ** 8;
dw 256 ** 7;
dw 256 ** 6;
dw 256 ** 5;
dw 256 ** 4;
dw 256 ** 3;
dw 256 ** 2;
dw 256 ** 1;
dw 256 ** 0;
}

// @notice Splits a felt into `len` bytes, big-endian, and outputs to `dst`.
Expand Down
33 changes: 9 additions & 24 deletions tests/src/utils/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,19 @@ from starkware.cairo.common.memset import memset
from utils.utils import Helpers
from kakarot.constants import Constants

func test__bytes_i_to_uint256{range_check_ptr}() {
func test__bytes_to_uint256{range_check_ptr}() -> Uint256 {
alloc_locals;

let (bytecode) = alloc();
assert bytecode[0] = 0x01;
assert bytecode[1] = 0x02;

let uint256 = Helpers.bytes_i_to_uint256(bytecode, 1);

assert_uint256_eq(uint256, Uint256(0x01, 0));

let uint256 = Helpers.bytes_i_to_uint256(bytecode, 2);

assert_uint256_eq(uint256, Uint256(0x0102, 0));

let (bytecode) = alloc();
memset(bytecode, 0xFF, 20);
let uint256 = Helpers.bytes_i_to_uint256(bytecode, 20);

assert_uint256_eq(uint256, Uint256(Constants.UINT128_MAX, 0xFFFFFFFF));

let (bytecode) = alloc();
memset(bytecode, 0xFF, 16);
let uint256 = Helpers.bytes_i_to_uint256(bytecode, 16);
tempvar word_len;
let (word) = alloc();
%{
ids.word_len = len(program_input["word"])
segments.write_arg(ids.word, program_input["word"])
%}

assert_uint256_eq(uint256, Uint256(Constants.UINT128_MAX, 0));
let res = Helpers.bytes_to_uint256(word_len, word);

return ();
return res;
}

func test__bytes_to_bytes4_array{range_check_ptr}() {
Expand Down
13 changes: 12 additions & 1 deletion tests/src/utils/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from math import ceil

import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
Expand Down Expand Up @@ -50,13 +52,22 @@
0x726C6400,
],
),
("test__bytes_i_to_uint256", [], []),
],
)
def test_utils(cairo_run, test_case, data, expected):
cairo_run(test_case, data=data, expected=expected)


@given(word=st.integers(min_value=0, max_value=2**256 - 1))
@settings(max_examples=20, deadline=None)
def test_bytes_to_uint256(cairo_run, word):
output = cairo_run(
"test__bytes_to_uint256",
word=int.to_bytes(word, ceil(word.bit_length() / 8), byteorder="big"),
)
assert int(output, 16) == word


@given(word=st.integers(min_value=0, max_value=2**128 - 1))
@settings(max_examples=20, deadline=None)
def test_should_return_bytes_used_in_128_word(cairo_run, word):
Expand Down

0 comments on commit 1904d37

Please sign in to comment.