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#46 #1055

Merged
merged 12 commits into from
Apr 28, 2023
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

#### Upcoming Changes

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

`BuiltinHintProcessor` now supports the following hint:

```python
%{
PRIME = 2**255 - 19
II = pow(2, (PRIME - 1) // 4, PRIME)

xx = ids.xx.low + (ids.xx.high<<128)
x = pow(xx, (PRIME + 3) // 8, PRIME)
if (x * x - xx) % PRIME != 0:
x = (x * II) % PRIME
if x % 2 != 0:
x = PRIME - x
ids.x.low = x & ((1<<128)-1)
ids.x.high = x >> 128
%}
```

* Implement fast_ec_add hint variant [#1087](https://github.com/lambdaclass/cairo-rs/pull/1087)

`BuiltinHintProcessor` now supports the following hint:
Expand Down
36 changes: 36 additions & 0 deletions cairo_programs/split_xx_hint.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from starkware.cairo.common.uint256 import Uint256

func split_xx(xx: Uint256) -> Uint256{
alloc_locals;
local x: Uint256;
%{
PRIME = 2**255 - 19
II = pow(2, (PRIME - 1) // 4, PRIME)

xx = ids.xx.low + (ids.xx.high<<128)
x = pow(xx, (PRIME + 3) // 8, PRIME)
if (x * x - xx) % PRIME != 0:
x = (x * II) % PRIME
if x % 2 != 0:
x = PRIME - x
ids.x.low = x & ((1<<128)-1)
ids.x.high = x >> 128
%}
return x;
}

func main() {
let xx: Uint256 = Uint256(7, 17);
let x = split_xx(xx);

assert x.low = 316161011683971866381321160306766491472;
assert x.high = 30265492890921847871084892076606437231;

let bb: Uint256 = Uint256(1, 1);
let b = split_xx(bb);

assert b.low = 60511716334934151406684885798996722026;
assert b.high = 47999103702266454150683157633393234489;

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ impl HintProcessor for BuiltinHintProcessor {
ec_recover_product_mod(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::EC_RECOVER_PRODUCT_DIV_M => ec_recover_product_div_m(exec_scopes),
hint_code::SPLIT_XX => split_xx(vm, &hint_data.ids_data, &hint_data.ap_tracking),
#[cfg(feature = "skip_next_instruction_hint")]
hint_code::SKIP_NEXT_INSTRUCTION => skip_next_instruction(vm),
code => Err(HintError::UnknownHint(code.to_string())),
Expand Down
11 changes: 11 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1340,5 +1340,16 @@ ids.b_inverse_mod_p.high = b_inverse_mod_p_split[1]"#;

pub const EC_RECOVER_PRODUCT_DIV_M: &str = "value = k = product // m";

pub const SPLIT_XX: &str = "PRIME = 2**255 - 19
II = pow(2, (PRIME - 1) // 4, PRIME)

xx = ids.xx.low + (ids.xx.high<<128)
x = pow(xx, (PRIME + 3) // 8, PRIME)
if (x * x - xx) % PRIME != 0:
x = (x * II) % PRIME
if x % 2 != 0:
x = PRIME - x
ids.x.low = x & ((1<<128)-1)
ids.x.high = x >> 128";
#[cfg(feature = "skip_next_instruction_hint")]
pub const SKIP_NEXT_INSTRUCTION: &str = "skip_next_instruction()";
62 changes: 61 additions & 1 deletion src/hint_processor/builtin_hint_processor/math_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::stdlib::{
ops::{Shl, Shr},
prelude::*,
};
use lazy_static::lazy_static;
use num_traits::{Bounded, Pow};

use crate::utils::CAIRO_PRIME;
Expand Down Expand Up @@ -30,7 +31,10 @@ use num_integer::Integer;
use num_traits::One;
use num_traits::{Signed, Zero};

use super::hint_utils::get_maybe_relocatable_from_var_name;
use super::{
hint_utils::{get_maybe_relocatable_from_var_name, get_relocatable_from_var_name},
uint256_utils::Uint256,
};

const ADDR_BOUND: &str = "starkware.starknet.common.storage.ADDR_BOUND";

Expand Down Expand Up @@ -702,6 +706,62 @@ pub fn a_b_bitand_1(
insert_value_from_var_name("b_lsb", b_lsb, vm, ids_data, ap_tracking)
}

lazy_static! {
static ref SPLIT_XX_PRIME: BigUint = BigUint::parse_bytes(
b"57896044618658097711785492504343953926634992332820282019728792003956564819949",
10
)
.unwrap();
static ref II: BigUint = BigUint::parse_bytes(
b"19681161376707505956807079304988542015446066515923890162744021073123829784752",
10
)
.unwrap();
}

/* Implements hint:
PRIME = 2**255 - 19
II = pow(2, (PRIME - 1) // 4, PRIME)

xx = ids.xx.low + (ids.xx.high<<128)
x = pow(xx, (PRIME + 3) // 8, PRIME)
if (x * x - xx) % PRIME != 0:
x = (x * II) % PRIME
if x % 2 != 0:
x = PRIME - x
ids.x.low = x & ((1<<128)-1)
ids.x.high = x >> 128

Note: doesnt belong to and is not variation of any hint from common/math
*/
pub fn split_xx(
vm: &mut VirtualMachine,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let xx = Uint256::from_var_name("xx", vm, ids_data, ap_tracking)?;
let x_addr = get_relocatable_from_var_name("x", vm, ids_data, ap_tracking)?;
let xx = xx.low.to_biguint() + (xx.high.to_biguint() << 128_u32);
let mut x = xx.modpow(
&(&*SPLIT_XX_PRIME + 3_u32).div_floor(&BigUint::from(8_u32)),
&SPLIT_XX_PRIME,
);
if !(&x * &x - xx).mod_floor(&SPLIT_XX_PRIME).is_zero() {
x = (&x * &*II).mod_floor(&SPLIT_XX_PRIME)
};
if !x.mod_floor(&2_u32.into()).is_zero() {
x = &*SPLIT_XX_PRIME - x;
}

vm.insert_value(
x_addr,
Felt252::from(&x & &BigUint::from(u128::max_value())),
)?;
vm.insert_value((x_addr + 1)?, Felt252::from(x >> 128_u32))?;

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
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 @@ -912,6 +912,13 @@ fn ec_double_assign_new_x_v3() {
run_program_simple(program_data.as_slice());
}

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

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn nondet_bigint3_v2() {
Expand Down