Skip to content

Commit

Permalink
Merge pull request #2 from HerodotusDev/fix/cut_assign
Browse files Browse the repository at this point in the history
fix: key verification
  • Loading branch information
feltroidprime committed May 8, 2024
2 parents 76d11f9 + 7f338f8 commit 4dcb024
Show file tree
Hide file tree
Showing 76 changed files with 383 additions and 42,425 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ jobs:
- name: Run Cairo tests
env:
RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }}
run: source ./tools/make/cairo_tests.sh
run: source ./tools/make/cairo_tests.sh
- name: Run MPT tests
run: source ./tools/make/fuzzer.sh tests/fuzzing/mpt.cairo --ci
102 changes: 51 additions & 51 deletions lib/mpt.cairo

Large diffs are not rendered by default.

243 changes: 186 additions & 57 deletions lib/rlp_little.cairo

Large diffs are not rendered by default.

43 changes: 24 additions & 19 deletions lib/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ const DIV_32_MINUS_1 = DIV_32 - 1;

// Takes the hex representation and count the number of zeroes.
// Ie: returns the number of trailing zeroes bytes.
// If x is 0, returns 0.
// If x is 0, returns 16.
func count_trailing_zeroes_128{bitwise_ptr: BitwiseBuiltin*}(x: felt, pow2_array: felt*) -> (
res: felt
) {
if (x == 0) {
return (res=0);
return (res=16);
}
alloc_locals;
local trailing_zeroes_bytes;
%{
from tools.py.utils import count_trailing_zero_bytes_from_int
ids.trailing_zeroes_bytes = count_trailing_zero_bytes_from_int(ids.x)
print(f"Input: {hex(ids.x)}_{ids.trailing_zeroes_bytes}bytes")
#print(f"Input: {hex(ids.x)}_{ids.trailing_zeroes_bytes}Tr_Zerobytes")
%}
// Verify.
if (trailing_zeroes_bytes == 0) {
Expand All @@ -55,6 +55,7 @@ func count_trailing_zeroes_128{bitwise_ptr: BitwiseBuiltin*}(x: felt, pow2_array
}
}
}

// Returns the number of bytes in a number with n_bits bits.
// Assumptions:
// - 0 <= n_bits < 8 * RC_BOUND
Expand Down Expand Up @@ -136,24 +137,23 @@ func uint128_reverse_endian_no_padding{range_check_ptr, bitwise_ptr: BitwiseBuil
x: felt, pow2_array: felt*
) -> (res: felt, n_bytes: felt) {
alloc_locals;
// %{ import math %}
let (num_bytes_input) = get_felt_n_bytes_128(x, pow2_array);
let (x_reversed) = word_reverse_endian(x);
let (num_bytes_reversed) = get_felt_n_bytes_128(x_reversed, pow2_array);
let (trailing_zeroes_input) = count_trailing_zeroes_128(x, pow2_array);

if (num_bytes_input != num_bytes_reversed) {
%{ print(f"\tinput: {hex(ids.x)}_{ids.num_bytes_input}bytes") %}
%{ print(f"\treversed: {hex(ids.x_reversed)}_{ids.num_bytes_reversed}bytes") %}
// %{ print(f"\tinput128: {hex(ids.x)}_{ids.num_bytes_input}bytes") %}
// %{ print(f"\treversed: {hex(ids.x_reversed)}_{ids.num_bytes_reversed}bytes") %}
let (x_reversed, r) = bitwise_divmod(
x_reversed,
pow2_array[8 * (num_bytes_reversed - num_bytes_input + trailing_zeroes_input)],
);
assert r = 0; // Sanity check.
%{
import math
print(f"\treversed_fixed: {hex(ids.x_reversed)}_{math.ceil(ids.x_reversed.bit_length() / 8)}bytes")
%}
// %{
// import math
// print(f"\treversed_fixed: {hex(ids.x_reversed)}_{math.ceil(ids.x_reversed.bit_length() / 8)}bytes")
// %}
return (res=x_reversed, n_bytes=num_bytes_input);
}
return (res=x_reversed, n_bytes=num_bytes_input);
Expand All @@ -166,15 +166,13 @@ func uint256_reverse_endian_no_padding{range_check_ptr, bitwise_ptr: BitwiseBuil
alloc_locals;
if (x.high != 0) {
let (high_reversed, n_bytes_high) = uint128_reverse_endian_no_padding(x.high, pow2_array);
%{ print(f"High: {hex(ids.high_reversed)}_{ids.high_reversed.bit_length()}b {ids.n_bytes_high}bytes") %}
let (low_reversed, n_bytes_low) = uint128_reverse_endian_no_padding(x.low, pow2_array);
%{ print(f"Low: {hex(ids.low_reversed)}_{ids.low_reversed.bit_length()}b {ids.n_bytes_low}bytes") %}
let low_reversed = low_reversed * pow2_array[8 * (16 - n_bytes_low)]; // Righ pad with 0 to make it 128 bits.
%{ print(f"Low: {hex(ids.low_reversed)}_{ids.low_reversed.bit_length()}b") %}
// %{ print(f"High_Rev: {hex(ids.high_reversed)}_{ids.high_reversed.bit_length()}b {ids.n_bytes_high}bytes") %}
let (low_reversed) = word_reverse_endian(x.low);
// %{ print(f"Low_rev: {hex(ids.low_reversed)}_{ids.low_reversed.bit_length()}b") %}

let (q, r) = bitwise_divmod(low_reversed, pow2_array[8 * (16 - n_bytes_high)]);
%{ print(f"Q: {hex(ids.q)}") %}
%{ print(f"R: {hex(ids.r)}") %}
// %{ print(f"Q: {hex(ids.q)}") %}
// %{ print(f"R: {hex(ids.r)}") %}
return (
res=Uint256(low=high_reversed + pow2_array[8 * n_bytes_high] * r, high=q),
n_bytes=16 + n_bytes_high,
Expand Down Expand Up @@ -296,10 +294,13 @@ func write_felt_array_to_dict_keys{dict_end: DictAccess*}(array: felt*, index: f
// Params:
// - x: felt - Input value.
// Assumptions for the caller:
// - 1 <= x < 2^127
// - 0 <= x < 2^127
// Returns:
// - bit_length: felt - Number of bits in x.
func get_felt_bitlength{range_check_ptr, pow2_array: felt*}(x: felt) -> felt {
if (x == 0) {
return 0;
}
alloc_locals;
local bit_length;
%{
Expand All @@ -324,12 +325,16 @@ func get_felt_bitlength{range_check_ptr, pow2_array: felt*}(x: felt) -> felt {
// Params:
// - x: felt - Input value.
// Assumptions for the caller:
// - 1 <= x < 2^128
// - 0 <= x < 2^128
// Returns:
// - bit_length: felt - Number of bits in x.
func get_felt_bitlength_128{range_check_ptr, pow2_array: felt*}(x: felt) -> felt {
if (x == 0) {
return 0;
}
alloc_locals;
local bit_length;

%{
x = ids.x
ids.bit_length = x.bit_length()
Expand Down
124 changes: 59 additions & 65 deletions tests/cairo_programs/reverse_uint256.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,63 +8,76 @@ from lib.utils import pow2alloc128, uint256_reverse_endian_no_padding, Uint256
func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;
let (pow2_array: felt*) = pow2alloc128();
// test_reverse(n_bits_index=1, pow2_array=pow2_array);
// %{ print("End tests!") %}
local x: Uint256;

// Some edge cases.
local x1: Uint256;
local x2: Uint256;
local x3: Uint256;
local x4: Uint256;
local x5: Uint256;
local x6: Uint256;
local x7: Uint256;
%{
import random
random.seed(0)
from tools.py.utils import split_128
# Used for the sanity check
def parse_int_to_bytes(x:int)-> bytes:
hex_str = hex(x)[2:]
if len(hex_str)%2==1:
hex_str = '0'+hex_str
return bytes.fromhex(hex_str)
from tools.py.utils import split_128, parse_int_to_bytes, count_leading_zero_nibbles_from_hex

x = 0x5553adf1a587bc5465b321660008c4c2e825bd3df2d2ccf001a009f3
input_bytes = parse_int_to_bytes(x)
print(f"input: {input_bytes}")
ids.x.low, ids.x.high = split_128(x)
print(f"input : {hex(x)}_{x.bit_length()}b")
print(f"input: {hex(ids.x.high)}_{ids.x.high.bit_length()}b {hex(ids.x.low)}_{ids.x.low.bit_length()}b")
%}
let (res, n_bytes) = uint256_reverse_endian_no_padding(x, pow2_array);
%{
# Test.
res_bytes = parse_int_to_bytes(ids.res.low + 2**128 * ids.res.high)
print(f"output : {hex(ids.res.high)}_{ids.res.high.bit_length()}b {hex(ids.res.low)}_{ids.res.low.bit_length()}b")
print(f"output: {res_bytes}")
# The input and output bytes should be the same, reversed.
assert input_bytes[::-1] == res_bytes, f"{input_bytes[::-1]} != {res_bytes}"
# The number of bytes returned should be the same as the number of bytes in the input.
assert ids.n_bytes == len(input_bytes)==len(res_bytes), f"{ids.n_bytes} != {len(input_bytes)} != {len(res_bytes)}"
%}
local x: Uint256;
%{
print("Second edge case")
x = 0xb847b60dcb5d984fc2a1ca0040a550cd3c4ac0adef268ded1249e1ae
input_bytes = parse_int_to_bytes(x)
print(f"input: {input_bytes}")
ids.x.low, ids.x.high = split_128(x)
print(f"input : {hex(x)}_{x.bit_length()}b")
print(f"input: {hex(ids.x.high)}_{ids.x.high.bit_length()}b {hex(ids.x.low)}_{ids.x.low.bit_length()}b")
x1 = 0x5553adf1a587bc5465b321660008c4c2e825bd3df2d2ccf001a009f3
x2 = 0xb847b60dcb5d984fc2a1ca0040a550cd3c4ac0adef268ded1249e1ae
x3 = 0xd4ae28bf208da8ad396463110021760d8278befbac8b4ecacb7c6e00
x4 = 0x12345600
x5 = 0x12401
x6 = 0x1240100
x7 = 0x124010

ids.x1.low, ids.x1.high = split_128(x1)
ids.x2.low, ids.x2.high = split_128(x2)
ids.x3.low, ids.x3.high = split_128(x3)
ids.x4.low, ids.x4.high = split_128(x4)
ids.x5.low, ids.x5.high = split_128(x5)
ids.x6.low, ids.x6.high = split_128(x6)
ids.x7.low, ids.x7.high = split_128(x7)

def test_function(test_input:int, test_output:int):
input_bytes = parse_int_to_bytes(test_input)
res_bytes = parse_int_to_bytes(test_output)

print(f"test_input: {input_bytes}")
print(f"test_output: {res_bytes}")

expected_output = input_bytes[::-1] # Reverse the input bytes.
# Trim leading zeroes from expected output :
expected_output = expected_output.lstrip(b'\x00')
# The input and output bytes should be the same, reversed.
assert expected_output == res_bytes, f"{expected_output} != {res_bytes}"
%}

test_reverse_single(x=x1, pow2_array=pow2_array);
test_reverse_single(x=x2, pow2_array=pow2_array);
test_reverse_single(x=x3, pow2_array=pow2_array);
test_reverse_single(x=x4, pow2_array=pow2_array);
test_reverse_single(x=x5, pow2_array=pow2_array);
test_reverse_single(x=x6, pow2_array=pow2_array);
test_reverse_single(x=x7, pow2_array=pow2_array);

test_reverse(n_bits_index=1, pow2_array=pow2_array);

%{ print("End tests!") %}

return ();
}

func test_reverse_single{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
x: Uint256, pow2_array: felt*
) {
alloc_locals;
let (res, n_bytes) = uint256_reverse_endian_no_padding(x, pow2_array);
%{
# Test.
res_bytes = parse_int_to_bytes(ids.res.low + 2**128 * ids.res.high)
print(f"output : {hex(ids.res.high)}_{ids.res.high.bit_length()}b {hex(ids.res.low)}_{ids.res.low.bit_length()}b")
print(f"output: {res_bytes}")
# The input and output bytes should be the same, reversed.
assert input_bytes[::-1] == res_bytes, f"{input_bytes[::-1]} != {res_bytes}"
# The number of bytes returned should be the same as the number of bytes in the input.
assert ids.n_bytes == len(input_bytes)==len(res_bytes), f"{ids.n_bytes} != {len(input_bytes)} != {len(res_bytes)}"
test_function(test_input=ids.x.low + 2**128*ids.x.high, test_output=ids.res.low+2**128*ids.res.high)
%}
return ();
}

func test_reverse_inner{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
n_bits_in_input: felt, pow2_array: felt*
) {
Expand All @@ -73,32 +86,13 @@ func test_reverse_inner{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
%{
import random
random.seed(0)
from tools.py.utils import split_128
# Used for the sanity check
def parse_int_to_bytes(x:int)-> bytes:
hex_str = hex(x)[2:]
if len(hex_str)%2==1:
hex_str = '0'+hex_str
return bytes.fromhex(hex_str)


x = random.randint(2**(ids.n_bits_in_input - 1), 2**ids.n_bits_in_input - 1)
input_bytes = parse_int_to_bytes(x)

print(f"N bits in input: {ids.n_bits_in_input}")
print(f"input: {input_bytes}")
ids.x.low, ids.x.high = split_128(x)
print(f"input: {hex(ids.x.low + 2**128 * ids.x.high)}")
%}
let (res, n_bytes) = uint256_reverse_endian_no_padding(x, pow2_array);
%{
# Test.
res_bytes = parse_int_to_bytes(ids.res.low + 2**128 * ids.res.high)
print(f"output: {res_bytes}")
# The input and output bytes should be the same, reversed.
assert input_bytes[::-1] == res_bytes, f"{input_bytes[::-1]} != {res_bytes}"
# The number of bytes returned should be the same as the number of bytes in the input.
assert ids.n_bytes == len(input_bytes)==len(res_bytes), f"{ids.n_bytes} != {len(input_bytes)} != {len(res_bytes)}"
test_function(test_input=ids.x.low + 2**128*ids.x.high, test_output=ids.res.low+2**128*ids.res.high)
%}
return ();
}
Expand Down
Loading

0 comments on commit 4dcb024

Please sign in to comment.