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): Implement NewHint#62 and NewHint#54 #1035

Merged
merged 14 commits into from
Apr 25, 2023
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,39 @@
* Optimizations for hash builtin [#1029](https://github.com/lambdaclass/cairo-rs/pull/1029):
* Track the verified addresses by offset in a `Vec<bool>` rather than storing the address in a `Vec<Relocatable>`

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

`BuiltinHintProcessor` now supports the following hint:

```python
%{
from starkware.python.math_utils import line_slope
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
# Compute the slope.
x0 = pack(ids.point0.x, PRIME)
y0 = pack(ids.point0.y, PRIME)
x1 = pack(ids.point1.x, PRIME)
y1 = pack(ids.point1.y, PRIME)
value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)
%}
```

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

`BuiltinHintProcessor` now supports the following hint:

```python
%{
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
%}
```

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

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

from starkware.cairo.common.cairo_secp.bigint import (
BigInt3,
UnreducedBigInt3,
nondet_bigint3,
bigint_to_uint256,
uint256_to_bigint,
)

struct EcPoint {
x: BigInt3,
y: BigInt3,
}

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

func compute_slope{range_check_ptr}(point0: EcPoint, point1: EcPoint) -> (slope: BigInt3) {
alloc_locals;
%{
from starkware.python.math_utils import line_slope
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
# Compute the slope.
x0 = pack(ids.point0.x, PRIME)
y0 = pack(ids.point0.y, PRIME)
x1 = pack(ids.point1.x, PRIME)
y1 = pack(ids.point1.y, PRIME)
value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)
%}
let (slope) = nondet_bigint3();

let x_diff = BigInt3(
d0=point0.x.d0 - point1.x.d0, d1=point0.x.d1 - point1.x.d1, d2=point0.x.d2 - point1.x.d2
);
let (x_diff_slope: UnreducedBigInt3) = unreduced_mul(x_diff, slope);

verify_zero(
UnreducedBigInt3(
d0=x_diff_slope.d0 - point0.y.d0 + point1.y.d0,
d1=x_diff_slope.d1 - point0.y.d1 + point1.y.d1,
d2=x_diff_slope.d2 - point0.y.d2 + point1.y.d2),
);

return (slope=slope);
}

func unreduced_mul(a: BigInt3, b: BigInt3) -> (res_low: UnreducedBigInt3) {
// The result of the product is:
// sum_{i, j} a.d_i * b.d_j * BASE**(i + j)
// Since we are computing it mod secp256k1_prime, we replace the term
// a.d_i * b.d_j * BASE**(i + j)
// where i + j >= 3 with
// a.d_i * b.d_j * BASE**(i + j - 3) * 4 * SECP_REM
// since BASE ** 3 = 4 * SECP_REM (mod secp256k1_prime).
return (
UnreducedBigInt3(
d0=a.d0 * b.d0 + (a.d1 * b.d2 + a.d2 * b.d1) * (8 * SECP_REM),
d1=a.d0 * b.d1 + a.d1 * b.d0 + (a.d2 * b.d2) * (8 * SECP_REM),
d2=a.d0 * b.d2 + a.d1 * b.d1 + a.d2 * b.d0),
);
}

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 ();
}

func main{range_check_ptr}() {
let point_1 = EcPoint(BigInt3(512,2412,133), BigInt3(64,0,6546));
let point_2 = EcPoint(BigInt3(7,8,123), BigInt3(1,7,465));

let (slope) = compute_slope(point_1, point_2);
assert slope = BigInt3(32565103718045841981942279,60662980405630750722698303,6577829329490861459174478);
return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::{
ec_recover_sub_a_b,
},
field_arithmetic::uint384_div,
secp::secp_utils::{SECP_P, SECP_P_V2},
vrf::{fq::uint512_unsigned_div_rem, inv_mod_p_uint512::inv_mod_p_uint512},
};
use crate::{
Expand Down Expand Up @@ -41,7 +42,7 @@ use crate::{
secp::{
bigint_utils::{bigint_to_uint256, hi_max_bitlen, nondet_bigint3},
ec_utils::{
compute_doubling_slope, compute_slope, compute_slope_secp_p, di_bit,
compute_doubling_slope, compute_slope, compute_slope_and_assing_secp_p, di_bit,
ec_double_assign_new_x, ec_double_assign_new_y, ec_mul_inner, ec_negate,
fast_ec_add_assign_new_x, fast_ec_add_assign_new_y, import_secp256r1_p,
quad_bit,
Expand Down Expand Up @@ -266,9 +267,20 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::BLAKE2S_COMPUTE => {
compute_blake2s(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::VERIFY_ZERO_V1 | hint_code::VERIFY_ZERO_V2 => {
verify_zero(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::VERIFY_ZERO_V1 | hint_code::VERIFY_ZERO_V2 => verify_zero(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
&SECP_P,
),
hint_code::VERIFY_ZERO_V3 => verify_zero(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
&SECP_P_V2,
),
hint_code::VERIFY_ZERO_EXTERNAL_SECP => verify_zero_with_external_const(
vm,
exec_scopes,
Expand Down Expand Up @@ -433,13 +445,23 @@ impl HintProcessor for BuiltinHintProcessor {
&hint_data.ap_tracking,
"pt",
),
hint_code::COMPUTE_SLOPE => compute_slope_secp_p(
hint_code::COMPUTE_SLOPE_V1 => compute_slope_and_assing_secp_p(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
"point0",
"point1",
&SECP_P,
),
hint_code::COMPUTE_SLOPE_V2 => compute_slope_and_assing_secp_p(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
"point0",
"point1",
&SECP_P_V2,
),
hint_code::COMPUTE_SLOPE_SECP256R1 => compute_slope(
vm,
Expand All @@ -450,13 +472,14 @@ impl HintProcessor for BuiltinHintProcessor {
"point1",
),
hint_code::IMPORT_SECP256R1_P => import_secp256r1_p(exec_scopes),
hint_code::COMPUTE_SLOPE_WHITELIST => compute_slope_secp_p(
hint_code::COMPUTE_SLOPE_WHITELIST => compute_slope_and_assing_secp_p(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
"pt0",
"pt1",
&SECP_P,
),
hint_code::EC_DOUBLE_ASSIGN_NEW_X_V1 | hint_code::EC_DOUBLE_ASSIGN_NEW_X_V2 => {
ec_double_assign_new_x(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
Expand Down
19 changes: 18 additions & 1 deletion src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,13 @@ 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_V3: &str = r#"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"#;

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)
Expand Down Expand Up @@ -556,7 +563,7 @@ x = pack(ids.pt.x, PRIME)
y = pack(ids.pt.y, PRIME)
value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)"#;

pub const COMPUTE_SLOPE: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
pub const COMPUTE_SLOPE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
from starkware.python.math_utils import line_slope

# Compute the slope.
Expand All @@ -566,6 +573,16 @@ x1 = pack(ids.point1.x, PRIME)
y1 = pack(ids.point1.y, PRIME)
value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#;

pub const COMPUTE_SLOPE_V2: &str = r#"from starkware.python.math_utils import line_slope
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
# Compute the slope.
x0 = pack(ids.point0.x, PRIME)
y0 = pack(ids.point0.y, PRIME)
x1 = pack(ids.point1.x, PRIME)
y1 = pack(ids.point1.y, PRIME)
value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#;

pub const COMPUTE_SLOPE_SECP256R1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import line_slope

Expand Down
60 changes: 58 additions & 2 deletions src/hint_processor/builtin_hint_processor/secp/ec_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,16 @@ Implements hint:
value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)
%}
*/
pub fn compute_slope_secp_p(
pub fn compute_slope_and_assing_secp_p(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
point0_alias: &str,
point1_alias: &str,
secp_p: &BigInt,
) -> Result<(), HintError> {
exec_scopes.insert_value("SECP_P", SECP_P.clone());
exec_scopes.insert_value("SECP_P", secp_p.clone());
compute_slope(
vm,
exec_scopes,
Expand Down Expand Up @@ -556,6 +557,61 @@ mod tests {
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_compute_slope_v2_ok() {
let mut vm = vm_with_range_check!();

//Insert ids.point0 and ids.point1 into memory
vm.segments = segments![
((1, 0), 512),
((1, 1), 2412),
((1, 2), 133),
((1, 3), 64),
((1, 4), 0),
((1, 5), 6546),
((1, 6), 7),
((1, 7), 8),
((1, 8), 123),
((1, 9), 1),
((1, 10), 7),
((1, 11), 465)
];
// let point_1 = EcPoint(BigInt3(512,2412,133), BigInt3(64,0,6546));
// let point_2 = EcPoint(BigInt3(7,8,123), BigInt3(1,7,465));

//Initialize fp
vm.run_context.fp = 14;
let ids_data = HashMap::from([
("point0".to_string(), HintReference::new_simple(-14)),
("point1".to_string(), HintReference::new_simple(-8)),
]);
let mut exec_scopes = ExecutionScopes::new();

//Execute the hint
assert_matches!(
run_hint!(vm, ids_data, hint_code::COMPUTE_SLOPE_V2, &mut exec_scopes),
Ok(())
);
check_scope!(
&exec_scopes,
[
(
"value",
bigint_str!(
"39376930140709393693483102164172662915882483986415749881375763965703119677959"
)
),
(
"slope",
bigint_str!(
"39376930140709393693483102164172662915882483986415749881375763965703119677959"
)
)
]
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_compute_slope_wdivmod_ok() {
Expand Down
28 changes: 26 additions & 2 deletions src/hint_processor/builtin_hint_processor/secp/field_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ pub fn verify_zero(
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
secp_p: &BigInt,
) -> Result<(), HintError> {
exec_scopes.insert_value("SECP_P", SECP_P.clone());
exec_scopes.insert_value("SECP_P", secp_p.clone());
let val = bigint3_pack(Uint384::from_var_name("val", vm, ids_data, ap_tracking)?);
let (q, r) = val.div_rem(&SECP_P);
let (q, r) = val.div_rem(secp_p);
if !r.is_zero() {
return Err(HintError::SecpVerifyZero(val));
}
Expand Down Expand Up @@ -220,6 +221,29 @@ mod tests {
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_verify_zero_ok() {
let hint_codes = vec![
&hint_code::VERIFY_ZERO_V1,
&hint_code::VERIFY_ZERO_V2,
&hint_code::VERIFY_ZERO_V3,
];
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_v3_ok() {
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",
Expand Down
Loading