diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90122135..1691bfea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - toolchain: [nightly, 0.35.0] + toolchain: [nightly, 0.36.0] steps: - name: Checkout sources uses: actions/checkout@v4 @@ -38,7 +38,31 @@ jobs: - name: Install Nargo uses: noir-lang/noirup@v0.1.3 with: - toolchain: 0.35.0 + toolchain: 0.36.0 - name: Run formatter run: nargo fmt --check + + +# This is a job which depends on all test jobs and reports the overall status. + # This allows us to add/remove test jobs without having to update the required workflows. + tests-end: + name: Noir End + runs-on: ubuntu-latest + # We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping. + if: ${{ always() }} + needs: + - test + - format + + steps: + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + env: + # We treat any cancelled, skipped or failing jobs as a failure for the workflow as a whole. + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} diff --git a/Nargo.toml b/Nargo.toml index 4eb93691..337a2e09 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -2,6 +2,6 @@ name = "bignum" type = "lib" authors = [""] -compiler_version = ">=0.35.0" +compiler_version = ">=0.36.0" [dependencies] diff --git a/README.md b/README.md index efc32af1..781e4631 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ TODO ## Dependencies -- Noir ≥v0.32.0 -- Barretenberg ≥v0.46.1 +- Noir ≥v0.36.0 +- Barretenberg ≥v0.56.1 Refer to [Noir's docs](https://noir-lang.org/docs/getting_started/installation/) and [Barretenberg's docs](https://github.com/AztecProtocol/aztec-packages/blob/master/barretenberg/cpp/src/barretenberg/bb/readme.md#installation) for installation steps. @@ -50,12 +50,13 @@ If your field moduli is _also_ known at compile-time, use the `BigNumTrait` defi Big numbers are instantiated with the BigNum struct: ```rust -struct BigNum { +struct BigNum { limbs: [Field; N] } ``` - `N` is the number of `Field` limbs together holding the value of the big number +- `MOD_BITS` is the bit-length of the modulus of the big number. - `Params` is the parameters associated with the big number; refer to sections below for presets and customizations ### Usage @@ -68,7 +69,7 @@ A simple 1 + 2 = 3 check in 256-bit unsigned integers: use dep::bignum::fields::U256::U256Params; use dep::bignum::BigNum; -type U256 = BigNum<3, U256Params>; +type U256 = BigNum<3, 257, U256Params>; fn main() { let one: U256 = BigNum::from_array([1, 0, 0]); @@ -96,7 +97,7 @@ e.g. use dep::bignum::fields::U256::U256Params; use dep::bignum::BigNum; -type U256 = BigNum<3, U256Params>; +type U256 = BigNum<3, 257, U256Params>; fn foo(x: U256, y: U256) -> U256 { x.udiv(y) @@ -105,70 +106,74 @@ fn foo(x: U256, y: U256) -> U256 { ##### Fields -`BigNum::fields` contains `BigNumInstance` constructors for common fields. +`BigNum::fields` contains `BigNumParams` for common fields. Feature requests and/or pull requests welcome for missing fields you need. TODO: Document existing field presets (e.g. bls, ed25519, secp256k1) -## `runtime_bignum` +## `RuntimeBigNum` -If your field moduli is _not_ known at compile-time (e.g. RSA verification), use the traits and structs defined in `runtime_bignum`: `runtime_bignum::BigNumTrait` and `runtime_bignum::BigNumInstanceTrait` +If your field moduli is _not_ known at compile-time (e.g. RSA verification), use the `RuntimeBigNum` struct defined in `runtime_bignum.nr`: `runtime_bignum::RuntimeBigNum`. -A `runtime_bignum::BigNumInstance` wraps the bignum modulus (as well as a derived parameter used internally to perform Barret reductions). A `BigNumInstance` object is required to evaluate most bignum operations. +```rust +use dep::bignum::fields::bn254Fq::BN254_Fq_Params; -### Types +// Notice how we don't provide the params here, because we're pretending they're +// not known at compile-time, for illustration purposes. +type My_RBN = RuntimeBigNum<3, 254>; -bignum operations are evaluated using two structs and a trait: `ParamsTrait`, `BigNum`, `BigNumInstance` +fn main() { + let params = BN254_Fq_Params::get_params(); // or some other params known at runtime. -`ParamsTrait` defines the compile-time properties of a BigNum instance: the number of modulus bits and the Barret reduction parameter `k` (TODO: these two values should be the same?!) + // Notice how we feed the params in, because we're pretending they're not + // known at compile-time. + let one: My_RBN = RuntimeBigNum::from_array(params, [1, 0, 0]); + let two: My_RBN = RuntimeBigNum::from_array(params, [2, 0, 0]); + let three: My_RBN = RuntimeBigNum::from_array(params, [3, 0, 0]); -`BigNumInstance` is a generator type that is used to create `BigNum` objects and evaluate operations on `BigNum` objects. It wraps BigNum parameters that may not be known at compile time (the `modulus` and a reduction parameter required for Barret reductions (`redc_param`)) + assert((one + two) == three); +} +``` -The `BigNum` struct represents individual big numbers. +### Types -BigNumInstance parameters (`modulus`, `redc_param`) can be provided at runtime via witnesses (e.g. RSA verification). The `redc_param` is only used in unconstrained functions and does not need to be derived from `modulus` in-circuit. +User-facing structs: -### Usage +`BigNum`: big numbers whose parameters are all known at compile-time. -#### Example +`RuntimeBigNum`: big numbers whose parameters are only known at runtime. (Note: the number of bits of the modulus of the bignum must be known at compile-time). -```rust -use crate::bignum::fields::bn254Fq{BNParams, BN254INSTANCE}; -use crate::bignum::runtime_bignum::BigNumInstance; -use crate::bignum::BigNum; +If creating custom bignum params: -type Fq = BigNum<3, BNParams>; -type FqInst = BigNumInstance<3, BNParams>; +`BigNumParams` is needed, to declare your params. These parameters (`modulus`, `redc_param`) can be provided at runtime via witnesses (e.g. RSA verification). The `redc_param` is only used in unconstrained functions and does not need to be derived from `modulus` in-circuit. -fn example(Fq a, Fq b) -> Fq { - let instance: FqInst = BN254INSTANCE; - instance.mul(a, b) -} -``` +`BigNumParamsGetter` is a convenient wrapper around params, which is needed if declaring a new type of `BigNum`. #### Methods ##### Arithmetics -Basic expressions can be evaluated using `BigNumInstance::add, BigNumInstance::sub, BigNumInstance::mul`. However, when evaluating relations (up to degree 2) that are more complex than single operations, the function `BigNumInstance::evaluate_quadratic_expression` is more efficient (due to needing only a single modular reduction). +Basic expressions can be evaluated using the `BigNum` and `RuntimeBigNum` operators `+`,`-`,`*`,`/`. However, when evaluating relations (up to degree 2) that are more complex than single operations, the static methods `BigNum::evaluate_quadratic_expression` or `RuntimeBigNum::evaluate_quadratic_expression` are much more efficient (due to needing only a single modular reduction). ##### Unconstrained arithmetics -Unconstrained functions `__mul, __add, __sub, __div, __pow` can be used to compute witnesses that can then be fed into `BigNumInstance::evaluate_quadratic_expression`. +Unconstrained functions `__mul, __add, __sub, __div, __pow` etc. can be used to compute witnesses that can then be fed into `BigNumInstance::evaluate_quadratic_expression`. -> **Note:** `__div`, `__pow` and `div` are expensive due to requiring modular exponentiations during witness computation. It is worth modifying witness generation algorithms to minimize the number of modular exponentiations required. (for example, using batch inverses) +> **Note:** `__div`, `__pow` and `div` are expensive due to requiring modular exponentiations during witness computation. It is worth modifying witness generation algorithms to minimize the number of modular exponentiations required. (for example, using batch inverses). e.g. if we wanted to compute `(a + b) * c + (d - e) * f = g` by evaluating the above example, `g` can be derived via: ```rust -let bn: BigNumInstance<3, BNParams> = BNInstance(); -let t0 = bn.__mul(bn.__add(a, b), c); -let t1 = bn.__mul(bn.__add(d, bn.__neg(e)), f); +let a: BigNumInstance<3, 254, BN254_Fq_Params> = BigNum::new(); +let t0 = c.__mul(a.__add(b)); +let t1 = f.__mul(d.__sub(e)); let g = bn.__add(t0, t1); ``` -See `bignum_test.nr` for more examples. +then the values can be arranged and fed-into `evaluate_quadratic_expression`. + +See `bignum_test.nr` and `runtime_bignum_test.nr` for more examples. ##### `evaluate_quadratic_expression` @@ -206,9 +211,9 @@ BigNum::evaluate_quadratic_expresson(lhs_terms, lhs_flags, rhs_terms, rhs_flags, ##### TODO: Document other available methods -#### Deriving BigNumInstance parameters: `modulus`, `redc_param` +#### Deriving BigNumParams parameters: `modulus`, `redc_param` -For common fields, BigNumInstance parameters can be pulled from the presets in `BigNum::fields`. +For common fields, BigNumParams parameters can be pulled from the presets in `bignum/fields/`. For other moduli (e.g. those used in RSA verification), both `modulus` and `redc_param` must be computed and formatted according to the following speficiations: @@ -218,17 +223,16 @@ For other moduli (e.g. those used in RSA verification), both `modulus` and `redc `double_modulus` is derived via the method `compute_double_modulus` in `runtime_bignum.nr`. If you want to provide this value as a compile-time constant (see `fields/bn254Fq.nr` for an example), follow the algorithm `compute_double_modulus` as this parameter is _not_ structly 2 \* modulus. Each limb except the most significant limb borrows 2^120 from the next most significant limb. This ensure that when performing limb subtractions `double_modulus.limbs[i] - x.limbs[i]`, we know that the result will not underflow. -BigNumInstance parameters can be derived from a known modulus using the rust crate `noir-bignum-paramgen` (https://crates.io/crates/noir-bignum-paramgen) +BigNumParams parameters can be derived from a known modulus using the rust crate `noir-bignum-paramgen` (https://crates.io/crates/noir-bignum-paramgen) ## Additional usage examples ```rust -use crate::bignum::fields::bn254Fq::BNParams; -use crate::bignum::fields::BN254Instance; -use crate::bignum::BigNum; -use crate::bignum::runtime_bignum::BigNumInstance; +use dep::bignum::fields::bn254Fq::BN254_Fq_Params; + +use dep::bignum::BigNum; -type Fq = BigNum<3, BNParams>; +type Fq = BigNum<3, 254, BN254_Fq_Params>; fn example_mul(Fq a, Fq b) -> Fq { a * b diff --git a/src/bignum.nr b/src/bignum.nr new file mode 100644 index 00000000..aaad1c8a --- /dev/null +++ b/src/bignum.nr @@ -0,0 +1,384 @@ +use crate::utils::map::map; + +use crate::params::BigNumParamsGetter; + +use crate::fns::{ + constrained_ops::{ + derive_from_seed, conditional_select, assert_is_not_equal, eq, validate_in_field, + validate_in_range, neg, add, sub, mul, div, udiv_mod, udiv, umod, + }, + unconstrained_ops::{ + __derive_from_seed, __eq, __is_zero, __neg, __add, __sub, __mul, __div, __udiv_mod, + __invmod, __pow, __batch_invert, __batch_invert_slice, __tonelli_shanks_sqrt, + }, expressions::{__compute_quadratic_expression, evaluate_quadratic_expression}, + serialization::{from_be_bytes, to_le_bytes}, +}; + +pub struct BigNum { + pub limbs: [Field; N], +} + +pub(crate) trait BigNumTrait { + // TODO: this crashes the compiler? v0.32 + // fn default() -> Self { std::default::Default::default () } + pub fn new() -> Self; + pub fn one() -> 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; + pub fn from_array(limbs: [Field; N]) -> Self; + pub fn from_be_bytes(x: [u8; NBytes]) -> Self; + pub fn to_le_bytes(self) -> [u8; NBytes]; + + pub fn modulus() -> Self; + pub fn modulus_bits() -> u32; + pub fn num_limbs() -> u32; + // pub fn get(self) -> [Field]; + pub fn get_limbs(self) -> [Field; N]; + pub fn get_limb(self, idx: u32) -> Field; + pub fn set_limb(&mut self, idx: u32, value: Field); + + pub unconstrained fn __eq(self, other: Self) -> bool; + pub unconstrained fn __is_zero(self) -> bool; + + pub unconstrained fn __neg(self) -> Self; + pub unconstrained fn __add(self, other: Self) -> Self; + pub unconstrained fn __sub(self, other: Self) -> Self; + pub unconstrained fn __mul(self, other: Self) -> Self; + pub unconstrained fn __div(self, other: Self) -> Self; + pub unconstrained fn __udiv_mod(self, divisor: Self) -> (Self, Self); + pub unconstrained fn __invmod(self) -> Self; + pub unconstrained fn __pow(self, exponent: Self) -> Self; + + pub unconstrained fn __batch_invert(to_invert: [Self; M]) -> [Self; M]; + pub unconstrained fn __batch_invert_slice(to_invert: [Self]) -> [Self]; + + pub unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option; + + pub unconstrained fn __compute_quadratic_expression( + lhs: [[Self; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs: [[Self; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + add: [Self; ADD_N], + add_flags: [bool; ADD_N], + ) -> (Self, Self); + + pub fn evaluate_quadratic_expression( + lhs: [[Self; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs: [[Self; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + add: [Self; ADD_N], + add_flags: [bool; ADD_N], + ); + + pub fn eq(self, other: Self) -> bool { + self == other + } + pub fn assert_is_not_equal(self, other: Self); + pub fn validate_in_range(self); + pub fn validate_in_field(self); + + pub fn neg(self) -> Self; + pub fn add(self, other: Self) -> Self { + self + other + } + pub fn sub(self, other: Self) -> Self { + self - other + } + pub fn mul(self, other: Self) -> Self { + self * other + } + pub fn div(self, other: Self) -> Self { + self / other + } + pub fn udiv_mod(self, divisor: Self) -> (Self, Self); + pub fn udiv(self, divisor: Self) -> Self; + pub fn umod(self, divisor: Self) -> Self; + + pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; +} + +impl BigNumTrait for BigNum +where + Params: BigNumParamsGetter, +{ + + fn new() -> Self { + Self { limbs: [0; N] } + } + + fn one() -> Self { + let mut result = BigNum::new(); + result.limbs[0] = 1; + result + } + + fn derive_from_seed(seed: [u8; SeedBytes]) -> Self { + let params = Params::get_params(); + Self { limbs: derive_from_seed::<_, MOD_BITS, _>(params, seed) } + } + + unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self { + let params = Params::get_params(); + Self { limbs: __derive_from_seed::<_, MOD_BITS, _>(params, seed) } + } + + fn from_slice(limbs: [Field]) -> Self { + Self { limbs: limbs.as_array() } + } + + fn from_array(limbs: [Field; N]) -> Self { + Self { limbs } + } + + fn from_be_bytes(x: [u8; NBytes]) -> Self { + Self { limbs: from_be_bytes::<_, MOD_BITS, _>(x) } + } + + fn to_le_bytes(self) -> [u8; NBytes] { + to_le_bytes::<_, MOD_BITS, _>(self.limbs) + } + + fn modulus() -> Self { + Self { limbs: Params::get_params().modulus } + } + + fn modulus_bits() -> u32 { + MOD_BITS + } + + fn num_limbs() -> u32 { + N + } + + // fn get(self) -> [Field] { + // self.get_limbs() + // } + + fn get_limbs(self) -> [Field; N] { + self.limbs + } + + fn get_limb(self, idx: u32) -> Field { + self.limbs[idx] + } + + fn set_limb(&mut self, idx: u32, value: Field) { + self.limbs[idx] = value; + } + + unconstrained fn __eq(self, other: Self) -> bool { + __eq(self.limbs, other.limbs) + } + + unconstrained fn __is_zero(self) -> bool { + __is_zero(self.limbs) + } + + unconstrained fn __neg(self) -> Self { + let params = Params::get_params(); + Self::from_array(__neg(params, self.limbs)) + } + + unconstrained fn __add(self, other: Self) -> Self { + let params = Params::get_params(); + Self::from_array(__add(params, self.limbs, other.limbs)) + } + + unconstrained fn __sub(self, other: Self) -> Self { + let params = Params::get_params(); + Self::from_array(__sub(params, self.limbs, other.limbs)) + } + + unconstrained fn __mul(self, other: Self) -> Self { + let params = Params::get_params(); + Self::from_array(__mul::<_, MOD_BITS>(params, self.limbs, other.limbs)) + } + + unconstrained fn __div(self, divisor: Self) -> Self { + let params = Params::get_params(); + Self::from_array(__div::<_, MOD_BITS>(params, self.limbs, divisor.limbs)) + } + + unconstrained fn __udiv_mod(self, divisor: Self) -> (Self, Self) { + let (q, r) = __udiv_mod(self.limbs, divisor.limbs); + (Self { limbs: q }, Self { limbs: r }) + } + + unconstrained fn __invmod(self) -> Self { + let params = Params::get_params(); + assert(params.has_multiplicative_inverse); + Self { limbs: __invmod::<_, MOD_BITS>(params, self.limbs) } + } + + unconstrained fn __pow(self, exponent: Self) -> Self { + let params = Params::get_params(); + Self { limbs: __pow::<_, MOD_BITS>(params, self.limbs, exponent.limbs) } + } + + unconstrained fn __batch_invert(x: [Self; M]) -> [Self; M] { + let params = Params::get_params(); + assert(params.has_multiplicative_inverse); + __batch_invert::<_, MOD_BITS, _>(params, x.map(|bn| Self::get_limbs(bn))).map(|limbs| { + Self { limbs } + }) + } + + unconstrained fn __batch_invert_slice(x: [Self]) -> [Self] { + let params = Params::get_params(); + assert(params.has_multiplicative_inverse); + __batch_invert_slice::<_, MOD_BITS>(params, x.map(|bn| Self::get_limbs(bn))).map(|limbs| { + Self { limbs } + }) + } + + unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option { + let params = Params::get_params(); + let maybe_limbs = unsafe { __tonelli_shanks_sqrt(params, self.limbs) }; + maybe_limbs.map(|limbs| Self { limbs }) + } + + unconstrained fn __compute_quadratic_expression( + lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + linear_terms: [Self; ADD_N], + linear_flags: [bool; ADD_N], + ) -> (Self, Self) { + let params = Params::get_params(); + let (q_limbs, r_limbs) = __compute_quadratic_expression::<_, MOD_BITS, _, _, _, _>( + params, + map(lhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + lhs_flags, + map(rhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + rhs_flags, + map(linear_terms, |bn| Self::get_limbs(bn)), + linear_flags, + ); + (Self { limbs: q_limbs }, Self { limbs: r_limbs }) + } + + fn evaluate_quadratic_expression( + lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + linear_terms: [Self; ADD_N], + linear_flags: [bool; ADD_N], + ) { + let params = Params::get_params(); + evaluate_quadratic_expression::<_, MOD_BITS, _, _, _, _>( + params, + map(lhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + lhs_flags, + map(rhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + rhs_flags, + map(linear_terms, |bn| Self::get_limbs(bn)), + linear_flags, + ) + } + + fn validate_in_field(self: Self) { + let params = Params::get_params(); + validate_in_field::<_, MOD_BITS>(params, self.limbs); + } + + fn validate_in_range(self) { + validate_in_range::<_, MOD_BITS>(self.limbs); + } + + fn assert_is_not_equal(self, other: Self) { + let params = Params::get_params(); + assert_is_not_equal(params, self.limbs, other.limbs); + } + + fn neg(self) -> Self { + let params = Params::get_params(); + Self { limbs: neg::<_, MOD_BITS>(params, self.limbs) } + } + + fn udiv_mod(self, divisor: Self) -> (Self, Self) { + let params = Params::get_params(); + let (q, r) = udiv_mod::<_, MOD_BITS>(params, self.limbs, divisor.limbs); + (Self { limbs: q }, Self { limbs: r }) + } + + fn udiv(self, divisor: Self) -> Self { + let params = Params::get_params(); + Self { limbs: udiv::<_, MOD_BITS>(params, self.limbs, divisor.limbs) } + } + + fn umod(self, divisor: Self) -> Self { + let params = Params::get_params(); + Self { limbs: umod::<_, MOD_BITS>(params, self.limbs, divisor.limbs) } + } + + fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self { + Self { limbs: conditional_select(lhs.limbs, rhs.limbs, predicate) } + } +} + +// impl BigNumTrait for BigNum where Params: BigNumParamsGetter {} + +impl std::ops::Add for BigNum +where + Params: BigNumParamsGetter, +{ + // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them + // via evaluate_quadratic_expression + fn add(self, other: Self) -> Self { + let params = Params::get_params(); + Self { limbs: add::<_, MOD_BITS>(params, self.limbs, other.limbs) } + } +} + +impl std::ops::Sub for BigNum +where + Params: BigNumParamsGetter, +{ + // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them + // via evaluate_quadratic_expression + fn sub(self, other: Self) -> Self { + let params = Params::get_params(); + Self { limbs: sub::<_, MOD_BITS>(params, self.limbs, other.limbs) } + } +} + +impl std::ops::Mul for BigNum +where + Params: BigNumParamsGetter, +{ + // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them + // via evaluate_quadratic_expression + // e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression` + // will create much fewer constraints than calling `mul` and `add` directly + fn mul(self, other: Self) -> Self { + let params = Params::get_params(); + Self { limbs: mul::<_, MOD_BITS>(params, self.limbs, other.limbs) } + } +} + +impl std::ops::Div for BigNum +where + Params: BigNumParamsGetter, +{ + // Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation + fn div(self, other: Self) -> Self { + let params = Params::get_params(); + Self { limbs: div::<_, MOD_BITS>(params, self.limbs, other.limbs) } + } +} + +impl std::cmp::Eq for BigNum +where + Params: BigNumParamsGetter, +{ + fn eq(self, other: Self) -> bool { + let params = Params::get_params(); + eq::<_, MOD_BITS>(params, self.limbs, other.limbs) + } +} + diff --git a/src/bignum_test.nr b/src/bignum_test.nr deleted file mode 100644 index a251119f..00000000 --- a/src/bignum_test.nr +++ /dev/null @@ -1,657 +0,0 @@ -use crate::BigNum; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; -use crate::BigNumParamsTrait as BigNumParamsTrait; - -use crate::utils::u60_representation::U60Repr; -use crate::fields::bn254Fq::BNParams; -use crate::fields::U256::U256Params; - -use crate::runtime_bignum::BigNumInstance; -use crate::BigNumTrait; - -struct Test2048Params{} - -// See https://github.com/noir-lang/noir/issues/6172 -#[test] -fn silence_warning() { - let _ = Test2048Params {}; -} -impl RuntimeBigNumParamsTrait<18> for Test2048Params { - fn modulus_bits() -> u32 { - 2048 - } -} -impl BigNumParamsTrait<18> for Test2048Params { - fn get_instance() -> BigNumInstance<18, Self> { - test2048_Instance - } - fn modulus_bits() -> u32 { - 2048 - } -} -global test2048_Instance: BigNumInstance<18, Test2048Params> = BigNumInstance { - modulus: [ - 0xc0a197a5ae0fcdceb052c9732614fe, 0x656ae034423283422243918ab83be3, 0x6bf590da48a7c1070b7d5aabaac678, 0x0cce39f530238b606f24b296e2bda9, 0x01e1fef9bb9c1c3ead98f226f1bfa0, 0xad8c1c816e12e0ed1379055e373abf, 0xcebe80e474f753aa9d1461c435123d, 0xaee5a18ceedef88d115a8b93c167ad, 0x268ba83c4a65c4307427fc495d9e44, 0xdd2777926848667b7df79f342639d4, 0xf455074c96855ca0068668efe7da3d, 0x5ddba6b30bbc168bfb3a1225f27d65, 0x591fec484f36707524133bcd6f4258, 0x59641b756766aeebe66781dd01d062, 0x58bc5eaff4b165e142bf9e2480eebb, 0x667a3964f08e06df772ce64b229a72, 0x9c1fdb18907711bfe3e3c1cf918395, 0xb8 - ], - double_modulus: [ - 0x0181432f4b5c1f9b9d60a592e64c29fc, 0x01cad5c06884650684448723157077c6, 0x01d7eb21b4914f820e16fab557558cef, 0x01199c73ea604716c0de49652dc57b51, 0x0103c3fdf37738387d5b31e44de37f3f, 0x015b183902dc25c1da26f20abc6e757d, 0x019d7d01c8e9eea7553a28c3886a247a, 0x015dcb4319ddbdf11a22b5172782cf5a, 0x014d17507894cb8860e84ff892bb3c88, 0x01ba4eef24d090ccf6fbef3e684c73a7, 0x01e8aa0e992d0ab9400d0cd1dfcfb47a, 0x01bbb74d6617782d17f674244be4faca, 0x01b23fd8909e6ce0ea4826779ade84af, 0x01b2c836eacecd5dd7cccf03ba03a0c3, 0x01b178bd5fe962cbc2857f3c4901dd75, 0x01ccf472c9e11c0dbeee59cc964534e3, 0x01383fb63120ee237fc7c7839f230729, 0x0170 - ], - modulus_u60: U60Repr { limbs: [ - 0x0eb052c9732614fe, 0x0c0a197a5ae0fcdc, 0x022243918ab83be3, 0x0656ae0344232834, 0x070b7d5aabaac678, 0x06bf590da48a7c10, 0x6f24b296e2bda9, 0xcce39f530238b6, 0x0ead98f226f1bfa0, 0x1e1fef9bb9c1c3, 0x0d1379055e373abf, 0x0ad8c1c816e12e0e, 0x0a9d1461c435123d, 0x0cebe80e474f753a, 0x0d115a8b93c167ad, 0x0aee5a18ceedef88, 0x7427fc495d9e44, 0x0268ba83c4a65c43, 0x0b7df79f342639d4, 0x0dd2777926848667, 0x068668efe7da3d, 0x0f455074c96855ca, 0x0bfb3a1225f27d65, 0x05ddba6b30bbc168, 0x0524133bcd6f4258, 0x0591fec484f36707, 0x0be66781dd01d062, 0x059641b756766aee, 0x0142bf9e2480eebb, 0x058bc5eaff4b165e, 0x0f772ce64b229a72, 0x0667a3964f08e06d, 0x0fe3e3c1cf918395, 0x09c1fdb18907711b, 0xb8, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0eb052c9732614fe, 0x0c0a197a5ae0fcdc, 0x022243918ab83be3, 0x0656ae0344232834, 0x070b7d5aabaac678, 0x06bf590da48a7c10, 0x6f24b296e2bda9, 0xcce39f530238b6, 0x0ead98f226f1bfa0, 0x1e1fef9bb9c1c3, 0x0d1379055e373abf, 0x0ad8c1c816e12e0e, 0x0a9d1461c435123d, 0x0cebe80e474f753a, 0x0d115a8b93c167ad, 0x0aee5a18ceedef88, 0x7427fc495d9e44, 0x0268ba83c4a65c43, 0x0b7df79f342639d4, 0x0dd2777926848667, 0x068668efe7da3d, 0x0f455074c96855ca, 0x0bfb3a1225f27d65, 0x05ddba6b30bbc168, 0x0524133bcd6f4258, 0x0591fec484f36707, 0x0be66781dd01d062, 0x059641b756766aee, 0x0142bf9e2480eebb, 0x058bc5eaff4b165e, 0x0f772ce64b229a72, 0x0667a3964f08e06d, 0x0fe3e3c1cf918395, 0x09c1fdb18907711b, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x1697def7100cd5cf8d890b4ef2ec3f, 0x765ba8304214dac764d3f4adc31859, 0x8404bd14d927ea230e60d4bebf9406, 0xc4d53a23bacc251ecbfc4b7ba5a0b4, 0x3eaf3499474a6f5b2fff83f1259c87, 0xbff4c737b97281f1a5f2384a8c16d9, 0x1b4cf2f55358476b53237829990555, 0xe7a804e8eacfe3a2a5673bc3885b86, 0xabadeae4282906c817adf70eab4ae1, 0x66f7df257fe2bf27f0809aceed9b0e, 0xd90fb7428901b8bed11f6b81e36bf1, 0x36e6ba885c60b7024c563605df7e07, 0x2b7c58d2fb5d2c8478963ae6d4a44f, 0x6ee761de26635f114ccc3f7d74f855, 0x3fb726a10cf2220897513f05243de3, 0x43a26bbd732496eb4d828591b8056e, 0xf4e42304e60fb3a54fca735499f2cf, 0x162f - ] -}; -type Fq = BigNum<3, BNParams>; - -fn test_eq(_: BigNum, __: [Field; N]) where BigNum: BigNumTrait { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let c = unsafe { - BigNum::__derive_from_seed([2, 2, 3, 4]) - }; - - let modulus = BigNum::modulus(); - let t0: U60Repr = (U60Repr::from(modulus.get().as_array())); - let t1: U60Repr = (U60Repr::from(b.get().as_array())); - let b_plus_modulus: BigNum = BigNum::from(U60Repr::into(t0 + t1).as_slice()); - assert(a.eq(b) == true); - assert(a.eq(b_plus_modulus) == true); - assert(c.eq(b) == false); - assert(c.eq(a) == false); -} - -// fn test_eq(_: BigNum) where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { -// let a = BigNum::__derive_from_seed([1, 2, 3, 4]); -// let b = BigNum::__derive_from_seed([1, 2, 3, 4]); -// let c = BigNum::__derive_from_seed([2, 2, 3, 4]); - -// let modulus: BigNum = Params::get_instance().modulus(); -// let t0: U60Repr = (U60Repr::from(modulus.limbs)); -// let t1: U60Repr = (U60Repr::from(b.limbs)); -// let b_plus_modulus: BigNum = BigNum { limbs: U60Repr::into(t0 + t1) }; - -// assert(a.eq(b) == true); -// assert(a.eq(b_plus_modulus) == true); -// assert(c.eq(b) == false); -// assert(c.eq(a) == false); -// } - -// // // 98760 -// // // 99689 -// // // 929 gates for a 2048 bit mul -fn test_mul(_: BigNum) where BigNum: BigNumTrait + std::ops::Mul + std::ops::Add { - let a: BigNum = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b: BigNum = unsafe { - BigNum::__derive_from_seed([4, 5, 6, 7]) - }; - - let c = (a + b) * (a + b); - let d = (a * a) + (b * b) + (a * b) + (a * b); - assert(c.eq(d)); -} - -fn test_add(_: BigNum) where BigNum: BigNumTrait + std::ops::Add + std::ops::Mul + std::cmp::Eq { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b: BigNum = unsafe { - BigNum::__derive_from_seed([4, 5, 6, 7]) - }; - let one = BigNum::one(); - a.validate_in_range(); - a.validate_in_field(); - b.validate_in_range(); - b.validate_in_field(); - let mut c = (a + b); - c += c; - let d = (a + b) * (one + one); - assert(c == (d)); - let e = one + one; - let limbs = e.get(); - let mut first: bool = true; - for limb in limbs { - if first { - first = false; - assert(limb == 2); - } else { - assert(limb == 0); - } - } -} - -fn test_div(_: BigNum) where BigNum: BigNumTrait + std::ops::Div + std::ops::Mul + std::ops::Add + std::cmp::Eq { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([4, 5, 6, 7]) - }; - - let c = a / b; - assert((b * c) == (a)); -} - -fn test_invmod(_: BigNum) where BigNum: BigNumTrait + std::cmp::Eq { - let u = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - for _ in 0..1 { - let v = unsafe { - u.__invmod() - }; - let result = unsafe { - u.__mul(v) - }; - let expected = BigNum::one(); - assert(result == expected); - } -} - -fn assert_is_not_equal(_: BigNum) where BigNum: BigNumTrait { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([4, 5, 6, 7]) - }; - - a.assert_is_not_equal(b); -} - -fn assert_is_not_equal_fail(_: BigNum) where BigNum: BigNumTrait { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - - a.assert_is_not_equal(b); -} - -fn assert_is_not_equal_overloaded_lhs_fail(_: BigNum, __: [Field; N]) where BigNum: BigNumTrait { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - - let modulus = BigNum::modulus(); - - let t0: U60Repr = U60Repr::from(a.get().as_array()); - let t1: U60Repr = U60Repr::from(modulus.get().as_array()); - let a_plus_modulus: BigNum = BigNum::from(U60Repr::into(t0 + t1).as_slice()); - a_plus_modulus.assert_is_not_equal(b); -} - -fn assert_is_not_equal_overloaded_rhs_fail(_: BigNum, __: [Field; N]) where BigNum: BigNumTrait { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - - let modulus = BigNum::modulus(); - - let t0: U60Repr = U60Repr::from(b.get().as_array()); - let t1: U60Repr = U60Repr::from(modulus.get().as_array()); - let b_plus_modulus: BigNum = BigNum::from(U60Repr::into(t0 + t1).as_slice()); - a.assert_is_not_equal(b_plus_modulus); -} - -fn assert_is_not_equal_overloaded_fail(_: BigNum, __: [Field; N]) where BigNum: BigNumTrait { - let a = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - - let modulus = BigNum::modulus(); - - let t0: U60Repr = U60Repr::from(a.get().as_array()); - let t1: U60Repr = U60Repr::from(b.get().as_array()); - let t2: U60Repr = U60Repr::from(modulus.get().as_array()); - let a_plus_modulus: BigNum = BigNum::from(U60Repr::into(t0 + t2).as_slice()); - let b_plus_modulus: BigNum = BigNum::from(U60Repr::into(t1 + t2).as_slice()); - a_plus_modulus.assert_is_not_equal(b_plus_modulus); -} - -#[test] -fn test_eq_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - test_eq(stub, [0; 3]); -} -#[test] -fn test_add_BN() { - let mut a: Fq = BigNum::modulus(); - let mut b: Fq = BigNum::modulus(); - let mut expected: Fq = BigNum::modulus(); - - a.limbs[0] -= 1; - b.limbs[0] -= 1; - expected.limbs[0] -= 2; - - let result = a.add(b); - assert(result.eq(expected)); -} - -#[test] -fn test_sub_test_BN() { - // 0 - 1 should equal p - 1 - let mut a: Fq = BigNum::new(); - let mut b: Fq = BigNum::one(); - let mut expected: Fq = BigNum::modulus(); - expected.limbs[0] -= 1; // p - 1 - - let result = a.sub(b); - assert(result.eq(expected)); -} - -#[test] -fn test_sub_modulus_limit() { - // if we underflow, maximum result should be ... - // 0 - 1 = o-1 - // 0 - p = 0 - let mut a: Fq = BigNum::new(); - let mut b: Fq = BigNum::modulus(); - let mut expected = BigNum::new(); - - let result = a.sub(b); - assert(result.eq(expected)); -} - -#[test(should_fail_with = "call to assert_max_bit_size")] -fn test_sub_modulus_underflow() { - // 0 - (p + 1) is smaller than p and should produce unsatisfiable constraints - let mut a: Fq = BigNum::new(); - let mut b: Fq = BigNum::modulus(); - b.limbs[0] += 1; - let mut expected = BigNum::one(); - - let result = a.sub(b); - assert(result.eq(expected)); -} - -#[test] -fn test_add_modulus_limit() { - // p + 2^{254} - 1 should be the maximum allowed value fed into an add operation - // when adding, if the result overflows the modulus, we conditionally subtract the modulus, producing 2^{254} - 1 - // this is the largest value that will satisfy the range check applied when constructing a bignum - let p : U60Repr<3, 2> = U60Repr::from(BNParams::get_instance().modulus().get().as_array()); - let two_pow_254_minus_1: U60Repr<3, 2> = U60Repr::from([0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x3fff]); - let a: Fq = BigNum { limbs: U60Repr::into(p) }; - let b: Fq = BigNum { limbs: U60Repr::into(two_pow_254_minus_1) }; - let result = a.add(b); - assert(result.eq(b)); -} - -#[test(should_fail_with = "call to assert_max_bit_size")] -fn test_add_modulus_overflow() { - //(2^{254} - 1) + (p - 1) = 2^{254} + p - // after subtracting modulus, result is 2^{254} will does not satisfy the range check applied when constructing a BigNum - let p : U60Repr<3, 2> = U60Repr::from(BNParams::get_instance().modulus().get().as_array()); - let two_pow_254_minus_1: U60Repr<3, 2> = U60Repr::from([0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x3fff]); - let one = U60Repr::from([1, 0, 0]); - let a: Fq = BigNum { limbs: U60Repr::into(p + one) }; - let b: Fq = BigNum { limbs: U60Repr::into(two_pow_254_minus_1) }; - let result = a.add(b); - assert(result.eq(b)); -} - -#[test] -fn test_mul_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - test_mul(stub); -} - -#[test] -fn test_add_BN2() { - let stub: BigNum<3, BNParams> = BigNum::new(); - test_add(stub); -} - -#[test] -fn test_div_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - test_div(stub); -} - -#[test] -fn test_invmod_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - test_invmod(stub); -} - -#[test] -fn test_assert_is_not_equal_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - assert_is_not_equal(stub); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_fail_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - assert_is_not_equal_fail(stub); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_lhs_fail_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - assert_is_not_equal_overloaded_lhs_fail(stub, [0; 3]); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_rhs_fail_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - assert_is_not_equal_overloaded_rhs_fail(stub, [0; 3]); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_fail_BN() { - let stub: BigNum<3, BNParams> = BigNum::new(); - assert_is_not_equal_overloaded_fail(stub, [0; 3]); -} - -#[test] -fn test_eq_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - test_eq(stub, [0; 18]); -} - -#[test] -fn test_mul_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - test_mul(stub); -} - -#[test] -fn test_add_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - test_add(stub); -} - -#[test] -fn test_assert_is_not_equal_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - assert_is_not_equal(stub); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_fail_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - assert_is_not_equal_fail(stub); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_lhs_fail_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - assert_is_not_equal_overloaded_lhs_fail(stub, [0; 18]); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_rhs_fail_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - assert_is_not_equal_overloaded_rhs_fail(stub, [0; 18]); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_fail_2048() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - assert_is_not_equal_overloaded_fail(stub, [0; 18]); -} - -#[test] -fn test_eq_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - test_eq(stub, [0; 3]); -} - -#[test] -fn test_mul_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - test_mul(stub); -} - -#[test] -fn test_add_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - test_add(stub); -} - -#[test] -fn test_assert_is_not_equal_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - assert_is_not_equal(stub); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_fail_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - assert_is_not_equal_fail(stub); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_lhs_fail_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - assert_is_not_equal_overloaded_lhs_fail(stub, [0; 3]); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_rhs_fail_U256() { - let stub: BigNum<3, U256Params> = BigNum::new(); - assert_is_not_equal_overloaded_rhs_fail(stub, [0; 3]); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn test_assert_is_not_equal_overloaded_fail_U256() { - let stub: BigNum<18, Test2048Params> = BigNum::new(); - assert_is_not_equal_overloaded_fail(stub, [0; 18]); -} - -type U256 = BigNum<3, U256Params>; -#[test] -fn test_udiv_mod_U256() { - let a: U256 = unsafe { - BigNum::__derive_from_seed([1, 2, 3, 4]) - }; - let b: U256 = BigNum::from_array([12, 0, 0]); - - let (q, r) = a.udiv_mod(b); - - // let qb = q.__mul(b); - let product = unsafe { - q.__mul(b).__add(r) - }; - assert(product.eq(a)); -} - -// // N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril -// #[test] -// fn test_div_2048() { -// let stub: BigNum<18, Test2048Params> = BigNum::new(); -// test_div(stub); -// } - -// // N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril -// #[test] -// fn test_invmod_2048() { -// let stub: BigNum<18, Test2048Params> = BigNum::new(); -// test_invmod(stub); -// } - -#[test] -fn test_2048_bit_quadratic_expression() { - let a: [Field; 18] = [ - 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, - 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, - 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, - 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, - 0x00000000000000000000000000000000008337197826e2e9ea000ed5b05d5ac5, - 0x000000000000000000000000000000000040680101b43f6d17de8e3507f3d820, - 0x00000000000000000000000000000000000c6ba0cdcf77cff1c10355ea48d387, - 0x0000000000000000000000000000000000e51717a72902214a9dbeb90e4f225f, - 0x0000000000000000000000000000000000c1bd5bec78406b691f71cbcddb4574, - 0x00000000000000000000000000000000001ce5e532cfb306d7b52e7d9f1aa442, - 0x000000000000000000000000000000000019575932f75ddf00595b22782e1ba2, - 0x0000000000000000000000000000000000d630b3fbf0a9e55861e4399900feb9, - 0x0000000000000000000000000000000000d6b37aeb2daa8d2e2f7e29b0f7752a, - 0x0000000000000000000000000000000000e9cacdd93406256b9eb46b73948849, - 0x00000000000000000000000000000000001400e1f0a38695db66993fe042c48b, - 0x0000000000000000000000000000000000e1d829cb4fa8cabb7d0265efbd8527, - 0x000000000000000000000000000000000055f1a92a5dd099ef2bcd89ac175b52, - 0x00000000000000000000000000000000000000000000000000000000000000fc - ]; - let b: [Field; 18] = [ - 0x0000000000000000000000000000000000c5694493e9bcc76e68dfcf73e0fde1, - 0x0000000000000000000000000000000000ede5e4b8b3e0dec1f4705c35521620, - 0x00000000000000000000000000000000007aa800bab1b33eda0f07695af6c583, - 0x000000000000000000000000000000000045892edea2c02bf0b8b1d2d9a4ebcc, - 0x00000000000000000000000000000000004dffb06bf396f3d0a5b67cff714bdd, - 0x00000000000000000000000000000000004d691db495235e1e032f1ef3e90274, - 0x0000000000000000000000000000000000d92c069d0f2675b2f46cb497aa62d4, - 0x00000000000000000000000000000000003d3f23584f113cef1a4b8b7d183f5c, - 0x0000000000000000000000000000000000289ba11d897837f9cec57dcc430bfc, - 0x0000000000000000000000000000000000765dc64f6ed4a6efd7b26c38f79e59, - 0x00000000000000000000000000000000008edf31fabf5c330ecf7f92fb6487cd, - 0x000000000000000000000000000000000053392f8b14dd78af702b3be2e0d557, - 0x000000000000000000000000000000000034abf357bfd56e9786a7e47ed9a5ae, - 0x0000000000000000000000000000000000a9ebb234064c8ab10d4e7900d4b973, - 0x00000000000000000000000000000000002a6850cce14a20463913002ddc0fa6, - 0x0000000000000000000000000000000000a97e3b06586bfa62325ef7557ab536, - 0x0000000000000000000000000000000000b942b0d26e5be2e08cd425107c59f7, - 0x0000000000000000000000000000000000000000000000000000000000000031 - ]; - let c_expected: [Field; 18] = [ - 0x00000000000000000000000000000000004518a874adebbcf963fed876dfcf78, - 0x00000000000000000000000000000000002b1535070c2deca63e2dc7145a9997, - 0x0000000000000000000000000000000000d9b738665a290c09f09202043d9387, - 0x0000000000000000000000000000000000c88853b11034fe12661eb7a5e41ca7, - 0x0000000000000000000000000000000000357cc4053e7eb127abc2c1430972a1, - 0x0000000000000000000000000000000000224df5e1be31a51562f8574027a992, - 0x000000000000000000000000000000000070ad9287e6326d534f1d2835e159ad, - 0x00000000000000000000000000000000000efa138f75f20b5117955e15bbb447, - 0x0000000000000000000000000000000000d9f45c310be1865ad23fbcdeb1d93f, - 0x00000000000000000000000000000000004f74ca4cf3df59a83f2df796fc9beb, - 0x0000000000000000000000000000000000ed1801428ebf7db771deb45f4311eb, - 0x00000000000000000000000000000000002ded3b46e3a84cda43157d4d927162, - 0x00000000000000000000000000000000009bcd6ac8f90601a44a84a026d4b383, - 0x0000000000000000000000000000000000ab098478b39031a1de85062fd5712b, - 0x00000000000000000000000000000000004432a79276f4375ff3ec2ced8b6cf6, - 0x0000000000000000000000000000000000a0922d75e96e3f9e31c0cbbcbd708a, - 0x00000000000000000000000000000000004013822c9e9aa5b5b1e9c33e4332b7, - 0x0000000000000000000000000000000000000000000000000000000000000058 - ]; - - let a_bn: BigNum<18, Test2048Params> = BigNum { limbs: a }; - let b_bn: BigNum<18, Test2048Params> = BigNum { limbs: b }; - let c_bn = unsafe { - a_bn.__mul(b_bn) - }; - assert(c_bn.limbs == c_expected); - - a_bn.validate_in_range(); - - BigNum::evaluate_quadratic_expression([[a_bn]], [[false]], [[b_bn]], [[false]], [c_bn], [true]); -} - -#[test] -fn test_expressions() { - let x: [Field; 6] = [ - 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, - 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, 0x00000000000000000000000000000000000000000000000000000000b05d5ac5, 0 - ]; - - let y: Fq = BigNum { - limbs: [ - 0x1, - 0x1, - 0x0 - ] - }; - let z: Fq = BigNum { - limbs: [ - 0x2, - 0x2, - 0x0 - ] - }; - let yy = unsafe { - y.__add(y) - }; - - assert(yy.limbs == z.limbs); - - let uu: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4a832748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e04080471712c1d7f18e89, - 0x000000000000000000000000000000000000000000000000000000000000063 - ] - }; - let vv: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4aec2748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e0408047171a01d7f18e89, - 0x0000000000000000000000000000000000000000000000000000000000000062 - ] - }; - let w: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4a832748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e04080471712c1d7f18e89, - 0x0000000000000000000000000000000000000000000000000000000000001f93 - ] - }; - let x: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4aec2748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e0408047171a01d7f18e89, - 0x0000000000000000000000000000000000000000000000000000000000000f93 - ] - }; - let wx = unsafe { - w.__mul(x) - }; - let uv = unsafe { - uu.__mul(vv) - }; - let y = unsafe { - (uv.__add(wx)).__neg() - }; - let z = unsafe { - uv.__add(wx) - }; - - BigNum::evaluate_quadratic_expression( - [[uu], [w]], - [[false], [false]], - [[vv], [x]], - [[false], [false]], - [z], - [true] - ); - BigNum::evaluate_quadratic_expression( - [[uu], [w]], - [[false], [false]], - [[vv], [x]], - [[false], [false]], - [y], - [false] - ); - - let wx_constrained = w * x; - assert(wx_constrained.limbs == wx.limbs); -} - diff --git a/src/fields/U1024.nr b/src/fields/U1024.nr index d08f2c0d..5f8f438a 100644 --- a/src/fields/U1024.nr +++ b/src/fields/U1024.nr @@ -1,33 +1,41 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U1024Params {} -impl RuntimeBigNumParamsTrait<9> for U1024Params { - fn modulus_bits() -> u32 { - 1025 + +impl BigNumParamsGetter<9, 1025> for U1024Params { + fn get_params() -> BigNumParams<9, 1025> { + U1024_PARAMS } } -impl BigNumParamsTrait<9> for U1024Params { - fn get_instance() -> BigNumInstance<9, Self> { - U1024_Instance - } - fn modulus_bits() -> u32 { - 1025 - } -} -pub global U1024_Instance: BigNumInstance<9, U1024Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000000000000000 + +global U1024_PARAMS: BigNumParams<9, 1025> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000000000000000], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ffffffffffffffff, + ], + modulus_u60: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ffffffffffffffff + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400000000000000000 - ] + }, + redc_param: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400000000000000000], }; diff --git a/src/fields/U2048.nr b/src/fields/U2048.nr index 1f98aec2..6c689179 100644 --- a/src/fields/U2048.nr +++ b/src/fields/U2048.nr @@ -1,33 +1,60 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U2048Params {} -impl RuntimeBigNumParamsTrait<18> for U2048Params { - fn modulus_bits() -> u32 { - 2049 + +impl BigNumParamsGetter<18, 2049> for U2048Params { + fn get_params() -> BigNumParams<18, 2049> { + U2048_PARAMS } } -impl BigNumParamsTrait<18> for U2048Params { - fn get_instance() -> BigNumInstance<18, Self> { - U2048_Instance - } - fn modulus_bits() -> u32 { - 2049 - } -} -pub global U2048_Instance: BigNumInstance<18, U2048Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100 + +global U2048_PARAMS: BigNumParams<18, 2049> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0100, + ], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ff, + ], + modulus_u60: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100, 0x00, ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ff + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4000 - ] + }, + redc_param: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4000, + ], }; diff --git a/src/fields/U256.nr b/src/fields/U256.nr index f6dee0df..e542d4a5 100644 --- a/src/fields/U256.nr +++ b/src/fields/U256.nr @@ -1,33 +1,26 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U256Params {} -impl RuntimeBigNumParamsTrait<3> for U256Params { - fn modulus_bits() -> u32 { - 257 + +impl BigNumParamsGetter<3, 257> for U256Params { + fn get_params() -> BigNumParams<3, 257> { + U256_PARAMS } } -impl BigNumParamsTrait<3> for U256Params { - fn get_instance() -> BigNumInstance<3, Self> { - U256_Instance - } - fn modulus_bits() -> u32 { - 257 - } -} -pub global U256_Instance: BigNumInstance<3, U256Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x010000 - ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0x01ffff - ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x010000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x400000 - ] + +global U256_PARAMS: BigNumParams<3, 257> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [0x00, 0x00, 0x010000], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0x01ffff, + ], + modulus_u60: U60Repr { limbs: [0x00, 0x00, 0x00, 0x00, 0x010000, 0x00] }, + modulus_u60_x4: U60Repr { + limbs: [0x00, 0x00, 0x00, 0x00, 0x010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + }, + redc_param: [0x00, 0x00, 0x400000], }; diff --git a/src/fields/U384.nr b/src/fields/U384.nr index 069a1435..572fbe67 100644 --- a/src/fields/U384.nr +++ b/src/fields/U384.nr @@ -1,33 +1,30 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; -pub struct U384Params {} -impl RuntimeBigNumParamsTrait<4> for U384Params { - fn modulus_bits() -> u32 { - 385 + +pub struct U384_Params {} + +impl BigNumParamsGetter<4, 385> for U384_Params { + fn get_params() -> BigNumParams<4, 385> { + U384_PARAMS } } -impl BigNumParamsTrait<4> for U384Params { - fn get_instance() -> BigNumInstance<4, Self> { - U384_Instance - } - fn modulus_bits() -> u32 { - 385 - } -} -pub global U384_Instance: BigNumInstance<4, U384Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x01000000 - ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ffffff + +global U384_PARAMS: BigNumParams<4, 385> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [0x00, 0x00, 0x00, 0x01000000], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ffffff, + ], + modulus_u60: U60Repr { limbs: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000, 0x00] }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x40000000 - ] + }, + redc_param: [0x00, 0x00, 0x00, 0x40000000], }; diff --git a/src/fields/U4096.nr b/src/fields/U4096.nr index cfb71e8b..d63124c7 100644 --- a/src/fields/U4096.nr +++ b/src/fields/U4096.nr @@ -1,33 +1,85 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U4096Params {} -impl RuntimeBigNumParamsTrait<35> for U4096Params { - fn modulus_bits() -> u32 { - 4097 + +impl BigNumParamsGetter<35, 4097> for U4096Params { + fn get_params() -> BigNumParams<35, 4097> { + U4096_PARAMS } } -impl BigNumParamsTrait<35> for U4096Params { - fn get_instance() -> BigNumInstance<35, Self> { - U4096_Instance - } - fn modulus_bits() -> u32 { - 4097 - } -} -pub global U4096_Instance: BigNumInstance<35, U4096Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000 + +global U4096_PARAMS: BigNumParams<35, 4097> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x010000, + ], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ffff, + ], + modulus_u60: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000, 0x00, ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ffff + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x010000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x400000 - ] + }, + redc_param: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x400000, + ], }; diff --git a/src/fields/U512.nr b/src/fields/U512.nr index 3ef3e3bf..50277773 100644 --- a/src/fields/U512.nr +++ b/src/fields/U512.nr @@ -1,33 +1,52 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U512Params {} -impl RuntimeBigNumParamsTrait<5> for U512Params { - fn modulus_bits() -> u32 { - 513 + +impl BigNumParamsGetter<5, 513> for U512Params { + fn get_params() -> BigNumParams<5, 513> { + U512_PARAMS } } -impl BigNumParamsTrait<5> for U512Params { - fn get_instance() -> BigNumInstance<5, Self> { - U512_Instance - } - fn modulus_bits() -> u32 { - 513 - } -} -pub global U512_Instance: BigNumInstance<5, U512Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x00, 0x0100000000 - ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ffffffff + +global U512_PARAMS: BigNumParams<5, 513> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [0x00, 0x00, 0x00, 0x00, 0x0100000000], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ffffffff, + ], + modulus_u60: U60Repr { + limbs: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100000000, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0100000000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100000000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x00, 0x4000000000 - ] + }, + redc_param: [0x00, 0x00, 0x00, 0x00, 0x4000000000], }; + diff --git a/src/fields/U768.nr b/src/fields/U768.nr index 6085088b..c9e0cb44 100644 --- a/src/fields/U768.nr +++ b/src/fields/U768.nr @@ -1,33 +1,76 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U768Params {} -impl RuntimeBigNumParamsTrait<7> for U768Params { - fn modulus_bits() -> u32 { - 769 + +impl BigNumParamsGetter<7, 769> for U768Params { + fn get_params() -> BigNumParams<7, 769> { + U768_PARAMS } } -impl BigNumParamsTrait<7> for U768Params { - fn get_instance() -> BigNumInstance<7, Self> { - U768_Instance - } - fn modulus_bits() -> u32 { - 769 - } -} -pub global U768_Instance: BigNumInstance<7, U768Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000000000 + +global U768_PARAMS: BigNumParams<7, 769> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000000000], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ffffffffffff, + ], + modulus_u60: U60Repr { + limbs: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01000000000000, + 0x00, ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ffffffffffff + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01000000000000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000000000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01000000000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40000000000000 - ] + }, + redc_param: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40000000000000], }; diff --git a/src/fields/U8192.nr b/src/fields/U8192.nr index 5f08709f..a70b3917 100644 --- a/src/fields/U8192.nr +++ b/src/fields/U8192.nr @@ -1,33 +1,650 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct U8192Params {} -impl RuntimeBigNumParamsTrait<69> for U8192Params { - fn modulus_bits() -> u32 { - 8193 + +impl BigNumParamsGetter<69, 8193> for U8192Params { + fn get_params() -> BigNumParams<69, 8193> { + U8192_PARAMS } } -impl BigNumParamsTrait<69> for U8192Params { - fn get_instance() -> BigNumInstance<69, Self> { - U8192_Instance - } - fn modulus_bits() -> u32 { - 8193 - } -} -pub global U8192_Instance: BigNumInstance<69, U8192Params> = BigNumInstance { - modulus: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100000000 + +global U8192_PARAMS: BigNumParams<69, 8193> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0100000000, + ], + double_modulus: [ + 0x01000000000000000000000000000000, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x01ffffffff, + ], + modulus_u60: U60Repr { + limbs: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0100000000, + 0x00, ], - double_modulus: [ - 0x01000000000000000000000000000000, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffff, 0x01ffffffff + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0100000000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100000000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0100000000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4000000000 - ] + }, + redc_param: [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x4000000000, + ], }; diff --git a/src/fields/bls12_377Fq.nr b/src/fields/bls12_377Fq.nr index 32cb87b7..81a6cc98 100644 --- a/src/fields/bls12_377Fq.nr +++ b/src/fields/bls12_377Fq.nr @@ -16,36 +16,68 @@ //! * G1 curve equation: y^2 = x^3 + 1 //! * G2 curve equation: y^2 = x^3 + B, where //! * B = Fq2(0, 155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906) -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct BLS12_377_Fq_Params {} -impl RuntimeBigNumParamsTrait<4> for BLS12_377_Fq_Params { - fn modulus_bits() -> u32 { - 377 + +impl BigNumParamsGetter<4, 377> for BLS12_377_Fq_Params { + fn get_params() -> BigNumParams<4, 377> { + BLS12_377_Fq_PARAMS } } -impl BigNumParamsTrait<4> for BLS12_377_Fq_Params { - fn get_instance() -> BigNumInstance<4, Self> { - BLS12_377_Fq_Instance - } - fn modulus_bits() -> u32 { - 377 - } -} -pub global BLS12_377_Fq_Instance: BigNumInstance<4, BLS12_377_Fq_Params> = BigNumInstance { - modulus: [ - 0x0b5d44300000008508c00000000001, 0xd9f300f5138f1ef3622fba09480017, 0x4617c510eac63b05c06ca1493b1a22, 0x01ae3a + +pub global BLS12_377_Fq_PARAMS: BigNumParams<4, 377> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0x0b5d44300000008508c00000000001, + 0xd9f300f5138f1ef3622fba09480017, + 0x4617c510eac63b05c06ca1493b1a22, + 0x01ae3a, + ], + double_modulus: [ + 0x0116ba88600000010a11800000000002, + 0x01b3e601ea271e3de6c45f741290002d, + 0x018c2f8a21d58c760b80d94292763444, + 0x035c73, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0508c00000000001, + 0xb5d44300000008, + 0x03622fba09480017, + 0x0d9f300f5138f1ef, + 0x05c06ca1493b1a22, + 0x04617c510eac63b0, + 0x01ae3a, + 0x00, ], - double_modulus: [ - 0x0116ba88600000010a11800000000002, 0x01b3e601ea271e3de6c45f741290002d, 0x018c2f8a21d58c760b80d94292763444, 0x035c73 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0508c00000000001, + 0xb5d44300000008, + 0x03622fba09480017, + 0x0d9f300f5138f1ef, + 0x05c06ca1493b1a22, + 0x04617c510eac63b0, + 0x01ae3a, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0508c00000000001, 0xb5d44300000008, 0x03622fba09480017, 0x0d9f300f5138f1ef, 0x05c06ca1493b1a22, 0x04617c510eac63b0, 0x01ae3a, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0508c00000000001, 0xb5d44300000008, 0x03622fba09480017, 0x0d9f300f5138f1ef, 0x05c06ca1493b1a22, 0x04617c510eac63b0, 0x01ae3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0xd687789c42a591f9fd58c5e4daffcc, 0x0de6776b1a06af2d488d85a6d02d0e, 0xd0cc4060e976c3ca0582ef4f73bbad, 0x261508 - ] + }, + redc_param: [ + 0xd687789c42a591f9fd58c5e4daffcc, + 0x0de6776b1a06af2d488d85a6d02d0e, + 0xd0cc4060e976c3ca0582ef4f73bbad, + 0x261508, + ], }; diff --git a/src/fields/bls12_377Fr.nr b/src/fields/bls12_377Fr.nr index ee3ac2ee..123b8139 100644 --- a/src/fields/bls12_377Fr.nr +++ b/src/fields/bls12_377Fr.nr @@ -17,36 +17,51 @@ //! * G2 curve equation: y^2 = x^3 + B, where //! * B = Fq2(0, 155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906) -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct BLS12_377_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for BLS12_377_Fr_Params { - fn modulus_bits() -> u32 { - 253 - } -} -impl BigNumParamsTrait<3> for BLS12_377_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - BLS12_377_Fr_Instance - } - fn modulus_bits() -> u32 { - 253 + +impl BigNumParamsGetter<3, 253> for BLS12_377_Fr_Params { + fn get_params() -> BigNumParams<3, 253> { + BLS12_377_Fr_PARAMS } } -pub global BLS12_377_Fr_Instance: BigNumInstance<3, BLS12_377_Fr_Params> = BigNumInstance { - modulus: [ - 0xaa76fed00000010a11800000000001, 0x655e9a2ca55660b44d1e5c37b00159, 0x12ab + +global BLS12_377_Fr_PARAMS: BigNumParams<3, 253> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xaa76fed00000010a11800000000001, 0x655e9a2ca55660b44d1e5c37b00159, 0x12ab], + double_modulus: [ + 0x0154edfda00000021423000000000002, + 0x01cabd34594aacc1689a3cb86f6002b2, + 0x2555, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0a11800000000001, + 0x0aa76fed00000010, + 0x044d1e5c37b00159, + 0x0655e9a2ca55660b, + 0x12ab, + 0x00, ], - double_modulus: [ - 0x0154edfda00000021423000000000002, 0x01cabd34594aacc1689a3cb86f6002b2, 0x2555 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0a11800000000001, + 0x0aa76fed00000010, + 0x044d1e5c37b00159, + 0x0655e9a2ca55660b, + 0x12ab, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0a11800000000001, 0x0aa76fed00000010, 0x044d1e5c37b00159, 0x0655e9a2ca55660b, 0x12ab, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0a11800000000001, 0x0aa76fed00000010, 0x044d1e5c37b00159, 0x0655e9a2ca55660b, 0x12ab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0xa180b8d69e258f5204c21151e79ea1, 0x91ec40b2c9ee4e51e49faa80548fd0, 0x036d94 - ] + }, + redc_param: [0xa180b8d69e258f5204c21151e79ea1, 0x91ec40b2c9ee4e51e49faa80548fd0, 0x036d94], }; diff --git a/src/fields/bls12_381Fq.nr b/src/fields/bls12_381Fq.nr index c91b4f34..f2ef2e65 100644 --- a/src/fields/bls12_381Fq.nr +++ b/src/fields/bls12_381Fq.nr @@ -14,36 +14,68 @@ //! * valuation(r - 1, 2) = 32 //! * G1 curve equation: y^2 = x^3 + 4 //! * G2 curve equation: y^2 = x^3 + Fq2(4, 4) -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct BLS12_381_Fq_Params {} -impl RuntimeBigNumParamsTrait<4> for BLS12_381_Fq_Params { - fn modulus_bits() -> u32 { - 381 + +impl BigNumParamsGetter<4, 381> for BLS12_381_Fq_Params { + fn get_params() -> BigNumParams<4, 381> { + BLS12_381_Fq_PARAMS } } -impl BigNumParamsTrait<4> for BLS12_381_Fq_Params { - fn get_instance() -> BigNumInstance<4, Self> { - BLS12_381_Fq_Instance - } - fn modulus_bits() -> u32 { - 381 - } -} -pub global BLS12_381_Fq_Instance: BigNumInstance<4, BLS12_381_Fq_Params> = BigNumInstance { - modulus: [ - 0xabfffeb153ffffb9feffffffffaaab, 0x4b84f38512bf6730d2a0f6b0f6241e, 0xea397fe69a4b1ba7b6434bacd76477, 0x1a0111 + +global BLS12_381_Fq_PARAMS: BigNumParams<4, 381> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0xabfffeb153ffffb9feffffffffaaab, + 0x4b84f38512bf6730d2a0f6b0f6241e, + 0xea397fe69a4b1ba7b6434bacd76477, + 0x1a0111, + ], + double_modulus: [ + 0x0157fffd62a7ffff73fdffffffff5556, + 0x019709e70a257ece61a541ed61ec483c, + 0x01d472ffcd3496374f6c869759aec8ed, + 0x340222, + ], + modulus_u60: U60Repr { + limbs: [ + 0x09feffffffffaaab, + 0x0abfffeb153ffffb, + 0xd2a0f6b0f6241e, + 0x04b84f38512bf673, + 0x07b6434bacd76477, + 0x0ea397fe69a4b1ba, + 0x1a0111, + 0x00, ], - double_modulus: [ - 0x0157fffd62a7ffff73fdffffffff5556, 0x019709e70a257ece61a541ed61ec483c, 0x01d472ffcd3496374f6c869759aec8ed, 0x340222 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x09feffffffffaaab, + 0x0abfffeb153ffffb, + 0xd2a0f6b0f6241e, + 0x04b84f38512bf673, + 0x07b6434bacd76477, + 0x0ea397fe69a4b1ba, + 0x1a0111, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x09feffffffffaaab, 0x0abfffeb153ffffb, 0xd2a0f6b0f6241e, 0x04b84f38512bf673, 0x07b6434bacd76477, 0x0ea397fe69a4b1ba, 0x1a0111, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x09feffffffffaaab, 0x0abfffeb153ffffb, 0xd2a0f6b0f6241e, 0x04b84f38512bf673, 0x07b6434bacd76477, 0x0ea397fe69a4b1ba, 0x1a0111, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x5c59e8163c701ec4f881fd59646e8b, 0x9d07fda82a52f7d1dc780a19de74e6, 0xbcf32791738a0406c331e9ae8a46e0, 0x02760d74 - ] + }, + redc_param: [ + 0x5c59e8163c701ec4f881fd59646e8b, + 0x9d07fda82a52f7d1dc780a19de74e6, + 0xbcf32791738a0406c331e9ae8a46e0, + 0x02760d74, + ], }; diff --git a/src/fields/bls12_381Fr.nr b/src/fields/bls12_381Fr.nr index 913b38a7..2635d62b 100644 --- a/src/fields/bls12_381Fr.nr +++ b/src/fields/bls12_381Fr.nr @@ -14,36 +14,51 @@ //! * valuation(r - 1, 2) = 32 //! * G1 curve equation: y^2 = x^3 + 4 //! * G2 curve equation: y^2 = x^3 + Fq2(4, 4) -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct BLS12_381_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for BLS12_381_Fr_Params { - fn modulus_bits() -> u32 { - 255 + +impl BigNumParamsGetter<3, 255> for BLS12_381_Fr_Params { + fn get_params() -> BigNumParams<3, 255> { + BLS12_381_Fr_PARAMS } } -impl BigNumParamsTrait<3> for BLS12_381_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - BLS12_381_Fr_Instance - } - fn modulus_bits() -> u32 { - 255 - } -} -pub global BLS12_381_Fr_Instance: BigNumInstance<3, BLS12_381_Fr_Params> = BigNumInstance { - modulus: [ - 0xbda402fffe5bfeffffffff00000001, 0xa753299d7d483339d80809a1d80553, 0x73ed + +global BLS12_381_Fr_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xbda402fffe5bfeffffffff00000001, 0xa753299d7d483339d80809a1d80553, 0x73ed], + double_modulus: [ + 0x017b4805fffcb7fdfffffffe00000002, + 0x014ea6533afa906673b0101343b00aa6, + 0xe7da, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0fffffff00000001, + 0x0bda402fffe5bfef, + 0x09d80809a1d80553, + 0x0a753299d7d48333, + 0x73ed, + 0x00, ], - double_modulus: [ - 0x017b4805fffcb7fdfffffffe00000002, 0x014ea6533afa906673b0101343b00aa6, 0xe7da + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0fffffff00000001, + 0x0bda402fffe5bfef, + 0x09d80809a1d80553, + 0x0a753299d7d48333, + 0x73ed, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0fffffff00000001, 0x0bda402fffe5bfef, 0x09d80809a1d80553, 0x0a753299d7d48333, 0x73ed, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0fffffff00000001, 0x0bda402fffe5bfef, 0x09d80809a1d80553, 0x0a753299d7d48333, 0x73ed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x10fad2f92eb5c509cde80830358e4c, 0x53b7fb78ddf0e2d772dc1f823b4d94, 0x08d542 - ] + }, + redc_param: [0x10fad2f92eb5c509cde80830358e4c, 0x53b7fb78ddf0e2d772dc1f823b4d94, 0x08d542], }; diff --git a/src/fields/bn254Fq.nr b/src/fields/bn254Fq.nr index c29850aa..d1fd56e9 100644 --- a/src/fields/bn254Fq.nr +++ b/src/fields/bn254Fq.nr @@ -1,33 +1,48 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; -pub struct BNParams {} -impl RuntimeBigNumParamsTrait<3> for BNParams { - fn modulus_bits() -> u32 { - 254 + +pub struct BN254_Fq_Params {} + +impl BigNumParamsGetter<3, 254> for BN254_Fq_Params { + fn get_params() -> BigNumParams<3, 254> { + BN254_Fq_PARAMS } } -impl BigNumParamsTrait<3> for BNParams { - fn get_instance() -> BigNumInstance<3, Self> { - BN254INSTANCE - } - fn modulus_bits() -> u32 { - 254 - } -} -pub global BN254INSTANCE: BigNumInstance<3, BNParams> = BigNumInstance { - modulus: [ - 0x816a916871ca8d3c208c16d87cfd47, 0x4e72e131a029b85045b68181585d97, 0x3064 + +global BN254_Fq_PARAMS: BigNumParams<3, 254> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0x816a916871ca8d3c208c16d87cfd47, 0x4e72e131a029b85045b68181585d97, 0x3064], + double_modulus: [ + 0x0102d522d0e3951a7841182db0f9fa8e, + 0x019ce5c263405370a08b6d0302b0bb2e, + 0x60c7, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0c208c16d87cfd47, + 0x0816a916871ca8d3, + 0x45b68181585d97, + 0x04e72e131a029b85, + 0x3064, + 0x00, ], - double_modulus: [ - 0x0102d522d0e3951a7841182db0f9fa8e, 0x019ce5c263405370a08b6d0302b0bb2e, 0x60c7 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0c208c16d87cfd47, + 0x0816a916871ca8d3, + 0x45b68181585d97, + 0x04e72e131a029b85, + 0x3064, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0c208c16d87cfd47, 0x0816a916871ca8d3, 0x45b68181585d97, 0x04e72e131a029b85, 0x3064, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0c208c16d87cfd47, 0x0816a916871ca8d3, 0x45b68181585d97, 0x04e72e131a029b85, 0x3064, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x65e1767cd4c086f3aed8a19bf90e51, 0x462623a04a7ab074a5868073013ae9, 0x054a47 - ] + }, + redc_param: [0x65e1767cd4c086f3aed8a19bf90e51, 0x462623a04a7ab074a5868073013ae9, 0x054a47], }; diff --git a/src/fields/ed25519Fq.nr b/src/fields/ed25519Fq.nr index c391af79..0a19b9a0 100644 --- a/src/fields/ed25519Fq.nr +++ b/src/fields/ed25519Fq.nr @@ -1,33 +1,48 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct ED25519_Fq_Params {} -impl RuntimeBigNumParamsTrait<3> for ED25519_Fq_Params { - fn modulus_bits() -> u32 { - 255 + +impl BigNumParamsGetter<3, 255> for ED25519_Fq_Params { + fn get_params() -> BigNumParams<3, 255> { + ED25519_Fq_PARAMS } } -impl BigNumParamsTrait<3> for ED25519_Fq_Params { - fn get_instance() -> BigNumInstance<3, Self> { - ED25519_Fq_Instance - } - fn modulus_bits() -> u32 { - 255 - } -} -pub global ED25519_Fq_Instance: BigNumInstance<3, ED25519_Fq_Params> = BigNumInstance { - modulus: [ - 0xffffffffffffffffffffffffffffed, 0xffffffffffffffffffffffffffffff, 0x7fff + +global ED25519_Fq_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xffffffffffffffffffffffffffffed, 0xffffffffffffffffffffffffffffff, 0x7fff], + double_modulus: [ + 0x01ffffffffffffffffffffffffffffda, + 0x01fffffffffffffffffffffffffffffe, + 0xfffe, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0fffffffffffffed, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x7fff, + 0x00, ], - double_modulus: [ - 0x01ffffffffffffffffffffffffffffda, 0x01fffffffffffffffffffffffffffffe, 0xfffe + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0fffffffffffffed, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x7fff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0fffffffffffffed, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x7fff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0fffffffffffffed, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x7fff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x0130, 0x00, 0x080000 - ] + }, + redc_param: [0x0130, 0x00, 0x080000], }; diff --git a/src/fields/ed25519Fr.nr b/src/fields/ed25519Fr.nr index 2bb1cbd6..cdc2005f 100644 --- a/src/fields/ed25519Fr.nr +++ b/src/fields/ed25519Fr.nr @@ -1,33 +1,41 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct ED25519_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for ED25519_Fr_Params { - fn modulus_bits() -> u32 { - 253 + +impl BigNumParamsGetter<3, 255> for ED25519_Fr_Params { + fn get_params() -> BigNumParams<3, 255> { + ED25519_Fr_PARAMS } } -impl BigNumParamsTrait<3> for ED25519_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - ED25519_Fr_Instance - } - fn modulus_bits() -> u32 { - 253 - } -} -pub global ED25519_Fr_Instance: BigNumInstance<3, ED25519_Fr_Params> = BigNumInstance { - modulus: [ - 0xdef9dea2f79cd65812631a5cf5d3ed, 0x14, 0x1000 - ], - double_modulus: [ - 0x01bdf3bd45ef39acb024c634b9eba7da, 0x01000000000000000000000000000028, 0x1fff + +global ED25519_Fr_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xdef9dea2f79cd65812631a5cf5d3ed, 0x14, 0x1000], + double_modulus: [ + 0x01bdf3bd45ef39acb024c634b9eba7da, + 0x01000000000000000000000000000028, + 0x1fff, + ], + modulus_u60: U60Repr { + limbs: [0x0812631a5cf5d3ed, 0x0def9dea2f79cd65, 0x14, 0x00, 0x1000, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0812631a5cf5d3ed, + 0x0def9dea2f79cd65, + 0x14, + 0x00, + 0x1000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0812631a5cf5d3ed, 0x0def9dea2f79cd65, 0x14, 0x00, 0x1000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0812631a5cf5d3ed, 0x0def9dea2f79cd65, 0x14, 0x00, 0x1000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x4188574218ca69fb673968c28b04c6, 0xfffffffffffffffffffffffffffac8, 0x03ffff - ] + }, + redc_param: [0x4188574218ca69fb673968c28b04c6, 0xfffffffffffffffffffffffffffac8, 0x03ffff], }; diff --git a/src/fields/mnt4_753Fq.nr b/src/fields/mnt4_753Fq.nr index e0a85991..849a7532 100644 --- a/src/fields/mnt4_753Fq.nr +++ b/src/fields/mnt4_753Fq.nr @@ -19,36 +19,95 @@ //! * B = Fq2(0, b * NON_RESIDUE) //! * NON_RESIDUE = 13 is the quadratic non-residue used to conpub struct the //! extension field Fq2 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct MNT4_753_Fq_Params {} -impl RuntimeBigNumParamsTrait<7> for MNT4_753_Fq_Params { - fn modulus_bits() -> u32 { - 753 + +impl BigNumParamsGetter<7, 753> for MNT4_753_Fq_Params { + fn get_params() -> BigNumParams<7, 753> { + MNT4_753_Fq_PARAMS } } -impl BigNumParamsTrait<7> for MNT4_753_Fq_Params { - fn get_instance() -> BigNumInstance<7, Self> { - MNT4_753_Fq_Instance - } - fn modulus_bits() -> u32 { - 753 - } -} -pub global MNT4_753_Fq_Instance: BigNumInstance<7, MNT4_753_Fq_Params> = BigNumInstance { - modulus: [ - 0x9d54522cdd119f5e9063de245e8001, 0xcce9767254a4638810719ac425f0e3, 0x76f218059db80f0da5cb537e38685a, 0xe8a0ed8d99d124d9a15af79db117e7, 0x8fafed5eb7e8f96c97d87307fdb925, 0xc41110229022eee2cdadb7f997505b, 0x01c4c62d92 + +global MNT4_753_Fq_PARAMS: BigNumParams<7, 753> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0x9d54522cdd119f5e9063de245e8001, + 0xcce9767254a4638810719ac425f0e3, + 0x76f218059db80f0da5cb537e38685a, + 0xe8a0ed8d99d124d9a15af79db117e7, + 0x8fafed5eb7e8f96c97d87307fdb925, + 0xc41110229022eee2cdadb7f997505b, + 0x01c4c62d92, + ], + double_modulus: [ + 0x013aa8a459ba233ebd20c7bc48bd0002, + 0x0199d2ece4a948c71020e335884be1c6, + 0x01ede4300b3b701e1b4b96a6fc70d0b4, + 0x01d141db1b33a249b342b5ef3b622fcd, + 0x011f5fdabd6fd1f2d92fb0e60ffb724a, + 0x01882220452045ddc59b5b6ff32ea0b6, + 0x03898c5b24, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0e9063de245e8001, + 0x09d54522cdd119f5, + 0x0810719ac425f0e3, + 0x0cce9767254a4638, + 0x0da5cb537e38685a, + 0x076f218059db80f0, + 0x09a15af79db117e7, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, ], - double_modulus: [ - 0x013aa8a459ba233ebd20c7bc48bd0002, 0x0199d2ece4a948c71020e335884be1c6, 0x01ede4300b3b701e1b4b96a6fc70d0b4, 0x01d141db1b33a249b342b5ef3b622fcd, 0x011f5fdabd6fd1f2d92fb0e60ffb724a, 0x01882220452045ddc59b5b6ff32ea0b6, 0x03898c5b24 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0e9063de245e8001, + 0x09d54522cdd119f5, + 0x0810719ac425f0e3, + 0x0cce9767254a4638, + 0x0da5cb537e38685a, + 0x076f218059db80f0, + 0x09a15af79db117e7, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0e9063de245e8001, 0x09d54522cdd119f5, 0x0810719ac425f0e3, 0x0cce9767254a4638, 0x0da5cb537e38685a, 0x076f218059db80f0, 0x09a15af79db117e7, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0e9063de245e8001, 0x09d54522cdd119f5, 0x0810719ac425f0e3, 0x0cce9767254a4638, 0x0da5cb537e38685a, 0x076f218059db80f0, 0x09a15af79db117e7, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x5dcc95da918349f4965a2aee8fd750, 0x82372b75580c27c4d1f1f57a96a114, 0x58326e3c0552419849e3c7171d8522, 0x300e0ede1965cbf72f0aa9bf03479d, 0x7fb932cae2aba9a5d17c1ff73538ba, 0x82727c6eaef38056aaa0aaedb05746, 0x242f916cfa - ] + }, + redc_param: [ + 0x5dcc95da918349f4965a2aee8fd750, + 0x82372b75580c27c4d1f1f57a96a114, + 0x58326e3c0552419849e3c7171d8522, + 0x300e0ede1965cbf72f0aa9bf03479d, + 0x7fb932cae2aba9a5d17c1ff73538ba, + 0x82727c6eaef38056aaa0aaedb05746, + 0x242f916cfa, + ], }; diff --git a/src/fields/mnt4_753Fr.nr b/src/fields/mnt4_753Fr.nr index 033fb4dc..21982f9f 100644 --- a/src/fields/mnt4_753Fr.nr +++ b/src/fields/mnt4_753Fr.nr @@ -19,36 +19,95 @@ //! * B = Fq2(0, b * NON_RESIDUE) //! * NON_RESIDUE = 13 is the quadratic non-residue used to conpub struct the //! extension field Fq2 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct MNT4_753_Fr_Params {} -impl RuntimeBigNumParamsTrait<7> for MNT4_753_Fr_Params { - fn modulus_bits() -> u32 { - 753 + +impl BigNumParamsGetter<7, 753> for MNT4_753_Fr_Params { + fn get_params() -> BigNumParams<7, 753> { + MNT4_753_Fr_PARAMS } } -impl BigNumParamsTrait<7> for MNT4_753_Fr_Params { - fn get_instance() -> BigNumInstance<7, Self> { - MNT4_753_Fr_Instance - } - fn modulus_bits() -> u32 { - 753 - } -} -pub global MNT4_753_Fr_Instance: BigNumInstance<7, MNT4_753_Fr_Params> = BigNumInstance { - modulus: [ - 0xa099170fa13a4fd90776e240000001, 0xf97634993aa4d6c381bc3f0057974e, 0x28c859a99b3eebca9429212636b9df, 0xe8a0ed8d99d124d9a15af79db26c5c, 0x8fafed5eb7e8f96c97d87307fdb925, 0xc41110229022eee2cdadb7f997505b, 0x01c4c62d92 + +global MNT4_753_Fr_PARAMS: BigNumParams<7, 753> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0xa099170fa13a4fd90776e240000001, + 0xf97634993aa4d6c381bc3f0057974e, + 0x28c859a99b3eebca9429212636b9df, + 0xe8a0ed8d99d124d9a15af79db26c5c, + 0x8fafed5eb7e8f96c97d87307fdb925, + 0xc41110229022eee2cdadb7f997505b, + 0x01c4c62d92, + ], + double_modulus: [ + 0x0141322e1f42749fb20eedc480000002, + 0x01f2ec69327549ad8703787e00af2e9c, + 0x015190b353367dd7952852424c6d73be, + 0x01d141db1b33a249b342b5ef3b64d8b7, + 0x011f5fdabd6fd1f2d92fb0e60ffb724a, + 0x01882220452045ddc59b5b6ff32ea0b6, + 0x03898c5b24, + ], + modulus_u60: U60Repr { + limbs: [ + 0x090776e240000001, + 0x0a099170fa13a4fd, + 0x0381bc3f0057974e, + 0x0f97634993aa4d6c, + 0x0a9429212636b9df, + 0x028c859a99b3eebc, + 0x09a15af79db26c5c, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, ], - double_modulus: [ - 0x0141322e1f42749fb20eedc480000002, 0x01f2ec69327549ad8703787e00af2e9c, 0x015190b353367dd7952852424c6d73be, 0x01d141db1b33a249b342b5ef3b64d8b7, 0x011f5fdabd6fd1f2d92fb0e60ffb724a, 0x01882220452045ddc59b5b6ff32ea0b6, 0x03898c5b24 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x090776e240000001, + 0x0a099170fa13a4fd, + 0x0381bc3f0057974e, + 0x0f97634993aa4d6c, + 0x0a9429212636b9df, + 0x028c859a99b3eebc, + 0x09a15af79db26c5c, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x090776e240000001, 0x0a099170fa13a4fd, 0x0381bc3f0057974e, 0x0f97634993aa4d6c, 0x0a9429212636b9df, 0x028c859a99b3eebc, 0x09a15af79db26c5c, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x090776e240000001, 0x0a099170fa13a4fd, 0x0381bc3f0057974e, 0x0f97634993aa4d6c, 0x0a9429212636b9df, 0x028c859a99b3eebc, 0x09a15af79db26c5c, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x2dae11d15867718ec70f5ff059bba2, 0x76d65fe7e00ba391da260f2623ff9a, 0x140a086edaa60c58eb476bdedcb352, 0x300e0ede1965cbf72f0aa9bee81208, 0x7fb932cae2aba9a5d17c1ff73538ba, 0x82727c6eaef38056aaa0aaedb05746, 0x242f916cfa - ] + }, + redc_param: [ + 0x2dae11d15867718ec70f5ff059bba2, + 0x76d65fe7e00ba391da260f2623ff9a, + 0x140a086edaa60c58eb476bdedcb352, + 0x300e0ede1965cbf72f0aa9bee81208, + 0x7fb932cae2aba9a5d17c1ff73538ba, + 0x82727c6eaef38056aaa0aaedb05746, + 0x242f916cfa, + ], }; diff --git a/src/fields/mnt6_753Fq.nr b/src/fields/mnt6_753Fq.nr index 41ede6e4..421a36b4 100644 --- a/src/fields/mnt6_753Fq.nr +++ b/src/fields/mnt6_753Fq.nr @@ -19,36 +19,95 @@ //! * B = Fq3(b * NON_RESIDUE, 0, 0) //! * NON_RESIDUE = 11 is the cubic non-residue used to conpub struct the //! extension field Fq3 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct MNT6_753_Fq_Params {} -impl RuntimeBigNumParamsTrait<7> for MNT6_753_Fq_Params { - fn modulus_bits() -> u32 { - 753 + +impl BigNumParamsGetter<7, 753> for MNT6_753_Fq_Params { + fn get_params() -> BigNumParams<7, 753> { + MNT6_753_Fq_PARAMS } } -impl BigNumParamsTrait<7> for MNT6_753_Fq_Params { - fn get_instance() -> BigNumInstance<7, Self> { - MNT6_753_Fq_Instance - } - fn modulus_bits() -> u32 { - 753 - } -} -pub global MNT6_753_Fq_Instance: BigNumInstance<7, MNT6_753_Fq_Params> = BigNumInstance { - modulus: [ - 0xa099170fa13a4fd90776e240000001, 0xf97634993aa4d6c381bc3f0057974e, 0x28c859a99b3eebca9429212636b9df, 0xe8a0ed8d99d124d9a15af79db26c5c, 0x8fafed5eb7e8f96c97d87307fdb925, 0xc41110229022eee2cdadb7f997505b, 0x01c4c62d92 + +global MNT6_753_Fq_PARAMS: BigNumParams<7, 753> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0xa099170fa13a4fd90776e240000001, + 0xf97634993aa4d6c381bc3f0057974e, + 0x28c859a99b3eebca9429212636b9df, + 0xe8a0ed8d99d124d9a15af79db26c5c, + 0x8fafed5eb7e8f96c97d87307fdb925, + 0xc41110229022eee2cdadb7f997505b, + 0x01c4c62d92, + ], + double_modulus: [ + 0x0141322e1f42749fb20eedc480000002, + 0x01f2ec69327549ad8703787e00af2e9c, + 0x015190b353367dd7952852424c6d73be, + 0x01d141db1b33a249b342b5ef3b64d8b7, + 0x011f5fdabd6fd1f2d92fb0e60ffb724a, + 0x01882220452045ddc59b5b6ff32ea0b6, + 0x03898c5b24, + ], + modulus_u60: U60Repr { + limbs: [ + 0x090776e240000001, + 0x0a099170fa13a4fd, + 0x0381bc3f0057974e, + 0x0f97634993aa4d6c, + 0x0a9429212636b9df, + 0x028c859a99b3eebc, + 0x09a15af79db26c5c, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, ], - double_modulus: [ - 0x0141322e1f42749fb20eedc480000002, 0x01f2ec69327549ad8703787e00af2e9c, 0x015190b353367dd7952852424c6d73be, 0x01d141db1b33a249b342b5ef3b64d8b7, 0x011f5fdabd6fd1f2d92fb0e60ffb724a, 0x01882220452045ddc59b5b6ff32ea0b6, 0x03898c5b24 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x090776e240000001, + 0x0a099170fa13a4fd, + 0x0381bc3f0057974e, + 0x0f97634993aa4d6c, + 0x0a9429212636b9df, + 0x028c859a99b3eebc, + 0x09a15af79db26c5c, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x090776e240000001, 0x0a099170fa13a4fd, 0x0381bc3f0057974e, 0x0f97634993aa4d6c, 0x0a9429212636b9df, 0x028c859a99b3eebc, 0x09a15af79db26c5c, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x090776e240000001, 0x0a099170fa13a4fd, 0x0381bc3f0057974e, 0x0f97634993aa4d6c, 0x0a9429212636b9df, 0x028c859a99b3eebc, 0x09a15af79db26c5c, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x2dae11d15867718ec70f5ff059bba2, 0x76d65fe7e00ba391da260f2623ff9a, 0x140a086edaa60c58eb476bdedcb352, 0x300e0ede1965cbf72f0aa9bee81208, 0x7fb932cae2aba9a5d17c1ff73538ba, 0x82727c6eaef38056aaa0aaedb05746, 0x242f916cfa - ] + }, + redc_param: [ + 0x2dae11d15867718ec70f5ff059bba2, + 0x76d65fe7e00ba391da260f2623ff9a, + 0x140a086edaa60c58eb476bdedcb352, + 0x300e0ede1965cbf72f0aa9bee81208, + 0x7fb932cae2aba9a5d17c1ff73538ba, + 0x82727c6eaef38056aaa0aaedb05746, + 0x242f916cfa, + ], }; diff --git a/src/fields/mnt6_753Fr.nr b/src/fields/mnt6_753Fr.nr index 9d67e421..24110720 100644 --- a/src/fields/mnt6_753Fr.nr +++ b/src/fields/mnt6_753Fr.nr @@ -19,36 +19,95 @@ //! * B = Fq3(b * NON_RESIDUE, 0, 0) //! * NON_RESIDUE = 11 is the cubic non-residue used to conpub struct the //! extension field Fq3 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct MNT6_753_Fr_Params {} -impl RuntimeBigNumParamsTrait<7> for MNT6_753_Fr_Params { - fn modulus_bits() -> u32 { - 753 + +impl BigNumParamsGetter<7, 753> for MNT6_753_Fr_Params { + fn get_params() -> BigNumParams<7, 753> { + MNT6_753_Fr_PARAMS } } -impl BigNumParamsTrait<7> for MNT6_753_Fr_Params { - fn get_instance() -> BigNumInstance<7, Self> { - MNT6_753_Fr_Instance - } - fn modulus_bits() -> u32 { - 753 - } -} -pub global MNT6_753_Fr_Instance: BigNumInstance<7, MNT6_753_Fr_Params> = BigNumInstance { - modulus: [ - 0x9d54522cdd119f5e9063de245e8001, 0xcce9767254a4638810719ac425f0e3, 0x76f218059db80f0da5cb537e38685a, 0xe8a0ed8d99d124d9a15af79db117e7, 0x8fafed5eb7e8f96c97d87307fdb925, 0xc41110229022eee2cdadb7f997505b, 0x01c4c62d92 + +global MNT6_753_Fr_PARAMS: BigNumParams<7, 753> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0x9d54522cdd119f5e9063de245e8001, + 0xcce9767254a4638810719ac425f0e3, + 0x76f218059db80f0da5cb537e38685a, + 0xe8a0ed8d99d124d9a15af79db117e7, + 0x8fafed5eb7e8f96c97d87307fdb925, + 0xc41110229022eee2cdadb7f997505b, + 0x01c4c62d92, + ], + double_modulus: [ + 0x013aa8a459ba233ebd20c7bc48bd0002, + 0x0199d2ece4a948c71020e335884be1c6, + 0x01ede4300b3b701e1b4b96a6fc70d0b4, + 0x01d141db1b33a249b342b5ef3b622fcd, + 0x011f5fdabd6fd1f2d92fb0e60ffb724a, + 0x01882220452045ddc59b5b6ff32ea0b6, + 0x03898c5b24, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0e9063de245e8001, + 0x09d54522cdd119f5, + 0x0810719ac425f0e3, + 0x0cce9767254a4638, + 0x0da5cb537e38685a, + 0x076f218059db80f0, + 0x09a15af79db117e7, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, ], - double_modulus: [ - 0x013aa8a459ba233ebd20c7bc48bd0002, 0x0199d2ece4a948c71020e335884be1c6, 0x01ede4300b3b701e1b4b96a6fc70d0b4, 0x01d141db1b33a249b342b5ef3b622fcd, 0x011f5fdabd6fd1f2d92fb0e60ffb724a, 0x01882220452045ddc59b5b6ff32ea0b6, 0x03898c5b24 + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0e9063de245e8001, + 0x09d54522cdd119f5, + 0x0810719ac425f0e3, + 0x0cce9767254a4638, + 0x0da5cb537e38685a, + 0x076f218059db80f0, + 0x09a15af79db117e7, + 0x0e8a0ed8d99d124d, + 0x0c97d87307fdb925, + 0x08fafed5eb7e8f96, + 0x02cdadb7f997505b, + 0x0c41110229022eee, + 0x01c4c62d92, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0e9063de245e8001, 0x09d54522cdd119f5, 0x0810719ac425f0e3, 0x0cce9767254a4638, 0x0da5cb537e38685a, 0x076f218059db80f0, 0x09a15af79db117e7, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0e9063de245e8001, 0x09d54522cdd119f5, 0x0810719ac425f0e3, 0x0cce9767254a4638, 0x0da5cb537e38685a, 0x076f218059db80f0, 0x09a15af79db117e7, 0x0e8a0ed8d99d124d, 0x0c97d87307fdb925, 0x08fafed5eb7e8f96, 0x02cdadb7f997505b, 0x0c41110229022eee, 0x01c4c62d92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x5dcc95da918349f4965a2aee8fd750, 0x82372b75580c27c4d1f1f57a96a114, 0x58326e3c0552419849e3c7171d8522, 0x300e0ede1965cbf72f0aa9bf03479d, 0x7fb932cae2aba9a5d17c1ff73538ba, 0x82727c6eaef38056aaa0aaedb05746, 0x242f916cfa - ] + }, + redc_param: [ + 0x5dcc95da918349f4965a2aee8fd750, + 0x82372b75580c27c4d1f1f57a96a114, + 0x58326e3c0552419849e3c7171d8522, + 0x300e0ede1965cbf72f0aa9bf03479d, + 0x7fb932cae2aba9a5d17c1ff73538ba, + 0x82727c6eaef38056aaa0aaedb05746, + 0x242f916cfa, + ], }; diff --git a/src/fields/mod.nr b/src/fields/mod.nr index db44ec3d..ef20e94e 100644 --- a/src/fields/mod.nr +++ b/src/fields/mod.nr @@ -28,42 +28,10 @@ pub mod U2048; pub mod U4096; pub mod U8192; -pub use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +// example typedef when using a defined bignum instance: +// +// use crate::bignum::BigNum; +// use bn254Fq::BN254_Fq_Params; +// +// type Fq = BigNum<3, 254, BN254_Fq_Params>; -/** - * @brief Parameter definitions for generic fields of varying bit lengths - * (these can be used when defining modular fields where the - * modulus is a witness value and cannot be predefined - * e.g. 2048-bit RSA) - **/ -pub struct Params512 {} -impl RuntimeBigNumParamsTrait<5> for Params512 { - fn modulus_bits() -> u32 { - 512 - } -} -pub struct Params768 {} -impl RuntimeBigNumParamsTrait<7> for Params768 { - fn modulus_bits() -> u32 { - 768 - } -} -pub struct Params1024 {} -impl RuntimeBigNumParamsTrait<9> for Params1024 { - fn modulus_bits() -> u32 { - 1024 - } -} -pub struct Params2048 {} -impl RuntimeBigNumParamsTrait<18> for Params2048 { - fn modulus_bits() -> u32 { - 2048 - } -} -pub struct Params4096 {} -impl RuntimeBigNumParamsTrait<35> for Params4096 { - fn modulus_bits() -> u32 { - 4096 - } -} diff --git a/src/fields/pallasFq.nr b/src/fields/pallasFq.nr index 99d7cb72..a5f6a1a8 100644 --- a/src/fields/pallasFq.nr +++ b/src/fields/pallasFq.nr @@ -13,36 +13,44 @@ //! * Curve equation: y^2 = x^3 + 5 //! * Valuation(q - 1, 2) = 32 //! * Valuation(r - 1, 2) = 32 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Pallas_Fq_Params {} -impl RuntimeBigNumParamsTrait<3> for Pallas_Fq_Params { - fn modulus_bits() -> u32 { - 255 + +impl BigNumParamsGetter<3, 255> for Pallas_Fq_Params { + fn get_params() -> BigNumParams<3, 255> { + Pallas_Fq_PARAMS } } -impl BigNumParamsTrait<3> for Pallas_Fq_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Pallas_Fq_Instance - } - fn modulus_bits() -> u32 { - 255 - } -} -pub global Pallas_Fq_Instance: BigNumInstance<3, Pallas_Fq_Params> = BigNumInstance { - modulus: [ - 0x4698fc094cf91b992d30ed00000001, 0x22, 0x4000 - ], - double_modulus: [ - 0x018d31f81299f237325a61da00000002, 0x01000000000000000000000000000043, 0x7fff + +global Pallas_Fq_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0x4698fc094cf91b992d30ed00000001, 0x22, 0x4000], + double_modulus: [ + 0x018d31f81299f237325a61da00000002, + 0x01000000000000000000000000000043, + 0x7fff, + ], + modulus_u60: U60Repr { + limbs: [0x092d30ed00000001, 0x04698fc094cf91b9, 0x22, 0x00, 0x4000, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x092d30ed00000001, + 0x04698fc094cf91b9, + 0x22, + 0x00, + 0x4000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x092d30ed00000001, 0x04698fc094cf91b9, 0x22, 0x00, 0x4000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x092d30ed00000001, 0x04698fc094cf91b9, 0x22, 0x00, 0x4000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x59c0fdacc1b919b4b3c4bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff - ] + }, + redc_param: [0x59c0fdacc1b919b4b3c4bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff], }; diff --git a/src/fields/pallasFr.nr b/src/fields/pallasFr.nr index 36ff966e..502b0da2 100644 --- a/src/fields/pallasFr.nr +++ b/src/fields/pallasFr.nr @@ -13,36 +13,44 @@ //! * Curve equation: y^2 = x^3 + 5 //! * Valuation(q - 1, 2) = 32 //! * Valuation(r - 1, 2) = 32 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Pallas_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for Pallas_Fr_Params { - fn modulus_bits() -> u32 { - 255 + +impl BigNumParamsGetter<3, 255> for Pallas_Fr_Params { + fn get_params() -> BigNumParams<3, 255> { + Pallas_Fr_PARAMS } } -impl BigNumParamsTrait<3> for Pallas_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Pallas_Fr_Instance - } - fn modulus_bits() -> u32 { - 255 - } -} -pub global Pallas_Fr_Instance: BigNumInstance<3, Pallas_Fr_Params> = BigNumInstance { - modulus: [ - 0x4698fc0994a8dd8c46eb2100000001, 0x22, 0x4000 - ], - double_modulus: [ - 0x018d31f8132951bb188dd64200000002, 0x01000000000000000000000000000043, 0x7fff + +global Pallas_Fr_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0x4698fc0994a8dd8c46eb2100000001, 0x22, 0x4000], + double_modulus: [ + 0x018d31f8132951bb188dd64200000002, + 0x01000000000000000000000000000043, + 0x7fff, + ], + modulus_u60: U60Repr { + limbs: [0x0c46eb2100000001, 0x04698fc0994a8dd8, 0x22, 0x00, 0x4000, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0c46eb2100000001, + 0x04698fc0994a8dd8, + 0x22, + 0x00, + 0x4000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0c46eb2100000001, 0x04698fc0994a8dd8, 0x22, 0x00, 0x4000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0c46eb2100000001, 0x04698fc0994a8dd8, 0x22, 0x00, 0x4000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x59c0fd9ad5c89cee4537bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff - ] + }, + redc_param: [0x59c0fd9ad5c89cee4537bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff], }; diff --git a/src/fields/secp256k1Fq.nr b/src/fields/secp256k1Fq.nr index 1bfdc16b..463ea901 100644 --- a/src/fields/secp256k1Fq.nr +++ b/src/fields/secp256k1Fq.nr @@ -1,33 +1,48 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Secp256k1_Fq_Params {} -impl RuntimeBigNumParamsTrait<3> for Secp256k1_Fq_Params { - fn modulus_bits() -> u32 { - 256 + +impl BigNumParamsGetter<3, 256> for Secp256k1_Fq_Params { + fn get_params() -> BigNumParams<3, 256> { + Secp256k1_Fq_PARAMS } } -impl BigNumParamsTrait<3> for Secp256k1_Fq_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Secp256k1_Fq_Instance - } - fn modulus_bits() -> u32 { - 256 - } -} -pub global Secp256k1_Fq_Instance: BigNumInstance<3, Secp256k1_Fq_Params> = BigNumInstance { - modulus: [ - 0xfffffffffffffffffffffefffffc2f, 0xffffffffffffffffffffffffffffff, 0xffff + +global Secp256k1_Fq_PARAMS: BigNumParams<3, 256> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xfffffffffffffffffffffefffffc2f, 0xffffffffffffffffffffffffffffff, 0xffff], + double_modulus: [ + 0x01fffffffffffffffffffffdfffff85e, + 0x01fffffffffffffffffffffffffffffe, + 0x01fffe, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0ffffffefffffc2f, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0xffff, + 0x00, ], - double_modulus: [ - 0x01fffffffffffffffffffffdfffff85e, 0x01fffffffffffffffffffffffffffffe, 0x01fffe + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0ffffffefffffc2f, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0xffff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0ffffffefffffc2f, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0xffff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0ffffffefffffc2f, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x1000003d10, 0x00, 0x100000 - ] + }, + redc_param: [0x1000003d10, 0x00, 0x100000], }; diff --git a/src/fields/secp256k1Fr.nr b/src/fields/secp256k1Fr.nr index 28608299..9b137928 100644 --- a/src/fields/secp256k1Fr.nr +++ b/src/fields/secp256k1Fr.nr @@ -1,33 +1,48 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Secp256k1_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for Secp256k1_Fr_Params { - fn modulus_bits() -> u32 { - 256 + +impl BigNumParamsGetter<3, 256> for Secp256k1_Fr_Params { + fn get_params() -> BigNumParams<3, 256> { + Secp256k1_Fr_PARAMS } } -impl BigNumParamsTrait<3> for Secp256k1_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Secp256k1_Fr_Instance - } - fn modulus_bits() -> u32 { - 256 - } -} -pub global Secp256k1_Fr_Instance: BigNumInstance<3, Secp256k1_Fr_Params> = BigNumInstance { - modulus: [ - 0xaedce6af48a03bbfd25e8cd0364141, 0xfffffffffffffffffffffffffffeba, 0xffff + +global Secp256k1_Fr_PARAMS: BigNumParams<3, 256> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xaedce6af48a03bbfd25e8cd0364141, 0xfffffffffffffffffffffffffffeba, 0xffff], + double_modulus: [ + 0x015db9cd5e9140777fa4bd19a06c8282, + 0x01fffffffffffffffffffffffffffd74, + 0x01fffe, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0fd25e8cd0364141, + 0x0aedce6af48a03bb, + 0x0ffffffffffffeba, + 0x0fffffffffffffff, + 0xffff, + 0x00, ], - double_modulus: [ - 0x015db9cd5e9140777fa4bd19a06c8282, 0x01fffffffffffffffffffffffffffd74, 0x01fffe + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0fd25e8cd0364141, + 0x0aedce6af48a03bb, + 0x0ffffffffffffeba, + 0x0fffffffffffffff, + 0xffff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0fd25e8cd0364141, 0x0aedce6af48a03bb, 0x0ffffffffffffeba, 0x0fffffffffffffff, 0xffff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0fd25e8cd0364141, 0x0aedce6af48a03bb, 0x0ffffffffffffeba, 0x0fffffffffffffff, 0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x1231950b75fc4402da1732fc9bec09, 0x1455, 0x100000 - ] + }, + redc_param: [0x1231950b75fc4402da1732fc9bec09, 0x1455, 0x100000], }; diff --git a/src/fields/secp256r1Fq.nr b/src/fields/secp256r1Fq.nr index a60a3fd2..4d4ebaee 100644 --- a/src/fields/secp256r1Fq.nr +++ b/src/fields/secp256r1Fq.nr @@ -1,33 +1,41 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Secp256r1_Fq_Params {} -impl RuntimeBigNumParamsTrait<3> for Secp256r1_Fq_Params { - fn modulus_bits() -> u32 { - 256 + +impl BigNumParamsGetter<3, 265> for Secp256r1_Fq_Params { + fn get_params() -> BigNumParams<3, 265> { + Secp256r1_Fq_PARAMS } } -impl BigNumParamsTrait<3> for Secp256r1_Fq_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Secp256r1_Fq_Instance - } - fn modulus_bits() -> u32 { - 256 - } -} -pub global Secp256r1_Fq_Instance: BigNumInstance<3, Secp256r1_Fq_Params> = BigNumInstance { - modulus: [ - 0xffffffffffffffffffffffff, 0xffff00000001000000000000000000, 0xffff - ], - double_modulus: [ - 0x01000001fffffffffffffffffffffffe, 0x01fffe00000001ffffffffffffffffff, 0x01fffe + +global Secp256r1_Fq_PARAMS: BigNumParams<3, 265> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xffffffffffffffffffffffff, 0xffff00000001000000000000000000, 0xffff], + double_modulus: [ + 0x01000001fffffffffffffffffffffffe, + 0x01fffe00000001ffffffffffffffffff, + 0x01fffe, + ], + modulus_u60: U60Repr { + limbs: [0x0fffffffffffffff, 0x0fffffffff, 0x00, 0x0ffff00000001000, 0xffff, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0fffffffffffffff, + 0x0fffffffff, + 0x00, + 0x0ffff00000001000, + 0xffff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0fffffffffffffff, 0x0fffffffff, 0x00, 0x0ffff00000001000, 0xffff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0fffffffffffffff, 0x0fffffffff, 0x00, 0x0ffff00000001000, 0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0xffffeffffffff00000000000000030, 0x0fffffffffffffffefffffffefff, 0x100000 - ] + }, + redc_param: [0xffffeffffffff00000000000000030, 0x0fffffffffffffffefffffffefff, 0x100000], }; diff --git a/src/fields/secp256r1Fr.nr b/src/fields/secp256r1Fr.nr index bce2efd5..8db71855 100644 --- a/src/fields/secp256r1Fr.nr +++ b/src/fields/secp256r1Fr.nr @@ -1,33 +1,48 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Secp256r1_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for Secp256r1_Fr_Params { - fn modulus_bits() -> u32 { - 256 + +impl BigNumParamsGetter<3, 256> for Secp256r1_Fr_Params { + fn get_params() -> BigNumParams<3, 256> { + Secp256r1_Fr_PARAMS } } -impl BigNumParamsTrait<3> for Secp256r1_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Secp256r1_Fr_Instance - } - fn modulus_bits() -> u32 { - 256 - } -} -pub global Secp256r1_Fr_Instance: BigNumInstance<3, Secp256r1_Fr_Params> = BigNumInstance { - modulus: [ - 0xe6faada7179e84f3b9cac2fc632551, 0xffff00000000ffffffffffffffffbc, 0xffff + +global Secp256r1_Fr_PARAMS: BigNumParams<3, 256> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0xe6faada7179e84f3b9cac2fc632551, 0xffff00000000ffffffffffffffffbc, 0xffff], + double_modulus: [ + 0x01cdf55b4e2f3d09e7739585f8c64aa2, + 0x01fffe00000001ffffffffffffffff78, + 0x01fffe, + ], + modulus_u60: U60Repr { + limbs: [ + 0x03b9cac2fc632551, + 0x0e6faada7179e84f, + 0x0fffffffffffffbc, + 0x0ffff00000000fff, + 0xffff, + 0x00, ], - double_modulus: [ - 0x01cdf55b4e2f3d09e7739585f8c64aa2, 0x01fffe00000001ffffffffffffffff78, 0x01fffe + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x03b9cac2fc632551, + 0x0e6faada7179e84f, + 0x0fffffffffffffbc, + 0x0ffff00000000fff, + 0xffff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x03b9cac2fc632551, 0x0e6faada7179e84f, 0x0fffffffffffffbc, 0x0ffff00000000fff, 0xffff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x03b9cac2fc632551, 0x0e6faada7179e84f, 0x0fffffffffffffbc, 0x0ffff00000000fff, 0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x90552df1a6c21012ffd85eedf9bfe6, 0x0fffffffffffffffeffffffff431, 0x100000 - ] + }, + redc_param: [0x90552df1a6c21012ffd85eedf9bfe6, 0x0fffffffffffffffeffffffff431, 0x100000], }; diff --git a/src/fields/secp384r1Fq.nr b/src/fields/secp384r1Fq.nr index 048edb19..599aeec8 100644 --- a/src/fields/secp384r1Fq.nr +++ b/src/fields/secp384r1Fq.nr @@ -1,33 +1,60 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Secp384r1_Fq_Params {} -impl RuntimeBigNumParamsTrait<4> for Secp384r1_Fq_Params { - fn modulus_bits() -> u32 { - 384 + +impl BigNumParamsGetter<4, 384> for Secp384r1_Fq_Params { + fn get_params() -> BigNumParams<4, 384> { + Secp384r1_Fq_PARAMS } } -impl BigNumParamsTrait<4> for Secp384r1_Fq_Params { - fn get_instance() -> BigNumInstance<4, Self> { - Secp384r1_Fq_Instance - } - fn modulus_bits() -> u32 { - 384 - } -} -pub global Secp384r1_Fq_Instance: BigNumInstance<4, Secp384r1_Fq_Params> = BigNumInstance { - modulus: [ - 0xffffff0000000000000000ffffffff, 0xfffffffffffffffffffffffffffeff, 0xffffffffffffffffffffffffffffff, 0xffffff + +global Secp384r1_Fq_PARAMS: BigNumParams<4, 384> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0xffffff0000000000000000ffffffff, + 0xfffffffffffffffffffffffffffeff, + 0xffffffffffffffffffffffffffffff, + 0xffffff, + ], + double_modulus: [ + 0x01fffffe0000000000000001fffffffe, + 0x01fffffffffffffffffffffffffffdfe, + 0x01fffffffffffffffffffffffffffffe, + 0x01fffffe, + ], + modulus_u60: U60Repr { + limbs: [ + 0xffffffff, + 0x0ffffff000000000, + 0x0ffffffffffffeff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0xffffff, + 0x00, ], - double_modulus: [ - 0x01fffffe0000000000000001fffffffe, 0x01fffffffffffffffffffffffffffdfe, 0x01fffffffffffffffffffffffffffffe, 0x01fffffe + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0xffffffff, + 0x0ffffff000000000, + 0x0ffffffffffffeff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0xffffff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0xffffffff, 0x0ffffff000000000, 0x0ffffffffffffeff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0xffffff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0xffffffff, 0x0ffffff000000000, 0x0ffffffffffffeff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0x0fffffffffffffff, 0xffffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x0ffffffffffffffff000000010, 0x1000, 0x00, 0x10000000 - ] + }, + redc_param: [0x0ffffffffffffffff000000010, 0x1000, 0x00, 0x10000000], }; diff --git a/src/fields/secp384r1Fr.nr b/src/fields/secp384r1Fr.nr index cd781b61..6755694e 100644 --- a/src/fields/secp384r1Fr.nr +++ b/src/fields/secp384r1Fr.nr @@ -1,33 +1,60 @@ -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Secp384r1_Fr_Params {} -impl RuntimeBigNumParamsTrait<4> for Secp384r1_Fr_Params { - fn modulus_bits() -> u32 { - 384 + +impl BigNumParamsGetter<4, 384> for Secp384r1_Fr_Params { + fn get_params() -> BigNumParams<4, 384> { + Secp384r1_Fr_PARAMS } } -impl BigNumParamsTrait<4> for Secp384r1_Fr_Params { - fn get_instance() -> BigNumInstance<4, Self> { - Secp384r1_Fr_Instance - } - fn modulus_bits() -> u32 { - 384 - } -} -pub global Secp384r1_Fr_Instance: BigNumInstance<4, Secp384r1_Fr_Params> = BigNumInstance { - modulus: [ - 0x1a0db248b0a77aecec196accc52973, 0xffffffffffffc7634d81f4372ddf58, 0xffffffffffffffffffffffffffffff, 0xffffff + +global Secp384r1_Fr_PARAMS: BigNumParams<4, 384> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [ + 0x1a0db248b0a77aecec196accc52973, + 0xffffffffffffc7634d81f4372ddf58, + 0xffffffffffffffffffffffffffffff, + 0xffffff, + ], + double_modulus: [ + 0x01341b6491614ef5d9d832d5998a52e6, + 0x01ffffffffffff8ec69b03e86e5bbeaf, + 0x01fffffffffffffffffffffffffffffe, + 0x01fffffe, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0cec196accc52973, + 0x01a0db248b0a77ae, + 0x034d81f4372ddf58, + 0x0ffffffffffffc76, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0xffffff, + 0x00, ], - double_modulus: [ - 0x01341b6491614ef5d9d832d5998a52e6, 0x01ffffffffffff8ec69b03e86e5bbeaf, 0x01fffffffffffffffffffffffffffffe, 0x01fffffe + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0cec196accc52973, + 0x01a0db248b0a77ae, + 0x034d81f4372ddf58, + 0x0ffffffffffffc76, + 0x0fffffffffffffff, + 0x0fffffffffffffff, + 0xffffff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0cec196accc52973, 0x01a0db248b0a77ae, 0x034d81f4372ddf58, 0x0ffffffffffffc76, 0x0fffffffffffffff, 0x0fffffffffffffff, 0xffffff, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0cec196accc52973, 0x01a0db248b0a77ae, 0x034d81f4372ddf58, 0x0ffffffffffffc76, 0x0fffffffffffffff, 0x0fffffffffffffff, 0xffffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x5f24db74f58851313e695333ad68d0, 0x0389cb27e0bc8d220a7e, 0x00, 0x10000000 - ] + }, + redc_param: [0x5f24db74f58851313e695333ad68d0, 0x0389cb27e0bc8d220a7e, 0x00, 0x10000000], }; diff --git a/src/fields/vestaFq.nr b/src/fields/vestaFq.nr index 39abb50d..56a309b1 100644 --- a/src/fields/vestaFq.nr +++ b/src/fields/vestaFq.nr @@ -14,36 +14,44 @@ //! * Curve equation: y^2 = x^3 + 5 //! * Valuation(q - 1, 2) = 32 //! * Valuation(r - 1, 2) = 32 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Vesta_Fq_Params {} -impl RuntimeBigNumParamsTrait<3> for Vesta_Fq_Params { - fn modulus_bits() -> u32 { - 255 + +impl BigNumParamsGetter<3, 255> for Vesta_Fq_Params { + fn get_params() -> BigNumParams<3, 255> { + Vesta_Fq_PARAMS } } -impl BigNumParamsTrait<3> for Vesta_Fq_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Vesta_Fq_Instance - } - fn modulus_bits() -> u32 { - 255 - } -} -pub global Vesta_Fq_Instance: BigNumInstance<3, Vesta_Fq_Params> = BigNumInstance { - modulus: [ - 0x4698fc0994a8dd8c46eb2100000001, 0x22, 0x4000 - ], - double_modulus: [ - 0x018d31f8132951bb188dd64200000002, 0x01000000000000000000000000000043, 0x7fff + +global Vesta_Fq_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0x4698fc0994a8dd8c46eb2100000001, 0x22, 0x4000], + double_modulus: [ + 0x018d31f8132951bb188dd64200000002, + 0x01000000000000000000000000000043, + 0x7fff, + ], + modulus_u60: U60Repr { + limbs: [0x0c46eb2100000001, 0x04698fc0994a8dd8, 0x22, 0x00, 0x4000, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0c46eb2100000001, + 0x04698fc0994a8dd8, + 0x22, + 0x00, + 0x4000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x0c46eb2100000001, 0x04698fc0994a8dd8, 0x22, 0x00, 0x4000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x0c46eb2100000001, 0x04698fc0994a8dd8, 0x22, 0x00, 0x4000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x59c0fd9ad5c89cee4537bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff - ] + }, + redc_param: [0x59c0fd9ad5c89cee4537bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff], }; diff --git a/src/fields/vestaFr.nr b/src/fields/vestaFr.nr index b5fccf58..438b2ff3 100644 --- a/src/fields/vestaFr.nr +++ b/src/fields/vestaFr.nr @@ -14,36 +14,44 @@ //! * Curve equation: y^2 = x^3 + 5 //! * Valuation(q - 1, 2) = 32 //! * Valuation(r - 1, 2) = 32 -use crate::BigNumParamsTrait; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; +use crate::params::BigNumParamsGetter; +use crate::params::BigNumParams; use crate::utils::u60_representation::U60Repr; + pub struct Vesta_Fr_Params {} -impl RuntimeBigNumParamsTrait<3> for Vesta_Fr_Params { - fn modulus_bits() -> u32 { - 255 + +impl BigNumParamsGetter<3, 255> for Vesta_Fr_Params { + fn get_params() -> BigNumParams<3, 255> { + Vesta_Fr_PARAMS } } -impl BigNumParamsTrait<3> for Vesta_Fr_Params { - fn get_instance() -> BigNumInstance<3, Self> { - Vesta_Fr_Instance - } - fn modulus_bits() -> u32 { - 255 - } -} -pub global Vesta_Fr_Instance: BigNumInstance<3, Vesta_Fr_Params> = BigNumInstance { - modulus: [ - 0x4698fc094cf91b992d30ed00000001, 0x22, 0x4000 - ], - double_modulus: [ - 0x018d31f81299f237325a61da00000002, 0x01000000000000000000000000000043, 0x7fff + +global Vesta_Fr_PARAMS: BigNumParams<3, 255> = BigNumParams { + has_multiplicative_inverse: true, + modulus: [0x4698fc094cf91b992d30ed00000001, 0x22, 0x4000], + double_modulus: [ + 0x018d31f81299f237325a61da00000002, + 0x01000000000000000000000000000043, + 0x7fff, + ], + modulus_u60: U60Repr { + limbs: [0x092d30ed00000001, 0x04698fc094cf91b9, 0x22, 0x00, 0x4000, 0x00], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x092d30ed00000001, + 0x04698fc094cf91b9, + 0x22, + 0x00, + 0x4000, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, ], - modulus_u60: U60Repr { limbs: [ - 0x092d30ed00000001, 0x04698fc094cf91b9, 0x22, 0x00, 0x4000, 0x00]}, - modulus_u60_x4: U60Repr { limbs: [ - 0x092d30ed00000001, 0x04698fc094cf91b9, 0x22, 0x00, 0x4000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }, - redc_param: [ - 0x59c0fdacc1b919b4b3c4bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff - ] + }, + redc_param: [0x59c0fdacc1b919b4b3c4bfffffffc4, 0xfffffffffffffffffffffffffff76e, 0x0fffff], }; diff --git a/src/fns/constrained_ops.nr b/src/fns/constrained_ops.nr new file mode 100644 index 00000000..b6c6d211 --- /dev/null +++ b/src/fns/constrained_ops.nr @@ -0,0 +1,488 @@ +use crate::params::BigNumParams as P; + +use crate::fns::{ + unconstrained_helpers::{ + __validate_in_field_compute_borrow_flags, __validate_gt_remainder, __neg_with_flags, + __add_with_flags, __sub_with_flags, + }, unconstrained_ops::{__mul, __div, __udiv_mod}, expressions::evaluate_quadratic_expression, +}; + +/** + * In this file: + * + * conditional_select + * assert_is_not_equal + * eq + * validate_in_field + * validate_in_range + * validate_quotient_in_range + * validate_gt + * neg + * add + * sub + * mul + * div + * udiv_mod + * udiv + * umod + */ + +/** +* @brief given an input seed, generate a pseudorandom BigNum value +* @details we hash the input seed into `modulus_bits * 2` bits of entropy, +* which is then reduced into a BigNum value +* 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 derive_from_seed( + params: P, + seed: [u8; SeedBytes], +) -> [Field; N] { + let mut rolling_seed: [u8; SeedBytes + 1] = [0; SeedBytes + 1]; + for i in 0..SeedBytes { + rolling_seed[i] = seed[i]; + assert_eq(rolling_seed[i], seed[i]); + } + + let mut hash_buffer: [u8; N * 2 * 15] = [0; N * 2 * 15]; + + let mut rolling_hash_fields: [Field; (SeedBytes / 31) + 1] = [0; (SeedBytes / 31) + 1]; + let mut seed_ptr = 0; + for i in 0..(SeedBytes / 31) + 1 { + let mut packed: Field = 0; + for _ in 0..31 { + if (seed_ptr < SeedBytes) { + packed *= 256; + packed += seed[seed_ptr] as Field; + seed_ptr += 1; + } + } + rolling_hash_fields[i] = packed; + } + + let compressed = + std::hash::poseidon2::Poseidon2::hash(rolling_hash_fields, (SeedBytes / 31) + 1); + let mut rolling_hash: [Field; 2] = [compressed, 0]; + let num_hashes = (30 * N) / 32 + (((30 * N) % 32) != 0) as u32; + for i in 0..num_hashes - 1 { + let hash: Field = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); + let hash: [u8; 32] = hash.to_le_bytes(); + for j in 0..30 { + hash_buffer[i * 30 + j] = hash[j]; + } + rolling_hash[1] += 1; + } + { + let hash: Field = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); + let hash: [u8; 32] = hash.to_le_bytes(); + let remaining_bytes = 30 * N - (num_hashes - 1) * 30; + for j in 0..remaining_bytes { + hash_buffer[(num_hashes - 1) * 30 + j] = hash[j]; + } + } + + let num_bits = MOD_BITS * 2; + let num_bytes = num_bits / 8 + ((num_bits % 8) != 0) as u32; + + let bits_in_last_byte = num_bits as u8 % 8; + let last_byte_mask = (1 as u8 << bits_in_last_byte) - 1; + hash_buffer[num_bytes - 1] = hash_buffer[num_bytes - 1] & last_byte_mask; + + let num_bigfield_chunks = (2 * N) / (N - 1) + (((2 * N) % (N - 1)) != 0) as u32; + let mut byte_ptr = 0; + + // we want to convert our byte array into bigfield chunks + // each chunk has at most N-1 limbs + // to determine the exact number of chunks, we need the `!=` or `>` operator which is not avaiable when defining array sizes + // so we overestimate at 4 + // 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 + // if N = 2, we have 4 limbs we want to reduce but each bigfield chunk is only 1 limb, so we need 4 + // max possible number of chunks is therefore 4 + let mut bigfield_chunks: [[Field; N]; 4] = [[0; N]; 4]; + for k in 0..num_bigfield_chunks { + let mut bigfield_limbs: [Field; N] = [0; N]; + let mut num_filled_bytes = (k * 30); + let mut num_remaining_bytes = num_bytes - num_filled_bytes; + let mut num_remaining_limbs = + (num_remaining_bytes / 15) + (num_remaining_bytes % 15 > 0) as u32; + let mut more_than_N_minus_one_limbs = (num_remaining_limbs > (N - 1)) as u32; + let mut num_limbs_in_bigfield = more_than_N_minus_one_limbs * (N - 1) + + num_remaining_limbs * (1 - more_than_N_minus_one_limbs); + + for j in 0..num_limbs_in_bigfield { + let mut limb: Field = 0; + for _ in 0..15 { + let need_more_bytes = (byte_ptr < num_bytes); + let mut byte = hash_buffer[byte_ptr]; + limb *= (256 * need_more_bytes as Field + (1 - need_more_bytes as Field)); + limb += byte as Field * need_more_bytes as Field; + byte_ptr += need_more_bytes as u32; + } + bigfield_limbs[num_limbs_in_bigfield - 1 - j] = limb; + } + bigfield_chunks[num_bigfield_chunks - 1 - k] = bigfield_limbs; + } + + let mut bigfield_rhs_limbs: [Field; N] = [0; N]; + bigfield_rhs_limbs[N - 1] = 1; + validate_in_range::<_, MOD_BITS>(bigfield_rhs_limbs); + + let mut result: [Field; N] = [0; N]; + + for i in 0..num_bigfield_chunks { + let bigfield_lhs_limbs = bigfield_chunks[i]; + + result = mul(params, result, bigfield_rhs_limbs); + result = add(params, result, bigfield_lhs_limbs); + } + result +} + +/** +* @brief conditional_select given the value of `predicate` return either `self` (if 0) or `other` (if 1) +* @description should be cheaper than using an IF statement (TODO: check!) +**/ +pub(crate) fn conditional_select( + lhs: [Field; N], + rhs: [Field; N], + predicate: bool, +) -> [Field; N] { + let mut result: [Field; N] = lhs; + for i in 0..N { + result[i] = (lhs[i] - rhs[i]) * predicate as Field + rhs[i]; + } + result +} + +/** + * @brief Validate self != other + * @details If A == B, then A == B mod N. + * We can efficiently evaluate A == B mod N where N = circuit modulus + * This method is *sound*, but not *complete* (i.e. A != B but A == B mod N) + * However the probability of an honest Prover being unable to satisfy this check is tiny! + * (todo: compute how tiny) + **/ +pub(crate) fn assert_is_not_equal( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) { + let mut l: Field = 0; + let mut r: Field = 0; + let mut modulus_mod_n: Field = 0; + let two_pow_120: Field = 0x1000000000000000000000000000000; + let modulus = params.modulus; + for i in 0..N { + l *= two_pow_120; + r *= two_pow_120; + modulus_mod_n *= two_pow_120; + l += lhs[N - i - 1]; + r += rhs[N - i - 1]; + modulus_mod_n += modulus[N - i - 1]; + } + + // lhs can be either X mod N or P + X mod N + // rhs can be either Y mod N or P + Y mod N + // If lhs - rhs = 0 mod P then lhs - rhs = 0, P or -P mod N + let mut diff = l - r; + let mut target = diff * (diff + modulus_mod_n) * (diff - modulus_mod_n); + assert(target != 0, "asssert_is_not_equal fail"); +} + +pub(crate) fn eq( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> bool { + let diff = sub::<_, MOD_BITS>(params, lhs, rhs); + // if self == other, possible values of `diff` will be `p` or `0` + // (the subtract operator constrains diff to be < ceil(log(p))) + // TODO: can do this more efficiently via witngen in unconstrained functions? + let mut is_equal_modulus: bool = true; + let mut is_equal_zero: bool = true; + for i in 0..N { + is_equal_modulus = is_equal_modulus & (diff[i] == params.modulus[i]); + is_equal_zero = is_equal_zero & (diff[i] == 0); + } + is_equal_modulus | is_equal_zero +} + +pub(crate) fn validate_in_field( + params: P, + val: [Field; N], +) { + // N.B. need to combine with validate_in_range if `self` limbs have not been range constrained + let mut p_minus_self: [Field; N] = [0; N]; + let modulus: [Field; N] = params.modulus; + for i in 0..N { + p_minus_self[i] = modulus[i] - val[i]; + } + let borrow_flags = unsafe { __validate_in_field_compute_borrow_flags(params, val) }; + let two_pow_120: Field = 0x1000000000000000000000000000000; + p_minus_self[0] += borrow_flags[0] as Field * two_pow_120; + for i in 1..N - 1 { + p_minus_self[i] += (borrow_flags[i] as Field * two_pow_120 - borrow_flags[i - 1] as Field); + } + p_minus_self[N - 1] -= borrow_flags[N - 2] as Field; + let mut compare = val; + compare = p_minus_self; + validate_in_range::<_, MOD_BITS>(compare); +} + +/** +* @brief Validate a BigNum instance is correctly range constrained to contain no more than Params::modulus_bits() +**/ +pub(crate) fn validate_in_range(limbs: [Field; N]) { + for i in 0..(N - 1) { + limbs[i].assert_max_bit_size::<120>(); + } + limbs[N - 1].assert_max_bit_size::(); +} + +/** +* @brief validate quotient produced from `evaluate_quadratic_expression` is well-formed +* @description because the inputs into evaluate_quadratic_expression may cause the quotient to extend beyond `Params::modulus_bits`. +* We allow the quotient to extend 6 bits beyond Params::modulus_bits() +* Why is this? +* several factors: 1. quotient * modulus , limbs cannot overflow field boundary (254 bits) +* 2. in `evaluate_quadratic_expression`, we require that for `expression - quotient * modulus`, +* limbs cannot exceed 246 bits (246 magic number due to a higher number adding extra range check gates) +* because of factor 2 and the fact that modulus limbs are 120 bits, quotient limbs cannot be >126 bits +* +* Note: doesn't this mean that final_limb_bits should be constrained to be 126 bits, not modulus_bits() - ((N - 1) * 120) + 6? +* TODO: think about this more! we want the range constraint we apply to be as small as allowable as this is more efficient +**/ +pub(crate) fn validate_quotient_in_range(limbs: [Field; N]) { + for i in 0..(N) { + limbs[i].assert_max_bit_size::<120>(); + } + // Note: replace magic number 6 with definition + limbs[N - 1].assert_max_bit_size::(); +} + +// validate that lhs - rhs does not underflow i.e. lhs > rhs +pub(crate) fn validate_gt(lhs: [Field; N], rhs: [Field; N]) { + // so we do... p - x - r = 0 and there might be borrow flags + // a - b = r + // p + a - b - r = 0 + let (result, carry_flags, borrow_flags) = unsafe { __validate_gt_remainder(lhs, rhs) }; + + validate_in_range::<_, MOD_BITS>(result); + + let borrow_shift = 0x1000000000000000000000000000000; + let carry_shift = 0x1000000000000000000000000000000; + + let mut addend: [Field; N] = [0; N]; + let result_limb = lhs[0] - rhs[0] + addend[0] - result[0] - 1 + + (borrow_flags[0] as Field * borrow_shift) + - (carry_flags[0] as Field * carry_shift); + assert(result_limb == 0); + for i in 1..N - 1 { + let result_limb = lhs[i] - rhs[i] + addend[i] - result[i] - borrow_flags[i - 1] as Field + + carry_flags[i - 1] as Field + + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift); + assert(result_limb == 0); + } + let result_limb = lhs[N - 1] - rhs[N - 1] + addend[N - 1] + - result[N - 1] + - borrow_flags[N - 2] as Field + + carry_flags[N - 2] as Field; + assert(result_limb == 0); +} + +pub(crate) fn neg( + params: P, + val: [Field; N], +) -> [Field; N] { + // so we do... p - x - r = 0 and there might be borrow flags + let (result, borrow_flags) = unsafe { __neg_with_flags(params, val) }; + validate_in_range::<_, MOD_BITS>(result); + let modulus = params.modulus; + let borrow_shift = 0x1000000000000000000000000000000; + let result_limb = modulus[0] - val[0] - result[0] + (borrow_flags[0] as Field * borrow_shift); + assert(result_limb == 0); + for i in 1..N - 1 { + let result_limb = modulus[i] - val[i] - result[i] - borrow_flags[i - 1] as Field + + (borrow_flags[i] as Field * borrow_shift); + assert(result_limb == 0); + } + let result_limb = modulus[N - 1] - val[N - 1] - result[N - 1] - borrow_flags[N - 2] as Field; + assert(result_limb == 0); + result +} + +pub(crate) fn add( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + // so we do... p - x - r = 0 and there might be borrow flags + let (result, carry_flags, borrow_flags, overflow_modulus) = + unsafe { __add_with_flags(params, lhs, rhs) }; + validate_in_range::<_, MOD_BITS>(result); + let modulus = params.modulus; + let borrow_shift = 0x1000000000000000000000000000000; + let carry_shift = 0x1000000000000000000000000000000; + + let mut subtrahend: [Field; N] = [0; N]; + if (overflow_modulus) { + subtrahend = modulus; + } + let result_limb = lhs[0] + rhs[0] - subtrahend[0] - result[0] + + (borrow_flags[0] as Field * borrow_shift) + - (carry_flags[0] as Field * carry_shift); + assert(result_limb == 0); + for i in 1..N - 1 { + let result_limb = lhs[i] + rhs[i] - subtrahend[i] - result[i] - borrow_flags[i - 1] as Field + + carry_flags[i - 1] as Field + + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift); + assert(result_limb == 0); + } + let result_limb = lhs[N - 1] + rhs[N - 1] + - subtrahend[N - 1] + - result[N - 1] + - borrow_flags[N - 2] as Field + + carry_flags[N - 2] as Field; + assert(result_limb == 0); + result +} + +pub(crate) fn sub( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + // so we do... p - x - r = 0 and there might be borrow flags + // a - b = r + // p + a - b - r = 0 + let (result, carry_flags, borrow_flags, underflow) = + unsafe { __sub_with_flags(params, lhs, rhs) }; + validate_in_range::<_, MOD_BITS>(result); + let modulus = params.modulus; + let borrow_shift = 0x1000000000000000000000000000000; + let carry_shift = 0x1000000000000000000000000000000; + + let mut addend: [Field; N] = [0; N]; + if (underflow) { + addend = modulus; + } + let result_limb = lhs[0] - rhs[0] + addend[0] - result[0] + + (borrow_flags[0] as Field * borrow_shift) + - (carry_flags[0] as Field * carry_shift); + assert(result_limb == 0); + for i in 1..N - 1 { + let result_limb = lhs[i] - rhs[i] + addend[i] - result[i] - borrow_flags[i - 1] as Field + + carry_flags[i - 1] as Field + + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift); + assert(result_limb == 0); + } + let result_limb = lhs[N - 1] - rhs[N - 1] + addend[N - 1] + - result[N - 1] + - borrow_flags[N - 2] as Field + + carry_flags[N - 2] as Field; + assert(result_limb == 0); + result +} + +// Note: this method is expensive! Try to craft quadratic relations and directly evaluate them +// via evaluate_quadratic_expression +// e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression` +// will create much fewer constraints than calling `mul` and `add` directly +pub(crate) fn mul( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + let result = unsafe { __mul::<_, MOD_BITS>(params, lhs, rhs) }; + evaluate_quadratic_expression( + params, + [[lhs]], + [[false]], + [[rhs]], + [[false]], + [result], + [true], + ); + result +} + +// Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation +pub(crate) fn div( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + assert( + params.has_multiplicative_inverse, + "BigNum has no multiplicative inverse. Use udiv for unsigned integer division", + ); + let result = unsafe { __div::<_, MOD_BITS>(params, lhs, rhs) }; + evaluate_quadratic_expression( + params, + [[result]], + [[false]], + [[rhs]], + [[false]], + [lhs], + [true], + ); + result +} + +/** +* @brief udiv_mod performs integer division between numerator, divisor +* +* i.e. 1. floor(numerator / divisor) = quotient +* 2. numerator % divisor = remainder +* 3. divisor * quotient + remainder = numerator +**/ +pub(crate) fn udiv_mod( + params: P, + numerator: [Field; N], + divisor: [Field; N], +) -> ([Field; N], [Field; N]) { + let (quotient, remainder) = unsafe { __udiv_mod(numerator, divisor) }; + + // self / divisor = quotient rounded + // quotient * divisor + remainder - self = 0 + evaluate_quadratic_expression( + params, + [[quotient]], + [[false]], + [[divisor]], + [[false]], + [numerator, remainder], + [true, false], + ); + // we need (remainder < divisor) + // implies (divisor - remainder > 0) + validate_gt::<_, MOD_BITS>(divisor, remainder); + (quotient, remainder) +} + +/** +* @brief udiv_mod performs integer division between numerator, divisor +* +* i.e. return param is floor(numerator / divisor) +**/ +pub(crate) fn udiv( + params: P, + numerator: [Field; N], + divisor: [Field; N], +) -> [Field; N] { + udiv_mod::<_, MOD_BITS>(params, numerator, divisor).0 +} + +/** +* @brief udiv_mod performs integer modular reduction +* +* i.e. 1. numerator % divisor = return value +**/ +pub(crate) fn umod( + params: P, + numerator: [Field; N], + divisor: [Field; N], +) -> [Field; N] { + udiv_mod::<_, MOD_BITS>(params, numerator, divisor).1 +} + diff --git a/src/fns/expressions.nr b/src/fns/expressions.nr new file mode 100644 index 00000000..38b2abfb --- /dev/null +++ b/src/fns/expressions.nr @@ -0,0 +1,400 @@ +use crate::utils::split_bits; + +use crate::params::BigNumParams as P; +use crate::fns::{ + constrained_ops::validate_quotient_in_range, unconstrained_helpers::__barrett_reduction, +}; + +/** + * In this file: + * + * __compute_quadratic_expression_with_borrow_flags + * __add_linear_expression + * __compute_quadratic_expression_product + * __compute_quadratic_expression + * evaluate_quadratic_expression + */ + +/** +* @brief Given a degree-2 BigNum expression that is equal to 0 mod p, compute the quotient and borrow flags +* @description The expression is of the form: +* +* \sum_{i=0}^{NUM_PRODUCTS - 1} ((\sum_{j=0}^{LHS_N-1}lhs[i][j]) * (\sum_{j=0}^{RHS_N-1}rhs[i][j])) + \sum_{i=0}^{ADD_N - 1}linear_terms[i] = quotient * modulus +* +* The intent is to capture an arbitrary degree-2 expression within the limitations of Noir (no efficient dynamically-sized vectors) +* +* When performing BigNum arithmetic, we want to represent desired BigNum operations in a way that minimizes the number of modular reductions that are required. +* This can be achieved by minimizing the number of degree-2 relations required. +* +* The borrow flags describe whether individual Field limbs will underflow when evaluating the above relation. +* For example, when computing the product a * b - q * p = 0, it is possible that: +* 1. a[0]*b[0] - p[0]*q[0] = -2^{120} +* 2. a[0]*b[1] + a[1]*b[0] - p[0]*q[1] - p[1]*q[0] = 1 +* In the above example, the value represented by these two limbs is zero despite each limb being nonzero. +* In this case, to correctly constrain the result, we must add (at least) 2^{120} from the first limb and subtract 1 from the second. +* +* @param lhs_terms a 2D array of BigNum +* @param lhs_flags a 2D array of sign flags +* @param rhs_terms a 2D array of BigNum +* @param rhs_flags a 2D array of sign flags +* @param linear_terms an array of BigNum +* @param linear_flags an array of sign flags +**/ +unconstrained fn __compute_quadratic_expression_with_borrow_flags( + params: P, + lhs_terms: [[[Field; N]; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs_terms: [[[Field; N]; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + linear_terms: [[Field; N]; ADD_N], + linear_flags: [bool; ADD_N], +) -> ([Field; N], [Field; N], [Field; 2 * N]) { + // TODO, validate we do not overflow N2 when multiplying and N when adding + let mut mulout_p = __compute_quadratic_expression_product( + params, + lhs_terms, + lhs_flags, + rhs_terms, + rhs_flags, + linear_terms, + linear_flags, + ); + let mut mulout_n: [Field; 2 * N] = [0; 2 * N]; + let mut relation_result: [Field; 2 * N] = split_bits::__normalize_limbs(mulout_p, 2 * N); + + let modulus: [Field; N] = params.modulus; + let modulus_bits = MOD_BITS; + let (quotient, remainder) = __barrett_reduction( + relation_result, + params.redc_param, + modulus_bits, + modulus, + params.modulus_u60_x4, + ); + assert(remainder == [0; N]); + + for i in 0..N { + for j in 0..N { + mulout_n[i + j] += quotient[i] * modulus[j]; + } + } + + // compute borrow flags from mulout_p and mulout_n + let mut borrow_flags: [Field; 2 * N] = [0; 2 * N]; + let borrow_shift: Field = 0x40000000000000000000000000000000000000000000000000000000000000; // 2^{246} + let borrow_carry: Field = 0x40000000000000000000000000000000; // 2^{246 - 120} = 2^{126} + let two_pow_120: Field = 0x1000000000000000000000000000000; + let downshift: Field = 1 / two_pow_120; + + // determine whether we need to borrow from more significant limbs. + // initial limb is "simple" comparison operation + // TODO: check how expensive `lt` operator is w.r.t. witness generation + borrow_flags[0] = mulout_p[0].lt(mulout_n[0]) as Field; + // we have 2N - 2 borrow flags. The number of limbs from our product computation is 2N - 1 + // and there is nothing to borrow against for the final limb. + let mut hi_bits = (mulout_p[0] - mulout_n[0] + (borrow_flags[0] * borrow_shift)) * downshift; + for i in 1..(N + N - 2) { + // compute the contribution from limb `i-1` that gets added into limb `i`, and add into limb `i` + // let hi_bits = (mulout_p.get(i - 1) - mulout_n.get(i - 1) + (borrow_flags.get(i - 1) * borrow_shift)) + // * downshift; + mulout_p[i] += hi_bits; + + // determine whether negative limb values are greater than positive limb values + let underflow: Field = + mulout_p[i].lt(mulout_n[i] + (borrow_flags[i - 1] * borrow_carry)) as Field; + borrow_flags[i] = underflow; + + hi_bits = ( + mulout_p[i] - mulout_n[i] + (borrow_flags[i] * borrow_shift) + - (borrow_flags[i - 1] * borrow_carry) + ) + * downshift; + } + + (quotient, remainder, borrow_flags) +} + +/** +* @brief Computes the result of a linear combination of (possibly negative) BigNum values (unconstrained) +**/ +// NOTE: modulus2 is structured such that all limbs will be greater than 0, even when subtracting. +// To do this, when computing `p - x`, we ensure that each limb in `p` is greater than each limb in `x`. +// We know that, for a valid bignum element, the limbs in `x` will be <2^{120} +// Therefore each of the limbs in `p` (except the most significant) will borrow 2^{120} from the more significant limb. +// Finally, to ensure we do not underflow in the most significant limb, we use `2p` instead of `p` +unconstrained fn __add_linear_expression( + params: P, + x: [[Field; N]; M], + flags: [bool; M], +) -> ([Field; N]) { + // TODO, validate we do not overflow N2 when multiplying and N when adding + let mut sum: [Field; N] = [0; N]; + // TODO: ugly! Will fail if input array is empty + let modulus2: [Field; N] = params.double_modulus; + for i in 0..M { + if (flags[i]) { + for j in 0..N { + sum[j] = sum[j] + modulus2[j] - x[i][j]; + // assert(x[i][j].lt(modulus2[j])); + } + } else { + for j in 0..N { + sum[j] = sum[j] + x[i][j]; + } + } + } + // problem if we normalize when used in computing quotient + sum +} + +/** +* @brief computes the limb products of a quadratic expression +* @details see __compute_quadratic_expression_with_borrow_flags for full description +**/ +unconstrained fn __compute_quadratic_expression_product( + params: P, + lhs_terms: [[[Field; N]; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs_terms: [[[Field; N]; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + linear_terms: [[Field; N]; ADD_N], + linear_flags: [bool; ADD_N], +) -> [Field; 2 * N] { + // TODO, validate we do not overflow N2 when multiplying and N when adding + let mut lhs: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; + let mut rhs: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; + let mut add: [Field; N] = [0; N]; + + for i in 0..NUM_PRODUCTS { + lhs[i] = __add_linear_expression(params, lhs_terms[i], lhs_flags[i]); + rhs[i] = __add_linear_expression(params, rhs_terms[i], rhs_flags[i]); + } + + let add: [Field; N] = __add_linear_expression(params, linear_terms, linear_flags); + + let mut mulout: [Field; 2 * N] = [0; 2 * N]; + + for i in 0..N { + for j in 0..N { + for k in 0..NUM_PRODUCTS { + mulout[i + j] += (lhs[k][i] * rhs[k][j]); + } + } + mulout[i] += add[i]; + } + mulout +} + +/** +* @brief computes the quotient/remainder of a quadratic expression +* @details see __compute_quadratic_expression_with_borrow_flags for full description +**/ +pub(crate) unconstrained fn __compute_quadratic_expression( + params: P, + lhs_terms: [[[Field; N]; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs_terms: [[[Field; N]; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + linear_terms: [[Field; N]; ADD_N], + linear_flags: [bool; ADD_N], +) -> ([Field; N], [Field; N]) { + // TODO, validate we do not overflow N2 when multiplying and N when adding + let mulout = __compute_quadratic_expression_product( + params, + lhs_terms, + lhs_flags, + rhs_terms, + rhs_flags, + linear_terms, + linear_flags, + ); + let mut relation_result: [Field; 2 * N] = split_bits::__normalize_limbs(mulout, 2 * N); + + // size 4 + // a[3] * b[3] = a[6] = 7 + // TODO: ugly! Will fail if input slice is empty + let k = MOD_BITS; + + let (quotient, remainder) = __barrett_reduction( + relation_result, + params.redc_param, + k, + params.modulus, + params.modulus_u60_x4, + ); + + let mut q = quotient; + let mut r = remainder; + (q, r) +} + +/** +* @brief Constrain a degree-2 BigNum expression to be equal to 0 modulo self.modulus +* @description The expression is of the form (when evaluated as an integer relation): +* +* \sum_{i=0}^{NUM_PRODUCTS - 1} ((\sum_{j=0}^{LHS_N-1}lhs[i][j]) * (\sum_{j=0}^{RHS_N-1}rhs[i][j])) + \sum_{i=0}^{ADD_N - 1}linear_terms[i] - quotient * modulus = 0 +* +* The intent is to capture an arbitrary degree-2 expression within the limitations of Noir (no efficient dynamically-sized vectors) +* +* Note: this method requires the remainder term of the expression to be ZERO +* When performing BigNum arithmetic, we want to represent desired BigNum operations in a way that minimizes the number of modular reductions that are required. +* This can be achieved by minimizing the number of degree-2 relations required. +* +* The expensive parts of this algorithm are the following: +* 1. evaluating the limb products required to compute `lhs * rhs` +* 2. applying range constraints to validate the result is 0 +* +* Range constraints are needed for the following reason: +* When evaluating the above expression over N-limb BigNum objects, the result will consist of 2N - 1 limbs. +* Each limb will be in the range [0, ..., 2^{240 + twiddle_factor} - 1] (twiddle_factor needs to be less than 6). +* Because of the subtractions, the limbs may underflow and represent NEGATIVE values. +* To account for this, we allow the Prover to borrow values from more significant limbs and add them into less significant limbs +* (explicitly, we can borrow 2^{126} from limb `i + 1` to add `2^{246}` into `i`). +* To ensure this has been done correctly, we validate that the borrow-adjusted limbs are all-zero for the first 120 bits. +* We do *this* by multiplying the borrow-adjusted limbs by 1 / 2^{120} modulo CircutModulus, and we validate the result is in the range [0, ..., 2^{126} - 1]. +* TODO: explain why this check works. It's statistically sound but not perfectly sound. Chance of the check failing is ~1 in 2^{120} +* I believe this is the most efficient way of performing the zero-check for this relation as it only requires `2N - 2` 126-bit range checks. +* TODO: explain why we apply a 126-bit range check, this feels like a magic number +* (it is. we could go higher, up to the number of bits in the CircuitModulus - 121, but 126 *should be* sufficient and is much cheaper) +* TODO: apply checks in this method to validate twiddle_factor does not exceed 6 +* +* @param lhs_terms a 2D array of BigNum +* @param lhs_flags a 2D array of sign flags +* @param rhs_terms a 2D array of BigNum +* @param rhs_flags a 2D array of sign flags +* @param linear_terms an array of BigNum +* @param linear_flags an array of sign flags +**/ +pub(crate) fn evaluate_quadratic_expression( + params: P, + lhs_terms: [[[Field; N]; LHS_N]; NUM_PRODUCTS], + lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], + rhs_terms: [[[Field; N]; RHS_N]; NUM_PRODUCTS], + rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], + linear_terms: [[Field; N]; ADD_N], + linear_flags: [bool; ADD_N], +) { + // use an unconstrained function to compute the value of the quotient + let (quotient, _, borrow_flags): ([Field; N], [Field; N], [Field; 2 * N]) = unsafe { + __compute_quadratic_expression_with_borrow_flags::<_, MOD_BITS, _, _, _, _>( + params, + lhs_terms, + lhs_flags, + rhs_terms, + rhs_flags, + linear_terms, + linear_flags, + ) + }; + // constrain the quotient to be in the range [0, ..., 2^{m} - 1], where `m` is log2(modulus) rounded up. + // Additionally, validate quotient limbs are also in the range [0, ..., 2^{120} - 1] + validate_quotient_in_range::<_, MOD_BITS>(quotient); + // TODO, validate we do not overflow N2 when multiplying and N when adding + // (should be a compile-time check...unconstrained function?) + // Compute the linear sums that represent lhs_1, rhs_1, lhs_2, rhs_2, add + let mut t0: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; + let mut t1: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; + let mut t4: [Field; N] = [0; N]; + + // TODO: this is super nasty as it requires a multiplication + let double_modulus: [Field; N] = params.double_modulus; + for k in 0..NUM_PRODUCTS { + for i in 0..N { + for j in 0..LHS_N { + // note: if is_negative is not known at comptime this is very expensive + if (lhs_flags[k][j]) { + t0[k][i] -= lhs_terms[k][j][i]; + t0[k][i] += double_modulus[i]; + } else { + t0[k][i] += lhs_terms[k][j][i]; + } + } + for j in 0..RHS_N { + if (rhs_flags[k][j]) { + t1[k][i] -= rhs_terms[k][j][i]; + t1[k][i] += double_modulus[i]; + } else { + t1[k][i] += rhs_terms[k][j][i]; + } + } + } + } + for i in 0..N { + for j in 0..ADD_N { + if (linear_flags[j]) { + t4[i] -= linear_terms[j][i]; + t4[i] += double_modulus[i]; + } else { + t4[i] += linear_terms[j][i]; + } + } + } + + // We want to evaluate that t0 * t1 + t2 * t3 + t4 - Quotient * Modulus = 0, evaluated over the integers + // For this we need to be able to borrow values from more-significant limbs into less-significant limbs, + // so that we can ensure that no limbs will underflow for an honest Prover + let mut product_limbs: [Field; 2 * N] = [0; 2 * N]; + + // Compute the product t0 * t1 + t2 * t3 + t4 - Quotient * Modulus + // TODO: this is super nasty as it requires a multiplication + for i in 0..N { + for j in 0..N { + for k in 0..NUM_PRODUCTS { + if k == 0 { + let new_term = t0[k][i] * t1[k][j] - quotient[i] * params.modulus[j]; + std::as_witness(new_term); // width-4 optimization (n.b. might not be optimal if t2, t3 input arrays are nonzero) + product_limbs[i + j] += new_term; + } else { + product_limbs[i + j] += t0[k][i] * t1[k][j]; + } + } + if (NUM_PRODUCTS == 0) { + product_limbs[i + j] -= quotient[i] * params.modulus[j]; + } + } + product_limbs[i] += t4[i]; + } + + // each limb product represents the sum of 120-bit products. + // by setting the borrow value to 2^246 we are restricting this method's completeness to expressions + // where no more than 64 limb products are summed together. + // TODO: check in unconstrained function that this condition is satisfied + // TODO: define trade-offs regarding the value of borrow_shift + // (the larger the value, the greater the range check that is required on product_limbs) + // (126-bit range check is a sweet spot for the barretenberg backend as it decomposes into 9 14-bit range checks) + // (the barretenberg backend can evaluate these in 5.25 gates. 127 bits costs 6.5 gates) + let borrow_shift: Field = 0x40000000000000000000000000000000000000000000000000000000000000; // 2^{246} + let borrow_carry: Field = 0x40000000000000000000000000000000; // 2^{246 - 120} = 2^{126} + // N.B. borrow_flags is `Field` type because making it `bool` would apply boolean constraints to all `N2` array entries. + // We only use `N2 - 2` borrow flags so applying 1-bit range checks on the array elements we use is more efficient. + // TODO: Once it is possible to perform arithmetic on generics we can use `borrow_flags: [bool;N+N-2]` to avoid this issue + borrow_flags[0].assert_max_bit_size::<1>(); + product_limbs[0] += borrow_flags[0] * borrow_shift; + for i in 1..(N + N - 2) { + borrow_flags[i].assert_max_bit_size::<1>(); + product_limbs[i] += (borrow_flags[i] * borrow_shift - borrow_flags[i - 1] * borrow_carry); + } + product_limbs[N + N - 2] -= borrow_flags[N + N - 3] * borrow_carry; + + // Final step: Validate `product_limbs` represents the integer value `0` + // Each element `i` in `product_limbs` overlaps in bitrange with element `i+1`, EXCEPT for the low 120 bits + // i.e. we need to do the following for each limb `i`: + // 1. validate the limb's low-120 bits equals zero + // 2. compute the limb "carry" by right-shifting by 2^{120} + // 3. add the carry into limb `i+1` + // We can efficiently do all of the above by multiplying the limb by 2^{-120} and constraining the result to be <2^{126} + // (if the low 120 bits are nonzero the result will underflow and product a large value that cannot be range constrained) + // (the probability of an underflow value satisfying a 126-bit range constraint is approx. 2^{k - 126}, + // where k is the number of bits in the prime field) + // We then add the result into the next limb and repeat. + let hi_shift: Field = 0x1000000000000000000000000000000; + let hi_downshift: Field = 1 / hi_shift; + for i in 0..N + N - 2 { + product_limbs[i] *= hi_downshift; + std::as_witness(product_limbs[i]); + product_limbs[i].assert_max_bit_size::<126>(); // N.B. is this sufficient? going beyond 126 costs us 1 gate per limb + product_limbs[i + 1] += product_limbs[i]; + } + // the most significant limb has no limb to "carry" values into - the entire limb must equal zero + assert(product_limbs[N + N - 2] == 0); +} diff --git a/src/fns/mod.nr b/src/fns/mod.nr new file mode 100644 index 00000000..dd9f5af0 --- /dev/null +++ b/src/fns/mod.nr @@ -0,0 +1,6 @@ +// Free functions called by structs +pub(crate) mod unconstrained_ops; +pub(crate) mod constrained_ops; +pub(crate) mod unconstrained_helpers; +pub(crate) mod expressions; +pub(crate) mod serialization; diff --git a/src/fns/serialization.nr b/src/fns/serialization.nr new file mode 100644 index 00000000..926f4271 --- /dev/null +++ b/src/fns/serialization.nr @@ -0,0 +1,61 @@ +/** +* @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], +) -> [Field; N] { + let num_bits = NBytes * 8; + assert(num_bits >= MOD_BITS); + assert(num_bits - MOD_BITS < 8); + let mut result = [0; N]; + + let excess_bytes = N * 15 - NBytes; + let final_limb_bytes = 15 - excess_bytes; + let mut limb: Field = 0; + let mut k = 0; + for _j in 0..final_limb_bytes { + limb *= 256; + limb += x[k] as Field; + k += 1; + } + result[N - 1] = limb; + + for i in 1..N { + let mut limb: Field = 0; + for _j in 0..15 { + limb *= 256; + limb += x[k] as Field; + k += 1; + } + result[N - i - 1] = limb; + } + + let most_significant_byte: Field = x[0] as Field; + + most_significant_byte.assert_max_bit_size::<8 - (NBytes * 8 - MOD_BITS)>(); + result +} + +pub(crate) fn to_le_bytes( + val: [Field; N], +) -> [u8; NBytes] { + let nbytes = (MOD_BITS / 8) + (MOD_BITS % 8 != 0) as u32; + assert(nbytes <= NBytes); + + let mut result: [u8; NBytes] = [0; NBytes]; + for i in 0..N - 1 { + let limb_bytes: [u8; 15] = val[i].to_le_bytes(); + for j in 0..15 { + result[i * 15 + j] = limb_bytes[j]; + } + } + let last_limb_bytes: [u8; 15] = val[N - 1].to_le_bytes(); + let num_last_bytes = (NBytes - (N - 1) * 15); + for i in 0..num_last_bytes { + result[(N - 1) * 15 + i] = last_limb_bytes[i]; + } + result +} diff --git a/src/fns/unconstrained_helpers.nr b/src/fns/unconstrained_helpers.nr new file mode 100644 index 00000000..694971e5 --- /dev/null +++ b/src/fns/unconstrained_helpers.nr @@ -0,0 +1,356 @@ +use crate::utils::u60_representation::U60Repr; +use crate::utils::split_bits; + +use crate::params::BigNumParams as P; +use crate::fns::unconstrained_ops::{__one, __eq, __neg, __add, __mul, __pow}; + +/** + * In this file: + * + * __validate_in_field_compute_borrow_flags + * __validate_gt_remainder + * __neg_with_flags + * __add_with_flags + * __sub_with_flags + * __barrett_reduction + * __tonelli_shanks_sqrt + */ + +pub(crate) unconstrained fn __validate_in_field_compute_borrow_flags( + params: P, + val: [Field; N], +) -> [bool; N] { + let mut flags: [bool; N] = [false; N]; + let modulus: [Field; N] = params.modulus; + flags[0] = modulus[0].lt(val[0]); + for i in 1..N - 1 { + flags[i] = modulus[i].lt(val[i] + flags[i - 1] as Field); + } + flags +} + +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 underflow = b_u60.gte(a_u60); + b_u60 += U60Repr::one(); + assert(underflow == false, "BigNum::validate_gt check fails"); + let mut addend_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + let mut result_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + + let mut carry: u64 = 0; + let mut carry_in: u64 = 0; + let mut borrow: u64 = 0; + let mut borrow_in: u64 = 0; + let mut borrow_flags: [bool; N] = [false; N]; + let mut carry_flags: [bool; N] = [false; N]; + for i in 0..2 * N { + let mut add_term: u64 = a_u60.limbs[i] + addend_u60.limbs[i] + carry_in; + carry = (add_term >= 0x1000000000000000) as u64; + add_term -= (carry as u64 * 0x1000000000000000); + result_u60.limbs[i] = add_term; + carry_in = carry as u64; + borrow = ((b_u60.limbs[i] + borrow_in) > result_u60.limbs[i]) as u64; + let sub = (borrow << 60) + result_u60.limbs[i] - b_u60.limbs[i] - borrow_in; + result_u60.limbs[i] = sub; + borrow_in = borrow; + + if ((i & 1) == 1) { + if (carry & borrow == 1) { + carry = 0; + borrow = 0; + } + carry_flags[i / 2] = carry as bool; + borrow_flags[i / 2] = borrow as bool; + } + } + + let result = U60Repr::into(result_u60); + (result, carry_flags, borrow_flags) +} + +pub(crate) unconstrained fn __neg_with_flags( + params: P, + val: [Field; N], +) -> ([Field; N], [bool; N]) { + let x_u60: U60Repr = U60Repr::from(val); + let mut result_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + + let mut borrow: u64 = 0; + let mut borrow_in: u64 = 0; + + let mut borrow_flags: [bool; N] = [false; N]; + for i in 0..2 * N { + borrow = ((x_u60.limbs[i] + borrow_in) > params.modulus_u60.limbs[i]) as u64; + let sub = (borrow << 60) + params.modulus_u60.limbs[i] - x_u60.limbs[i] - borrow_in; + result_u60.limbs[i] = sub; + borrow_in = borrow; + if ((i & 1) == 1) { + borrow_flags[i / 2] = borrow as bool; + } + } + let result = U60Repr::into(result_u60); + (result, borrow_flags) +} + +pub(crate) unconstrained fn __add_with_flags( + params: P, + 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 add_u60 = a_u60 + b_u60; + + let overflow = add_u60.gte(params.modulus_u60); + + let mut subtrahend_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + let mut result_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + + if overflow { + subtrahend_u60 = params.modulus_u60; + } + + let mut carry: u64 = 0; + let mut carry_in: u64 = 0; + let mut borrow: u64 = 0; + let mut borrow_in: u64 = 0; + let mut borrow_flags: [bool; N] = [false; N]; + let mut carry_flags: [bool; N] = [false; N]; + for i in 0..2 * N { + let mut add_term: u64 = a_u60.limbs[i] + b_u60.limbs[i] + carry_in; + carry = (add_term >= 0x1000000000000000) as u64; + add_term -= (carry as u64 * 0x1000000000000000); + result_u60.limbs[i] = add_term; + carry_in = carry as u64; + borrow = ((subtrahend_u60.limbs[i] + borrow_in) > result_u60.limbs[i]) as u64; + let sub = (borrow << 60) + result_u60.limbs[i] - subtrahend_u60.limbs[i] - borrow_in; + result_u60.limbs[i] = sub; + borrow_in = borrow; + + if ((i & 1) == 1) { + let idx = (i - 1) / 2; + if (carry & borrow == 1) { + carry = 0; + borrow = 0; + } + carry_flags[idx] = carry as bool; + borrow_flags[idx] = borrow as bool; + } + } + let result = U60Repr::into(result_u60); + + (result, carry_flags, borrow_flags, overflow) +} + +pub(crate) unconstrained fn __sub_with_flags( + params: P, + 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 underflow = b_u60.gte(a_u60 + U60Repr::one()); + + let mut addend_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + let mut result_u60: U60Repr = U60Repr { limbs: [0; 2 * N] }; + + if underflow { + addend_u60 = params.modulus_u60; + } + + let mut carry: u64 = 0; + let mut carry_in: u64 = 0; + let mut borrow: u64 = 0; + let mut borrow_in: u64 = 0; + let mut borrow_flags: [bool; N] = [false; N]; + let mut carry_flags: [bool; N] = [false; N]; + for i in 0..2 * N { + let mut add_term: u64 = a_u60.limbs[i] + addend_u60.limbs[i] + carry_in; + carry = (add_term >= 0x1000000000000000) as u64; + add_term -= (carry as u64 * 0x1000000000000000); + result_u60.limbs[i] = add_term; + carry_in = carry as u64; + borrow = ((b_u60.limbs[i] + borrow_in) > result_u60.limbs[i]) as u64; + let sub = (borrow << 60) + result_u60.limbs[i] - b_u60.limbs[i] - borrow_in; + result_u60.limbs[i] = sub; + borrow_in = borrow; + + if ((i & 1) == 1) { + if (carry & borrow == 1) { + carry = 0; + borrow = 0; + } + carry_flags[i / 2] = carry as bool; + borrow_flags[i / 2] = borrow as bool; + } + } + let result = U60Repr::into(result_u60); + (result, carry_flags, borrow_flags, underflow) +} + +/** + * @brief BARRETT_REDUCTION_OVERFLOW_BITS defines how large an input to barrett reduction can be + * @details maximum value = modulus^2 <( + x: [Field; 2 * N], + redc_param: [Field; N], + k: u32, + modulus: [Field; N], + modulus_u60: U60Repr, +) -> ([Field; N], [Field; N]) { + let mut mulout: [Field; 3 * N] = [0; 3 * N]; + for i in 0..(N + N) { + for j in 0..N { + mulout[i + j] += x[i] * redc_param[j]; + } + } + mulout = split_bits::__normalize_limbs(mulout, 3 * N - 2); + let mulout_u60: U60Repr = U60Repr::new(mulout); + + // When we apply the barrett reduction, the maximum value of the output will be + // <= p * (1 + x/2^{2k}) + // where p = modulus, + // x = reduction input + // if x > p * p, we need k to be larger than modulus_bits() + // we hardcode k = 4, which means that the maximum value of x is approx. 16 * p * p + // this should be larger than most values put into `evaluate_quadratic_expression` + // TODO: try and detect cases where x might be too large at comptime + // N.B. BARRETT_REDUCTION_OVERFLOW_BITS affects how `redc_param` is generated. + // `redc_param` = 2^{modulus_bits() * 2 + BARRETT_REDUCTION_OVERFLOW_BITS} / modulus + // NOTE: very niche edge case error that we need to be aware of: + // N must be large enough to cover the modulus *plus* BARRETT_REDUCTION_OVERFLOW_BITS + // i.e. a 359-bit prime needs (I think) 4 limbs to represent or we may overflow when calling __barrett_reduction + let mut quotient_u60 = mulout_u60.shr((k + k + BARRETT_REDUCTION_OVERFLOW_BITS)); + + // N.B. we assume that the shifted quotient cannot exceed 2 times original bit size. + // (partial_quotient should be just slightly larger than the modulus, we could probably represent with a size N+1 array) + let partial_quotient_full: [Field; 3 * N] = quotient_u60.into_field_array(); + let mut partial_quotient: [Field; 2 * N] = [0; 2 * N]; + for i in 0..2 * N { + partial_quotient[i] = partial_quotient_full[i]; + } + // quotient_mul_modulus can never exceed input value `x` so can fit into size-2 array + let mut quotient_mul_modulus: [Field; 2 * N] = [0; 2 * N]; + let mut quotient_mul_modulus_normalized: [Field; 2 * N] = [0; 2 * N]; + for j in 0..N { + for i in 0..(N + N - j) { + quotient_mul_modulus[i + j] += partial_quotient[i] * modulus[j]; + } + } + + for i in 0..(N + N) { + let (lo, hi) = split_bits::split_120_bits(quotient_mul_modulus[i]); + quotient_mul_modulus_normalized[i] = lo; + // TODO: what is faster, leaving this if statement in or out? + // (array is size-1 too large so we can tolerate adding 0 into max element) + if (i + 1 < N + N) { + quotient_mul_modulus[i + 1] += hi; + } + } + let quotient_mul_modulus_u60: U60Repr = U60Repr::new(quotient_mul_modulus_normalized); + + let x_u60: U60Repr = U60Repr::new(x); + let mut remainder_u60 = x_u60 - quotient_mul_modulus_u60; + + if (remainder_u60.gte(modulus_u60)) { + remainder_u60 = remainder_u60 - modulus_u60; + quotient_u60.increment(); + } else {} + + let q: [Field; N] = U60Repr::into(quotient_u60); + let r: [Field; N] = U60Repr::into(remainder_u60); + + (q, r) +} + +/** +* @brief compute the log of the size of the primitive root +* @details find the maximum value k where x^k = 1, where x = primitive root +* This is needed for our Tonelli-Shanks sqrt algorithm +**/ +pub(crate) unconstrained fn __primitive_root_log_size( + params: P, +) -> u32 { + let mut target: U60Repr = params.modulus_u60 - U60Repr::one(); + let mut result: u32 = 0; + for _ in 0..MOD_BITS { + let lsb_is_one = (target.limbs[0] & 1) == 1; + if (!lsb_is_one) { + result += 1; + target.shr1(); + } else { + break; + } + } + result +} + +/** +* @brief inner loop fn for `find_multiplive_generator` +* @details recursive function to get around the lack of a `while` keyword +**/ +unconstrained fn __recursively_find_multiplicative_generator( + params: P, + target: [Field; N], + p_minus_one_over_two: [Field; N], +) -> (bool, [Field; N]) { + let exped = __pow(params, target, p_minus_one_over_two); + let one: [Field; N] = __one(); + let neg_one = __neg(params, one); + let found = __eq(exped, neg_one); + let mut result: (bool, [Field; N]) = (found, target); + if (!found) { + let _target = unsafe { __add(params, target, one) }; + result = __recursively_find_multiplicative_generator::<_, MOD_BITS>( + params, + _target, + p_minus_one_over_two, + ); + } + result +} + +/** +* @brief find multiplicative generator `g` where `g` is the smallest value that is not a quadratic residue +* i.e. smallest g where g^2 = -1 +* @note WARNING if multiplicative generator does not exist, this function will enter an infinite loop! +**/ +pub(crate) unconstrained fn __multiplicative_generator( + params: P, +) -> [Field; N] { + let mut target: [Field; N] = __one(); + let p_minus_one_over_two: U60Repr = (params.modulus_u60 - U60Repr::one()).shr(1); + let p_minus_one_over_two: [Field; N] = U60Repr::into(p_minus_one_over_two); + let (_, target) = __recursively_find_multiplicative_generator::<_, MOD_BITS>( + params, + target, + p_minus_one_over_two, + ); + target +} + +pub(crate) unconstrained fn __tonelli_shanks_sqrt_inner_loop_check( + params: P, + t2m: [Field; N], + i: u32, +) -> u32 { + let one: [Field; N] = __one(); + let is_one = __eq(t2m, one); + let mut result = i; + if (!is_one) { + let t2m = __mul::<_, MOD_BITS>(params, t2m, t2m); + let i = i + 1; + result = __tonelli_shanks_sqrt_inner_loop_check::<_, MOD_BITS>(params, t2m, i); + } + result +} diff --git a/src/fns/unconstrained_ops.nr b/src/fns/unconstrained_ops.nr new file mode 100644 index 00000000..b72f913b --- /dev/null +++ b/src/fns/unconstrained_ops.nr @@ -0,0 +1,442 @@ +use crate::utils::u60_representation::U60Repr; +use crate::utils::split_bits; + +use crate::params::BigNumParams as P; +use crate::fns::unconstrained_helpers::{ + __barrett_reduction, __primitive_root_log_size, __multiplicative_generator, + __tonelli_shanks_sqrt_inner_loop_check, +}; + +/** + * In this file: + * + * __one + * __derive_from_seed + * __eq + * __is_zero + * __neg + * __add + * __sub + * __mul_with_quotient + * __mul + * __div + * __udiv_mod + * __invmod + * __pow + * __batch_invert + * __batch_invert_slice + */ + +pub(crate) unconstrained fn __one() -> [Field; N] { + let mut limbs: [Field; N] = [0; N]; + limbs[0] = 1; + limbs +} + +pub(crate) unconstrained fn __derive_from_seed( + params: P, + seed: [u8; SeedBytes], +) -> [Field; N] { + let mut rolling_hash_fields: [Field; (SeedBytes / 31) + 1] = [0; (SeedBytes / 31) + 1]; + let mut seed_ptr = 0; + for i in 0..(SeedBytes / 31) + 1 { + let mut packed: Field = 0; + for _ in 0..31 { + if (seed_ptr < SeedBytes) { + packed *= 256; + packed += seed[seed_ptr] as Field; + seed_ptr += 1; + } + } + rolling_hash_fields[i] = packed; + } + let compressed = + std::hash::poseidon2::Poseidon2::hash(rolling_hash_fields, (SeedBytes / 31) + 1); + let mut rolling_hash: [Field; 2] = [compressed, 0]; + + let mut to_reduce: [Field; 2 * N] = [0; 2 * N]; + + let mut double_modulus_bits = MOD_BITS * 2; + let mut double_modulus_bytes = + (double_modulus_bits) / 8 + (double_modulus_bits % 8 != 0) as u32; + + let mut last_limb_bytes = double_modulus_bytes % 15; + if (last_limb_bytes == 0) { + last_limb_bytes = 15; + } + let mut last_limb_bits = double_modulus_bits % 8; + if (last_limb_bits == 0) { + last_limb_bits = 8; + } + + for i in 0..(N - 1) { + let hash = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); + let hash: [u8; 30] = hash.to_le_bytes(); + let mut lo: Field = 0; + let mut hi: Field = 0; + for j in 0..15 { + hi *= 256; + lo *= 256; + + if (i < 2 * N - 2) { + lo += hash[j + 15] as Field; + hi += hash[j] as Field; + } + } + to_reduce[2 * i] = lo; + to_reduce[2 * i + 1] = hi; + rolling_hash[1] += 1; + } + + { + let hash = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); + let hash: [u8; 30] = hash.to_le_bytes(); + let mut hi: Field = 0; + for j in 0..(last_limb_bytes - 1) { + hi *= 256; + hi += hash[j] as Field; + } + hi *= 256; + let last_byte = hash[last_limb_bytes - 1]; + let mask = (1 as u64 << (last_limb_bits) as u8) - 1; + let last_bits = last_byte as u64 & mask; + hi += last_bits as Field; + to_reduce[2 * N - 2] = hi; + } + + let (_, remainder) = __barrett_reduction( + to_reduce, + params.redc_param, + MOD_BITS, + params.modulus, + params.modulus_u60_x4, + ); + let result = remainder; + result +} + +pub(crate) unconstrained fn __eq(lhs: [Field; N], rhs: [Field; N]) -> bool { + lhs == rhs +} + +pub(crate) unconstrained fn __is_zero(limbs: [Field; N]) -> bool { + let mut result: bool = true; + for i in 0..N { + result = result & (limbs[i] == 0); + } + result +} + +/** +* @brief given an input `x`, compute `2p - x` (unconstrained) +* +* @description we subtract the input from double the modulus, because all constrained BigNum operations +* only guarantee that the output is in the range [0, ceil(log2(p))]. +* I.E. the input may be larger than the modulus `p`. +* In order to ensure this operation does not underflow, we compute `2p - x` instead of `p - x`. +* N.B. constrained BigNum operations do not fully constrain outputs to be in the range [0, p-1] +* because such a check is expensive and usually unneccesary. +*/ +pub(crate) unconstrained fn __neg( + params: P, + limbs: [Field; N], +) -> [Field; N] { + let f: [Field; N] = limbs; + let x_u60: U60Repr = U60Repr::from(f); + U60Repr::into(params.modulus_u60 - x_u60) +} + +pub(crate) unconstrained fn __add( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + let x_u60: U60Repr = U60Repr::from(lhs); + let y_u60: U60Repr = U60Repr::from(rhs); + + let mut z_u60 = x_u60 + y_u60; + + if z_u60.gte(params.modulus_u60) { + z_u60 = z_u60 - params.modulus_u60; + } + U60Repr::into(z_u60) +} + +/** +* @brief given inputs `x, y` compute 2p + x - y (unconstrained) +* @description see `__neg` for why we use 2p instead of p +**/ +pub(crate) unconstrained fn __sub( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + __add(params, lhs, __neg(params, rhs)) +} + +pub(crate) unconstrained fn __mul_with_quotient( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> ([Field; N], [Field; N]) { + let mut mul: [Field; 2 * N] = [0; 2 * N]; + for i in 0..N { + for j in 0..N { + mul[i + j] += lhs[i] * rhs[j]; + } + } + let to_reduce = split_bits::__normalize_limbs(mul, 2 * N); + let (q, r) = __barrett_reduction( + to_reduce, + params.redc_param, + MOD_BITS, + params.modulus, + params.modulus_u60_x4, + ); + + (q, r) +} + +pub(crate) unconstrained fn __mul( + params: P, + lhs: [Field; N], + rhs: [Field; N], +) -> [Field; N] { + let (_, b) = __mul_with_quotient::<_, MOD_BITS>(params, lhs, rhs); + b +} + +pub(crate) unconstrained fn __div( + params: P, + numerator: [Field; N], + divisor: [Field; N], +) -> [Field; N] { + let inv_divisor = __invmod::<_, MOD_BITS>(params, divisor); + __mul::<_, MOD_BITS>(params, numerator, inv_divisor) +} + +/** +* @brief __udiv_mod performs *unconstrained* integer division between numerator, divisor +* +* i.e. 1. floor(numerator / divisor) = quotient +* 2. numerator % divisor = remainder +* 3. divisor * quotient + remainder = numerator +**/ +pub(crate) unconstrained fn __udiv_mod( + numerator: [Field; N], + divisor: [Field; N], +) -> ([Field; N], [Field; N]) { + let mut quotient_u60: U60Repr = U60Repr::from([0; N]); + let mut remainder_u60: U60Repr = U60Repr::from(numerator); + + let mut divisor_u60: U60Repr = U60Repr::from(divisor); + let b = divisor_u60; + + let mut bit_difference = remainder_u60.get_msb() - divisor_u60.get_msb(); + + let mut accumulator_u60: U60Repr = U60Repr::one(); + divisor_u60 = divisor_u60.shl(bit_difference); + accumulator_u60 = accumulator_u60.shl(bit_difference); + + if (divisor_u60.gte(remainder_u60 + U60Repr::one())) { + divisor_u60.shr1(); + accumulator_u60.shr1(); + } + for _ in 0..(N * 120) { + if (remainder_u60.gte(b) == false) { + break; + } + + // we've shunted 'divisor' up to have the same bit length as our remainder. + // If remainder >= divisor, then a is at least '1 << bit_difference' multiples of b + if (remainder_u60.gte(divisor_u60)) { + remainder_u60 -= divisor_u60; + // we can use OR here instead of +, as + // accumulator is always a nice power of two + quotient_u60 = quotient_u60 + accumulator_u60; + } + divisor_u60.shr1(); // >>= 1; + accumulator_u60.shr1(); // >>= 1; + } + + (U60Repr::into(quotient_u60), U60Repr::into(remainder_u60)) +} + +pub(crate) unconstrained fn __invmod( + params: P, + val: [Field; N], +) -> [Field; N] { + let one: [Field; N] = __one::(); + let one_u60: U60Repr = U60Repr::from(one); + let exp_u60 = params.modulus_u60.sub(one_u60.add(one_u60)); + let exp = U60Repr::into(exp_u60); + __pow::<_, MOD_BITS>(params, val, exp) +} + +pub(crate) unconstrained fn __pow( + params: P, + val: [Field; N], + exponent: [Field; N], +) -> [Field; N] { + let x: U60Repr = U60Repr::from(exponent); + + let num_bits = MOD_BITS + 1; + + let mut accumulator: [Field; N] = __one::(); + + for i in 0..num_bits { + accumulator = __mul::<_, MOD_BITS>(params, accumulator, accumulator); + if x.get_bit(num_bits - i - 1) { + accumulator = __mul::<_, MOD_BITS>(params, accumulator, val); + } + } + accumulator +} + +pub(crate) unconstrained fn __batch_invert( + params: P, + x: [[Field; N]; M], +) -> [[Field; N]; M] { + // TODO: ugly! Will fail if input slice is empty + let mut accumulator: [Field; N] = __one::(); + let mut result: [[Field; N]; M] = [[0; N]; M]; + let mut temporaries: [[Field; N]] = &[]; + for i in 0..x.len() { + temporaries = temporaries.push_back(accumulator); + if (__is_zero(x[i]) == false) { + accumulator = __mul::<_, MOD_BITS>(params, accumulator, x[i]); + } + } + + accumulator = __invmod::<_, MOD_BITS>(params, accumulator); + let mut T0: [Field; N] = [0; N]; + for i in 0..x.len() { + let idx = x.len() - 1 - i; + if (__is_zero(x[idx]) == false) { + T0 = __mul::<_, MOD_BITS>(params, accumulator, temporaries[idx]); + accumulator = __mul::<_, MOD_BITS>(params, accumulator, x[idx]); + result[idx] = T0; + } + } + result +} + +pub(crate) unconstrained fn __batch_invert_slice( + params: P, + x: [[Field; N]], +) -> [[Field; N]] { + // TODO: ugly! Will fail if input slice is empty + let mut accumulator: [Field; N] = __one::(); + let mut result: [[Field; N]] = [[0; N]]; + let mut temporaries: [[Field; N]] = &[]; + for i in 0..x.len() { + temporaries = temporaries.push_back(accumulator); + if (__is_zero(x[i]) == false) { + accumulator = __mul::<_, MOD_BITS>(params, accumulator, x[i]); + } + result = result.push_back([0; N]); + } + + accumulator = __invmod::<_, MOD_BITS>(params, accumulator); + let mut T0: [Field; N] = [0; N]; + for i in 0..x.len() { + let idx = x.len() - 1 - i; + if (__is_zero(x[idx]) == false) { + T0 = __mul::<_, MOD_BITS>(params, accumulator, temporaries[idx]); + accumulator = __mul::<_, MOD_BITS>(params, accumulator, x[idx]); + result[idx] = T0; + } + } + result +} + +/** +* @brief compute a modular square root using the Tonelli-Shanks algorithm +* @details only use for prime fields! Function may infinite loop if used for non-prime fields +* @note this is unconstrained fn. To constrain a square root, validate that output^2 = self +* TODO: create fn that constrains nonexistence of square root (i.e. find x where x^2 = -self) +**/ +pub(crate) unconstrained fn __tonelli_shanks_sqrt( + params: P, + input: [Field; N], +) -> std::option::Option<[Field; N]> { + // Tonelli-shanks algorithm begins by finding a field element Q and integer S, + // such that (p - 1) = Q.2^{s} + // We can compute the square root of a, by considering a^{(Q + 1) / 2} = R + // Once we have found such an R, we have + // R^{2} = a^{Q + 1} = a^{Q}a + // If a^{Q} = 1, we have found our square root. + // Otherwise, we have a^{Q} = t, where t is a 2^{s-1}'th root of unity. + // This is because t^{2^{s-1}} = a^{Q.2^{s-1}}. + // We know that (p - 1) = Q.w^{s}, therefore t^{2^{s-1}} = a^{(p - 1) / 2} + // From Euler's criterion, if a is a quadratic residue, a^{(p - 1) / 2} = 1 + // i.e. t^{2^{s-1}} = 1 + // To proceed with computing our square root, we want to transform t into a smaller subgroup, + // specifically, the (s-2)'th roots of unity. + // We do this by finding some value b,such that + // (t.b^2)^{2^{s-2}} = 1 and R' = R.b + // Finding such a b is trivial, because from Euler's criterion, we know that, + // for any quadratic non-residue z, z^{(p - 1) / 2} = -1 + // i.e. z^{Q.2^{s-1}} = -1 + // => z^Q is a 2^{s-1}'th root of -1 + // => z^{Q^2} is a 2^{s-2}'th root of -1 + // Since t^{2^{s-1}} = 1, we know that t^{2^{s - 2}} = -1 + // => t.z^{Q^2} is a 2^{s - 2}'th root of unity. + // We can iteratively transform t into ever smaller subgroups, until t = 1. + // At each iteration, we need to find a new value for b, which we can obtain + // by repeatedly squaring z^{Q} + let one_u60: U60Repr = unsafe { U60Repr::one() }; + let primitive_root_log_size = __primitive_root_log_size::<_, MOD_BITS>(params); + let mut Q = (params.modulus_u60 - one_u60).shr(primitive_root_log_size - 1); + let Q_minus_one_over_two_u60 = (Q - one_u60).shr(2); + let Q_minus_one_over_two: [Field; N] = U60Repr::into(Q_minus_one_over_two_u60); + let mut z = __multiplicative_generator::<_, MOD_BITS>(params); // the generator is a non-residue + let mut b = __pow::<_, MOD_BITS>(params, input, Q_minus_one_over_two); + let mut r = __mul::<_, MOD_BITS>(params, input, b); + let mut t = __mul::<_, MOD_BITS>(params, r, b); + let mut check: [Field; N] = t; + for _ in 0..primitive_root_log_size - 1 { + check = __mul::<_, MOD_BITS>(params, check, check); + } + let mut found_root = false; + let one: [Field; N] = __one::(); + if (__eq(check, one) == false) {} else { + let mut t1 = __pow::<_, MOD_BITS>(params, z, Q_minus_one_over_two); + let mut t2 = __mul::<_, MOD_BITS>(params, t1, z); + let mut c = __mul::<_, MOD_BITS>(params, t2, t1); + let mut m: u32 = primitive_root_log_size; + // tonelli shanks inner 1 + // (if t2m == 1) then skip + // else increase i and square t2m and go again + // algorithm runtime should only be max the number of bits in modulus + for _ in 0..MOD_BITS { + if (__eq(t, one)) { + found_root = true; + break; + } + let mut t2m = t; + // while loop time + let i = __tonelli_shanks_sqrt_inner_loop_check::<_, MOD_BITS>(params, t2m, 0); + let mut j = m - i - 1; + b = c; + for _ in 0..j { + // how big + if (j == 0) { + break; + } + b = __mul(params, b, b); + //j -= 1; + } + c = __mul::<_, MOD_BITS>(params, b, b); + t = __mul::<_, MOD_BITS>(params, t, c); + r = __mul::<_, MOD_BITS>(params, r, b); + m = i; + } + } + let result = if found_root { + std::option::Option::some(r) + } else { + std::option::Option::none() + }; + result +} diff --git a/src/lib.nr b/src/lib.nr index 32026120..60b25d8d 100644 --- a/src/lib.nr +++ b/src/lib.nr @@ -1,320 +1,22 @@ -pub(crate) mod utils; -mod bignum_test; -pub mod fields; -pub(crate) mod runtime_bignum; -mod runtime_bignum_test; - -pub use crate::utils::u60_representation::U60Repr; -pub use crate::runtime_bignum::BigNumInstance as RuntimeBigNumInstance; -pub use crate::runtime_bignum::BigNumInstanceTrait as RuntimeBigNumInstanceTrait; -pub use crate::runtime_bignum::BigNumParamsTrait as RuntimeBigNumParamsTrait; -pub use crate::runtime_bignum::BigNumTrait as RuntimeBigNumTrait; - -pub struct BigNum { - limbs: [Field; N] -} - -/** - * @brief BigNumParamsTrait defines a "field" with which to parametrise BigNum. - * @description The "field" does not need to be prime, any value *should* work (TODO: test!) -**/ -// -// trait BigNumParamsTrait where Params: RuntimeBigNumParamsTrait, RuntimeBigNumInstance: RuntimeBigNumInstanceTrait> { -pub trait BigNumParamsTrait where Self: RuntimeBigNumParamsTrait { - - fn get_instance() -> RuntimeBigNumInstance where Self: RuntimeBigNumParamsTrait;// ; - - /** - * @brief modulus_bits = log2(modulus) rounded up - **/ - fn modulus_bits() -> u32; - - fn has_multiplicative_inverse() -> bool { true } -} - -pub trait BigNumTrait where BigNumTrait: std::ops::Add + std::ops::Sub + std::ops::Mul + std::ops::Div + std::ops::Eq + RuntimeBigNumTrait { - // TODO: this crashes the compiler? v0.32 - // fn default() -> Self { std::default::Default::default () } - fn from(limbs: [Field]) -> Self { RuntimeBigNumTrait::from(limbs) } - fn new() -> Self { RuntimeBigNumTrait::new() } - fn one() -> Self { RuntimeBigNumTrait::one() } - fn modulus() -> Self; - fn modulus_bits(self) -> u32; - fn num_limbs(self) -> u32; - fn derive_from_seed(seed: [u8; SeedBytes]) -> Self; - unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self; - unconstrained fn __pow(self, exponent: Self) -> Self; - unconstrained fn __neg(self) -> Self; - unconstrained fn __add(self, other: Self) -> Self; - unconstrained fn __sub(self, other: Self) -> Self; - unconstrained fn __mul(self, other: Self) -> Self; - unconstrained fn __div(self, other: Self) -> Self; - unconstrained fn __udiv_mod(self, divisor: Self) -> (Self, Self); - unconstrained fn __invmod(self) -> Self; - unconstrained fn __batch_invert(to_invert: [Self; M]) -> [Self; M]; - unconstrained fn __is_zero(self) -> bool { RuntimeBigNumTrait::__is_zero(self) } - unconstrained fn __eq(self, other: Self) -> bool { RuntimeBigNumTrait::__eq(self, other) } - unconstrained fn __compute_quadratic_expression(lhs: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], rhs: [[Self; RHS_N]; NUM_PRODUCTS], rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], add: [Self; ADD_N], add_flags: [bool; ADD_N]) -> (Self, Self); - fn evaluate_quadratic_expression(lhs: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], rhs: [[Self; RHS_N]; NUM_PRODUCTS], rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], add: [Self; ADD_N], add_flags: [bool; ADD_N]); - fn validate_in_range(self){ RuntimeBigNumTrait::validate_in_range(self) } - fn validate_in_field(self); - fn assert_is_not_equal(self, other: Self); - fn neg(self) -> Self; - fn add(self, other: Self) -> Self { self + other } - fn sub(self, other: Self) -> Self { self - other } - fn mul(self, other: Self) -> Self { self * other } - fn div(self, other: Self) -> Self { self / other } - fn udiv_mod(self, divisor: Self) -> (Self, Self); - fn udiv(self, divisor: Self) -> Self; - fn umod(self, divisor: Self) -> Self; - fn eq(self, other: Self) -> bool { self == other } - fn get(self) -> [Field] { RuntimeBigNumTrait::get(self) } - fn get_limb(self, idx: u64) -> Field { RuntimeBigNumTrait::get_limb(self, idx) } - fn set_limb(&mut self, idx: u32, value: Field) { RuntimeBigNumTrait::set_limb(self, idx, value) } - fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self { RuntimeBigNumTrait::conditional_select(lhs, rhs, predicate) } - fn to_le_bytes(self) -> [u8; X] { RuntimeBigNumTrait::to_le_bytes(self) } - unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option; -} - -impl BigNumTrait for BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { - - // Weird compiler issue where if we do not pass `Self` as a parameter to these methods, - // then a generic struct that conforms to BigNumTrait cannot access these methods? - // the Params: BigNumParamsTrait needs to be satisfied, but the BigNumTrait has no knowledge of BigNumParamsTrait? - // but...passing in a Self parameter seems to fix. really weird - fn modulus_bits(_: Self) -> u32 { - let r: u32 = Params::modulus_bits(); - r - } - fn num_limbs(_: Self) -> u32 { - N - } - - fn modulus() -> Self { - Params::get_instance().modulus() - } - - // #################################################################################################################### - // #################################################################################################################### - // ### C O N S T R U C T O R S - // #################################################################################################################### - // #################################################################################################################### - // fn new() -> Self { - // BigNum { limbs: [0; N] } - // } - - // fn one() -> Self { - // let mut result = BigNum::new(); - // result.limbs[0] = 1; - // result - // } - - // #################################################################################################################### - // #################################################################################################################### - // ### U N C O N S T R A I N E D F U N C T I O N S - // ### NOTE: these functions call unconstrained internal implementations because trait impl modifiers are not supported - // #################################################################################################################### - // #################################################################################################################### - unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self { - Params::get_instance().__derive_from_seed(seed) - } - - fn derive_from_seed(seed: [u8; SeedBytes]) -> Self { - Params::get_instance().derive_from_seed(seed) - } - unconstrained fn __neg(self) -> Self { - Params::get_instance().__neg(self) - } - - unconstrained fn __add(self, rhs: Self) -> Self { - Params::get_instance().__add(self, rhs) - } - - unconstrained fn __sub(self, rhs: Self) -> Self { - Params::get_instance().__sub(self, rhs) - } - - unconstrained fn __mul(self, rhs: Self) -> Self { - Params::get_instance().__mul(self, rhs) - } +// BigNum +pub mod bignum; - unconstrained fn __div(self, rhs: Self) -> Self { - Params::get_instance().__div(self, rhs) - } +// RuntimeBigNum +pub mod runtime_bignum; - unconstrained fn __batch_invert(x: [Self; M]) -> [Self; M] { - assert(Params::has_multiplicative_inverse()); - Params::get_instance().__batch_invert(x) - } - - unconstrained fn __invmod(self) -> Self { - assert(Params::has_multiplicative_inverse()); - Params::get_instance().__invmod(self) - } - - unconstrained fn __pow(self, exponent: Self) -> Self { - Params::get_instance().__pow(self, exponent) - } - - unconstrained fn __compute_quadratic_expression( - lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], - lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], - rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [Self; ADD_N], - linear_flags: [bool; ADD_N] - ) -> (Self, Self) { - Params::get_instance().__compute_quadratic_expression( - lhs_terms, - lhs_flags, - rhs_terms, - rhs_flags, - linear_terms, - linear_flags - ) - } - - // #################################################################################################################### - // #################################################################################################################### - // ### C O N S T R A I N E D F U N C T I O N S - // #################################################################################################################### - // #################################################################################################################### - - /** - * @brief Constrain a degree-2 BigNum expression to be equal to 0 modulo Params::modulus() - * @description The expression is of the form (when evaluated as an integer relation): - * - * \sum_{i=0}^{NUM_PRODUCTS - 1} ((\sum_{j=0}^{LHS_N-1}lhs[i][j]) * (\sum_{j=0}^{RHS_N-1}rhs[i][j])) + \sum_{i=0}^{ADD_N - 1}linear_terms[i] - quotient * modulus = 0 - * - * The intent is to capture an arbitrary degree-2 expression within the limitations of Noir (no efficient dynamically-sized vectors) - * - * Note: this method requires the remainder term of the expression to be ZERO - * When performing BigNum arithmetic, we want to represent desired BigNum operations in a way that minimizes the number of modular reductions that are required. - * This can be achieved by minimizing the number of degree-2 relations required. - * - * The expensive parts of this algorithm are the following: - * 1. evaluating the limb products required to compute `lhs * rhs` - * 2. applying range constraints to validate the result is 0 - * - * Range constraints are needed for the following reason: - * When evaluating the above expression over N-limb BigNum objects, the result will consist of 2N - 1 limbs. - * Each limb will be in the range [0, ..., 2^{240 + twiddle_factor} - 1] (twiddle_factor needs to be less than 6). - * Because of the subtractions, the limbs may underflow and represent NEGATIVE values. - * To account for this, we allow the Prover to borrow values from more significant limbs and add them into less significant limbs - * (explicitly, we can borrow 2^{126} from limb `i + 1` to add `2^{246}` into `i`). - * To ensure this has been done correctly, we validate that the borrow-adjusted limbs are all-zero for the first 120 bits. - * We do *this* by multiplying the borrow-adjusted limbs by 1 / 2^{120} modulo CircutModulus, and we validate the result is in the range [0, ..., 2^{126} - 1]. - * TODO: explain why this check works. It's statistically sound but not perfectly sound. Chance of the check failing is ~1 in 2^{120} - * I believe this is the most efficient way of performing the zero-check for this relation as it only requires `2N - 2` 126-bit range checks. - * TODO: explain why we apply a 126-bit range check, this feels like a magic number - * (it is. we could go higher, up to the number of bits in the CircuitModulus - 121, but 126 *should be* sufficient and is much cheaper) - * TODO: apply checks in this method to validate twiddle_factor does not exceed 6 - * - * @param lhs_terms a 2D array of BigNum - * @param lhs_flags a 2D array of sign flags - * @param rhs_terms a 2D array of BigNum - * @param rhs_flags a 2D array of sign flags - * @param linear_terms an array of BigNum - * @param linear_flags an array of sign flags - **/ - fn evaluate_quadratic_expression( - lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], - lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], - rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [Self; ADD_N], - linear_flags: [bool; ADD_N] - ) { - Params::get_instance().evaluate_quadratic_expression( - lhs_terms, - lhs_flags, - rhs_terms, - rhs_flags, - linear_terms, - linear_flags - ) - } - - fn validate_in_field(self: Self) { - Params::get_instance().validate_in_field(self); - } - - /** - * @brief Validate self != other - * @details If A == B, then A == B mod N. - * We can efficiently evaluate A == B mod N where N = circuit modulus - * This method is *sound*, but not *complete* (i.e. A != B but A == B mod N) - * However the probability of an honest Prover being unable to satisfy this check is tiny! - * (todo: compute how tiny) - **/ - fn assert_is_not_equal(self, other: Self) { - Params::get_instance().assert_is_not_equal(self, other); - } - - fn neg(self) -> Self { - Params::get_instance().neg(self) - } - - unconstrained fn __udiv_mod(self, divisor: Self) -> (Self, Self) { - Params::get_instance().__udiv_mod(self, divisor) - } - - fn udiv_mod(self, divisor: Self) -> (Self, Self) { - Params::get_instance().udiv_mod(self, divisor) - } - - fn udiv(self, divisor: Self) -> Self { - Params::get_instance().udiv(self, divisor) - } - - fn umod(self, divisor: Self) -> Self { - Params::get_instance().umod(self, divisor) - } - - unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option { - Params::get_instance().__tonelli_shanks_sqrt(self) - } -} - -impl BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait {} - -impl std::ops::Add for BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { - // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them - // via evaluate_quadratic_expression - fn add(self, other: Self) -> Self { - Params::get_instance().add(self, other) - } -} - -impl std::ops::Sub for BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { - // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them - // via evaluate_quadratic_expression - fn sub(self, other: Self) -> Self { - Params::get_instance().sub(self, other) - } -} +// Pre-defined fields and bignums for people to use: +pub mod fields; -impl std::ops::Mul for BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { - // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them - // via evaluate_quadratic_expression - // e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression` - // will create much fewer constraints than calling `mul` and `add` directly - fn mul(self, other: Self) -> Self { - Params::get_instance().mul(self, other) - } -} +// Structs enabling people to define their own bignum params +pub mod params; -impl std::ops::Div for BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { - // Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation - fn div(self, other: Self) -> Self { - Params::get_instance().div(self, other) - } -} +// Free functions and other utils, called by the BigNum and RuntimeBigNum structs +pub(crate) mod fns; +pub(crate) mod utils; -impl std::cmp::Eq for BigNum where Params: BigNumParamsTrait + RuntimeBigNumParamsTrait { +// Re-export the main structs so that users don't have to specify the paths +pub use bignum::BigNum; +pub use runtime_bignum::RuntimeBigNum; - fn eq(self, other: Self) -> bool { - let bn: RuntimeBigNumInstance = Params::get_instance(); - bn.eq(self, other) - } -} +// Tests +mod tests; diff --git a/src/params.nr b/src/params.nr new file mode 100644 index 00000000..01854ab3 --- /dev/null +++ b/src/params.nr @@ -0,0 +1,53 @@ +use crate::utils::u60_representation::U60Repr; + +pub struct BigNumParams { + pub has_multiplicative_inverse: bool, + + // @brief modulus: all BigNum operations are evaluated modulo this value + pub modulus: [Field; N], + + // @brief modulus but represented in a U60Repr form + pub modulus_u60: U60Repr, + pub modulus_u60_x4: U60Repr, + + // @brief double_modulus: used when performing negations and subtractions + pub double_modulus: [Field; N], + + // @brief redc_param used for __barrett_reduction. See https://en.wikipedia.org/wiki/Barrett_reduction + pub redc_param: [Field; N], +} + +// To be implemented by the user for any BigNum they define, or within the predefined BigNums in the `fields/` dir. +pub trait BigNumParamsGetter { + pub fn get_params() -> BigNumParams; +} + +impl BigNumParams { + pub fn new( + has_multiplicative_inverse: bool, + modulus: [Field; N], + redc_param: [Field; N], + ) -> Self { + Self { + has_multiplicative_inverse, + modulus, + modulus_u60: U60Repr::from(modulus), + modulus_u60_x4: U60Repr::from(modulus), + double_modulus: get_double_modulus(modulus), + redc_param, + } + } +} + +fn get_double_modulus(modulus: [Field; N]) -> [Field; N] { + let TWO_POW_120: Field = 0x1000000000000000000000000000000; + let m: U60Repr = U60Repr::from(modulus); + let mut result: [Field; N] = U60Repr::into(m + m); + + result[0] += TWO_POW_120; + for i in 1..N - 1 { + result[i] += (TWO_POW_120 - 1); + } + result[N - 1] -= 1; + result +} diff --git a/src/runtime_bignum.nr b/src/runtime_bignum.nr index 98c708d2..66e091eb 100644 --- a/src/runtime_bignum.nr +++ b/src/runtime_bignum.nr @@ -1,1876 +1,425 @@ -use crate::utils::u60_representation::U60Repr; -use crate::utils::split_bits; -use crate::BigNum; -/** - * @brief runtime_bignum::BigNumTrait defines methods available to BigNum *if* the modulus is not known at compile time. - * e.g. RSA where the modulus is a witness value as it changes for every RSA signature - * tee `lib.nr` for a trait definition where the modulus is known at compile time - **/ -pub trait BigNumTrait { - fn new() -> Self; - fn one() -> Self; - fn from(limbs: [Field]) -> Self; - fn from_be_bytes(x: [u8; NBytes]) -> Self; - fn to_le_bytes(val: Self) -> [u8; NBytes]; - fn get(self) -> [Field]; - fn get_limb(self, idx: u64) -> Field; - fn set_limb(&mut self, idx: u32, value: Field); - fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; - fn validate_in_range(self); - fn validate_quotient_in_range(self); - unconstrained fn __is_zero(self) -> bool; - unconstrained fn __eq(self, rhs: Self) -> bool; +use dep::std; +use crate::utils::map::map; + +use crate::params::BigNumParams; + +use crate::fns::{ + constrained_ops::{ + derive_from_seed, conditional_select, assert_is_not_equal, eq, validate_in_field, + validate_in_range, neg, add, sub, mul, div, udiv_mod, udiv, umod, + }, + unconstrained_ops::{ + __derive_from_seed, __eq, __is_zero, __neg, __add, __sub, __mul, __div, __udiv_mod, + __invmod, __pow, __batch_invert, __batch_invert_slice, __tonelli_shanks_sqrt, + }, expressions::{__compute_quadratic_expression, evaluate_quadratic_expression}, + serialization::{from_be_bytes, to_le_bytes}, +}; + +pub struct RuntimeBigNum { + pub limbs: [Field; N], + pub params: BigNumParams, } -/** - * @brief BARRETT_REDUCTION_OVERFLOW_BITS defines how large an input to barrett reduction can be - * @details maximum value = modulus^2 < where BN: BigNumTrait { - fn modulus(self) -> BN; - fn eq(self, lhs: BN, rhs: BN) -> bool; - fn derive_from_seed(self, seed: [u8; SeedBytes]) -> BN; - unconstrained fn __derive_from_seed(self, seed: [u8; SeedBytes]) -> BN; - unconstrained fn __neg(self, val: BN) -> BN; - unconstrained fn __add(self, lhs: BN, rhs: BN) -> BN; - unconstrained fn __sub(self, lhs: BN, rhs: BN) -> BN; - unconstrained fn __mul(self, lhs: BN, rhs: BN) -> BN; - unconstrained fn __div(self, lhs: BN, rhs: BN) -> BN; - unconstrained fn __batch_invert(self, x: [BN; M]) -> [BN; M]; - unconstrained fn __udiv_mod(self, numerator: BN, divisor: BN) -> (BN, BN); - unconstrained fn __invmod(self, val: BN) -> BN; - unconstrained fn __pow(self, val: BN, exponent: BN) -> BN; - unconstrained fn __compute_quadratic_expression( - self, - lhs_terms: [[BN; LHS_N]; NUM_PRODUCTS], +impl RuntimeBigNum {} + +// All functions prefixed `__` are unconstrained! +// They're not actually decorated as `unconstrained` because to return the `params` (as part of Self) from an `unconstrained` fn would cause range constraints. Instead, each `__` fn wraps a call to an unconstrained fn, so that the already-range-constrained `params` can be inserted into Self after the unconstrained call. +pub(crate) trait RuntimeBigNumTrait { + pub fn new(params: BigNumParams) -> Self; + pub fn one(params: BigNumParams) -> Self; + pub fn derive_from_seed( + params: BigNumParams, + seed: [u8; SeedBytes], + ) -> Self; + pub fn __derive_from_seed( + params: BigNumParams, + seed: [u8; SeedBytes], + ) -> Self; + pub fn from_slice(params: BigNumParams, limbs: [Field]) -> Self; + pub fn from_array(params: BigNumParams, limbs: [Field; N]) -> Self; + pub fn from_be_bytes( + params: BigNumParams, + x: [u8; NBytes], + ) -> Self; + + pub fn to_le_bytes(self) -> [u8; NBytes]; + + pub fn modulus(self) -> Self; + pub fn modulus_bits() -> u32; + pub fn num_limbs() -> u32; + // pub fn get(self) -> [Field]; + pub fn get_limbs(self) -> [Field; N]; + pub fn get_limb(self, idx: u32) -> Field; + pub fn set_limb(&mut self, idx: u32, value: Field); + + unconstrained fn __eq(self, other: Self) -> bool; + unconstrained fn __is_zero(self) -> bool; + + // unconstrained + pub fn __neg(self) -> Self; + // unconstrained + pub fn __add(self, other: Self) -> Self; + // unconstrained + pub fn __sub(self, other: Self) -> Self; + // unconstrained + pub fn __mul(self, other: Self) -> Self; + // unconstrained + pub fn __div(self, other: Self) -> Self; + // unconstrained + pub fn __udiv_mod(self, divisor: Self) -> (Self, Self); + // unconstrained + pub fn __invmod(self) -> Self; + // unconstrained + pub fn __pow(self, exponent: Self) -> Self; + + // unconstrained + pub fn __batch_invert(x: [Self; M]) -> [Self; M]; + unconstrained fn __batch_invert_slice(to_invert: [Self]) -> [Self]; + + pub fn __tonelli_shanks_sqrt(self) -> std::option::Option; + + // unconstrained + pub fn __compute_quadratic_expression( + params: BigNumParams, + lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BN; RHS_N]; NUM_PRODUCTS], + rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BN; ADD_N], - linear_flags: [bool; ADD_N] - ) -> (BN, BN); + linear_terms: [Self; ADD_N], + linear_flags: [bool; ADD_N], + ) -> (Self, Self); - fn evaluate_quadratic_expression( - self, - lhs_terms: [[BN; LHS_N]; NUM_PRODUCTS], + pub fn evaluate_quadratic_expression( + params: BigNumParams, + lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BN; RHS_N]; NUM_PRODUCTS], + rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BN; ADD_N], - linear_flags: [bool; ADD_N] + linear_terms: [Self; ADD_N], + linear_flags: [bool; ADD_N], ); - fn validate_in_field(self, val: BN); - fn validate_gt(self, lhs: BN, rhs: BN); - fn assert_is_not_equal(self, lhs: BN, rhs: BN); - fn neg(self, val: BN) -> BN; - fn add(self, lhs: BN, rhs: BN) -> BN; - fn sub(self, lhs: BN, rhs: BN) -> BN; - fn mul(self, lhs: BN, rhs: BN) -> BN; - fn div(self, lhs: BN, rhs: BN) -> BN; - fn udiv_mod(self, numerator: BN, divisor: BN) -> (BN, BN); - fn udiv(self, numerator: BN, divisor: BN) -> BN; - fn umod(self, numerator: BN, divisor: BN) -> BN; - -unconstrained fn __tonelli_shanks_sqrt(self, input: BN) -> std::option::Option; -} - -/** - * @brief BigNumParamsTrait defines a "field" with which to parametrise BigNum. - * @description The "field" does not need to be prime, any value *should* work (TODO: test!) -**/ -pub trait BigNumParamsTrait { - /** - * @brief modulus_bits = log2(modulus) rounded up - **/ - fn modulus_bits() -> u32; - - fn has_multiplicative_inverse() -> bool { true } -} - -pub struct BigNumInstance { - - /** - * @brief modulus: all BigNum operations are evaluated modulo this value - **/ - modulus: [Field; N], - - /** - * @brief modulus but represented in a U60Repr form - **/ - modulus_u60: U60Repr, - modulus_u60_x4: U60Repr, - - // /** - // * @brief double_modulus: used when performing negations and subtractions - // **/ - double_modulus: [Field; N], - // /** - // * @brief redc_param used for __barrett_reduction. See https://en.wikipedia.org/wiki/Barrett_reduction - // **/ - redc_param: [Field; N], -} - -impl BigNum { - // some strange circular dependency problem means we need to define `new` as a member of BigNumTrait as well as a definition outside of the trait - // (delete this method to see. BigNumInstance methods that use BigNum::new() error out, and I can't find a way of declaring BigNum to satisfy BigNumTrait as part of the BigNumInstance definition because BigNumInstance has no contextual knowledge of the BigNum type...) - fn new() -> Self { - BigNum { limbs: [0; N] } - } - fn one() -> BigNum { - let mut result: Self = BigNum { limbs: [0; N] }; - result.limbs[0] = 1; - result + pub fn eq(lhs: Self, rhs: Self) -> bool { + lhs == rhs } -} + pub fn assert_is_not_equal(self, other: Self); + pub fn validate_in_field(self); + pub fn validate_in_range(self); + // pub fn validate_gt(self, lhs: Self, rhs: Self); -impl BigNumTrait for BigNum where Params: BigNumParamsTrait { - - fn new() -> Self { - BigNum::new() + pub fn neg(self) -> Self; + pub fn add(lhs: Self, rhs: Self) -> Self { + lhs + rhs } - fn one() -> Self { - BigNum::one() + pub fn sub(lhs: Self, rhs: Self) -> Self { + lhs - rhs } - - fn from(limbs: [Field]) -> Self { - BigNum { limbs: limbs.as_array() } + pub fn mul(lhs: Self, rhs: Self) -> Self { + lhs * rhs } + pub fn div(lhs: Self, rhs: Self) -> Self { + lhs / rhs + } + pub fn udiv_mod(numerator: Self, divisor: Self) -> (Self, Self); + pub fn udiv(numerator: Self, divisor: Self) -> Self; + pub fn umod(numerator: Self, divisor: Self) -> Self; - /** - * @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 Params::modulus_bits() - * @param x: input byte array - **/ - fn from_be_bytes(x: [u8; NBytes]) -> BigNum { - let num_bits = NBytes * 8; - let modulus_bits = Params::modulus_bits(); - assert(num_bits >= modulus_bits); - assert(num_bits - modulus_bits < 8); - let mut result = BigNum::new(); - - let excess_bytes = N * 15 - NBytes; - let final_limb_bytes = 15 - excess_bytes; - let mut limb: Field = 0; - let mut k = 0; - for _j in 0..final_limb_bytes { - limb *= 256; - limb += x[k] as Field; - k += 1; - } - result.limbs[N - 1] = limb; - - for i in 1..N { - let mut limb: Field = 0; - for _j in 0..15 { - limb *= 256; - limb += x[k] as Field; - k += 1; - } - result.limbs[N - i - 1] = limb; - } - - // max_bits_in_most_significant_byte should be known at comptime. if not...messy! - let mut max_bits_in_most_significant_byte = 8 - (num_bits - modulus_bits); + pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; +} - let most_significant_byte: Field = x[0] as Field; +impl RuntimeBigNumTrait for RuntimeBigNum { - most_significant_byte.assert_max_bit_size(max_bits_in_most_significant_byte as u32); - result + fn new(params: BigNumParams) -> Self { + let limbs: [Field; N] = [0; N]; + Self { limbs, params } } - fn to_le_bytes(val: BigNum) -> [u8; NBytes] { - let nbytes = (Params::modulus_bits() / 8) + (Params::modulus_bits() % 8 != 0) as u32; - assert(nbytes <= NBytes); - - let mut result: [u8; NBytes] = [0; NBytes]; - for i in 0..N - 1 { - let limb_bytes: [u8; 15] = val.limbs[i].to_le_bytes(); - for j in 0..15 { - result[i * 15 + j] = limb_bytes[j]; - } - } - let last_limb_bytes: [u8; 15] = val.limbs[N - 1].to_le_bytes(); - let num_last_bytes = (NBytes - (N - 1) * 15); - for i in 0..num_last_bytes { - result[(N-1) * 15 + i] = last_limb_bytes[i]; - } + fn one(params: BigNumParams) -> Self { + let mut result = RuntimeBigNum::new(params); + result.limbs[0] = 1; result } - fn get(self) -> [Field] { - self.limbs - } - fn get_limb(self, idx: u64) -> Field { - self.limbs[idx] - } - fn set_limb(&mut self, idx: u32, value: Field) { - self.limbs[idx] = value; + fn derive_from_seed( + params: BigNumParams, + seed: [u8; SeedBytes], + ) -> Self { + let limbs = unsafe { derive_from_seed::<_, MOD_BITS, _>(params, seed) }; + Self { limbs, params } } - /** - * @brief conditional_select given the value of `predicate` return either `self` (if 0) or `other` (if 1) - * @description should be cheaper than using an IF statement (TODO: check!) - **/ - fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self { - let mut result: Self = lhs; - for i in 0..N { - result.limbs[i] = (lhs.limbs[i] - rhs.limbs[i]) * predicate as Field + rhs.limbs[i]; - } - result + // UNCONSTRAINED! (Hence `__` prefix). + fn __derive_from_seed( + params: BigNumParams, + seed: [u8; SeedBytes], + ) -> Self { + let limbs = unsafe { __derive_from_seed::<_, MOD_BITS, _>(params, seed) }; + Self { limbs, params } } - /** - * @brief Validate a BigNum instance is correctly range constrained to contain no more than Params::modulus_bits() - **/ - fn validate_in_range(self) { - for i in 0..(N - 1) { - self.limbs[i].assert_max_bit_size(120); - } - let final_limb_bits = Params::modulus_bits() - ((N - 1) * 120); - self.limbs[N - 1].assert_max_bit_size(final_limb_bits as u32); + fn from_slice(params: BigNumParams, limbs: [Field]) -> Self { + Self { limbs: limbs.as_array(), params } } - /** - * @brief validate quotient produced from `evaluate_quadratic_expression` is well-formed - * @description because the inputs into evaluate_quadratic_expression may cause the quotient to extend beyond `Params::modulus_bits`. - * We allow the quotient to extend 6 bits beyond Params::modulus_bits() - * Why is this? - * several factors: 1. quotient * modulus , limbs cannot overflow field boundary (254 bits) - * 2. in `evaluate_quadratic_expression`, we require that for `expression - quotient * modulus`, - * limbs cannot exceed 246 bits (246 magic number due to a higher number adding extra range check gates) - * because of factor 2 and the fact that modulus limbs are 120 bits, quotient limbs cannot be >126 bits - * - * Note: doesn't this mean that final_limb_bits should be constrained to be 126 bits, not modulus_bits() - ((N - 1) * 120) + 6? - * TODO: think about this more! we want the range constraint we apply to be as small as allowable as this is more efficient - **/ - fn validate_quotient_in_range(self) { - for i in 0..(N) { - self.limbs[i].assert_max_bit_size(120); - } - // Note: replace magic number 6 with definition - let final_limb_bits = Params::modulus_bits() - ((N - 1) * 120) + 6; - self.limbs[N - 1].assert_max_bit_size(final_limb_bits as u32); + fn from_array(params: BigNumParams, limbs: [Field; N]) -> Self { + Self { limbs, params } } - unconstrained fn __is_zero(self) -> bool { - self.__is_zero_impl() + fn from_be_bytes(params: BigNumParams, x: [u8; NBytes]) -> Self { + Self { limbs: from_be_bytes::<_, MOD_BITS, _>(x), params } } - unconstrained fn __eq(self, rhs: Self) -> bool { - self.__eq_impl(rhs) + fn to_le_bytes(self) -> [u8; NBytes] { + to_le_bytes::<_, MOD_BITS, _>(self.limbs) } -} - -impl BigNum where Params: BigNumParamsTrait { - fn from_array(limbs: [Field; N]) -> BigNum { - BigNum { limbs } + fn modulus(self) -> Self { + let params = self.params; + Self { limbs: params.modulus, params } } - unconstrained fn __is_zero_impl(self) -> bool { - let mut result: bool = true; - for i in 0..N { - result = result & (self.limbs[i] == 0); - } - result + fn modulus_bits() -> u32 { + MOD_BITS } - unconstrained fn __eq_impl(lhs: Self, rhs: Self) -> bool { - lhs.limbs == rhs.limbs + fn num_limbs() -> u32 { + N } -} -impl BigNumInstance where Params: BigNumParamsTrait { + // fn get(self) -> [Field] { + // self.get_limbs() + // } - /** - * @brief compute the log of the size of the primitive root - * @details find the maximum value k where x^k = 1, where x = primitive root - * This is needed for our Tonelli-Shanks sqrt algorithm - **/ - unconstrained fn primitive_root_log_size(self) -> u32 { - let mut target: U60Repr = self.modulus_u60 - U60Repr::one(); - let mut result: u32 = 0; - for _ in 0..Params::modulus_bits() { - let lsb_is_one = (target.limbs[0] & 1) == 1; - if (!lsb_is_one) { - result += 1; - target.shr1(); - } else { - break; - } - } - result + fn get_limbs(self) -> [Field; N] { + self.limbs } - /** - * @brief inner loop fn for `find_multiplive_generator` - * @details recursive function to get around the lack of a `while` keyword - **/ - unconstrained fn recursively_find_multiplicative_generator( - self, - target: BigNum, - p_minus_one_over_two: BigNum - ) -> (bool, BigNum) { - let exped = (self.__pow(target, p_minus_one_over_two)); - let found = exped.__eq(self.__neg(BigNum::one())); - let mut result: (bool, BigNum) = (found, target); - if (!found) { - let _target = unsafe { - self.__add(target, BigNum::one()) - }; - result = self.recursively_find_multiplicative_generator(_target, p_minus_one_over_two); - } - result + fn get_limb(self, idx: u32) -> Field { + self.limbs[idx] } - /** - * @brief find multiplicative generator `g` where `g` is the smallest value that is not a quadratic residue - * i.e. smallest g where g^2 = -1 - * @note WARNING if multiplicative generator does not exist, this function will enter an infinite loop! - **/ - unconstrained fn multiplicative_generator(self) -> BigNum { - let mut target = BigNum::one(); - let p_minus_one_over_two: U60Repr = (self.modulus_u60 - U60Repr::one()).shr(1); - let p_minus_one_over_two: BigNum = BigNum::from_array(U60Repr::into(p_minus_one_over_two)); - - let (_, target) = self.recursively_find_multiplicative_generator(target, p_minus_one_over_two); - target + fn set_limb(&mut self, idx: u32, value: Field) { + self.limbs[idx] = value; } - unconstrained fn __tonelli_shanks_sqrt_inner_loop_check(self, t2m: BigNum, i: u32) -> u32 { - let is_one = t2m.__eq(BigNum::one()); - let mut result = i; - if (!is_one) { - let t2m = self.__mul(t2m, t2m); - let i = i + 1; - result = self.__tonelli_shanks_sqrt_inner_loop_check(t2m, i); - } - result + unconstrained fn __eq(self, other: Self) -> bool { + __eq(self.limbs, other.limbs) } -} -impl BigNumInstanceTrait> for BigNumInstance where Params: BigNumParamsTrait { - - /** - * @brief compute a modular square root using the Tonelli-Shanks algorithm - * @details only use for prime fields! Function may infinite loop if used for non-prime fields - * @note this is unconstrained fn. To constrain a square root, validate that output^2 = self - * TODO: create fn that constrains nonexistence of square root (i.e. find x where x^2 = -self) - **/ - unconstrained fn __tonelli_shanks_sqrt( - self, - input: BigNum - ) -> std::option::Option> { - // Tonelli-shanks algorithm begins by finding a field element Q and integer S, - // such that (p - 1) = Q.2^{s} - - // We can compute the square root of a, by considering a^{(Q + 1) / 2} = R - // Once we have found such an R, we have - // R^{2} = a^{Q + 1} = a^{Q}a - // If a^{Q} = 1, we have found our square root. - // Otherwise, we have a^{Q} = t, where t is a 2^{s-1}'th root of unity. - // This is because t^{2^{s-1}} = a^{Q.2^{s-1}}. - // We know that (p - 1) = Q.w^{s}, therefore t^{2^{s-1}} = a^{(p - 1) / 2} - // From Euler's criterion, if a is a quadratic residue, a^{(p - 1) / 2} = 1 - // i.e. t^{2^{s-1}} = 1 - - // To proceed with computing our square root, we want to transform t into a smaller subgroup, - // specifically, the (s-2)'th roots of unity. - // We do this by finding some value b,such that - // (t.b^2)^{2^{s-2}} = 1 and R' = R.b - // Finding such a b is trivial, because from Euler's criterion, we know that, - // for any quadratic non-residue z, z^{(p - 1) / 2} = -1 - // i.e. z^{Q.2^{s-1}} = -1 - // => z^Q is a 2^{s-1}'th root of -1 - // => z^{Q^2} is a 2^{s-2}'th root of -1 - // Since t^{2^{s-1}} = 1, we know that t^{2^{s - 2}} = -1 - // => t.z^{Q^2} is a 2^{s - 2}'th root of unity. - - // We can iteratively transform t into ever smaller subgroups, until t = 1. - // At each iteration, we need to find a new value for b, which we can obtain - // by repeatedly squaring z^{Q} - - let one: U60Repr = unsafe { - U60Repr::one() - }; - let primitive_root_log_size = self.primitive_root_log_size(); - - let mut Q = (self.modulus_u60 - one).shr(primitive_root_log_size - 1); - let mut Q_minus_one_over_two = (Q - one).shr(2); - let mut Q_minus_one_over_two = BigNum::from_array(U60Repr::into(Q_minus_one_over_two)); - let mut z = self.multiplicative_generator(); // the generator is a non-residue - let mut b = self.__pow(input, Q_minus_one_over_two); - let mut r = self.__mul(input, b); - let mut t = self.__mul(r, b); - let mut check: BigNum = t; - for _ in 0..primitive_root_log_size - 1 { - check = self.__mul(check, check); - } - let mut found_root = false; - if (check.__eq(BigNum::one()) == false) {} else { - let mut t1 = self.__pow(z, Q_minus_one_over_two); - let mut t2 = self.__mul(t1, z); - let mut c = self.__mul(t2, t1); - let mut m: u32 = primitive_root_log_size; - // tonelli shanks inner 1 - // (if t2m == 1) then skip - // else increase i and square t2m and go again - // algorithm runtime should only be max the number of bits in modulus - let num_bits: u32 = Params::modulus_bits(); - for _ in 0..num_bits { - if (t.__eq(BigNum::one())) { - found_root = true; - break; - } - let mut t2m = t; - // while loop time - let i = self.__tonelli_shanks_sqrt_inner_loop_check(t2m, 0); - let mut j = m - i - 1; - b = c; - - for _ in 0..j { // how big - if (j == 0) { - break; - } - b = self.__mul(b, b); - //j -= 1; - } - c = self.__mul(b, b); - t = self.__mul(t, c); - r = self.__mul(r, b); - m = i; - } - } - let mut result = std::option::Option { _value: r, _is_some: found_root }; - result + unconstrained fn __is_zero(self) -> bool { + __is_zero(self.limbs) } - /** - * @brief given an input seed, generate a pseudorandom BigNum value - * @details we hash the input seed into `modulus_bits * 2` bits of entropy, - * which is then reduced into a BigNum value - * 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() - **/ - fn derive_from_seed(self, seed: [u8; SeedBytes]) -> BigNum { - let mut rolling_seed: [u8; SeedBytes + 1] = [0; SeedBytes + 1]; - for i in 0..SeedBytes { - rolling_seed[i] = seed[i]; - assert_eq(rolling_seed[i], seed[i]); - } - - let mut hash_buffer: [u8; N * 2 * 15] = [0; N * 2 * 15]; - - let mut rolling_hash_fields: [Field; (SeedBytes / 31) + 1] = [0; (SeedBytes / 31) + 1]; - let mut seed_ptr = 0; - for i in 0..(SeedBytes / 31) + 1 { - let mut packed: Field = 0; - for _ in 0..31 { - if (seed_ptr < SeedBytes) { - packed *= 256; - packed += seed[seed_ptr] as Field; - seed_ptr += 1; - } - } - rolling_hash_fields[i] = packed; - } - - let compressed = std::hash::poseidon2::Poseidon2::hash(rolling_hash_fields, (SeedBytes / 31) + 1); - let mut rolling_hash: [Field; 2] = [compressed, 0]; - let num_hashes = (30 * N) / 32 + (((30 * N) % 32) != 0) as u32; - for i in 0..num_hashes - 1 { - let hash: Field = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); - let hash: [u8; 32] = hash.to_le_bytes(); - for j in 0..30 { - hash_buffer[i * 30 + j] = hash[j]; - } - rolling_hash[1] += 1; - } - { - let hash: Field = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); - let hash: [u8; 32] = hash.to_le_bytes(); - let remaining_bytes = 30 * N - (num_hashes - 1) * 30; - for j in 0..remaining_bytes { - hash_buffer[(num_hashes - 1) * 30 + j] = hash[j]; - } - } - - let num_bits = Params::modulus_bits() * 2; - let num_bytes = num_bits / 8 + ((num_bits % 8) != 0) as u32; - - let bits_in_last_byte = num_bits as u8 % 8; - let last_byte_mask = (1 as u8 << bits_in_last_byte) - 1; - hash_buffer[num_bytes - 1] = hash_buffer[num_bytes - 1] & last_byte_mask; - - let num_bigfield_chunks = (2 * N) / (N - 1) + (((2 * N) % (N - 1)) != 0) as u32; - let mut byte_ptr = 0; - - // we want to convert our byte array into bigfield chunks - // each chunk has at most N-1 limbs - // to determine the exact number of chunks, we need the `!=` or `>` operator which is not avaiable when defining array sizes - // so we overestimate at 4 - // 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 - // if N = 2, we have 4 limbs we want to reduce but each bigfield chunk is only 1 limb, so we need 4 - // max possible number of chunks is therefore 4 - - let mut bigfield_chunks: [[Field; N]; 4] = [[0; N]; 4]; - for k in 0..num_bigfield_chunks { - let mut bigfield_limbs: [Field; N] = [0; N]; - let mut num_filled_bytes = (k * 30); - let mut num_remaining_bytes = num_bytes - num_filled_bytes; - let mut num_remaining_limbs = (num_remaining_bytes / 15) + (num_remaining_bytes % 15 > 0) as u32; - let mut more_than_N_minus_one_limbs = (num_remaining_limbs > (N - 1)) as u32; - let mut num_limbs_in_bigfield = more_than_N_minus_one_limbs * (N - 1) - + num_remaining_limbs * (1 - more_than_N_minus_one_limbs); - - for j in 0..num_limbs_in_bigfield { - let mut limb: Field = 0; - for _ in 0..15 { - let need_more_bytes = (byte_ptr < num_bytes); - let mut byte = hash_buffer[byte_ptr]; - limb *= (256 * need_more_bytes as Field + (1 - need_more_bytes as Field)); - limb += byte as Field * need_more_bytes as Field; - byte_ptr += need_more_bytes as u32; - } - bigfield_limbs[num_limbs_in_bigfield - 1 - j] = limb; - } - bigfield_chunks[num_bigfield_chunks - 1 - k] = bigfield_limbs; - } - - let mut bigfield_rhs_limbs: [Field; N] = [0; N]; - bigfield_rhs_limbs[N-1] = 1; - let bigfield_rhs: BigNum = BigNum::from_array(bigfield_rhs_limbs); - bigfield_rhs.validate_in_range(); - let mut result: BigNum = BigNum::new(); - - for i in 0..num_bigfield_chunks { - let bigfield_limbs = bigfield_chunks[i]; - let bigfield_lhs: BigNum = BigNum::from_array(bigfield_limbs); - - result = self.mul(result, bigfield_rhs); - result = self.add(result, bigfield_lhs); - } - result + // UNCONSTRAINED! (Hence `__` prefix). + fn __neg(self) -> Self { + let params = self.params; + let limbs = unsafe { __neg(params, self.limbs) }; + Self { params, limbs } } - fn modulus(self) -> BigNum { - BigNum { limbs: self.modulus } + // UNCONSTRAINED! (Hence `__` prefix). + fn __add(self, other: Self) -> Self { + let params = self.params; + let limbs = unsafe { __add(params, self.limbs, other.limbs) }; + Self { params, limbs } } - unconstrained fn __derive_from_seed(self, seed: [u8; SeedBytes]) -> BigNum { - self.__derive_from_seed_impl(seed) + + // UNCONSTRAINED! (Hence `__` prefix). + fn __sub(self, other: Self) -> Self { + let params = self.params; + let limbs = unsafe { __sub(params, self.limbs, other.limbs) }; + Self { params, limbs } } - // #################################################################################################################### - // #################################################################################################################### - // ### U N C O N S T R A I N E D F U N C T I O N S - // ### NOTE: these functions call unconstrained internal implementations because trait impl modifiers are not supported - // #################################################################################################################### - // #################################################################################################################### - unconstrained fn __neg(self, val: BigNum) -> BigNum { - self.__neg_impl(val) + // UNCONSTRAINED! (Hence `__` prefix). + fn __mul(self, other: Self) -> Self { + let params = self.params; + let limbs = unsafe { __mul::<_, MOD_BITS>(params, self.limbs, other.limbs) }; + Self { params, limbs } } - unconstrained fn __add(self, lhs: BigNum, rhs: BigNum) -> BigNum { - self.__add_impl(lhs, rhs) + // UNCONSTRAINED! (Hence `__` prefix). + fn __div(self, divisor: Self) -> Self { + let params = self.params; + let limbs = unsafe { __div::<_, MOD_BITS>(params, self.limbs, divisor.limbs) }; + Self { params, limbs } } - unconstrained fn __sub(self, lhs: BigNum, rhs: BigNum) -> BigNum { - self.__sub_impl(lhs, rhs) + // UNCONSTRAINED! (Hence `__` prefix). + fn __udiv_mod(self, divisor: Self) -> (Self, Self) { + let params = self.params; + let (q, r) = unsafe { __udiv_mod(self.limbs, divisor.limbs) }; + (Self { limbs: q, params }, Self { limbs: r, params }) } - unconstrained fn __mul(self, lhs: BigNum, rhs: BigNum) -> BigNum { - self.__mul_impl(lhs, rhs) + // UNCONSTRAINED! (Hence `__` prefix). + fn __invmod(self) -> Self { + let params = self.params; + assert(params.has_multiplicative_inverse); + let limbs = unsafe { __invmod::<_, MOD_BITS>(params, self.limbs) }; + Self { limbs, params } } - unconstrained fn __div(self, lhs: BigNum, rhs: BigNum) -> BigNum { - self.__div_impl(lhs, rhs) + // UNCONSTRAINED! (Hence `__` prefix). + fn __pow(self, exponent: Self) -> Self { + let params = self.params; + let limbs = unsafe { __pow::<_, MOD_BITS>(params, self.limbs, exponent.limbs) }; + Self { limbs, params } } - unconstrained fn __batch_invert( - self, - x: [BigNum; M] - ) -> [BigNum; M] { - self.batch_invert_impl(x) + // UNCONSTRAINED! (Hence `__` prefix). + fn __batch_invert(x: [Self; M]) -> [Self; M] { + let params = x[0].params; + assert(params.has_multiplicative_inverse); + let all_limbs = + unsafe { __batch_invert::<_, MOD_BITS, _>(params, x.map(|bn| Self::get_limbs(bn))) }; + all_limbs.map(|limbs| Self { limbs, params }) } - unconstrained fn __invmod(self, val: BigNum) -> BigNum { - self.__invmod_impl(val) + // Note: can't return a slice from this unconstrained to a constrained function. + unconstrained fn __batch_invert_slice(x: [Self]) -> [Self] { + let params = x[0].params; + assert(params.has_multiplicative_inverse); + let all_limbs = unsafe { + let inv_slice = + __batch_invert_slice::<_, MOD_BITS>(params, x.map(|bn| Self::get_limbs(bn))); + inv_slice.as_array() + }; + all_limbs.map(|limbs| Self { limbs, params }) } - unconstrained fn __pow( - self, - val: BigNum, - exponent: BigNum - ) -> BigNum { - self.__pow_impl(val, exponent) + // UNCONSTRAINED! (Hence `__` prefix). + fn __tonelli_shanks_sqrt(self) -> std::option::Option { + let params = self.params; + let maybe_limbs = unsafe { __tonelli_shanks_sqrt(params, self.limbs) }; + maybe_limbs.map(|limbs| Self { limbs, params }) } - unconstrained fn __compute_quadratic_expression( - self, - lhs_terms: [[BigNum; LHS_N]; NUM_PRODUCTS], + // UNCONSTRAINED! (Hence `__` prefix). + fn __compute_quadratic_expression( + params: BigNumParams, + lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BigNum; RHS_N]; NUM_PRODUCTS], + rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BigNum; ADD_N], - linear_flags: [bool; ADD_N] - ) -> (BigNum, BigNum) { - self.__compute_quadratic_expression_impl( - lhs_terms, - lhs_flags, - rhs_terms, - rhs_flags, - linear_terms, - linear_flags - ) + linear_terms: [Self; ADD_N], + linear_flags: [bool; ADD_N], + ) -> (Self, Self) { + let (q_limbs, r_limbs) = unsafe { + __compute_quadratic_expression::<_, MOD_BITS, _, _, _, _>( + params, + map(lhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + lhs_flags, + map(rhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + rhs_flags, + map(linear_terms, |bn| Self::get_limbs(bn)), + linear_flags, + ) + }; + (Self { limbs: q_limbs, params }, Self { limbs: r_limbs, params }) } - // #################################################################################################################### - // #################################################################################################################### - // ### C O N S T R A I N E D F U N C T I O N S - // #################################################################################################################### - // #################################################################################################################### - - /** - * @brief Constrain a degree-2 BigNum expression to be equal to 0 modulo self.modulus - * @description The expression is of the form (when evaluated as an integer relation): - * - * \sum_{i=0}^{NUM_PRODUCTS - 1} ((\sum_{j=0}^{LHS_N-1}lhs[i][j]) * (\sum_{j=0}^{RHS_N-1}rhs[i][j])) + \sum_{i=0}^{ADD_N - 1}linear_terms[i] - quotient * modulus = 0 - * - * The intent is to capture an arbitrary degree-2 expression within the limitations of Noir (no efficient dynamically-sized vectors) - * - * Note: this method requires the remainder term of the expression to be ZERO - * When performing BigNum arithmetic, we want to represent desired BigNum operations in a way that minimizes the number of modular reductions that are required. - * This can be achieved by minimizing the number of degree-2 relations required. - * - * The expensive parts of this algorithm are the following: - * 1. evaluating the limb products required to compute `lhs * rhs` - * 2. applying range constraints to validate the result is 0 - * - * Range constraints are needed for the following reason: - * When evaluating the above expression over N-limb BigNum objects, the result will consist of 2N - 1 limbs. - * Each limb will be in the range [0, ..., 2^{240 + twiddle_factor} - 1] (twiddle_factor needs to be less than 6). - * Because of the subtractions, the limbs may underflow and represent NEGATIVE values. - * To account for this, we allow the Prover to borrow values from more significant limbs and add them into less significant limbs - * (explicitly, we can borrow 2^{126} from limb `i + 1` to add `2^{246}` into `i`). - * To ensure this has been done correctly, we validate that the borrow-adjusted limbs are all-zero for the first 120 bits. - * We do *this* by multiplying the borrow-adjusted limbs by 1 / 2^{120} modulo CircutModulus, and we validate the result is in the range [0, ..., 2^{126} - 1]. - * TODO: explain why this check works. It's statistically sound but not perfectly sound. Chance of the check failing is ~1 in 2^{120} - * I believe this is the most efficient way of performing the zero-check for this relation as it only requires `2N - 2` 126-bit range checks. - * TODO: explain why we apply a 126-bit range check, this feels like a magic number - * (it is. we could go higher, up to the number of bits in the CircuitModulus - 121, but 126 *should be* sufficient and is much cheaper) - * TODO: apply checks in this method to validate twiddle_factor does not exceed 6 - * - * @param lhs_terms a 2D array of BigNum - * @param lhs_flags a 2D array of sign flags - * @param rhs_terms a 2D array of BigNum - * @param rhs_flags a 2D array of sign flags - * @param linear_terms an array of BigNum - * @param linear_flags an array of sign flags - **/ fn evaluate_quadratic_expression( - self, - lhs_terms: [[BigNum; LHS_N]; NUM_PRODUCTS], + params: BigNumParams, + lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BigNum; RHS_N]; NUM_PRODUCTS], + rhs_terms: [[Self; RHS_N]; NUM_PRODUCTS], rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BigNum; ADD_N], - linear_flags: [bool; ADD_N] + linear_terms: [Self; ADD_N], + linear_flags: [bool; ADD_N], ) { - // use an unconstrained function to compute the value of the quotient - let (quotient, _, borrow_flags): (BigNum, BigNum, [Field; 2 * N]) = unsafe { - unsafe { - self.__compute_quadratic_expression_with_borrow_flags( - lhs_terms, - lhs_flags, - rhs_terms, - rhs_flags, - linear_terms, - linear_flags - ) - } - }; - // constrain the quotient to be in the range [0, ..., 2^{m} - 1], where `m` is log2(modulus) rounded up. - // Additionally, validate quotient limbs are also in the range [0, ..., 2^{120} - 1] - quotient.validate_quotient_in_range(); - // TODO, validate we do not overflow N2 when multiplying and N when adding - // (should be a compile-time check...unconstrained function?) - - // Compute the linear sums that represent lhs_1, rhs_1, lhs_2, rhs_2, add - let mut t0: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; - let mut t1: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; - let mut t4: [Field; N] = [0; N]; - - // TODO: this is super nasty as it requires a multiplication - let double_modulus: [Field; N] = self.double_modulus; - for k in 0..NUM_PRODUCTS { - for i in 0..N { - for j in 0..LHS_N { - // note: if is_negative is not known at comptime this is very expensive - if (lhs_flags[k][j]) { - t0[k][i] -= lhs_terms[k][j].limbs[i]; - t0[k][i] += double_modulus[i]; - } else { - t0[k][i] += lhs_terms[k][j].limbs[i]; - } - } - for j in 0..RHS_N { - if (rhs_flags[k][j]) { - t1[k][i] -= rhs_terms[k][j].limbs[i]; - t1[k][i] += double_modulus[i]; - } else { - t1[k][i] += rhs_terms[k][j].limbs[i]; - } - } - } - } - for i in 0..N { - for j in 0..ADD_N { - if (linear_flags[j]) { - t4[i] -= linear_terms[j].limbs[i]; - t4[i] += double_modulus[i]; - } else { - t4[i] += linear_terms[j].limbs[i]; - } - } - } - - // We want to evaluate that t0 * t1 + t2 * t3 + t4 - Quotient * Modulus = 0, evaluated over the integers - // For this we need to be able to borrow values from more-significant limbs into less-significant limbs, - // so that we can ensure that no limbs will underflow for an honest Prover - let mut product_limbs: [Field; 2 * N] = [0; 2 * N]; - - // Compute the product t0 * t1 + t2 * t3 + t4 - Quotient * Modulus - // TODO: this is super nasty as it requires a multiplication - for i in 0..N { - for j in 0..N { - for k in 0..NUM_PRODUCTS { - if k == 0 { - let new_term = t0[k][i] * t1[k][j] - quotient.limbs[i] * self.modulus[j]; - std::as_witness(new_term); // width-4 optimization (n.b. might not be optimal if t2, t3 input arrays are nonzero) - product_limbs[i + j] += new_term; - } else { - product_limbs[i + j] += t0[k][i] * t1[k][j]; - } - } - if (NUM_PRODUCTS == 0) { - product_limbs[i + j] -= quotient.limbs[i] * self.modulus[j]; - } - } - product_limbs[i] += t4[i]; - } - - // each limb product represents the sum of 120-bit products. - // by setting the borrow value to 2^246 we are restricting this method's completeness to expressions - // where no more than 64 limb products are summed together. - // TODO: check in unconstrained function that this condition is satisfied - // TODO: define trade-offs regarding the value of borrow_shift - // (the larger the value, the greater the range check that is required on product_limbs) - // (126-bit range check is a sweet spot for the barretenberg backend as it decomposes into 9 14-bit range checks) - // (the barretenberg backend can evaluate these in 5.25 gates. 127 bits costs 6.5 gates) - let borrow_shift: Field = 0x40000000000000000000000000000000000000000000000000000000000000; // 2^{246} - let borrow_carry: Field = 0x40000000000000000000000000000000; // 2^{246 - 120} = 2^{126} - - // N.B. borrow_flags is `Field` type because making it `bool` would apply boolean constraints to all `N2` array entries. - // We only use `N2 - 2` borrow flags so applying 1-bit range checks on the array elements we use is more efficient. - // TODO: Once it is possible to perform arithmetic on generics we can use `borrow_flags: [bool;N+N-2]` to avoid this issue - borrow_flags[0].assert_max_bit_size(1); - product_limbs[0] += borrow_flags[0] * borrow_shift; - for i in 1..(N + N - 2) { - borrow_flags[i].assert_max_bit_size(1); - product_limbs[i] += - (borrow_flags[i] * borrow_shift - borrow_flags[i - 1] * borrow_carry); - } - product_limbs[N + N - 2] -= borrow_flags[N + N - 3] * borrow_carry; - - // Final step: Validate `product_limbs` represents the integer value `0` - // Each element `i` in `product_limbs` overlaps in bitrange with element `i+1`, EXCEPT for the low 120 bits - // i.e. we need to do the following for each limb `i`: - // 1. validate the limb's low-120 bits equals zero - // 2. compute the limb "carry" by right-shifting by 2^{120} - // 3. add the carry into limb `i+1` - // We can efficiently do all of the above by multiplying the limb by 2^{-120} and constraining the result to be <2^{126} - // (if the low 120 bits are nonzero the result will underflow and product a large value that cannot be range constrained) - // (the probability of an underflow value satisfying a 126-bit range constraint is approx. 2^{k - 126}, - // where k is the number of bits in the prime field) - // We then add the result into the next limb and repeat. - let hi_shift: Field = 0x1000000000000000000000000000000; - let hi_downshift: Field = 1 / hi_shift; - for i in 0..N + N - 2 { - product_limbs[i] *= hi_downshift; - std::as_witness(product_limbs[i]); - product_limbs[i].assert_max_bit_size(126); // N.B. is this sufficient? going beyond 126 costs us 1 gate per limb - product_limbs[i + 1] += product_limbs[i]; - } - // the most significant limb has no limb to "carry" values into - the entire limb must equal zero - assert(product_limbs[N + N - 2] == 0); - } - - fn validate_in_field(self, val: BigNum) { - // N.B. need to combine with validate_in_range if `self` limbs have not been range constrained - let mut p_minus_self: [Field; N] = [0; N]; - let modulus: [Field; N] = self.modulus; - for i in 0..N { - p_minus_self[i] = modulus[i] - val.limbs[i]; - } - let borrow_flags = unsafe { - self.__validate_in_field_compute_borrow_flags(val) - }; - let two_pow_120: Field = 0x1000000000000000000000000000000; - p_minus_self[0] += borrow_flags[0] as Field * two_pow_120; - for i in 1..N - 1 { - p_minus_self[i] += (borrow_flags[i] as Field * two_pow_120 - borrow_flags[i-1] as Field); - } - p_minus_self[N - 1] -= borrow_flags[N - 2] as Field; - let mut compare = val; - compare.limbs = p_minus_self; - compare.validate_in_range(); - } - - /** - * @brief Validate self != other - * @details If A == B, then A == B mod N. - * We can efficiently evaluate A == B mod N where N = circuit modulus - * This method is *sound*, but not *complete* (i.e. A != B but A == B mod N) - * However the probability of an honest Prover being unable to satisfy this check is tiny! - * (todo: compute how tiny) - **/ - fn assert_is_not_equal(self, lhs: BigNum, rhs: BigNum) { - let mut l: Field = 0; - let mut r: Field = 0; - let mut modulus_mod_n: Field = 0; - let mut two_pow_120: Field = 0x1000000000000000000000000000000; - let modulus = self.modulus; - for i in 0..N { - l *= two_pow_120; - r *= two_pow_120; - modulus_mod_n *= two_pow_120; - l += lhs.limbs[N - i - 1]; - r += rhs.limbs[N - i - 1] ; - modulus_mod_n += modulus[N - i - 1]; - } - - // lhs can be either X mod N or P + X mod N - // rhs can be either Y mod N or P + Y mod N - // If lhs - rhs = 0 mod P then lhs - rhs = 0, P or -P mod N - let mut diff = l - r; - let mut target = diff * (diff + modulus_mod_n) * (diff - modulus_mod_n); - assert(target != 0, "asssert_is_not_equal fail"); - } - - fn eq(self, lhs: BigNum, rhs: BigNum) -> bool { - let diff = self.sub(lhs, rhs); - // if self == other, possible values of `diff` will be `p` or `0` - // (the subtract operator constrains diff to be < ceil(log(p))) - // TODO: can do this more efficiently via witngen in unconstrained functions? - let mut is_equal_modulus: bool = true; - let mut is_equal_zero: bool = true; - for i in 0..N { - is_equal_modulus = is_equal_modulus & (diff.limbs[i] == self.modulus[i]); - is_equal_zero = is_equal_zero & (diff.limbs[i] == 0); - } - is_equal_modulus | is_equal_zero + evaluate_quadratic_expression::<_, MOD_BITS, _, _, _, _>( + params, + map(lhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + lhs_flags, + map(rhs_terms, |bns| map(bns, |bn| Self::get_limbs(bn))), + rhs_flags, + map(linear_terms, |bn| Self::get_limbs(bn)), + linear_flags, + ) } - fn neg(self, val: BigNum) -> BigNum { - // so we do... p - x - r = 0 and there might be borrow flags - let (result, borrow_flags) = unsafe { - self.__neg_with_flags(val) - }; - result.validate_in_range(); - let modulus = self.modulus; - let borrow_shift = 0x1000000000000000000000000000000; - let result_limb = modulus[0] - val.limbs[0] - result.limbs[0] + (borrow_flags[0] as Field * borrow_shift); - assert(result_limb == 0); - for i in 1..N - 1 { - let result_limb = modulus[i] - val.limbs[i] - result.limbs[i] - borrow_flags[i - 1] as Field - + (borrow_flags[i] as Field * borrow_shift); - assert(result_limb == 0); - } - let result_limb = modulus[N - 1] - val.limbs[N - 1] - result.limbs[N - 1] - borrow_flags[N - 2] as Field; - assert(result_limb == 0); - result + fn validate_in_field(self: Self) { + let params = self.params; + validate_in_field::<_, MOD_BITS>(params, self.limbs); } - fn add(self, lhs: BigNum, rhs: BigNum) -> BigNum { - // so we do... p - x - r = 0 and there might be borrow flags - let (result, carry_flags, borrow_flags, overflow_modulus) = unsafe { - self.__add_with_flags(lhs, rhs) - }; - result.validate_in_range(); - let modulus = self.modulus; - let borrow_shift = 0x1000000000000000000000000000000; - let carry_shift = 0x1000000000000000000000000000000; - - let mut subtrahend: [Field; N] = [0; N]; - if (overflow_modulus) { - subtrahend = modulus; - } - let result_limb = lhs.limbs[0] + rhs.limbs[0] - subtrahend[0] - result.limbs[0] - + (borrow_flags[0] as Field * borrow_shift) - - (carry_flags[0] as Field * carry_shift); - assert(result_limb == 0); - for i in 1..N - 1 { - let result_limb = lhs.limbs[i] + rhs.limbs[i] - - subtrahend[i] - - result.limbs[i] - - borrow_flags[i - 1] as Field - + carry_flags[i - 1] as Field - + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift); - assert(result_limb == 0); - } - let result_limb = lhs.limbs[N - 1] + rhs.limbs[N - 1] - - subtrahend[N - 1] - - result.limbs[N - 1] - - borrow_flags[N - 2] as Field - + carry_flags[N - 2] as Field; - assert(result_limb == 0); - result + fn validate_in_range(self) { + validate_in_range::<_, MOD_BITS>(self.limbs); } - // validate that lhs - rhs does not underflow i.e. lhs > rhs - fn validate_gt(self, lhs: BigNum, rhs: BigNum) { - // so we do... p - x - r = 0 and there might be borrow flags - - // a - b = r - // p + a - b - r = 0 - let (result, carry_flags, borrow_flags) = unsafe { - self.__validate_gt_remainder(lhs, rhs) - }; - - result.validate_in_range(); - - let borrow_shift = 0x1000000000000000000000000000000; - let carry_shift = 0x1000000000000000000000000000000; - - let mut addend: [Field; N] = [0; N]; - let result_limb = lhs.limbs[0] - rhs.limbs[0] + addend[0] - result.limbs[0] - 1 - + (borrow_flags[0] as Field * borrow_shift) - - (carry_flags[0] as Field * carry_shift); - assert(result_limb == 0); - for i in 1..N - 1 { - let result_limb = lhs.limbs[i] - rhs.limbs[i] + addend[i] - result.limbs[i] - borrow_flags[i - 1] as Field - + carry_flags[i - 1] as Field - + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift); - assert(result_limb == 0); - } - let result_limb = lhs.limbs[N - 1] - rhs.limbs[N - 1] + addend[N - 1] - - result.limbs[N - 1] - - borrow_flags[N - 2] as Field - + carry_flags[N - 2] as Field; - assert(result_limb == 0); + fn assert_is_not_equal(self, other: Self) { + let params = self.params; + assert_is_not_equal(params, self.limbs, other.limbs); } - fn sub(self, lhs: BigNum, rhs: BigNum) -> BigNum { - // so we do... p - x - r = 0 and there might be borrow flags - - // a - b = r - // p + a - b - r = 0 - let (result, carry_flags, borrow_flags, underflow) = unsafe { - unsafe { - self.__sub_with_flags(lhs, rhs) - } - }; - result.validate_in_range(); - let modulus = self.modulus; - let borrow_shift = 0x1000000000000000000000000000000; - let carry_shift = 0x1000000000000000000000000000000; - - let mut addend: [Field; N] = [0; N]; - if (underflow) { - addend = modulus; - } - let result_limb = lhs.limbs[0] - rhs.limbs[0] + addend[0] - result.limbs[0] - + (borrow_flags[0] as Field * borrow_shift) - - (carry_flags[0] as Field * carry_shift); - assert(result_limb == 0); - for i in 1..N - 1 { - let result_limb = lhs.limbs[i] - rhs.limbs[i] + addend[i] - result.limbs[i] - borrow_flags[i - 1] as Field - + carry_flags[i - 1] as Field - + ((borrow_flags[i] as Field - carry_flags[i] as Field) * borrow_shift); - assert(result_limb == 0); - } - let result_limb = lhs.limbs[N - 1] - rhs.limbs[N - 1] + addend[N - 1] - - result.limbs[N - 1] - - borrow_flags[N - 2] as Field - + carry_flags[N - 2] as Field; - assert(result_limb == 0); - result - } - // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them - // via evaluate_quadratic_expression - // e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression` - // will create much fewer constraints than calling `mul` and `add` directly - fn mul(self, lhs: BigNum, rhs: BigNum) -> BigNum { - let result = unsafe { - self.__mul(lhs, rhs) - }; - self.evaluate_quadratic_expression([[lhs]], [[false]], [[rhs]], [[false]], [result], [true]); - result - } - // Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation - fn div(self, lhs: BigNum, rhs: BigNum) -> BigNum { - assert( - Params::has_multiplicative_inverse(), "BigNum has no multiplicative inverse. Use udiv for unsigned integer division" - ); - let result = unsafe { - self.__div(lhs, rhs) - }; - self.evaluate_quadratic_expression([[result]], [[false]], [[rhs]], [[false]], [lhs], [true]); - result + fn neg(self) -> Self { + let params = self.params; + Self { limbs: neg::<_, MOD_BITS>(params, self.limbs), params } } - /** - * @brief __udiv_mod performs *unconstrained* integer division between numerator, divisor - * - * i.e. 1. floor(numerator / divisor) = quotient - * 2. numerator % divisor = remainder - * 3. divisor * quotient + remainder = numerator - **/ - unconstrained fn __udiv_mod( - self, - numerator: BigNum, - divisor: BigNum - ) -> (BigNum, BigNum) { - self.__udiv_mod_impl(numerator, divisor) + fn udiv_mod(self, divisor: Self) -> (Self, Self) { + let params = self.params; + let (q, r) = udiv_mod::<_, MOD_BITS>(params, self.limbs, divisor.limbs); + (Self { limbs: q, params }, Self { limbs: r, params }) } - /** - * @brief udiv_mod performs integer division between numerator, divisor - * - * i.e. 1. floor(numerator / divisor) = quotient - * 2. numerator % divisor = remainder - * 3. divisor * quotient + remainder = numerator - **/ - fn udiv_mod( - self, - numerator: BigNum, - divisor: BigNum - ) -> (BigNum, BigNum) { - let (quotient, remainder) = unsafe { - BigNumInstance::__udiv_mod_impl(self, numerator, divisor) - }; - // self / divisor = quotient rounded - // quotient * divisor + remainder - self = 0 - self.evaluate_quadratic_expression( - [[quotient]], - [[false]], - [[divisor]], - [[false]], - [numerator, remainder], - [true, false] - ); - // we need (remainder < divisor) - // implies (divisor - remainder > 0) - self.validate_gt(divisor, remainder); - (quotient, remainder) + fn udiv(self, divisor: Self) -> Self { + let params = self.params; + Self { limbs: udiv::<_, MOD_BITS>(params, self.limbs, divisor.limbs), params } } - /** - * @brief udiv_mod performs integer division between numerator, divisor - * - * i.e. return param is floor(numerator / divisor) - **/ - fn udiv(self, numerator: BigNum, divisor: BigNum) -> BigNum { - self.udiv_mod(numerator, divisor).0 + fn umod(self, divisor: Self) -> Self { + let params = self.params; + Self { limbs: umod::<_, MOD_BITS>(params, self.limbs, divisor.limbs), params } } - /** - * @brief udiv_mod performs integer modular reduction - * - * i.e. 1. numerator % divisor = return value - **/ - fn umod(self, numerator: BigNum, divisor: BigNum) -> BigNum { - self.udiv_mod(numerator, divisor).1 + fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self { + let params = lhs.params; + Self { limbs: conditional_select(lhs.limbs, rhs.limbs, predicate), params } } } -impl BigNumInstance where Params: BigNumParamsTrait { - - // #################################################################################################################### - // #################################################################################################################### - // ### C O N S T R U C T O R S - // #################################################################################################################### - // #################################################################################################################### - - fn new(modulus: [Field; N], redc_param: [Field; N]) -> Self { - Self { - redc_param, - modulus, - modulus_u60: U60Repr::from(modulus), - modulus_u60_x4: U60Repr::from(modulus), - double_modulus: get_double_modulus(modulus) - } - } - - unconstrained fn __derive_from_seed_impl(self, seed: [u8; SeedBytes]) -> BigNum { - let mut rolling_hash_fields: [Field; (SeedBytes / 31) + 1] = [0; (SeedBytes / 31) + 1]; - let mut seed_ptr = 0; - for i in 0..(SeedBytes / 31) + 1 { - let mut packed: Field = 0; - for _ in 0..31 { - if (seed_ptr < SeedBytes) { - packed *= 256; - packed += seed[seed_ptr] as Field; - seed_ptr += 1; - } - } - rolling_hash_fields[i] = packed; - } - let compressed = std::hash::poseidon2::Poseidon2::hash(rolling_hash_fields, (SeedBytes / 31) + 1); - let mut rolling_hash: [Field; 2] = [compressed, 0]; - - let mut to_reduce: [Field; 2 * N] = [0; 2 * N]; - - let mut double_modulus_bits = Params::modulus_bits() * 2; - let mut double_modulus_bytes = (double_modulus_bits) / 8 + (double_modulus_bits % 8 != 0) as u32; - - let mut last_limb_bytes = double_modulus_bytes % 15; - if (last_limb_bytes == 0) { - last_limb_bytes = 15; - } - let mut last_limb_bits = double_modulus_bits % 8; - if (last_limb_bits == 0) { - last_limb_bits = 8; - } - - for i in 0..(N - 1) { - let hash = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); - let hash : [u8; 30] = hash.to_le_bytes(); - let mut lo: Field = 0; - let mut hi: Field = 0; - for j in 0..15 { - hi *= 256; - lo *= 256; - - if (i < 2 * N - 2) { - lo += hash[j + 15] as Field; - hi += hash[j] as Field; - } - } - to_reduce[2 * i] = lo; - to_reduce[2 * i + 1] = hi; - rolling_hash[1] += 1; - } - - { - let hash = std::hash::poseidon2::Poseidon2::hash(rolling_hash, 2); - let hash : [u8; 30] = hash.to_le_bytes(); - let mut hi: Field = 0; - for j in 0..(last_limb_bytes - 1) { - hi *= 256; - hi += hash[j] as Field; - } - hi *= 256; - let last_byte = hash[last_limb_bytes - 1]; - let mask = (1 as u64 << (last_limb_bits) as u8) - 1; - let last_bits = last_byte as u64 & mask; - hi += last_bits as Field; - to_reduce[2 * N - 2] = hi; - } - let (_, remainder) = __barrett_reduction( - to_reduce, - self.redc_param, - Params::modulus_bits(), - self.modulus, - self.modulus_u60_x4 - ); - let mut result = BigNum::new(); - result.limbs = remainder; - result - } - - // #################################################################################################################### - // #################################################################################################################### - // ### U N C O N S T R A I N E D F U N C T I O N S - // #################################################################################################################### - // #################################################################################################################### - - unconstrained fn __validate_in_field_compute_borrow_flags(self: Self, val: BigNum) -> [bool; N] { - let mut flags: [bool; N] = [false; N]; - let modulus: [Field; N] = self.modulus; - flags[0] = modulus[0].lt(val.limbs[0]); - for i in 1..N - 1 { - flags[i] = modulus[i].lt(val.limbs[i] + flags[i - 1] as Field); - } - flags - } - - unconstrained fn __pow_impl( - self, - val: BigNum, - exponent: BigNum - ) -> BigNum { - let x: U60Repr = U60Repr::from(exponent.limbs); - - let num_bits = Params::modulus_bits() + 1; - - let mut accumulator: BigNum = BigNum::one(); - - for i in 0..num_bits { - accumulator = self.__mul(accumulator, accumulator); - if x.get_bit(num_bits - i - 1) { - accumulator = self.__mul(accumulator, val); - } - } - accumulator - } - - unconstrained fn __mul_with_quotient( - self, - lhs: BigNum, - rhs: BigNum - ) -> (BigNum, BigNum) { - let mut mul: [Field; 2 * N] = [0; 2 * N]; - for i in 0..N { - for j in 0..N { - mul[i + j] += lhs.limbs[i] * rhs.limbs[j]; - } - } - let to_reduce = split_bits::__normalize_limbs(mul, 2 * N); - let (q, r) = __barrett_reduction( - to_reduce, - self.redc_param, - Params::modulus_bits(), - self.modulus, - self.modulus_u60_x4 - ); - - let mut quotient = BigNum::from_array(q); - let mut remainder = BigNum::from_array(r); - (quotient, remainder) - } - - unconstrained fn __mul_impl( - self, - lhs: BigNum, - rhs: BigNum - ) -> BigNum { - let (_, b) = self.__mul_with_quotient(lhs, rhs); - b - } - - unconstrained fn __add_impl( - self, - lhs: BigNum, - rhs: BigNum - ) -> BigNum { - let x_u60 : U60Repr = U60Repr::from(lhs.limbs); - let y_u60 : U60Repr = U60Repr::from(rhs.limbs); - - let mut z_u60 = x_u60 + y_u60; - - if z_u60.gte(self.modulus_u60) { - z_u60 = z_u60 - self.modulus_u60; - } - let mut result = BigNum::from_array(U60Repr::into(z_u60)); - result - } - - /** - * @brief given an input `x`, compute `2p - x` (unconstrained) - * - * @description we subtract the input from double the modulus, because all constrained BigNum operations - * only guarantee that the output is in the range [0, ceil(log2(p))]. - * I.E. the input may be larger than the modulus `p`. - * In order to ensure this operation does not underflow, we compute `2p - x` instead of `p - x`. - * N.B. constrained BigNum operations do not fully constrain outputs to be in the range [0, p-1] - * because such a check is expensive and usually unneccesary. - */ - unconstrained fn __neg_impl(self, val: BigNum) -> BigNum { - let f: [Field; N] = val.limbs; - let x_u60 : U60Repr = U60Repr::from(f); - let mut result = BigNum::from_array(U60Repr::into(self.modulus_u60 - x_u60)); - result - } - - unconstrained fn __add_with_flags( - self, - lhs: BigNum, - rhs: BigNum - ) -> (BigNum, [bool; N], [bool; N], bool) { - let a_u60 : U60Repr = U60Repr::from(lhs.limbs); - let b_u60 : U60Repr = U60Repr::from(rhs.limbs); - let add_u60 = a_u60 + b_u60; - - let overflow = add_u60.gte(self.modulus_u60); - - let mut subtrahend_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - let mut result_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - - if overflow { - subtrahend_u60 = self.modulus_u60; - } - - let mut carry: u64 = 0; - let mut carry_in: u64 = 0; - let mut borrow: u64 = 0; - let mut borrow_in: u64 = 0; - let mut borrow_flags: [bool; N] = [false; N]; - let mut carry_flags: [bool; N] = [false; N]; - for i in 0..2 * N { - let mut add_term: u64 = a_u60.limbs[i] + b_u60.limbs[i] + carry_in; - carry = (add_term >= 0x1000000000000000) as u64; - add_term -= (carry as u64 * 0x1000000000000000); - result_u60.limbs[i] = add_term; - carry_in = carry as u64; - borrow = ((subtrahend_u60.limbs[i] + borrow_in) > result_u60.limbs[i]) as u64; - let sub = (borrow << 60) + result_u60.limbs[i] - subtrahend_u60.limbs[i] - borrow_in; - result_u60.limbs[i] = sub; - borrow_in = borrow; - - if ((i & 1) == 1) { - let idx = (i - 1) / 2; - if (carry & borrow == 1) { - carry = 0; - borrow = 0; - } - carry_flags[idx] = carry as bool; - borrow_flags[idx] = borrow as bool; - } - } - let mut result = BigNum::from_array(U60Repr::into(result_u60)); - - (result, carry_flags, borrow_flags, overflow) - } - - unconstrained fn __validate_gt_remainder( - _: Self, - lhs: BigNum, - rhs: BigNum - ) -> (BigNum, [bool; N], [bool; N]) { - let a_u60 : U60Repr = U60Repr::from(lhs.limbs); - let mut b_u60 : U60Repr = U60Repr::from(rhs.limbs); - - let underflow = b_u60.gte(a_u60); - b_u60 += U60Repr::one(); - assert(underflow == false, "BigNum::validate_gt check fails"); - let mut addend_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - let mut result_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - - let mut carry: u64 = 0; - let mut carry_in: u64 = 0; - let mut borrow: u64 = 0; - let mut borrow_in: u64 = 0; - let mut borrow_flags: [bool; N] = [false; N]; - let mut carry_flags: [bool; N] = [false; N]; - for i in 0..2 * N { - let mut add_term: u64 = a_u60.limbs[i] + addend_u60.limbs[i] + carry_in; - carry = (add_term >= 0x1000000000000000) as u64; - add_term -= (carry as u64 * 0x1000000000000000); - result_u60.limbs[i] = add_term; - carry_in = carry as u64; - borrow = ((b_u60.limbs[i] + borrow_in) > result_u60.limbs[i]) as u64; - let sub = (borrow << 60) + result_u60.limbs[i] - b_u60.limbs[i] - borrow_in; - result_u60.limbs[i] = sub; - borrow_in = borrow; - - if ((i & 1) == 1) { - if (carry & borrow == 1) { - carry = 0; - borrow = 0; - } - carry_flags[i/2] = carry as bool; - borrow_flags[i/2] = borrow as bool; - } - } - - let mut result = BigNum::from_array(U60Repr::into(result_u60)); - (result, carry_flags, borrow_flags) - } - - unconstrained fn __sub_with_flags( - self, - lhs: BigNum, - rhs: BigNum - ) -> (BigNum, [bool; N], [bool; N], bool) { - let a_u60 : U60Repr = U60Repr::from(lhs.limbs); - let b_u60 : U60Repr = U60Repr::from(rhs.limbs); - - let underflow = b_u60.gte(a_u60 + U60Repr::one()); - - let mut addend_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - let mut result_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - - if underflow { - addend_u60 = self.modulus_u60; - } - - let mut carry: u64 = 0; - let mut carry_in: u64 = 0; - let mut borrow: u64 = 0; - let mut borrow_in: u64 = 0; - let mut borrow_flags: [bool; N] = [false; N]; - let mut carry_flags: [bool; N] = [false; N]; - for i in 0..2 * N { - let mut add_term: u64 = a_u60.limbs[i] + addend_u60.limbs[i] + carry_in; - carry = (add_term >= 0x1000000000000000) as u64; - add_term -= (carry as u64 * 0x1000000000000000); - result_u60.limbs[i] = add_term; - carry_in = carry as u64; - borrow = ((b_u60.limbs[i] + borrow_in) > result_u60.limbs[i]) as u64; - let sub = (borrow << 60) + result_u60.limbs[i] - b_u60.limbs[i] - borrow_in; - result_u60.limbs[i] = sub; - borrow_in = borrow; - - if ((i & 1) == 1) { - if (carry & borrow == 1) { - carry = 0; - borrow = 0; - } - carry_flags[i/2] = carry as bool; - borrow_flags[i/2] = borrow as bool; - } - } - let mut result = BigNum::from_array(U60Repr::into(result_u60)); - (result, carry_flags, borrow_flags, underflow) - } - - unconstrained fn __neg_with_flags( - self, - val: BigNum - ) -> (BigNum, [bool; N]) { - let f: [Field; N] = val.limbs; - let x_u60 : U60Repr = U60Repr::from(f); - let mut result_u60 : U60Repr = U60Repr { limbs: [0; 2 * N] }; - - let mut borrow: u64 = 0; - let mut borrow_in: u64 = 0; - - let mut borrow_flags: [bool; N] = [false; N]; - for i in 0..2 * N { - borrow = ((x_u60.limbs[i] + borrow_in) > self.modulus_u60.limbs[i]) as u64; - let sub = (borrow << 60) + self.modulus_u60.limbs[i] - x_u60.limbs[i] - borrow_in; - result_u60.limbs[i] = sub; - borrow_in = borrow; - if ((i & 1) == 1) { - borrow_flags[i / 2] = borrow as bool; - } - } - let mut result = BigNum::from_array(U60Repr::into(result_u60)); - (result, borrow_flags) - } - - /** - * @brief given inputs `x, y` compute 2p + x - y (unconstrained) - * @description see `__neg` for why we use 2p instead of p - **/ - unconstrained fn __sub_impl( - self, - lhs: BigNum, - rhs: BigNum - ) -> BigNum { - self.__add(lhs, self.__neg(rhs)) - } - - unconstrained fn __invmod_impl(self, val: BigNum) -> BigNum { - let one: BigNum = BigNum::one(); - let one_u60: U60Repr = U60Repr::from(one.limbs); - let exponent = self.modulus_u60.sub(one_u60.add(one_u60)); - let mut result = BigNum::from_array(U60Repr::into(exponent)); - self.__pow(val, result) - } - - unconstrained fn batch_invert_impl( - self, - x: [BigNum; M] - ) -> [BigNum; M] { - // TODO: ugly! Will fail if input slice is empty - let mut accumulator: BigNum = BigNum::one(); - let mut result: [BigNum; M] = [BigNum::new(); M]; - let mut temporaries: [BigNum] = &[]; - for i in 0..x.len() { - temporaries = temporaries.push_back(accumulator); - if (x[i].__is_zero() == false) { - accumulator = self.__mul(accumulator, x[i]); - } - } - - accumulator = self.__invmod(accumulator); - let mut T0: BigNum = BigNum::new(); - T0.limbs = [0; N]; - for i in 0..x.len() { - let idx = x.len() - 1 - i; - if (x[idx].__is_zero() == false) { - T0 = self.__mul(accumulator, temporaries[idx]); - accumulator = self.__mul(accumulator, x[idx]); - result[idx] = T0; - } - } - result - } - - unconstrained fn batch_invert_slice_impl(self, x: [BigNum]) -> [BigNum] { - // TODO: ugly! Will fail if input slice is empty - let mut accumulator: BigNum = BigNum::one(); - let mut result: [BigNum] = [BigNum::new()]; - let mut temporaries: [BigNum] = &[]; - for i in 0..x.len() { - temporaries = temporaries.push_back(accumulator); - if (x[i].__is_zero() == false) { - accumulator = self.__mul(accumulator, x[i]); - } - result = result.push_back(BigNum::new()); - } - - accumulator = self.__invmod(accumulator); - let mut T0: BigNum = BigNum::new(); - T0.limbs = [0; N]; - for i in 0..x.len() { - let idx = x.len() - 1 - i; - if (x[idx].__is_zero() == false) { - T0 = self.__mul(accumulator, temporaries[idx]); - accumulator = self.__mul(accumulator, x[idx]); - result[idx] = T0; - } - } - result - } - - unconstrained fn __div_impl( - self, - numerator: BigNum, - divisor: BigNum - ) -> BigNum { - let t0 = self.__invmod(divisor); - self.__mul(numerator, t0) - } - - /** - * @brief Computes the result of a linear combination of (possibly negative) BigNum values (unconstrained) - **/ - // NOTE: modulus2 is structured such that all limbs will be greater than 0, even when subtracting. - // To do this, when computing `p - x`, we ensure that each limb in `p` is greater than each limb in `x`. - // We know that, for a valid bignum element, the limbs in `x` will be <2^{120} - // Therefore each of the limbs in `p` (except the most significant) will borrow 2^{120} from the more significant limb. - // Finally, to ensure we do not underflow in the most significant limb, we use `2p` instead of `p` - unconstrained fn __add_linear_expression(self, x: [BigNum; M], flags: [bool; M]) -> ([Field; N]) { - // TODO, validate we do not overflow N2 when multiplying and N when adding - let mut sum: [Field; N] = [0; N]; - // TODO: ugly! Will fail if input array is empty - let modulus2: [Field;N] = self.double_modulus; - for i in 0..M { - if (flags[i]) { - for j in 0..N { - sum[j] = sum[j] + modulus2[j] - x[i].limbs[j]; - // assert(x[i].limbs[j].lt(modulus2[j])); - } - } else { - for j in 0..N { - sum[j] = sum[j] + x[i].limbs[j]; - } - } - } - // problem if we normalize when used in computing quotient - sum - } - - /** - * @brief computes the limb products of a quadratic expression - * @details see __compute_quadratic_expression_with_borrow_flags for full description - **/ - unconstrained fn __compute_quadratic_expression_product( - self, - lhs_terms: [[BigNum; LHS_N]; NUM_PRODUCTS], - lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BigNum; RHS_N]; NUM_PRODUCTS], - rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BigNum; ADD_N], - linear_flags: [bool; ADD_N] - ) -> [Field; 2 * N] { - // TODO, validate we do not overflow N2 when multiplying and N when adding - let mut lhs: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; - let mut rhs: [[Field; N]; NUM_PRODUCTS] = [[0; N]; NUM_PRODUCTS]; - let mut add: [Field; N] = [0; N]; - - for i in 0..NUM_PRODUCTS { - lhs[i] = self.__add_linear_expression(lhs_terms[i], lhs_flags[i]); - rhs[i] = self.__add_linear_expression(rhs_terms[i], rhs_flags[i]); - } - - let add: [Field; N] = self.__add_linear_expression(linear_terms, linear_flags); - - let mut mulout: [Field; 2 * N] = [0; 2 * N]; - - for i in 0..N { - for j in 0..N { - for k in 0..NUM_PRODUCTS { - mulout[i + j] += (lhs[k][i] * rhs[k][j]); - } - } - mulout[i] += add[i]; - } - mulout - } - - /** - * @brief computes the quotient/remainder of a quadratic expression - * @details see __compute_quadratic_expression_with_borrow_flags for full description - **/ - unconstrained fn __compute_quadratic_expression_impl( - self, - lhs_terms: [[BigNum; LHS_N]; NUM_PRODUCTS], - lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BigNum; RHS_N]; NUM_PRODUCTS], - rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BigNum; ADD_N], - linear_flags: [bool; ADD_N] - ) -> (BigNum, BigNum) { - // TODO, validate we do not overflow N2 when multiplying and N when adding - let mulout = self.__compute_quadratic_expression_product( - lhs_terms, - lhs_flags, - rhs_terms, - rhs_flags, - linear_terms, - linear_flags - ); - let mut relation_result: [Field; 2 * N] = split_bits::__normalize_limbs(mulout, 2 * N); - // size 4 - // a[3] * b[3] = a[6] = 7 - // TODO: ugly! Will fail if input slice is empty - let k = Params::modulus_bits(); - - let (quotient, remainder) = __barrett_reduction( - relation_result, - self.redc_param, - k, - self.modulus, - self.modulus_u60_x4 - ); - - let mut q = BigNum::from_array(quotient); - let mut r = BigNum::from_array(remainder); - (q, r) - } - - /** - * @brief Given a degree-2 BigNum expression that is equal to 0 mod p, compute the quotient and borrow flags - * @description The expression is of the form: - * - * \sum_{i=0}^{NUM_PRODUCTS - 1} ((\sum_{j=0}^{LHS_N-1}lhs[i][j]) * (\sum_{j=0}^{RHS_N-1}rhs[i][j])) + \sum_{i=0}^{ADD_N - 1}linear_terms[i] = quotient * modulus - * - * The intent is to capture an arbitrary degree-2 expression within the limitations of Noir (no efficient dynamically-sized vectors) - * - * When performing BigNum arithmetic, we want to represent desired BigNum operations in a way that minimizes the number of modular reductions that are required. - * This can be achieved by minimizing the number of degree-2 relations required. - * - * The borrow flags describe whether individual Field limbs will underflow when evaluating the above relation. - * For example, when computing the product a * b - q * p = 0, it is possible that: - * 1. a[0]*b[0] - p[0]*q[0] = -2^{120} - * 2. a[0]*b[1] + a[1]*b[0] - p[0]*q[1] - p[1]*q[0] = 1 - * In the above example, the value represented by these two limbs is zero despite each limb being nonzero. - * In this case, to correctly constrain the result, we must add (at least) 2^{120} from the first limb and subtract 1 from the second. - * - * @param lhs_terms a 2D array of BigNum - * @param lhs_flags a 2D array of sign flags - * @param rhs_terms a 2D array of BigNum - * @param rhs_flags a 2D array of sign flags - * @param linear_terms an array of BigNum - * @param linear_flags an array of sign flags - **/ - unconstrained fn __compute_quadratic_expression_with_borrow_flags( - self, - lhs_terms: [[BigNum; LHS_N]; NUM_PRODUCTS], - lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], - rhs_terms: [[BigNum; RHS_N]; NUM_PRODUCTS], - rhs_flags: [[bool; RHS_N]; NUM_PRODUCTS], - linear_terms: [BigNum; ADD_N], - linear_flags: [bool; ADD_N] - ) -> (BigNum, BigNum, [Field; 2 * N]) { - // TODO, validate we do not overflow N2 when multiplying and N when adding - - let mut mulout_p = self.__compute_quadratic_expression_product( - lhs_terms, - lhs_flags, - rhs_terms, - rhs_flags, - linear_terms, - linear_flags - ); - let mut mulout_n: [Field; 2 * N] = [0; 2 * N]; - let mut relation_result: [Field; 2 * N] = split_bits::__normalize_limbs(mulout_p, 2 * N); - - let modulus: [Field; N] = self.modulus; - let (quotient, remainder) = __barrett_reduction( - relation_result, - self.redc_param, - Params::modulus_bits(), - modulus, - self.modulus_u60_x4 - ); - assert(remainder == [0; N]); - - for i in 0..N { - for j in 0..N { - mulout_n[i + j] += quotient[i] * modulus[j]; - } - } - - // compute borrow flags from mulout_p and mulout_n - let mut borrow_flags: [Field; 2 * N] = [0; 2 * N]; - let borrow_shift: Field = 0x40000000000000000000000000000000000000000000000000000000000000; // 2^{246} - let borrow_carry: Field = 0x40000000000000000000000000000000; // 2^{246 - 120} = 2^{126} - let two_pow_120: Field = 0x1000000000000000000000000000000; - let downshift: Field = 1 / two_pow_120; - - // determine whether we need to borrow from more significant limbs. - // initial limb is "simple" comparison operation - // TODO: check how expensive `lt` operator is w.r.t. witness generation - borrow_flags[0] = mulout_p[0].lt(mulout_n[0]) as Field; - // we have 2N - 2 borrow flags. The number of limbs from our product computation is 2N - 1 - // and there is nothing to borrow against for the final limb. - let mut hi_bits = (mulout_p[0] - mulout_n[0] + (borrow_flags[0] * borrow_shift)) * downshift; - for i in 1..(N + N - 2) { - // compute the contribution from limb `i-1` that gets added into limb `i`, and add into limb `i` - // let hi_bits = (mulout_p.get(i - 1) - mulout_n.get(i - 1) + (borrow_flags.get(i - 1) * borrow_shift)) - // * downshift; - mulout_p[i] += hi_bits; - - // determine whether negative limb values are greater than positive limb values - let underflow: Field = mulout_p[i].lt(mulout_n[i] + (borrow_flags[i - 1] * borrow_carry)) as Field; - borrow_flags[i] = underflow; - - hi_bits = (mulout_p[i] - mulout_n[i] + (borrow_flags[i] * borrow_shift) - - (borrow_flags[i - 1] * borrow_carry)) * downshift; - } - - let mut q = BigNum::from_array(quotient); - let mut r = BigNum::from_array(remainder); - (q, r, borrow_flags) +impl std::ops::Add for RuntimeBigNum { + // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them + // via evaluate_quadratic_expression + fn add(self, other: Self) -> Self { + let params = self.params; + Self { limbs: add::<_, MOD_BITS>(params, self.limbs, other.limbs), params } } +} - unconstrained fn __udiv_mod_impl( - _: Self, - numerator: BigNum, - divisor: BigNum - ) -> (BigNum, BigNum) { - let mut quotient_u60: U60Repr = U60Repr::from([0; N]); - let mut remainder_u60: U60Repr = U60Repr::from(numerator.limbs); - - let mut divisor_u60: U60Repr = U60Repr::from(divisor.limbs); - let b = divisor_u60; - - let mut bit_difference = remainder_u60.get_msb() - divisor_u60.get_msb(); - - let mut accumulator_u60: U60Repr = U60Repr::one(); - divisor_u60 = divisor_u60.shl(bit_difference); - accumulator_u60 = accumulator_u60.shl(bit_difference); - - if (divisor_u60.gte(remainder_u60 + U60Repr::one())) { - divisor_u60.shr1(); - accumulator_u60.shr1(); - } - for _ in 0..(N * 120) { - if (remainder_u60.gte(b) == false) { - break; - } - - // we've shunted 'divisor' up to have the same bit length as our remainder. - // If remainder >= divisor, then a is at least '1 << bit_difference' multiples of b - if (remainder_u60.gte(divisor_u60)) { - remainder_u60 -= divisor_u60; - // we can use OR here instead of +, as - // accumulator is always a nice power of two - quotient_u60 = quotient_u60 + accumulator_u60; - } - divisor_u60.shr1(); // >>= 1; - accumulator_u60.shr1(); // >>= 1; - } - - ( - BigNum::from_array(U60Repr::into(quotient_u60)), BigNum::from_array(U60Repr::into(remainder_u60)) - ) +impl std::ops::Sub for RuntimeBigNum { + // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them + // via evaluate_quadratic_expression + fn sub(self, other: Self) -> Self { + let params = self.params; + Self { limbs: sub::<_, MOD_BITS>(params, self.limbs, other.limbs), params } } } -fn get_double_modulus(modulus: [Field; N]) -> [Field; N] { - let TWO_POW_120: Field = 0x1000000000000000000000000000000; - let m: U60Repr = U60Repr::from(modulus); - let mut result: [Field; N] = U60Repr::into(m + m); - - result[0] += TWO_POW_120; - for i in 1..N - 1 { - result[i] += (TWO_POW_120 - 1); +impl std::ops::Mul for RuntimeBigNum { + // Note: this method is expensive! Try to craft quadratic relations and directly evaluate them + // via evaluate_quadratic_expression + // e.g. performing a sum of multiple multiplications and additions via `evaluate_quadratic_expression` + // will create much fewer constraints than calling `mul` and `add` directly + fn mul(self, other: Self) -> Self { + let params = self.params; + Self { limbs: mul::<_, MOD_BITS>(params, self.limbs, other.limbs), params } } - result[N - 1] -= 1; - result } -unconstrained fn __barrett_reduction( - x: [Field; 2 * N], - redc_param: [Field; N], - k: u32, - modulus: [Field; N], - modulus_u60: U60Repr -) -> ([Field; N], [Field; N]) { - let mut mulout: [Field; 3 * N] = [0; 3 * N]; - for i in 0..(N + N) { - for j in 0..N { - mulout[i + j] += x[i] * redc_param[j]; - } +impl std::ops::Div for RuntimeBigNum { + // Note: this method is expensive! Witness computation is extremely expensive as it requires modular exponentiation + fn div(self, divisor: Self) -> Self { + let params = self.params; + Self { limbs: div::<_, MOD_BITS>(params, self.limbs, divisor.limbs), params } } - mulout = split_bits::__normalize_limbs(mulout, 3 * N - 2); - let mulout_u60: U60Repr = U60Repr::new(mulout); - - // When we apply the barrett reduction, the maximum value of the output will be - // <= p * (1 + x/2^{2k}) - // where p = modulus, - // x = reduction input - // if x > p * p, we need k to be larger than modulus_bits() - // we hardcode k = 4, which means that the maximum value of x is approx. 16 * p * p - // this should be larger than most values put into `evaluate_quadratic_expression` - // TODO: try and detect cases where x might be too large at comptime - // N.B. BARRETT_REDUCTION_OVERFLOW_BITS affects how `redc_param` is generated. - // `redc_param` = 2^{modulus_bits() * 2 + BARRETT_REDUCTION_OVERFLOW_BITS} / modulus - // NOTE: very niche edge case error that we need to be aware of: - // N must be large enough to cover the modulus *plus* BARRETT_REDUCTION_OVERFLOW_BITS - // i.e. a 359-bit prime needs (I think) 4 limbs to represent or we may overflow when calling __barrett_reduction - let mut quotient_u60 = mulout_u60.shr((k + k + BARRETT_REDUCTION_OVERFLOW_BITS)); +} - // N.B. we assume that the shifted quotient cannot exceed 2 times original bit size. - // (partial_quotient should be just slightly larger than the modulus, we could probably represent with a size N+1 array) - let partial_quotient_full: [Field; 3 * N] = quotient_u60.into_field_array(); - let mut partial_quotient: [Field; 2 * N] = [0; 2 * N]; - for i in 0..2 * N { - partial_quotient[i] = partial_quotient_full[i]; - } - // quotient_mul_modulus can never exceed input value `x` so can fit into size-2 array - let mut quotient_mul_modulus: [Field; 2 * N] = [0; 2 * N]; - let mut quotient_mul_modulus_normalized: [Field; 2 * N] = [0; 2 * N]; - for j in 0..N { - for i in 0..(N + N - j) { - quotient_mul_modulus[i + j] += partial_quotient[i] * modulus[j]; - } +impl std::cmp::Eq for RuntimeBigNum { + fn eq(self, other: Self) -> bool { + let params = self.params; + eq::<_, MOD_BITS>(params, self.limbs, other.limbs) } - for i in 0..(N + N) { - let (lo, hi) = split_bits::split_120_bits(quotient_mul_modulus[i]); - quotient_mul_modulus_normalized[i] = lo; - // TODO: what is faster, leaving this if statement in or out? - // (array is size-1 too large so we can tolerate adding 0 into max element) - if (i + 1 < N + N) { - quotient_mul_modulus[i + 1] += hi; - } - } - let quotient_mul_modulus_u60: U60Repr = U60Repr::new(quotient_mul_modulus_normalized); - - let x_u60 : U60Repr = U60Repr::new(x); - let mut remainder_u60 = x_u60 - quotient_mul_modulus_u60; - - if (remainder_u60.gte(modulus_u60)) { - remainder_u60 = remainder_u60 - modulus_u60; - quotient_u60.increment(); - } else {} - let q: [Field; N] = U60Repr::into(quotient_u60); - let r: [Field; N] = U60Repr::into(remainder_u60); - - (q, r) } diff --git a/src/runtime_bignum_test.nr b/src/runtime_bignum_test.nr deleted file mode 100644 index e9d67e17..00000000 --- a/src/runtime_bignum_test.nr +++ /dev/null @@ -1,589 +0,0 @@ -use crate::BigNum; -use crate::runtime_bignum::BigNumInstance; -use crate::runtime_bignum::BigNumParamsTrait; -use crate::BigNumParamsTrait as NotRuntimeBigNumParamsTrait; - -use crate::utils::u60_representation::U60Repr; -use crate::fields::bn254Fq::BNParams as BNParams; -use crate::fields::secp256k1Fq::Secp256k1_Fq_Params; -use crate::fields::bls12_381Fq::BLS12_381_Fq_Params; -use crate::fields::bls12_381Fr::BLS12_381_Fr_Params; -use crate::fields::bls12_377Fq::BLS12_377_Fq_Params; -use crate::fields::bls12_377Fr::BLS12_377_Fr_Params; - -struct Test2048Params {} - -// See https://github.com/noir-lang/noir/issues/6172 -#[test] -fn silence_warning() { - let _ = Test2048Params {}; -} - -impl BigNumParamsTrait<18> for Test2048Params { - fn modulus_bits() -> u32 { - 2048 - } -} -impl NotRuntimeBigNumParamsTrait<18> for Test2048Params { - fn modulus_bits() -> u32 { - 2048 - } - - fn get_instance() -> BigNumInstance<18, Test2048Params> { - let modulus: [Field; 18] = [ - 0x0000000000000000000000000000000000c0a197a5ae0fcdceb052c9732614fe, - 0x0000000000000000000000000000000000656ae034423283422243918ab83be3, - 0x00000000000000000000000000000000006bf590da48a7c1070b7d5aabaac678, - 0x00000000000000000000000000000000000cce39f530238b606f24b296e2bda9, - 0x000000000000000000000000000000000001e1fef9bb9c1c3ead98f226f1bfa0, - 0x0000000000000000000000000000000000ad8c1c816e12e0ed1379055e373abf, - 0x0000000000000000000000000000000000cebe80e474f753aa9d1461c435123d, - 0x0000000000000000000000000000000000aee5a18ceedef88d115a8b93c167ad, - 0x0000000000000000000000000000000000268ba83c4a65c4307427fc495d9e44, - 0x0000000000000000000000000000000000dd2777926848667b7df79f342639d4, - 0x0000000000000000000000000000000000f455074c96855ca0068668efe7da3d, - 0x00000000000000000000000000000000005ddba6b30bbc168bfb3a1225f27d65, - 0x0000000000000000000000000000000000591fec484f36707524133bcd6f4258, - 0x000000000000000000000000000000000059641b756766aeebe66781dd01d062, - 0x000000000000000000000000000000000058bc5eaff4b165e142bf9e2480eebb, - 0x0000000000000000000000000000000000667a3964f08e06df772ce64b229a72, - 0x00000000000000000000000000000000009c1fdb18907711bfe3e3c1cf918395, - 0x00000000000000000000000000000000000000000000000000000000000000b8 - ]; - let redc_param: [Field; 18] = [ - 0x1697def7100cd5cf8d890b4ef2ec3f, 0x765ba8304214dac764d3f4adc31859, 0x8404bd14d927ea230e60d4bebf9406, 0xc4d53a23bacc251ecbfc4b7ba5a0b4, 0x3eaf3499474a6f5b2fff83f1259c87, 0xbff4c737b97281f1a5f2384a8c16d9, 0x1b4cf2f55358476b53237829990555, 0xe7a804e8eacfe3a2a5673bc3885b86, 0xabadeae4282906c817adf70eab4ae1, 0x66f7df257fe2bf27f0809aceed9b0e, 0xd90fb7428901b8bed11f6b81e36bf1, 0x36e6ba885c60b7024c563605df7e07, 0x2b7c58d2fb5d2c8478963ae6d4a44f, 0x6ee761de26635f114ccc3f7d74f855, 0x3fb726a10cf2220897513f05243de3, 0x43a26bbd732496eb4d828591b8056e, 0xf4e42304e60fb3a54fca735499f2cf, 0x162f - ]; - BigNumInstance::new(modulus, redc_param) - } -} - -/** - * @brief this example was failing - sanity test to validate it now works - **/ -#[test] -fn test_bls_reduction() { - let X1: BigNum<4, BLS12_381_Fq_Params> = BigNum { - limbs: [ - 0x55e83ff97a1aeffb3af00adb22c6bb, 0x8c4f9774b905a14e3a3f171bac586c, 0xa73197d7942695638c4fa9ac0fc368, 0x17f1d3 - ] - }; - X1.validate_in_field(); - let mut (_, XX_mul_3): (BigNum<4, BLS12_381_Fq_Params>, BigNum<4, BLS12_381_Fq_Params> ) = unsafe { - BigNum::__compute_quadratic_expression( - [[X1, X1, X1]], - [[false, false, false]], - [[X1]], - [[false]], - [], - [] - ) - }; - XX_mul_3.validate_in_field(); -} - -/** - * @brief experimenting with macro madness and code generation to make some tests that apply to multiple BigNum parametrisations! - **/ -comptime fn make_test(f: StructDefinition, N: Quoted, typ: Quoted) -> Quoted { - let k = f.name(); - quote{ -impl $k { -#[test] -fn test_add() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([4, 5, 6, 7]) }; - let one: BigNum<$N, $typ> = BigNum::one(); - a.validate_in_range(); - bn.validate_in_field(a); - b.validate_in_range(); - bn.validate_in_field(b); - - let mut c = bn.add(a, b); - c = bn.add(c, c); - let d = bn.mul(bn.add(a, b), bn.add(one, one)); - assert(bn.eq(c, d)); - - let e = bn.add(one, one); - for i in 1..$N { - assert(e.limbs[i] == 0); - } - assert(e.limbs[0] == 2); -} - -#[test] -fn test_sub() { - let bn = $typ::get_instance(); - // 0 - 1 should equal p - 1 - let mut a: BigNum<$N, $typ> = BigNum::new(); - let mut b: BigNum<$N, $typ> = BigNum::one(); - let mut expected: BigNum<$N, $typ> = bn.modulus(); - expected.limbs[0] -= 1; // p - 1 - - let result = bn.sub(a, b); - assert(bn.eq(result, expected)); -} - - -#[test] -fn test_sub_modulus_limit() { - let instance = $typ::get_instance(); - // if we underflow, maximum result should be ... - // 0 - 1 = o-1 - // 0 - p = 0 - let mut a: BigNum<$N, $typ> = BigNum::new(); - let mut b: BigNum<$N, $typ> = instance.modulus(); - let mut expected: BigNum<$N, $typ> = BigNum::new(); - let result = instance.sub(a, b); - assert(instance.eq(result, expected)); -} - - -#[test(should_fail_with = "call to assert_max_bit_size")] -fn test_sub_modulus_underflow() { - let instance = $typ::get_instance(); - - // 0 - (p + 1) is smaller than p and should produce unsatisfiable constraints - let mut a: BigNum<$N, $typ> = BigNum::new(); - let mut b: BigNum<$N, $typ> = instance.modulus(); - b.limbs[0] += 1; - let mut expected: BigNum<$N, $typ> = BigNum::one(); - - let result = instance.sub(a, b); - - assert(instance.eq(result, expected)); -} - -#[test] -fn test_add_modulus_limit() { - let instance = $typ::get_instance(); - // p + 2^{modulus_bits()} - 1 should be the maximum allowed value fed into an add operation - // when adding, if the result overflows the modulus, we conditionally subtract the modulus, producing 2^{254} - 1 - // this is the largest value that will satisfy the range check applied when constructing a bignum - let p : U60Repr<$N, 2> = U60Repr::from(instance.modulus().limbs); - let one = unsafe{ U60Repr::one() }; - - let a: BigNum<$N, $typ> = unsafe{ BigNum { limbs: U60Repr::into(p) } }; - let mut two_pow_modulus_bits_minus_one: U60Repr<$N, 2> = unsafe{ one.shl(a.modulus_bits()) - one }; - let b: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(two_pow_modulus_bits_minus_one) }; - let result = instance.add(a, b); - assert(instance.eq(result, b)); -} - -#[test(should_fail_with = "call to assert_max_bit_size")] -fn test_add_modulus_overflow() { - - let instance = $typ::get_instance(); - let p : U60Repr<$N, 2> = U60Repr::from(instance.modulus().limbs); - let one = unsafe{ U60Repr::one() }; - let a: BigNum<$N, $typ> = unsafe{ BigNum { limbs: U60Repr::into(p + one) } }; - let mut two_pow_modulus_bits_minus_one: U60Repr<$N, 2> = unsafe{ one.shl(a.modulus_bits()) - one }; - let b: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(two_pow_modulus_bits_minus_one) }; - let result = instance.add(a, b); - assert(instance.eq(result, b)); -} - -#[test] -fn test_mul() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([4, 5, 6, 7]) }; - - let c = bn.mul(bn.add(a, b), bn.add(a, b)); - let d = bn.add( - bn.add( - bn.add(bn.mul(a, a), bn.mul(b, b)), - bn.mul(a, b) - ), - bn.mul(a, b) - ); - assert(bn.eq(c, d)); -} - -#[test] -fn test_quadratic_expression() { - let bn = $typ ::get_instance(); - for i in 0..32 { - let X1: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([i as u8,2,3,4]) }; - let Y1: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([i as u8,i as u8,6,7]) }; - let Z1: BigNum<$N, $typ> = BigNum::one(); - - let (_, YY_mul_2): (BigNum<$N, $typ>, BigNum<$N, $typ> ) = unsafe{BigNum::__compute_quadratic_expression([[Y1]], [[false]], [[Y1, Y1]], [[false, false]], [], [])}; - let mut (_, XX_mul_3): (BigNum<$N, $typ>, BigNum<$N, $typ> ) = unsafe{BigNum::__compute_quadratic_expression( - [[X1]], - [[false]], - [[X1, X1, X1]], - [[false, false, false]], - [], - [] - )}; - let (_, D): (BigNum<$N, $typ>, BigNum<$N, $typ> ) = unsafe{BigNum::__compute_quadratic_expression([[X1, X1]], [[false, false]], [[YY_mul_2]], [[false]], [], [])}; - let mut (_, X3): (BigNum<$N, $typ>, BigNum<$N, $typ> ) = unsafe{BigNum::__compute_quadratic_expression( - [[XX_mul_3]], - [[false]], - [[XX_mul_3]], - [[false]], - [D, D], - [true, true] - )}; - let (_, Y3): (BigNum<$N, $typ>, BigNum<$N, $typ> ) = unsafe{BigNum::__compute_quadratic_expression( - [[XX_mul_3], [YY_mul_2]], - [[false], [true]], - [[D, X3], [YY_mul_2, YY_mul_2]], - [[false, true], [false, false]], - [], - [] - )}; - // 3XX * (D - X3) - 8YYYY - - let (_, Z3): (BigNum<$N, $typ>, BigNum<$N, $typ> ) = unsafe{ BigNum::__compute_quadratic_expression([[Y1]], [[false]], [[Z1, Z1]], [[false, false]], [], []) }; - - bn.validate_in_field(X3); - bn.validate_in_field(Y3); - bn.validate_in_field(Z3); - } -} - -#[test] -fn assert_is_not_equal() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([4, 5, 6, 7]) }; - - bn.assert_is_not_equal(a, b); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn assert_is_not_equal_fail() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - - bn.assert_is_not_equal(a, b); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn assert_is_not_equal_overloaded_lhs_fail() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - - let modulus = bn.modulus(); - - let t0: U60Repr<$N, 2> = U60Repr::from(a.limbs); - let t1: U60Repr<$N, 2> = U60Repr::from(modulus.limbs); - let a_plus_modulus: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(t0 + t1) }; - bn.assert_is_not_equal(a_plus_modulus, b); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn assert_is_not_equal_overloaded_rhs_fail() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - - let modulus = bn.modulus(); - - let t0: U60Repr<$N, 2> = U60Repr::from(b.limbs); - let t1: U60Repr<$N, 2> = U60Repr::from(modulus.limbs); - let b_plus_modulus: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(t0 + t1) }; - bn.assert_is_not_equal(a, b_plus_modulus); -} - -#[test(should_fail_with = "asssert_is_not_equal fail")] -fn assert_is_not_equal_overloaded_fail() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let b: BigNum<$N, $typ> = unsafe{ bn.__derive_from_seed([1, 2, 3, 4]) }; - let modulus = bn.modulus(); - let t0: U60Repr<$N, 2> = U60Repr::from(a.limbs); - let t1: U60Repr<$N, 2> = U60Repr::from(b.limbs); - let t2: U60Repr<$N, 2> = U60Repr::from(modulus.limbs); - let a_plus_modulus: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(t0 + t2) }; - let b_plus_modulus: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(t1 + t2) }; - bn.assert_is_not_equal(a_plus_modulus, b_plus_modulus); -} - -#[test] -fn test_derive() -{ - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = bn.derive_from_seed("hello".as_bytes()); - let b: BigNum<$N, $typ> = unsafe { - bn.__derive_from_seed("hello".as_bytes()) - }; - assert(bn.eq(a, b)); -} - -#[test] -fn test_eq() { - let bn = $typ ::get_instance(); - let a: BigNum<$N, $typ> = unsafe { - bn.__derive_from_seed([1, 2, 3, 4]) - }; - let b: BigNum<$N, $typ> = unsafe { - bn.__derive_from_seed([1, 2, 3, 4]) - }; - let c: BigNum<$N, $typ> = unsafe { - bn.__derive_from_seed([2, 2, 3, 4]) - }; - - let modulus: BigNum<$N, $typ> = bn.modulus(); - let t0: U60Repr<$N, 2> = (U60Repr::from(modulus.limbs)); - let t1: U60Repr<$N, 2> = (U60Repr::from(b.limbs)); - let b_plus_modulus: BigNum<$N, $typ> = BigNum { limbs: U60Repr::into(t0 + t1) }; - - assert(bn.eq(a, b) == true); - assert(bn.eq(a, b_plus_modulus) == true); - assert(bn.eq(c, b) == false); - assert(bn.eq(c, a) == false); -} - -} -} -} - -#[make_test(quote{3},quote{BNParams})] -pub struct BNTests{} -#[make_test(quote{3},quote{Secp256k1_Fq_Params})] -pub struct Secp256K1FqTests{} -#[make_test(quote{4},quote{BLS12_381_Fq_Params})] -pub struct BLS12_381FqTests{} - -#[make_test(quote{18},quote{Test2048Params})] -pub struct Test2048Tests{} - -#[make_test(quote{3},quote{BLS12_381_Fr_Params})] -pub struct BLS12_381_Fr_ParamsTests{} - -#[make_test(quote{4},quote{BLS12_377_Fq_Params})] -pub struct BLS12_377_Fq_ParamsTests{} - -#[make_test(quote{3},quote{BLS12_377_Fr_Params})] -pub struct BLS12_377_Fr_ParamsTests{} - -type Fq = BigNum<3, BNParams>; - -// 98760 -// 99689 -// 929 gates for a 2048 bit mul - -fn test_div(bn: BigNumInstance) where Params: BigNumParamsTrait { - let a: BigNum = unsafe { - bn.__derive_from_seed([1, 2, 3, 4]) - }; - let b: BigNum = unsafe { - bn.__derive_from_seed([4, 5, 6, 7]) - }; - - let c = bn.div(a, b); - assert(bn.eq(bn.mul(b, c), a)); -} - -fn test_invmod(bn: BigNumInstance) where Params: BigNumParamsTrait { - let u: BigNum = unsafe { - bn.__derive_from_seed([1, 2, 3, 4]) - }; - for _ in 0..1 { - let v = unsafe { - bn.__invmod(u) - }; - let result = unsafe { - bn.__mul(u, v) - }; - let expected: BigNum = BigNum::one(); - assert(result.limbs == expected.limbs); - } -} - -#[test] -fn test_div_BN() { - let instance = BNParams::get_instance(); - test_div(instance); -} - -#[test] -fn test_invmod_BN() { - let instance = BNParams::get_instance(); - test_invmod(instance); -} - -// N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril -// #[test] -// fn test_div_2048() { -// let instance = get_2048_BN_instance(); -// test_div(instance); -// } - -// N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril -// #[test] -// fn test_invmod_2048() { -// let instance = get_2048_BN_instance(); -// test_invmod(instance); -// } - -#[test] -fn test_2048_bit_quadratic_expression() { - let instance = Test2048Params::get_instance(); - let a: [Field; 18] = [ - 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, - 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, - 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, - 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, - 0x00000000000000000000000000000000008337197826e2e9ea000ed5b05d5ac5, - 0x000000000000000000000000000000000040680101b43f6d17de8e3507f3d820, - 0x00000000000000000000000000000000000c6ba0cdcf77cff1c10355ea48d387, - 0x0000000000000000000000000000000000e51717a72902214a9dbeb90e4f225f, - 0x0000000000000000000000000000000000c1bd5bec78406b691f71cbcddb4574, - 0x00000000000000000000000000000000001ce5e532cfb306d7b52e7d9f1aa442, - 0x000000000000000000000000000000000019575932f75ddf00595b22782e1ba2, - 0x0000000000000000000000000000000000d630b3fbf0a9e55861e4399900feb9, - 0x0000000000000000000000000000000000d6b37aeb2daa8d2e2f7e29b0f7752a, - 0x0000000000000000000000000000000000e9cacdd93406256b9eb46b73948849, - 0x00000000000000000000000000000000001400e1f0a38695db66993fe042c48b, - 0x0000000000000000000000000000000000e1d829cb4fa8cabb7d0265efbd8527, - 0x000000000000000000000000000000000055f1a92a5dd099ef2bcd89ac175b52, - 0x00000000000000000000000000000000000000000000000000000000000000fc - ]; - let b: [Field; 18] = [ - 0x0000000000000000000000000000000000c5694493e9bcc76e68dfcf73e0fde1, - 0x0000000000000000000000000000000000ede5e4b8b3e0dec1f4705c35521620, - 0x00000000000000000000000000000000007aa800bab1b33eda0f07695af6c583, - 0x000000000000000000000000000000000045892edea2c02bf0b8b1d2d9a4ebcc, - 0x00000000000000000000000000000000004dffb06bf396f3d0a5b67cff714bdd, - 0x00000000000000000000000000000000004d691db495235e1e032f1ef3e90274, - 0x0000000000000000000000000000000000d92c069d0f2675b2f46cb497aa62d4, - 0x00000000000000000000000000000000003d3f23584f113cef1a4b8b7d183f5c, - 0x0000000000000000000000000000000000289ba11d897837f9cec57dcc430bfc, - 0x0000000000000000000000000000000000765dc64f6ed4a6efd7b26c38f79e59, - 0x00000000000000000000000000000000008edf31fabf5c330ecf7f92fb6487cd, - 0x000000000000000000000000000000000053392f8b14dd78af702b3be2e0d557, - 0x000000000000000000000000000000000034abf357bfd56e9786a7e47ed9a5ae, - 0x0000000000000000000000000000000000a9ebb234064c8ab10d4e7900d4b973, - 0x00000000000000000000000000000000002a6850cce14a20463913002ddc0fa6, - 0x0000000000000000000000000000000000a97e3b06586bfa62325ef7557ab536, - 0x0000000000000000000000000000000000b942b0d26e5be2e08cd425107c59f7, - 0x0000000000000000000000000000000000000000000000000000000000000031 - ]; - let c_expected: [Field; 18] = [ - 0x00000000000000000000000000000000004518a874adebbcf963fed876dfcf78, - 0x00000000000000000000000000000000002b1535070c2deca63e2dc7145a9997, - 0x0000000000000000000000000000000000d9b738665a290c09f09202043d9387, - 0x0000000000000000000000000000000000c88853b11034fe12661eb7a5e41ca7, - 0x0000000000000000000000000000000000357cc4053e7eb127abc2c1430972a1, - 0x0000000000000000000000000000000000224df5e1be31a51562f8574027a992, - 0x000000000000000000000000000000000070ad9287e6326d534f1d2835e159ad, - 0x00000000000000000000000000000000000efa138f75f20b5117955e15bbb447, - 0x0000000000000000000000000000000000d9f45c310be1865ad23fbcdeb1d93f, - 0x00000000000000000000000000000000004f74ca4cf3df59a83f2df796fc9beb, - 0x0000000000000000000000000000000000ed1801428ebf7db771deb45f4311eb, - 0x00000000000000000000000000000000002ded3b46e3a84cda43157d4d927162, - 0x00000000000000000000000000000000009bcd6ac8f90601a44a84a026d4b383, - 0x0000000000000000000000000000000000ab098478b39031a1de85062fd5712b, - 0x00000000000000000000000000000000004432a79276f4375ff3ec2ced8b6cf6, - 0x0000000000000000000000000000000000a0922d75e96e3f9e31c0cbbcbd708a, - 0x00000000000000000000000000000000004013822c9e9aa5b5b1e9c33e4332b7, - 0x0000000000000000000000000000000000000000000000000000000000000058 - ]; - - let a_bn: BigNum<18, Test2048Params> = BigNum { limbs: a }; - let b_bn: BigNum<18, Test2048Params> = BigNum { limbs: b }; - let c_bn = unsafe { - instance.__mul(a_bn, b_bn) - }; - assert(c_bn.limbs == c_expected); - - a_bn.validate_in_range(); - - instance.evaluate_quadratic_expression([[a_bn]], [[false]], [[b_bn]], [[false]], [c_bn], [true]); -} - -#[test] -fn test_expressions() { - let instance = BNParams::get_instance(); - let x: [Field; 6] = [ - 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, - 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, 0x00000000000000000000000000000000000000000000000000000000b05d5ac5, 0 - ]; - - let y: Fq = BigNum { - limbs: [ - 0x1, - 0x1, - 0x0 - ] - }; - let z: Fq = BigNum { - limbs: [ - 0x2, - 0x2, - 0x0 - ] - }; - let yy = unsafe { - instance.__add(y, y) - }; - - assert(yy.limbs == z.limbs); - - let uu: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4a832748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e04080471712c1d7f18e89, - 0x000000000000000000000000000000000000000000000000000000000000063 - ] - }; - let vv: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4aec2748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e0408047171a01d7f18e89, - 0x0000000000000000000000000000000000000000000000000000000000000062 - ] - }; - let w: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4a832748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e04080471712c1d7f18e89, - 0x0000000000000000000000000000000000000000000000000000000000001f93 - ] - }; - let x: Fq = BigNum { - limbs: [ - 0x0000000000000000000000000000000000b4aec2748da6ad742a1fd81b787643, - 0x00000000000000000000000000000000009575f594e0408047171a01d7f18e89, - 0x0000000000000000000000000000000000000000000000000000000000000f93 - ] - }; - let wx = unsafe { - instance.__mul(w, x) - }; - let uv = unsafe { - instance.__mul(uu, vv) - }; - let y = unsafe { - instance.__neg(instance.__add(uv, wx)) - }; - let z = unsafe { - instance.__add(uv, wx) - }; - - instance.evaluate_quadratic_expression( - [[uu], [w]], - [[false], [false]], - [[vv], [x]], - [[false], [false]], - [z], - [true] - ); - instance.evaluate_quadratic_expression( - [[uu], [w]], - [[false], [false]], - [[vv], [x]], - [[false], [false]], - [y], - [false] - ); - - let wx_constrained = instance.mul(w, x); - assert(wx_constrained.limbs == wx.limbs); -} diff --git a/src/tests/bignum_test.nr b/src/tests/bignum_test.nr new file mode 100644 index 00000000..9449ddc3 --- /dev/null +++ b/src/tests/bignum_test.nr @@ -0,0 +1,792 @@ +use crate::utils::u60_representation::U60Repr; + +use crate::bignum::BigNum; +use crate::bignum::BigNumTrait; + +use crate::params::BigNumParams; +use crate::params::BigNumParamsGetter; + +use crate::fields::bn254Fq::BN254_Fq_Params; +use crate::fields::U256::U256Params; +use crate::fields::bls12_381Fq::BLS12_381_Fq_Params; + +struct Test2048Params {} + +// See https://github.com/noir-lang/noir/issues/6172 +#[test] +fn silence_warning() { + let _ = Test2048Params {}; +} + +global TEST_2048_PARAMS: BigNumParams<18, 2048> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [ + 0xc0a197a5ae0fcdceb052c9732614fe, + 0x656ae034423283422243918ab83be3, + 0x6bf590da48a7c1070b7d5aabaac678, + 0x0cce39f530238b606f24b296e2bda9, + 0x01e1fef9bb9c1c3ead98f226f1bfa0, + 0xad8c1c816e12e0ed1379055e373abf, + 0xcebe80e474f753aa9d1461c435123d, + 0xaee5a18ceedef88d115a8b93c167ad, + 0x268ba83c4a65c4307427fc495d9e44, + 0xdd2777926848667b7df79f342639d4, + 0xf455074c96855ca0068668efe7da3d, + 0x5ddba6b30bbc168bfb3a1225f27d65, + 0x591fec484f36707524133bcd6f4258, + 0x59641b756766aeebe66781dd01d062, + 0x58bc5eaff4b165e142bf9e2480eebb, + 0x667a3964f08e06df772ce64b229a72, + 0x9c1fdb18907711bfe3e3c1cf918395, + 0xb8, + ], + double_modulus: [ + 0x0181432f4b5c1f9b9d60a592e64c29fc, + 0x01cad5c06884650684448723157077c6, + 0x01d7eb21b4914f820e16fab557558cef, + 0x01199c73ea604716c0de49652dc57b51, + 0x0103c3fdf37738387d5b31e44de37f3f, + 0x015b183902dc25c1da26f20abc6e757d, + 0x019d7d01c8e9eea7553a28c3886a247a, + 0x015dcb4319ddbdf11a22b5172782cf5a, + 0x014d17507894cb8860e84ff892bb3c88, + 0x01ba4eef24d090ccf6fbef3e684c73a7, + 0x01e8aa0e992d0ab9400d0cd1dfcfb47a, + 0x01bbb74d6617782d17f674244be4faca, + 0x01b23fd8909e6ce0ea4826779ade84af, + 0x01b2c836eacecd5dd7cccf03ba03a0c3, + 0x01b178bd5fe962cbc2857f3c4901dd75, + 0x01ccf472c9e11c0dbeee59cc964534e3, + 0x01383fb63120ee237fc7c7839f230729, + 0x0170, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0eb052c9732614fe, + 0x0c0a197a5ae0fcdc, + 0x022243918ab83be3, + 0x0656ae0344232834, + 0x070b7d5aabaac678, + 0x06bf590da48a7c10, + 0x6f24b296e2bda9, + 0xcce39f530238b6, + 0x0ead98f226f1bfa0, + 0x1e1fef9bb9c1c3, + 0x0d1379055e373abf, + 0x0ad8c1c816e12e0e, + 0x0a9d1461c435123d, + 0x0cebe80e474f753a, + 0x0d115a8b93c167ad, + 0x0aee5a18ceedef88, + 0x7427fc495d9e44, + 0x0268ba83c4a65c43, + 0x0b7df79f342639d4, + 0x0dd2777926848667, + 0x068668efe7da3d, + 0x0f455074c96855ca, + 0x0bfb3a1225f27d65, + 0x05ddba6b30bbc168, + 0x0524133bcd6f4258, + 0x0591fec484f36707, + 0x0be66781dd01d062, + 0x059641b756766aee, + 0x0142bf9e2480eebb, + 0x058bc5eaff4b165e, + 0x0f772ce64b229a72, + 0x0667a3964f08e06d, + 0x0fe3e3c1cf918395, + 0x09c1fdb18907711b, + 0xb8, + 0x00, + ], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0eb052c9732614fe, + 0x0c0a197a5ae0fcdc, + 0x022243918ab83be3, + 0x0656ae0344232834, + 0x070b7d5aabaac678, + 0x06bf590da48a7c10, + 0x6f24b296e2bda9, + 0xcce39f530238b6, + 0x0ead98f226f1bfa0, + 0x1e1fef9bb9c1c3, + 0x0d1379055e373abf, + 0x0ad8c1c816e12e0e, + 0x0a9d1461c435123d, + 0x0cebe80e474f753a, + 0x0d115a8b93c167ad, + 0x0aee5a18ceedef88, + 0x7427fc495d9e44, + 0x0268ba83c4a65c43, + 0x0b7df79f342639d4, + 0x0dd2777926848667, + 0x068668efe7da3d, + 0x0f455074c96855ca, + 0x0bfb3a1225f27d65, + 0x05ddba6b30bbc168, + 0x0524133bcd6f4258, + 0x0591fec484f36707, + 0x0be66781dd01d062, + 0x059641b756766aee, + 0x0142bf9e2480eebb, + 0x058bc5eaff4b165e, + 0x0f772ce64b229a72, + 0x0667a3964f08e06d, + 0x0fe3e3c1cf918395, + 0x09c1fdb18907711b, + 0xb8, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ], + }, + redc_param: [ + 0x1697def7100cd5cf8d890b4ef2ec3f, + 0x765ba8304214dac764d3f4adc31859, + 0x8404bd14d927ea230e60d4bebf9406, + 0xc4d53a23bacc251ecbfc4b7ba5a0b4, + 0x3eaf3499474a6f5b2fff83f1259c87, + 0xbff4c737b97281f1a5f2384a8c16d9, + 0x1b4cf2f55358476b53237829990555, + 0xe7a804e8eacfe3a2a5673bc3885b86, + 0xabadeae4282906c817adf70eab4ae1, + 0x66f7df257fe2bf27f0809aceed9b0e, + 0xd90fb7428901b8bed11f6b81e36bf1, + 0x36e6ba885c60b7024c563605df7e07, + 0x2b7c58d2fb5d2c8478963ae6d4a44f, + 0x6ee761de26635f114ccc3f7d74f855, + 0x3fb726a10cf2220897513f05243de3, + 0x43a26bbd732496eb4d828591b8056e, + 0xf4e42304e60fb3a54fca735499f2cf, + 0x162f, + ], +}; + +impl BigNumParamsGetter<18, 2048> for Test2048Params { + fn get_params() -> BigNumParams<18, 2048> { + TEST_2048_PARAMS + } +} + +type Fq = BigNum<3, 254, BN254_Fq_Params>; +type BN256 = BigNum<3, 257, U256Params>; +type BN381 = BigNum<4, 381, BLS12_381_Fq_Params>; +type BN2048 = BigNum<18, 2048, Test2048Params>; + +/** + * @brief this example was failing - sanity test to validate it now works + **/ +#[test] +fn test_bls_reduction() { + let X1: BN381 = BigNum { + limbs: [ + 0x55e83ff97a1aeffb3af00adb22c6bb, + 0x8c4f9774b905a14e3a3f171bac586c, + 0xa73197d7942695638c4fa9ac0fc368, + 0x17f1d3, + ], + }; + X1.validate_in_field(); + let mut (_, XX_mul_3): (BN381, BN381) = unsafe { + BigNum::__compute_quadratic_expression( + [[X1, X1, X1]], + [[false, false, false]], + [[X1]], + [[false]], + [], + [], + ) + }; + XX_mul_3.validate_in_field(); +} + +fn test_eq() +where + BN: BigNumTrait, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let c = unsafe { BN::__derive_from_seed([2, 2, 3, 4]) }; + + let modulus = BN::modulus(); + let t0: U60Repr = (U60Repr::from(modulus.get_limbs())); + let t1: U60Repr = (U60Repr::from(b.get_limbs())); + let b_plus_modulus = BN::from_array(U60Repr::into(t0 + t1)); + assert(a.eq(b) == true); + assert(a.eq(b_plus_modulus) == true); + assert(c.eq(b) == false); + assert(c.eq(a) == false); +} + +// fn test_eq(_: BigNum) where Params: BigNumParamsGetter + RuntimeBigNumParamsTrait { +// let a = BigNum::__derive_from_seed([1, 2, 3, 4]); +// let b = BigNum::__derive_from_seed([1, 2, 3, 4]); +// let c = BigNum::__derive_from_seed([2, 2, 3, 4]); + +// let modulus: BigNum = Params::get_params().modulus(); +// let t0: U60Repr = (U60Repr::from(modulus.limbs)); +// let t1: U60Repr = (U60Repr::from(b.limbs)); +// let b_plus_modulus: BigNum = BigNum { limbs: U60Repr::into(t0 + t1) }; + +// assert(a.eq(b) == true); +// assert(a.eq(b_plus_modulus) == true); +// assert(c.eq(b) == false); +// assert(c.eq(a) == false); +// } + +// // // 98760 +// // // 99689 +// // // 929 gates for a 2048 bit mul +fn test_mul() +where + BN: BigNumTrait + std::ops::Mul + std::ops::Add, +{ + let a: BN = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b: BN = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) }; + + let c = (a + b) * (a + b); + let d = (a * a) + (b * b) + (a * b) + (a * b); + assert(c.eq(d)); +} + +fn test_add() +where + BN: BigNumTrait + std::ops::Add + std::ops::Mul + std::cmp::Eq, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b: BN = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) }; + let one = BN::one(); + a.validate_in_range(); + a.validate_in_field(); + b.validate_in_range(); + b.validate_in_field(); + let mut c = (a + b); + c += c; + let d = (a + b) * (one + one); + assert(c == (d)); + let e = one + one; + let limbs = e.get_limbs(); + let mut first: bool = true; + for limb in limbs { + if first { + first = false; + assert(limb == 2); + } else { + assert(limb == 0); + } + } +} + +fn test_div() +where + BN: BigNumTrait + std::ops::Div + std::ops::Mul + std::ops::Add + std::cmp::Eq, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) }; + + let c = a / b; + assert((b * c) == (a)); +} + +fn test_invmod() +where + BN: BigNumTrait + std::cmp::Eq, +{ + let u = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + for _ in 0..1 { + let v = unsafe { u.__invmod() }; + let result = unsafe { u.__mul(v) }; + let expected = BN::one(); + assert(result == expected); + } +} + +fn assert_is_not_equal() +where + BN: BigNumTrait, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) }; + + a.assert_is_not_equal(b); +} + +fn assert_is_not_equal_fail() +where + BN: BigNumTrait, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + + a.assert_is_not_equal(b); +} + +fn assert_is_not_equal_overloaded_lhs_fail() +where + BN: BigNumTrait, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + + let modulus = BN::modulus(); + + let t0: U60Repr = U60Repr::from(a.get_limbs()); + let t1: U60Repr = U60Repr::from(modulus.get_limbs()); + let a_plus_modulus = BN::from_array(U60Repr::into(t0 + t1)); + a_plus_modulus.assert_is_not_equal(b); +} + +fn assert_is_not_equal_overloaded_rhs_fail() +where + BN: BigNumTrait, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + + let modulus = BN::modulus(); + + let t0: U60Repr = U60Repr::from(b.get_limbs()); + let t1: U60Repr = U60Repr::from(modulus.get_limbs()); + let b_plus_modulus = BN::from_array(U60Repr::into(t0 + t1)); + a.assert_is_not_equal(b_plus_modulus); +} + +fn assert_is_not_equal_overloaded_fail() +where + BN: BigNumTrait, +{ + let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + let b = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) }; + + let modulus = BN::modulus(); + + let t0: U60Repr = U60Repr::from(a.get_limbs()); + let t1: U60Repr = U60Repr::from(b.get_limbs()); + let t2: U60Repr = U60Repr::from(modulus.get_limbs()); + let a_plus_modulus: BN = BN::from_array(U60Repr::into(t0 + t2)); + let b_plus_modulus: BN = BN::from_array(U60Repr::into(t1 + t2)); + a_plus_modulus.assert_is_not_equal(b_plus_modulus); +} + +#[test] +fn test_eq_BN() { + // let stub: Fq = BigNum::new(); + test_eq::<3, Fq>(); +} +#[test] +fn test_add_BN() { + let mut a: Fq = BigNum::modulus(); + let mut b: Fq = BigNum::modulus(); + let mut expected: Fq = BigNum::modulus(); + + a.limbs[0] -= 1; + b.limbs[0] -= 1; + expected.limbs[0] -= 2; + + let result = a + b; + assert(result == expected); +} + +#[test] +fn test_sub_test_BN() { + // 0 - 1 should equal p - 1 + let mut a: Fq = BigNum::new(); + let mut b: Fq = BigNum::one(); + let mut expected: Fq = BigNum::modulus(); + expected.limbs[0] -= 1; // p - 1 + let result = a - b; + assert(result == expected); +} + +#[test] +fn test_sub_modulus_limit() { + // if we underflow, maximum result should be ... + // 0 - 1 = o-1 + // 0 - p = 0 + let mut a: Fq = BigNum::new(); + let mut b: Fq = BigNum::modulus(); + let mut expected = BigNum::new(); + + let result = a - b; + assert(result == expected); +} + +#[test(should_fail_with = "call to assert_max_bit_size")] +fn test_sub_modulus_underflow() { + // 0 - (p + 1) is smaller than p and should produce unsatisfiable constraints + let mut a: Fq = BigNum::new(); + let mut b: Fq = BigNum::modulus(); + b.limbs[0] += 1; + let mut expected = BigNum::one(); + + let result = a - b; + assert(result == expected); +} + +#[test] +fn test_add_modulus_limit() { + // p + 2^{254} - 1 should be the maximum allowed value fed into an add operation + // when adding, if the result overflows the modulus, we conditionally subtract the modulus, producing 2^{254} - 1 + // this is the largest value that will satisfy the range check applied when constructing a bignum + let p: U60Repr<3, 2> = U60Repr::from(BN254_Fq_Params::get_params().modulus); + let two_pow_254_minus_1: U60Repr<3, 2> = U60Repr::from([ + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x3fff, + ]); + let a: Fq = BigNum { limbs: U60Repr::into(p) }; + let b: Fq = BigNum { limbs: U60Repr::into(two_pow_254_minus_1) }; + let result = a + b; + assert(result == b); +} + +#[test(should_fail_with = "call to assert_max_bit_size")] +fn test_add_modulus_overflow() { + //(2^{254} - 1) + (p - 1) = 2^{254} + p + // after subtracting modulus, result is 2^{254} will does not satisfy the range check applied when constructing a BigNum + let p: U60Repr<3, 2> = U60Repr::from(BN254_Fq_Params::get_params().modulus); + let two_pow_254_minus_1: U60Repr<3, 2> = U60Repr::from([ + 0xffffffffffffffffffffffffffffff, + 0xffffffffffffffffffffffffffffff, + 0x3fff, + ]); + let one = U60Repr::from([1, 0, 0]); + let a: Fq = BigNum { limbs: U60Repr::into(p + one) }; + let b: Fq = BigNum { limbs: U60Repr::into(two_pow_254_minus_1) }; + let result = a + b; + assert(result == b); +} + +#[test] +fn test_mul_BN() { + test_mul::<3, Fq>(); +} + +#[test] +fn test_add_BN2() { + test_add::<3, Fq>(); +} + +#[test] +fn test_div_BN() { + test_div::<3, Fq>(); +} + +#[test] +fn test_invmod_BN() { + test_invmod::<3, Fq>(); +} + +#[test] +fn test_assert_is_not_equal_BN() { + assert_is_not_equal::<3, Fq>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_fail_BN() { + assert_is_not_equal_fail::<3, Fq>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_lhs_fail_BN() { + assert_is_not_equal_overloaded_lhs_fail::<3, Fq>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_rhs_fail_BN() { + assert_is_not_equal_overloaded_rhs_fail::<3, Fq>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_fail_BN() { + assert_is_not_equal_overloaded_fail::<3, Fq>(); +} + +#[test] +fn test_eq_2048() { + test_eq::<18, BN2048>(); +} + +#[test] +fn test_mul_2048() { + test_mul::<18, BN2048>(); +} + +#[test] +fn test_add_2048() { + test_add::<18, BN2048>(); +} + +#[test] +fn test_assert_is_not_equal_2048() { + assert_is_not_equal::<18, BN2048>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_fail_2048() { + assert_is_not_equal_fail::<18, BN2048>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_lhs_fail_2048() { + assert_is_not_equal_overloaded_lhs_fail::<18, BN2048>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_rhs_fail_2048() { + assert_is_not_equal_overloaded_rhs_fail::<18, BN2048>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_fail_2048() { + assert_is_not_equal_overloaded_fail::<18, BN2048>(); +} + +#[test] +fn test_eq_U256() { + test_eq::<3, BN256>(); +} + +#[test] +fn test_mul_U256() { + test_mul::<3, BN256>(); +} + +#[test] +fn test_add_U256() { + test_add::<3, BN256>(); +} + +#[test] +fn test_assert_is_not_equal_U256() { + assert_is_not_equal::<3, BN256>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_fail_U256() { + assert_is_not_equal_fail::<3, BN256>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_lhs_fail_U256() { + assert_is_not_equal_overloaded_lhs_fail::<3, BN256>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_rhs_fail_U256() { + assert_is_not_equal_overloaded_rhs_fail::<3, BN256>(); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn test_assert_is_not_equal_overloaded_fail_U256() { + assert_is_not_equal_overloaded_fail::<3, BN256>(); +} + +type U256 = BN256; + +#[test] +fn test_udiv_mod_U256() { + let a: U256 = unsafe { BigNum::__derive_from_seed([1, 2, 3, 4]) }; + let b: U256 = BigNum::from_array([12, 0, 0]); + + let (q, r) = a.udiv_mod(b); + + // let qb = q.__mul(b); + let product = unsafe { q.__mul(b).__add(r) }; + assert(product == a); +} + +// // N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril +// #[test] +// fn test_div_2048() { +// let stub: BN2048 = BigNum::new(); +// test_div(stub); +// } + +// // N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril +// #[test] +// fn test_invmod_2048() { +// let stub: BN2048 = BigNum::new(); +// test_invmod(stub); +// } + +#[test] +fn test_2048_bit_quadratic_expression() { + let a: [Field; 18] = [ + 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, + 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, + 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, + 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, + 0x00000000000000000000000000000000008337197826e2e9ea000ed5b05d5ac5, + 0x000000000000000000000000000000000040680101b43f6d17de8e3507f3d820, + 0x00000000000000000000000000000000000c6ba0cdcf77cff1c10355ea48d387, + 0x0000000000000000000000000000000000e51717a72902214a9dbeb90e4f225f, + 0x0000000000000000000000000000000000c1bd5bec78406b691f71cbcddb4574, + 0x00000000000000000000000000000000001ce5e532cfb306d7b52e7d9f1aa442, + 0x000000000000000000000000000000000019575932f75ddf00595b22782e1ba2, + 0x0000000000000000000000000000000000d630b3fbf0a9e55861e4399900feb9, + 0x0000000000000000000000000000000000d6b37aeb2daa8d2e2f7e29b0f7752a, + 0x0000000000000000000000000000000000e9cacdd93406256b9eb46b73948849, + 0x00000000000000000000000000000000001400e1f0a38695db66993fe042c48b, + 0x0000000000000000000000000000000000e1d829cb4fa8cabb7d0265efbd8527, + 0x000000000000000000000000000000000055f1a92a5dd099ef2bcd89ac175b52, + 0x00000000000000000000000000000000000000000000000000000000000000fc, + ]; + let b: [Field; 18] = [ + 0x0000000000000000000000000000000000c5694493e9bcc76e68dfcf73e0fde1, + 0x0000000000000000000000000000000000ede5e4b8b3e0dec1f4705c35521620, + 0x00000000000000000000000000000000007aa800bab1b33eda0f07695af6c583, + 0x000000000000000000000000000000000045892edea2c02bf0b8b1d2d9a4ebcc, + 0x00000000000000000000000000000000004dffb06bf396f3d0a5b67cff714bdd, + 0x00000000000000000000000000000000004d691db495235e1e032f1ef3e90274, + 0x0000000000000000000000000000000000d92c069d0f2675b2f46cb497aa62d4, + 0x00000000000000000000000000000000003d3f23584f113cef1a4b8b7d183f5c, + 0x0000000000000000000000000000000000289ba11d897837f9cec57dcc430bfc, + 0x0000000000000000000000000000000000765dc64f6ed4a6efd7b26c38f79e59, + 0x00000000000000000000000000000000008edf31fabf5c330ecf7f92fb6487cd, + 0x000000000000000000000000000000000053392f8b14dd78af702b3be2e0d557, + 0x000000000000000000000000000000000034abf357bfd56e9786a7e47ed9a5ae, + 0x0000000000000000000000000000000000a9ebb234064c8ab10d4e7900d4b973, + 0x00000000000000000000000000000000002a6850cce14a20463913002ddc0fa6, + 0x0000000000000000000000000000000000a97e3b06586bfa62325ef7557ab536, + 0x0000000000000000000000000000000000b942b0d26e5be2e08cd425107c59f7, + 0x0000000000000000000000000000000000000000000000000000000000000031, + ]; + let c_expected: [Field; 18] = [ + 0x00000000000000000000000000000000004518a874adebbcf963fed876dfcf78, + 0x00000000000000000000000000000000002b1535070c2deca63e2dc7145a9997, + 0x0000000000000000000000000000000000d9b738665a290c09f09202043d9387, + 0x0000000000000000000000000000000000c88853b11034fe12661eb7a5e41ca7, + 0x0000000000000000000000000000000000357cc4053e7eb127abc2c1430972a1, + 0x0000000000000000000000000000000000224df5e1be31a51562f8574027a992, + 0x000000000000000000000000000000000070ad9287e6326d534f1d2835e159ad, + 0x00000000000000000000000000000000000efa138f75f20b5117955e15bbb447, + 0x0000000000000000000000000000000000d9f45c310be1865ad23fbcdeb1d93f, + 0x00000000000000000000000000000000004f74ca4cf3df59a83f2df796fc9beb, + 0x0000000000000000000000000000000000ed1801428ebf7db771deb45f4311eb, + 0x00000000000000000000000000000000002ded3b46e3a84cda43157d4d927162, + 0x00000000000000000000000000000000009bcd6ac8f90601a44a84a026d4b383, + 0x0000000000000000000000000000000000ab098478b39031a1de85062fd5712b, + 0x00000000000000000000000000000000004432a79276f4375ff3ec2ced8b6cf6, + 0x0000000000000000000000000000000000a0922d75e96e3f9e31c0cbbcbd708a, + 0x00000000000000000000000000000000004013822c9e9aa5b5b1e9c33e4332b7, + 0x0000000000000000000000000000000000000000000000000000000000000058, + ]; + + let a_bn: BN2048 = BigNum { limbs: a }; + let b_bn: BN2048 = BigNum { limbs: b }; + let c_bn = unsafe { a_bn.__mul(b_bn) }; + assert(c_bn.limbs == c_expected); + + a_bn.validate_in_range(); + + BigNum::evaluate_quadratic_expression([[a_bn]], [[false]], [[b_bn]], [[false]], [c_bn], [true]); +} + +#[test] +fn test_expressions() { + let x: [Field; 6] = [ + 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, + 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, + 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, + 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, + 0x00000000000000000000000000000000000000000000000000000000b05d5ac5, + 0, + ]; + + let y: Fq = BigNum { limbs: [0x1, 0x1, 0x0] }; + let z: Fq = BigNum { limbs: [0x2, 0x2, 0x0] }; + let yy = unsafe { y.__add(y) }; + + assert(yy.limbs == z.limbs); + + let uu: Fq = BigNum { + limbs: [ + 0x0000000000000000000000000000000000b4a832748da6ad742a1fd81b787643, + 0x00000000000000000000000000000000009575f594e04080471712c1d7f18e89, + 0x000000000000000000000000000000000000000000000000000000000000063, + ], + }; + let vv: Fq = BigNum { + limbs: [ + 0x0000000000000000000000000000000000b4aec2748da6ad742a1fd81b787643, + 0x00000000000000000000000000000000009575f594e0408047171a01d7f18e89, + 0x0000000000000000000000000000000000000000000000000000000000000062, + ], + }; + let w: Fq = BigNum { + limbs: [ + 0x0000000000000000000000000000000000b4a832748da6ad742a1fd81b787643, + 0x00000000000000000000000000000000009575f594e04080471712c1d7f18e89, + 0x0000000000000000000000000000000000000000000000000000000000001f93, + ], + }; + let x: Fq = BigNum { + limbs: [ + 0x0000000000000000000000000000000000b4aec2748da6ad742a1fd81b787643, + 0x00000000000000000000000000000000009575f594e0408047171a01d7f18e89, + 0x0000000000000000000000000000000000000000000000000000000000000f93, + ], + }; + let wx = unsafe { w.__mul(x) }; + let uv = unsafe { uu.__mul(vv) }; + let y = unsafe { (uv.__add(wx)).__neg() }; + let z = unsafe { uv.__add(wx) }; + + BigNum::evaluate_quadratic_expression( + [[uu], [w]], + [[false], [false]], + [[vv], [x]], + [[false], [false]], + [z], + [true], + ); + BigNum::evaluate_quadratic_expression( + [[uu], [w]], + [[false], [false]], + [[vv], [x]], + [[false], [false]], + [y], + [false], + ); + + let wx_constrained = w * x; + assert(wx_constrained.limbs == wx.limbs); +} + diff --git a/src/tests/mod.nr b/src/tests/mod.nr new file mode 100644 index 00000000..fdef940a --- /dev/null +++ b/src/tests/mod.nr @@ -0,0 +1,2 @@ +mod bignum_test; +mod runtime_bignum_test; diff --git a/src/tests/runtime_bignum_test.nr b/src/tests/runtime_bignum_test.nr new file mode 100644 index 00000000..a97f4ccd --- /dev/null +++ b/src/tests/runtime_bignum_test.nr @@ -0,0 +1,684 @@ +use crate::utils::u60_representation::U60Repr; +use crate::runtime_bignum::RuntimeBigNum; +use crate::params::{BigNumParams, BigNumParamsGetter}; + +use crate::fields::bn254Fq::BN254_Fq_Params; +use crate::fields::secp256k1Fq::Secp256k1_Fq_Params; +use crate::fields::bls12_381Fq::BLS12_381_Fq_Params; +use crate::fields::bls12_381Fr::BLS12_381_Fr_Params; +use crate::fields::bls12_377Fq::BLS12_377_Fq_Params; +use crate::fields::bls12_377Fr::BLS12_377_Fr_Params; + +global TEST_2048_PARAMS: BigNumParams<18, 2048> = BigNumParams { + has_multiplicative_inverse: false, + modulus: [ + 0xc0a197a5ae0fcdceb052c9732614fe, + 0x656ae034423283422243918ab83be3, + 0x6bf590da48a7c1070b7d5aabaac678, + 0x0cce39f530238b606f24b296e2bda9, + 0x01e1fef9bb9c1c3ead98f226f1bfa0, + 0xad8c1c816e12e0ed1379055e373abf, + 0xcebe80e474f753aa9d1461c435123d, + 0xaee5a18ceedef88d115a8b93c167ad, + 0x268ba83c4a65c4307427fc495d9e44, + 0xdd2777926848667b7df79f342639d4, + 0xf455074c96855ca0068668efe7da3d, + 0x5ddba6b30bbc168bfb3a1225f27d65, + 0x591fec484f36707524133bcd6f4258, + 0x59641b756766aeebe66781dd01d062, + 0x58bc5eaff4b165e142bf9e2480eebb, + 0x667a3964f08e06df772ce64b229a72, + 0x9c1fdb18907711bfe3e3c1cf918395, + 0xb8, + ], + double_modulus: [ + 0x0181432f4b5c1f9b9d60a592e64c29fc, + 0x01cad5c06884650684448723157077c6, + 0x01d7eb21b4914f820e16fab557558cef, + 0x01199c73ea604716c0de49652dc57b51, + 0x0103c3fdf37738387d5b31e44de37f3f, + 0x015b183902dc25c1da26f20abc6e757d, + 0x019d7d01c8e9eea7553a28c3886a247a, + 0x015dcb4319ddbdf11a22b5172782cf5a, + 0x014d17507894cb8860e84ff892bb3c88, + 0x01ba4eef24d090ccf6fbef3e684c73a7, + 0x01e8aa0e992d0ab9400d0cd1dfcfb47a, + 0x01bbb74d6617782d17f674244be4faca, + 0x01b23fd8909e6ce0ea4826779ade84af, + 0x01b2c836eacecd5dd7cccf03ba03a0c3, + 0x01b178bd5fe962cbc2857f3c4901dd75, + 0x01ccf472c9e11c0dbeee59cc964534e3, + 0x01383fb63120ee237fc7c7839f230729, + 0x0170, + ], + modulus_u60: U60Repr { + limbs: [ + 0x0eb052c9732614fe, + 0x0c0a197a5ae0fcdc, + 0x022243918ab83be3, + 0x0656ae0344232834, + 0x070b7d5aabaac678, + 0x06bf590da48a7c10, + 0x6f24b296e2bda9, + 0xcce39f530238b6, + 0x0ead98f226f1bfa0, + 0x1e1fef9bb9c1c3, + 0x0d1379055e373abf, + 0x0ad8c1c816e12e0e, + 0x0a9d1461c435123d, + 0x0cebe80e474f753a, + 0x0d115a8b93c167ad, + 0x0aee5a18ceedef88, + 0x7427fc495d9e44, + 0x0268ba83c4a65c43, + 0x0b7df79f342639d4, + 0x0dd2777926848667, + 0x068668efe7da3d, + 0x0f455074c96855ca, + 0x0bfb3a1225f27d65, + 0x05ddba6b30bbc168, + 0x0524133bcd6f4258, + 0x0591fec484f36707, + 0x0be66781dd01d062, + 0x059641b756766aee, + 0x0142bf9e2480eebb, + 0x058bc5eaff4b165e, + 0x0f772ce64b229a72, + 0x0667a3964f08e06d, + 0x0fe3e3c1cf918395, + 0x09c1fdb18907711b, + 0xb8, + 0x00, + ], + }, + modulus_u60_x4: U60Repr { + limbs: [ + 0x0eb052c9732614fe, + 0x0c0a197a5ae0fcdc, + 0x022243918ab83be3, + 0x0656ae0344232834, + 0x070b7d5aabaac678, + 0x06bf590da48a7c10, + 0x6f24b296e2bda9, + 0xcce39f530238b6, + 0x0ead98f226f1bfa0, + 0x1e1fef9bb9c1c3, + 0x0d1379055e373abf, + 0x0ad8c1c816e12e0e, + 0x0a9d1461c435123d, + 0x0cebe80e474f753a, + 0x0d115a8b93c167ad, + 0x0aee5a18ceedef88, + 0x7427fc495d9e44, + 0x0268ba83c4a65c43, + 0x0b7df79f342639d4, + 0x0dd2777926848667, + 0x068668efe7da3d, + 0x0f455074c96855ca, + 0x0bfb3a1225f27d65, + 0x05ddba6b30bbc168, + 0x0524133bcd6f4258, + 0x0591fec484f36707, + 0x0be66781dd01d062, + 0x059641b756766aee, + 0x0142bf9e2480eebb, + 0x058bc5eaff4b165e, + 0x0f772ce64b229a72, + 0x0667a3964f08e06d, + 0x0fe3e3c1cf918395, + 0x09c1fdb18907711b, + 0xb8, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ], + }, + redc_param: [ + 0x1697def7100cd5cf8d890b4ef2ec3f, + 0x765ba8304214dac764d3f4adc31859, + 0x8404bd14d927ea230e60d4bebf9406, + 0xc4d53a23bacc251ecbfc4b7ba5a0b4, + 0x3eaf3499474a6f5b2fff83f1259c87, + 0xbff4c737b97281f1a5f2384a8c16d9, + 0x1b4cf2f55358476b53237829990555, + 0xe7a804e8eacfe3a2a5673bc3885b86, + 0xabadeae4282906c817adf70eab4ae1, + 0x66f7df257fe2bf27f0809aceed9b0e, + 0xd90fb7428901b8bed11f6b81e36bf1, + 0x36e6ba885c60b7024c563605df7e07, + 0x2b7c58d2fb5d2c8478963ae6d4a44f, + 0x6ee761de26635f114ccc3f7d74f855, + 0x3fb726a10cf2220897513f05243de3, + 0x43a26bbd732496eb4d828591b8056e, + 0xf4e42304e60fb3a54fca735499f2cf, + 0x162f, + ], +}; + +struct Test2048Params {} + +// See https://github.com/noir-lang/noir/issues/6172 +#[test] +fn silence_warning() { + let _ = Test2048Params {}; +} + +impl BigNumParamsGetter<18, 2048> for Test2048Params { + fn get_params() -> BigNumParams<18, 2048> { + TEST_2048_PARAMS + } +} + +/** + * @brief experimenting with macro madness and code generation to make some tests that apply to multiple BigNum parametrisations! + **/ +comptime fn make_test(f: StructDefinition, N: Quoted, MOD_BITS: Quoted, typ: Quoted) -> Quoted { + let k = f.name(); + quote { +impl $k { +#[test] +fn test_add() { + let params = $typ ::get_params(); + + 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); + + a.validate_in_range(); + a.validate_in_field(); + b.validate_in_range(); + b.validate_in_field(); + + let mut c = a + b; + c = c + c; + let d = (a + b) * (one + one); + assert(c == d); + + let e = one + one; + for i in 1..$N { + assert(e.limbs[i] == 0); + } + assert(e.limbs[0] == 2); +} + +#[test] +fn test_sub() { + let params = $typ ::get_params(); + + // 0 - 1 should equal p - 1 + let mut a: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::new(params); + let mut b: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::one(params); + let mut expected: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: params.modulus, params }; + + expected.limbs[0] -= 1; // p - 1 + + let result = a - b; + assert(result == expected); +} + + +#[test] +fn test_sub_modulus_limit() { + let params = $typ ::get_params(); + // if we underflow, maximum result should be ... + // 0 - 1 = o-1 + // 0 - p = 0 + let mut a: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::new(params); + let mut b: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: params.modulus, params }; + let mut expected: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::new(params); + + let result = a - b; + assert(result == expected); +} + + +#[test(should_fail_with = "call to assert_max_bit_size")] +fn test_sub_modulus_underflow() { + let params = $typ ::get_params(); + + // 0 - (p + 1) is smaller than p and should produce unsatisfiable constraints + let mut a: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::new(params); + let mut b: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: params.modulus, params }; + b.limbs[0] += 1; + let mut expected: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::one(params); + + let result = a - b; + + assert(result == expected); +} + +#[test] +fn test_add_modulus_limit() { + let params = $typ ::get_params(); + + // p + 2^{modulus_bits()} - 1 should be the maximum allowed value fed into an add operation + // when adding, if the result overflows the modulus, we conditionally subtract the modulus, producing 2^{254} - 1 + // this is the largest value that will satisfy the range check applied when constructing a bignum + let p: U60Repr<$N, 2> = U60Repr::from(params.modulus); + let one = unsafe{ U60Repr::one() }; + + let a: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(p), params }; + + let two_pow_modulus_bits_minus_one: U60Repr<$N, 2> = unsafe{ one.shl($MOD_BITS) - one }; + + let b: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(two_pow_modulus_bits_minus_one), params }; + + let result = a + b; + assert(result == b); +} + +#[test(should_fail_with = "call to assert_max_bit_size")] +fn test_add_modulus_overflow() { + let params = $typ ::get_params(); + + let p : U60Repr<$N, 2> = U60Repr::from(params.modulus); + let one = unsafe{ U60Repr::one() }; + + let a: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(p + one), params }; + + let mut two_pow_modulus_bits_minus_one: U60Repr<$N, 2> = unsafe{ one.shl($MOD_BITS) - one }; + + let b: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(two_pow_modulus_bits_minus_one), params }; + + let result = a + b; + assert(result == b); +} + +#[test] +fn test_mul() { + let params = $typ ::get_params(); + + 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 c = (a + b) * (a + b); + let d = (a * a) + (b * b) + (a * b) + (a * b); + assert(c == d); +} + +#[test] +fn test_quadratic_expression() { + let params = $typ ::get_params(); + + for i in 0..32 { + let X1: RuntimeBigNum<$N, $MOD_BITS> = unsafe{ RuntimeBigNum::__derive_from_seed(params, [i as u8, 2, 3, 4]) }; + let Y1: RuntimeBigNum<$N, $MOD_BITS> = unsafe{ RuntimeBigNum::__derive_from_seed(params, [i as u8, i as u8, 6, 7]) }; + let Z1: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::one(params); + + let (_, YY_mul_2): (RuntimeBigNum<$N, $MOD_BITS>, RuntimeBigNum<$N, $MOD_BITS>) = unsafe{ RuntimeBigNum::__compute_quadratic_expression(params, [[Y1]], [[false]], [[Y1, Y1]], [[false, false]], [], []) }; + let mut (_, XX_mul_3): (RuntimeBigNum<$N, $MOD_BITS>, RuntimeBigNum<$N, $MOD_BITS>) = unsafe{ RuntimeBigNum::__compute_quadratic_expression( + params, + [[X1]], + [[false]], + [[X1, X1, X1]], + [[false, false, false]], + [], + [] + ) }; + let (_, D): (RuntimeBigNum<$N, $MOD_BITS>, RuntimeBigNum<$N, $MOD_BITS>) = unsafe{ RuntimeBigNum::__compute_quadratic_expression(params, [[X1, X1]], [[false, false]], [[YY_mul_2]], [[false]], [], []) }; + let mut (_, X3) = unsafe{ RuntimeBigNum::__compute_quadratic_expression( + params, + [[XX_mul_3]], + [[false]], + [[XX_mul_3]], + [[false]], + [D, D], + [true, true] + ) }; + let (_, Y3): (RuntimeBigNum<$N, $MOD_BITS>, RuntimeBigNum<$N, $MOD_BITS>) = unsafe{ RuntimeBigNum::__compute_quadratic_expression( + params, + [[XX_mul_3], [YY_mul_2]], + [[false], [true]], + [[D, X3], [YY_mul_2, YY_mul_2]], + [[false, true], [false, false]], + [], + [] + ) }; + // 3XX * (D - X3) - 8YYYY + + let (_, Z3): (RuntimeBigNum<$N, $MOD_BITS>, RuntimeBigNum<$N, $MOD_BITS>) = unsafe{ RuntimeBigNum::__compute_quadratic_expression(params, [[Y1]], [[false]], [[Z1, Z1]], [[false, false]], [], []) }; + + X3.validate_in_field(); + Y3.validate_in_field(); + Z3.validate_in_field(); + } +} + +#[test] +fn assert_is_not_equal() { + let params = $typ ::get_params(); + + 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]) + }; + + a.assert_is_not_equal(b); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn assert_is_not_equal_fail() { + let params = $typ ::get_params(); + + 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, [1, 2, 3, 4]) + }; + + a.assert_is_not_equal(b); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn assert_is_not_equal_overloaded_lhs_fail() { + let params = $typ ::get_params(); + + 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, [1, 2, 3, 4]) + }; + + let modulus = params.modulus; + + let t0: U60Repr<$N, 2> = U60Repr::from(a.limbs); + let t1: U60Repr<$N, 2> = U60Repr::from(modulus); + let a_plus_modulus: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(t0 + t1), params }; + + a_plus_modulus.assert_is_not_equal(b); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn assert_is_not_equal_overloaded_rhs_fail() { + let params = $typ ::get_params(); + + 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, [1, 2, 3, 4]) + }; + + let modulus = params.modulus; + + let t0: U60Repr<$N, 2> = U60Repr::from(b.limbs); + let t1: U60Repr<$N, 2> = U60Repr::from(modulus); + let b_plus_modulus: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(t0 + t1), params }; + + a.assert_is_not_equal(b_plus_modulus); +} + +#[test(should_fail_with = "asssert_is_not_equal fail")] +fn assert_is_not_equal_overloaded_fail() { + let params = $typ ::get_params(); + + 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, [1, 2, 3, 4]) + }; + + let modulus = params.modulus; + + let t0: U60Repr<$N, 2> = U60Repr::from(a.limbs); + let t1: U60Repr<$N, 2> = U60Repr::from(b.limbs); + let t2: U60Repr<$N, 2> = U60Repr::from(modulus); + + let a_plus_modulus: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(t0 + t2), params }; + let b_plus_modulus: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(t1 + t2), params }; + + a_plus_modulus.assert_is_not_equal(b_plus_modulus); +} + +#[test] +fn test_derive() +{ + let params = $typ ::get_params(); + + let a: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum::derive_from_seed(params, "hello".as_bytes()); + let b: RuntimeBigNum<$N, $MOD_BITS> = unsafe { + RuntimeBigNum::__derive_from_seed(params, "hello".as_bytes()) + }; + assert(a == b); +} + +#[test] +fn test_eq() { + let params = $typ ::get_params(); + + 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, [1, 2, 3, 4]) + }; + let c: RuntimeBigNum<$N, $MOD_BITS> = unsafe { + RuntimeBigNum::__derive_from_seed(params, [2, 2, 3, 4]) + }; + + let modulus = a.modulus(); + + let t0: U60Repr<$N, 2> = (U60Repr::from(modulus.limbs)); + let t1: U60Repr<$N, 2> = (U60Repr::from(b.limbs)); + + let b_plus_modulus: RuntimeBigNum<$N, $MOD_BITS> = RuntimeBigNum { limbs: U60Repr::into(t0 + t1), params }; + + assert((a == b) == true); + assert((a == b_plus_modulus) == true); + assert((c == b) == false); + assert((c == a) == false); +} + +} +} +} + +#[make_test(quote{3}, quote{254}, quote{BN254_Fq_Params})] +pub struct BNTests {} + +#[make_test(quote{3}, quote{256}, quote{Secp256k1_Fq_Params})] +pub struct Secp256K1FqTests {} + +#[make_test(quote{4}, quote{381} ,quote{BLS12_381_Fq_Params})] +pub struct BLS12_381FqTests {} + +#[make_test(quote{18}, quote{2048}, quote{Test2048Params})] +pub struct Test2048Tests {} + +#[make_test(quote{3}, quote{255}, quote{BLS12_381_Fr_Params})] +pub struct BLS12_381_Fr_ParamsTests {} + +#[make_test(quote{4}, quote{377}, quote{BLS12_377_Fq_Params})] +pub struct BLS12_377_Fq_ParamsTests {} + +#[make_test(quote{3}, quote{253}, quote{BLS12_377_Fr_Params})] +pub struct BLS12_377_Fr_ParamsTests {} + +// 98760 +// 99689 +// 929 gates for a 2048 bit mul + +fn test_div(params: BigNumParams) { + let a: RuntimeBigNum = + unsafe { RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]) }; + let b: RuntimeBigNum = + unsafe { RuntimeBigNum::__derive_from_seed(params, [4, 5, 6, 7]) }; + + let c = a / b; + assert((b * c) == a); +} + +unconstrained fn test_invmod(params: BigNumParams) { + let u: RuntimeBigNum = RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]); + for _ in 0..1 { + let v = u.__invmod(); + let result = u.__mul(v); + let expected: RuntimeBigNum = RuntimeBigNum::one(params); + assert(result.limbs == expected.limbs); + } +} + +#[test] +fn test_div_BN() { + let params = BN254_Fq_Params::get_params(); + test_div(params); +} + +#[test] +fn test_invmod_BN() { + let params = BN254_Fq_Params::get_params(); + unsafe { test_invmod(params) }; +} + +// N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril +// #[test] +// fn test_div_2048() { +// let params = get_2048_params(); +// test_div(params); +// } + +// N.B. witness generation times make these tests take ~15 minutes each! Uncomment at your peril +// #[test] +// fn test_invmod_2048() { +// let params = get_2048_params(); +// test_invmod(params); +// } + +#[test] +fn test_2048_bit_quadratic_expression() { + let params = TEST_2048_PARAMS; + let a: [Field; 18] = [ + 0x000000000000000000000000000000000083684820ff40795b8d9f1be2220cba, + 0x0000000000000000000000000000000000d4924fbdc522b07b6cd0ef5508fd66, + 0x0000000000000000000000000000000000d48f6c43c5930f3d70d6db09a48f4a, + 0x0000000000000000000000000000000000e7f72b2c0756704bea85be38352b34, + 0x00000000000000000000000000000000008337197826e2e9ea000ed5b05d5ac5, + 0x000000000000000000000000000000000040680101b43f6d17de8e3507f3d820, + 0x00000000000000000000000000000000000c6ba0cdcf77cff1c10355ea48d387, + 0x0000000000000000000000000000000000e51717a72902214a9dbeb90e4f225f, + 0x0000000000000000000000000000000000c1bd5bec78406b691f71cbcddb4574, + 0x00000000000000000000000000000000001ce5e532cfb306d7b52e7d9f1aa442, + 0x000000000000000000000000000000000019575932f75ddf00595b22782e1ba2, + 0x0000000000000000000000000000000000d630b3fbf0a9e55861e4399900feb9, + 0x0000000000000000000000000000000000d6b37aeb2daa8d2e2f7e29b0f7752a, + 0x0000000000000000000000000000000000e9cacdd93406256b9eb46b73948849, + 0x00000000000000000000000000000000001400e1f0a38695db66993fe042c48b, + 0x0000000000000000000000000000000000e1d829cb4fa8cabb7d0265efbd8527, + 0x000000000000000000000000000000000055f1a92a5dd099ef2bcd89ac175b52, + 0x00000000000000000000000000000000000000000000000000000000000000fc, + ]; + let b: [Field; 18] = [ + 0x0000000000000000000000000000000000c5694493e9bcc76e68dfcf73e0fde1, + 0x0000000000000000000000000000000000ede5e4b8b3e0dec1f4705c35521620, + 0x00000000000000000000000000000000007aa800bab1b33eda0f07695af6c583, + 0x000000000000000000000000000000000045892edea2c02bf0b8b1d2d9a4ebcc, + 0x00000000000000000000000000000000004dffb06bf396f3d0a5b67cff714bdd, + 0x00000000000000000000000000000000004d691db495235e1e032f1ef3e90274, + 0x0000000000000000000000000000000000d92c069d0f2675b2f46cb497aa62d4, + 0x00000000000000000000000000000000003d3f23584f113cef1a4b8b7d183f5c, + 0x0000000000000000000000000000000000289ba11d897837f9cec57dcc430bfc, + 0x0000000000000000000000000000000000765dc64f6ed4a6efd7b26c38f79e59, + 0x00000000000000000000000000000000008edf31fabf5c330ecf7f92fb6487cd, + 0x000000000000000000000000000000000053392f8b14dd78af702b3be2e0d557, + 0x000000000000000000000000000000000034abf357bfd56e9786a7e47ed9a5ae, + 0x0000000000000000000000000000000000a9ebb234064c8ab10d4e7900d4b973, + 0x00000000000000000000000000000000002a6850cce14a20463913002ddc0fa6, + 0x0000000000000000000000000000000000a97e3b06586bfa62325ef7557ab536, + 0x0000000000000000000000000000000000b942b0d26e5be2e08cd425107c59f7, + 0x0000000000000000000000000000000000000000000000000000000000000031, + ]; + let c_expected: [Field; 18] = [ + 0x00000000000000000000000000000000004518a874adebbcf963fed876dfcf78, + 0x00000000000000000000000000000000002b1535070c2deca63e2dc7145a9997, + 0x0000000000000000000000000000000000d9b738665a290c09f09202043d9387, + 0x0000000000000000000000000000000000c88853b11034fe12661eb7a5e41ca7, + 0x0000000000000000000000000000000000357cc4053e7eb127abc2c1430972a1, + 0x0000000000000000000000000000000000224df5e1be31a51562f8574027a992, + 0x000000000000000000000000000000000070ad9287e6326d534f1d2835e159ad, + 0x00000000000000000000000000000000000efa138f75f20b5117955e15bbb447, + 0x0000000000000000000000000000000000d9f45c310be1865ad23fbcdeb1d93f, + 0x00000000000000000000000000000000004f74ca4cf3df59a83f2df796fc9beb, + 0x0000000000000000000000000000000000ed1801428ebf7db771deb45f4311eb, + 0x00000000000000000000000000000000002ded3b46e3a84cda43157d4d927162, + 0x00000000000000000000000000000000009bcd6ac8f90601a44a84a026d4b383, + 0x0000000000000000000000000000000000ab098478b39031a1de85062fd5712b, + 0x00000000000000000000000000000000004432a79276f4375ff3ec2ced8b6cf6, + 0x0000000000000000000000000000000000a0922d75e96e3f9e31c0cbbcbd708a, + 0x00000000000000000000000000000000004013822c9e9aa5b5b1e9c33e4332b7, + 0x0000000000000000000000000000000000000000000000000000000000000058, + ]; + + let a_bn: RuntimeBigNum<_, 2048> = RuntimeBigNum { limbs: a, params }; + let b_bn: RuntimeBigNum<_, 2048> = RuntimeBigNum { limbs: b, params }; + let c = a_bn * b_bn; + assert(c.limbs == c_expected); + + a_bn.validate_in_range(); + + RuntimeBigNum::evaluate_quadratic_expression( + params, + [[a_bn]], + [[false]], + [[b_bn]], + [[false]], + [c], + [true], + ); +} + +#[test] +fn test_sqrt_BN() { + let params = BN254_Fq_Params::get_params(); + + let x = RuntimeBigNum { limbs: [9, 0, 0], params }; + + let maybe_sqrt_x = x.__tonelli_shanks_sqrt(); + + let sqrt_x = maybe_sqrt_x.unwrap(); + + assert(sqrt_x * sqrt_x == x); +} diff --git a/src/utils/map.nr b/src/utils/map.nr new file mode 100644 index 00000000..698e5f46 --- /dev/null +++ b/src/utils/map.nr @@ -0,0 +1,11 @@ +// Copied from std::array, because I couldn't figure out how to import the `map` method of the weird trait for an array. +// And the reason I wanted direct access to it, is because I couldn't figure out how to implement a double map. +pub(crate) fn map(arr: [T; N], f: fn[Env](T) -> U) -> [U; N] { + let mut ret: [U; N] = std::mem::zeroed(); + + for i in 0..arr.len() { + ret[i] = f(arr[i]); + } + + ret +} diff --git a/src/utils/mod.nr b/src/utils/mod.nr index ca761e47..e419cfce 100644 --- a/src/utils/mod.nr +++ b/src/utils/mod.nr @@ -2,3 +2,4 @@ pub(crate) mod u60_representation; pub(crate) mod split_bits; pub(crate) mod u60_representation_test; pub(crate) mod msb; +pub(crate) mod map; diff --git a/src/utils/msb.nr b/src/utils/msb.nr index 172ca12b..3452eacd 100644 --- a/src/utils/msb.nr +++ b/src/utils/msb.nr @@ -3,18 +3,16 @@ global n1: u32 = 0xffffffff; global MUL_DE_BRUIJN_BIT: [u32; 128] = [ - 0,// change to 1 if you want bitSize(0) = 1 - 48, n1, n1, 31, n1, 15, 51, n1, 63, 5, n1, n1, n1, 19, n1, - 23, 28, n1, n1, n1, 40, 36, 46, n1, 13, n1, n1, n1, 34, n1, 58, - n1, 60, 2, 43, 55, n1, n1, n1, 50, 62, 4, n1, 18, 27, n1, 39, - 45, n1, n1, 33, 57, n1, 1, 54, n1, 49, n1, 17, n1, n1, 32, n1, - 53, n1, 16, n1, n1, 52, n1, n1, n1, 64, 6, 7, 8, n1, 9, n1, - n1, n1, 20, 10, n1, n1, 24, n1, 29, n1, n1, 21, n1, 11, n1, n1, - 41, n1, 25, 37, n1, 47, n1, 30, 14, n1, n1, n1, n1, 22, n1, n1, - 35, 12, n1, n1, n1, 59, 42, n1, n1, 61, 3, 26, 38, 44, n1, 56 - ]; + 0, // change to 1 if you want bitSize(0) = 1 + 48, n1, n1, 31, n1, 15, 51, n1, 63, 5, n1, n1, n1, 19, n1, 23, 28, n1, n1, n1, 40, 36, 46, n1, + 13, n1, n1, n1, 34, n1, 58, n1, 60, 2, 43, 55, n1, n1, n1, 50, 62, 4, n1, 18, 27, n1, 39, 45, + n1, n1, 33, 57, n1, 1, 54, n1, 49, n1, 17, n1, n1, 32, n1, 53, n1, 16, n1, n1, 52, n1, n1, n1, + 64, 6, 7, 8, n1, 9, n1, n1, n1, 20, 10, n1, n1, 24, n1, 29, n1, n1, 21, n1, 11, n1, n1, 41, n1, + 25, 37, n1, 47, n1, 30, 14, n1, n1, n1, n1, 22, n1, n1, 35, 12, n1, n1, n1, 59, 42, n1, n1, 61, + 3, 26, 38, 44, n1, 56, +]; -unconstrained pub fn get_msb64(x: u64) -> u32 { +pub unconstrained fn get_msb64(x: u64) -> u32 { let mut v = x; v |= v >> 1; v |= v >> 2; diff --git a/src/utils/split_bits.nr b/src/utils/split_bits.nr index 3527080e..94d79ea9 100644 --- a/src/utils/split_bits.nr +++ b/src/utils/split_bits.nr @@ -1,13 +1,28 @@ - // Decomposes a single field into two 120 bit fields and a carry -unconstrained pub fn split_120_bits(x: Field) -> (Field, Field) { +pub unconstrained fn split_120_bits(x: Field) -> (Field, Field) { let x_bytes: [u8; 32] = x.to_le_bytes(); let mut low: Field = 0; let mut high: Field = 0; let offsets: [Field; 17] = [ - 1, 0x100, 0x10000, 0x1000000, 0x100000000, 0x10000000000, 0x1000000000000, 0x100000000000000, 0x10000000000000000, 0x1000000000000000000, 0x100000000000000000000, 0x10000000000000000000000, 0x1000000000000000000000000, 0x100000000000000000000000000, 0x10000000000000000000000000000, 0x1000000000000000000000000000000, 0x100000000000000000000000000000000 + 1, + 0x100, + 0x10000, + 0x1000000, + 0x100000000, + 0x10000000000, + 0x1000000000000, + 0x100000000000000, + 0x10000000000000000, + 0x1000000000000000000, + 0x100000000000000000000, + 0x10000000000000000000000, + 0x1000000000000000000000000, + 0x100000000000000000000000000, + 0x10000000000000000000000000000, + 0x1000000000000000000000000000000, + 0x100000000000000000000000000000000, ]; for i in 0..15 { @@ -26,13 +41,22 @@ unconstrained pub fn split_120_bits(x: Field) -> (Field, Field) { * * @description Expects the input limb to be in the range [0, ..., 2^{120 - 1}] **/ -unconstrained pub fn split_60_bits(x: Field) -> (u64, u64) { +pub unconstrained fn split_60_bits(x: Field) -> (u64, u64) { let x_bytes: [u8; 32] = x.to_le_bytes(); let mut low: u64 = 0; let mut high: u64 = 0; - let offsets: [u64; 8] = [1, 0x100, 0x10000, 0x1000000, 0x100000000, 0x10000000000, 0x1000000000000, 0x100000000000000]; + let offsets: [u64; 8] = [ + 1, + 0x100, + 0x10000, + 0x1000000, + 0x100000000, + 0x10000000000, + 0x1000000000000, + 0x100000000000000, + ]; for i in 0..8 { low += (x_bytes[i] as u64) * offsets[i]; high += (x_bytes[i + 8] as u64) * offsets[i]; @@ -44,21 +68,21 @@ unconstrained pub fn split_60_bits(x: Field) -> (u64, u64) { (low, high) } -unconstrained pub(crate) fn __normalize_limbs( +pub(crate) unconstrained fn __normalize_limbs( input: [Field; N], - range: u32 + range: u32, ) -> [Field; N] { let mut normalized: [Field; N] = [0; N]; let mut inp: _ = input; for i in 0..(range - 1) { let (lo, hi) = split_120_bits(inp[i]); - normalized[i]= lo; - inp[i + 1] += hi; + normalized[i] = lo; + inp[i + 1] += hi; } { let (lo, hi) = split_120_bits(inp[range - 1]); - normalized[range - 1]= lo; + normalized[range - 1] = lo; assert(hi == 0); } normalized diff --git a/src/utils/u60_representation.nr b/src/utils/u60_representation.nr index 8ef929c7..ea4c9b50 100644 --- a/src/utils/u60_representation.nr +++ b/src/utils/u60_representation.nr @@ -9,7 +9,7 @@ use crate::utils::msb::get_msb64; * as well as when performing bit shifts. */ pub struct U60Repr { - limbs: [u64; N * NumSegments] + pub(crate) limbs: [u64; N * NumSegments], } impl std::ops::Add for U60Repr { @@ -49,9 +49,7 @@ impl std::convert::From<[Field; N]> for U60Rep fn from(input: [Field; N]) -> Self { let mut result: Self = U60Repr { limbs: [0; N * NumSegments] }; for i in 0..(N) { - let (lo, hi) = unsafe { - split_bits::split_60_bits(input[i]) - }; + let (lo, hi) = unsafe { split_bits::split_60_bits(input[i]) }; result.limbs[2 * i] = lo; result.limbs[2 * i + 1] = hi; } @@ -78,7 +76,9 @@ impl std::cmp::Eq for U60Repr impl U60Repr { - unconstrained fn new(x: [Field; N * NumFieldSegments]) -> Self { + pub(crate) unconstrained fn new( + x: [Field; N * NumFieldSegments], + ) -> Self { let mut result: Self = U60Repr { limbs: [0; N * NumSegments] }; for i in 0..(N * NumFieldSegments) { let (lo, hi) = split_bits::split_60_bits(x[i]); @@ -88,22 +88,24 @@ impl U60Repr { result } - unconstrained fn one() -> Self { + pub(crate) unconstrained fn one() -> Self { let mut result: Self = U60Repr { limbs: [0; N * NumSegments] }; result.limbs[0] = 1; result } - unconstrained fn into_field_array(x: U60Repr) -> [Field; N * NumSegments / 2] { + pub(crate) unconstrained fn into_field_array( + x: U60Repr, + ) -> [Field; N * NumSegments / 2] { let mut result: [Field; N * NumSegments / 2] = [0; N * NumSegments / 2]; let two_pow_60: Field = 0x1000000000000000; for i in 0..(N * NumSegments / 2) { - result[i]= x.limbs[2 * i] as Field + (x.limbs[2 * i + 1] as Field * two_pow_60); + result[i] = x.limbs[2 * i] as Field + (x.limbs[2 * i + 1] as Field * two_pow_60); } result } - unconstrained fn gte(self, b: Self) -> bool { + pub(crate) unconstrained fn gte(self, b: Self) -> bool { let mut result = false; let mut early_exit = false; for i in 0..(N * NumSegments) { @@ -111,7 +113,9 @@ impl U60Repr { result = true; early_exit = true; break; - } else if (b.limbs[(N * NumSegments) - 1 - i] != self.limbs[((N * NumSegments) - 1 - i)]) { + } else if ( + b.limbs[(N * NumSegments) - 1 - i] != self.limbs[((N * NumSegments) - 1 - i)] + ) { result = false; early_exit = true; break; @@ -123,7 +127,7 @@ impl U60Repr { result } - fn get_bit(self, bit: u32) -> bool { + pub(crate) fn get_bit(self, bit: u32) -> bool { let segment_index = bit / 60; let uint_index = bit % 60; @@ -133,7 +137,7 @@ impl U60Repr { } // note: shr cannot satisfy `Shr` Trait due to `shift` parameter being u64 and not u8 (shift value might be greater than 255) - fn shr(self, shift: u32) -> Self { + pub(crate) fn shr(self, shift: u32) -> Self { let mut result: Self = U60Repr { limbs: [0; N * NumSegments] }; let num_shifted_limbs = shift / 60; @@ -152,7 +156,7 @@ impl U60Repr { } // note: shr cannot satisfy `Shr` Trait due to `shift` parameter being u64 and not u8 (shift value might be greater than 255) - fn shr1(&mut self) { + pub(crate) fn shr1(&mut self) { let value = self.limbs[NumSegments * N - 1]; self.limbs[NumSegments * N - 1] = value >> 1; @@ -166,7 +170,7 @@ impl U60Repr { } // note: shr cannot satisfy `Shr` Trait due to `shift` parameter being u64 and not u8 (shift value might be greater than 255) - fn shl(self, shift: u32) -> Self { + pub(crate) fn shl(self, shift: u32) -> Self { let mut result: Self = U60Repr { limbs: [0; NumSegments * N] }; let num_shifted_limbs = shift / 60; @@ -185,7 +189,6 @@ impl U60Repr { result.limbs[num_shifted_limbs] = (value << (limb_shift as u8)) & mask; // shift 84. num shifted = 1 - for i in 1..((N * NumSegments) - num_shifted_limbs) { let value = self.limbs[i]; let upshift = ((value << (limb_shift as u8)) + remainder) & mask; @@ -197,7 +200,7 @@ impl U60Repr { result } - fn increment(&mut self) { + pub(crate) fn increment(&mut self) { let mut carry: u64 = 0; let mut add: u64 = self.limbs[0] + 1; @@ -213,7 +216,7 @@ impl U60Repr { } } - unconstrained fn get_msb(val: Self) -> u32 { + pub(crate) unconstrained fn get_msb(val: Self) -> u32 { let mut count = 0; for i in 0..N * NumSegments { let v = val.limbs[((N * NumSegments) - 1 - i)]; diff --git a/src/utils/u60_representation_test.nr b/src/utils/u60_representation_test.nr index 3ac4df07..da1a38ec 100644 --- a/src/utils/u60_representation_test.nr +++ b/src/utils/u60_representation_test.nr @@ -1,15 +1,11 @@ use crate::utils::u60_representation::U60Repr; #[test] -fn test_conversion() { +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> = unsafe { U60Repr::new(expected) }; + let result = unsafe { u60repr.into_field_array() }; assert(result == expected); } @@ -23,14 +19,10 @@ fn test_shr() { // 120 bits of 01010101 (repeating) let Y = 0x555555555555555555555555555555; let input: [Field; 6] = [X, X, X, X, X, X]; - let u60repr: U60Repr<3, 6> = unsafe { - U60Repr::new(input) - }; + let u60repr: U60Repr<3, 6> = unsafe { U60Repr::new(input) }; let result = u60repr.shr(121); - let expected: U60Repr<3, 6> = unsafe { - U60Repr::new([Y, Y, Y, Y, Y, 0]) - }; + let expected: U60Repr<3, 6> = unsafe { U60Repr::new([Y, Y, Y, Y, Y, 0]) }; assert(result == expected); let noshift = u60repr.shr(0); @@ -44,14 +36,10 @@ fn test_shl() { // 120 bits of 01010101 (repeating) let Y = 0x555555555555555555555555555555; let input: [Field; 6] = [Y, Y, Y, Y, Y, Y]; - let u60repr: U60Repr<3, 6> = unsafe { - U60Repr::new(input) - }; + let u60repr: U60Repr<3, 6> = unsafe { U60Repr::new(input) }; let result = u60repr.shl(121); - let expected: U60Repr<3, 6> = unsafe { - U60Repr::new([0, X, X, X, X, X, X, 0, 0]) - }; + let expected: U60Repr<3, 6> = unsafe { U60Repr::new([0, X, X, X, X, X, X, 0, 0]) }; assert(result == expected); let noshift = u60repr.shr(0); @@ -63,9 +51,7 @@ fn test_get_bit() { // 0x8000 = b1000000000000000 (16th bit is high) // 256th bit of input should be high let input: [Field; 6] = [0, 0, 0x8000, 0, 0, 0]; - let u60repr: U60Repr<3, 6> = unsafe { - U60Repr::new(input) - }; + let u60repr: U60Repr<3, 6> = unsafe { U60Repr::new(input) }; for i in 0..720 { if i == 255 { assert(u60repr.get_bit(i) == true); @@ -76,39 +62,25 @@ fn test_get_bit() { } #[test] -fn test_gte() { +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> = unsafe { U60Repr::new(input) }; { let rhs = lhs; - assert( - unsafe { - lhs.gte(rhs) - } - ); + assert(unsafe { 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(unsafe { lhs.gte(rhs) }); } { // make rhs greater by 1 let mut rhs = lhs; rhs.limbs[0] += 1; - assert( - !unsafe { - lhs.gte(rhs) - } - ); + assert(!unsafe { lhs.gte(rhs) }); } }