Skip to content

Commit

Permalink
Feat(hints) 55, 56 & 57 (#1077)
Browse files Browse the repository at this point in the history
* Skeleton + hint55 implementation

* Refactor

* Implement hint66

* Hint 57

* Appease clippy

* Fix: change SECP_P_V2 instead of SECP_P

* Add integration tests

Also renamed:
 - `ASSIGN_PACK_MOD_SECP_PRIME_TO_X` -> `IS_ZERO_PACK_ED25519`
 - `ASSIGN_PACK_MOD_SECP_PRIME_TO_VALUE` -> `REDUCE_ED25519`
 - `ASSIGN_DIV_MOD_1_X_SECP_PRIME_TO_X_INV_AND_VALUE` -> `IS_ZERO_PACK_ED25519`

* Update changelog

* Insert SECP_P to exec_scopes, and rename functions

* Add call to `test_reduce_ed25519` on reduce.cairo

Co-authored-by: fmoletta <[email protected]>

* Apply changes requesed by @fmoletta

- fix: `test_reduce_ed25519` wasn't being called in main of reduce.cairo
- don't call `add_segments` macro when using `segments`
- use `check_scope` instead of manual `assert_eq`s
- change `run_program_simple_with_memory_holes(..., 0)` -> `run_program_simple`

* Use `scope` macro instead of manual build

Also allow trailing commas in `scope` macro

* Add missing `check_scope`

* Allow use of `scope` macro without args

* Change `assert_matches`+`Ok` for `assert`+`is_ok`

* Fix: remove unused import

---------

Co-authored-by: Tomás <[email protected]>
Co-authored-by: Tomás <[email protected]>
Co-authored-by: fmoletta <[email protected]>
Co-authored-by: Pedro Fontana <[email protected]>
  • Loading branch information
5 people authored Apr 28, 2023
1 parent 2891936 commit 4bc7c54
Show file tree
Hide file tree
Showing 10 changed files with 476 additions and 3 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,31 @@
x = pack(ids.x, PRIME) % SECP_P
%}

* Add missing hints `NewHint#55`, `NewHint#56`, and `NewHint#57` [#1077](https://github.com/lambdaclass/cairo-rs/issues/1077)

`BuiltinHintProcessor` now supports the following hints:

```python
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19

x = pack(ids.x, PRIME) % SECP_P
```

```python
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19

value = pack(ids.x, PRIME) % SECP_P
```

```python
SECP_P=2**255-19
from starkware.python.math_utils import div_mod

value = x_inv = div_mod(1, x, SECP_P)
```

* Implement hint for `starkware.cairo.common.cairo_keccak.keccak._copy_inputs` as described by whitelist `starknet/security/whitelists/cairo_keccak.json` [#1058](https://github.com/lambdaclass/cairo-rs/pull/1058)

`BuiltinHintProcessor` now supports the following hint:
Expand Down
94 changes: 94 additions & 0 deletions cairo_programs/is_zero.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,49 @@
from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3
from starkware.cairo.common.cairo_secp.field import unreduced_mul, verify_zero

const BASE = 2 ** 86;
const SECP_REM = 19;

func verify_zero_ed25519{range_check_ptr}(val: UnreducedBigInt3) {
let q = [ap];
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
to_assert = pack(ids.val, PRIME)
q, r = divmod(pack(ids.val, PRIME), SECP_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME
%}
let q_biased = [ap + 1];
q_biased = q + 2 ** 127, ap++;
[range_check_ptr] = q_biased, ap++;
// This implies that q is in the range [-2**127, 2**127).

tempvar r1 = (val.d0 + q * SECP_REM) / BASE;
assert [range_check_ptr + 1] = r1 + 2 ** 127;
// This implies that r1 is in the range [-2**127, 2**127).
// Therefore, r1 * BASE is in the range [-2**213, 2**213).
// By the soundness assumption, val.d0 is in the range (-2**250, 2**250).
// This implies that r1 * BASE = val.d0 + q * SECP_REM (as integers).

tempvar r2 = (val.d1 + r1) / BASE;
assert [range_check_ptr + 2] = r2 + 2 ** 127;
// Similarly, this implies that r2 * BASE = val.d1 + r1 (as integers).
// Therefore, r2 * BASE**2 = val.d1 * BASE + r1 * BASE.

assert val.d2 = q * (BASE / 8) - r2;
// Similarly, this implies that q * BASE / 4 = val.d2 + r2 (as integers).
// Therefore,
// q * BASE**3 / 4 = val.d2 * BASE**2 + r2 * BASE ** 2 =
// val.d2 * BASE**2 + val.d1 * BASE + r1 * BASE =
// val.d2 * BASE**2 + val.d1 * BASE + val.d0 + q * SECP_REM =
// val + q * SECP_REM.
// Hence, val = q * (BASE**3 / 4 - SECP_REM) = q * (2**256 - SECP_REM) = q * secp256k1_prime.

let range_check_ptr = range_check_ptr + 3;
return ();
}

// Returns 1 if x == 0 (mod secp256k1_prime), and 0 otherwise.
//
// Completeness assumption: x's limbs are in the range (-BASE, 2*BASE).
Expand Down Expand Up @@ -86,6 +129,36 @@ func is_zero_v2_pack{range_check_ptr}(x: BigInt3) -> (res: felt) {
return (res=0);
}

// Returns 1 if x == 0 (mod Ed25519 prime), and 0 otherwise.
//
// Completeness assumption: x's limbs are in the range (-BASE, 2*BASE).
// Soundness assumption: x's limbs are in the range (-2**107.49, 2**107.49).
func is_zero_ed25519{range_check_ptr}(x: BigInt3) -> (res: felt) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
x = pack(ids.x, PRIME) % SECP_P
%}
if (nondet %{ x == 0 %} != 0) {
verify_zero_ed25519(UnreducedBigInt3(d0=x.d0, d1=x.d1, d2=x.d2));
return (res=1);
}

%{
SECP_P=2**255-19
from starkware.python.math_utils import div_mod
value = x_inv = div_mod(1, x, SECP_P)
%}
let (x_inv) = nondet_bigint3();
let (x_x_inv) = unreduced_mul(x, x_inv);

// Check that x * x_inv = 1 to verify that x != 0.
verify_zero_ed25519(UnreducedBigInt3(d0=x_x_inv.d0 - 1, d1=x_x_inv.d1, d2=x_x_inv.d2));
return (res=0);
}

func test_is_zero{range_check_ptr}() -> () {
let zero = BigInt3(0, 0, 0);

Expand Down Expand Up @@ -149,11 +222,32 @@ func test_is_zero_v2_pack{range_check_ptr}() -> () {
return ();
}

func test_is_zero_ed25519{range_check_ptr}() -> () {
let zero = BigInt3(0, 0, 0);

let (res: felt) = is_zero_ed25519(zero);
assert res = 1;

let one = BigInt3(1, 0, 0);

let (res: felt) = is_zero_ed25519(one);
assert res = 0;

let ed25519_prime = BigInt3(
77371252455336267181195245, 77371252455336267181195263, 9671406556917033397649407
);

let (res: felt) = is_zero_ed25519(ed25519_prime);
assert res = 1;

return ();
}

func main{range_check_ptr}() -> () {
test_is_zero();
test_is_zero_alt();
test_is_zero_v2_pack();
test_is_zero_ed25519();

return ();
}
35 changes: 35 additions & 0 deletions cairo_programs/is_zero_pack.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ func is_zero_pack_v2{range_check_ptr}(x: BigInt3) -> (res: felt) {
return (res=0);
}

func is_zero_pack_ed25519{range_check_ptr}(x: BigInt3) -> (res: felt) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
x = pack(ids.x, PRIME) % SECP_P
%}
if (nondet %{ x == 0 %} != 0) {
return (res=1);
}
return (res=0);
}

func test_is_zero_pack{range_check_ptr}() -> () {
let zero = BigInt3(0, 0, 0);

Expand Down Expand Up @@ -80,9 +93,31 @@ func test_is_zero_pack_v2{range_check_ptr}() -> () {
return ();
}

func test_is_zero_pack_ed25519{range_check_ptr}() -> () {
let zero = BigInt3(0, 0, 0);

let (res: felt) = is_zero_pack_ed25519(zero);
assert res = 1;

let one = BigInt3(1, 0, 0);

let (res: felt) = is_zero_pack_ed25519(one);
assert res = 0;

let ed25519_prime = BigInt3(
77371252455336267181195245, 77371252455336267181195263, 9671406556917033397649407
);

let (res: felt) = is_zero_pack_ed25519(ed25519_prime);
assert res = 1;

return ();
}

func main{range_check_ptr}() -> () {
test_is_zero_pack();
test_is_zero_pack_v2();
test_is_zero_pack_ed25519();

return ();
}
89 changes: 89 additions & 0 deletions cairo_programs/reduce.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
%builtins range_check

from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3

const BASE = 2 ** 86;
const SECP_REM = 19;

func verify_zero{range_check_ptr}(val: UnreducedBigInt3) {
let q = [ap];
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
to_assert = pack(ids.val, PRIME)
q, r = divmod(pack(ids.val, PRIME), SECP_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME
%}
let q_biased = [ap + 1];
q_biased = q + 2 ** 127, ap++;
[range_check_ptr] = q_biased, ap++;
// This implies that q is in the range [-2**127, 2**127).

tempvar r1 = (val.d0 + q * SECP_REM) / BASE;
assert [range_check_ptr + 1] = r1 + 2 ** 127;
// This implies that r1 is in the range [-2**127, 2**127).
// Therefore, r1 * BASE is in the range [-2**213, 2**213).
// By the soundness assumption, val.d0 is in the range (-2**250, 2**250).
// This implies that r1 * BASE = val.d0 + q * SECP_REM (as integers).

tempvar r2 = (val.d1 + r1) / BASE;
assert [range_check_ptr + 2] = r2 + 2 ** 127;
// Similarly, this implies that r2 * BASE = val.d1 + r1 (as integers).
// Therefore, r2 * BASE**2 = val.d1 * BASE + r1 * BASE.

assert val.d2 = q * (BASE / 8) - r2;
// Similarly, this implies that q * BASE / 4 = val.d2 + r2 (as integers).
// Therefore,
// q * BASE**3 / 4 = val.d2 * BASE**2 + r2 * BASE ** 2 =
// val.d2 * BASE**2 + val.d1 * BASE + r1 * BASE =
// val.d2 * BASE**2 + val.d1 * BASE + val.d0 + q * SECP_REM =
// val + q * SECP_REM.
// Hence, val = q * (BASE**3 / 4 - SECP_REM) = q * (2**256 - SECP_REM) = q * secp256k1_prime.

let range_check_ptr = range_check_ptr + 3;
return ();
}

// Receives an unreduced number, and returns a number that is equal to the original number mod
// Ed25519 prime and in reduced form (meaning every limb is in the range [0, BASE)).
//
// Completeness assumption: x's limbs are in the range (-2**210.99, 2**210.99).
// Soundness assumption: x's limbs are in the range (-2**249.99, 2**249.99).
func reduce_ed25519{range_check_ptr}(x: UnreducedBigInt3) -> (reduced_x: BigInt3) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
value = pack(ids.x, PRIME) % SECP_P
%}
let (reduced_x: BigInt3) = nondet_bigint3();

verify_zero(
UnreducedBigInt3(d0=x.d0 - reduced_x.d0, d1=x.d1 - reduced_x.d1, d2=x.d2 - reduced_x.d2)
);
return (reduced_x=reduced_x);
}

func test_reduce_ed25519{range_check_ptr}() {
let x = UnreducedBigInt3(0, 0, 0);
let (res) = reduce_ed25519(x);
assert res = BigInt3(0, 0, 0);

let x = UnreducedBigInt3(
1113660525233188137217661511617697775365785011829423399545361443,
1243997169368861650657124871657865626433458458266748922940703512,
1484456708474143440067316914074363277495967516029110959982060577,
);
let (res) = reduce_ed25519(x);
assert res = BigInt3(
42193159084937489098474581, 19864776835133205750023223, 916662843592479469328893
);

return ();
}

func main{range_check_ptr}() {
test_reduce_ed25519();
return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::{
vrf::{
fq::{inv_mod_p_uint256, uint512_unsigned_div_rem},
inv_mod_p_uint512::inv_mod_p_uint512,
pack::*,
},
};
use crate::hint_processor::builtin_hint_processor::secp::ec_utils::ec_double_assign_new_x;
Expand Down Expand Up @@ -312,6 +313,9 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::REDUCE => {
reduce(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::REDUCE_ED25519 => {
ed25519_reduce(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::BLAKE2S_FINALIZE | hint_code::BLAKE2S_FINALIZE_V2 => {
finalize_blake2s(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
Expand Down Expand Up @@ -420,10 +424,16 @@ impl HintProcessor for BuiltinHintProcessor {
&hint_data.ap_tracking,
)
}
hint_code::IS_ZERO_PACK_ED25519 => {
ed25519_is_zero_pack(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS => is_zero_assign_scope_variables(exec_scopes),
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP => {
is_zero_assign_scope_variables_external_const(exec_scopes)
}
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_ED25519 => {
ed25519_is_zero_assign_scope_vars(exec_scopes)
}
hint_code::DIV_MOD_N_PACKED_DIVMOD_V1 => div_mod_n_packed_divmod(
vm,
exec_scopes,
Expand Down
15 changes: 15 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,11 @@ pub const REDUCE: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils im
value = pack(ids.x, PRIME) % SECP_P"#;

pub const REDUCE_ED25519: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
value = pack(ids.x, PRIME) % SECP_P"#;

pub const UNSAFE_KECCAK: &str = r#"from eth_hash.auto import keccak
data, length = ids.data, ids.length
Expand Down Expand Up @@ -581,6 +586,11 @@ x = pack(ids.x, PRIME) % SECP_P"#;
pub const IS_ZERO_PACK_EXTERNAL_SECP_V2: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
x = pack(ids.x, PRIME) % SECP_P"#;

pub const IS_ZERO_PACK_ED25519: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
x = pack(ids.x, PRIME) % SECP_P"#;

pub const IS_ZERO_ASSIGN_SCOPE_VARS: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P
from starkware.python.math_utils import div_mod
Expand All @@ -590,6 +600,11 @@ pub const IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP: &str = r#"from starkware.pyth
value = x_inv = div_mod(1, x, SECP_P)"#;

pub const IS_ZERO_ASSIGN_SCOPE_VARS_ED25519: &str = r#"SECP_P=2**255-19
from starkware.python.math_utils import div_mod
value = x_inv = div_mod(1, x, SECP_P)"#;

pub const DIV_MOD_N_PACKED_DIVMOD_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import N, pack
from starkware.python.math_utils import div_mod, safe_div
Expand Down
1 change: 1 addition & 0 deletions src/hint_processor/builtin_hint_processor/vrf/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod fq;
pub mod inv_mod_p_uint512;
pub mod pack;
Loading

0 comments on commit 4bc7c54

Please sign in to comment.