diff --git a/export/test_add_BN.json b/export/test_add_BN.json new file mode 100644 index 00000000..58b84a13 --- /dev/null +++ b/export/test_add_BN.json @@ -0,0 +1 @@ +{"noir_version":"0.36.0+801c71880ecf8386a26737a5d8bb5b4cb164b2ab","hash":1828426501882327147,"abi":{"parameters":[],"return_type":null,"error_types":{}},"bytecode":"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","debug_symbols":"zZJNCsMgFITv8tYuoml+r1JK0ESDIBrUFIp495o2bQPNAdzNvPkYZvECTJyt8yC1MA76awBlRuql0ckFKF4nt1C9Oeep9dC35IKA62lTXUQgpOJJNxH9oRhXpNvhpNvii2NSnPGkrqsPT+ruV9+U8YYAZ7aHZLanzGpPMsxKpeQ8HL8qne/USsoU361Y9XhI/WN5J6niCQ==","file_map":{"73":{"source":"use crate::params::BigNumParams as P;\n\nuse crate::fns::{\n expressions::evaluate_quadratic_expression,\n unconstrained_helpers::{\n __add_with_flags, __neg_with_flags, __sub_with_flags, __validate_gt_remainder,\n __validate_in_field_compute_borrow_flags,\n }, unconstrained_ops::{__div, __mul, __udiv_mod},\n};\n\n/**\n * In this file:\n *\n * conditional_select\n * assert_is_not_equal\n * eq\n * validate_in_field\n * validate_in_range\n * validate_quotient_in_range\n * validate_gt\n * neg\n * add\n * sub\n * mul\n * div\n * udiv_mod\n * udiv\n * umod\n */\n\n/**\n* @brief given an input seed, generate a pseudorandom BigNum value\n* @details we hash the input seed into `modulus_bits * 2` bits of entropy,\n* which is then reduced into a BigNum value\n* We use a hash function that can be modelled as a random oracle\n* This function *should* produce an output that is a uniformly randomly distributed value modulo BigNum::modulus()\n**/\npub(crate) fn derive_from_seed(\n params: P,\n seed: [u8; SeedBytes],\n) -> [Field; N] {\n let mut rolling_seed: [u8; SeedBytes + 1] = [0; SeedBytes + 1];\n for i in 0..SeedBytes {\n rolling_seed[i] = seed[i];\n assert_eq(rolling_seed[i], seed[i]);\n }\n\n let mut hash_buffer: [u8; N * 2 * 15] = [0; N * 2 * 15];\n\n let mut rolling_hash_fields: [Field; (SeedBytes / 31) + 1] = [0; (SeedBytes / 31) + 1];\n let mut seed_ptr = 0;\n for i in 0..(SeedBytes / 31) + 1 {\n let mut packed: Field = 0;\n for _ in 0..31 {\n if (seed_ptr < SeedBytes) {\n packed *= 256;\n packed += seed[seed_ptr] as Field;\n seed_ptr += 1;\n }\n }\n rolling_hash_fields[i] = packed;\n }\n\n let compressed =\n std::hash::poseidon2::Poseidon2::hash(rolling_hash_fields, (SeedBytes / 31) + 1);\n let mut rolling_hash: [Field; 2] = [compressed, 0];\n\n let num_hashes = (240 * N) / 254 + (((30 * N) % 32) != 0) as u32;\n for i in 0..num_hashes - 1 {\n let hash: Field = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2);\n let hash: [u8; 32] = hash.to_le_bytes();\n for j in 0..30 {\n hash_buffer[i * 30 + j] = hash[j];\n }\n rolling_hash[1] += 1;\n }\n\n {\n let hash: Field = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2);\n let hash: [u8; 32] = hash.to_le_bytes();\n let remaining_bytes = 30 * N - (num_hashes - 1) * 30;\n for j in 0..remaining_bytes {\n hash_buffer[(num_hashes - 1) * 30 + j] = hash[j];\n }\n }\n\n let num_bits = MOD_BITS * 2;\n let num_bytes = num_bits / 8 + ((num_bits % 8) != 0) as u32;\n\n let bits_in_last_byte = num_bits as u8 % 8;\n let last_byte_mask = (1 as u8 << bits_in_last_byte) - 1;\n hash_buffer[num_bytes - 1] = hash_buffer[num_bytes - 1] & last_byte_mask;\n\n let num_bigfield_chunks = (2 * N) / (N - 1) + (((2 * N) % (N - 1)) != 0) as u32;\n let mut byte_ptr = 0;\n\n // we want to convert our byte array into bigfield chunks\n // each chunk has at most N-1 limbs\n // to determine the exact number of chunks, we need the `!=` or `>` operator which is not avaiable when defining array sizes\n // so we overestimate at 4\n // e.g. if N = 20, then we have 40 limbs we want to reduce, but each bigfield chunk is 19 limbs, so we need 3\n // if N = 2, we have 4 limbs we want to reduce but each bigfield chunk is only 1 limb, so we need 4\n // max possible number of chunks is therefore 4\n let mut bigfield_chunks: [[Field; N]; 4] = [[0; N]; 4];\n for k in 0..num_bigfield_chunks {\n let mut bigfield_limbs: [Field; N] = [0; N];\n let mut num_filled_bytes = (k * 30);\n let mut num_remaining_bytes = num_bytes - num_filled_bytes;\n let mut num_remaining_limbs =\n (num_remaining_bytes / 15) + (num_remaining_bytes % 15 > 0) as u32;\n let mut more_than_N_minus_one_limbs = (num_remaining_limbs > (N - 1)) as u32;\n let mut num_limbs_in_bigfield = more_than_N_minus_one_limbs * (N - 1)\n + num_remaining_limbs * (1 - more_than_N_minus_one_limbs);\n\n for j in 0..num_limbs_in_bigfield {\n let mut limb: Field = 0;\n for _ in 0..15 {\n let need_more_bytes = (byte_ptr < num_bytes);\n let mut byte = hash_buffer[byte_ptr];\n limb *= (256 * need_more_bytes as Field + (1 - need_more_bytes as Field));\n limb += byte as Field * need_more_bytes as Field;\n byte_ptr += need_more_bytes as u32;\n }\n bigfield_limbs[num_limbs_in_bigfield - 1 - j] = limb;\n }\n bigfield_chunks[num_bigfield_chunks - 1 - k] = bigfield_limbs;\n }\n\n let mut bigfield_rhs_limbs: [Field; N] = [0; N];\n bigfield_rhs_limbs[N - 1] = 1;\n validate_in_range::<_, MOD_BITS>(bigfield_rhs_limbs);\n\n let mut result: [Field; N] = [0; N];\n\n for i in 0..num_bigfield_chunks {\n let bigfield_lhs_limbs = bigfield_chunks[i];\n\n result = mul(params, result, bigfield_rhs_limbs);\n result = add(params, result, bigfield_lhs_limbs);\n }\n result\n}\n\n/**\n* @brief conditional_select given the value of `predicate` return either `self` (if 0) or `other` (if 1)\n* @description should be cheaper than using an IF statement (TODO: check!)\n**/\npub(crate) fn conditional_select(\n lhs: [Field; N],\n rhs: [Field; N],\n predicate: bool,\n) -> [Field; N] {\n let mut result: [Field; N] = lhs;\n for i in 0..N {\n result[i] = (lhs[i] - rhs[i]) * predicate as Field + rhs[i];\n }\n result\n}\n\n/**\n * @brief Validate self != other\n * @details If A == B, then A == B mod N.\n * We can efficiently evaluate A == B mod N where N = circuit modulus\n * This method is *sound*, but not *complete* (i.e. A != B but A == B mod N)\n * However the probability of an honest Prover being unable to satisfy this check is tiny!\n * (todo: compute how tiny)\n **/\npub(crate) fn assert_is_not_equal(\n params: P,\n lhs: [Field; N],\n rhs: [Field; N],\n) {\n let mut l: Field = 0;\n let mut r: Field = 0;\n let mut modulus_mod_n: Field = 0;\n let two_pow_120: Field = 0x1000000000000000000000000000000;\n let modulus = params.modulus;\n for i in 0..N {\n l *= two_pow_120;\n r *= two_pow_120;\n modulus_mod_n *= two_pow_120;\n l += lhs[N - i - 1];\n r += rhs[N - i - 1];\n modulus_mod_n += modulus[N - i - 1];\n }\n\n // lhs can be either X mod N or P + X mod N\n // rhs can be either Y mod N or P + Y mod N\n // If lhs - rhs = 0 mod P then lhs - rhs = 0, P or -P mod N\n let mut diff = l - r;\n let mut target = diff * (diff + modulus_mod_n) * (diff - modulus_mod_n);\n assert(target != 0, \"asssert_is_not_equal fail\");\n}\n\npub(crate) fn eq(\n params: P,\n lhs: [Field; N],\n rhs: [Field; N],\n) -> bool {\n let diff = sub::<_, MOD_BITS>(params, lhs, rhs);\n // if self == other, possible values of `diff` will be `p` or `0`\n // (the subtract operator constrains diff to be < ceil(log(p)))\n // TODO: can do this more efficiently via witngen in unconstrained functions?\n let mut is_equal_modulus: bool = true;\n let mut is_equal_zero: bool = true;\n for i in 0..N {\n is_equal_modulus = is_equal_modulus & (diff[i] == params.modulus[i]);\n is_equal_zero = is_equal_zero & (diff[i] == 0);\n }\n is_equal_modulus | is_equal_zero\n}\n\npub(crate) fn validate_in_field(\n params: P,\n val: [Field; N],\n) {\n // N.B. need to combine with validate_in_range if `self` limbs have not been range constrained\n let mut p_minus_self: [Field; N] = [0; N];\n let modulus: [Field; N] = params.modulus;\n for i in 0..N {\n p_minus_self[i] = modulus[i] - val[i];\n }\n let borrow_flags = unsafe { __validate_in_field_compute_borrow_flags(params, val) };\n let two_pow_120: Field = 0x1000000000000000000000000000000;\n p_minus_self[0] += borrow_flags[0] as Field * two_pow_120;\n for i in 1..N - 1 {\n p_minus_self[i] += (borrow_flags[i] as Field * two_pow_120 - borrow_flags[i - 1] as Field);\n }\n p_minus_self[N - 1] -= borrow_flags[N - 2] as Field;\n let mut compare = val;\n compare = p_minus_self;\n validate_in_range::<_, MOD_BITS>(compare);\n}\n\n/**\n* @brief Validate a BigNum instance is correctly range constrained to contain no more than Params::modulus_bits()\n**/\npub(crate) fn validate_in_range(limbs: [Field; N]) {\n for i in 0..(N - 1) {\n limbs[i].assert_max_bit_size::<120>();\n }\n limbs[N - 1].assert_max_bit_size::();\n}\n\n/**\n* @brief validate quotient produced from `evaluate_quadratic_expression` is well-formed\n* @description because the inputs into evaluate_quadratic_expression may cause the quotient to extend beyond `Params::modulus_bits`.\n* We allow the quotient to extend 6 bits beyond Params::modulus_bits()\n* Why is this?\n* several factors: 1. quotient * modulus , limbs cannot overflow field boundary (254 bits)\n* 2. in `evaluate_quadratic_expression`, we require that for `expression - quotient * modulus`,\n* limbs cannot exceed 246 bits (246 magic number due to a higher number adding extra range check gates)\n* because of factor 2 and the fact that modulus limbs are 120 bits, quotient limbs cannot be >126 bits\n*\n* Note: doesn't this mean that final_limb_bits should be constrained to be 126 bits, not modulus_bits() - ((N - 1) * 120) + 6?\n* TODO: think about this more! we want the range constraint we apply to be as small as allowable as this is more efficient\n**/\npub(crate) fn validate_quotient_in_range(limbs: [Field; N]) {\n for i in 0..(N) {\n limbs[i].assert_max_bit_size::<120>();\n }\n // Note: replace magic number 6 with definition\n limbs[N - 1].assert_max_bit_size::();\n}\n\n// validate that lhs - rhs does not underflow i.e. lhs > rhs\npub(crate) fn validate_gt(lhs: [Field; N], rhs: [Field; N]) {\n // so we do... p - x - r = 0 and there might be borrow flags\n // a - b = r\n // p + a - b - r = 0\n let (result, carry_flags, borrow_flags) = unsafe { __validate_gt_remainder(lhs, rhs) };\n validate_in_range::<_, MOD_BITS>(result);\n\n let borrow_shift = 0x1000000000000000000000000000000;\n let carry_shift = 0x1000000000000000000000000000000;\n\n let mut addend: [Field; N] = [0; N];\n let result_limb = lhs[0] - rhs[0] + addend[0] - result[0] - 1\n + (borrow_flags[0] as Field * borrow_shift)\n - (carry_flags[0] as Field * carry_shift);\n assert(result_limb == 0);\n\n for i in 1..N - 1 {\n let result_limb = lhs[i] - rhs[i] + addend[i] - result[i] - borrow_flags[i - 1] as Field\n + carry_flags[i - 1] as Field\n + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift);\n assert(result_limb == 0);\n }\n\n let result_limb = lhs[N - 1] - rhs[N - 1] + addend[N - 1]\n - result[N - 1]\n - borrow_flags[N - 2] as Field\n + carry_flags[N - 2] as Field;\n assert(result_limb == 0);\n}\n\npub(crate) fn neg(\n params: P,\n val: [Field; N],\n) -> [Field; N] {\n // so we do... p - x - r = 0 and there might be borrow flags\n let (result, borrow_flags) = unsafe { __neg_with_flags(params, val) };\n validate_in_range::<_, MOD_BITS>(result);\n let modulus = params.modulus;\n let borrow_shift = 0x1000000000000000000000000000000;\n let result_limb = modulus[0] - val[0] - result[0] + (borrow_flags[0] as Field * borrow_shift);\n assert(result_limb == 0);\n for i in 1..N - 1 {\n let result_limb = modulus[i] - val[i] - result[i] - borrow_flags[i - 1] as Field\n + (borrow_flags[i] as Field * borrow_shift);\n assert(result_limb == 0);\n }\n let result_limb = modulus[N - 1] - val[N - 1] - result[N - 1] - borrow_flags[N - 2] as Field;\n assert(result_limb == 0);\n result\n}\n\npub(crate) fn add(\n params: P,\n lhs: [Field; N],\n rhs: [Field; N],\n) -> [Field; N] {\n // so we do... p - x - r = 0 and there might be borrow flags\n let (result, carry_flags, borrow_flags, overflow_modulus) =\n unsafe { __add_with_flags(params, lhs, rhs) };\n validate_in_range::<_, MOD_BITS>(result);\n let modulus = params.modulus;\n let borrow_shift = 0x1000000000000000000000000000000;\n let carry_shift = 0x1000000000000000000000000000000;\n\n let mut subtrahend: [Field; N] = [0; N];\n if (overflow_modulus) {\n subtrahend = modulus;\n }\n let result_limb = lhs[0] + rhs[0] - subtrahend[0] - result[0]\n + (borrow_flags[0] as Field * borrow_shift)\n - (carry_flags[0] as Field * carry_shift);\n assert(result_limb == 0);\n for i in 1..N - 1 {\n let result_limb = lhs[i] + rhs[i] - subtrahend[i] - result[i] - borrow_flags[i - 1] as Field\n + carry_flags[i - 1] as Field\n + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift);\n assert(result_limb == 0);\n }\n let result_limb = lhs[N - 1] + rhs[N - 1]\n - subtrahend[N - 1]\n - result[N - 1]\n - borrow_flags[N - 2] as Field\n + carry_flags[N - 2] as Field;\n assert(result_limb == 0);\n result\n}\n\npub(crate) fn sub(\n params: P,\n lhs: [Field; N],\n rhs: [Field; N],\n) -> [Field; N] {\n // so we do... p - x - r = 0 and there might be borrow flags\n // a - b = r\n // p + a - b - r = 0\n let (result, carry_flags, borrow_flags, underflow) =\n unsafe { __sub_with_flags(params, lhs, rhs) };\n validate_in_range::<_, MOD_BITS>(result);\n let modulus = params.modulus;\n let borrow_shift = 0x1000000000000000000000000000000;\n let carry_shift = 0x1000000000000000000000000000000;\n\n let mut addend: [Field; N] = [0; N];\n if (underflow) {\n addend = modulus;\n }\n let result_limb = lhs[0] - rhs[0] + addend[0] - result[0]\n + (borrow_flags[0] as Field * borrow_shift)\n - (carry_flags[0] as Field * carry_shift);\n assert(result_limb == 0);\n for i in 1..N - 1 {\n let result_limb = lhs[i] - rhs[i] + addend[i] - result[i] - borrow_flags[i - 1] as Field\n + carry_flags[i - 1] as Field\n + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift);\n assert(result_limb == 0);\n }\n let result_limb = lhs[N - 1] - rhs[N - 1] + addend[N - 1]\n - result[N - 1]\n - borrow_flags[N - 2] as Field\n + carry_flags[N - 2] as Field;\n assert(result_limb == 0);\n result\n}\n\n// Note: this method is expensive! Try to craft quadratic relations and directly evaluate them\n// via evaluate_quadratic_expression\n// e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression`\n// will create much fewer constraints than calling `mul` and `add` directly\npub(crate) fn mul(\n params: P,\n lhs: [Field; N],\n rhs: [Field; N],\n) -> [Field; N] {\n let result = unsafe { __mul::<_, MOD_BITS>(params, lhs, rhs) };\n evaluate_quadratic_expression(\n params,\n [[lhs]],\n [[false]],\n [[rhs]],\n [[false]],\n [result],\n [true],\n );\n result\n}\n\n// Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation\npub(crate) fn div(\n params: P,\n lhs: [Field; N],\n rhs: [Field; N],\n) -> [Field; N] {\n assert(\n params.has_multiplicative_inverse,\n \"BigNum has no multiplicative inverse. Use udiv for unsigned integer division\",\n );\n let result = unsafe { __div::<_, MOD_BITS>(params, lhs, rhs) };\n evaluate_quadratic_expression(\n params,\n [[result]],\n [[false]],\n [[rhs]],\n [[false]],\n [lhs],\n [true],\n );\n result\n}\n\n/**\n* @brief udiv_mod performs integer division between numerator, divisor \n*\n* i.e. 1. floor(numerator / divisor) = quotient\n* 2. numerator % divisor = remainder\n* 3. divisor * quotient + remainder = numerator\n**/\npub(crate) fn udiv_mod(\n params: P,\n numerator: [Field; N],\n divisor: [Field; N],\n) -> ([Field; N], [Field; N]) {\n let (quotient, remainder) = unsafe { __udiv_mod(numerator, divisor) };\n\n // self / divisor = quotient rounded\n // quotient * divisor + remainder - self = 0\n evaluate_quadratic_expression(\n params,\n [[quotient]],\n [[false]],\n [[divisor]],\n [[false]],\n [numerator, remainder],\n [true, false],\n );\n // we need (remainder < divisor)\n // implies (divisor - remainder > 0)\n validate_gt::<_, MOD_BITS>(divisor, remainder);\n (quotient, remainder)\n}\n\n/**\n* @brief udiv_mod performs integer division between numerator, divisor \n*\n* i.e. return param is floor(numerator / divisor)\n**/\npub(crate) fn udiv(\n params: P,\n numerator: [Field; N],\n divisor: [Field; N],\n) -> [Field; N] {\n udiv_mod::<_, MOD_BITS>(params, numerator, divisor).0\n}\n\n/**\n* @brief udiv_mod performs integer modular reduction\n*\n* i.e. 1. numerator % divisor = return value\n**/\npub(crate) fn umod(\n params: P,\n numerator: [Field; N],\n divisor: [Field; N],\n) -> [Field; N] {\n udiv_mod::<_, MOD_BITS>(params, numerator, divisor).1\n}\n\n","path":"/Users/khashayarbarooti/aztec/noir-bignum-oracles/src/fns/constrained_ops.nr"},"87":{"source":"use crate::utils::u60_representation::U60Repr;\n\nuse crate::bignum::BigNum;\nuse crate::bignum::BigNumTrait;\n\nuse crate::params::BigNumParams;\nuse crate::params::BigNumParamsGetter;\n\nuse crate::fields::bls12_381Fq::BLS12_381_Fq_Params;\nuse crate::fields::bn254Fq::BN254_Fq_Params;\nuse crate::fields::U256::U256Params;\n\nstruct Test2048Params {}\n\n// See https://github.com/noir-lang/noir/issues/6172\n\ntype Fq = BigNum<3, 254, BN254_Fq_Params>;\ntype BN256 = BigNum<3, 257, U256Params>;\ntype BN381 = BigNum<4, 381, BLS12_381_Fq_Params>;\ntype BN2048 = BigNum<18, 2048, Test2048Params>;\n\n\n\n#[export]\nfn test_add_BN() {\n let mut a: Fq = BigNum::modulus();\n let mut b: Fq = BigNum::modulus();\n let mut expected: Fq = BigNum::modulus();\n\n a.limbs[0] -= 1;\n b.limbs[0] -= 1;\n expected.limbs[0] -= 2;\n\n let result = a + b;\n assert(result == expected);\n}\n","path":"/Users/khashayarbarooti/aztec/noir-bignum-oracles/src/benchmarks/bignum_bench.nr"},"120":{"source":"use crate::utils::map::map;\n\nuse crate::params::BigNumParamsGetter;\n\nuse crate::fns::{\n constrained_ops::{\n add, assert_is_not_equal, conditional_select, derive_from_seed, div, eq, mul, neg, sub,\n udiv, udiv_mod, umod, validate_in_field, validate_in_range,\n }, expressions::{__compute_quadratic_expression, evaluate_quadratic_expression},\n serialization::{from_be_bytes, to_le_bytes},\n unconstrained_ops::{\n __add, __batch_invert, __batch_invert_slice, __derive_from_seed, __div, __eq, __invmod,\n __is_zero, __mul, __neg, __pow, __sub, __tonelli_shanks_sqrt, __udiv_mod,\n },\n};\n\npub struct BigNum {\n pub limbs: [Field; N],\n}\n// We aim to avoid needing to add a generic parameter to this trait, for this reason we do not allow\n// accessing the limbs of the bignum except through slices.\npub trait BigNumTrait {\n // TODO: this crashes the compiler? v0.32\n // fn default() -> Self { std::default::Default::default () }\n pub fn new() -> Self;\n pub fn one() -> Self;\n pub fn derive_from_seed(seed: [u8; SeedBytes]) -> Self;\n pub unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self;\n pub fn from_slice(limbs: [Field]) -> Self;\n pub fn from_be_bytes(x: [u8; NBytes]) -> Self;\n pub fn to_le_bytes(self) -> [u8; NBytes];\n\n pub fn modulus() -> Self;\n pub fn modulus_bits(self) -> u32;\n pub fn num_limbs(self) -> u32;\n pub fn get_limbs_slice(self) -> [Field];\n pub fn get_limb(self, idx: u32) -> Field;\n pub fn set_limb(&mut self, idx: u32, value: Field);\n\n pub unconstrained fn __eq(self, other: Self) -> bool;\n pub unconstrained fn __is_zero(self) -> bool;\n\n pub unconstrained fn __neg(self) -> Self;\n pub unconstrained fn __add(self, other: Self) -> Self;\n pub unconstrained fn __sub(self, other: Self) -> Self;\n pub unconstrained fn __mul(self, other: Self) -> Self;\n pub unconstrained fn __div(self, other: Self) -> Self;\n pub unconstrained fn __udiv_mod(self, divisor: Self) -> (Self, Self);\n pub unconstrained fn __invmod(self) -> Self;\n pub unconstrained fn __pow(self, exponent: Self) -> Self;\n\n pub unconstrained fn __batch_invert(to_invert: [Self; M]) -> [Self; M];\n pub unconstrained fn __batch_invert_slice(to_invert: [Self]) -> [Self];\n\n pub unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option;\n\n pub unconstrained fn __compute_quadratic_expression(\n lhs: [[Self; LHS_N]; NUM_PRODUCTS],\n lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS],\n rhs: [[Self; RHS_N]; NUM_PRODUCTS],\n rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS],\n add: [Self; ADD_N],\n add_flags: [bool; ADD_N],\n ) -> (Self, Self);\n\n pub fn evaluate_quadratic_expression(\n lhs: [[Self; LHS_N]; NUM_PRODUCTS],\n lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS],\n rhs: [[Self; RHS_N]; NUM_PRODUCTS],\n rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS],\n add: [Self; ADD_N],\n add_flags: [bool; ADD_N],\n );\n\n pub fn eq(self, other: Self) -> bool {\n self == other\n }\n pub fn assert_is_not_equal(self, other: Self);\n pub fn validate_in_range(self);\n pub fn validate_in_field(self);\n\n pub fn neg(self) -> Self;\n pub fn add(self, other: Self) -> Self {\n self + other\n }\n pub fn sub(self, other: Self) -> Self {\n self - other\n }\n pub fn mul(self, other: Self) -> Self {\n self * other\n }\n pub fn div(self, other: Self) -> Self {\n self / other\n }\n pub fn udiv_mod(self, divisor: Self) -> (Self, Self);\n pub fn udiv(self, divisor: Self) -> Self;\n pub fn umod(self, divisor: Self) -> Self;\n\n pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self;\n}\n\nimpl BigNumTrait for BigNum\nwhere\n Params: BigNumParamsGetter,\n{\n\n fn new() -> Self {\n Self { limbs: [0; N] }\n }\n\n fn one() -> Self {\n let mut result = BigNum::new();\n result.limbs[0] = 1;\n result\n }\n\n fn derive_from_seed(seed: [u8; SeedBytes]) -> Self {\n let params = Params::get_params();\n Self { limbs: derive_from_seed::<_, MOD_BITS, _>(params, seed) }\n }\n\n unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self {\n let params = Params::get_params();\n Self { limbs: __derive_from_seed::<_, MOD_BITS, _>(params, seed) }\n }\n\n fn from_slice(limbs: [Field]) -> Self {\n Self { limbs: limbs.as_array() }\n }\n\n fn from_be_bytes(x: [u8; NBytes]) -> Self {\n Self { limbs: from_be_bytes::<_, MOD_BITS, _>(x) }\n }\n\n fn to_le_bytes(self) -> [u8; NBytes] {\n to_le_bytes::<_, MOD_BITS, _>(self.limbs)\n }\n\n fn modulus() -> Self {\n Self { limbs: Params::get_params().modulus }\n }\n\n fn modulus_bits(_: Self) -> u32 {\n MOD_BITS\n }\n\n fn num_limbs(_: Self) -> u32 {\n N\n }\n\n fn get_limbs_slice(self) -> [Field] {\n self.limbs\n }\n\n fn get_limb(self, idx: u32) -> Field {\n self.limbs[idx]\n }\n\n fn set_limb(&mut self, idx: u32, value: Field) {\n self.limbs[idx] = value;\n }\n\n unconstrained fn __eq(self, other: Self) -> bool {\n __eq(self.limbs, other.limbs)\n }\n\n unconstrained fn __is_zero(self) -> bool {\n __is_zero(self.limbs)\n }\n\n unconstrained fn __neg(self) -> Self {\n let params = Params::get_params();\n Self::from_slice(__neg(params, self.limbs))\n }\n\n unconstrained fn __add(self, other: Self) -> Self {\n let params = Params::get_params();\n Self::from_slice(__add(params, self.limbs, other.limbs))\n }\n\n unconstrained fn __sub(self, other: Self) -> Self {\n let params = Params::get_params();\n Self::from_slice(__sub(params, self.limbs, other.limbs))\n }\n\n unconstrained fn __mul(self, other: Self) -> Self {\n let params = Params::get_params();\n Self::from_slice(__mul::<_, MOD_BITS>(params, self.limbs, other.limbs))\n }\n\n unconstrained fn __div(self, divisor: Self) -> Self {\n let params = Params::get_params();\n Self::from_slice(__div::<_, MOD_BITS>(params, self.limbs, divisor.limbs))\n }\n\n unconstrained fn __udiv_mod(self, divisor: Self) -> (Self, Self) {\n let (q, r) = __udiv_mod(self.limbs, divisor.limbs);\n (Self { limbs: q }, Self { limbs: r })\n }\n\n unconstrained fn __invmod(self) -> Self {\n let params = Params::get_params();\n assert(params.has_multiplicative_inverse);\n Self { limbs: __invmod::<_, MOD_BITS>(params, self.limbs) }\n }\n\n unconstrained fn __pow(self, exponent: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: __pow::<_, MOD_BITS>(params, self.limbs, exponent.limbs) }\n }\n\n unconstrained fn __batch_invert(x: [Self; M]) -> [Self; M] {\n let params = Params::get_params();\n assert(params.has_multiplicative_inverse);\n __batch_invert::<_, MOD_BITS, _>(params, x.map(|bn: Self| bn.limbs)).map(|limbs| {\n Self { limbs }\n })\n }\n\n unconstrained fn __batch_invert_slice(x: [Self]) -> [Self] {\n let params = Params::get_params();\n assert(params.has_multiplicative_inverse);\n __batch_invert_slice::<_, MOD_BITS>(params, x.map(|bn: Self| bn.limbs)).map(|limbs| {\n Self { limbs }\n })\n }\n\n unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option {\n let params = Params::get_params();\n let maybe_limbs = unsafe { __tonelli_shanks_sqrt(params, self.limbs) };\n maybe_limbs.map(|limbs| Self { limbs })\n }\n\n unconstrained fn __compute_quadratic_expression(\n lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS],\n lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS],\n rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS],\n rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS],\n linear_terms: [Self; ADD_N],\n linear_flags: [bool; ADD_N],\n ) -> (Self, Self) {\n let params = Params::get_params();\n let (q_limbs, r_limbs) = __compute_quadratic_expression::<_, MOD_BITS, _, _, _, _>(\n params,\n map(lhs_terms, |bns| map(bns, |bn: Self| bn.limbs)),\n lhs_flags,\n map(rhs_terms, |bns| map(bns, |bn: Self| bn.limbs)),\n rhs_flags,\n map(linear_terms, |bn: Self| bn.limbs),\n linear_flags,\n );\n (Self { limbs: q_limbs }, Self { limbs: r_limbs })\n }\n\n fn evaluate_quadratic_expression(\n lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS],\n lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS],\n rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS],\n rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS],\n linear_terms: [Self; ADD_N],\n linear_flags: [bool; ADD_N],\n ) {\n let params = Params::get_params();\n evaluate_quadratic_expression::<_, MOD_BITS, _, _, _, _>(\n params,\n map(lhs_terms, |bns| map(bns, |bn: Self| bn.limbs)),\n lhs_flags,\n map(rhs_terms, |bns| map(bns, |bn: Self| bn.limbs)),\n rhs_flags,\n map(linear_terms, |bn: Self| bn.limbs),\n linear_flags,\n )\n }\n\n fn validate_in_field(self: Self) {\n let params = Params::get_params();\n validate_in_field::<_, MOD_BITS>(params, self.limbs);\n }\n\n fn validate_in_range(self) {\n validate_in_range::<_, MOD_BITS>(self.limbs);\n }\n\n fn assert_is_not_equal(self, other: Self) {\n let params = Params::get_params();\n assert_is_not_equal(params, self.limbs, other.limbs);\n }\n\n fn neg(self) -> Self {\n let params = Params::get_params();\n Self { limbs: neg::<_, MOD_BITS>(params, self.limbs) }\n }\n\n fn udiv_mod(self, divisor: Self) -> (Self, Self) {\n let params = Params::get_params();\n let (q, r) = udiv_mod::<_, MOD_BITS>(params, self.limbs, divisor.limbs);\n (Self { limbs: q }, Self { limbs: r })\n }\n\n fn udiv(self, divisor: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: udiv::<_, MOD_BITS>(params, self.limbs, divisor.limbs) }\n }\n\n fn umod(self, divisor: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: umod::<_, MOD_BITS>(params, self.limbs, divisor.limbs) }\n }\n\n fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self {\n Self { limbs: conditional_select(lhs.limbs, rhs.limbs, predicate) }\n }\n}\n\n// impl BigNumTrait for BigNum where Params: BigNumParamsGetter {}\n\nimpl std::ops::Add for BigNum\nwhere\n Params: BigNumParamsGetter,\n{\n // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them\n // via evaluate_quadratic_expression\n fn add(self, other: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: add::<_, MOD_BITS>(params, self.limbs, other.limbs) }\n }\n}\n\nimpl std::ops::Sub for BigNum\nwhere\n Params: BigNumParamsGetter,\n{\n // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them\n // via evaluate_quadratic_expression\n fn sub(self, other: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: sub::<_, MOD_BITS>(params, self.limbs, other.limbs) }\n }\n}\n\nimpl std::ops::Mul for BigNum\nwhere\n Params: BigNumParamsGetter,\n{\n // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them\n // via evaluate_quadratic_expression\n // e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression`\n // will create much fewer constraints than calling `mul` and `add` directly\n fn mul(self, other: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: mul::<_, MOD_BITS>(params, self.limbs, other.limbs) }\n }\n}\n\nimpl std::ops::Div for BigNum\nwhere\n Params: BigNumParamsGetter,\n{\n // Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation\n fn div(self, other: Self) -> Self {\n let params = Params::get_params();\n Self { limbs: div::<_, MOD_BITS>(params, self.limbs, other.limbs) }\n }\n}\n\nimpl std::cmp::Eq for BigNum\nwhere\n Params: BigNumParamsGetter,\n{\n fn eq(self, other: Self) -> bool {\n let params = Params::get_params();\n eq::<_, MOD_BITS>(params, self.limbs, other.limbs)\n }\n}\n\n","path":"/Users/khashayarbarooti/aztec/noir-bignum-oracles/src/bignum.nr"}},"names":["test_add_BN"],"brillig_names":["__add_with_flags","__sub_with_flags"]} \ No newline at end of file diff --git a/src/bignum.nr b/src/bignum.nr index 1f54d498..7b76f263 100644 --- a/src/bignum.nr +++ b/src/bignum.nr @@ -4,8 +4,8 @@ use crate::params::BigNumParamsGetter; use crate::fns::{ constrained_ops::{ - add, assert_is_not_equal, conditional_select, derive_from_seed, div, eq, mul, neg, sub, - udiv, udiv_mod, umod, validate_in_field, validate_in_range, + add, assert_is_not_equal, conditional_select, derive_from_seed, div, eq, from_field, mul, + 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}, @@ -88,6 +88,16 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; } +impl std::convert::From for BigNum +where + Params: BigNumParamsGetter, +{ + fn from(input: Field) -> Self { + let params = Params::get_params(); + Self { limbs: from_field::(params, input) } + } +} + impl Neg for BigNum where Params: BigNumParamsGetter, @@ -226,7 +236,7 @@ where unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option { let params = Params::get_params(); - let maybe_limbs = unsafe { __tonelli_shanks_sqrt(params, self.limbs) }; + let maybe_limbs = __tonelli_shanks_sqrt(params, self.limbs); maybe_limbs.map(|limbs| Self { limbs }) } diff --git a/src/fns/constrained_ops.nr b/src/fns/constrained_ops.nr index 30ded4ea..5d49c3b9 100644 --- a/src/fns/constrained_ops.nr +++ b/src/fns/constrained_ops.nr @@ -1,13 +1,12 @@ -use crate::params::BigNumParams as P; - use crate::fns::{ expressions::evaluate_quadratic_expression, unconstrained_helpers::{ - __add_with_flags, __neg_with_flags, __sub_with_flags, __validate_gt_remainder, + __add_with_flags, __from_field, __neg_with_flags, __sub_with_flags, __validate_gt_remainder, __validate_in_field_compute_borrow_flags, }, unconstrained_ops::{__div, __mul, __udiv_mod}, }; +use crate::params::BigNumParams as P; /** * In this file: @@ -36,6 +35,41 @@ use crate::fns::{ * We use a hash function that can be modelled as a random oracle * This function *should* produce an output that is a uniformly randomly distributed value modulo BigNum::modulus() **/ +pub(crate) fn from_field( + params: P, + field: Field, +) -> [Field; N] { + // safty: we check that the resulting limbs represent the intended field element + // we check the bit length, the limbs being max 120 bits, and the value in total is less than the field modulus + let result = unsafe { __from_field::(field) }; + // validate the limbs are in range and the value in total is less than 2^254 + + let TWO_POW_120 = 0x1000000000000000000000000000000; + // validate that the last limb is less than the modulus + if N > 2 { + // validate that the result is less than the modulus + let mut grumpkin_modulus = [0; N]; + grumpkin_modulus[0] = 0x33e84879b9709143e1f593f0000001; + grumpkin_modulus[1] = 0x4e72e131a029b85045b68181585d28; + grumpkin_modulus[2] = 0x3064; + validate_gt::(grumpkin_modulus, result); + // validate that the limbs are in range + validate_in_range::(result); + } + // validate the limbs sum up to the field value + let field_val = if N < 2 { + result[0] + } else if N == 2 { + validate_in_range::(result); + result[0] + result[1] * TWO_POW_120 + } else { + validate_in_range::(result); + result[0] + result[1] * TWO_POW_120 + result[2] * TWO_POW_120 * TWO_POW_120 + }; + assert(field_val == field); + result +} + pub(crate) fn derive_from_seed( params: P, seed: [u8; SeedBytes], diff --git a/src/fns/unconstrained_helpers.nr b/src/fns/unconstrained_helpers.nr index 2e663a04..c900958a 100644 --- a/src/fns/unconstrained_helpers.nr +++ b/src/fns/unconstrained_helpers.nr @@ -18,6 +18,13 @@ global TWO_POW_60: u64 = 0x1000000000000000; * __tonelli_shanks_sqrt */ +pub(crate) unconstrained fn __from_field(field: Field) -> [Field; N] { + // cast the field to a u60 representation + let res_u60: U60Repr = U60Repr::from_field(field); + let result: [Field; N] = U60Repr::into(res_u60); + result +} + pub(crate) unconstrained fn __validate_in_field_compute_borrow_flags( params: P, val: [Field; N], @@ -35,8 +42,8 @@ pub(crate) unconstrained fn __validate_gt_remainder( lhs: [Field; N], rhs: [Field; N], ) -> ([Field; N], [bool; N], [bool; N]) { - let a_u60: U60Repr = U60Repr::from(lhs); - let mut b_u60: U60Repr = U60Repr::from(rhs); + let a_u60: U60Repr = From::from(lhs); + let mut b_u60: U60Repr = From::from(rhs); let underflow = b_u60.gte(a_u60); b_u60 += U60Repr::one(); @@ -76,7 +83,7 @@ pub(crate) unconstrained fn __neg_with_flags( params: P, val: [Field; N], ) -> ([Field; N], [bool; N]) { - let x_u60: U60Repr = U60Repr::from(val); + let x_u60: U60Repr = From::from(val); let mut result_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; let mut borrow_in: u64 = 0; @@ -101,8 +108,8 @@ pub(crate) unconstrained fn __add_with_flags( lhs: [Field; N], rhs: [Field; N], ) -> ([Field; N], [bool; N], [bool; N], bool) { - let a_u60: U60Repr = U60Repr::from(lhs); - let b_u60: U60Repr = U60Repr::from(rhs); + let a_u60: U60Repr = From::from(lhs); + let b_u60: U60Repr = From::from(rhs); let add_u60 = a_u60 + b_u60; let overflow = add_u60.gte(params.modulus_u60); diff --git a/src/runtime_bignum.nr b/src/runtime_bignum.nr index 3cdc9c0e..64d48461 100644 --- a/src/runtime_bignum.nr +++ b/src/runtime_bignum.nr @@ -31,7 +31,7 @@ pub(crate) trait RuntimeBigNumTrait: Neg + Add + params: BigNumParams, seed: [u8; SeedBytes], ) -> Self; - pub fn __derive_from_seed( + pub unconstrained fn __derive_from_seed( params: BigNumParams, seed: [u8; SeedBytes], ) -> Self; @@ -138,16 +138,16 @@ impl RuntimeBigNumTrait for RuntimeB params: BigNumParams, seed: [u8; SeedBytes], ) -> Self { - let limbs = unsafe { derive_from_seed::<_, MOD_BITS, _>(params, seed) }; + let limbs = derive_from_seed::<_, MOD_BITS, _>(params, seed); Self { limbs, params } } // UNCONSTRAINED! (Hence `__` prefix). - fn __derive_from_seed( + unconstrained fn __derive_from_seed( params: BigNumParams, seed: [u8; SeedBytes], ) -> Self { - let limbs = unsafe { __derive_from_seed::<_, MOD_BITS, _>(params, seed) }; + let limbs = __derive_from_seed::<_, MOD_BITS, _>(params, seed); Self { limbs, params } } @@ -281,7 +281,7 @@ impl RuntimeBigNumTrait for RuntimeB unconstrained fn __batch_invert_slice(x: [Self]) -> [Self] { let params = x[0].params; assert(params.has_multiplicative_inverse); - let all_limbs = unsafe { + let all_limbs = { let inv_slice = __batch_invert_slice::<_, MOD_BITS>(params, x.map(|bn| Self::get_limbs(bn))); inv_slice.as_array() diff --git a/src/tests/bignum_test.nr b/src/tests/bignum_test.nr index 72da0d2a..2a4ba115 100644 --- a/src/tests/bignum_test.nr +++ b/src/tests/bignum_test.nr @@ -790,3 +790,29 @@ fn test_expressions() { assert(wx_constrained.limbs == wx.limbs); } +#[test] +fn test_from_field_1_digit() { + let field: Field = 1; + let result = Fq::from(field); + assert(result == Fq::one()); +} + +#[test] +fn test_from_field_2_digits() { + let field: Field = 762576765071760201410184025311678064293966151975347778787092903729041075; + let result = Fq::from(field); + let expected: Fq = + BigNum { limbs: [0xe88ed97f8f707abd3fa65763c80eb3, 0x6e7d8b5586595aa1fb2ee04d5cb4f5, 0x0] }; + assert(result == expected); +} + +#[test] +fn test_from_field_3_digits() { + let field: Field = -1; + let result = Fq::from(field); + let expected: Fq = BigNum { + limbs: [0x33e84879b9709143e1f593f0000000, 0x4e72e131a029b85045b68181585d28, 0x3064], + }; + assert(result == expected); +} + diff --git a/src/utils/split_bits.nr b/src/utils/split_bits.nr index 29c2410f..9804f384 100644 --- a/src/utils/split_bits.nr +++ b/src/utils/split_bits.nr @@ -2,6 +2,30 @@ global TWO_POW_56: u64 = 0x100000000000000; global TWO_POW_60: u64 = 0x1000000000000000; global TWO_POW_64: Field = 0x10000000000000000; +//fields to u60rep conversion +// field elements are 254 bits +// so there will be 5 limbs +pub(crate) unconstrained fn field_to_u60rep(mut x: Field) -> (u64, u64, u64, u64, u64) { + // get the first 60 bits by casting to u64 and then taking the lower 60 bits + // we use the fact that this casting drops everything above 64 bits + let x_first_u64 = (x as u64); + let first: u64 = x_first_u64 % TWO_POW_60; + // this becomes the same as a integer division because we're removing the remainder + x = (x - (first as Field)) / (TWO_POW_60 as Field); + let x_second_u64 = (x as u64); + let second = x_second_u64 % TWO_POW_60; + x = (x - (second as Field)) / (TWO_POW_60 as Field); + let x_third_u64 = (x as u64); + let third = x_third_u64 % TWO_POW_60; + x = (x - (third as Field)) / (TWO_POW_60 as Field); + let x_fourth_u64 = (x as u64); + let fourth = x_fourth_u64 % TWO_POW_60; + x = (x - (fourth as Field)) / (TWO_POW_60 as Field); + let x_fifth_u64 = (x as u64); + let fifth = x_fifth_u64 % TWO_POW_60; + (first, second, third, fourth, fifth) +} + // Decomposes a single field into two 120 bit fields pub unconstrained fn split_120_bits(mut x: Field) -> (Field, Field) { // Here we're taking advantage of truncating 64 bit limbs from the input field diff --git a/src/utils/u60_representation.nr b/src/utils/u60_representation.nr index ae0dc172..8d7cb2a3 100644 --- a/src/utils/u60_representation.nr +++ b/src/utils/u60_representation.nr @@ -1,5 +1,6 @@ use crate::utils::msb::get_msb64; use crate::utils::split_bits; +use crate::utils::split_bits::field_to_u60rep; /** * @brief U60Repr represents a BigNum element as a sequence of 60-bit unsigned integers. @@ -57,6 +58,29 @@ impl std::convert::From<[Field; N]> for U60Rep } } +// impl std::convert::From for U60Repr { +// fn from(input: Field) -> Self { +// let (low, mid, high) = unsafe { field_to_u60rep(input) } ; +// let mut result: Self = U60Repr { limbs: [0; N * NumSegments] }; +// let N_u60: u32 = N * NumSegments; +// assert(N_u60 >=1, "N must be at least 1"); +// if N_u60 == 1 { +// assert((mid ==0) & (high == 0), "input field is too large to fit in a single limb"); +// result.limbs[0] = low; +// } +// else if N_u60 == 2{ +// assert(high == 0, "input field is too large to fit in two limbs"); +// result.limbs[0] = low; +// result.limbs[1] = mid; +// }else{ +// result.limbs[0] = low; +// result.limbs[1] = mid; +// result.limbs[2] = high; +// } +// result +// } +// } + impl std::convert::Into<[Field; N]> for U60Repr { fn into(x: U60Repr) -> [Field; N] { let mut result: [Field; N] = [0; N]; @@ -94,6 +118,45 @@ impl U60Repr { result } + pub(crate) unconstrained fn from_field(input: Field) -> Self { + let (first, second, third, fourth, fifth) = field_to_u60rep(input); + let mut result: Self = U60Repr { limbs: [0; N * NumSegments] }; + let N_u60: u32 = N * NumSegments; + assert(N_u60 >= 1, "N must be at least 1"); + if N_u60 == 1 { + assert( + (second == 0) & (third == 0) & (fourth == 0) & (fifth == 0), + "input field is too large to fit in a single limb", + ); + result.limbs[0] = first; + } else if N_u60 == 2 { + assert( + (third == 0) & (fourth == 0) & (fifth == 0), + "input field is too large to fit in two limbs", + ); + result.limbs[0] = first; + result.limbs[1] = second; + } else if N_u60 == 3 { + assert((fourth == 0) & (fifth == 0), "input field is too large to fit in three limbs"); + result.limbs[0] = first; + result.limbs[1] = second; + result.limbs[2] = third; + } else if N_u60 == 4 { + assert((fifth == 0), "input field is too large to fit in four limbs"); + result.limbs[0] = first; + result.limbs[1] = second; + result.limbs[2] = third; + result.limbs[3] = fourth; + } else { + result.limbs[0] = first; + result.limbs[1] = second; + result.limbs[2] = third; + result.limbs[3] = fourth; + result.limbs[4] = fifth; + } + result + } + pub(crate) unconstrained fn into_field_array( x: U60Repr, ) -> [Field; N * NumSegments / 2] {