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#23 #996

Merged
merged 11 commits into from
Apr 18, 2023
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
* 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 hint on cairo_secp lib [#996](https://github.com/lambdaclass/cairo-rs/pull/996):

`BuiltinHintProcessor` now supports the following hint:

```python
from starkware.python.math_utils import div_mod
value = x_inv = div_mod(1, x, SECP_P)
```

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

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

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

// Returns 1 if x == 0 (mod secp256k1_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{range_check_ptr}(x: BigInt3) -> (res: felt) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack

x = pack(ids.x, PRIME) % SECP_P
%}
if (nondet %{ x == 0 %} != 0) {
verify_zero(UnreducedBigInt3(d0=x.d0, d1=x.d1, d2=x.d2));
return (res=1);
}

%{
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(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);

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

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

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

let secp256k1_prime = BigInt3(
77371252455336262886226991, 77371252455336267181195263, 19342813113834066795298815
);

let (res: felt) = is_zero(secp256k1_prime);
assert res = 1;

return ();
}

func main{range_check_ptr}() -> () {
test_is_zero();

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ use crate::{
fast_ec_add_assign_new_y,
},
field_utils::{
is_zero_assign_scope_variables, is_zero_nondet, is_zero_pack, reduce,
verify_zero, verify_zero_with_external_const,
is_zero_assign_scope_variables, is_zero_assign_scope_variables_external_const,
is_zero_nondet, is_zero_pack, reduce, verify_zero,
verify_zero_with_external_const,
},
signature::{
div_mod_n_packed_divmod, div_mod_n_packed_external_n, div_mod_n_safe_div,
Expand Down Expand Up @@ -350,6 +351,9 @@ 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::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP => {
is_zero_assign_scope_variables_external_const(exec_scopes)
}
hint_code::DIV_MOD_N_PACKED_DIVMOD_V1 => div_mod_n_packed_divmod(
vm,
exec_scopes,
Expand Down
5 changes: 5 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,16 @@ pub const IS_ZERO_NONDET: &str = "memory[ap] = to_felt_or_relocatable(x == 0)";
pub const IS_ZERO_PACK: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack

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

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

pub const IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP: &str = r#"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
84 changes: 54 additions & 30 deletions src/hint_processor/builtin_hint_processor/secp/field_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ pub fn is_zero_pack(
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));

let x_packed = pack(BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?);
let x = x_packed.mod_floor(&SECP_P);
exec_scopes.insert_value("x", x);
Expand Down Expand Up @@ -156,9 +155,31 @@ pub fn is_zero_assign_scope_variables(exec_scopes: &mut ExecutionScopes) -> Resu
Ok(())
}

/*
Implements hint:
%{
from starkware.python.math_utils import div_mod

value = x_inv = div_mod(1, x, SECP_P)
%}
*/
pub fn is_zero_assign_scope_variables_external_const(
exec_scopes: &mut ExecutionScopes,
) -> Result<(), HintError> {
//Get variables from vm scope
let secp_p = exec_scopes.get_ref::<BigInt>("SECP_P")?;
let x = exec_scopes.get_ref::<BigInt>("x")?;

let value = div_mod(&BigInt::one(), x, secp_p);
exec_scopes.insert_value("value", value.clone());
exec_scopes.insert_value("x_inv", value);
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::hint_processor::builtin_hint_processor::hint_code;
use crate::stdlib::string::ToString;
use crate::vm::vm_memory::memory_segments::MemorySegmentManager;
use crate::{
Expand Down Expand Up @@ -517,38 +538,41 @@ mod tests {
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn is_zero_assign_scope_variables_ok() {
let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P\nfrom starkware.python.math_utils import div_mod\n\nvalue = x_inv = div_mod(1, x, SECP_P)";
let mut vm = vm_with_range_check!();

//Initialize vm scope with variable `x`
let mut exec_scopes = ExecutionScopes::new();
exec_scopes.assign_or_update_variable(
"x",
any_box!(bigint_str!(
"52621538839140286024584685587354966255185961783273479086367"
)),
);
//Execute the hint
assert_matches!(
run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes),
Ok(())
);
let hint_codes = vec![
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS,
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP,
];

//Check 'value' is defined in the vm scope
assert_matches!(
exec_scopes.get::<BigInt>("value"),
Ok(x) if x == bigint_str!(
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
)
);
for hint_code in hint_codes {
let mut vm = vm_with_range_check!();

//Check 'x_inv' is defined in the vm scope
assert_matches!(
exec_scopes.get::<BigInt>("x_inv"),
Ok(x) if x == bigint_str!(
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
)
);
//Initialize vm scope with variable `x`
exec_scopes.assign_or_update_variable(
"x",
any_box!(bigint_str!(
"52621538839140286024584685587354966255185961783273479086367"
)),
);
//Execute the hint
assert!(run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes).is_ok());

//Check 'value' is defined in the vm scope
assert_matches!(
exec_scopes.get::<BigInt>("value"),
Ok(x) if x == bigint_str!(
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
)
);

//Check 'x_inv' is defined in the vm scope
assert_matches!(
exec_scopes.get::<BigInt>("x_inv"),
Ok(x) if x == bigint_str!(
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
)
);
}
}

#[test]
Expand Down
7 changes: 7 additions & 0 deletions src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,3 +1329,10 @@ fn cairo_run_div_mod_n() {
let program_data = include_bytes!("../../cairo_programs/div_mod_n.json");
run_program_simple(program_data.as_slice());
}

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