diff --git a/src/lib/field.ts b/src/lib/field.ts index 2ba4e84534..3ef00688c0 100644 --- a/src/lib/field.ts +++ b/src/lib/field.ts @@ -536,6 +536,43 @@ 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); + * ``` + */ + not(length: number = 32) { + 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)); + } else { + return new Field(Snarky.field.not(this.value, length)); + } + } + /** * @deprecated use `x.equals(0)` which is equivalent */ 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, diff --git a/src/lib/int.ts b/src/lib/int.ts index 39744a84cf..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. * @@ -539,6 +559,27 @@ 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(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. * diff --git a/src/snarky.d.ts b/src/snarky.d.ts index d7f24b000d..87de3b23d3 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, length: number): FieldVar; }; bool: {