Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue: nargo is complaining about trait visibility not matching the import #92

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
name = "bignum"
type = "lib"
authors = [""]
compiler_version = ">=1.0.0"
compiler_version = ">=0.38.0"

[dependencies]
1 change: 1 addition & 0 deletions export/test_add_BN.json

Large diffs are not rendered by default.

22 changes: 19 additions & 3 deletions src/bignum.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::params::BigNumParamsGetter;

use crate::fns::{
constrained_ops::{
add, assert_is_not_equal, conditional_select, derive_from_seed, div, eq, mul, neg, sub,
udiv, udiv_mod, umod, validate_in_field, validate_in_range,
add, assert_is_not_equal, conditional_select, derive_from_seed, div, eq, from_field, mul,
neg, sub, udiv, udiv_mod, umod, validate_in_field, validate_in_range,
},
expressions::{__compute_quadratic_expression, evaluate_quadratic_expression},
serialization::{from_be_bytes, to_le_bytes},
Expand All @@ -26,6 +26,7 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq {
// fn default() -> Self { std::default::Default::default () }
pub fn new() -> Self;
pub fn one() -> Self;
pub fn from_field(field: Field) -> Self;
pub fn derive_from_seed<let SeedBytes: u32>(seed: [u8; SeedBytes]) -> Self;
pub unconstrained fn __derive_from_seed<let SeedBytes: u32>(seed: [u8; SeedBytes]) -> Self;
pub fn from_slice(limbs: [Field]) -> Self;
Expand Down Expand Up @@ -88,6 +89,16 @@ pub trait BigNumTrait: Neg + Add + Sub + Mul + Div + Eq {
pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self;
}

// impl<let N: u32, let MOD_BITS: u32, Params> std::convert::From<Field> for BigNum<N, MOD_BITS, Params>
// where
// Params: BigNumParamsGetter<N, MOD_BITS>,
// {
// fn from(input: Field) -> Self {
// let params = Params::get_params();
// Self { limbs: from_field::<N, MOD_BITS>(params, input) }
// }
// }

impl<let N: u32, let MOD_BITS: u32, Params> Neg for BigNum<N, MOD_BITS, Params>
where
Params: BigNumParamsGetter<N, MOD_BITS>,
Expand All @@ -113,6 +124,11 @@ where
result
}

fn from_field(field: Field) -> Self {
let params = Params::get_params();
Self { limbs: from_field::<N, MOD_BITS>(params, field) }
}

fn derive_from_seed<let SeedBytes: u32>(seed: [u8; SeedBytes]) -> Self {
let params = Params::get_params();
Self { limbs: derive_from_seed::<_, MOD_BITS, _>(params, seed) }
Expand Down Expand Up @@ -226,7 +242,7 @@ where

unconstrained fn __tonelli_shanks_sqrt(self) -> std::option::Option<Self> {
let params = Params::get_params();
let maybe_limbs = unsafe { __tonelli_shanks_sqrt(params, self.limbs) };
let maybe_limbs = __tonelli_shanks_sqrt(params, self.limbs) ;
maybe_limbs.map(|limbs| Self { limbs })
}

Expand Down
38 changes: 35 additions & 3 deletions src/fns/constrained_ops.nr
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::params::BigNumParams as P;

use crate::fns::{
expressions::evaluate_quadratic_expression,
unconstrained_helpers::{
__add_with_flags, __neg_with_flags, __sub_with_flags, __validate_gt_remainder,
__add_with_flags, __from_field, __neg_with_flags, __sub_with_flags, __validate_gt_remainder,
__validate_in_field_compute_borrow_flags,
},
unconstrained_ops::{__div, __mul, __udiv_mod},
};
use crate::params::BigNumParams as P;

/**
* In this file:
Expand Down Expand Up @@ -36,6 +35,39 @@ use crate::fns::{
* We use a hash function that can be modelled as a random oracle
* This function *should* produce an output that is a uniformly randomly distributed value modulo BigNum::modulus()
**/
pub(crate) fn from_field<let N: u32, let MOD_BITS: u32>(
params: P<N, MOD_BITS>,
field: Field,
) -> [Field; N] {
// @safety : we check that the resulting limbs represent the intended field element we check the bit length, the limbs being max 120 bits, and the value in total is less than the field modulus
let result = unsafe { __from_field::<N>(field) };
// validate the limbs are in range and the value in total is less than 2^254
let shift = 0x1000000000000000000000000000000;
// validate that the last limb is less than the modulus
if N > 2 {
// validate that the result is less than the modulus
let mut grumpkin_modulus = [0; N];
grumpkin_modulus[0] = 0x33e84879b9709143e1f593f0000001;
grumpkin_modulus[1] = 0x4e72e131a029b85045b68181585d28;
grumpkin_modulus[2] = 0x3064;
validate_gt::<N, 254>(grumpkin_modulus, result);
// validate that the limbs are in range
validate_in_range::<N, 254>(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::<N, 254>(result);
result[0] + result[1] * shift
} else {
validate_in_range::<N, 254>(result);
result[0] + result[1] * shift + result[2] * shift * shift
};
assert(field_val == field);
result
}

pub(crate) fn derive_from_seed<let N: u32, let MOD_BITS: u32, let SeedBytes: u32>(
params: P<N, MOD_BITS>,
seed: [u8; SeedBytes],
Expand Down
17 changes: 12 additions & 5 deletions src/fns/unconstrained_helpers.nr
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ global TWO_POW_60: u64 = 0x1000000000000000;
* __tonelli_shanks_sqrt
*/

pub(crate) unconstrained fn __from_field<let N: u32>(field: Field) -> [Field; N] {
// cast the field to a u60 representation
let res_u60: U60Repr<N, 2> = U60Repr::from_field(field);
let result: [Field; N] = U60Repr::into(res_u60);
result
}

pub(crate) unconstrained fn __validate_in_field_compute_borrow_flags<let N: u32, let MOD_BITS: u32>(
params: P<N, MOD_BITS>,
val: [Field; N],
Expand All @@ -35,8 +42,8 @@ pub(crate) unconstrained fn __validate_gt_remainder<let N: u32>(
lhs: [Field; N],
rhs: [Field; N],
) -> ([Field; N], [bool; N], [bool; N]) {
let a_u60: U60Repr<N, 2> = U60Repr::from(lhs);
let mut b_u60: U60Repr<N, 2> = U60Repr::from(rhs);
let a_u60: U60Repr<N, 2> = From::from(lhs);
let mut b_u60: U60Repr<N, 2> = From::from(rhs);

let underflow = b_u60.gte(a_u60);
b_u60 += U60Repr::one();
Expand Down Expand Up @@ -76,7 +83,7 @@ pub(crate) unconstrained fn __neg_with_flags<let N: u32, let MOD_BITS: u32>(
params: P<N, MOD_BITS>,
val: [Field; N],
) -> ([Field; N], [bool; N]) {
let x_u60: U60Repr<N, 2> = U60Repr::from(val);
let x_u60: U60Repr<N, 2> = From::from(val);
let mut result_u60: U60Repr<N, 2> = U60Repr { limbs: [0; 2 * N] };

let mut borrow_in: u64 = 0;
Expand All @@ -101,8 +108,8 @@ pub(crate) unconstrained fn __add_with_flags<let N: u32, let MOD_BITS: u32>(
lhs: [Field; N],
rhs: [Field; N],
) -> ([Field; N], [bool; N], [bool; N], bool) {
let a_u60: U60Repr<N, 2> = U60Repr::from(lhs);
let b_u60: U60Repr<N, 2> = U60Repr::from(rhs);
let a_u60: U60Repr<N, 2> = From::from(lhs);
let b_u60: U60Repr<N, 2> = From::from(rhs);
let add_u60 = a_u60 + b_u60;

let overflow = add_u60.gte(params.modulus_u60);
Expand Down
2 changes: 1 addition & 1 deletion src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ pub(crate) mod utils;
pub use bignum::BigNum;
pub use bignum::BigNumTrait; // So that external code can operate on a generic BigNum, `where BigNum: BigNumTrait`.
pub use runtime_bignum::RuntimeBigNum;

pub use runtime_bignum::RuntimeBigNumTrait;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've imported the trait here. but the I'm getting an error.
the BignumTrait is imported here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2025-01-07 at 15 14 00

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub use is saying that you want to reexport RuntimeBigNumTrait so it's visible outside of the crate. As runtime_bignum::RuntimeBigNumTraitispub(crate)` then you're increasing the visibility of this trait, which isn't allowed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed the trait to a pub instead of pub(crate). The error disappeared but the warning is still around.

Copy link
Member

@TomAFrench TomAFrench Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean?

warning: Visibility is ignored on a trait method
   ┌─ src/runtime_bignum.nr:69:5
   │
69 │     pub fn __udiv_mod(self, divisor: Self) -> (Self, Self);
   │     ---
   │

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is expected as those modifiers don't mean anything on trait methods.

// Tests
mod tests;
4 changes: 2 additions & 2 deletions src/runtime_bignum.nr
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl<let N: u32, let MOD_BITS: u32> RuntimeBigNumTrait<N, MOD_BITS> for RuntimeB
params: BigNumParams<N, MOD_BITS>,
seed: [u8; SeedBytes],
) -> Self {
let limbs = unsafe { derive_from_seed::<_, MOD_BITS, _>(params, seed) };
let limbs = derive_from_seed::<_, MOD_BITS, _>(params, seed) ;
Self { limbs, params }
}

Expand Down Expand Up @@ -281,7 +281,7 @@ impl<let N: u32, let MOD_BITS: u32> RuntimeBigNumTrait<N, MOD_BITS> for RuntimeB
unconstrained fn __batch_invert_slice<let M: u32>(x: [Self]) -> [Self] {
let params = x[0].params;
assert(params.has_multiplicative_inverse);
let all_limbs = unsafe {
let all_limbs = {
let inv_slice =
__batch_invert_slice::<_, MOD_BITS>(params, x.map(|bn| Self::get_limbs(bn)));
inv_slice.as_array()
Expand Down
26 changes: 26 additions & 0 deletions src/tests/bignum_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -790,3 +790,29 @@ fn test_expressions() {
assert(wx_constrained.limbs == wx.limbs);
}

#[test]
fn test_from_field_1_digit() {
let field: Field = 1;
let result = Fq::from_field(field);
assert(result == Fq::one());
}

#[test]
fn test_from_field_2_digits() {
let field: Field = 762576765071760201410184025311678064293966151975347778787092903729041075;
let result = Fq::from_field(field);
let expected: Fq =
BigNum { limbs: [0xe88ed97f8f707abd3fa65763c80eb3, 0x6e7d8b5586595aa1fb2ee04d5cb4f5, 0x0] };
assert(result == expected);
}

#[test]
fn test_from_field_3_digits() {
let field: Field = -1;
let result = Fq::from_field(field);
let expected: Fq = BigNum {
limbs: [0x33e84879b9709143e1f593f0000000, 0x4e72e131a029b85045b68181585d28, 0x3064],
};
assert(result == expected);
}

7 changes: 4 additions & 3 deletions src/tests/runtime_bignum_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ comptime fn make_test(_m: Module, N: u32, MOD_BITS: u32, typ: Quoted) -> Quoted
#[test]
fn test_add() {
let params = $typ ::get_params();

// safety: these are just random values for tests
let a: $RuntimeBigNum<$N, $MOD_BITS> = unsafe{ $RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]) };
let b: $RuntimeBigNum<$N, $MOD_BITS> = unsafe{ $RuntimeBigNum::__derive_from_seed(params, [4, 5, 6, 7]) };
let one: $RuntimeBigNum<$N, $MOD_BITS> = $RuntimeBigNum::one(params);
Expand Down Expand Up @@ -539,9 +539,9 @@ pub mod BLS12_377_Fr_ParamsTests {}

fn test_div<let N: u32, let MOD_BITS: u32>(params: BigNumParams<N, MOD_BITS>) {
let a: RuntimeBigNum<N, MOD_BITS> =
unsafe { RuntimeBigNum::__derive_from_seed(params, [1, 2, 3, 4]) };
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]) };
RuntimeBigNum::__derive_from_seed(params, [4, 5, 6, 7]) ;

let c = a / b;
assert((b * c) == a);
Expand Down Expand Up @@ -741,3 +741,4 @@ fn test_barrett_reduction_fix() {
};
assert(remainder[8].lt(params.modulus[8]));
}

24 changes: 24 additions & 0 deletions src/utils/split_bits.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@ global TWO_POW_56: u64 = 0x100000000000000;
global TWO_POW_60: u64 = 0x1000000000000000;
global TWO_POW_64: Field = 0x10000000000000000;

//fields to u60rep conversion
// field elements are 254 bits
// so there will be 5 limbs
pub unconstrained fn field_to_u60rep(mut x: Field) -> (u64, u64, u64, u64, u64) {
// get the first 60 bits by casting to u64 and then taking the lower 60 bits
// we use the fact that this casting drops everything above 64 bits
let x_first_u64 = (x as u64);
let first: u64 = x_first_u64 % TWO_POW_60;
// this becomes the same as a integer division because we're removing the remainder
x = (x - (first as Field)) / (TWO_POW_60 as Field);
let x_second_u64 = (x as u64);
let second = x_second_u64 % TWO_POW_60;
x = (x - (second as Field)) / (TWO_POW_60 as Field);
let x_third_u64 = (x as u64);
let third = x_third_u64 % TWO_POW_60;
x = (x - (third as Field)) / (TWO_POW_60 as Field);
let x_fourth_u64 = (x as u64);
let fourth = x_fourth_u64 % TWO_POW_60;
x = (x - (fourth as Field)) / (TWO_POW_60 as Field);
let x_fifth_u64 = (x as u64);
let fifth = x_fifth_u64 % TWO_POW_60;
(first, second, third, fourth, fifth)
}

// Decomposes a single field into two 120 bit fields
pub unconstrained fn split_120_bits(mut x: Field) -> (Field, Field) {
// Here we're taking advantage of truncating 64 bit limbs from the input field
Expand Down
63 changes: 63 additions & 0 deletions src/utils/u60_representation.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::utils::msb::get_msb64;
use crate::utils::split_bits;
use crate::utils::split_bits::field_to_u60rep;

/**
* @brief U60Repr represents a BigNum element as a sequence of 60-bit unsigned integers.
Expand Down Expand Up @@ -57,6 +58,29 @@ impl<let N: u32, let NumSegments: u32> std::convert::From<[Field; N]> for U60Rep
}
}

// impl<let N: u32, let NumSegments: u32> std::convert::From<Field> for U60Repr<N, NumSegments> {
// fn from(input: Field) -> Self {
// let (low, mid, high) = unsafe { field_to_u60rep(input) } ;
// let mut result: Self = U60Repr { limbs: [0; N * NumSegments] };
// let N_u60: u32 = N * NumSegments;
// assert(N_u60 >=1, "N must be at least 1");
// if N_u60 == 1 {
// assert((mid ==0) & (high == 0), "input field is too large to fit in a single limb");
// result.limbs[0] = low;
// }
// else if N_u60 == 2{
// assert(high == 0, "input field is too large to fit in two limbs");
// result.limbs[0] = low;
// result.limbs[1] = mid;
// }else{
// result.limbs[0] = low;
// result.limbs[1] = mid;
// result.limbs[2] = high;
// }
// result
// }
// }

impl<let N: u32, let NumSegments: u32> std::convert::Into<[Field; N]> for U60Repr<N, NumSegments> {
fn into(x: U60Repr<N, NumSegments>) -> [Field; N] {
let mut result: [Field; N] = [0; N];
Expand Down Expand Up @@ -94,6 +118,45 @@ impl<let N: u32, let NumSegments: u32> U60Repr<N, NumSegments> {
result
}

pub(crate) fn from_field(input: Field) -> Self {
let (first, second, third, fourth, fifth) = unsafe { field_to_u60rep(input) };
let mut result: Self = U60Repr { limbs: [0; N * NumSegments] };
let N_u60: u32 = N * NumSegments;
assert(N_u60 >= 1, "N must be at least 1");
if N_u60 == 1 {
assert(
(second == 0) & (third == 0) & (fourth == 0) & (fifth == 0),
"input field is too large to fit in a single limb",
);
result.limbs[0] = first;
} else if N_u60 == 2 {
assert(
(third == 0) & (fourth == 0) & (fifth == 0),
"input field is too large to fit in two limbs",
);
result.limbs[0] = first;
result.limbs[1] = second;
} else if N_u60 == 3 {
assert((fourth == 0) & (fifth == 0), "input field is too large to fit in three limbs");
result.limbs[0] = first;
result.limbs[1] = second;
result.limbs[2] = third;
} else if N_u60 == 4 {
assert((fifth == 0), "input field is too large to fit in four limbs");
result.limbs[0] = first;
result.limbs[1] = second;
result.limbs[2] = third;
result.limbs[3] = fourth;
} else {
result.limbs[0] = first;
result.limbs[1] = second;
result.limbs[2] = third;
result.limbs[3] = fourth;
result.limbs[4] = fifth;
}
result
}

pub(crate) unconstrained fn into_field_array(
x: U60Repr<N, NumSegments>,
) -> [Field; N * NumSegments / 2] {
Expand Down
12 changes: 6 additions & 6 deletions src/utils/u60_representation_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::utils::u60_representation::U60Repr;
unconstrained fn test_conversion() {
let p = 0xffffffffffffffffffffffffffffff; // 2^120 - 1
let expected: [Field; 3 * 2] = [p, p - 1, p - 2, p - 3, p - 4, p - 5];
let u60repr: U60Repr<3, 4> = unsafe { U60Repr::new(expected) };
let result = unsafe { u60repr.into_field_array() };
let u60repr: U60Repr<3, 4> = U60Repr::new(expected) ;
let result = u60repr.into_field_array() ;
assert(result == expected);
}

Expand Down Expand Up @@ -65,22 +65,22 @@ fn test_get_bit() {
unconstrained fn test_gte() {
let p = 0xffffffffffffffffffffffffffffff; // 2^120 - 1
let input: [Field; 6] = [p, p - 1, p - 2, p - 3, p - 4, p - 5];
let lhs: U60Repr<3, 6> = unsafe { U60Repr::new(input) };
let lhs: U60Repr<3, 6> = U60Repr::new(input) ;

{
let rhs = lhs;
assert(unsafe { lhs.gte(rhs) });
assert( lhs.gte(rhs) );
}
{
// make rhs smaller by 1
let mut rhs: U60Repr<3, 6> = lhs;
rhs.limbs[0] -= 1;
assert(unsafe { lhs.gte(rhs) });
assert( lhs.gte(rhs) );
}
{
// make rhs greater by 1
let mut rhs = lhs;
rhs.limbs[0] += 1;
assert(!unsafe { lhs.gte(rhs) });
assert(! lhs.gte(rhs) );
}
}
Loading