Skip to content

Commit

Permalink
Merge branch 'main' into newhint49-inv_mod_p_u256
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaRedHand committed Apr 25, 2023
2 parents 39c4cbd + 4842bf1 commit 4a97fa9
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 11 deletions.
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::{inv_mod_p_uint256, uint512_unsigned_div_rem},
inv_mod_p_uint512::inv_mod_p_uint512,
Expand Down Expand Up @@ -44,7 +45,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 @@ -269,9 +270,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 @@ -436,13 +448,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 @@ -453,13 +475,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

0 comments on commit 4a97fa9

Please sign in to comment.