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#26 #992

Merged
merged 6 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
* 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 [#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
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,12 +78,6 @@ 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,
};

pub struct HintProcessorData {
pub code: String,
pub ap_tracking: ApTracking,
Expand Down Expand Up @@ -253,8 +251,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
6 changes: 6 additions & 0 deletions 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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::stdlib::{collections::HashMap, ops::BitAnd, prelude::*};
use crate::{
any_box,
hint_processor::{
builtin_hint_processor::{
hint_utils::{
Expand All @@ -11,6 +11,7 @@ use crate::{
},
math_utils::{ec_double_slope, line_slope},
serde::deserialize_program::ApTracking,
stdlib::{collections::HashMap, ops::BitAnd, prelude::*},
types::exec_scope::ExecutionScopes,
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
};
Expand Down Expand Up @@ -58,6 +59,7 @@ pub fn ec_negate(
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
//ids.point
let point_y = (get_relocatable_from_var_name("point", vm, ids_data, ap_tracking)? + 3i32)?;
let y_bigint3 = BigInt3::from_base_addr(point_y, "point.y", vm)?;
Expand Down Expand Up @@ -86,6 +88,7 @@ pub fn compute_doubling_slope(
ap_tracking: &ApTracking,
point_alias: &str,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
//ids.point
let point = EcPoint::from_var_name(point_alias, vm, ids_data, ap_tracking)?;

Expand Down Expand Up @@ -117,6 +120,7 @@ pub fn compute_slope(
point0_alias: &str,
point1_alias: &str,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
//ids.point0
let point0 = EcPoint::from_var_name(point0_alias, vm, ids_data, ap_tracking)?;
//ids.point1
Expand Down Expand Up @@ -150,6 +154,7 @@ pub fn ec_double_assign_new_x(
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
//ids.slope
let slope = BigInt3::from_var_name("slope", vm, ids_data, ap_tracking)?;
//ids.point
Expand Down Expand Up @@ -208,6 +213,7 @@ pub fn fast_ec_add_assign_new_x(
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
//ids.slope
let slope = BigInt3::from_var_name("slope", vm, ids_data, ap_tracking)?;
//ids.point0
Expand Down
81 changes: 61 additions & 20 deletions src/hint_processor/builtin_hint_processor/secp/field_utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::any_box;
use crate::stdlib::{collections::HashMap, prelude::*};

use crate::{
Expand Down Expand Up @@ -30,9 +31,11 @@ Implements hint:
*/
pub fn verify_zero(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
let val = pack(BigInt3::from_var_name("val", vm, ids_data, ap_tracking)?);
let (q, r) = val.div_rem(&SECP_P);
if !r.is_zero() {
Expand All @@ -42,6 +45,32 @@ pub fn verify_zero(
insert_value_from_var_name("q", Felt252::new(q), vm, ids_data, ap_tracking)
}

/*
Implements hint:
%{
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 fn verify_zero_with_external_const(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let secp_p = exec_scopes.get_ref("SECP_P")?;
let val = pack(BigInt3::from_var_name("val", vm, ids_data, ap_tracking)?);
let (q, r) = val.div_rem(secp_p);
if !r.is_zero() {
return Err(HintError::SecpVerifyZero(val));
}

insert_value_from_var_name("q", Felt252::new(q), vm, ids_data, ap_tracking)
}

/*
Implements hint:
%{
Expand All @@ -56,6 +85,7 @@ pub fn reduce(
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
let value = pack(BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?);
exec_scopes.insert_value("value", value.mod_floor(&SECP_P));
Ok(())
Expand All @@ -75,6 +105,8 @@ pub fn is_zero_pack(
ids_data: &HashMap<String, HintReference>,
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 @@ -114,6 +146,7 @@ Implements hint:
%}
*/
pub fn is_zero_assign_scope_variables(exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
//Get `x` variable from vm scope
let x = exec_scopes.get::<BigInt>("x")?;

Expand Down Expand Up @@ -154,38 +187,46 @@ mod tests {
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_verify_zero_ok() {
let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME";
let mut vm = vm_with_range_check!();
//Initialize run_context
run_context!(vm, 0, 9, 9);
//Create hint data
let ids_data = non_continuous_ids_data![("val", -5), ("q", 0)];
vm.segments = segments![((1, 4), 0), ((1, 5), 0), ((1, 6), 0)];
//Execute the hint
assert_matches!(
run_hint!(vm, ids_data, hint_code, exec_scopes_ref!()),
Ok(())
);
//Check hint memory inserts
//ids.q
check_memory![vm.segments.memory, ((1, 9), 0)];
let hint_codes = vec![
"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME",
"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME",
];
for hint_code in hint_codes {
let mut vm = vm_with_range_check!();
//Initialize run_context
run_context!(vm, 0, 9, 9);
//Create hint data
let ids_data = non_continuous_ids_data![("val", -5), ("q", 0)];
vm.segments = segments![((1, 4), 0), ((1, 5), 0), ((1, 6), 0)];
//Execute the hint
assert!(run_hint!(vm, ids_data, hint_code, exec_scopes_ref!()).is_ok());
//Check hint memory inserts
//ids.q
check_memory![vm.segments.memory, ((1, 9), 0)];
}
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_verify_zero_without_pack_ok() {
let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME";
fn run_verify_zero_with_external_const_ok() {
let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME";
let mut vm = vm_with_range_check!();
//Initialize run_context
run_context!(vm, 0, 9, 9);
//Create hint data
let ids_data = non_continuous_ids_data![("val", -5), ("q", 0)];
vm.segments = segments![((1, 4), 0), ((1, 5), 0), ((1, 6), 0)];
vm.segments = segments![((1, 4), 55), ((1, 5), 0), ((1, 6), 0)];

let new_secp_p = 55;

let mut exec_scopes = ExecutionScopes::new();
exec_scopes.assign_or_update_variable("SECP_P", any_box!(bigint!(new_secp_p)));

//Execute the hint
assert!(run_hint!(vm, ids_data, hint_code, exec_scopes_ref!()).is_ok());
assert!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes).is_ok());
//Check hint memory inserts
//ids.q
check_memory![vm.segments.memory, ((1, 9), 0)];
check_memory![vm.segments.memory, ((1, 9), 1)];
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions src/hint_processor/builtin_hint_processor/secp/signature.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::any_box;
use crate::stdlib::{collections::HashMap, ops::Shr, prelude::*};

use crate::{
Expand Down Expand Up @@ -87,6 +88,7 @@ pub fn get_point_from_x(
ap_tracking: &ApTracking,
constants: &HashMap<String, Felt252>,
) -> Result<(), HintError> {
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
#[allow(deprecated)]
let beta = constants
.get(BETA)
Expand Down