Skip to content

Commit

Permalink
Merge branch 'main' of github.com:lambdaclass/cairo-rs into new-hint-39
Browse files Browse the repository at this point in the history
  • Loading branch information
fmoletta committed Apr 25, 2023
2 parents 8efc71c + 50c90d9 commit 42d8f05
Show file tree
Hide file tree
Showing 57 changed files with 1,204 additions and 572 deletions.
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

#### Upcoming Changes

<<<<<<< HEAD
* Implement hint on ec_recover.json whitelist [#1037](https://github.com/lambdaclass/cairo-rs/pull/1037):
=======
* Implement hint for `starkware.cairo.common.cairo_keccak.keccak.finalize_keccak` as described by whitelist `starknet/security/whitelists/cairo_keccak.json` [#1041](https://github.com/lambdaclass/cairo-rs/pull/1041)
>>>>>>> 50c90d944bc090578824bb50bed1b1ada5a5fbc0
`BuiltinHintProcessor` now supports the following hint:

```python
%{
<<<<<<< HEAD
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div

Expand All @@ -17,6 +22,16 @@
m = pack(ids.m, PRIME)

value = res = product % m
=======
# Add dummy pairs of input and output.
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
_block_size = int(ids.BLOCK_SIZE)
assert 0 <= _keccak_state_size_felts < 100
assert 0 <= _block_size < 1000
inp = [0] * _keccak_state_size_felts
padding = (inp + keccak_func(inp)) * _block_size
segments.write_arg(ids.keccak_ptr_end, padding)
>>>>>>> 50c90d944bc090578824bb50bed1b1ada5a5fbc0
%}
```

Expand Down Expand Up @@ -244,6 +259,43 @@
ids.res.high = res_split[1]
```

* Add missing hint on vrf.json lib [#1030](https://github.com/lambdaclass/cairo-rs/pull/1030):

`BuiltinHintProcessor` now supports the following hint:

```python
def split(num: int, num_bits_shift: int, length: int):
a = []
for _ in range(length):
a.append( num & ((1 << num_bits_shift) - 1) )
num = num >> num_bits_shift
return tuple(a)

def pack(z, num_bits_shift: int) -> int:
limbs = (z.low, z.high)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))

def pack_extended(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2, z.d3)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))

x = pack_extended(ids.x, num_bits_shift = 128)
div = pack(ids.div, num_bits_shift = 128)

quotient, remainder = divmod(x, div)

quotient_split = split(quotient, num_bits_shift=128, length=4)

ids.quotient.d0 = quotient_split[0]
ids.quotient.d1 = quotient_split[1]
ids.quotient.d2 = quotient_split[2]
ids.quotient.d3 = quotient_split[3]

remainder_split = split(remainder, num_bits_shift=128, length=2)
ids.remainder.low = remainder_split[0]
ids.remainder.high = remainder_split[1]
```

* Add method `Program::data_len(&self) -> usize` to get the number of data cells in a given program [#1022](https://github.com/lambdaclass/cairo-rs/pull/1022)

* Add missing hint on uint256_improvements lib [#1013](https://github.com/lambdaclass/cairo-rs/pull/1013):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.bool import TRUE
from cairo_programs.uint384 import uint384_lib, Uint384, Uint384_expand
from cairo_programs.uint384_extension import uint384_extension_lib
from cairo_programs.uint384 import u384, Uint384, Uint384_expand
from cairo_programs.uint384_extension import u384_ext
from cairo_programs.field_arithmetic import field_arithmetic


func run_get_square{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(prime: Uint384, generator: Uint384, num: Uint384, iterations: felt) {
func run_get_square{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
prime: Uint384, generator: Uint384, num: Uint384, iterations: felt
) {
alloc_locals;
if (iterations == 0) {
return ();
}

let (square) = field_arithmetic.mul(num, num, prime);
let (square) = field_arithmetic.mul(num, num, prime);

let (success, root_1) = field_arithmetic.get_square_root(square, prime, generator);
assert success = 1;

// We calculate this before in order to prevent revoked range_check_ptr reference due to branching
let (root_2) = uint384_lib.sub(prime, root_1);
let (is_first_root) = uint384_lib.eq(root_1, num);
let (root_2) = u384.sub(prime, root_1);
let (is_first_root) = u384.eq(root_1, num);

if ( is_first_root != TRUE) {
if (is_first_root != TRUE) {
assert root_2 = num;
}

return run_get_square(prime, generator, square, iterations -1);
return run_get_square(prime, generator, square, iterations - 1);
}

func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() {
let p = Uint384(18446744069414584321, 0, 0); // Goldilocks Prime
let p = Uint384(18446744069414584321, 0, 0); // Goldilocks Prime
let x = Uint384(5, 0, 0);
let g = Uint384(7, 0, 0);
run_get_square(p, g, x, 100);
Expand Down
60 changes: 60 additions & 0 deletions cairo_programs/cairo_finalize_keccak_block_size_1000.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
%builtins range_check bitwise

from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.cairo_keccak.keccak import _finalize_keccak_inner, cairo_keccak, BLOCK_SIZE, KECCAK_STATE_SIZE_FELTS
from starkware.cairo.common.math import unsigned_div_rem
from starkware.cairo.common.uint256 import Uint256

// Verifies that the results of cairo_keccak() are valid. For optimization, this can be called only
// once after all the keccak calculations are completed.
// Version copied from starknet/security/whitelists/cairo_keccak.json
func finalize_keccak{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
keccak_ptr_start: felt*, keccak_ptr_end: felt*
) {
alloc_locals;

tempvar n = (keccak_ptr_end - keccak_ptr_start) / (2 * KECCAK_STATE_SIZE_FELTS);
if (n == 0) {
return ();
}

%{
# Add dummy pairs of input and output.
_keccak_state_size_felts = int(ids.KECCAK_STATE_SIZE_FELTS)
_block_size = int(ids.BLOCK_SIZE)
assert 0 <= _keccak_state_size_felts < 100
assert 0 <= _block_size < 1000
inp = [0] * _keccak_state_size_felts
padding = (inp + keccak_func(inp)) * _block_size
segments.write_arg(ids.keccak_ptr_end, padding)
%}

// Compute the amount of blocks (rounded up).
let (local q, r) = unsigned_div_rem(n + BLOCK_SIZE - 1, BLOCK_SIZE);
_finalize_keccak_inner(keccak_ptr_start, n=q);
return ();
}

func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;

let (keccak_ptr: felt*) = alloc();
let keccak_ptr_start = keccak_ptr;

let (inputs: felt*) = alloc();

assert inputs[0] = 8031924123371070792;
assert inputs[1] = 560229490;

let n_bytes = 16;

let (res: Uint256) = cairo_keccak{keccak_ptr=keccak_ptr}(inputs=inputs, n_bytes=n_bytes);

assert res.low = 293431514620200399776069983710520819074;
assert res.high = 317109767021952548743448767588473366791;

finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr);

return ();
}
46 changes: 24 additions & 22 deletions cairo_programs/field_arithmetic.cairo
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
%builtins range_check bitwise

// Code taken from https://github.com/NethermindEth/research-basic-Cairo-operations-big-integers/blob/fbf532651959f27037d70cd70ec6dbaf987f535c/lib/field_arithmetic.cairo
from starkware.cairo.common.bitwise import bitwise_and, bitwise_or, bitwise_xor
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.math import assert_in_range, assert_le, assert_nn_le, assert_not_zero
from starkware.cairo.common.math_cmp import is_le
from starkware.cairo.common.pow import pow
from starkware.cairo.common.registers import get_ap, get_fp_and_pc
from cairo_programs.uint384 import uint384_lib, Uint384, Uint384_expand, SHIFT, HALF_SHIFT
from cairo_programs.uint384_extension import uint384_extension_lib, Uint768
from cairo_programs.uint384 import u384, Uint384, Uint384_expand, SHIFT, HALF_SHIFT
from cairo_programs.uint384_extension import u384_ext, Uint768

// Functions for operating elements in a finite field F_p (i.e. modulo a prime p), with p of at most 384 bits
namespace field_arithmetic {
// Computes a * b modulo p
func mul{range_check_ptr}(a: Uint384, b: Uint384, p: Uint384) -> (res: Uint384) {
let (low: Uint384, high: Uint384) = uint384_lib.mul_d(a, b);
let (low: Uint384, high: Uint384) = u384.mul_d(a, b);
let full_mul_result: Uint768 = Uint768(low.d0, low.d1, low.d2, high.d0, high.d1, high.d2);
let (
quotient: Uint768, remainder: Uint384
) = uint384_extension_lib.unsigned_div_rem_uint768_by_uint384(full_mul_result, p);
let (quotient: Uint768, remainder: Uint384) = u384_ext.unsigned_div_rem_uint768_by_uint384(
full_mul_result, p
);
return (remainder,);
}

// Computes a**2 modulo p
func square{range_check_ptr}(a: Uint384, p: Uint384) -> (res: Uint384) {
let (low: Uint384, high: Uint384) = uint384_lib.square_e(a);
let (low: Uint384, high: Uint384) = u384.square_e(a);
let full_mul_result: Uint768 = Uint768(low.d0, low.d1, low.d2, high.d0, high.d1, high.d2);
let (
quotient: Uint768, remainder: Uint384
) = uint384_extension_lib.unsigned_div_rem_uint768_by_uint384(full_mul_result, p);
let (quotient: Uint768, remainder: Uint384) = u384_ext.unsigned_div_rem_uint768_by_uint384(
full_mul_result, p
);
return (remainder,);
}

Expand All @@ -43,7 +45,7 @@ namespace field_arithmetic {
alloc_locals;

// TODO: Create an equality function within field_arithmetic to avoid overflow bugs
let (is_zero) = uint384_lib.eq(x, Uint384(0, 0, 0));
let (is_zero) = u384.eq(x, Uint384(0, 0, 0));
if (is_zero == 1) {
return (1, Uint384(0, 0, 0));
}
Expand Down Expand Up @@ -101,22 +103,22 @@ namespace field_arithmetic {
// Verify that the values computed in the hint are what they are supposed to be
let (gx: Uint384) = mul(generator, x, p);
if (success_x == 1) {
uint384_lib.check(sqrt_x);
let (is_valid) = uint384_lib.lt(sqrt_x, p);
assert is_valid = 1;
u384.check(sqrt_x);
let (is_valid) = u384.lt(sqrt_x, p);
assert is_valid = 1;
let (sqrt_x_squared: Uint384) = mul(sqrt_x, sqrt_x, p);
// Note these checks may fail if the input x does not satisfy 0<= x < p
// TODO: Create a equality function within field_arithmetic to avoid overflow bugs
let (check_x) = uint384_lib.eq(x, sqrt_x_squared);
let (check_x) = u384.eq(x, sqrt_x_squared);
assert check_x = 1;
return (1, sqrt_x);
} else {
// In this case success_gx = 1
uint384_lib.check(sqrt_gx);
let (is_valid) = uint384_lib.lt(sqrt_gx, p);
assert is_valid = 1;
u384.check(sqrt_gx);
let (is_valid) = u384.lt(sqrt_gx, p);
assert is_valid = 1;
let (sqrt_gx_squared: Uint384) = mul(sqrt_gx, sqrt_gx, p);
let (check_gx) = uint384_lib.eq(gx, sqrt_gx_squared);
let (check_gx) = u384.eq(gx, sqrt_gx_squared);
assert check_gx = 1;
// No square roots were found
// Note that Uint384(0, 0, 0) is not a square root here, but something needs to be returned
Expand Down Expand Up @@ -158,7 +160,7 @@ namespace field_arithmetic {
ids.b_inverse_mod_p.d1 = b_inverse_mod_p_split[1]
ids.b_inverse_mod_p.d2 = b_inverse_mod_p_split[2]
%}
uint384_lib.check(b_inverse_mod_p);
u384.check(b_inverse_mod_p);
let (b_times_b_inverse) = mul(b, b_inverse_mod_p, p);
assert b_times_b_inverse = Uint384(1, 0, 0);

Expand All @@ -171,7 +173,7 @@ func test_field_arithmetics_extension_operations{range_check_ptr, bitwise_ptr: B
alloc_locals;
// Test get_square

//Small prime
// Small prime
let p_a = Uint384(7, 0, 0);
let x_a = Uint384(2, 0, 0);
let generator_a = Uint384(3, 0, 0);
Expand All @@ -183,7 +185,7 @@ func test_field_arithmetics_extension_operations{range_check_ptr, bitwise_ptr: B
assert r_a.d2 = 0;

// Goldilocks Prime
let p_b = Uint384(18446744069414584321, 0, 0); // Goldilocks Prime
let p_b = Uint384(18446744069414584321, 0, 0); // Goldilocks Prime
let x_b = Uint384(25, 0, 0);
let generator_b = Uint384(7, 0, 0);
let (s_b, r_b) = field_arithmetic.get_square_root(x_b, p_b, generator_b);
Expand Down
Loading

0 comments on commit 42d8f05

Please sign in to comment.