Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### Upcoming Changes
* 0.11 Support
* Added support for hints `PACK_MODN_DIV_MODN` and `XS_SAFE_DIV` [#991](https://github.com/lambdaclass/cairo-rs/pull/991)
* Layouts update [#874](https://github.com/lambdaclass/cairo-rs/pull/874)
* Keccak builtin updated [#873](https://github.com/lambdaclass/cairo-rs/pull/873), [#883](https://github.com/lambdaclass/cairo-rs/pull/883)
* Changes to `ec_op` [#876](https://github.com/lambdaclass/cairo-rs/pull/876)
Expand Down
60 changes: 60 additions & 0 deletions cairo_programs/mul_s_inv.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
%builtins range_check

// Source: https://github.com/NilFoundation/cairo-placeholder-verification/blob/382924c6f1c4f9673a12a31d19835e00978ab241/src/signatures/ed25519.cairo

from starkware.cairo.common.cairo_secp.bigint import BASE, BigInt3, bigint_mul, nondet_bigint3
from starkware.cairo.common.cairo_secp.constants import N0, N1, N2
from starkware.cairo.common.cairo_secp.ec import EcPoint, ec_add, ec_mul

from starkware.cairo.common.math import assert_nn_le, assert_not_zero

// Computes x * s^(-1) modulo the size of the elliptic curve (N).
func mul_s_inv{range_check_ptr}(x : BigInt3, s : BigInt3) -> (res : BigInt3){
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div

N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
x = pack(ids.x, PRIME) % N
s = pack(ids.s, PRIME) % N
value = res = div_mod(x, s, N)
%}
let (res) = nondet_bigint3();

%{ value = k = safe_div(res * s - x, N) %}
let (k) = nondet_bigint3();

let (res_s) = bigint_mul(res, s);
let n = BigInt3(N0, N1, N2);
let (k_n) = bigint_mul(k, n);

// We should now have res_s = k_n + x. Since the numbers are in unreduced form,
// we should handle the carry.

tempvar carry1 = (res_s.d0 - k_n.d0 - x.d0) / BASE;
assert [range_check_ptr + 0] = carry1 + 2 ** 127;

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

tempvar carry3 = (res_s.d2 - k_n.d2 - x.d2 + carry2) / BASE;
assert [range_check_ptr + 2] = carry3 + 2 ** 127;

tempvar carry4 = (res_s.d3 - k_n.d3 + carry3) / BASE;
assert [range_check_ptr + 3] = carry4 + 2 ** 127;

assert res_s.d4 - k_n.d4 + carry4 = 0;

let range_check_ptr = range_check_ptr + 4;

return (res=res);
}

func main{range_check_ptr} () -> (){
alloc_locals;
let bi1 = BigInt3(0x216936D3CD6E53FEC0A4E, 0x231FDD6DC5C692CC760952, 0x5A7B2C9562D608F25D51A);
let bi2 = BigInt3(0x666666666666666666666, 0x6666666666666666666666, 0x666666666666666666658);
let res = mul_s_inv(bi1, bi2);
assert res = res;
return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ use crate::{
is_zero_assign_scope_variables, is_zero_nondet, is_zero_pack, reduce,
verify_zero,
},
signature::{div_mod_n_packed_divmod, div_mod_n_safe_div, get_point_from_x},
signature::{
div_mod_n_packed_divmod, div_mod_n_safe_div, get_point_from_x,
pack_modn_div_modn,
},
},
segments::{relocate_segment, temporary_array},
set::set_add,
Expand Down Expand Up @@ -347,7 +350,7 @@ impl HintProcessor for BuiltinHintProcessor {
&hint_data.ids_data,
&hint_data.ap_tracking,
),
hint_code::DIV_MOD_N_SAFE_DIV => div_mod_n_safe_div(exec_scopes),
hint_code::DIV_MOD_N_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "a", "b"),
hint_code::GET_POINT_FROM_X => get_point_from_x(
vm,
exec_scopes,
Expand Down Expand Up @@ -457,6 +460,10 @@ impl HintProcessor for BuiltinHintProcessor {
chained_ec_op_random_ec_point_hint(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::RECOVER_Y => recover_y_hint(vm, &hint_data.ids_data, &hint_data.ap_tracking),
hint_code::PACK_MODN_DIV_MODN => {
pack_modn_div_modn(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::XS_SAFE_DIV => div_mod_n_safe_div(exec_scopes, "x", "s"),
hint_code::UINT384_UNSIGNED_DIV_REM => {
uint384_unsigned_div_rem(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
Expand Down
9 changes: 9 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,15 @@ from starkware.python.math_utils import recover_y
ids.p.x = ids.x
# This raises an exception if `x` is not on the curve.
ids.p.y = recover_y(ids.x, ALPHA, BETA, FIELD_PRIME)";
pub(crate) const PACK_MODN_DIV_MODN: &str =
"from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div

N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
x = pack(ids.x, PRIME) % N
s = pack(ids.s, PRIME) % N
value = res = div_mod(x, s, N)";
pub(crate) const XS_SAFE_DIV: &str = "value = k = safe_div(res * s - x, N)";

// The following hints support the lib https://github.com/NethermindEth/research-basic-Cairo-operations-big-integers/blob/main/lib/uint384.cairo
pub(crate) const UINT384_UNSIGNED_DIV_REM: &str =
Expand Down
60 changes: 56 additions & 4 deletions src/hint_processor/builtin_hint_processor/secp/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ pub fn div_mod_n_packed_divmod(

// Implements hint:
// value = k = safe_div(res * b - a, N)
pub fn div_mod_n_safe_div(exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> {
let a = exec_scopes.get_ref::<BigInt>("a")?;
let b = exec_scopes.get_ref::<BigInt>("b")?;
pub fn div_mod_n_safe_div(
exec_scopes: &mut ExecutionScopes,
a_alias: &str,
b_alias: &str,
) -> Result<(), HintError> {
let a = exec_scopes.get_ref::<BigInt>(a_alias)?;
let b = exec_scopes.get_ref::<BigInt>(b_alias)?;
let res = exec_scopes.get_ref::<BigInt>("res")?;

let value = safe_div_bigint(&(res * b - a), &N)?;
Expand Down Expand Up @@ -103,6 +107,31 @@ pub fn get_point_from_x(
exec_scopes.insert_value("value", y);
Ok(())
}
/* Implements hint:
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div

N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
x = pack(ids.x, PRIME) % N
s = pack(ids.s, PRIME) % N
value = res = div_mod(x, s, N)
*/
pub fn pack_modn_div_modn(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let x = pack(BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?).mod_floor(&N);
let s = pack(BigInt3::from_var_name("s", vm, ids_data, ap_tracking)?).mod_floor(&N);

let value = div_mod(&x, &s, &N);
exec_scopes.insert_value("x", x);
exec_scopes.insert_value("s", s);
exec_scopes.insert_value("value", value.clone());
exec_scopes.insert_value("res", value);
Ok(())
}

#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -147,7 +176,7 @@ mod tests {
let ids_data = non_continuous_ids_data![("a", -3), ("b", 0)];
let mut exec_scopes = ExecutionScopes::new();
assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "a", "b"), Ok(()));
}

#[test]
Expand All @@ -161,6 +190,8 @@ mod tests {
assert_matches!(
div_mod_n_safe_div(
&mut exec_scopes,
"a",
"b"
),
Err(
HintError::Math(MathError::SafeDivFailBigInt(
Expand Down Expand Up @@ -238,4 +269,25 @@ mod tests {
)]
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn pack_modn_div_modn_ok() {
let hint_code = hint_code::PACK_MODN_DIV_MODN;
let mut vm = vm!();

vm.segments = segments![
((1, 0), 15),
((1, 1), 3),
((1, 2), 40),
((1, 3), 0),
((1, 4), 10),
((1, 5), 1)
];
vm.run_context.fp = 3;
let ids_data = non_continuous_ids_data![("x", -3), ("s", 0)];
let mut exec_scopes = ExecutionScopes::new();
assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(()));
assert_matches!(div_mod_n_safe_div(&mut exec_scopes, "x", "s"), Ok(()));
}
}
7 changes: 7 additions & 0 deletions src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,13 @@ fn cairo_run_is_quad_residue_test() {
run_program_simple(program_data.as_slice());
}

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

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