diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 1799fc43..9bec6407 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -23,8 +23,10 @@ jobs: run: | npm install -g bbup bbup -nv 1.0.0-beta.0 + sudo apt install libc++-dev + - name: Build Noir benchmark programs run: nargo export @@ -47,3 +49,4 @@ jobs: # delete the comment in case changes no longer impact circuit sizes delete: ${{ !steps.gates_diff.outputs.markdown }} message: ${{ steps.gates_diff.outputs.markdown }} + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 98590389..df39c9f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,6 +51,7 @@ jobs: run: nargo test format: + needs: [noir-version-list] runs-on: ubuntu-latest steps: - name: Checkout sources diff --git a/Nargo.toml b/Nargo.toml index 1c3c348f..337a2e09 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -2,6 +2,6 @@ name = "bignum" type = "lib" authors = [""] -compiler_version = ">=1.0.0" +compiler_version = ">=0.36.0" [dependencies] diff --git a/src/bignum.nr b/src/bignum.nr index c723f090..3489308c 100644 --- a/src/bignum.nr +++ b/src/bignum.nr @@ -24,39 +24,39 @@ pub struct BigNum { pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { // 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_be_bytes(x: [u8; NBytes]) -> Self; - pub fn to_le_bytes(self) -> [u8; NBytes]; - - pub fn modulus() -> Self; - pub fn modulus_bits(self) -> u32; - pub fn num_limbs(self) -> u32; - pub fn get_limbs_slice(self) -> [Field]; - 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( + fn new() -> Self; + fn one() -> Self; + fn derive_from_seed(seed: [u8; SeedBytes]) -> Self; + unconstrained fn __derive_from_seed(seed: [u8; SeedBytes]) -> Self; + fn from_slice(limbs: [Field]) -> Self; + fn from_be_bytes(x: [u8; NBytes]) -> Self; + fn to_le_bytes(self) -> [u8; NBytes]; + + fn modulus() -> Self; + fn modulus_bits(self) -> u32; + fn num_limbs(self) -> u32; + fn get_limbs_slice(self) -> [Field]; + fn get_limb(self, idx: u32) -> Field; + fn set_limb(&mut self, idx: u32, value: Field); + + unconstrained fn __eq(self, other: Self) -> bool; + unconstrained fn __is_zero(self) -> bool; + + 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 __pow(self, exponent: Self) -> Self; + + unconstrained fn __batch_invert(to_invert: [Self; M]) -> [Self; M]; + unconstrained fn __batch_invert_slice(to_invert: [Self]) -> [Self]; + + unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option; + + unconstrained fn __compute_quadratic_expression( lhs: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], rhs: [[Self; RHS_N]; NUM_PRODUCTS], @@ -65,7 +65,7 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { add_flags: [bool; ADD_N], ) -> (Self, Self); - pub fn evaluate_quadratic_expression( + fn evaluate_quadratic_expression( lhs: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], rhs: [[Self; RHS_N]; NUM_PRODUCTS], @@ -74,15 +74,15 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq { add_flags: [bool; ADD_N], ); - pub fn assert_is_not_equal(self, other: Self); - pub fn validate_in_range(self); - pub fn validate_in_field(self); + fn assert_is_not_equal(self, other: Self); + fn validate_in_range(self); + fn validate_in_field(self); - pub fn udiv_mod(self, divisor: Self) -> (Self, Self); - pub fn udiv(self, divisor: Self) -> Self; - pub fn umod(self, divisor: Self) -> Self; + fn udiv_mod(self, divisor: Self) -> (Self, Self); + fn udiv(self, divisor: Self) -> Self; + fn umod(self, divisor: Self) -> Self; - pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; + fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; } impl std::convert::From for BigNum diff --git a/src/fns/constrained_ops.nr b/src/fns/constrained_ops.nr index fcdf2147..7b038cd4 100644 --- a/src/fns/constrained_ops.nr +++ b/src/fns/constrained_ops.nr @@ -2,7 +2,7 @@ use crate::fns::{ expressions::evaluate_quadratic_expression, unconstrained_helpers::{ __add_with_flags, __from_field, __neg_with_flags, __sub_with_flags, __validate_gt_remainder, - __validate_in_field_compute_borrow_flags, + __validate_in_field_compute_borrow_flags, __validate_in_grumpkin_compute_borrow_flags, }, unconstrained_ops::{__div, __mul, __udiv_mod}, }; @@ -45,18 +45,18 @@ pub(crate) fn from_field( grumpkin_modulus[0] = 0x33e84879b9709143e1f593f0000001; grumpkin_modulus[1] = 0x4e72e131a029b85045b68181585d28; grumpkin_modulus[2] = 0x3064; - validate_gt::(grumpkin_modulus, result); + validate_gt::(grumpkin_modulus, result); // validate that the limbs are in range - validate_in_range::(result); + validate_in_range::(result); } // validate the limbs sum up to the field value let field_val = if N < 2 { result[0] } else if N == 2 { - validate_in_range::(result); + validate_in_range::(result); result[0] + result[1] * TWO_POW_120 } else { - validate_in_range::(result); + validate_in_range::(result); result[0] + result[1] * TWO_POW_120 + result[2] * TWO_POW_120 * TWO_POW_120 }; assert(field_val == field); @@ -267,6 +267,30 @@ pub(crate) fn validate_in_field( validate_in_range::<_, MOD_BITS>(compare); } +pub(crate) fn validate_in_grumpkin(limbs: [Field; N]) { + // N.B. need to combine with validate_in_range if `self` limbs have not been range constrained + let mut grumpkin_modulus = [0; N]; + grumpkin_modulus[0] = 0x33e84879b9709143e1f593f0000001; + grumpkin_modulus[1] = 0x4e72e131a029b85045b68181585d28; + grumpkin_modulus[2] = 0x3064; + + let mut p_grumpkin_minus_self: [Field; N] = [0; N]; + for i in 0..N { + p_grumpkin_minus_self[i] = grumpkin_modulus[i] - limbs[i]; + } + let borrow_flags = unsafe { __validate_in_grumpkin_compute_borrow_flags(limbs) }; + let two_pow_120: Field = 0x1000000000000000000000000000000; + p_grumpkin_minus_self[0] += borrow_flags[0] as Field * two_pow_120; + for i in 1..N - 1 { + p_grumpkin_minus_self[i] += + (borrow_flags[i] as Field * two_pow_120 - borrow_flags[i - 1] as Field); + } + p_grumpkin_minus_self[N - 1] -= borrow_flags[N - 2] as Field; + let mut compare = limbs; + compare = p_grumpkin_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() **/ diff --git a/src/fns/unconstrained_helpers.nr b/src/fns/unconstrained_helpers.nr index c900958a..07afcda0 100644 --- a/src/fns/unconstrained_helpers.nr +++ b/src/fns/unconstrained_helpers.nr @@ -38,6 +38,21 @@ pub(crate) unconstrained fn __validate_in_field_compute_borrow_flags( + val: [Field; N], +) -> [bool; N] { + let mut flags: [bool; N] = [false; N]; + let mut grumpkin_modulus = [0; N]; + grumpkin_modulus[0] = 0x33e84879b9709143e1f593f0000001; + grumpkin_modulus[1] = 0x4e72e131a029b85045b68181585d28; + grumpkin_modulus[2] = 0x3064; + flags[0] = grumpkin_modulus[0].lt(val[0]); + for i in 1..N - 1 { + flags[i] = grumpkin_modulus[i].lt(val[i] + flags[i - 1] as Field); + } + flags +} + pub(crate) unconstrained fn __validate_gt_remainder( lhs: [Field; N], rhs: [Field; N], diff --git a/src/params.nr b/src/params.nr index f5beb504..aab9d9f2 100644 --- a/src/params.nr +++ b/src/params.nr @@ -19,7 +19,7 @@ pub struct BigNumParams { // 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; + fn get_params() -> BigNumParams; } impl BigNumParams { diff --git a/src/runtime_bignum.nr b/src/runtime_bignum.nr index 64d48461..ce050383 100644 --- a/src/runtime_bignum.nr +++ b/src/runtime_bignum.nr @@ -25,61 +25,58 @@ 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: Neg + Add + Sub + Mul + Div + Eq { - pub fn new(params: BigNumParams) -> Self; - pub fn one(params: BigNumParams) -> Self; - pub fn derive_from_seed( + fn new(params: BigNumParams) -> Self; + fn one(params: BigNumParams) -> Self; + fn derive_from_seed( params: BigNumParams, seed: [u8; SeedBytes], ) -> Self; - pub unconstrained fn __derive_from_seed( + unconstrained 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; + fn from_slice(params: BigNumParams, limbs: [Field]) -> Self; + fn from_array(params: BigNumParams, limbs: [Field; N]) -> Self; + fn from_be_bytes(params: BigNumParams, x: [u8; NBytes]) -> Self; - pub fn to_le_bytes(self) -> [u8; NBytes]; + fn to_le_bytes(self) -> [u8; NBytes]; - pub fn modulus(self) -> Self; - pub fn modulus_bits() -> u32; - pub fn num_limbs() -> u32; + fn modulus(self) -> Self; + fn modulus_bits() -> u32; + 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); + fn get_limbs(self) -> [Field; N]; + fn get_limb(self, idx: u32) -> Field; + 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; + fn __neg(self) -> Self; // unconstrained - pub fn __add(self, other: Self) -> Self; + fn __add(self, other: Self) -> Self; // unconstrained - pub fn __sub(self, other: Self) -> Self; + fn __sub(self, other: Self) -> Self; // unconstrained - pub fn __mul(self, other: Self) -> Self; + fn __mul(self, other: Self) -> Self; // unconstrained - pub fn __div(self, other: Self) -> Self; + fn __div(self, other: Self) -> Self; // unconstrained - pub fn __udiv_mod(self, divisor: Self) -> (Self, Self); + fn __udiv_mod(self, divisor: Self) -> (Self, Self); // unconstrained - pub fn __invmod(self) -> Self; + fn __invmod(self) -> Self; // unconstrained - pub fn __pow(self, exponent: Self) -> Self; + fn __pow(self, exponent: Self) -> Self; // unconstrained - pub fn __batch_invert(x: [Self; M]) -> [Self; M]; + 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; + fn __tonelli_shanks_sqrt(self) -> std::option::Option; // unconstrained - pub fn __compute_quadratic_expression( + fn __compute_quadratic_expression( params: BigNumParams, lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], @@ -89,7 +86,7 @@ pub(crate) trait RuntimeBigNumTrait: Neg + Add + linear_flags: [bool; ADD_N], ) -> (Self, Self); - pub fn evaluate_quadratic_expression( + fn evaluate_quadratic_expression( params: BigNumParams, lhs_terms: [[Self; LHS_N]; NUM_PRODUCTS], lhs_flags: [[bool; LHS_N]; NUM_PRODUCTS], @@ -99,19 +96,19 @@ pub(crate) trait RuntimeBigNumTrait: Neg + Add + linear_flags: [bool; ADD_N], ); - pub fn eq(lhs: Self, rhs: Self) -> bool { + 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); + fn assert_is_not_equal(self, other: Self); + fn validate_in_field(self); + fn validate_in_range(self); // pub fn validate_gt(self, lhs: Self, rhs: Self); - 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; + fn udiv_mod(numerator: Self, divisor: Self) -> (Self, Self); + fn udiv(numerator: Self, divisor: Self) -> Self; + fn umod(numerator: Self, divisor: Self) -> Self; - pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; + fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self; } impl Neg for RuntimeBigNum { diff --git a/src/tests/bignum_test.nr b/src/tests/bignum_test.nr index bc00bda5..2a4ba115 100644 --- a/src/tests/bignum_test.nr +++ b/src/tests/bignum_test.nr @@ -815,3 +815,4 @@ fn test_from_field_3_digits() { }; assert(result == expected); } +