From d3dcf4e3df3292cfae7c1eda30994ad6d5b466e8 Mon Sep 17 00:00:00 2001 From: ymekuria Date: Wed, 28 Jun 2023 14:19:01 +0200 Subject: [PATCH 1/8] feat: add NOT gadget to Fields --- src/snarky.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/snarky.d.ts b/src/snarky.d.ts index d7f24b000d..53faf5b4a4 100644 --- a/src/snarky.d.ts +++ b/src/snarky.d.ts @@ -170,6 +170,8 @@ declare const Snarky: { constant: MlOption, terms: MlList> ]; + + not(left: FieldVar, right: FieldVar, length: number): FieldVar; }; bool: { From 0d677a5cb2c79503b2d51fcd30db183e9d1e7482 Mon Sep 17 00:00:00 2001 From: ymekuria Date: Thu, 29 Jun 2023 18:00:38 +0200 Subject: [PATCH 2/8] feat: add not documentation --- src/lib/field.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/lib/field.ts b/src/lib/field.ts index 2ba4e84534..8fc9abf4e1 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -536,6 +536,29 @@ class Field { return new Field(z); } + /** + * Bitwise NOT gate on {@link Field} elements. Equivalent to the [bitwise + * NOT `~` operator in JavaScript](https://developer.mozilla.org/en-US/docs/ + * Web/JavaScript/Reference/Operators/Bitwise_NOT). + * A NOT gate works by returning `1` in each bit position if the + * corresponding bit of the operand is `0`, and returning `0` if the + * corresponding bit of the operand is `1`. + * + * The `length` parameter lets you define how many bits to compare. It + * defaults to the size of the field in bits ({@link Fp.sizeInBits}). + * + * **Note:** Specifying a larger `length` parameter adds additional * * * + * constraints. + * + * @example + * ```ts + * let a = Field(5); // ... 000101 + * let b = a.not(); // ... 111010 + * + * b.assertEquals(-6); + * ``` + */ + /** * @deprecated use `x.equals(0)` which is equivalent */ From a678ec05047ea6f20b2a15dd19bbb7aa9f4f7c37 Mon Sep 17 00:00:00 2001 From: ymekuria Date: Thu, 29 Jun 2023 18:41:06 +0200 Subject: [PATCH 3/8] feat: add NOT to fields class --- src/lib/field.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib/field.ts b/src/lib/field.ts index 8fc9abf4e1..ae8e34e6f3 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -558,6 +558,18 @@ class Field { * b.assertEquals(-6); * ``` */ + not(length: number) { + if (this.isConstant()) { + let max = 1n << BigInt(length); + let thisBigint = this.toBigInt(); + + if (thisBigint >= max) { + throw Error(`${thisBigint} need to fit into ${length} bits.`); + } + + return new Field(Fp.not(thisBigint)); + } + } /** * @deprecated use `x.equals(0)` which is equivalent From 5585d47975b97f6f5b7777368e5f027fad91054c Mon Sep 17 00:00:00 2001 From: ymekuria Date: Thu, 29 Jun 2023 18:45:58 +0200 Subject: [PATCH 4/8] feat: set NOT length default value to 32 --- src/lib/field.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/field.ts b/src/lib/field.ts index ae8e34e6f3..67c3996b92 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -558,7 +558,7 @@ class Field { * b.assertEquals(-6); * ``` */ - not(length: number) { + not(length: number = 32) { if (this.isConstant()) { let max = 1n << BigInt(length); let thisBigint = this.toBigInt(); From e5d6cd6bff66270a8b76663b4a45ef0d97dee30d Mon Sep 17 00:00:00 2001 From: ymekuria Date: Thu, 29 Jun 2023 20:15:21 +0200 Subject: [PATCH 5/8] feat: update NOT in fields --- src/lib/field.ts | 2 ++ src/snarky.d.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/field.ts b/src/lib/field.ts index 67c3996b92..3ef00688c0 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -568,6 +568,8 @@ class Field { } return new Field(Fp.not(thisBigint)); + } else { + return new Field(Snarky.field.not(this.value, length)); } } diff --git a/src/snarky.d.ts b/src/snarky.d.ts index 53faf5b4a4..87de3b23d3 100644 --- a/src/snarky.d.ts +++ b/src/snarky.d.ts @@ -171,7 +171,7 @@ declare const Snarky: { terms: MlList> ]; - not(left: FieldVar, right: FieldVar, length: number): FieldVar; + not(left: FieldVar, length: number): FieldVar; }; bool: { From 6f8d8eef859f2d37521cd6916326eb59ffcbdfd2 Mon Sep 17 00:00:00 2001 From: ymekuria Date: Fri, 30 Jun 2023 01:44:45 +0200 Subject: [PATCH 6/8] feat: add NOT to uint32 --- src/lib/int.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/lib/int.ts b/src/lib/int.ts index 39744a84cf..4a19b132dc 100644 --- a/src/lib/int.ts +++ b/src/lib/int.ts @@ -539,6 +539,28 @@ class UInt32 extends CircuitValue { z.rangeCheckHelper(UInt32.NUM_BITS).assertEquals(z); return new UInt32(z); } + + /** + * Bitwise NOT gate on {@link UInt32} elements. Equivalent to the [bitwise + * NOT `~` operator in JavaScript](https://developer.mozilla.org/en-US/docs/ + * Web/JavaScript/Reference/Operators/Bitwise_NOT). + * A NOT gate works by returning `1` in each bit position if the + * corresponding bit of the operand is `0`, and returning `0` if the + * corresponding bit of the operand is `1`. + * + * @example + * ```ts + * let a = UInt32.from(5); // ... 000101 + * let b = a.not(); // ... 111010 + * + * b.assertEquals(-6); + * ``` + */ + + not() { + return new UInt32(this.value.not(UInt32.NUM_BITS)); + } + /** * @deprecated Use {@link lessThanOrEqual} instead. * From 8d8852f0227b809b297281f5fa1449d4d02704a1 Mon Sep 17 00:00:00 2001 From: ymekuria Date: Fri, 30 Jun 2023 02:25:02 +0200 Subject: [PATCH 7/8] feat: add NOT to uint64 --- src/lib/int.ts | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/lib/int.ts b/src/lib/int.ts index 4a19b132dc..2a08b0fb45 100644 --- a/src/lib/int.ts +++ b/src/lib/int.ts @@ -202,6 +202,26 @@ class UInt64 extends CircuitValue { return new UInt64(z); } + /** + * Bitwise NOT gate on {@link UInt64} elements. Equivalent to the [bitwise + * NOT `~` operator in JavaScript](https://developer.mozilla.org/en-US/docs/ + * Web/JavaScript/Reference/Operators/Bitwise_NOT). + * A NOT gate works by returning `1` in each bit position if the + * corresponding bit of the operand is `0`, and returning `0` if the + * corresponding bit of the operand is `1`. + * + * @example + * ```ts + * let a = UInt64(5); // ... 000101 + * let b = a.not(); // ... 111010 + * + * b.assertEquals(-6); + * ``` + */ + not() { + return new UInt64(this.value.not(UInt64.NUM_BITS)); + } + /** * @deprecated Use {@link lessThanOrEqual} instead. * @@ -550,13 +570,12 @@ class UInt32 extends CircuitValue { * * @example * ```ts - * let a = UInt32.from(5); // ... 000101 - * let b = a.not(); // ... 111010 + * let a = UInt32(5); // ... 000101 + * let b = a.not(); // ... 111010 * * b.assertEquals(-6); * ``` */ - not() { return new UInt32(this.value.not(UInt32.NUM_BITS)); } From b55faffac4319fb3b337580051bf67ee50a93d40 Mon Sep 17 00:00:00 2001 From: ymekuria Date: Fri, 30 Jun 2023 02:59:50 +0200 Subject: [PATCH 8/8] feat: add test for NOT operator --- src/lib/field.unit-test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/lib/field.unit-test.ts b/src/lib/field.unit-test.ts index 657a8c4dbd..d53c56ab0f 100644 --- a/src/lib/field.unit-test.ts +++ b/src/lib/field.unit-test.ts @@ -55,6 +55,21 @@ test(Random.field, Random.int(-5, 5), (x, k) => { deepEqual(Field(x + BigInt(k) * Field.ORDER), Field(x)); }); +// NOT with some common and odd lengths +[2, 4, 8, 16, 32, 64, 3, 5, 10, 15].forEach((length) => { + test(Random.field, Random.field, (x_, _, assert) => { + let modulus = 1n << BigInt(length); + let x = x_ % modulus; + let r1 = Fp.not(BigInt(x)); + + Provable.runAndCheck(() => { + let x_witness = Provable.witness(Field, () => Field(x)); + let r2 = x_witness.not(length); + Provable.asProver(() => assert(r1 === r2.toBigInt())); + }); + }); +}); + // special generator let SmallField = Random.reject( Random.field,