Skip to content

Commit

Permalink
feat(hints): add NewHint#25 and NewHint#24 (lambdaclass#994)
Browse files Browse the repository at this point in the history
* Add NewHint#26

* Update changelog

* Change assert_matches for assert + is_ok

* Get and insert SECP_P from scope where applicable

* Add NewHint#25

* Add NewHint#24

* Update changelog

* Appease clippy

* Rename hint codes

* Get or insert N from scope

* Change test contract

* Fix test

* Fix test (for real this time)
  • Loading branch information
MegaRedHand authored and kariy committed Jun 23, 2023
1 parent 8ce29cc commit 83108ec
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 30 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@
* 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:
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 ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use crate::{
verify_zero, verify_zero_with_external_const,
},
signature::{
div_mod_n_packed_divmod, div_mod_n_safe_div, get_point_from_x,
pack_modn_div_modn,
div_mod_n_packed_divmod, div_mod_n_packed_external_n, div_mod_n_safe_div,
get_point_from_x, pack_modn_div_modn,
},
},
segments::{relocate_segment, temporary_array},
Expand Down Expand Up @@ -350,13 +350,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_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "a", "b"),
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", 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 @@ -493,7 +500,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
12 changes: 11 additions & 1 deletion src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,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 @@ -449,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
81 changes: 57 additions & 24 deletions src/hint_processor/builtin_hint_processor/secp/signature.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::any_box;
use crate::stdlib::{collections::HashMap, ops::Shr, prelude::*};

use crate::{
any_box,
hint_processor::{
builtin_hint_processor::{
hint_utils::get_integer_from_var_name,
Expand All @@ -11,10 +9,11 @@ use crate::{
},
math_utils::{div_mod, safe_div_bigint},
serde::deserialize_program::ApTracking,
stdlib::{collections::HashMap, ops::Shr, prelude::*},
types::exec_scope::ExecutionScopes,
vm::errors::hint_errors::HintError,
vm::vm_core::VirtualMachine,
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
};
use core::ops::Add;
use felt::Felt252;
use num_bigint::BigInt;
use num_integer::Integer;
Expand All @@ -32,35 +31,57 @@ a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
*/
pub fn div_mod_n_packed_divmod(
pub fn div_mod_n_packed(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
n: &BigInt,
) -> Result<(), HintError> {
let a = pack(BigInt3::from_var_name("a", vm, ids_data, ap_tracking)?);
let b = pack(BigInt3::from_var_name("b", vm, ids_data, ap_tracking)?);

let value = div_mod(&a, &b, &N);
let value = div_mod(&a, &b, n);
exec_scopes.insert_value("a", a);
exec_scopes.insert_value("b", b);
exec_scopes.insert_value("value", value.clone());
exec_scopes.insert_value("res", value);
Ok(())
}

pub fn div_mod_n_packed_divmod(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("N", any_box!(N.clone()));
div_mod_n_packed(vm, exec_scopes, ids_data, ap_tracking, &N)
}

pub fn div_mod_n_packed_external_n(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let n = exec_scopes.get::<BigInt>("N")?;
div_mod_n_packed(vm, exec_scopes, ids_data, ap_tracking, &n)
}

// Implements hint:
// value = k = safe_div(res * b - a, N)
pub fn div_mod_n_safe_div(
exec_scopes: &mut ExecutionScopes,
a_alias: &str,
b_alias: &str,
to_add: u64,
) -> Result<(), HintError> {
let a = exec_scopes.get_ref::<BigInt>(a_alias)?;
let b = exec_scopes.get_ref::<BigInt>(b_alias)?;
let res = exec_scopes.get_ref::<BigInt>("res")?;

let value = safe_div_bigint(&(res * b - a), &N)?;
let value = safe_div_bigint(&(res * b - a), &N)?.add(to_add);

exec_scopes.insert_value("value", value);
Ok(())
Expand Down Expand Up @@ -163,22 +184,33 @@ mod tests {
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn safe_div_ok() {
let hint_code = hint_code::DIV_MOD_N_PACKED_DIVMOD;
let mut vm = vm!();
// "import N"
let mut exec_scopes = ExecutionScopes::new();
exec_scopes.assign_or_update_variable("N", any_box!(N.clone()));

vm.segments = segments![
((1, 0), 15),
((1, 1), 3),
((1, 2), 40),
((1, 3), 0),
((1, 4), 10),
((1, 5), 1)
let hint_codes = vec![
hint_code::DIV_MOD_N_PACKED_DIVMOD_V1,
hint_code::DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N,
];
vm.run_context.fp = 3;
let ids_data = non_continuous_ids_data![("a", -3), ("b", 0)];
let mut exec_scopes = ExecutionScopes::new();
assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "a", "b"), Ok(()));
for hint_code in hint_codes {
let mut vm = vm!();

vm.segments = segments![
((1, 0), 15),
((1, 1), 3),
((1, 2), 40),
((1, 3), 0),
((1, 4), 10),
((1, 5), 1)
];
vm.run_context.fp = 3;
let ids_data = non_continuous_ids_data![("a", -3), ("b", 0)];

assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));

assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "a", "b", 0), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "a", "b", 1), Ok(()));
}
}

#[test]
Expand All @@ -193,7 +225,8 @@ mod tests {
div_mod_n_safe_div(
&mut exec_scopes,
"a",
"b"
"b",
0,
),
Err(
HintError::Math(MathError::SafeDivFailBigInt(
Expand Down Expand Up @@ -290,6 +323,6 @@ mod tests {
let ids_data = non_continuous_ids_data![("x", -3), ("s", 0)];
let mut exec_scopes = ExecutionScopes::new();
assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "x", "s"), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "x", "s", 0), Ok(()));
}
}
7 changes: 7 additions & 0 deletions src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1322,3 +1322,10 @@ fn cairo_run_efficient_secp256r1_ec() {
let program_data = include_bytes!("../../cairo_programs/efficient_secp256r1_ec.json");
run_program_simple(program_data.as_slice());
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn cairo_run_div_mod_n() {
let program_data = include_bytes!("../../cairo_programs/div_mod_n.json");
run_program_simple(program_data.as_slice());
}

0 comments on commit 83108ec

Please sign in to comment.