@kotevode/ffjavascript
Version:
Finite Field Library in Javascript
199 lines (157 loc) • 5.04 kB
JavaScript
import { getThreadRng } from "./random.js";
import * as Scalar from "./scalar.js";
export default class WasmField3 {
constructor(tm, prefix, F) {
this.tm = tm;
this.prefix = prefix;
this.F = F;
this.type = "F3";
this.m = F.m * 3;
this.n8 = this.F.n8*3;
this.n32 = this.F.n32*3;
this.n64 = this.F.n64*3;
this.pOp1 = tm.alloc(F.n8*3);
this.pOp2 = tm.alloc(F.n8*3);
this.pOp3 = tm.alloc(F.n8*3);
this.tm.instance.exports[prefix + "_zero"](this.pOp1);
this.zero = tm.getBuff(this.pOp1, this.n8);
this.tm.instance.exports[prefix + "_one"](this.pOp1);
this.one = tm.getBuff(this.pOp1, this.n8);
this.negone = this.neg(this.one);
this.two = this.add(this.one, this.one);
}
op2(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op2Bool(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2);
}
op1(opName, a) {
this.tm.setBuff(this.pOp1, a);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op1Bool(opName, a) {
this.tm.setBuff(this.pOp1, a);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
}
eq(a,b) {
return this.op2Bool("_eq", a, b);
}
isZero(a) {
return this.op1Bool("_isZero", a);
}
add(a,b) {
return this.op2("_add", a, b);
}
sub(a,b) {
return this.op2("_sub", a, b);
}
neg(a) {
return this.op1("_neg", a);
}
inv(a) {
return this.op1("_inverse", a);
}
isNegative(a) {
return this.op1Bool("_isNegative", a);
}
toMontgomery(a) {
return this.op1("_toMontgomery", a);
}
fromMontgomery(a) {
return this.op1("_fromMontgomery", a);
}
mul(a,b) {
return this.op2("_mul", a, b);
}
div(a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_inverse"](this.pOp2, this.pOp2);
this.tm.instance.exports[this.prefix + "_mul"](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
square(a) {
return this.op1("_square", a);
}
isSquare(a) {
return this.op1Bool("_isSquare", a);
}
sqrt(a) {
return this.op1("_sqrt", a);
}
exp(a, b) {
if (!(b instanceof Uint8Array)) {
b = Scalar.toLEBuff(Scalar.e(b));
}
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3);
return this.getBuff(this.pOp3, this.n8);
}
e(a, b) {
if (a instanceof Uint8Array) return a;
if ((Array.isArray(a)) && (a.length == 3)) {
const c1 = this.F.e(a[0], b);
const c2 = this.F.e(a[1], b);
const c3 = this.F.e(a[2], b);
const res = new Uint8Array(this.F.n8*3);
res.set(c1);
res.set(c2, this.F.n8);
res.set(c3, this.F.n8*2);
return res;
} else {
throw new Error("invalid F3");
}
}
toString(a, radix) {
const s1 = this.F.toString(a.slice(0, this.F.n8), radix);
const s2 = this.F.toString(a.slice(this.F.n8, this.F.n8*2), radix);
const s3 = this.F.toString(a.slice(this.F.n8*2), radix);
return `[${s1}, ${s2}, ${s3}]`;
}
fromRng(rng) {
const c1 = this.F.fromRng(rng);
const c2 = this.F.fromRng(rng);
const c3 = this.F.fromRng(rng);
const res = new Uint8Array(this.F.n8*3);
res.set(c1);
res.set(c2, this.F.n8);
res.set(c3, this.F.n8*2);
return res;
}
random() {
return this.fromRng(getThreadRng());
}
toObject(a) {
const c1 = this.F.toObject(a.slice(0, this.F.n8));
const c2 = this.F.toObject(a.slice(this.F.n8, this.F.n8*2));
const c3 = this.F.toObject(a.slice(this.F.n8*2, this.F.n8*3));
return [c1, c2, c3];
}
fromObject(a) {
const buff = new Uint8Array(this.F.n8*3);
const b1 = this.F.fromObject(a[0]);
const b2 = this.F.fromObject(a[1]);
const b3 = this.F.fromObject(a[2]);
buff.set(b1);
buff.set(b2, this.F.n8);
buff.set(b3, this.F.n8*2);
return buff;
}
c1(a) {
return a.slice(0, this.F.n8);
}
c2(a) {
return a.slice(this.F.n8, this.F.n8*2);
}
c3(a) {
return a.slice(this.F.n8*2);
}
}