Skip to content

Commit

Permalink
address feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
mitschabaude committed Nov 21, 2023
1 parent 976f212 commit 021b001
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 10 deletions.
21 changes: 11 additions & 10 deletions src/lib/gadgets/foreign-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ function singleAdd(x: Field3, y: Field3, sign: Sign, f: bigint) {
let y_ = toBigint3(y);

// figure out if there's overflow
let r = collapse(x_) + sign * collapse(y_);
let r = combine(x_) + sign * combine(y_);
let overflow = 0n;
if (sign === 1n && r >= f) overflow = 1n;
if (sign === -1n && r < 0n) overflow = -1n;
if (f === 0n) overflow = 0n; // special case where overflow doesn't change anything

// do the add with carry
// note: this "just works" with negative r01
let r01 = collapse2(x_) + sign * collapse2(y_) - overflow * collapse2(f_);
let r01 = combine2(x_) + sign * combine2(y_) - overflow * combine2(f_);
let carry = r01 >> l2;
r01 &= l2Mask;
let [r0, r1] = split2(r01);
Expand Down Expand Up @@ -141,6 +141,7 @@ function inverse(x: Field3, f: bigint): Field3 {
return xInv === undefined ? [0n, 0n, 0n] : split(xInv);
});
multiRangeCheck(xInv);
// we need to bound xInv because it's a multiplication input
let xInv2Bound = weakBound(xInv[2], f);

let one: Field2 = [Field.from(1n), Field.from(0n)];
Expand Down Expand Up @@ -189,7 +190,7 @@ function divide(
let y01 = y[0].add(y[1].mul(1n << l));
y01.equals(0n).and(y[2].equals(0n)).assertFalse();
let [f0, f1, f2] = split(f);
let f01 = collapse2([f0, f1]);
let f01 = combine2([f0, f1]);
y01.equals(f01).and(y[2].equals(f2)).assertFalse();
}

Expand Down Expand Up @@ -233,21 +234,21 @@ function multiplyNoRangeCheck(a: Field3, b: Field3, f: bigint) {
let [b0, b1, b2] = toBigint3(b);

// compute q and r such that a*b = q*f + r
let ab = collapse([a0, a1, a2]) * collapse([b0, b1, b2]);
let ab = combine([a0, a1, a2]) * combine([b0, b1, b2]);
let q = ab / f;
let r = ab - q * f;

let [q0, q1, q2] = split(q);
let [r0, r1, r2] = split(r);
let r01 = collapse2([r0, r1]);
let r01 = combine2([r0, r1]);

// compute product terms
let p0 = a0 * b0 + q0 * f_0;
let p1 = a0 * b1 + a1 * b0 + q0 * f_1 + q1 * f_0;
let p2 = a0 * b2 + a1 * b1 + a2 * b0 + q0 * f_2 + q1 * f_1 + q2 * f_0;

let [p10, p110, p111] = split(p1);
let p11 = collapse2([p110, p111]);
let p11 = combine2([p110, p111]);

// carry bottom limbs
let c0 = (p0 + (p10 << l) - r01) >> l2;
Expand Down Expand Up @@ -337,7 +338,7 @@ const Field3 = {
* Turn a 3-tuple of Fields into a bigint
*/
toBigint(x: Field3): bigint {
return collapse(toBigint3(x));
return combine(toBigint3(x));
},

/**
Expand All @@ -352,22 +353,22 @@ const Field3 = {
type Field2 = [Field, Field];
const Field2 = {
toBigint(x: Field2): bigint {
return collapse2(Tuple.map(x, (x) => x.toBigInt()));
return combine2(Tuple.map(x, (x) => x.toBigInt()));
},
};

function toBigint3(x: Field3): bigint3 {
return Tuple.map(x, (x) => x.toBigInt());
}

function collapse([x0, x1, x2]: bigint3) {
function combine([x0, x1, x2]: bigint3) {
return x0 + (x1 << l) + (x2 << l2);
}
function split(x: bigint): bigint3 {
return [x & lMask, (x >> l) & lMask, (x >> l2) & lMask];
}

function collapse2([x0, x1]: bigint3 | [bigint, bigint]) {
function combine2([x0, x1]: bigint3 | [bigint, bigint]) {
return x0 + (x1 << l);
}
function split2(x: bigint): [bigint, bigint] {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/gadgets/gadgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ const Gadgets = {
* Foreign field subtraction: `x - y mod f`
*
* See {@link ForeignField.add} for assumptions and usage examples.
*
* @throws fails if `x - y < -f`, where the result cannot be brought back to a positive number by adding `f` once.
*/
sub(x: Field3, y: Field3, f: bigint) {
return ForeignField.sub(x, y, f);
Expand Down Expand Up @@ -466,6 +468,8 @@ const Gadgets = {
* See {@link ForeignField.mul} for assumptions on inputs and usage examples.
*
* This gadget adds an extra bound check on the result, so it can be used directly in another foreign field multiplication.
*
* @throws Different than {@link ForeignField.mul}, this fails on unreduced input `x`, because it checks that `x === (x/y)*y` and the right side will be reduced.
*/
div(x: Field3, y: Field3, f: bigint) {
return ForeignField.div(x, y, f);
Expand Down

0 comments on commit 021b001

Please sign in to comment.