Skip to content

Commit

Permalink
clarify and rename misleading "is in range" gadget
Browse files Browse the repository at this point in the history
  • Loading branch information
mitschabaude committed Mar 14, 2024
1 parent 2a2debc commit 0021fb1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 20 deletions.
20 changes: 11 additions & 9 deletions src/lib/gadgets/gadgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
rangeCheck64,
rangeCheck32,
rangeCheckN,
isInRangeN,
isDefinitelyInRangeN,
rangeCheck8,
} from './range-check.js';
import {
Expand Down Expand Up @@ -109,24 +109,26 @@ const Gadgets = {
},

/**
* Checks whether the input value is in the range [0, 2^n). `n` must be a multiple of 16.
* Returns a boolean which being true proves that x is in the range [0, 2^n).
*
* This function proves that the provided field element can be represented with `n` bits.
* If the field element exceeds `n` bits, `Bool(false)` is returned and `Bool(true)` otherwise.
* **Beware**: The output being false does **not** prove that x is not in the range [0, 2^n).
* This should not be viewed as a standalone provable method but as an advanced helper function
* for gadgets which need a weakened form of range check.
*
* @param x - The value to be range-checked.
* @param x - The value to be weakly range-checked.
* @param n - The number of bits to be considered for the range check.
*
* @returns a Bool indicating whether the input value is in the range [0, 2^n).
* @returns a Bool that is definitely only true if the input is in the range [0, 2^n),
* but could also be false _even if_ the input is in the range [0, 2^n).
*
* @example
* ```ts
* const x = Provable.witness(Field, () => Field(12345678n));
* let inRange = Gadgets.isInRangeN(32, x); // return Bool(true)
* let definitelyInRange = Gadgets.isDefinitelyInRangeN(32, x); // could be true or false
* ```
*/
isInRangeN(n: number, x: Field) {
return isInRangeN(n, x);
isDefinitelyInRangeN(n: number, x: Field) {
return isDefinitelyInRangeN(n, x);
},
/*
* Asserts that the input value is in the range [0, 2^16).
Expand Down
12 changes: 9 additions & 3 deletions src/lib/gadgets/range-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export {
multiRangeCheck,
compactMultiRangeCheck,
rangeCheckN,
isInRangeN,
isDefinitelyInRangeN,
rangeCheck8,
rangeCheck16,
};
Expand Down Expand Up @@ -289,9 +289,15 @@ function rangeCheckN(n: number, x: Field, message: string = '') {
}

/**
* Checks that x is in the range [0, 2^n) and returns a Boolean indicating whether the check passed.
* Returns a boolean which, being true, proves that x is in the range [0, 2^n).
*
* **Beware**: The output being false does **not** prove that x is not in the range [0, 2^n).
* In other words, it can happen that this returns false even if x is in the range [0, 2^n).
*
* This should not be viewed as a standalone provable method but as an advanced helper function
* for gadgets which need a weakened form of range check.
*/
function isInRangeN(n: number, x: Field) {
function isDefinitelyInRangeN(n: number, x: Field) {
assert(
n <= Fp.sizeInBits,
`bit length must be ${Fp.sizeInBits} or less, got ${n}`
Expand Down
40 changes: 32 additions & 8 deletions src/lib/int.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,15 @@ class UInt64 extends CircuitValue {
let xMinusY = this.value.sub(y.value).seal();
let yMinusX = xMinusY.neg();

let xMinusYFits = RangeCheck.isInRangeN(UInt64.NUM_BITS, xMinusY);
let xMinusYFits = RangeCheck.isDefinitelyInRangeN(
UInt64.NUM_BITS,
xMinusY
);

let yMinusXFits = RangeCheck.isInRangeN(UInt64.NUM_BITS, yMinusX);
let yMinusXFits = RangeCheck.isDefinitelyInRangeN(
UInt64.NUM_BITS,
yMinusX
);

xMinusYFits.or(yMinusXFits).assertEquals(true);
// x <= y if y - x fits in 64 bits
Expand All @@ -425,9 +431,15 @@ class UInt64 extends CircuitValue {
let xMinusY = this.value.sub(y.value).seal();
let yMinusX = xMinusY.neg();

let xMinusYFits = RangeCheck.isInRangeN(UInt64.NUM_BITS, xMinusY);
let xMinusYFits = RangeCheck.isDefinitelyInRangeN(
UInt64.NUM_BITS,
xMinusY
);

let yMinusXFits = RangeCheck.isInRangeN(UInt64.NUM_BITS, yMinusX);
let yMinusXFits = RangeCheck.isDefinitelyInRangeN(
UInt64.NUM_BITS,
yMinusX
);

xMinusYFits.or(yMinusXFits).assertEquals(true);
// x <= y if y - x fits in 64 bits
Expand Down Expand Up @@ -935,8 +947,14 @@ class UInt32 extends CircuitValue {
} else {
let xMinusY = this.value.sub(y.value).seal();
let yMinusX = xMinusY.neg();
let xMinusYFits = RangeCheck.isInRangeN(UInt32.NUM_BITS, xMinusY);
let yMinusXFits = RangeCheck.isInRangeN(UInt32.NUM_BITS, yMinusX);
let xMinusYFits = RangeCheck.isDefinitelyInRangeN(
UInt32.NUM_BITS,
xMinusY
);
let yMinusXFits = RangeCheck.isDefinitelyInRangeN(
UInt32.NUM_BITS,
yMinusX
);
xMinusYFits.or(yMinusXFits).assertEquals(true);
// x <= y if y - x fits in 64 bits
return yMinusXFits;
Expand All @@ -952,8 +970,14 @@ class UInt32 extends CircuitValue {
} else {
let xMinusY = this.value.sub(y.value).seal();
let yMinusX = xMinusY.neg();
let xMinusYFits = RangeCheck.isInRangeN(UInt32.NUM_BITS, xMinusY);
let yMinusXFits = RangeCheck.isInRangeN(UInt32.NUM_BITS, yMinusX);
let xMinusYFits = RangeCheck.isDefinitelyInRangeN(
UInt32.NUM_BITS,
xMinusY
);
let yMinusXFits = RangeCheck.isDefinitelyInRangeN(
UInt32.NUM_BITS,
yMinusX
);
xMinusYFits.or(yMinusXFits).assertEquals(true);
// x <= y if y - x fits in 64 bits
return yMinusXFits;
Expand Down

0 comments on commit 0021fb1

Please sign in to comment.