From 95d4d133d1eb5e0eb44cd928d8183d890e970a13 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Wed, 8 May 2024 17:27:52 +0100 Subject: [PATCH] feat: add `Not` trait to stdlib (#4999) # Description ## Problem\* Resolves ## Summary\* This PR adds a `Not` trait which is an equivalent of Rust's `std::ops::Not` trait which represents a bitwise NOT. ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [x] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- docs/docs/noir/standard_library/traits.md | 9 +++++++ noir_stdlib/src/ops.nr | 2 +- noir_stdlib/src/ops/bit.nr | 21 ++++++++++++++++ noir_stdlib/src/uint128.nr | 30 +++++++++++++++++++++-- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/docs/docs/noir/standard_library/traits.md b/docs/docs/noir/standard_library/traits.md index 08370dde9e..96a7b8e2f2 100644 --- a/docs/docs/noir/standard_library/traits.md +++ b/docs/docs/noir/standard_library/traits.md @@ -241,6 +241,15 @@ impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } Implementations: #include_code neg-trait-impls noir_stdlib/src/ops/arith.nr rust +### `std::ops::Not` + +#include_code not-trait noir_stdlib/src/ops/bit.nr rust + +`Not::not` is equivalent to the unary bitwise NOT operator `!`. + +Implementations: +#include_code not-trait-impls noir_stdlib/src/ops/bit.nr rust + ### `std::ops::{ BitOr, BitAnd, BitXor }` #include_code bitor-trait noir_stdlib/src/ops/bit.nr rust diff --git a/noir_stdlib/src/ops.nr b/noir_stdlib/src/ops.nr index d7ea1dfd48..8b1903cff0 100644 --- a/noir_stdlib/src/ops.nr +++ b/noir_stdlib/src/ops.nr @@ -2,4 +2,4 @@ mod arith; mod bit; use arith::{Add, Sub, Mul, Div, Rem, Neg}; -use bit::{BitOr, BitAnd, BitXor, Shl, Shr}; +use bit::{Not, BitOr, BitAnd, BitXor, Shl, Shr}; diff --git a/noir_stdlib/src/ops/bit.nr b/noir_stdlib/src/ops/bit.nr index ae06520e9c..a31cfee878 100644 --- a/noir_stdlib/src/ops/bit.nr +++ b/noir_stdlib/src/ops/bit.nr @@ -1,3 +1,24 @@ +// docs:start:not-trait +trait Not { + fn not(self: Self) -> Self; +} +// docs:end:not-trait + +// docs:start:not-trait-impls +impl Not for bool { fn not(self) -> bool { !self } } + +impl Not for u64 { fn not(self) -> u64 { !self } } +impl Not for u32 { fn not(self) -> u32 { !self } } +impl Not for u16 { fn not(self) -> u16 { !self } } +impl Not for u8 { fn not(self) -> u8 { !self } } +impl Not for u1 { fn not(self) -> u1 { !self } } + +impl Not for i8 { fn not(self) -> i8 { !self } } +impl Not for i16 { fn not(self) -> i16 { !self } } +impl Not for i32 { fn not(self) -> i32 { !self } } +impl Not for i64 { fn not(self) -> i64 { !self } } +// docs:end:not-trait-impls + // docs:start:bitor-trait trait BitOr { fn bitor(self, other: Self) -> Self; diff --git a/noir_stdlib/src/uint128.nr b/noir_stdlib/src/uint128.nr index d0f38079e6..9c61fc801f 100644 --- a/noir_stdlib/src/uint128.nr +++ b/noir_stdlib/src/uint128.nr @@ -1,4 +1,4 @@ -use crate::ops::{Add, Sub, Mul, Div, Rem, BitOr, BitAnd, BitXor, Shl, Shr}; +use crate::ops::{Add, Sub, Mul, Div, Rem, Not, BitOr, BitAnd, BitXor, Shl, Shr}; use crate::cmp::{Eq, Ord, Ordering}; global pow64 : Field = 18446744073709551616; //2^64; @@ -228,11 +228,20 @@ impl Ord for U128 { } } +impl Not for U128 { + fn not(self) -> U128 { + U128 { + lo: (!(self.lo as u64)) as Field, + hi: (!(self.hi as u64)) as Field + } + } +} + impl BitOr for U128 { fn bitor(self, other: U128) -> U128 { U128 { lo: ((self.lo as u64) | (other.lo as u64)) as Field, - hi: ((self.hi as u64) | (other.hi as u64))as Field + hi: ((self.hi as u64) | (other.hi as u64)) as Field } } } @@ -284,3 +293,20 @@ impl Shr for U128 { self / U128::from_integer(y) } } + +mod test { + use crate::uint128::{U128, pow64}; + + #[test] + fn test_not() { + let num = U128::from_u64s_le(0, 0); + let not_num = num.not(); + + let max_u64: Field = pow64 - 1; + assert_eq(not_num.hi, max_u64); + assert_eq(not_num.lo, max_u64); + + let not_not_num = not_num.not(); + assert_eq(num, not_not_num); + } +}