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
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,27 @@

#### Upcoming Changes

Add missing hint on vrf.json lib [#1053](https://github.com/lambdaclass/cairo-rs/pull/1053):
* Add missing hint on vrf.json lib [#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
%}
```

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

`BuiltinHintProcessor` now supports the following hint:

Expand Down
26 changes: 26 additions & 0 deletions cairo_programs/split_xx_hint.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from starkware.cairo.common.uint256 import Uint256

func main() {
alloc_locals;

local xx: Uint256 = Uint256(7, 17);
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
%}

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

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,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 @@ -1278,5 +1278,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 @@
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_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,
};

//Implements hint: memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1
pub fn is_nn(
Expand Down Expand Up @@ -641,6 +645,62 @@
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)
};

Check warning on line 690 in src/hint_processor/builtin_hint_processor/math_utils.rs

View check run for this annotation

Codecov / codecov/patch

src/hint_processor/builtin_hint_processor/math_utils.rs#L690

Added line #L690 was not covered by tests
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 @@ -890,3 +890,10 @@ fn ec_double_assign_new_x_v3() {
let program_data = include_bytes!("../../cairo_programs/ec_double_assign_new_x_v3.json");
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());
}