diff --git a/CHANGELOG.md b/CHANGELOG.md index e66e01a0ba..e40e2f071d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* perf: precompute prime/constants in get_data and avoid clones in field_element_repr [#2256](https://github.com/lambdaclass/cairo-vm/pull/2256) + #### [3.0.0-rc.4] - 2025-28-10 * fix: error mapping for fee_provision in excess_balance hint [#2236](https://github.com/lambdaclass/cairo-vm/pull/2236) diff --git a/cairo-vm-tracer/src/tracer.rs b/cairo-vm-tracer/src/tracer.rs index 5e7e467093..63edeec1a5 100644 --- a/cairo-vm-tracer/src/tracer.rs +++ b/cairo-vm-tracer/src/tracer.rs @@ -8,7 +8,6 @@ use axum::{ routing::get, Json, Router, }; -use cairo_vm::utils::PRIME_STR; use cairo_vm::vm::trace::trace_entry::RelocatedTraceEntry; use cairo_vm::{serde::deserialize_program::DebugInfo, types::program::Program, Felt252}; use include_dir::{include_dir, Dir}; @@ -57,6 +56,13 @@ pub async fn run_tracer( } async fn get_data(tracer_data: State) -> Json { + // Precompute field modulus and constants once per request to avoid repeated allocations. + let prime_bigint = + BigInt::from_biguint(num_bigint::Sign::Plus, cairo_vm::utils::CAIRO_PRIME.clone()); + let half_prime: BigInt = &prime_bigint >> 1u32; + let two_pow_40: BigInt = BigInt::one() << 40; + let two_pow_100: BigInt = BigInt::one() << 100; + let data_response = DataReponse { code: tracer_data .input_files @@ -71,7 +77,10 @@ async fn get_data(tracer_data: State) -> Json { .map(|x| { field_element_repr( &x.to_bigint(), - &BigInt::parse_bytes(&PRIME_STR.as_bytes()[2..], 16).unwrap(), + &prime_bigint, + &half_prime, + &two_pow_40, + &two_pow_100, ) }) .enumerate() @@ -108,17 +117,22 @@ async fn static_path(Path(path): Path) -> impl IntoResponse { } } -fn field_element_repr(val: &BigInt, prime: &BigInt) -> String { +fn field_element_repr( + val: &BigInt, + prime: &BigInt, + half_prime: &BigInt, + two_pow_40: &BigInt, + two_pow_100: &BigInt, +) -> String { // Shift val to the range (-prime / 2, prime / 2). - let shifted_val: BigInt = (val.clone() + prime.clone() / 2) % prime.clone() - prime.clone() / 2; + let shifted_val: BigInt = ((val + half_prime) % prime) - half_prime; // If shifted_val is small, use decimal representation. - let two_pow_40: BigInt = BigInt::one() << 40; - if shifted_val.abs() < two_pow_40 { + let abs = shifted_val.abs(); + if &abs < two_pow_40 { return shifted_val.to_string(); } // Otherwise, use hex representation (allowing a sign if the number is close to prime). - let two_pow_100: BigInt = BigInt::one() << 100; - if shifted_val.abs() < two_pow_100 { + if &abs < two_pow_100 { return format!("0x{:x}", shifted_val); } format!("0x{:x}", val)