UNPKG

@kotevode/ffjavascript

Version:

Finite Field Library in Javascript

199 lines (157 loc) 5.04 kB
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); } }