diff --git a/CHANGELOG.md b/CHANGELOG.md index ac650ef5e3..9da74bde75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ #### Upcoming Changes +* Implement hint on field_arithmetic lib [#1090](https://github.com/lambdaclass/cairo-rs/pull/1090) + + `BuiltinHintProcessor` now supports the following hints: + + ```python + %{ + def split(num: int, num_bits_shift: int, length: int): + a = [] + for _ in range(length): + a.append( num & ((1 << num_bits_shift) - 1) ) + num = num >> num_bits_shift + return tuple(a) + + def pack(z, num_bits_shift: int) -> int: + limbs = (z.d0, z.d1, z.d2) + return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) + + a = pack(ids.a, num_bits_shift = 128) + b = pack(ids.b, num_bits_shift = 128) + p = pack(ids.p, num_bits_shift = 128) + + res = (a - b) % p + + + res_split = split(res, num_bits_shift=128, length=3) + + ids.res.d0 = res_split[0] + ids.res.d1 = res_split[1] + ids.res.d2 = res_split[2] + %} + ``` + * Add missing hint on cairo_secp lib [#1089](https://github.com/lambdaclass/cairo-rs/pull/1089): `BuiltinHintProcessor` now supports the following hint: @@ -1203,39 +1235,6 @@ ids.carry_d2 = 1 if sum_d2 >= ids.SHIFT else 0 ``` - ```python - def split(num: int, num_bits_shift: int, length: int): - a = [] - for _ in range(length): - a.append( num & ((1 << num_bits_shift) - 1) ) - num = num >> num_bits_shift - return tuple(a) - - def pack(z, num_bits_shift: int) -> int: - limbs = (z.d0, z.d1, z.d2) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - - def pack2(z, num_bits_shift: int) -> int: - limbs = (z.b01, z.b23, z.b45) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - - a = pack(ids.a, num_bits_shift = 128) - div = pack2(ids.div, num_bits_shift = 128) - quotient, remainder = divmod(a, div) - - quotient_split = split(quotient, num_bits_shift=128, length=3) - assert len(quotient_split) == 3 - - ids.quotient.d0 = quotient_split[0] - ids.quotient.d1 = quotient_split[1] - ids.quotient.d2 = quotient_split[2] - - remainder_split = split(remainder, num_bits_shift=128, length=3) - ids.remainder.d0 = remainder_split[0] - ids.remainder.d1 = remainder_split[1] - ids.remainder.d2 = remainder_split[2] - ``` - ```python from starkware.python.math_utils import isqrt diff --git a/cairo_programs/benchmarks/field_arithmetic_get_square_benchmark.cairo b/cairo_programs/benchmarks/field_arithmetic_get_square_benchmark.cairo index 8cd40d7641..5a251b48ae 100644 --- a/cairo_programs/benchmarks/field_arithmetic_get_square_benchmark.cairo +++ b/cairo_programs/benchmarks/field_arithmetic_get_square_benchmark.cairo @@ -1,6 +1,6 @@ from starkware.cairo.common.cairo_builtins import BitwiseBuiltin from starkware.cairo.common.bool import TRUE -from cairo_programs.uint384 import u384, Uint384, Uint384_expand +from cairo_programs.uint384 import u384, Uint384 from cairo_programs.uint384_extension import u384_ext from cairo_programs.field_arithmetic import field_arithmetic diff --git a/cairo_programs/field_arithmetic.cairo b/cairo_programs/field_arithmetic.cairo index 1726a213b0..a3c18c8827 100644 --- a/cairo_programs/field_arithmetic.cairo +++ b/cairo_programs/field_arithmetic.cairo @@ -13,6 +13,17 @@ from cairo_programs.uint384_extension import u384_ext, Uint768 // Functions for operating elements in a finite field F_p (i.e. modulo a prime p), with p of at most 384 bits namespace field_arithmetic { + // Computes (a + b) modulo p . + func add{range_check_ptr}(a: Uint384, b: Uint384, p: Uint384) -> (res: Uint384) { + let (sum: Uint384, carry) = u384.add(a, b); + let sum_with_carry: Uint768 = Uint768(sum.d0, sum.d1, sum.d2, carry, 0, 0); + + let ( + quotient: Uint768, remainder: Uint384 + ) = u384_ext.unsigned_div_rem_uint768_by_uint384(sum_with_carry, p); + return (remainder,); + } + // Computes a * b modulo p func mul{range_check_ptr}(a: Uint384, b: Uint384, p: Uint384) -> (res: Uint384) { let (low: Uint384, high: Uint384) = u384.mul_d(a, b); @@ -267,6 +278,49 @@ namespace field_arithmetic { let (res: Uint384) = mul(a, b_inverse_mod_p, p); return (res,); } + + // Computes (a - b) modulo p . + // NOTE: Expects a and b to be reduced modulo p (i.e. between 0 and p-1). The function will revert if a > p. + // NOTE: To reduce a, take the remainder of uint384_lin.unsigned_div_rem(a, p), and similarly for b. + // @dev First it computes res =(a-b) mod p in a hint and then checks outside of the hint that res + b = a modulo p + func sub_reduced_a_and_reduced_b{range_check_ptr}(a: Uint384, b: Uint384, p: Uint384) -> ( + res: Uint384 + ) { + alloc_locals; + local res: Uint384; + %{ + def split(num: int, num_bits_shift: int, length: int): + a = [] + for _ in range(length): + a.append( num & ((1 << num_bits_shift) - 1) ) + num = num >> num_bits_shift + return tuple(a) + + def pack(z, num_bits_shift: int) -> int: + limbs = (z.d0, z.d1, z.d2) + return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) + + a = pack(ids.a, num_bits_shift = 128) + b = pack(ids.b, num_bits_shift = 128) + p = pack(ids.p, num_bits_shift = 128) + + res = (a - b) % p + + + res_split = split(res, num_bits_shift=128, length=3) + + ids.res.d0 = res_split[0] + ids.res.d1 = res_split[1] + ids.res.d2 = res_split[2] + %} + u384.check(res); + let (is_valid) = u384.lt(res, p); + assert is_valid = 1; + let (b_plus_res) = add(b, res, p); + assert b_plus_res = a; + return (res,); + } + } func test_field_arithmetics_extension_operations{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { @@ -365,9 +419,22 @@ func test_u256_get_square_root{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() return (); } +func test_sub_reduced_a_and_reduced_b{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(){ + let a = Uint384(1, 1, 1); + let b = Uint384(2, 2, 2); + let p = Uint384(7, 7, 7); + let (r) = field_arithmetic.sub_reduced_a_and_reduced_b(a, b, p); + assert r.d0 = 6; + assert r.d1 = 6; + assert r.d2 = 6; + + return (); +} + func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { test_field_arithmetics_extension_operations(); test_u256_get_square_root(); + test_sub_reduced_a_and_reduced_b(); return (); } diff --git a/cairo_programs/uint384.cairo b/cairo_programs/uint384.cairo index d66ddbc921..e924c1ab26 100644 --- a/cairo_programs/uint384.cairo +++ b/cairo_programs/uint384.cairo @@ -358,62 +358,6 @@ namespace u384 { return (quotient=quotient, remainder=remainder); } - // Unsigned integer division between two integers. Returns the quotient and the remainder. - func unsigned_div_rem_expanded{range_check_ptr}(a: Uint384, div: Uint384_expand) -> ( - quotient: Uint384, remainder: Uint384 - ) { - alloc_locals; - local quotient: Uint384; - local remainder: Uint384; - - let div2 = Uint384(div.b01, div.b23, div.b45); - - %{ - def split(num: int, num_bits_shift: int, length: int): - a = [] - for _ in range(length): - a.append( num & ((1 << num_bits_shift) - 1) ) - num = num >> num_bits_shift - return tuple(a) - - def pack(z, num_bits_shift: int) -> int: - limbs = (z.d0, z.d1, z.d2) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - - def pack2(z, num_bits_shift: int) -> int: - limbs = (z.b01, z.b23, z.b45) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - - a = pack(ids.a, num_bits_shift = 128) - div = pack2(ids.div, num_bits_shift = 128) - quotient, remainder = divmod(a, div) - - quotient_split = split(quotient, num_bits_shift=128, length=3) - assert len(quotient_split) == 3 - - ids.quotient.d0 = quotient_split[0] - ids.quotient.d1 = quotient_split[1] - ids.quotient.d2 = quotient_split[2] - - remainder_split = split(remainder, num_bits_shift=128, length=3) - ids.remainder.d0 = remainder_split[0] - ids.remainder.d1 = remainder_split[1] - ids.remainder.d2 = remainder_split[2] - %} - check(quotient); - check(remainder); - let (res_mul: Uint384, carry: Uint384) = mul_expanded(quotient, div); - assert carry = Uint384(0, 0, 0); - - let (check_val: Uint384, add_carry: felt) = _add_no_uint384_check(res_mul, remainder); - assert check_val = a; - assert add_carry = 0; - - let (is_valid) = lt(remainder, div2); - assert is_valid = 1; - return (quotient=quotient, remainder=remainder); - } - func square_e{range_check_ptr}(a: Uint384) -> (low: Uint384, high: Uint384) { alloc_locals; let (a0, a1) = split_64(a.d0); diff --git a/cairo_programs/uint384_test.cairo b/cairo_programs/uint384_test.cairo index b84625eea5..c87d940a37 100644 --- a/cairo_programs/uint384_test.cairo +++ b/cairo_programs/uint384_test.cairo @@ -34,22 +34,6 @@ func test_uint384_operations{range_check_ptr}() { assert sum_res.d2 = 7; assert carry = 1; - // Test unsigned_div_rem_expanded - let e = Uint384(83434123481193248, 82349321849739284, 839243219401320423); - let div_expand = Uint384_expand( - 9283430921839492319493, 313248123482483248, 3790328402913840, 13, 78990, 109, 7 - ); - let (quotient: Uint384, remainder: Uint384) = u384.unsigned_div_rem_expanded{ - range_check_ptr=range_check_ptr - }(a, div_expand); - assert quotient.d0 = 7699479077076334; - assert quotient.d1 = 0; - assert quotient.d2 = 0; - - assert remainder.d0 = 340279955073565776659831804641277151872; - assert remainder.d1 = 340282366920938463463356863525615958397; - assert remainder.d2 = 16; - // Test sqrt let f = Uint384(83434123481193248, 82349321849739284, 839243219401320423); let (root) = u384.sqrt(f); @@ -65,7 +49,7 @@ func test_uint384_operations{range_check_ptr}() { let (sign_h) = u384.signed_nn(h); assert sign_h = 0; - return (); + return(); } func main{range_check_ptr: felt}() { diff --git a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index 281aaea402..ef38cc3218 100644 --- a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -13,6 +13,7 @@ use super::{ }, secp_utils::{ALPHA, ALPHA_V2, SECP_P, SECP_P_V2}, }, + uint384::sub_reduced_a_and_reduced_b, vrf::{ fq::{inv_mod_p_uint256, uint512_unsigned_div_rem}, inv_mod_p_uint512::inv_mod_p_uint512, @@ -89,7 +90,7 @@ use crate::{ }, uint384::{ add_no_uint384_check, uint384_signed_nn, uint384_split_128, uint384_sqrt, - uint384_unsigned_div_rem, uint384_unsigned_div_rem_expanded, + uint384_unsigned_div_rem, }, uint384_extension::unsigned_div_rem_uint768_by_uint384, usort::{ @@ -721,9 +722,6 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::ADD_NO_UINT384_CHECK => { add_no_uint384_check(vm, &hint_data.ids_data, &hint_data.ap_tracking, constants) } - hint_code::UINT384_UNSIGNED_DIV_REM_EXPANDED => { - uint384_unsigned_div_rem_expanded(vm, &hint_data.ids_data, &hint_data.ap_tracking) - } hint_code::UINT384_SQRT => { uint384_sqrt(vm, &hint_data.ids_data, &hint_data.ap_tracking) } @@ -731,6 +729,9 @@ impl HintProcessor for BuiltinHintProcessor { | hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED => { unsigned_div_rem_uint768_by_uint384(vm, &hint_data.ids_data, &hint_data.ap_tracking) } + hint_code::SUB_REDUCED_A_AND_REDUCED_B => { + sub_reduced_a_and_reduced_b(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } hint_code::UINT384_GET_SQUARE_ROOT => { u384_get_square_root(vm, &hint_data.ids_data, &hint_data.ap_tracking) } diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 5a8c04df5c..e1e88af924 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -1017,8 +1017,9 @@ sum_d1 = ids.a.d1 + ids.b.d1 + ids.carry_d0 ids.carry_d1 = 1 if sum_d1 >= ids.SHIFT else 0 sum_d2 = ids.a.d2 + ids.b.d2 + ids.carry_d1 ids.carry_d2 = 1 if sum_d2 >= ids.SHIFT else 0"; -pub const UINT384_UNSIGNED_DIV_REM_EXPANDED: &str = - "def split(num: int, num_bits_shift: int, length: int): +pub const UINT384_SQRT: &str = "from starkware.python.math_utils import isqrt + +def split(num: int, num_bits_shift: int, length: int): a = [] for _ in range(length): a.append( num & ((1 << num_bits_shift) - 1) ) @@ -1029,28 +1030,16 @@ def pack(z, num_bits_shift: int) -> int: limbs = (z.d0, z.d1, z.d2) return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) -def pack2(z, num_bits_shift: int) -> int: - limbs = (z.b01, z.b23, z.b45) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - -a = pack(ids.a, num_bits_shift = 128) -div = pack2(ids.div, num_bits_shift = 128) -quotient, remainder = divmod(a, div) - -quotient_split = split(quotient, num_bits_shift=128, length=3) -assert len(quotient_split) == 3 - -ids.quotient.d0 = quotient_split[0] -ids.quotient.d1 = quotient_split[1] -ids.quotient.d2 = quotient_split[2] - -remainder_split = split(remainder, num_bits_shift=128, length=3) -ids.remainder.d0 = remainder_split[0] -ids.remainder.d1 = remainder_split[1] -ids.remainder.d2 = remainder_split[2]"; -pub const UINT384_SQRT: &str = "from starkware.python.math_utils import isqrt +a = pack(ids.a, num_bits_shift=128) +root = isqrt(a) +assert 0 <= root < 2 ** 192 +root_split = split(root, num_bits_shift=128, length=3) +ids.root.d0 = root_split[0] +ids.root.d1 = root_split[1] +ids.root.d2 = root_split[2]"; -def split(num: int, num_bits_shift: int, length: int): +pub const SUB_REDUCED_A_AND_REDUCED_B: &str = + "def split(num: int, num_bits_shift: int, length: int): a = [] for _ in range(length): a.append( num & ((1 << num_bits_shift) - 1) ) @@ -1061,13 +1050,18 @@ def pack(z, num_bits_shift: int) -> int: limbs = (z.d0, z.d1, z.d2) return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) -a = pack(ids.a, num_bits_shift=128) -root = isqrt(a) -assert 0 <= root < 2 ** 192 -root_split = split(root, num_bits_shift=128, length=3) -ids.root.d0 = root_split[0] -ids.root.d1 = root_split[1] -ids.root.d2 = root_split[2]"; +a = pack(ids.a, num_bits_shift = 128) +b = pack(ids.b, num_bits_shift = 128) +p = pack(ids.p, num_bits_shift = 128) + +res = (a - b) % p + + +res_split = split(res, num_bits_shift=128, length=3) + +ids.res.d0 = res_split[0] +ids.res.d1 = res_split[1] +ids.res.d2 = res_split[2]"; pub const UNSIGNED_DIV_REM_UINT768_BY_UINT384: &str = "def split(num: int, num_bits_shift: int, length: int): diff --git a/src/hint_processor/builtin_hint_processor/uint384.rs b/src/hint_processor/builtin_hint_processor/uint384.rs index ee2a2e5fea..aa856bb7d2 100644 --- a/src/hint_processor/builtin_hint_processor/uint384.rs +++ b/src/hint_processor/builtin_hint_processor/uint384.rs @@ -1,13 +1,10 @@ -use core::ops::Shl; use felt::Felt252; -use num_bigint::BigUint; use num_integer::Integer; use num_traits::Zero; use crate::math_utils::isqrt; -use crate::stdlib::{borrow::Cow, collections::HashMap, prelude::*}; +use crate::stdlib::{collections::HashMap, prelude::*}; use crate::types::errors::math_errors::MathError; -use crate::types::relocatable::Relocatable; use crate::{ hint_processor::hint_processor_definition::HintReference, serde::deserialize_program::ApTracking, @@ -21,57 +18,6 @@ use super::hint_utils::{ use super::secp::bigint_utils::Uint384; // Notes: Hints in this lib use the type Uint384, which is equal to common lib's BigInt3 -/* Reduced version of Uint384_expand -The full version has 7 limbs (B0, b01, b12, b23, b34, b45, b5), but only 3 are used by the pack2 fn (b01, b23, b45) -As there are no other uses of Uint384_expand outside of these in the lib, we can use a reduced version with just 3 limbs -*/ -#[derive(Debug, PartialEq)] -#[allow(non_snake_case)] -pub(crate) struct Uint384ExpandReduced<'a> { - pub b01: Cow<'a, Felt252>, - pub b23: Cow<'a, Felt252>, - pub b45: Cow<'a, Felt252>, -} - -impl Uint384ExpandReduced<'_> { - pub(crate) fn from_base_addr<'a>( - addr: Relocatable, - name: &str, - vm: &'a VirtualMachine, - ) -> Result, HintError> { - Ok(Uint384ExpandReduced { - b01: vm.get_integer((addr + 1)?).map_err(|_| { - HintError::IdentifierHasNoMember(name.to_string(), "b01".to_string()) - })?, - b23: vm.get_integer((addr + 3)?).map_err(|_| { - HintError::IdentifierHasNoMember(name.to_string(), "b23".to_string()) - })?, - b45: vm.get_integer((addr + 5)?).map_err(|_| { - HintError::IdentifierHasNoMember(name.to_string(), "b45".to_string()) - })?, - }) - } - pub(crate) fn from_var_name<'a>( - name: &str, - vm: &'a VirtualMachine, - ids_data: &HashMap, - ap_tracking: &ApTracking, - ) -> Result, HintError> { - let base_addr = get_relocatable_from_var_name(name, vm, ids_data, ap_tracking)?; - Uint384ExpandReduced::from_base_addr(base_addr, name, vm) - } - - fn pack(self) -> BigUint { - let limbs = [self.b01, self.b23, self.b45]; - #[allow(deprecated)] - limbs - .into_iter() - .enumerate() - .map(|(idx, value)| value.to_biguint().shl(idx * 128)) - .sum() - } -} - /* Implements Hint: %{ def split(num: int, num_bits_shift: int, length: int): @@ -177,60 +123,6 @@ pub fn add_no_uint384_check( insert_value_from_var_name("carry_d2", carry_d2, vm, ids_data, ap_tracking) } -/* Implements Hint: -%{ - def split(num: int, num_bits_shift: int, length: int): - a = [] - for _ in range(length): - a.append( num & ((1 << num_bits_shift) - 1) ) - num = num >> num_bits_shift - return tuple(a) - - def pack(z, num_bits_shift: int) -> int: - limbs = (z.d0, z.d1, z.d2) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - - def pack2(z, num_bits_shift: int) -> int: - limbs = (z.b01, z.b23, z.b45) - return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) - - a = pack(ids.a, num_bits_shift = 128) - div = pack2(ids.div, num_bits_shift = 128) - quotient, remainder = divmod(a, div) - - quotient_split = split(quotient, num_bits_shift=128, length=3) - assert len(quotient_split) == 3 - - ids.quotient.d0 = quotient_split[0] - ids.quotient.d1 = quotient_split[1] - ids.quotient.d2 = quotient_split[2] - - remainder_split = split(remainder, num_bits_shift=128, length=3) - ids.remainder.d0 = remainder_split[0] - ids.remainder.d1 = remainder_split[1] - ids.remainder.d2 = remainder_split[2] -%} -*/ -pub fn uint384_unsigned_div_rem_expanded( - vm: &mut VirtualMachine, - ids_data: &HashMap, - ap_tracking: &ApTracking, -) -> Result<(), HintError> { - let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?.pack(); - let div = Uint384ExpandReduced::from_var_name("div", vm, ids_data, ap_tracking)?.pack(); - - if div.is_zero() { - return Err(MathError::DividedByZero.into()); - } - let (quotient, remainder) = a.div_mod_floor(&div); - - let quotient_split = Uint384::split("ient); - quotient_split.insert_from_var_name("quotient", vm, ids_data, ap_tracking)?; - - let remainder_split = Uint384::split(&remainder); - remainder_split.insert_from_var_name("remainder", vm, ids_data, ap_tracking) -} - /* Implements Hint %{ from starkware.python.math_utils import isqrt @@ -289,8 +181,55 @@ pub fn uint384_signed_nn( insert_value_into_ap(vm, res) } +/* Implements Hint: +%{ + def split(num: int, num_bits_shift: int, length: int): + a = [] + for _ in range(length): + a.append( num & ((1 << num_bits_shift) - 1) ) + num = num >> num_bits_shift + return tuple(a) + + def pack(z, num_bits_shift: int) -> int: + limbs = (z.d0, z.d1, z.d2) + return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs)) + + a = pack(ids.a, num_bits_shift = 128) + b = pack(ids.b, num_bits_shift = 128) + p = pack(ids.p, num_bits_shift = 128) + + res = (a - b) % p + + + res_split = split(res, num_bits_shift=128, length=3) + + ids.res.d0 = res_split[0] + ids.res.d1 = res_split[1] + ids.res.d2 = res_split[2] +%} +*/ +pub fn sub_reduced_a_and_reduced_b( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?.pack(); + let b = Uint384::from_var_name("b", vm, ids_data, ap_tracking)?.pack(); + let p = Uint384::from_var_name("p", vm, ids_data, ap_tracking)?.pack(); + let res = if a > b { + (a - b).mod_floor(&p) + } else { + &p - (b - &a).mod_floor(&p) + }; + + let res_split = Uint384::split(&res); + res_split.insert_from_var_name("res", vm, ids_data, ap_tracking) +} + #[cfg(test)] mod tests { + use core::ops::Shl; + use super::*; use crate::hint_processor::builtin_hint_processor::hint_code; @@ -609,96 +548,6 @@ mod tests { ); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn run_unsigned_div_rem_expand_ok() { - let mut vm = vm_with_range_check!(); - //Initialize fp - vm.run_context.fp = 13; - //Create hint_data - let ids_data = - non_continuous_ids_data![("a", -13), ("div", -10), ("quotient", -3), ("remainder", 0)]; - //Insert ids into memory - vm.segments = segments![ - //a - ((1, 0), 83434123481193248), - ((1, 1), 82349321849739284), - ((1, 2), 839243219401320423), - //div - ((1, 3), 9283430921839492319493), - ((1, 4), 313248123482483248), - ((1, 5), 3790328402913840), - ((1, 6), 13), - ((1, 7), 78990), - ((1, 8), 109), - ((1, 9), 7) - ]; - //Execute the hint - assert_matches!( - run_hint!(vm, ids_data, hint_code::UINT384_UNSIGNED_DIV_REM_EXPANDED), - Ok(()) - ); - //Check hint memory inserts - check_memory![ - vm.segments.memory, - // quotient - ((1, 10), 7699479077076334), - ((1, 11), 0), - ((1, 12), 0), - // remainder - //((1, 13), 340279955073565776659831804641277151872), - //((1, 14), 340282366920938463463356863525615958397), - ((1, 15), 16) - ]; - assert_eq!( - vm.segments - .memory - .get_integer((1, 13).into()) - .unwrap() - .as_ref(), - &felt_str!("340279955073565776659831804641277151872") - ); - assert_eq!( - vm.segments - .memory - .get_integer((1, 14).into()) - .unwrap() - .as_ref(), - &felt_str!("340282366920938463463356863525615958397") - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn run_unsigned_div_rem_expand_divide_by_zero() { - let mut vm = vm_with_range_check!(); - //Initialize fp - vm.run_context.fp = 13; - //Create hint_data - let ids_data = - non_continuous_ids_data![("a", -13), ("div", -10), ("quotient", -3), ("remainder", 0)]; - //Insert ids into memory - vm.segments = segments![ - //a - ((1, 0), 83434123481193248), - ((1, 1), 82349321849739284), - ((1, 2), 839243219401320423), - //div - ((1, 3), 0), - ((1, 4), 0), - ((1, 5), 0), - ((1, 6), 0), - ((1, 7), 0), - ((1, 8), 0), - ((1, 9), 0) - ]; - //Execute the hint - assert_matches!( - run_hint!(vm, ids_data, hint_code::UINT384_UNSIGNED_DIV_REM_EXPANDED), - Err(HintError::Math(MathError::DividedByZero)) - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_sqrt_ok() { @@ -815,4 +664,74 @@ mod tests { ((1, 0), 0) ]; } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_uint384_sub_a_b_ok_a_max() { + let mut vm = vm_with_range_check!(); + //Initialize fp + vm.run_context.fp = 10; + //Create hint_data + let ids_data = non_continuous_ids_data![("a", -10), ("b", -7), ("p", -4), ("res", -1)]; + //Insert ids into memory + vm.segments = segments![ + // a + ((1, 0), 6), + ((1, 1), 6), + ((1, 2), 6), + // b + ((1, 3), 1), + ((1, 4), 1), + ((1, 5), 1), + // p + ((1, 6), 7), + ((1, 7), 7), + ((1, 8), 7) + ]; + //Execute the hint + assert!(run_hint!(vm, ids_data, hint_code::SUB_REDUCED_A_AND_REDUCED_B).is_ok()); + //Check hint memory inserts + check_memory![ + vm.segments.memory, + // res + ((1, 9), 5), + ((1, 10), 5), + ((1, 11), 5) + ]; + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_uint384_sub_a_b_ok_b_max() { + let mut vm = vm_with_range_check!(); + //Initialize fp + vm.run_context.fp = 10; + //Create hint_data + let ids_data = non_continuous_ids_data![("a", -10), ("b", -7), ("p", -4), ("res", -1)]; + //Insert ids into memory + vm.segments = segments![ + // a + ((1, 0), 3), + ((1, 1), 3), + ((1, 2), 3), + // b + ((1, 3), 5), + ((1, 4), 5), + ((1, 5), 5), + // p + ((1, 6), 7), + ((1, 7), 7), + ((1, 8), 7) + ]; + //Execute the hint + assert!(run_hint!(vm, ids_data, hint_code::SUB_REDUCED_A_AND_REDUCED_B).is_ok()); + //Check hint memory inserts + check_memory![ + vm.segments.memory, + // res + ((1, 9), 5), + ((1, 10), 5), + ((1, 11), 5) + ]; + } } diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index e9990af76e..831dd734a5 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -720,7 +720,7 @@ fn keccak_alternative_hint() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn uint384() { let program_data = include_bytes!("../../cairo_programs/uint384_test.json"); - run_program_simple_with_memory_holes(program_data.as_slice(), 74); + run_program_simple_with_memory_holes(program_data.as_slice(), 54); } #[test] @@ -734,7 +734,7 @@ fn uint384_extension() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn field_arithmetic() { let program_data = include_bytes!("../../cairo_programs/field_arithmetic.json"); - run_program_simple_with_memory_holes(program_data.as_slice(), 467); + run_program_simple_with_memory_holes(program_data.as_slice(), 507); } #[test]