diff --git a/CHANGELOG.md b/CHANGELOG.md index 3287d6bc4c..49f3e07dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Cairo-VM Changelog #### Upcoming Changes +* fix: Handle the deserialization of serde_json::Number with scientific notation (e.g.: Number(1e27)) in felt_from_number function [#1188](https://github.com/lambdaclass/cairo-rs/pull/1188) * bugfix: Use cairo constants in `ASSERT_250_BIT` hint [#1187](https://github.com/lambdaclass/cairo-rs/pull/1187) diff --git a/src/serde/deserialize_program.rs b/src/serde/deserialize_program.rs index ef1e161df4..ecf0cdf862 100644 --- a/src/serde/deserialize_program.rs +++ b/src/serde/deserialize_program.rs @@ -16,7 +16,7 @@ use crate::{ }, }; use felt::{Felt252, PRIME_STR}; -use num_traits::Num; +use num_traits::{Num, Pow}; use serde::{de, de::MapAccess, de::SeqAccess, Deserialize, Deserializer, Serialize}; use serde_json::Number; @@ -167,10 +167,32 @@ where let n = Number::deserialize(deserializer)?; match Felt252::parse_bytes(n.to_string().as_bytes(), 10) { Some(x) => Ok(Some(x)), - None => Err(String::from("felt_from_number parse error")).map_err(de::Error::custom), + None => { + // Handle de Number with scientific notation cases + // e.g.: n = Number(1e27) + let felt = deserialize_scientific_notation(n); + if felt.is_some() { + return Ok(felt); + } + + Err(de::Error::custom(String::from( + "felt_from_number parse error", + ))) + } } } +fn deserialize_scientific_notation(n: Number) -> Option { + let str = n.to_string(); + let list: [&str; 2] = str.split('e').collect::>().try_into().ok()?; + + let base = Felt252::parse_bytes(list[0].to_string().as_bytes(), 10)?; + let exponent = list[1].parse::().ok()?; + + let result = base * Felt252::from(10).pow(exponent); + Some(result) +} + #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct ReferenceManager { pub references: Vec, @@ -421,6 +443,7 @@ mod tests { use super::*; use assert_matches::assert_matches; use felt::felt_str; + use num_traits::One; use num_traits::Zero; #[cfg(target_arch = "wasm32")] @@ -1363,4 +1386,17 @@ mod tests { let iden: Result = serde_json::from_str(valid_json); assert!(iden.err().is_some()); } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_felt_from_number_with_scientific_notation() { + let n = Number::deserialize(serde_json::Value::from(1000000000000000000000000000_u128)) + .unwrap(); + assert_eq!(n.to_string(), "1e27".to_owned()); + + assert_matches!( + felt_from_number(n), + Ok(x) if x == Some(Felt252::one() * Felt252::from(10).pow(27)) + ); + } }