diff --git a/Nargo.toml b/Nargo.toml index 1c3c348f..d1e894aa 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -2,6 +2,6 @@ name = "bignum" type = "lib" authors = [""] -compiler_version = ">=1.0.0" +compiler_version = ">=0.38.0" [dependencies] 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..74c89118 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}, @@ -26,6 +26,7 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { // fn default() -> Self { std::default::Default::default () } pub fn new() -> Self; pub fn one() -> Self; + pub fn from_field(field: Field) -> Self; pub fn derive_from_seed(seed: [u8; SeedBytes]) -> Self; pub unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self; pub fn from_slice(limbs: [Field]) -> Self; @@ -88,6 +89,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, @@ -113,6 +124,11 @@ where result } + fn from_field(field: Field) -> Self { + let params = Params::get_params(); + Self { limbs: from_field::(params, field) } + } + fn derive_from_seed(seed: [u8; SeedBytes]) -> Self { let params = Params::get_params(); Self { limbs: derive_from_seed::<_, MOD_BITS, _>(params, seed) } @@ -226,7 +242,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..bc4a0fa4 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,39 @@ 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] { + // @safety : 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 shift = 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] * shift + } else { + validate_in_range::(result); + result[0] + result[1] * shift + result[2] * shift * shift + }; + 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/lib.nr b/src/lib.nr index fa8840ff..a6b6ada6 100644 --- a/src/lib.nr +++ b/src/lib.nr @@ -18,6 +18,6 @@ pub(crate) mod utils; pub use bignum::BigNum; pub use bignum::BigNumTrait; // So that external code can operate on a generic BigNum, `where BigNum: BigNumTrait`. pub use runtime_bignum::RuntimeBigNum; - +pub use runtime_bignum::RuntimeBigNumTrait; // Tests mod tests; diff --git a/src/runtime_bignum.nr b/src/runtime_bignum.nr index 3cdc9c0e..609a71bc 100644 --- a/src/runtime_bignum.nr +++ b/src/runtime_bignum.nr @@ -138,7 +138,7 @@ 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 } } @@ -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..2f0082d8 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(field); + assert(result == Fq::one()); +} + +#[test] +fn test_from_field_2_digits() { + let field: Field = 762576765071760201410184025311678064293966151975347778787092903729041075; + let result = Fq::from_field(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(field); + let expected: Fq = BigNum { + limbs: [0x33e84879b9709143e1f593f0000000, 0x4e72e131a029b85045b68181585d28, 0x3064], + }; + assert(result == expected); +} + diff --git a/src/tests/runtime_bignum_test.nr b/src/tests/runtime_bignum_test.nr index 3b7fe4f0..dce51ccc 100644 --- a/src/tests/runtime_bignum_test.nr +++ b/src/tests/runtime_bignum_test.nr @@ -210,7 +210,7 @@ comptime fn make_test(_m: Module, N: u32, MOD_BITS: u32, typ: Quoted) -> Quoted #[test] fn test_add() { let params = $typ ::get_params(); - + // safety: these are just random values for tests let a: $RuntimeBigNum<$N, $MOD_BITS> = unsafe{ $RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]) }; let b: $RuntimeBigNum<$N, $MOD_BITS> = unsafe{ $RuntimeBigNum::__derive_from_seed(params, [4, 5, 6, 7]) }; let one: $RuntimeBigNum<$N, $MOD_BITS> = $RuntimeBigNum::one(params); @@ -539,9 +539,9 @@ pub mod BLS12_377_Fr_ParamsTests {} fn test_div(params: BigNumParams) { let a: RuntimeBigNum = - unsafe { RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]) }; + RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]) ; let b: RuntimeBigNum = - unsafe { RuntimeBigNum::__derive_from_seed(params, [4, 5, 6, 7]) }; + RuntimeBigNum::__derive_from_seed(params, [4, 5, 6, 7]) ; let c = a / b; assert((b * c) == a); @@ -741,3 +741,4 @@ fn test_barrett_reduction_fix() { }; assert(remainder[8].lt(params.modulus[8])); } + diff --git a/src/utils/split_bits.nr b/src/utils/split_bits.nr index 29c2410f..16e63273 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 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..59f6c63b 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) fn from_field(input: Field) -> Self { + let (first, second, third, fourth, fifth) = 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( + (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] { diff --git a/src/utils/u60_representation_test.nr b/src/utils/u60_representation_test.nr index da1a38ec..642e9b89 100644 --- a/src/utils/u60_representation_test.nr +++ b/src/utils/u60_representation_test.nr @@ -4,8 +4,8 @@ use crate::utils::u60_representation::U60Repr; unconstrained fn test_conversion() { let p = 0xffffffffffffffffffffffffffffff; // 2^120 - 1 let expected: [Field; 3 * 2] = [p, p - 1, p - 2, p - 3, p - 4, p - 5]; - let u60repr: U60Repr<3, 4> = unsafe { U60Repr::new(expected) }; - let result = unsafe { u60repr.into_field_array() }; + let u60repr: U60Repr<3, 4> = U60Repr::new(expected) ; + let result = u60repr.into_field_array() ; assert(result == expected); } @@ -65,22 +65,22 @@ fn test_get_bit() { unconstrained fn test_gte() { let p = 0xffffffffffffffffffffffffffffff; // 2^120 - 1 let input: [Field; 6] = [p, p - 1, p - 2, p - 3, p - 4, p - 5]; - let lhs: U60Repr<3, 6> = unsafe { U60Repr::new(input) }; + let lhs: U60Repr<3, 6> = U60Repr::new(input) ; { let rhs = lhs; - assert(unsafe { lhs.gte(rhs) }); + assert( lhs.gte(rhs) ); } { // make rhs smaller by 1 let mut rhs: U60Repr<3, 6> = lhs; rhs.limbs[0] -= 1; - assert(unsafe { lhs.gte(rhs) }); + assert( lhs.gte(rhs) ); } { // make rhs greater by 1 let mut rhs = lhs; rhs.limbs[0] += 1; - assert(!unsafe { lhs.gte(rhs) }); + assert(! lhs.gte(rhs) ); } }