Skip to content

Commit 258dd84

Browse files
authored
Add hint U256InvModN to Cairo1HintProcessor (#1744)
* Add test * Add hint * Add Changelog entry * fmt * Move code to method * fmt
1 parent bc5a14e commit 258dd84

File tree

4 files changed

+112
-4
lines changed

4 files changed

+112
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#### Upcoming Changes
44

5+
* feat: Add hint `U256InvModN` to `Cairo1HintProcessor` [#1744](https://github.com/lambdaclass/cairo-vm/pull/1744)
6+
57
* perf: use a more compact representation for `MemoryCell` [#1672](https://github.com/lambdaclass/cairo-vm/pull/1672)
68
* BREAKING: `Memory::get_value` will now always return `Cow::Owned` variants, code that relied on `Cow::Borrowed` may break
79

cairo1-run/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ mod tests {
267267
use rstest::rstest;
268268

269269
#[rstest]
270+
#[case(
271+
"ecdsa_recover.cairo",
272+
"3490001189944926769628658346285649224182856084131963744896357527096042836716",
273+
None
274+
)]
270275
#[case("tensor_new.cairo", "[1 2] [1 false 1 true]", None)]
271276
#[case("bytes31_ret.cairo", "123", None)]
272277
#[case("null_ret.cairo", "null", None)]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
fn main() -> felt252 {
3+
let message_hash: felt252 = 0x503f4bea29baee10b22a7f10bdc82dda071c977c1f25b8f3973d34e6b03b2c;
4+
let signature_r: felt252 = 0xbe96d72eb4f94078192c2e84d5230cde2a70f4b45c8797e2c907acff5060bb;
5+
let signature_s: felt252 = 0x677ae6bba6daf00d2631fab14c8acf24be6579f9d9e98f67aa7f2770e57a1f5;
6+
core::ecdsa::recover_public_key(:message_hash, :signature_r, :signature_s, y_parity: false).unwrap()
7+
}

vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ use cairo_lang_casm::{
2525
use core::any::Any;
2626
use core::ops::Shl;
2727

28-
use num_bigint::BigUint;
29-
use num_integer::Integer;
30-
use num_traits::ToPrimitive;
28+
use num_bigint::{BigInt, BigUint};
29+
use num_integer::{ExtendedGcd, Integer};
30+
use num_traits::{Signed, ToPrimitive};
3131

3232
/// Execution scope for constant memory allocation.
3333
struct MemoryExecScope {
@@ -242,6 +242,30 @@ impl Cairo1HintProcessor {
242242
vm, dividend0, dividend1, dividend2, dividend3, divisor0, divisor1, quotient0,
243243
quotient1, quotient2, quotient3, remainder0, remainder1,
244244
),
245+
Hint::Core(CoreHintBase::Core(CoreHint::U256InvModN {
246+
b0,
247+
b1,
248+
n0,
249+
n1,
250+
g0_or_no_inv,
251+
g1_option,
252+
s_or_r0,
253+
s_or_r1,
254+
t_or_k0,
255+
t_or_k1,
256+
})) => self.u256_inv_mod_n(
257+
vm,
258+
b0,
259+
b1,
260+
n0,
261+
n1,
262+
g0_or_no_inv,
263+
g1_option,
264+
s_or_r0,
265+
s_or_r1,
266+
t_or_k0,
267+
t_or_k1,
268+
),
245269

246270
hint => Err(HintError::UnknownHint(
247271
format!("{:?}", hint).into_boxed_str(),
@@ -397,7 +421,6 @@ impl Cairo1HintProcessor {
397421
dict_manager_exec_scope.finalize_segment(vm, dict_address)
398422
}
399423

400-
#[allow(clippy::too_many_arguments)]
401424
#[allow(clippy::too_many_arguments)]
402425
fn uint256_div_mod(
403426
&self,
@@ -1076,6 +1099,77 @@ impl Cairo1HintProcessor {
10761099
)
10771100
.map_err(HintError::from)
10781101
}
1102+
1103+
#[allow(clippy::too_many_arguments)]
1104+
fn u256_inv_mod_n(
1105+
&self,
1106+
vm: &mut VirtualMachine,
1107+
b0: &ResOperand,
1108+
b1: &ResOperand,
1109+
n0: &ResOperand,
1110+
n1: &ResOperand,
1111+
g0_or_no_inv: &CellRef,
1112+
g1_option: &CellRef,
1113+
s_or_r0: &CellRef,
1114+
s_or_r1: &CellRef,
1115+
t_or_k0: &CellRef,
1116+
t_or_k1: &CellRef,
1117+
) -> Result<(), HintError> {
1118+
let pow_2_128 = BigInt::from(u128::MAX) + 1u32;
1119+
let b0 = get_val(vm, b0)?.to_bigint();
1120+
let b1 = get_val(vm, b1)?.to_bigint();
1121+
let n0 = get_val(vm, n0)?.to_bigint();
1122+
let n1 = get_val(vm, n1)?.to_bigint();
1123+
let b: BigInt = b0.clone() + b1.clone().shl(128);
1124+
let n: BigInt = n0 + n1.shl(128);
1125+
let ExtendedGcd {
1126+
gcd: mut g,
1127+
x: _,
1128+
y: mut r,
1129+
} = n.extended_gcd(&b);
1130+
if n == 1.into() {
1131+
vm.insert_value(cell_ref_to_relocatable(s_or_r0, vm)?, Felt252::from(b0))?;
1132+
vm.insert_value(cell_ref_to_relocatable(s_or_r1, vm)?, Felt252::from(b1))?;
1133+
vm.insert_value(cell_ref_to_relocatable(t_or_k0, vm)?, Felt252::from(1))?;
1134+
vm.insert_value(cell_ref_to_relocatable(t_or_k1, vm)?, Felt252::from(0))?;
1135+
vm.insert_value(cell_ref_to_relocatable(g0_or_no_inv, vm)?, Felt252::from(1))?;
1136+
vm.insert_value(cell_ref_to_relocatable(g1_option, vm)?, Felt252::from(0))?;
1137+
} else if g != 1.into() {
1138+
// This makes sure `g0_or_no_inv` is always non-zero in the no inverse case.
1139+
if g.is_even() {
1140+
g = 2u32.into();
1141+
}
1142+
let (limb1, limb0) = (&b / &g).div_rem(&pow_2_128);
1143+
vm.insert_value(cell_ref_to_relocatable(s_or_r0, vm)?, Felt252::from(limb0))?;
1144+
vm.insert_value(cell_ref_to_relocatable(s_or_r1, vm)?, Felt252::from(limb1))?;
1145+
let (limb1, limb0) = (&n / &g).div_rem(&pow_2_128);
1146+
vm.insert_value(cell_ref_to_relocatable(t_or_k0, vm)?, Felt252::from(limb0))?;
1147+
vm.insert_value(cell_ref_to_relocatable(t_or_k1, vm)?, Felt252::from(limb1))?;
1148+
let (limb1, limb0) = g.div_rem(&pow_2_128);
1149+
vm.insert_value(
1150+
cell_ref_to_relocatable(g0_or_no_inv, vm)?,
1151+
Felt252::from(limb0),
1152+
)?;
1153+
vm.insert_value(
1154+
cell_ref_to_relocatable(g1_option, vm)?,
1155+
Felt252::from(limb1),
1156+
)?;
1157+
} else {
1158+
r %= &n;
1159+
if r.is_negative() {
1160+
r += &n;
1161+
}
1162+
let k: BigInt = (&r * b - 1) / n;
1163+
let (limb1, limb0) = r.div_rem(&pow_2_128);
1164+
vm.insert_value(cell_ref_to_relocatable(s_or_r0, vm)?, Felt252::from(limb0))?;
1165+
vm.insert_value(cell_ref_to_relocatable(s_or_r1, vm)?, Felt252::from(limb1))?;
1166+
let (limb1, limb0) = k.div_rem(&pow_2_128);
1167+
vm.insert_value(cell_ref_to_relocatable(t_or_k0, vm)?, Felt252::from(limb0))?;
1168+
vm.insert_value(cell_ref_to_relocatable(t_or_k1, vm)?, Felt252::from(limb1))?;
1169+
vm.insert_value(cell_ref_to_relocatable(g0_or_no_inv, vm)?, Felt252::from(0))?;
1170+
}
1171+
Ok(())
1172+
}
10791173
}
10801174

10811175
impl HintProcessorLogic for Cairo1HintProcessor {

0 commit comments

Comments
 (0)