diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b5a7b71e3..33db92e862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* fix(security): avoid denial of service on malicious input exploiting the scientific notation parser [#1239](https://github.com/lambdaclass/cairo-rs/pull/1239) + * perf: accumulate `min` and `max` instruction offsets during run to speed up range check [#1080](https://github.com/lambdaclass/cairo-rs/pull/) BREAKING: `Cairo_runner::get_perm_range_check_limits` no longer returns an error when called without trace enabled, as it no longer depends on it diff --git a/felt/src/bigint_felt.rs b/felt/src/bigint_felt.rs index 4ac543f963..f4fa998d6a 100644 --- a/felt/src/bigint_felt.rs +++ b/felt/src/bigint_felt.rs @@ -495,17 +495,16 @@ impl<const PH: u128, const PL: u128> Pow<u32> for FeltBigInt<PH, PL> { type Output = Self; fn pow(self, rhs: u32) -> Self { FeltBigInt { - val: self.val.pow(rhs).mod_floor(&CAIRO_PRIME_BIGUINT), + val: self.val.modpow(&BigUint::from(rhs), &CAIRO_PRIME_BIGUINT), } } } impl<'a, const PH: u128, const PL: u128> Pow<u32> for &'a FeltBigInt<PH, PL> { type Output = FeltBigInt<PH, PL>; - #[allow(clippy::needless_borrow)] // the borrow of self.val is necessary becase it's of the type BigUInt, which doesn't implement the Copy trait fn pow(self, rhs: u32) -> Self::Output { FeltBigInt { - val: (&self.val).pow(rhs).mod_floor(&CAIRO_PRIME_BIGUINT), + val: self.val.modpow(&BigUint::from(rhs), &CAIRO_PRIME_BIGUINT), } } } diff --git a/vm/src/serde/deserialize_program.rs b/vm/src/serde/deserialize_program.rs index af03542197..024a421002 100644 --- a/vm/src/serde/deserialize_program.rs +++ b/vm/src/serde/deserialize_program.rs @@ -1436,4 +1436,31 @@ mod tests { ) ); } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_felt_from_number_with_scientific_notation_big_exponent() { + #[derive(Deserialize, Debug, PartialEq)] + struct Test { + #[serde(deserialize_with = "felt_from_number")] + f: Option<Felt252>, + } + let malicious_input = &format!( + "{{ \"f\": {}e{} }}", + String::from_utf8(vec![b'9'; 1000]).unwrap(), + u32::MAX + ); + let f = serde_json::from_str::<Test>(malicious_input) + .unwrap() + .f + .unwrap(); + assert_eq!( + f, + Felt252::from_str_radix( + "2471602022505793130446032259107029522557827898253184929958153020344968292412", + 10 + ) + .unwrap() + ); + } }