From c02e54489a3f0f9e04599be9943329f313f0c20e Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Mon, 7 Apr 2025 13:43:25 +0100 Subject: [PATCH 1/9] added more serialization and tests --- brillig_report.json | 511 ++++++++++++++++++++++++++++ src/benchmarks/bignum_benchmarks.nr | 33 +- src/bignum.nr | 27 +- src/fns/constrained_ops.nr | 2 +- src/fns/serialization.nr | 101 +++++- src/runtime_bignum.nr | 21 +- src/tests/bignum_test.nr | 17 + 7 files changed, 676 insertions(+), 36 deletions(-) create mode 100644 brillig_report.json diff --git a/brillig_report.json b/brillig_report.json new file mode 100644 index 00000000..fc216128 --- /dev/null +++ b/brillig_report.json @@ -0,0 +1,511 @@ +{ + "programs": [ + { + "package_name": "add_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__add_with_flags", + "opcodes": 501 + } + ] + }, + { + "package_name": "add_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__add_with_flags", + "opcodes": 486 + } + ] + }, + { + "package_name": "add_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__add_with_flags", + "opcodes": 578 + } + ] + }, + { + "package_name": "add_U256_Bench", + "unconstrained_functions": [ + { + "name": "__add_with_flags", + "opcodes": 486 + } + ] + }, + { + "package_name": "bench_from_be_bytes", + "unconstrained_functions": [ + { + "name": "__field_to_u128", + "opcodes": 25 + } + ] + }, + { + "package_name": "bench_from_le_bytes", + "unconstrained_functions": [] + }, + { + "package_name": "bench_to_be_bytes", + "unconstrained_functions": [ + { + "name": "print_unconstrained", + "opcodes": 270 + }, + { + "name": "directive_to_radix", + "opcodes": 17 + } + ] + }, + { + "package_name": "bench_to_le_bytes", + "unconstrained_functions": [ + { + "name": "directive_to_radix", + "opcodes": 17 + } + ] + }, + { + "package_name": "div_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__div", + "opcodes": 4585 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2526 + } + ] + }, + { + "package_name": "div_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__div", + "opcodes": 4413 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2437 + } + ] + }, + { + "package_name": "div_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__div", + "opcodes": 5023 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2764 + } + ] + }, + { + "package_name": "div_U256_Bench", + "unconstrained_functions": [ + { + "name": "__div", + "opcodes": 4413 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2437 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_12_elements_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 4715 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_12_elements_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 4555 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_12_elements_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 5963 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_12_elements_U256_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 4555 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_3_elements_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 3131 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_3_elements_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 3024 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_3_elements_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 3622 + } + ] + }, + { + "package_name": "evaluate_quadratic_expression_3_elements_U256_Bench", + "unconstrained_functions": [ + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 3024 + } + ] + }, + { + "package_name": "from_field_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__from_field", + "opcodes": 82 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 377 + } + ] + }, + { + "package_name": "from_field_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__from_field", + "opcodes": 79 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 369 + } + ] + }, + { + "package_name": "from_field_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__from_field", + "opcodes": 110 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 408 + } + ] + }, + { + "package_name": "from_field_U256_Bench", + "unconstrained_functions": [ + { + "name": "__from_field", + "opcodes": 79 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 369 + } + ] + }, + { + "package_name": "mul_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__mul", + "opcodes": 1668 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2526 + } + ] + }, + { + "package_name": "mul_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__mul", + "opcodes": 1592 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2437 + } + ] + }, + { + "package_name": "mul_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__mul", + "opcodes": 1841 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2764 + } + ] + }, + { + "package_name": "mul_U256_Bench", + "unconstrained_functions": [ + { + "name": "__mul", + "opcodes": 1592 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2437 + } + ] + }, + { + "package_name": "sub_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__sub_with_flags", + "opcodes": 415 + } + ] + }, + { + "package_name": "sub_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__sub_with_flags", + "opcodes": 404 + } + ] + }, + { + "package_name": "sub_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__sub_with_flags", + "opcodes": 490 + } + ] + }, + { + "package_name": "sub_U256_Bench", + "unconstrained_functions": [ + { + "name": "__sub_with_flags", + "opcodes": 404 + } + ] + }, + { + "package_name": "udiv_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 2034 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2566 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 377 + } + ] + }, + { + "package_name": "udiv_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 1948 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2474 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 369 + } + ] + }, + { + "package_name": "udiv_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 2095 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2818 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 408 + } + ] + }, + { + "package_name": "udiv_U256_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 1948 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2474 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 369 + } + ] + }, + { + "package_name": "udiv_mod_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 2034 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2566 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 377 + } + ] + }, + { + "package_name": "udiv_mod_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 1948 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2474 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 369 + } + ] + }, + { + "package_name": "udiv_mod_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 2095 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2818 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 408 + } + ] + }, + { + "package_name": "udiv_mod_U256_Bench", + "unconstrained_functions": [ + { + "name": "__udiv_mod", + "opcodes": 1948 + }, + { + "name": "__compute_quadratic_expression_with_borrow_flags", + "opcodes": 2474 + }, + { + "name": "__validate_gt_remainder", + "opcodes": 369 + } + ] + }, + { + "package_name": "validate_in_field_BLS12_381Fq_Bench", + "unconstrained_functions": [ + { + "name": "__validate_in_field_compute_borrow_flags", + "opcodes": 209 + } + ] + }, + { + "package_name": "validate_in_field_BN254_Fq_Bench", + "unconstrained_functions": [ + { + "name": "__validate_in_field_compute_borrow_flags", + "opcodes": 136 + } + ] + }, + { + "package_name": "validate_in_field_U2048_Bench", + "unconstrained_functions": [ + { + "name": "__validate_in_field_compute_borrow_flags", + "opcodes": 293 + } + ] + }, + { + "package_name": "validate_in_field_U256_Bench", + "unconstrained_functions": [ + { + "name": "__validate_in_field_compute_borrow_flags", + "opcodes": 136 + } + ] + } + ] +} diff --git a/src/benchmarks/bignum_benchmarks.nr b/src/benchmarks/bignum_benchmarks.nr index a1573f63..82616590 100644 --- a/src/benchmarks/bignum_benchmarks.nr +++ b/src/benchmarks/bignum_benchmarks.nr @@ -1,4 +1,8 @@ -use crate::bignum::BigNum; +use crate::bignum::{BigNum, BigNumTrait}; +use crate::fields::bls12_381Fq::BLS12_381_Fq; +use crate::fields::bn254Fq::BN254_Fq; +use crate::fields::U2048::U2048; +use crate::fields::U256::U256; comptime fn make_bench(_m: Module, N: u32, MOD_BITS: u32, params: Quoted) -> Quoted { let module_name = _m.name(); @@ -14,7 +18,11 @@ comptime fn make_bench(_m: Module, N: u32, MOD_BITS: u32, params: Quoted) -> Quo f"evaluate_quadratic_expression_3_elements_{module_name}".quoted_contents(); let evaluate_quadratic_expression_12_elements_bench_name = f"evaluate_quadratic_expression_12_elements_{module_name}".quoted_contents(); - + let to_be_bytes_bench_name = f"to_be_bytes_{module_name}".quoted_contents(); + let from_be_bytes_bench_name = f"from_be_bytes_{module_name}".quoted_contents(); + let to_le_bytes_bench_name = f"to_le_bytes_{module_name}".quoted_contents(); + let from_le_bytes_bench_name = f"from_le_bytes_{module_name}".quoted_contents(); + let BigNumTrait = quote { crate::bignum::BigNumTrait }; let BigNum = quote { crate::bignum::BigNum }; let BigNumTrait = quote { crate::bignum::BigNumTrait }; @@ -111,3 +119,24 @@ pub mod BLS12_381Fq_Bench { pub mod U2048_Bench { use crate::fields::U2048::U2048Params; } + +// TODO: add the benchmarks for serialization to the macro (currently dealing with trait visibility issues) +#[export] +fn bench_to_be_bytes(a: BN254_Fq) -> [u8; 32] { + a.to_be_bytes() +} + +#[export] +fn bench_from_be_bytes(a: [u8; 32]) -> BN254_Fq { + BN254_Fq::from_be_bytes(a) +} + +#[export] +fn bench_to_le_bytes(a: BN254_Fq) -> [u8; 32] { + a.to_le_bytes() +} + +#[export] +fn bench_from_le_bytes(a: [u8; 32]) -> BN254_Fq { + BN254_Fq::from_le_bytes(a) +} diff --git a/src/bignum.nr b/src/bignum.nr index 84f558f9..f3f47c28 100644 --- a/src/bignum.nr +++ b/src/bignum.nr @@ -10,7 +10,7 @@ use crate::fns::{ validate_in_range, }, expressions::{__compute_quadratic_expression, evaluate_quadratic_expression}, - serialization::{from_be_bytes, to_le_bytes}, + serialization::{from_be_bytes, from_le_bytes, to_be_bytes, to_le_bytes}, unconstrained_ops::{ __add, __batch_invert, __batch_invert_slice, __derive_from_seed, __div, __eq, __invmod, __is_zero, __mul, __neg, __pow, __sub, __tonelli_shanks_sqrt, __udiv_mod, @@ -24,6 +24,7 @@ pub struct BigNum { // We aim to avoid needing to add a generic parameter to this trait, for this reason we do not allow // accessing the limbs of the bignum except through slices. pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { + let MOD_BITS: u32; // TODO: this crashes the compiler? v0.32 // fn default() -> Self { std::default::Default::default () } fn new() -> Self; @@ -32,8 +33,10 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { fn derive_from_seed(seed: [u8; SeedBytes]) -> Self; unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self; fn from_slice(limbs: [u128]) -> Self; - fn from_be_bytes(x: [u8; NBytes]) -> Self; - fn to_le_bytes(self) -> [u8; NBytes]; + fn from_be_bytes(x: [u8; (MOD_BITS + 7) / 8]) -> Self; + fn to_be_bytes(self) -> [u8; (MOD_BITS + 7) / 8]; + fn from_le_bytes(x: [u8; (MOD_BITS + 7) / 8]) -> Self; + fn to_le_bytes(self) -> [u8; (MOD_BITS + 7) / 8]; fn modulus() -> Self; fn modulus_bits(self) -> u32; @@ -112,7 +115,7 @@ impl BigNumTrait for BigNum, { - + let MOD_BITS: u32 = MOD_BITS; #[deprecated("`BigNum::zero()` is preferred")] fn new() -> Self { Self::zero() @@ -142,12 +145,20 @@ where Self { limbs: limbs.as_array() } } - fn from_be_bytes(x: [u8; NBytes]) -> Self { - Self { limbs: from_be_bytes::<_, MOD_BITS, _>(x) } + fn from_be_bytes(x: [u8; (MOD_BITS + 7) / 8]) -> Self { + Self { limbs: from_be_bytes::<_, MOD_BITS>(x) } + } + + fn to_be_bytes(self) -> [u8; (MOD_BITS + 7) / 8] { + to_be_bytes::<_, MOD_BITS>(self.limbs) + } + + fn from_le_bytes(x: [u8; (MOD_BITS + 7) / 8]) -> Self { + Self { limbs: from_le_bytes::<_, MOD_BITS>(x) } } - fn to_le_bytes(self) -> [u8; NBytes] { - to_le_bytes::<_, MOD_BITS, _>(self.limbs) + fn to_le_bytes(self) -> [u8; (MOD_BITS + 7) / 8] { + to_le_bytes::<_, MOD_BITS>(self.limbs) } fn modulus() -> Self { diff --git a/src/fns/constrained_ops.nr b/src/fns/constrained_ops.nr index 8e203975..fbae31f6 100644 --- a/src/fns/constrained_ops.nr +++ b/src/fns/constrained_ops.nr @@ -207,7 +207,7 @@ pub(crate) fn derive_from_seed u128 { + input as u128 +} + +fn field_to_u128(input: Field) -> u128 { + // Safety: convert to u128 and validate equality + let r = unsafe { __field_to_u128(input) }; + assert_eq(r as Field, input); + r +} /** * @brief construct a BigNum instance out of an array of bytes in BIG ENDIAN format * @description: each 120-bit limb represents 15 bytes, we require that the size of the byte array * is precisely large enough to cover MOD_BITS * @param x: input byte array **/ -pub(crate) fn from_be_bytes( - x: [u8; NBytes], +pub(crate) fn from_be_bytes( + x: [u8; (MOD_BITS + 7) / 8], ) -> [u128; N] { - let num_bits = NBytes * 8; + let num_bits = (MOD_BITS + 7) / 8 * 8; assert(num_bits >= MOD_BITS); assert(num_bits - MOD_BITS < 8); let mut result: [u128; N] = [0; N]; - let excess_bytes = N * 15 - NBytes; + let excess_bytes = N * 15 - (MOD_BITS + 7) / 8; let final_limb_bytes = 15 - excess_bytes; - let mut limb: u128 = 0; + let mut limb: Field = 0; let mut k = 0; for _j in 0..final_limb_bytes { limb *= 256; - limb += x[k] as u128; + limb += x[k] as Field; k += 1; } - result[N - 1] = limb; + result[N - 1] = field_to_u128(limb); for i in 1..N { - let mut limb: u128 = 0; + let mut limb: Field = 0; for _j in 0..15 { limb *= 256; - limb += x[k] as u128; + limb += x[k] as Field; k += 1; } - result[N - i - 1] = limb; + result[N - i - 1] = field_to_u128(limb); } let most_significant_byte: Field = x[0] as Field; - most_significant_byte.assert_max_bit_size::<8 - (NBytes * 8 - MOD_BITS)>(); + most_significant_byte.assert_max_bit_size::<8 - ((MOD_BITS + 7) / 8 * 8 - MOD_BITS)>(); result } -pub(crate) fn to_le_bytes( +pub(crate) fn to_be_bytes( val: [u128; N], -) -> [u8; NBytes] { - let nbytes = (MOD_BITS / 8) + (MOD_BITS % 8 != 0) as u32; - assert(nbytes <= NBytes); +) -> [u8; (MOD_BITS + 7) / 8] { + let mut result: [u8; (MOD_BITS + 7) / 8] = [0; (MOD_BITS + 7) / 8]; + // the last limb will not have all the 15 bytes so we deal with the full limbs first + for i in 0..N - 1 { + let index = N - i - 2; + let limb_bytes: [u8; 15] = (val[index] as Field).to_be_bytes(); + for j in 0..15 { + // we leave the space for the first byte empty, which would take (MOD_BITS+7)/8 - MOD_BITS/8 bytes + result[i * 15 + j + (MOD_BITS + 7) / 8 - (N - 1) * 15] = limb_bytes[j]; + } + } + // now we deal with the last limb + let last_limb_bytes: [u8; ((MOD_BITS + 7) / 8 - (N - 1) * 15)] = + (val[N - 1] as Field).to_be_bytes(); + println(f"last_limb_bytes: {last_limb_bytes}"); + for i in 0..((MOD_BITS + 7) / 8 - (N - 1) * 15) { + result[i] = last_limb_bytes[i]; + } + result +} - let mut result: [u8; NBytes] = [0; NBytes]; +pub(crate) fn to_le_bytes( + val: [u128; N], +) -> [u8; (MOD_BITS + 7) / 8] { + let mut result: [u8; (MOD_BITS + 7) / 8] = [0; (MOD_BITS + 7) / 8]; for i in 0..N - 1 { let limb_bytes: [u8; 15] = (val[i] as Field).to_le_bytes(); for j in 0..15 { @@ -53,9 +83,46 @@ pub(crate) fn to_le_bytes( } } let last_limb_bytes: [u8; 15] = (val[N - 1] as Field).to_le_bytes(); - let num_last_bytes = (NBytes - (N - 1) * 15); + let num_last_bytes = ((MOD_BITS + 7) / 8 - (N - 1) * 15); for i in 0..num_last_bytes { result[(N - 1) * 15 + i] = last_limb_bytes[i]; } result } + +pub(crate) fn from_le_bytes( + x: [u8; (MOD_BITS + 7) / 8], +) -> [u128; N] { + let mut result: [u128; N] = [0; N]; + // first we deal with the full limbs + for i in 0..N - 1 { + let mut limb: u128 = 0; + for j in 0..15 { + limb *= 256; + limb += x[(i + 1) * 15 - j - 1] as u128; + } + result[i] = limb; + } + // now we deal with the not full limb + let num_bytes = (MOD_BITS + 7) / 8; + let excess_bytes = N * 15 - num_bytes; + let final_limb_bytes = 15 - excess_bytes; + let mut limb: u128 = 0; + for j in 0..final_limb_bytes { + limb *= 256; + limb += x[(N - 1) * 15 + final_limb_bytes - j - 1] as u128; + } + result[N - 1] = limb; + let most_significant_byte: Field = x[(MOD_BITS + 7) / 8 - 1] as Field; + // the most significant byte should have at most ((MOD_BITS+7)/8 * 8 - MOD_BITS) bits + most_significant_byte.assert_max_bit_size::<8 - ((MOD_BITS + 7) / 8 * 8 - MOD_BITS)>(); + result +} + +#[test] +fn test_from_to_le_bytes() { + let val = [2; 32]; + let result: [u128; 3] = from_le_bytes::<3, 254>(val); + let bytes: [u8; 32] = to_le_bytes::<3, 254>(result); + assert(bytes == val); +} diff --git a/src/runtime_bignum.nr b/src/runtime_bignum.nr index 167684e3..ab952abc 100644 --- a/src/runtime_bignum.nr +++ b/src/runtime_bignum.nr @@ -7,7 +7,7 @@ use crate::fns::{ neg, sub, udiv, udiv_mod, umod, validate_in_field, validate_in_range, }, expressions::{__compute_quadratic_expression, evaluate_quadratic_expression}, - serialization::{from_be_bytes, to_le_bytes}, + serialization::{from_be_bytes, from_le_bytes, to_be_bytes, to_le_bytes}, unconstrained_ops::{ __add, __batch_invert, __batch_invert_slice, __derive_from_seed, __div, __eq, __invmod, __is_zero, __mul, __neg, __pow, __sub, __tonelli_shanks_sqrt, __udiv_mod, @@ -60,15 +60,20 @@ impl RuntimeBigNum { Self { limbs, params } } - pub fn from_be_bytes( - params: BigNumParams, - x: [u8; NBytes], - ) -> Self { - Self { limbs: from_be_bytes::<_, MOD_BITS, _>(x), params } + pub fn from_be_bytes(params: BigNumParams, x: [u8; (MOD_BITS + 7) / 8]) -> Self { + Self { limbs: from_be_bytes::<_, MOD_BITS>(x), params } + } + + pub fn from_le_bytes(params: BigNumParams, x: [u8; (MOD_BITS + 7) / 8]) -> Self { + Self { limbs: from_le_bytes::<_, MOD_BITS>(x), params } + } + + pub fn to_be_bytes(self) -> [u8; (MOD_BITS + 7) / 8] { + to_be_bytes::<_, MOD_BITS>(self.limbs) } - pub fn to_le_bytes(self) -> [u8; NBytes] { - to_le_bytes::<_, MOD_BITS, _>(self.limbs) + pub fn to_le_bytes(self) -> [u8; (MOD_BITS + 7) / 8] { + to_le_bytes::<_, MOD_BITS>(self.limbs) } pub fn modulus(self) -> Self { diff --git a/src/tests/bignum_test.nr b/src/tests/bignum_test.nr index f4d11d73..712ba2d3 100644 --- a/src/tests/bignum_test.nr +++ b/src/tests/bignum_test.nr @@ -974,3 +974,20 @@ fn test_cmp_BN_fuzz(seed: [u8; 5]) { a = if a > modulus_sub_1_div_2 { -a } else { a }; assert(a < modulus_sub_1_div_2); } + +#[test] +fn fuzz_from_le_bytes(seed: [u8; 5]) { + let a = BN254_Fq::derive_from_seed(seed); + let bytes = a.to_le_bytes(); + let b = BN254_Fq::from_le_bytes(bytes); + assert(a == b); +} + +#[test] +fn fuzz_to_be_bytes(seed: [u8; 5]) { + let a = BN254_Fq::derive_from_seed(seed); + let bytes = a.to_be_bytes(); + let b = BN254_Fq::from_be_bytes(bytes); + println(b); + assert(a == b); +} From 5eeefa28acd5acb631f4cf2d5195f9c0ea9a81b2 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Mon, 7 Apr 2025 13:43:44 +0100 Subject: [PATCH 2/9] removed the brillig report --- brillig_report.json | 511 -------------------------------------------- 1 file changed, 511 deletions(-) delete mode 100644 brillig_report.json diff --git a/brillig_report.json b/brillig_report.json deleted file mode 100644 index fc216128..00000000 --- a/brillig_report.json +++ /dev/null @@ -1,511 +0,0 @@ -{ - "programs": [ - { - "package_name": "add_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__add_with_flags", - "opcodes": 501 - } - ] - }, - { - "package_name": "add_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__add_with_flags", - "opcodes": 486 - } - ] - }, - { - "package_name": "add_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__add_with_flags", - "opcodes": 578 - } - ] - }, - { - "package_name": "add_U256_Bench", - "unconstrained_functions": [ - { - "name": "__add_with_flags", - "opcodes": 486 - } - ] - }, - { - "package_name": "bench_from_be_bytes", - "unconstrained_functions": [ - { - "name": "__field_to_u128", - "opcodes": 25 - } - ] - }, - { - "package_name": "bench_from_le_bytes", - "unconstrained_functions": [] - }, - { - "package_name": "bench_to_be_bytes", - "unconstrained_functions": [ - { - "name": "print_unconstrained", - "opcodes": 270 - }, - { - "name": "directive_to_radix", - "opcodes": 17 - } - ] - }, - { - "package_name": "bench_to_le_bytes", - "unconstrained_functions": [ - { - "name": "directive_to_radix", - "opcodes": 17 - } - ] - }, - { - "package_name": "div_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__div", - "opcodes": 4585 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2526 - } - ] - }, - { - "package_name": "div_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__div", - "opcodes": 4413 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2437 - } - ] - }, - { - "package_name": "div_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__div", - "opcodes": 5023 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2764 - } - ] - }, - { - "package_name": "div_U256_Bench", - "unconstrained_functions": [ - { - "name": "__div", - "opcodes": 4413 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2437 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_12_elements_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 4715 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_12_elements_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 4555 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_12_elements_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 5963 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_12_elements_U256_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 4555 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_3_elements_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 3131 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_3_elements_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 3024 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_3_elements_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 3622 - } - ] - }, - { - "package_name": "evaluate_quadratic_expression_3_elements_U256_Bench", - "unconstrained_functions": [ - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 3024 - } - ] - }, - { - "package_name": "from_field_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__from_field", - "opcodes": 82 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 377 - } - ] - }, - { - "package_name": "from_field_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__from_field", - "opcodes": 79 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 369 - } - ] - }, - { - "package_name": "from_field_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__from_field", - "opcodes": 110 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 408 - } - ] - }, - { - "package_name": "from_field_U256_Bench", - "unconstrained_functions": [ - { - "name": "__from_field", - "opcodes": 79 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 369 - } - ] - }, - { - "package_name": "mul_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__mul", - "opcodes": 1668 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2526 - } - ] - }, - { - "package_name": "mul_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__mul", - "opcodes": 1592 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2437 - } - ] - }, - { - "package_name": "mul_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__mul", - "opcodes": 1841 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2764 - } - ] - }, - { - "package_name": "mul_U256_Bench", - "unconstrained_functions": [ - { - "name": "__mul", - "opcodes": 1592 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2437 - } - ] - }, - { - "package_name": "sub_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__sub_with_flags", - "opcodes": 415 - } - ] - }, - { - "package_name": "sub_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__sub_with_flags", - "opcodes": 404 - } - ] - }, - { - "package_name": "sub_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__sub_with_flags", - "opcodes": 490 - } - ] - }, - { - "package_name": "sub_U256_Bench", - "unconstrained_functions": [ - { - "name": "__sub_with_flags", - "opcodes": 404 - } - ] - }, - { - "package_name": "udiv_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 2034 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2566 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 377 - } - ] - }, - { - "package_name": "udiv_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 1948 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2474 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 369 - } - ] - }, - { - "package_name": "udiv_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 2095 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2818 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 408 - } - ] - }, - { - "package_name": "udiv_U256_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 1948 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2474 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 369 - } - ] - }, - { - "package_name": "udiv_mod_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 2034 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2566 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 377 - } - ] - }, - { - "package_name": "udiv_mod_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 1948 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2474 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 369 - } - ] - }, - { - "package_name": "udiv_mod_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 2095 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2818 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 408 - } - ] - }, - { - "package_name": "udiv_mod_U256_Bench", - "unconstrained_functions": [ - { - "name": "__udiv_mod", - "opcodes": 1948 - }, - { - "name": "__compute_quadratic_expression_with_borrow_flags", - "opcodes": 2474 - }, - { - "name": "__validate_gt_remainder", - "opcodes": 369 - } - ] - }, - { - "package_name": "validate_in_field_BLS12_381Fq_Bench", - "unconstrained_functions": [ - { - "name": "__validate_in_field_compute_borrow_flags", - "opcodes": 209 - } - ] - }, - { - "package_name": "validate_in_field_BN254_Fq_Bench", - "unconstrained_functions": [ - { - "name": "__validate_in_field_compute_borrow_flags", - "opcodes": 136 - } - ] - }, - { - "package_name": "validate_in_field_U2048_Bench", - "unconstrained_functions": [ - { - "name": "__validate_in_field_compute_borrow_flags", - "opcodes": 293 - } - ] - }, - { - "package_name": "validate_in_field_U256_Bench", - "unconstrained_functions": [ - { - "name": "__validate_in_field_compute_borrow_flags", - "opcodes": 136 - } - ] - } - ] -} From 342d34fb72457558984dea7e6e50711182c4dc5f Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Mon, 7 Apr 2025 14:51:59 +0100 Subject: [PATCH 3/9] remove prints --- src/fns/serialization.nr | 2 +- src/tests/bignum_test.nr | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fns/serialization.nr b/src/fns/serialization.nr index e2a163c7..13044021 100644 --- a/src/fns/serialization.nr +++ b/src/fns/serialization.nr @@ -65,7 +65,7 @@ pub(crate) fn to_be_bytes( // now we deal with the last limb let last_limb_bytes: [u8; ((MOD_BITS + 7) / 8 - (N - 1) * 15)] = (val[N - 1] as Field).to_be_bytes(); - println(f"last_limb_bytes: {last_limb_bytes}"); + for i in 0..((MOD_BITS + 7) / 8 - (N - 1) * 15) { result[i] = last_limb_bytes[i]; } diff --git a/src/tests/bignum_test.nr b/src/tests/bignum_test.nr index 712ba2d3..ceb258c4 100644 --- a/src/tests/bignum_test.nr +++ b/src/tests/bignum_test.nr @@ -988,6 +988,5 @@ fn fuzz_to_be_bytes(seed: [u8; 5]) { let a = BN254_Fq::derive_from_seed(seed); let bytes = a.to_be_bytes(); let b = BN254_Fq::from_be_bytes(bytes); - println(b); assert(a == b); } From f1035466276c595b39a41e27e4fdfda5b0d754d7 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Tue, 8 Apr 2025 10:45:33 +0100 Subject: [PATCH 4/9] bumped nargo version --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/test.yml | 2 +- src/benchmarks/bignum_benchmarks.nr | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 83fbfde5..1a247380 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -17,12 +17,12 @@ jobs: - name: Install Nargo uses: noir-lang/noirup@v0.1.4 with: - toolchain: 1.0.0-beta.3 + toolchain: 1.0.0-beta.4 - name: Install bb run: | npm install -g bbup - bbup -nv 1.0.0-beta.3 + bbup -nv 1.0.0-beta.4 sudo apt install libc++-dev - name: Build Noir benchmark programs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6d634d65..1a6aa674 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ on: env: CARGO_TERM_COLOR: always - MINIMUM_NOIR_VERSION: v1.0.0-beta.3 + MINIMUM_NOIR_VERSION: v1.0.0-beta.4 jobs: noir-version-list: diff --git a/src/benchmarks/bignum_benchmarks.nr b/src/benchmarks/bignum_benchmarks.nr index 82616590..888ecfd6 100644 --- a/src/benchmarks/bignum_benchmarks.nr +++ b/src/benchmarks/bignum_benchmarks.nr @@ -90,7 +90,7 @@ comptime fn make_bench(_m: Module, N: u32, MOD_BITS: u32, params: Quoted) -> Quo ) { $BigNumTrait::evaluate_quadratic_expression(lhs, lhs_flags, rhs, rhs_flags, add, add_flags) } - + } } @@ -101,22 +101,26 @@ comptime fn make_bench(_m: Module, N: u32, MOD_BITS: u32, params: Quoted) -> Quo // type U2048 #[make_bench(3, 254, quote { BN254_Fq_Params })] pub mod BN254_Fq_Bench { + use crate::bignum::BigNumTrait; use crate::fields::bn254Fq::BN254_Fq_Params; } #[make_bench(3, 257, quote { U256Params })] pub mod U256_Bench { + use crate::bignum::BigNumTrait; use crate::fields::U256::U256Params; } #[make_bench(4, 381, quote { BLS12_381_Fq_Params })] pub mod BLS12_381Fq_Bench { + use crate::bignum::BigNumTrait; use crate::fields::bls12_381Fq::BLS12_381_Fq_Params; } #[make_bench(18, 2049, quote { U2048Params })] pub mod U2048_Bench { + use crate::bignum::BigNumTrait; use crate::fields::U2048::U2048Params; } From a081449d4df9d5346b0a79c4225f7daa4a6390d9 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Tue, 8 Apr 2025 10:46:59 +0100 Subject: [PATCH 5/9] bb version --- .github/workflows/benchmark.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 1a247380..f2085dc6 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -15,14 +15,14 @@ jobs: uses: actions/checkout@v4 - name: Install Nargo - uses: noir-lang/noirup@v0.1.4 + uses: noir-lang/noirup@v0.1.3 with: toolchain: 1.0.0-beta.4 - name: Install bb run: | npm install -g bbup - bbup -nv 1.0.0-beta.4 + bbup -nv 1.0.0-beta.3 sudo apt install libc++-dev - name: Build Noir benchmark programs From 45b51b7f5dff4e64295645c409311d69f4c2ee85 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Tue, 8 Apr 2025 10:48:17 +0100 Subject: [PATCH 6/9] newer noirup --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index f2085dc6..07732ad1 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@v4 - name: Install Nargo - uses: noir-lang/noirup@v0.1.3 + uses: noir-lang/noirup@v0.1.4 with: toolchain: 1.0.0-beta.4 From 3840a5a8554659255ced08117e3a8bf17588dc14 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Tue, 8 Apr 2025 10:53:45 +0100 Subject: [PATCH 7/9] changed the casting to u128 --- src/fns/serialization.nr | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/fns/serialization.nr b/src/fns/serialization.nr index 13044021..bbac78a1 100644 --- a/src/fns/serialization.nr +++ b/src/fns/serialization.nr @@ -1,13 +1,3 @@ -unconstrained fn __field_to_u128(input: Field) -> u128 { - input as u128 -} - -fn field_to_u128(input: Field) -> u128 { - // Safety: convert to u128 and validate equality - let r = unsafe { __field_to_u128(input) }; - assert_eq(r as Field, input); - r -} /** * @brief construct a BigNum instance out of an array of bytes in BIG ENDIAN format * @description: each 120-bit limb represents 15 bytes, we require that the size of the byte array @@ -31,7 +21,8 @@ pub(crate) fn from_be_bytes( limb += x[k] as Field; k += 1; } - result[N - 1] = field_to_u128(limb); + limb.assert_max_bit_size::<128>(); + result[N - 1] = limb as u128; for i in 1..N { let mut limb: Field = 0; @@ -40,7 +31,8 @@ pub(crate) fn from_be_bytes( limb += x[k] as Field; k += 1; } - result[N - i - 1] = field_to_u128(limb); + limb.assert_max_bit_size::<128>(); + result[N - i - 1] = limb as u128; } let most_significant_byte: Field = x[0] as Field; @@ -96,33 +88,27 @@ pub(crate) fn from_le_bytes( let mut result: [u128; N] = [0; N]; // first we deal with the full limbs for i in 0..N - 1 { - let mut limb: u128 = 0; + let mut limb: Field = 0; for j in 0..15 { limb *= 256; - limb += x[(i + 1) * 15 - j - 1] as u128; + limb += x[(i + 1) * 15 - j - 1] as Field; } - result[i] = limb; + limb.assert_max_bit_size::<128>(); + result[i] = limb as u128; } // now we deal with the not full limb let num_bytes = (MOD_BITS + 7) / 8; let excess_bytes = N * 15 - num_bytes; let final_limb_bytes = 15 - excess_bytes; - let mut limb: u128 = 0; + let mut limb: Field = 0; for j in 0..final_limb_bytes { limb *= 256; - limb += x[(N - 1) * 15 + final_limb_bytes - j - 1] as u128; + limb += x[(N - 1) * 15 + final_limb_bytes - j - 1] as Field; } - result[N - 1] = limb; + limb.assert_max_bit_size::<128>(); + result[N - 1] = limb as u128; let most_significant_byte: Field = x[(MOD_BITS + 7) / 8 - 1] as Field; // the most significant byte should have at most ((MOD_BITS+7)/8 * 8 - MOD_BITS) bits most_significant_byte.assert_max_bit_size::<8 - ((MOD_BITS + 7) / 8 * 8 - MOD_BITS)>(); result } - -#[test] -fn test_from_to_le_bytes() { - let val = [2; 32]; - let result: [u128; 3] = from_le_bytes::<3, 254>(val); - let bytes: [u8; 32] = to_le_bytes::<3, 254>(result); - assert(bytes == val); -} From 2a8d736d52ae2b8737d9401164c72673c5145f09 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Tue, 8 Apr 2025 11:56:41 +0100 Subject: [PATCH 8/9] moved the benchmarks into macros --- src/benchmarks/bignum_benchmarks.nr | 41 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/benchmarks/bignum_benchmarks.nr b/src/benchmarks/bignum_benchmarks.nr index 888ecfd6..0e330bec 100644 --- a/src/benchmarks/bignum_benchmarks.nr +++ b/src/benchmarks/bignum_benchmarks.nr @@ -91,6 +91,26 @@ comptime fn make_bench(_m: Module, N: u32, MOD_BITS: u32, params: Quoted) -> Quo $BigNumTrait::evaluate_quadratic_expression(lhs, lhs_flags, rhs, rhs_flags, add, add_flags) } + #[export] + fn $to_be_bytes_bench_name(a: $BigNum<$N, $MOD_BITS, $params>) -> [u8; ($MOD_BITS+7) / 8] { + $BigNum::<$N, $MOD_BITS, $params> ::to_be_bytes(a) + } + + #[export] + fn $from_be_bytes_bench_name(a: [u8; ($MOD_BITS+7) / 8]) -> $BigNum<$N, $MOD_BITS, $params> { + $BigNum::<$N, $MOD_BITS, $params> ::from_be_bytes(a) + } + + #[export] + fn $to_le_bytes_bench_name(a: $BigNum<$N, $MOD_BITS, $params>) -> [u8; ($MOD_BITS+7) / 8] { + $BigNum::<$N, $MOD_BITS, $params> ::to_le_bytes(a) + } + + #[export] + fn $from_le_bytes_bench_name(a: [u8; ($MOD_BITS+7) / 8]) -> $BigNum<$N, $MOD_BITS, $params> { + $BigNum::<$N, $MOD_BITS, $params> ::from_le_bytes(a) + } + } } @@ -123,24 +143,3 @@ pub mod U2048_Bench { use crate::bignum::BigNumTrait; use crate::fields::U2048::U2048Params; } - -// TODO: add the benchmarks for serialization to the macro (currently dealing with trait visibility issues) -#[export] -fn bench_to_be_bytes(a: BN254_Fq) -> [u8; 32] { - a.to_be_bytes() -} - -#[export] -fn bench_from_be_bytes(a: [u8; 32]) -> BN254_Fq { - BN254_Fq::from_be_bytes(a) -} - -#[export] -fn bench_to_le_bytes(a: BN254_Fq) -> [u8; 32] { - a.to_le_bytes() -} - -#[export] -fn bench_from_le_bytes(a: [u8; 32]) -> BN254_Fq { - BN254_Fq::from_le_bytes(a) -} From 8b0a1d0bebddc62324d8e90ff33229f32bec5d96 Mon Sep 17 00:00:00 2001 From: Khashayar Barooti Date: Tue, 8 Apr 2025 16:29:29 +0100 Subject: [PATCH 9/9] unified the le and be logics --- src/fns/serialization.nr | 53 +++++++--------------------------------- src/utils/map.nr | 9 +++++++ 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/src/fns/serialization.nr b/src/fns/serialization.nr index bbac78a1..41267735 100644 --- a/src/fns/serialization.nr +++ b/src/fns/serialization.nr @@ -1,9 +1,7 @@ -/** -* @brief construct a BigNum instance out of an array of bytes in BIG ENDIAN format -* @description: each 120-bit limb represents 15 bytes, we require that the size of the byte array -* is precisely large enough to cover MOD_BITS -* @param x: input byte array -**/ +use crate::utils::map::invert_array; +/// conversions between big endian and little endian byte arrays and BigNum instances +/// the byte serialization should have `(MOD_BITS + 7) / 8` bytes. +/// each 120-bit limb is represented by 15 bytes, and there are fewer bytes for covering the most significant limb pub(crate) fn from_be_bytes( x: [u8; (MOD_BITS + 7) / 8], ) -> [u128; N] { @@ -67,48 +65,15 @@ pub(crate) fn to_be_bytes( pub(crate) fn to_le_bytes( val: [u128; N], ) -> [u8; (MOD_BITS + 7) / 8] { - let mut result: [u8; (MOD_BITS + 7) / 8] = [0; (MOD_BITS + 7) / 8]; - for i in 0..N - 1 { - let limb_bytes: [u8; 15] = (val[i] as Field).to_le_bytes(); - for j in 0..15 { - result[i * 15 + j] = limb_bytes[j]; - } - } - let last_limb_bytes: [u8; 15] = (val[N - 1] as Field).to_le_bytes(); - let num_last_bytes = ((MOD_BITS + 7) / 8 - (N - 1) * 15); - for i in 0..num_last_bytes { - result[(N - 1) * 15 + i] = last_limb_bytes[i]; - } + let result_be: [u8; (MOD_BITS + 7) / 8] = to_be_bytes(val); + let result = invert_array(result_be); result } pub(crate) fn from_le_bytes( x: [u8; (MOD_BITS + 7) / 8], ) -> [u128; N] { - let mut result: [u128; N] = [0; N]; - // first we deal with the full limbs - for i in 0..N - 1 { - let mut limb: Field = 0; - for j in 0..15 { - limb *= 256; - limb += x[(i + 1) * 15 - j - 1] as Field; - } - limb.assert_max_bit_size::<128>(); - result[i] = limb as u128; - } - // now we deal with the not full limb - let num_bytes = (MOD_BITS + 7) / 8; - let excess_bytes = N * 15 - num_bytes; - let final_limb_bytes = 15 - excess_bytes; - let mut limb: Field = 0; - for j in 0..final_limb_bytes { - limb *= 256; - limb += x[(N - 1) * 15 + final_limb_bytes - j - 1] as Field; - } - limb.assert_max_bit_size::<128>(); - result[N - 1] = limb as u128; - let most_significant_byte: Field = x[(MOD_BITS + 7) / 8 - 1] as Field; - // the most significant byte should have at most ((MOD_BITS+7)/8 * 8 - MOD_BITS) bits - most_significant_byte.assert_max_bit_size::<8 - ((MOD_BITS + 7) / 8 * 8 - MOD_BITS)>(); - result + // make the bytes big endian + let be_x = invert_array(x); + from_be_bytes(be_x) } diff --git a/src/utils/map.nr b/src/utils/map.nr index 6dc48820..a3ee0d38 100644 --- a/src/utils/map.nr +++ b/src/utils/map.nr @@ -9,3 +9,12 @@ pub(crate) fn map(arr: [T; N], f: fn[Env](T) -> U) -> [U; ret } + +pub(crate) fn invert_array(array: [T; M]) -> [T; M] { + let mut ret: [T; M] = std::mem::zeroed(); + + for i in 0..M { + ret[i] = array[M - i - 1]; + } + ret +}