From 086522d4e644fa9de2c1298f1ddd1813926341a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Tue, 23 Jul 2024 15:52:00 +0200 Subject: [PATCH] feat: Avoid heap allocs when going to/from field (#7547) This PR plus [integer operations using u128](https://github.com/AztecProtocol/aztec-packages/pull/7518) makes [this test](https://github.com/zac-williamson/noir_bigcurve/blob/main/src/bigcurve_test.nr#L129) go from 110 seconds of ACVM execution to around 22 seconds (34 seconds with only the change of the integer ops) Flamegraph before: ![image](https://github.com/user-attachments/assets/5281fc59-9172-4a5d-97cd-1aa98d25bd41) Flamegraph after: ![image](https://github.com/user-attachments/assets/745b8bb8-4c26-4123-919b-f10c99e9dd7c) --------- Co-authored-by: Maxim Vezenov --- .../acvm-repo/acir_field/src/field_element.rs | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/noir/noir-repo/acvm-repo/acir_field/src/field_element.rs b/noir/noir-repo/acvm-repo/acir_field/src/field_element.rs index 3c16276adc9..92ccbc4e5f6 100644 --- a/noir/noir-repo/acvm-repo/acir_field/src/field_element.rs +++ b/noir/noir-repo/acvm-repo/acir_field/src/field_element.rs @@ -139,17 +139,25 @@ impl<'de, T: ark_ff::PrimeField> Deserialize<'de> for FieldElement { impl From for FieldElement { fn from(a: u128) -> FieldElement { - let result = match F::from_str(&a.to_string()) { - Ok(result) => result, - Err(_) => panic!("Cannot convert u128 as a string to a field element"), - }; - FieldElement(result) + FieldElement(F::from(a)) } } impl From for FieldElement { fn from(a: usize) -> FieldElement { - FieldElement::from(a as u128) + FieldElement::from(a as u64) + } +} + +impl From for FieldElement { + fn from(a: u64) -> FieldElement { + FieldElement(F::from(a)) + } +} + +impl From for FieldElement { + fn from(a: u32) -> FieldElement { + FieldElement(F::from(a)) } } @@ -265,8 +273,16 @@ impl AcirField for FieldElement { } fn to_u128(self) -> u128 { - let bytes = self.to_be_bytes(); - u128::from_be_bytes(bytes[16..32].try_into().unwrap()) + let as_bigint = self.0.into_bigint(); + let limbs = as_bigint.as_ref(); + + let mut result = limbs[0] as u128; + if limbs.len() > 1 { + let high_limb = limbs[1] as u128; + result += high_limb << 64; + } + + result } fn try_into_u128(self) -> Option {