Skip to content

Commit

Permalink
Merge branch 'main' into kb/add_from_field_method
Browse files Browse the repository at this point in the history
  • Loading branch information
kashbrti authored Jan 6, 2025
2 parents 27c6139 + b5c6ce2 commit 7cb70cf
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 55 deletions.
89 changes: 89 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Contributing

Thank you for your interest in contributing! We value your contributions. 🙏

This guide will discuss how the team handles [Commits](#commits), [Pull Requests](#pull-requests), [Releases](#releases), the [Changelog](#changelog), and [Response time](#response-time).

**Note:** We won't force external contributors to follow this verbatim, but following these guidelines definitely helps us in accepting your contributions.

## Commits

We want to keep our commits small and focused. This allows for easily reviewing individual commits and/or splitting up pull requests when they grow too big. Additionally, this allows us to merge smaller changes quicker.

When committing, it's often useful to use the `git add -p` workflow to decide on what parts of the changeset to stage for commit.

## Pull Requests

Before you create a pull request, search for any issues related to the change you are making. If none exist already, create an issue that thoroughly describes the problem that you are trying to solve. These are used to inform reviewers of the original intent and should be referenced via the pull request template.

Pull Requests should be focused on the specific change they are working towards. If prerequisite work is required to complete the original pull request, that work should be submitted as a separate pull request.

This strategy avoids scenarios where pull requests grow too large/out-of-scope and don't get proper reviews—we want to avoid "LGTM, I trust you" reviews.

### Conventional Commits

We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) naming conventions for PRs, which help with releases and changelogs. Please use the following format for PR titles:

```
<type>[optional scope]: <description>
```

Generally, we want to only use the three primary types defined by the specification:

- `feat:` - This should be the most used type, as most work we are doing in the project are new features. Commits using this type will always show up in the Changelog.
- `fix:` - When fixing a bug, we should use this type. Commits using this type will always show up in the Changelog.
- `chore:` - The least used type, these are not included in the Changelog unless they are breaking changes. But remain useful for an understandable commit history.

#### Breaking Changes

Annotating BREAKING CHANGES is extremely important to our release process and versioning. To mark a commit as breaking, we add the ! character after the type, but before the colon. For example:

```
feat!: Rename nargo build to nargo check (#693)
```

```
feat(nargo)!: Enforce minimum rustc version
```

#### Scopes

Scopes significantly improve the Changelog, so we want to use a scope whenever possible. If we are only changing one part of the project, we can use the name of the crate, like (nargo) or (noirc_driver). If a change touches multiple parts of the codebase, there might be a better scope, such as using (syntax) for new language features.

```
feat(nargo): Add support for wasm backend (#234)
```

```
feat(syntax): Implement String data type (#123)
```

### Typos and other small changes

Significant changes, like new features or important bug fixes, typically have a more pronounced impact on the project’s overall development. For smaller fixes, such as typos, we encourage you to report them as Issues instead of opening PRs. This approach helps us manage our resources effectively and ensures that every change contributes meaningfully to the project. PRs involving such smaller fixes will likely be closed and incorporated in PRs authored by the core team.

### Reviews

For any repository in the organization, we require code review & approval by **one** team member before the changes are merged, as enforced by GitHub branch protection. Non-breaking pull requests may be merged at any time. Breaking pull requests should only be merged when the team has general agreement of the changes and is preparing a breaking release.

### Documentation

Breaking changes must be documented, either through adding/updating existing docs or README.md.

## Releases

Releases are managed by [Release Please](https://github.com/googleapis/release-please) which runs in a GitHub Action whenever a commit is made on the master branch.

Release Please parses Conventional Commit messages and opens (or updates) a pull request against the master branch that contains updates to the versions & Changelog within the project. If it doesn't detect any breaking change commits, it will only increment the "patch" version; however, if it detects a breaking change commit, it will increment the "minor" version number to indicate a breaking release.

When we are ready to release the version, we approve and squash merge the release pull request into master. Release Please will detect this merge and generate the appropriate tags for the release. Additional release steps may be triggered inside the GitHub Action to automate other parts of the release process.

There is no strict release cadence, but a new release is usually cut every 1 to 2 months.

## Changelog

The Changelog is automatically managed by Release Please and informed by the Conventional Commits (as discussed above).

## Response time

The team will respond to issues and PRs within 1 week from submission.
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 = ">=0.36.0"
compiler_version = ">=1.0.0"

[dependencies]
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ TODO

## Noir Version Compatibility

This library is tested with all stable releases since 0.36.0 as well as nightly.
This library is tested with all stable releases since 1.0.0-beta.0 as well as nightly.

## Dependencies

- Noir ≥v0.36.0
- Noir ≥v1.0.0-beta.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.
Expand All @@ -42,8 +42,8 @@ bignum = { tag = "v0.2.2", git = "https://github.com/noir-lang/noir-bignum" }
Add imports at the top of your Noir code, for example:

```rust
use dep::bignum::fields::U256::U256Params;
use dep::bignum::BigNum;
use bignum::fields::U256::U256Params;
use bignum::BigNum;
```

## `bignum`
Expand Down Expand Up @@ -73,8 +73,8 @@ struct BigNum<let N: u32, let MOD_BITS: u32, Params> {
A simple 1 + 2 = 3 check in 256-bit unsigned integers:

```rust
use dep::bignum::fields::U256::U256Params;
use dep::bignum::BigNum;
use bignum::fields::U256::U256Params;
use bignum::BigNum;

type U256 = BigNum<3, 257, U256Params>;

Expand All @@ -101,8 +101,8 @@ All arithmetic operations are supported including integer div and mod functions
e.g.

```rust
use dep::bignum::fields::U256::U256Params;
use dep::bignum::BigNum;
use bignum::fields::U256::U256Params;
use bignum::BigNum;

type U256 = BigNum<3, 257, U256Params>;

Expand All @@ -124,7 +124,7 @@ TODO: Document existing field presets (e.g. bls, ed25519, secp256k1)
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`.

```rust
use dep::bignum::fields::bn254Fq::BN254_Fq_Params;
use bignum::fields::bn254Fq::BN254_Fq_Params;

// Notice how we don't provide the params here, because we're pretending they're
// not known at compile-time, for illustration purposes.
Expand Down Expand Up @@ -235,9 +235,9 @@ BigNumParams parameters can be derived from a known modulus using the rust crate
## Additional usage examples

```rust
use dep::bignum::fields::bn254Fq::BN254_Fq_Params;
use bignum::fields::bn254Fq::BN254_Fq_Params;

use dep::bignum::BigNum;
use bignum::BigNum;

type Fq = BigNum<3, 254, BN254_Fq_Params>;

Expand Down
33 changes: 14 additions & 19 deletions src/bignum.nr
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ use crate::fns::{
__is_zero, __mul, __neg, __pow, __sub, __tonelli_shanks_sqrt, __udiv_mod,
},
};
use std::ops::{Add, Div, Mul, Neg, Sub};

pub struct BigNum<let N: u32, let MOD_BITS: u32, Params> {
pub limbs: [Field; N],
}
// We aim to avoid needing to add a generic parameter to this trait, for this reason we do not allow
// accessing the limbs of the bignum except through slices.
pub trait BigNumTrait {
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;
Expand Down Expand Up @@ -81,26 +82,14 @@ pub trait BigNumTrait {
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<let N: u32, let MOD_BITS: u32, Params> std::convert::From<Field> for BigNum<N, MOD_BITS, Params>
// where
// Params: BigNumParamsGetter<N, MOD_BITS>,
Expand All @@ -110,6 +99,17 @@ pub trait BigNumTrait {
// 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>,
{
fn neg(self) -> Self {
let params = Params::get_params();
Self { limbs: neg::<_, MOD_BITS>(params, self.limbs) }
}
}

impl<let N: u32, let MOD_BITS: u32, Params> BigNumTrait for BigNum<N, MOD_BITS, Params>
where
Params: BigNumParamsGetter<N, MOD_BITS>,
Expand Down Expand Up @@ -302,11 +302,6 @@ where
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);
Expand Down
2 changes: 1 addition & 1 deletion src/fns/unconstrained_ops.nr
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ pub(crate) unconstrained fn __invmod<let N: u32, let MOD_BITS: u32>(
) -> [Field; N] {
let one: [Field; N] = __one::<N>();
let one_u60: U60Repr<N, 2> = U60Repr::from(one);
let exp_u60 = params.modulus_u60.sub(one_u60.add(one_u60));
let exp_u60 = params.modulus_u60 - (one_u60 + one_u60);
let exp = U60Repr::into(exp_u60);
__pow::<_, MOD_BITS>(params, val, exp)
}
Expand Down
28 changes: 9 additions & 19 deletions src/runtime_bignum.nr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::fns::{
__is_zero, __mul, __neg, __pow, __sub, __tonelli_shanks_sqrt, __udiv_mod,
},
};
use std::ops::{Add, Div, Mul, Neg, Sub};

pub struct RuntimeBigNum<let N: u32, let MOD_BITS: u32> {
pub limbs: [Field; N],
Expand All @@ -23,7 +24,7 @@ impl<let N: u32, let MOD_BITS: u32> RuntimeBigNum<N, MOD_BITS> {}

// 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<let N: u32, let MOD_BITS: u32> {
pub(crate) trait RuntimeBigNumTrait<let N: u32, let MOD_BITS: u32>: Neg + Add + Sub + Mul + Div + Eq {
pub fn new(params: BigNumParams<N, MOD_BITS>) -> Self;
pub fn one(params: BigNumParams<N, MOD_BITS>) -> Self;
pub fn derive_from_seed<let SeedBytes: u32>(
Expand Down Expand Up @@ -106,26 +107,20 @@ pub(crate) trait RuntimeBigNumTrait<let N: u32, let MOD_BITS: u32> {
pub fn validate_in_range(self);
// pub fn validate_gt(self, lhs: Self, rhs: Self);

pub fn neg(self) -> Self;
pub fn add(lhs: Self, rhs: Self) -> Self {
lhs + rhs
}
pub fn sub(lhs: Self, rhs: Self) -> Self {
lhs - rhs
}
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;

pub fn conditional_select(lhs: Self, rhs: Self, predicate: bool) -> Self;
}

impl<let N: u32, let MOD_BITS: u32> Neg for RuntimeBigNum<N, MOD_BITS> {
fn neg(self) -> Self {
let params = self.params;
Self { limbs: neg::<_, MOD_BITS>(params, self.limbs), params }
}
}

impl<let N: u32, let MOD_BITS: u32> RuntimeBigNumTrait<N, MOD_BITS> for RuntimeBigNum<N, MOD_BITS> {

fn new(params: BigNumParams<N, MOD_BITS>) -> Self {
Expand Down Expand Up @@ -360,11 +355,6 @@ impl<let N: u32, let MOD_BITS: u32> RuntimeBigNumTrait<N, MOD_BITS> for RuntimeB
assert_is_not_equal(params, self.limbs, other.limbs);
}

fn neg(self) -> Self {
let params = self.params;
Self { limbs: neg::<_, MOD_BITS>(params, self.limbs), params }
}

fn udiv_mod(self, divisor: Self) -> (Self, Self) {
let params = self.params;
assert(params == divisor.params);
Expand Down
8 changes: 4 additions & 4 deletions src/tests/bignum_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ where
// // // 929 gates for a 2048 bit mul
fn test_mul<let N: u32, BN>()
where
BN: BigNumTrait + std::ops::Mul + std::ops::Add,
BN: BigNumTrait,
{
let a: BN = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) };
let b: BN = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) };
Expand All @@ -287,7 +287,7 @@ where

fn test_add<let N: u32, BN>()
where
BN: BigNumTrait + std::ops::Add + std::ops::Mul + std::cmp::Eq,
BN: BigNumTrait,
{
let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) };
let b: BN = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) };
Expand Down Expand Up @@ -315,7 +315,7 @@ where

fn test_div<let N: u32, BN>()
where
BN: BigNumTrait + std::ops::Div + std::ops::Mul + std::ops::Add + std::cmp::Eq,
BN: BigNumTrait,
{
let a = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) };
let b = unsafe { BN::__derive_from_seed([4, 5, 6, 7]) };
Expand All @@ -326,7 +326,7 @@ where

fn test_invmod<let N: u32, BN>()
where
BN: BigNumTrait + std::cmp::Eq,
BN: BigNumTrait,
{
let u = unsafe { BN::__derive_from_seed([1, 2, 3, 4]) };
for _ in 0..1 {
Expand Down

0 comments on commit 7cb70cf

Please sign in to comment.