Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hints): add NewHint#25 and NewHint#24 #994

Merged
merged 15 commits into from
Apr 17, 2023
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@
* Added dynamic layout [#879](https://github.com/lambdaclass/cairo-rs/pull/879)
* `get_segment_size` was exposed [#934](https://github.com/lambdaclass/cairo-rs/pull/934)

* Add missing hints on cairo_secp lib [#994](https://github.com/lambdaclass/cairo-rs/pull/994)::

`BuiltinHintProcessor` now supports the following hints:
```python
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div

a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
```

```python
value = k_plus_one = safe_div(res * b - a, N) + 1
```

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

`BuiltinHintProcessor` now supports the following hint:

```python
from starkware.cairo.common.cairo_secp.secp_utils import pack

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
```

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

`BuiltinHintProcessor` now supports the following hint:
Expand Down
129 changes: 129 additions & 0 deletions cairo_programs/div_mod_n.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
%builtins range_check

from starkware.cairo.common.cairo_secp.bigint import BigInt3, nondet_bigint3, BASE, bigint_mul
from starkware.cairo.common.cairo_secp.constants import BETA, N0, N1, N2

// Source: https://github.com/myBraavos/efficient-secp256r1/blob/73cca4d53730cb8b2dcf34e36c7b8f34b96b3230/src/secp256r1/signature.cairo

// Computes a * b^(-1) modulo the size of the elliptic curve (N).
//
// Prover assumptions:
// * All the limbs of a are in the range (-2 ** 210.99, 2 ** 210.99).
// * All the limbs of b are in the range (-2 ** 124.99, 2 ** 124.99).
// * b is in the range [0, 2 ** 256).
//
// Soundness assumptions:
// * The limbs of a are in the range (-2 ** 249, 2 ** 249).
// * The limbs of b are in the range (-2 ** 159.83, 2 ** 159.83).
func div_mod_n{range_check_ptr}(a: BigInt3, b: BigInt3) -> (res: BigInt3) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import N, pack
from starkware.python.math_utils import div_mod, safe_div

a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
%}
let (res) = nondet_bigint3();

%{ value = k_plus_one = safe_div(res * b - a, N) + 1 %}
let (k_plus_one) = nondet_bigint3();
let k = BigInt3(d0=k_plus_one.d0 - 1, d1=k_plus_one.d1, d2=k_plus_one.d2);

let (res_b) = bigint_mul(res, b);
let n = BigInt3(N0, N1, N2);
let (k_n) = bigint_mul(k, n);

// We should now have res_b = k_n + a. Since the numbers are in unreduced form,
// we should handle the carry.

tempvar carry1 = (res_b.d0 - k_n.d0 - a.d0) / BASE;
assert [range_check_ptr + 0] = carry1 + 2 ** 127;

tempvar carry2 = (res_b.d1 - k_n.d1 - a.d1 + carry1) / BASE;
assert [range_check_ptr + 1] = carry2 + 2 ** 127;

tempvar carry3 = (res_b.d2 - k_n.d2 - a.d2 + carry2) / BASE;
assert [range_check_ptr + 2] = carry3 + 2 ** 127;

tempvar carry4 = (res_b.d3 - k_n.d3 + carry3) / BASE;
assert [range_check_ptr + 3] = carry4 + 2 ** 127;

assert res_b.d4 - k_n.d4 + carry4 = 0;

let range_check_ptr = range_check_ptr + 4;

return (res=res);
}

func div_mod_n_alt{range_check_ptr}(a: BigInt3, b: BigInt3) -> (res: BigInt3) {
// just used to import N
%{
from starkware.cairo.common.cairo_secp.secp_utils import N, pack
from starkware.python.math_utils import div_mod, safe_div

a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
%}

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

a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
%}
let (res) = nondet_bigint3();

%{ value = k_plus_one = safe_div(res * b - a, N) + 1 %}
let (k_plus_one) = nondet_bigint3();
let k = BigInt3(d0=k_plus_one.d0 - 1, d1=k_plus_one.d1, d2=k_plus_one.d2);

let (res_b) = bigint_mul(res, b);
let n = BigInt3(N0, N1, N2);
let (k_n) = bigint_mul(k, n);

tempvar carry1 = (res_b.d0 - k_n.d0 - a.d0) / BASE;
assert [range_check_ptr + 0] = carry1 + 2 ** 127;

tempvar carry2 = (res_b.d1 - k_n.d1 - a.d1 + carry1) / BASE;
assert [range_check_ptr + 1] = carry2 + 2 ** 127;

tempvar carry3 = (res_b.d2 - k_n.d2 - a.d2 + carry2) / BASE;
assert [range_check_ptr + 2] = carry3 + 2 ** 127;

tempvar carry4 = (res_b.d3 - k_n.d3 + carry3) / BASE;
assert [range_check_ptr + 3] = carry4 + 2 ** 127;

assert res_b.d4 - k_n.d4 + carry4 = 0;

let range_check_ptr = range_check_ptr + 4;

return (res=res);
}

func test_div_mod_n{range_check_ptr: felt}() {
let a: BigInt3 = BigInt3(100, 99, 98);
let b: BigInt3 = BigInt3(10, 9, 8);

let (res) = div_mod_n(a, b);

assert res = BigInt3(
3413472211745629263979533, 17305268010345238170172332, 11991751872105858217578135
);

// test alternative hint
let (res_alt) = div_mod_n_alt(a, b);

assert res_alt = res;

return ();
}

func main{range_check_ptr: felt}() {
test_div_mod_n();

return ();
}
54 changes: 54 additions & 0 deletions cairo_programs/ed25519_field.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,51 @@ func verify_zero{range_check_ptr}(val: UnreducedBigInt3) {
return ();
}

// Source: https://github.com/myBraavos/efficient-secp256r1/blob/73cca4d53730cb8b2dcf34e36c7b8f34b96b3230/src/secp256r1/ec.cairo#L106
func verify_zero_alt{range_check_ptr}(val: UnreducedBigInt3) {
let x = val;
// Used just to import SECP_P in scope
%{
from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack

value = pack(ids.x, PRIME) % SECP_P
%}
nondet_bigint3();

let q = [ap];
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack

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++;

tempvar r1 = (val.d0 + q * SECP_REM) / BASE;
assert [range_check_ptr + 1] = r1 + 2 ** 127;
// This implies r1 * BASE = val.d0 + q * SECP_REM (as integers).

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

assert val.d2 = q * (BASE / 4) - r2;
// This implies 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).

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

func test_verify_zero{range_check_ptr: felt}() {
let val = UnreducedBigInt3(0, 0, 0);

Expand All @@ -59,8 +104,17 @@ func test_verify_zero{range_check_ptr: felt}() {
return ();
}

func test_verify_zero_alt{range_check_ptr: felt}() {
let val = UnreducedBigInt3(0, 0, 0);

verify_zero_alt(val);

return ();
}

func main{range_check_ptr: felt}() {
test_verify_zero();
test_verify_zero_alt();

return ();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::stdlib::{any::Any, collections::HashMap, prelude::*, rc::Rc};

use crate::{
hint_processor::{
builtin_hint_processor::{
Expand All @@ -14,6 +12,7 @@ use crate::{
default_dict_new, dict_new, dict_read, dict_squash_copy_dict,
dict_squash_update_ptr, dict_update, dict_write,
},
ec_utils::{chained_ec_op_random_ec_point_hint, random_ec_point_hint, recover_y_hint},
find_element_hint::{find_element, search_sorted_lower},
hint_code,
keccak_utils::{
Expand All @@ -36,7 +35,7 @@ use crate::{
},
field_utils::{
is_zero_assign_scope_variables, is_zero_nondet, is_zero_pack, reduce,
verify_zero,
verify_zero, verify_zero_with_external_const,
},
signature::{
div_mod_n_packed_divmod, div_mod_n_safe_div, get_point_from_x,
Expand All @@ -58,6 +57,10 @@ use crate::{
split_64, uint256_add, uint256_mul_div_mod, uint256_signed_nn, uint256_sqrt,
uint256_unsigned_div_rem,
},
uint384::{
add_no_uint384_check, uint384_signed_nn, uint384_split_128, uint384_sqrt,
uint384_unsigned_div_rem, uint384_unsigned_div_rem_expanded,
},
usort::{
usort_body, usort_enter_scope, verify_multiplicity_assert,
verify_multiplicity_body, verify_usort,
Expand All @@ -66,6 +69,7 @@ use crate::{
hint_processor_definition::{HintProcessor, HintReference},
},
serde::deserialize_program::ApTracking,
stdlib::{any::Any, collections::HashMap, prelude::*, rc::Rc},
types::exec_scope::ExecutionScopes,
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
};
Expand All @@ -74,11 +78,7 @@ use felt::Felt252;
#[cfg(feature = "skip_next_instruction_hint")]
use crate::hint_processor::builtin_hint_processor::skip_next_instruction::skip_next_instruction;

use super::ec_utils::{chained_ec_op_random_ec_point_hint, random_ec_point_hint, recover_y_hint};
use super::uint384::{
add_no_uint384_check, uint384_signed_nn, uint384_split_128, uint384_sqrt,
uint384_unsigned_div_rem, uint384_unsigned_div_rem_expanded,
};
use super::secp::signature::div_mod_n_packed_external_n;

pub struct HintProcessorData {
pub code: String,
Expand Down Expand Up @@ -253,8 +253,14 @@ impl HintProcessor for BuiltinHintProcessor {
compute_blake2s(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::VERIFY_ZERO_V1 | hint_code::VERIFY_ZERO_V2 => {
verify_zero(vm, &hint_data.ids_data, &hint_data.ap_tracking)
verify_zero(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::VERIFY_ZERO_EXTERNAL_SECP => verify_zero_with_external_const(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
),
hint_code::NONDET_BIGINT3 => {
nondet_bigint3(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
Expand Down Expand Up @@ -346,13 +352,20 @@ impl HintProcessor for BuiltinHintProcessor {
}
hint_code::IS_ZERO_NONDET => is_zero_nondet(vm, exec_scopes),
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS => is_zero_assign_scope_variables(exec_scopes),
hint_code::DIV_MOD_N_PACKED_DIVMOD => div_mod_n_packed_divmod(
hint_code::DIV_MOD_N_PACKED_DIVMOD_V1 => div_mod_n_packed_divmod(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
),
hint_code::DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N => div_mod_n_packed_external_n(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
),
hint_code::DIV_MOD_N_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "a", "b"),
hint_code::DIV_MOD_N_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "a", "b", 0),
hint_code::DIV_MOD_N_SAFE_DIV_PLUS_ONE => div_mod_n_safe_div(exec_scopes, "a", "b", 1),
hint_code::GET_POINT_FROM_X => get_point_from_x(
vm,
exec_scopes,
Expand Down Expand Up @@ -489,7 +502,7 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::PACK_MODN_DIV_MODN => {
pack_modn_div_modn(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::XS_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "x", "s"),
hint_code::XS_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "x", "s", 0),
hint_code::UINT384_UNSIGNED_DIV_REM => {
uint384_unsigned_div_rem(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
Expand Down
18 changes: 17 additions & 1 deletion src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ 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"#;

pub const VERIFY_ZERO_EXTERNAL_SECP: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack

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"#;

pub const REDUCE: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack

value = pack(ids.x, PRIME) % SECP_P"#;
Expand Down Expand Up @@ -434,7 +440,14 @@ from starkware.python.math_utils import div_mod

value = x_inv = div_mod(1, x, SECP_P)"#;

pub const DIV_MOD_N_PACKED_DIVMOD: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import N, pack
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

a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)"#;

pub const DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div

a = pack(ids.a, PRIME)
Expand All @@ -443,6 +456,9 @@ value = res = div_mod(a, b, N)"#;

pub const DIV_MOD_N_SAFE_DIV: &str = r#"value = k = safe_div(res * b - a, N)"#;

pub const DIV_MOD_N_SAFE_DIV_PLUS_ONE: &str =
r#"value = k_plus_one = safe_div(res * b - a, N) + 1"#;

pub const GET_POINT_FROM_X: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack

x_cube_int = pack(ids.x_cube, PRIME) % SECP_P
Expand Down
Loading