Skip to content

Commit

Permalink
Merge branch 'main' into feat(hint)/66-cairo_keccak_finalize_v2
Browse files Browse the repository at this point in the history
  • Loading branch information
Oppen committed Apr 24, 2023
2 parents b761b20 + 3be76c4 commit a238b43
Show file tree
Hide file tree
Showing 8 changed files with 489 additions and 0 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,28 @@
* Remove duplicated tests in cairo_run_test
* BREAKING CHANGE: `MemorySegmentManager.get_memory_holes` now also receives the amount of builtins in the vm. Signature is now `pub fn get_memory_holes(&self, builtin_count: usize) -> Result<usize, MemoryError>`

* Add missing hints `NewHint#35` and `NewHint#36` [#975](https://github.com/lambdaclass/cairo-rs/issues/975)

`BuiltinHintProcessor` now supports the following hint:

```python
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.cairo.common.math_utils import as_int
from starkware.python.math_utils import div_mod, safe_div

p = pack(ids.P, PRIME)
x = pack(ids.x, PRIME) + as_int(ids.x.d3, PRIME) * ids.BASE ** 3 + as_int(ids.x.d4, PRIME) * ids.BASE ** 4
y = pack(ids.y, PRIME)

value = res = div_mod(x, y, p)
```

```python
k = safe_div(res * y - x, p)
value = k if k > 0 else 0 - k
ids.flag = 1 if k > 0 else 0
```

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

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

from starkware.cairo.common.cairo_secp.bigint import (
BigInt3,
UnreducedBigInt3,
UnreducedBigInt5,
nondet_bigint3,
bigint_mul,
)
from starkware.cairo.common.cairo_secp.constants import BASE

func bigint_mul_u(x: UnreducedBigInt3, y: BigInt3) -> (res: UnreducedBigInt5) {
return (
UnreducedBigInt5(
d0=x.d0 * y.d0,
d1=x.d0 * y.d1 + x.d1 * y.d0,
d2=x.d0 * y.d2 + x.d1 * y.d1 + x.d2 * y.d0,
d3=x.d1 * y.d2 + x.d2 * y.d1,
d4=x.d2 * y.d2
),
);
}

// Returns (x / y) % P
func bigint_div_mod{range_check_ptr}(x: UnreducedBigInt5, y: UnreducedBigInt3, P: BigInt3) -> (
res: BigInt3
) {
alloc_locals;
local flag;
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.cairo.common.math_utils import as_int
from starkware.python.math_utils import div_mod, safe_div

p = pack(ids.P, PRIME)
x = pack(ids.x, PRIME) + as_int(ids.x.d3, PRIME) * ids.BASE ** 3 + as_int(ids.x.d4, PRIME) * ids.BASE ** 4
y = pack(ids.y, PRIME)

value = res = div_mod(x, y, p)
%}
let (res) = nondet_bigint3();

%{
k = safe_div(res * y - x, p)
value = k if k > 0 else 0 - k
ids.flag = 1 if k > 0 else 0
%}
let (k) = nondet_bigint3();
let (res_y) = bigint_mul_u(y, res);
let (k_p) = bigint_mul(k, P);

tempvar carry1 = (res_y.d0 - (2 * flag - 1) * k_p.d0 - x.d0) / BASE;
assert [range_check_ptr + 0] = carry1 + 2 ** 127;

tempvar carry2 = (res_y.d1 - (2 * flag - 1) * k_p.d1 - x.d1 + carry1) / BASE;
assert [range_check_ptr + 1] = carry2 + 2 ** 127;

tempvar carry3 = (res_y.d2 - (2 * flag - 1) * k_p.d2 - x.d2 + carry2) / BASE;
assert [range_check_ptr + 2] = carry3 + 2 ** 127;

tempvar carry4 = (res_y.d3 - (2 * flag - 1) * k_p.d3 - x.d3 + carry3) / BASE;
assert [range_check_ptr + 3] = carry4 + 2 ** 127;

assert res_y.d4 - (2 * flag - 1) * k_p.d4 - x.d4 + carry4 = 0;
let range_check_ptr = range_check_ptr + 4;

return (res=res);
}

// Check val = 0 mod n?
func verify_urbigint5_zero{range_check_ptr}(val: UnreducedBigInt5, n: BigInt3) {
let (res) = bigint_div_mod(val, UnreducedBigInt3(1, 0, 0), n);
assert res.d0 = 0;
assert res.d1 = 0;
assert res.d2 = 0;
return ();
}

func main{range_check_ptr: felt}() {
let x = UnreducedBigInt5(0x38a23ca66202c8c2a72277, 0x6730e765376ff17ea8385, 0xca1ad489ab60ea581e6c1, 0, 0);
let y = UnreducedBigInt3(0x20a4b46d3c5e24cda81f22, 0x967bf895824330d4273d0, 0x541e10c21560da25ada4c);
let p = BigInt3(0x8a03bbfd25e8cd0364141, 0x3ffffffffffaeabb739abd, 0xfffffffffffffffffffff);

let (actual : BigInt3) = bigint_div_mod(x, y, p);

assert actual.d0 = 39016122801346771958523117;
assert actual.d1 = 70716674902939638702535965;
assert actual.d2 = 18303064213085914713888892;

return ();
}
225 changes: 225 additions & 0 deletions src/hint_processor/builtin_hint_processor/bigint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
use crate::hint_processor::builtin_hint_processor::secp::bigint_utils::BigInt5;
use crate::hint_processor::builtin_hint_processor::secp::secp_utils::BASE;
use crate::math_utils::{div_mod, safe_div_bigint};
use crate::stdlib::collections::HashMap;
use crate::stdlib::prelude::String;
use crate::types::exec_scope::ExecutionScopes;
use crate::{
hint_processor::{
builtin_hint_processor::secp::{bigint_utils::BigInt3, secp_utils::pack},
hint_processor_definition::HintReference,
},
serde::deserialize_program::ApTracking,
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
};
use felt::Felt252;
use num_bigint::BigInt;
use num_bigint::ToBigInt;
use num_traits::{One, Signed, Zero};

use super::hint_utils::insert_value_from_var_name;

/// Implements hint:
/// ```python
/// from starkware.cairo.common.cairo_secp.secp_utils import pack
/// from starkware.cairo.common.math_utils import as_int
/// from starkware.python.math_utils import div_mod, safe_div
///
/// p = pack(ids.P, PRIME)
/// x = pack(ids.x, PRIME) + as_int(ids.x.d3, PRIME) * ids.BASE ** 3 + as_int(ids.x.d4, PRIME) * ids.BASE ** 4
/// y = pack(ids.y, PRIME)
///
/// value = res = div_mod(x, y, p)
/// ```
pub fn bigint_pack_div_mod_hint(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let p: BigInt = pack(BigInt3::from_var_name("P", vm, ids_data, ap_tracking)?);

let x: BigInt = {
let x_bigint5 = BigInt5::from_var_name("x", vm, ids_data, ap_tracking)?;
let x_lower = BigInt3 {
d0: x_bigint5.d0,
d1: x_bigint5.d1,
d2: x_bigint5.d2,
};
let d3 = x_bigint5.d3.as_ref().to_biguint().to_bigint().unwrap();
let d4 = x_bigint5.d4.as_ref().to_biguint().to_bigint().unwrap();
pack(x_lower) + d3 * BigInt::from(BASE.pow(3)) + d4 * BigInt::from(BASE.pow(4))
};
let y: BigInt = pack(BigInt3::from_var_name("y", vm, ids_data, ap_tracking)?);

let res = div_mod(&x, &y, &p);
exec_scopes.insert_value("res", res.clone());
exec_scopes.insert_value("value", res);
exec_scopes.insert_value("x", x);
exec_scopes.insert_value("y", y);
exec_scopes.insert_value("p", p);

Ok(())
}

/// Implements hint:
/// ```python
/// k = safe_div(res * y - x, p)
/// value = k if k > 0 else 0 - k
/// ids.flag = 1 if k > 0 else 0
/// ```
pub fn bigint_safe_div_hint(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let res = exec_scopes.get::<BigInt>("res")?;
let y = exec_scopes.get::<BigInt>("y")?;
let x = exec_scopes.get::<BigInt>("x")?;
let p = exec_scopes.get::<BigInt>("p")?;

let k = safe_div_bigint(&(res * y - x), &p)?;
let (value, flag) = if k.is_positive() {
(k.clone(), Felt252::one())
} else {
(-k.clone(), Felt252::zero())
};

exec_scopes.insert_value("k", k);
exec_scopes.insert_value("value", value);
insert_value_from_var_name("flag", flag, vm, ids_data, ap_tracking)?;

Ok(())
}

#[cfg(test)]
mod test {
use crate::any_box;
use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
use crate::hint_processor::builtin_hint_processor::hint_code;
use crate::hint_processor::hint_processor_definition::HintProcessor;
use crate::hint_processor::hint_processor_definition::HintReference;
use crate::stdlib::collections::HashMap;
use crate::types::exec_scope::ExecutionScopes;
use crate::types::relocatable::MaybeRelocatable;
use crate::utils::test_utils::*;
use crate::vm::errors::memory_errors::MemoryError;
use crate::vm::vm_core::VirtualMachine;
use crate::vm::vm_memory::{memory::Memory, memory_segments::MemorySegmentManager};
use assert_matches::assert_matches;
use num_bigint::BigInt;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;

/// Input:
/// x = UnreducedBigInt5(0x38a23ca66202c8c2a72277, 0x6730e765376ff17ea8385, 0xca1ad489ab60ea581e6c1, 0, 0);
/// y = UnreducedBigInt3(0x20a4b46d3c5e24cda81f22, 0x967bf895824330d4273d0, 0x541e10c21560da25ada4c);
/// p = BigInt3(0x8a03bbfd25e8cd0364141, 0x3ffffffffffaeabb739abd, 0xfffffffffffffffffffff);
/// expected: value = res = 109567829260688255124154626727441144629993228404337546799996747905569082729709 (py int)
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_bigint_pack_div_mod_hint() {
// Prepare the VM context:
let ids_data = non_continuous_ids_data![
("x", 0), // located at `fp + 0`.
("y", 5), // located at `fp + 5`.
("P", 8) // located at `fp + 8`.
];

let mut vm = vm!();
vm.run_context.fp = 0;
add_segments!(vm, 11); // Alloc space for `ids.x`, `ids.y` and `ids.p`.
vm.segments = segments![
((1, 0), 0x38a23ca66202c8c2a72277_i128), // x.d0
((1, 1), 0x6730e765376ff17ea8385_i128), // x.d1
((1, 2), 0xca1ad489ab60ea581e6c1_i128), // x.d2
((1, 3), 0_i128), // x.d3
((1, 4), 0_i128), // x.d4
((1, 5), 0x20a4b46d3c5e24cda81f22_i128), // y.d0
((1, 6), 0x967bf895824330d4273d0_i128), // y.d1
((1, 7), 0x541e10c21560da25ada4c_i128), // y.d2
((1, 8), 0x8a03bbfd25e8cd0364141_i128), // P.id0
((1, 9), 0x3ffffffffffaeabb739abd_i128), // P.id1
((1, 10), 0xfffffffffffffffffffff_i128), // P.id2
];

let mut exec_scopes = ExecutionScopes::new();
assert_matches!(
run_hint!(
vm,
ids_data,
hint_code::BIGINT_PACK_DIV_MOD,
&mut exec_scopes
),
Ok(())
);

let expected = bigint_str!(
"109567829260688255124154626727441144629993228404337546799996747905569082729709"
);
assert_matches!(exec_scopes.get::<BigInt>("res"), Ok(x) if x == expected);
assert_matches!(exec_scopes.get::<BigInt>("value"), Ok(x) if x == expected);
assert_matches!(exec_scopes.get::<BigInt>("y"), Ok(x) if x == bigint_str!("38047400353360331012910998489219098987968251547384484838080352663220422975266"));
assert_matches!(exec_scopes.get::<BigInt>("x"), Ok(x) if x == bigint_str!("91414600319290532004473480113251693728834511388719905794310982800988866814583"));
assert_matches!(exec_scopes.get::<BigInt>("p"), Ok(x) if x == bigint_str!("115792089237316195423570985008687907852837564279074904382605163141518161494337"));
}

/// Input:
/// res = 109567829260688255124154626727441144629993228404337546799996747905569082729709
/// y = 38047400353360331012910998489219098987968251547384484838080352663220422975266
/// x = 91414600319290532004473480113251693728834511388719905794310982800988866814583
/// p = 115792089237316195423570985008687907852837564279074904382605163141518161494337
/// Output:
/// k = 36002209591245282109880156842267569109802494162594623391338581162816748840003
/// value = 36002209591245282109880156842267569109802494162594623391338581162816748840003
/// ids.flag = 1
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_bigint_safe_div_hint() {
let mut exec_scopes = ExecutionScopes::new();
exec_scopes.insert_value(
"res",
bigint_str!(
"109567829260688255124154626727441144629993228404337546799996747905569082729709"
),
);
exec_scopes.insert_value(
"x",
bigint_str!(
"91414600319290532004473480113251693728834511388719905794310982800988866814583"
),
);
exec_scopes.insert_value(
"y",
bigint_str!(
"38047400353360331012910998489219098987968251547384484838080352663220422975266"
),
);
exec_scopes.insert_value(
"p",
bigint_str!(
"115792089237316195423570985008687907852837564279074904382605163141518161494337"
),
);

let mut vm = vm!();
let ids_data = non_continuous_ids_data![("flag", 0)];
vm.run_context.fp = 0;
add_segments!(vm, 2); // Alloc space for `flag`

assert_matches!(
run_hint!(vm, ids_data, hint_code::BIGINT_SAFE_DIV, &mut exec_scopes),
Ok(())
);
assert_matches!(exec_scopes.get::<BigInt>("k"), Ok(x) if x == bigint_str!("36002209591245282109880156842267569109802494162594623391338581162816748840003"));
assert_matches!(exec_scopes.get::<BigInt>("value"), Ok(x) if x == bigint_str!("36002209591245282109880156842267569109802494162594623391338581162816748840003"));

check_memory![vm.segments.memory, ((1, 0), 1)];
// let flag_result = get_integer_from_var_name("flag", vm, ids_data, ap_tracking);
// assert!(flag_result.is_ok());
// assert_eq!(flag_result.unwrap().as_ref(), Felt252::one());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
hint_processor::{
builtin_hint_processor::{
bigint::{bigint_pack_div_mod_hint, bigint_safe_div_hint},
blake2s_utils::{
blake2s_add_uint256, blake2s_add_uint256_bigend, compute_blake2s, finalize_blake2s,
},
Expand Down Expand Up @@ -386,6 +387,15 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::GET_FELT_BIT_LENGTH => {
get_felt_bitlenght(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::BIGINT_PACK_DIV_MOD => bigint_pack_div_mod_hint(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
),
hint_code::BIGINT_SAFE_DIV => {
bigint_safe_div_hint(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N => div_mod_n_packed_external_n(
vm,
exec_scopes,
Expand Down
14 changes: 14 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,20 @@ pub const DIV_MOD_N_SAFE_DIV: &str = r#"value = k = safe_div(res * b - a, N)"#;
pub const GET_FELT_BIT_LENGTH: &str = r#"x = ids.x
ids.bit_length = x.bit_length()"#;

pub const BIGINT_PACK_DIV_MOD: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.cairo.common.math_utils import as_int
from starkware.python.math_utils import div_mod, safe_div
p = pack(ids.P, PRIME)
x = pack(ids.x, PRIME) + as_int(ids.x.d3, PRIME) * ids.BASE ** 3 + as_int(ids.x.d4, PRIME) * ids.BASE ** 4
y = pack(ids.y, PRIME)
value = res = div_mod(x, y, p)"#;

pub const BIGINT_SAFE_DIV: &str = r#"k = safe_div(res * y - x, p)
value = k if k > 0 else 0 - k
ids.flag = 1 if k > 0 else 0"#;

pub const DIV_MOD_N_SAFE_DIV_PLUS_ONE: &str =
r#"value = k_plus_one = safe_div(res * b - a, N) + 1"#;

Expand Down
1 change: 1 addition & 0 deletions src/hint_processor/builtin_hint_processor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod bigint;
pub mod blake2s_hash;
pub mod blake2s_utils;
pub mod builtin_hint_processor_definition;
Expand Down
Loading

0 comments on commit a238b43

Please sign in to comment.