Skip to content

Commit

Permalink
attempt at compatible compare gadget
Browse files Browse the repository at this point in the history
  • Loading branch information
mitschabaude committed Mar 26, 2024
1 parent adf67e8 commit cc39156
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/lib/provable/gadgets/comparison.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Field } from '../field.js';
import { createBool, createField } from '../core/field-constructor.js';
import { Fp } from '../../../bindings/crypto/finite-field.js';
import { assert } from '../../../lib/util/assert.js';
import { exists } from '../core/exists.js';
import { assertMul } from './compatible.js';

export { compareCompatible };

/**
* Compare x and y assuming both have at most `n` bits.
*/
function compareCompatible(x: Field, y: Field, n = Fp.sizeInBits - 2) {
// compatible with snarky's `compare`

let maxLength = Fp.sizeInBits - 2;
assert(n <= maxLength, `bitLength must be at most ${maxLength}`);

// 2^n + x - y
let z = createField(1n << BigInt(n))
.add(y)
.sub(x);

let zBits = unpack(z, n + 1);

// n-th bit tells us if x <= y
let lessOrEqual = zBits[n];

// other bits tell us if x = y
let prefix = zBits.slice(0, n);
let notAllZeros = prefix.reduce((a, b) => a.or(b));
let less = lessOrEqual.and(notAllZeros);

return { lessOrEqual, less };
}

// custom version of toBits to be compatible

function unpack(x: Field, length: number) {
let bits = exists(length, () => {
let x0 = x.toBigInt();
return Array.from({ length }, (_, k) => (x0 >> BigInt(k)) & 1n);
});
bits.forEach((b) => b.assertBool());
let lc = bits.reduce(
(acc, b, i) => acc.add(b.mul(1n << BigInt(i))),
createField(0)
);
assertMul(lc, createField(1), x);
return bits.map((b) => createBool(b.value));
}

0 comments on commit cc39156

Please sign in to comment.