UNPKG

wasmcurves

Version:

elliptic curves implementations in wasm

1,368 lines (1,062 loc) 59 kB
const utils = require("../utils"); const buildF1m =require("../build_f1m.js"); const buildF1 =require("../build_f1.js"); const buildF2m =require("../build_f2m.js"); const buildF3m =require("../build_f3m.js"); const buildCurve =require("../build_curve_jacobian_a0.js"); const buildFFT = require("../build_fft"); const buildPol = require("../build_pol"); const buildQAP = require("../build_qap"); const buildApplyKey = require("../build_applykey"); const { bitLength, isOdd, isNegative } = require("../bigint.js"); // Definition here: https://electriccoin.co/blog/new-snark-curve/ module.exports = function buildBLS12381(module, _prefix) { const prefix = _prefix || "bls12381"; if (module.modules[prefix]) return prefix; // already builded const q = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn; const r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n; const n64q = Math.floor((bitLength(q - 1n) - 1)/64) +1; const n8q = n64q*8; const f1size = n8q; const f2size = f1size * 2; const ftsize = f1size * 12; const n64r = Math.floor((bitLength(r - 1n) - 1)/64) +1; const n8r = n64r*8; const frsize = n8r; const pr = module.alloc(utils.bigInt2BytesLE( r, frsize )); const f1mPrefix = buildF1m(module, q, "f1m", "intq"); buildF1(module, r, "fr", "frm", "intr"); const pG1b = module.alloc(utils.bigInt2BytesLE( toMontgomery(4n), f1size )); const g1mPrefix = buildCurve(module, "g1m", "f1m", pG1b); buildFFT(module, "frm", "frm", "frm", "frm_mul"); buildPol(module, "pol", "frm"); buildQAP(module, "qap", "frm"); const f2mPrefix = buildF2m(module, "f1m_neg", "f2m", "f1m"); const pG2b = module.alloc([ ...utils.bigInt2BytesLE( toMontgomery(4n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(4n), f1size ) ]); const g2mPrefix = buildCurve(module, "g2m", "f2m", pG2b); function buildGTimesFr(fnName, opMul) { const f = module.addFunction(fnName); f.addParam("pG", "i32"); f.addParam("pFr", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8r)); f.addCode( c.call("frm_fromMontgomery", c.getLocal("pFr"), AUX), c.call( opMul, c.getLocal("pG"), AUX, c.i32_const(n8r), c.getLocal("pr") ) ); module.exportFunction(fnName); } buildGTimesFr("g1m_timesFr", "g1m_timesScalar"); buildFFT(module, "g1m", "g1m", "frm", "g1m_timesFr"); buildGTimesFr("g2m_timesFr", "g2m_timesScalar"); buildFFT(module, "g2m", "g2m", "frm", "g2m_timesFr"); buildGTimesFr("g1m_timesFrAffine", "g1m_timesScalarAffine"); buildGTimesFr("g2m_timesFrAffine", "g2m_timesScalarAffine"); buildApplyKey(module, "frm_batchApplyKey", "fmr", "frm", n8r, n8r, n8r, "frm_mul"); buildApplyKey(module, "g1m_batchApplyKey", "g1m", "frm", n8q*3, n8q*3, n8r, "g1m_timesFr"); buildApplyKey(module, "g1m_batchApplyKeyMixed", "g1m", "frm", n8q*2, n8q*3, n8r, "g1m_timesFrAffine"); buildApplyKey(module, "g2m_batchApplyKey", "g2m", "frm", n8q*2*3, n8q*3*2, n8r, "g2m_timesFr"); buildApplyKey(module, "g2m_batchApplyKeyMixed", "g2m", "frm", n8q*2*2, n8q*3*2, n8r, "g2m_timesFrAffine"); function toMontgomery(a) { return BigInt(a) * (1n << BigInt(f1size*8)) % q; } const G1gen = [ 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507n, 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569n, 1n ]; const pG1gen = module.alloc( [ ...utils.bigInt2BytesLE( toMontgomery(G1gen[0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G1gen[1]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G1gen[2]), f1size ), ] ); const G1zero = [ 0n, 1n, 0n ]; const pG1zero = module.alloc( [ ...utils.bigInt2BytesLE( toMontgomery(G1zero[0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G1zero[1]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G1zero[2]), f1size ) ] ); const G2gen = [ [ 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160n, 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758n, ],[ 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905n, 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582n, ],[ 1n, 0n, ] ]; const pG2gen = module.alloc( [ ...utils.bigInt2BytesLE( toMontgomery(G2gen[0][0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2gen[0][1]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2gen[1][0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2gen[1][1]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2gen[2][0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2gen[2][1]), f1size ), ] ); const G2zero = [ [ 0n, 0n, ],[ 1n, 0n, ],[ 0n, 0n, ] ]; const pG2zero = module.alloc( [ ...utils.bigInt2BytesLE( toMontgomery(G2zero[0][0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2zero[0][1]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2zero[1][0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2zero[1][1]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2zero[2][0]), f1size ), ...utils.bigInt2BytesLE( toMontgomery(G2zero[2][1]), f1size ), ] ); const pOneT = module.alloc([ ...utils.bigInt2BytesLE( toMontgomery(1n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(0n), f1size ), ]); const pBls12381Twist = module.alloc([ ...utils.bigInt2BytesLE( toMontgomery(1n), f1size ), ...utils.bigInt2BytesLE( toMontgomery(1n), f1size ), ]); function build_mulNR2() { const f = module.addFunction(f2mPrefix + "_mulNR"); f.addParam("x", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); const x0c = c.i32_const(module.alloc(f1size)); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1size)); const r0 = c.getLocal("pr"); const r1 = c.i32_add(c.getLocal("pr"), c.i32_const(f1size)); f.addCode( c.call(f1mPrefix+"_copy", x0, x0c), c.call(f1mPrefix+"_sub", x0, x1, r0), c.call(f1mPrefix+"_add", x0c, x1, r1), ); } build_mulNR2(); const f6mPrefix = buildF3m(module, f2mPrefix+"_mulNR", "f6m", "f2m"); function build_mulNR6() { const f = module.addFunction(f6mPrefix + "_mulNR"); f.addParam("x", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); const c0copy = c.i32_const(module.alloc(f1size*2)); f.addCode( c.call( f2mPrefix + "_copy", c.getLocal("x"), c0copy ), c.call( f2mPrefix + "_mulNR", c.i32_add(c.getLocal("x"), c.i32_const(n8q*4)), c.getLocal("pr") ), c.call( f2mPrefix + "_copy", c.i32_add(c.getLocal("x"), c.i32_const(n8q*2)), c.i32_add(c.getLocal("pr"), c.i32_const(n8q*4)), ), c.call( f2mPrefix + "_copy", c0copy, c.i32_add(c.getLocal("pr"), c.i32_const(n8q*2)), ), ); } build_mulNR6(); const ftmPrefix = buildF2m(module, f6mPrefix+"_mulNR", "ftm", f6mPrefix); const ateLoopCount = 0xd201000000010000n; const ateLoopBitBytes = bits(ateLoopCount); const pAteLoopBitBytes = module.alloc(ateLoopBitBytes); const isLoopNegative = true; const ateCoefSize = 3 * f2size; const ateNDblCoefs = ateLoopBitBytes.length-1; const ateNAddCoefs = ateLoopBitBytes.reduce((acc, b) => acc + ( b!=0 ? 1 : 0) ,0); const ateNCoefs = ateNAddCoefs + ateNDblCoefs + 1; const prePSize = 3*2*n8q; const preQSize = 3*n8q*2 + ateNCoefs*ateCoefSize; const finalExpIsNegative = true; const finalExpZ = 15132376222941642752n; module.modules[prefix] = { n64q: n64q, n64r: n64r, n8q: n8q, n8r: n8r, pG1gen: pG1gen, pG1zero: pG1zero, pG1b: pG1b, pG2gen: pG2gen, pG2zero: pG2zero, pG2b: pG2b, pq: module.modules["f1m"].pq, pr: pr, pOneT: pOneT, r: r, q: q, prePSize: prePSize, preQSize: preQSize }; function naf(n) { let E = n; const res = []; while (E > 0n) { if (isOdd(E)) { const z = 2 - Number(E % 4n); res.push( z ); E = E - BigInt(z); } else { res.push( 0 ); } E = E >> 1n; } return res; } function bits(n) { let E = n; const res = []; while (E > 0n) { if (isOdd(E)) { res.push( 1 ); } else { res.push( 0 ); } E = E >> 1n; } return res; } function buildPrepareG1() { const f = module.addFunction(prefix+ "_prepareG1"); f.addParam("pP", "i32"); f.addParam("ppreP", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine ); } function buildPrepDoubleStep() { const f = module.addFunction(prefix+ "_prepDblStep"); f.addParam("R", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const Rx = c.getLocal("R"); const Ry = c.i32_add(c.getLocal("R"), c.i32_const(2*n8q)); const Rz = c.i32_add(c.getLocal("R"), c.i32_const(4*n8q)); const t0 = c.getLocal("r"); const t3 = c.i32_add(c.getLocal("r"), c.i32_const(2*n8q)); const t6 = c.i32_add(c.getLocal("r"), c.i32_const(4*n8q)); const zsquared = c.i32_const(module.alloc(f2size)); const t1 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); f.addCode( // tmp0 = r.x.square(); c.call(f2mPrefix + "_square", Rx, t0), // tmp1 = r.y.square(); c.call(f2mPrefix + "_square", Ry, t1), // tmp2 = tmp1.square(); c.call(f2mPrefix + "_square", t1, t2), // tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2; c.call(f2mPrefix + "_add", t1, Rx, t3), c.call(f2mPrefix + "_square", t3, t3), c.call(f2mPrefix + "_sub", t3, t0, t3), c.call(f2mPrefix + "_sub", t3, t2, t3), // tmp3 = tmp3 + tmp3; c.call(f2mPrefix + "_add", t3, t3, t3), // tmp4 = tmp0 + tmp0 + tmp0; c.call(f2mPrefix + "_add", t0, t0, t4), c.call(f2mPrefix + "_add", t4, t0, t4), // tmp6 = r.x + tmp4; c.call(f2mPrefix + "_add", Rx, t4, t6), // tmp5 = tmp4.square(); c.call(f2mPrefix + "_square", t4, t5), // zsquared = r.z.square(); c.call(f2mPrefix + "_square", Rz, zsquared), // r.x = tmp5 - tmp3 - tmp3; c.call(f2mPrefix + "_sub", t5, t3, Rx), c.call(f2mPrefix + "_sub", Rx, t3, Rx), // r.z = (r.z + r.y).square() - tmp1 - zsquared; c.call(f2mPrefix + "_add", Rz, Ry, Rz), c.call(f2mPrefix + "_square", Rz, Rz), c.call(f2mPrefix + "_sub", Rz, t1, Rz), c.call(f2mPrefix + "_sub", Rz, zsquared, Rz), // r.y = (tmp3 - r.x) * tmp4; c.call(f2mPrefix + "_sub", t3, Rx, Ry), c.call(f2mPrefix + "_mul", Ry, t4, Ry), // tmp2 = tmp2 + tmp2; c.call(f2mPrefix + "_add", t2, t2, t2), // tmp2 = tmp2 + tmp2; c.call(f2mPrefix + "_add", t2, t2, t2), // tmp2 = tmp2 + tmp2; c.call(f2mPrefix + "_add", t2, t2, t2), // r.y -= tmp2; c.call(f2mPrefix + "_sub", Ry, t2, Ry), // tmp3 = tmp4 * zsquared; c.call(f2mPrefix + "_mul", t4, zsquared, t3), // tmp3 = tmp3 + tmp3; c.call(f2mPrefix + "_add", t3, t3, t3), // tmp3 = -tmp3; c.call(f2mPrefix + "_neg", t3, t3), // tmp6 = tmp6.square() - tmp0 - tmp5; c.call(f2mPrefix + "_square", t6, t6), c.call(f2mPrefix + "_sub", t6, t0, t6), c.call(f2mPrefix + "_sub", t6, t5, t6), // tmp1 = tmp1 + tmp1; c.call(f2mPrefix + "_add", t1, t1, t1), // tmp1 = tmp1 + tmp1; c.call(f2mPrefix + "_add", t1, t1, t1), // tmp6 = tmp6 - tmp1; c.call(f2mPrefix + "_sub", t6, t1, t6), // tmp0 = r.z * zsquared; c.call(f2mPrefix + "_mul", Rz, zsquared, t0), // tmp0 = tmp0 + tmp0; c.call(f2mPrefix + "_add", t0, t0, t0), ); } function buildPrepAddStep() { const f = module.addFunction(prefix+ "_prepAddStep"); f.addParam("R", "i32"); f.addParam("Q", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const Rx = c.getLocal("R"); const Ry = c.i32_add(c.getLocal("R"), c.i32_const(2*n8q)); const Rz = c.i32_add(c.getLocal("R"), c.i32_const(4*n8q)); const Qx = c.getLocal("Q"); const Qy = c.i32_add(c.getLocal("Q"), c.i32_const(2*n8q)); const t10 = c.getLocal("r"); const t1 = c.i32_add(c.getLocal("r"), c.i32_const(2*n8q)); const t9 = c.i32_add(c.getLocal("r"), c.i32_const(4*n8q)); const zsquared = c.i32_const(module.alloc(f2size)); const ysquared = c.i32_const(module.alloc(f2size)); const ztsquared = c.i32_const(module.alloc(f2size)); const t0 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t3 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); const t6 = c.i32_const(module.alloc(f2size)); const t7 = c.i32_const(module.alloc(f2size)); const t8 = c.i32_const(module.alloc(f2size)); f.addCode( // zsquared = r.z.square(); c.call(f2mPrefix + "_square", Rz, zsquared), // ysquared = q.y.square(); c.call(f2mPrefix + "_square", Qy, ysquared), // t0 = zsquared * q.x; c.call(f2mPrefix + "_mul", zsquared, Qx, t0), // t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared; c.call(f2mPrefix + "_add", Qy, Rz, t1), c.call(f2mPrefix + "_square", t1, t1), c.call(f2mPrefix + "_sub", t1, ysquared, t1), c.call(f2mPrefix + "_sub", t1, zsquared, t1), c.call(f2mPrefix + "_mul", t1, zsquared, t1), // t2 = t0 - r.x; c.call(f2mPrefix + "_sub", t0, Rx, t2), // t3 = t2.square(); c.call(f2mPrefix + "_square", t2, t3), // t4 = t3 + t3; c.call(f2mPrefix + "_add", t3, t3, t4), // t4 = t4 + t4; c.call(f2mPrefix + "_add", t4, t4, t4), // t5 = t4 * t2; c.call(f2mPrefix + "_mul", t4, t2, t5), // t6 = t1 - r.y - r.y; c.call(f2mPrefix + "_sub", t1, Ry, t6), c.call(f2mPrefix + "_sub", t6, Ry, t6), // t9 = t6 * q.x; c.call(f2mPrefix + "_mul", t6, Qx, t9), // t7 = t4 * r.x; c.call(f2mPrefix + "_mul", t4, Rx, t7), // r.x = t6.square() - t5 - t7 - t7; c.call(f2mPrefix + "_square", t6, Rx), c.call(f2mPrefix + "_sub", Rx, t5, Rx), c.call(f2mPrefix + "_sub", Rx, t7, Rx), c.call(f2mPrefix + "_sub", Rx, t7, Rx), // r.z = (r.z + t2).square() - zsquared - t3; c.call(f2mPrefix + "_add", Rz, t2, Rz), c.call(f2mPrefix + "_square", Rz, Rz), c.call(f2mPrefix + "_sub", Rz, zsquared, Rz), c.call(f2mPrefix + "_sub", Rz, t3, Rz), // t10 = q.y + r.z; c.call(f2mPrefix + "_add", Qy, Rz, t10), // t8 = (t7 - r.x) * t6; c.call(f2mPrefix + "_sub", t7, Rx, t8), c.call(f2mPrefix + "_mul", t8, t6, t8), // t0 = r.y * t5; c.call(f2mPrefix + "_mul", Ry, t5, t0), // t0 = t0 + t0; c.call(f2mPrefix + "_add", t0, t0, t0), // r.y = t8 - t0; c.call(f2mPrefix + "_sub", t8, t0, Ry), // t10 = t10.square() - ysquared; c.call(f2mPrefix + "_square", t10, t10), c.call(f2mPrefix + "_sub", t10, ysquared, t10), // ztsquared = r.z.square(); c.call(f2mPrefix + "_square", Rz, ztsquared), // t10 = t10 - ztsquared; c.call(f2mPrefix + "_sub", t10, ztsquared, t10), // t9 = t9 + t9 - t10; c.call(f2mPrefix + "_add", t9, t9, t9), c.call(f2mPrefix + "_sub", t9, t10, t9), // t10 = r.z + r.z; c.call(f2mPrefix + "_add", Rz, Rz, t10), // t6 = -t6; c.call(f2mPrefix + "_neg", t6, t6), // t1 = t6 + t6; c.call(f2mPrefix + "_add", t6, t6, t1), ); } function buildPrepareG2() { const f = module.addFunction(prefix+ "_prepareG2"); f.addParam("pQ", "i32"); f.addParam("ppreQ", "i32"); f.addLocal("pCoef", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const Q = c.getLocal("pQ"); const pR = module.alloc(f2size*3); const R = c.i32_const(pR); const base = c.getLocal("ppreQ"); f.addCode( c.call(g2mPrefix + "_normalize", Q, base), c.if( c.call(g2mPrefix + "_isZero", base), c.ret([]) ), c.call(g2mPrefix + "_copy", base, R), c.setLocal("pCoef", c.i32_add(c.getLocal("ppreQ"), c.i32_const(f2size*3))), ); f.addCode( c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)), c.block(c.loop( c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.if( c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes), [ ...c.call(prefix + "_prepAddStep", R, base, c.getLocal("pCoef")), ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ] ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildF6Mul1() { const f = module.addFunction(f6mPrefix+ "_mul1"); f.addParam("pA", "i32"); // F6 f.addParam("pC1", "i32"); // F2 f.addParam("pR", "i32"); // F6 const c = f.getCodeBuilder(); const A_c0 = c.getLocal("pA"); const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*2)); const A_c2 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*4)); const c1 = c.getLocal("pC1"); const t1 = c.getLocal("pR"); const t2 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*2)); const b_b = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*4)); const Ac0_Ac1 = c.i32_const(module.alloc(f1size*2)); const Ac1_Ac2 = c.i32_const(module.alloc(f1size*2)); f.addCode( c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1), c.call(f2mPrefix + "_add", A_c1, A_c2, Ac1_Ac2), // let b_b = self.c1 * c1; c.call(f2mPrefix + "_mul", A_c1, c1, b_b), // let t1 = (self.c1 + self.c2) * c1 - b_b; c.call(f2mPrefix + "_mul", Ac1_Ac2, c1, t1), c.call(f2mPrefix + "_sub", t1, b_b, t1), // let t1 = t1.mul_by_nonresidue(); c.call(f2mPrefix + "_mulNR", t1, t1), // let t2 = (self.c0 + self.c1) * c1 - b_b; c.call(f2mPrefix + "_mul", Ac0_Ac1, c1, t2), c.call(f2mPrefix + "_sub", t2, b_b, t2), ); } buildF6Mul1(); function buildF6Mul01() { const f = module.addFunction(f6mPrefix+ "_mul01"); f.addParam("pA", "i32"); // F6 f.addParam("pC0", "i32"); // F2 f.addParam("pC1", "i32"); // F2 f.addParam("pR", "i32"); // F6 const c = f.getCodeBuilder(); const A_c0 = c.getLocal("pA"); const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*2)); const A_c2 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*4)); const c0 = c.getLocal("pC0"); const c1 = c.getLocal("pC1"); const t1 = c.getLocal("pR"); const t2 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*2)); const t3 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*4)); const a_a = c.i32_const(module.alloc(f1size*2)); const b_b = c.i32_const(module.alloc(f1size*2)); const Ac0_Ac1 = c.i32_const(module.alloc(f1size*2)); const Ac0_Ac2 = c.i32_const(module.alloc(f1size*2)); f.addCode( // let a_a = self.c0 * c0; c.call(f2mPrefix + "_mul", A_c0, c0, a_a), // let b_b = self.c1 * c1; c.call(f2mPrefix + "_mul", A_c1, c1, b_b), c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1), c.call(f2mPrefix + "_add", A_c0, A_c2, Ac0_Ac2), // let t1 = (self.c1 + self.c2) * c1 - b_b; c.call(f2mPrefix + "_add", A_c1, A_c2, t1), c.call(f2mPrefix + "_mul", t1, c1, t1), c.call(f2mPrefix + "_sub", t1, b_b, t1), // let t1 = t1.mul_by_nonresidue() + a_a; c.call(f2mPrefix + "_mulNR", t1, t1), c.call(f2mPrefix + "_add", t1, a_a, t1), // let t2 = (c0 + c1) * (self.c0 + self.c1) - a_a - b_b; c.call(f2mPrefix + "_add", c0, c1, t2), c.call(f2mPrefix + "_mul", t2, Ac0_Ac1, t2), c.call(f2mPrefix + "_sub", t2, a_a, t2), c.call(f2mPrefix + "_sub", t2, b_b, t2), // let t3 = (self.c0 + self.c2) * c0 - a_a + b_b; c.call(f2mPrefix + "_mul", Ac0_Ac2, c0, t3), c.call(f2mPrefix + "_sub", t3, a_a, t3), c.call(f2mPrefix + "_add", t3, b_b, t3), ); } buildF6Mul01(); function buildF12Mul014() { const f = module.addFunction(ftmPrefix+ "_mul014"); f.addParam("pA", "i32"); // F12 f.addParam("pC0", "i32"); // F2 f.addParam("pC1", "i32"); // F2 f.addParam("pC4", "i32"); // F2 f.addParam("pR", "i32"); // F12 const c = f.getCodeBuilder(); const A_c0 = c.getLocal("pA"); const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*6)); const c0 = c.getLocal("pC0"); const c1 = c.getLocal("pC1"); const c4 = c.getLocal("pC4"); const aa = c.i32_const(module.alloc(f1size*6)); const bb = c.i32_const(module.alloc(f1size*6)); const o = c.i32_const(module.alloc(f1size*2)); const R_c0 = c.getLocal("pR"); const R_c1 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*6)); f.addCode( // let aa = self.c0.mul_by_01(c0, c1); c.call(f6mPrefix + "_mul01", A_c0, c0, c1, aa), // let bb = self.c1.mul_by_1(c4); c.call(f6mPrefix + "_mul1", A_c1, c4, bb), // let o = c1 + c4; c.call(f2mPrefix + "_add", c1, c4, o), // let c1 = self.c1 + self.c0; c.call(f6mPrefix + "_add", A_c1, A_c0, R_c1), // let c1 = c1.mul_by_01(c0, &o); c.call(f6mPrefix + "_mul01", R_c1, c0, o, R_c1), // let c1 = c1 - aa - bb; c.call(f6mPrefix + "_sub", R_c1, aa, R_c1), c.call(f6mPrefix + "_sub", R_c1, bb, R_c1), // let c0 = bb; c.call(f6mPrefix + "_copy", bb, R_c0), // let c0 = c0.mul_by_nonresidue(); c.call(f6mPrefix + "_mulNR", R_c0, R_c0), // let c0 = c0 + aa; c.call(f6mPrefix + "_add", R_c0, aa, R_c0), ); } buildF12Mul014(); function buildELL() { const f = module.addFunction(prefix+ "_ell"); f.addParam("pP", "i32"); f.addParam("pCoefs", "i32"); f.addParam("pF", "i32"); const c = f.getCodeBuilder(); const Px = c.getLocal("pP"); const Py = c.i32_add(c.getLocal("pP"), c.i32_const(n8q)); const F = c.getLocal("pF"); const coef0_0 = c.getLocal("pCoefs"); const coef0_1 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size)); const coef1_0 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*2)); const coef1_1 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*3)); const coef2 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*4)); const pc0 = module.alloc(f1size*2); const c0 = c.i32_const(pc0); const c0_c0 = c.i32_const(pc0); const c0_c1 = c.i32_const(pc0+f1size); const pc1 = module.alloc(f1size*2); const c1 = c.i32_const(pc1); const c1_c0 = c.i32_const(pc1); const c1_c1 = c.i32_const(pc1+f1size); f.addCode( // let mut c0 = coeffs.0; // let mut c1 = coeffs.1; // // c0.c0 *= p.y; // c0.c1 *= p.y; // // c1.c0 *= p.x; // c1.c1 *= p.x; // // f.mul_by_014(&coeffs.2, &c1, &c0) c.call(f1mPrefix + "_mul", coef0_0, Py, c0_c0), c.call(f1mPrefix + "_mul", coef0_1, Py, c0_c1), c.call(f1mPrefix + "_mul", coef1_0, Px, c1_c0), c.call(f1mPrefix + "_mul", coef1_1, Px, c1_c1), c.call(ftmPrefix + "_mul014", F, coef2, c1, c0, F), ); } buildELL(); function buildMillerLoop() { const f = module.addFunction(prefix+ "_millerLoop"); f.addParam("ppreP", "i32"); f.addParam("ppreQ", "i32"); f.addParam("r", "i32"); f.addLocal("pCoef", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const preP = c.getLocal("ppreP"); const coefs = c.getLocal("pCoef"); const F = c.getLocal("r"); f.addCode( c.call(ftmPrefix + "_one", F), c.if( c.call(g1mPrefix + "_isZero", preP), c.ret([]) ), c.if( c.call(g1mPrefix + "_isZero", c.getLocal("ppreQ")), c.ret([]) ), c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))), c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)), c.block(c.loop( c.call(prefix + "_ell", preP, coefs, F), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.if( c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes), [ ...c.call(prefix + "_ell", preP, coefs, F), ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ] ), c.call(ftmPrefix + "_square", F, F), c.br_if(1, c.i32_eq ( c.getLocal("i"), c.i32_const(1) )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )), c.call(prefix + "_ell", preP, coefs, F), ); if (isLoopNegative) { f.addCode( c.call(ftmPrefix + "_conjugate", F, F), ); } } function buildFrobeniusMap(n) { const F12 = [ [ [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], ], [ [1n, 0n], [3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760n, 151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027n], [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351n, 0n], [2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n, 1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257n], [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n, 0n], [3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557n, 877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230n], [4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786n, 0n], [151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027n, 3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760n], [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n, 0n], [1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257n, 2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n], [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437n, 0n], [877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230n, 3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557n], ] ]; const F6 = [ [ [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], [1n, 0n], ], [ [1n, 0n], [0n, 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n], [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n, 0n], [0n, 1n], [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n, 0n], [0n, 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n], ], [ [1n, 0n], [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437n, 0n], [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n, 0n], [4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786n, 0n], [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n, 0n], [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351n, 0n], ] ]; const f = module.addFunction(ftmPrefix + "_frobeniusMap"+n); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); for (let i=0; i<6; i++) { const X = (i==0) ? c.getLocal("x") : c.i32_add(c.getLocal("x"), c.i32_const(i*f2size)); const Xc0 = X; const Xc1 = c.i32_add(c.getLocal("x"), c.i32_const(i*f2size + f1size)); const R = (i==0) ? c.getLocal("r") : c.i32_add(c.getLocal("r"), c.i32_const(i*f2size)); const Rc0 = R; const Rc1 = c.i32_add(c.getLocal("r"), c.i32_const(i*f2size + f1size)); const coef = mul2(F12[Math.floor(i/3)][n%12] , F6[i%3][n%6]); const pCoef = module.alloc([ ...utils.bigInt2BytesLE(toMontgomery(coef[0]), n8q), ...utils.bigInt2BytesLE(toMontgomery(coef[1]), n8q), ]); if (n%2 == 1) { f.addCode( c.call(f1mPrefix + "_copy", Xc0, Rc0), c.call(f1mPrefix + "_neg", Xc1, Rc1), c.call(f2mPrefix + "_mul", R, c.i32_const(pCoef), R), ); } else { f.addCode(c.call(f2mPrefix + "_mul", X, c.i32_const(pCoef), R)); } } function mul2(a, b) { const ac0 = a[0]; const ac1 = a[1]; const bc0 = b[0]; const bc1 = b[1]; const res = [ (ac0 * bc0 - (ac1 * bc1)) % q, (ac0 * bc1 + (ac1 * bc0)) % q, ]; if (isNegative(res[0])) res[0] = res[0] + q; return res; } } function buildCyclotomicSquare() { const f = module.addFunction(prefix+ "__cyclotomicSquare"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x4 = c.i32_add(c.getLocal("x"), c.i32_const(f2size)); const x3 = c.i32_add(c.getLocal("x"), c.i32_const(2*f2size)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(3*f2size)); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(4*f2size)); const x5 = c.i32_add(c.getLocal("x"), c.i32_const(5*f2size)); const r0 = c.getLocal("r"); const r4 = c.i32_add(c.getLocal("r"), c.i32_const(f2size)); const r3 = c.i32_add(c.getLocal("r"), c.i32_const(2*f2size)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(3*f2size)); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(4*f2size)); const r5 = c.i32_add(c.getLocal("r"), c.i32_const(5*f2size)); const t0 = c.i32_const(module.alloc(f2size)); const t1 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t3 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); const tmp = c.i32_const(module.alloc(f2size)); const AUX = c.i32_const(module.alloc(f2size)); f.addCode( // // t0 + t1*y = (z0 + z1*y)^2 = a^2 // tmp = z0 * z1; // t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; // t1 = tmp + tmp; c.call(f2mPrefix + "_mul", x0, x1, tmp), c.call(f2mPrefix + "_mulNR", x1, t0), c.call(f2mPrefix + "_add", x0, t0, t0), c.call(f2mPrefix + "_add", x0, x1, AUX), c.call(f2mPrefix + "_mul", AUX, t0, t0), c.call(f2mPrefix + "_mulNR", tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t0, AUX, t0), c.call(f2mPrefix + "_add", tmp, tmp, t1), // // t2 + t3*y = (z2 + z3*y)^2 = b^2 // tmp = z2 * z3; // t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; // t3 = tmp + tmp; c.call(f2mPrefix + "_mul", x2, x3, tmp), c.call(f2mPrefix + "_mulNR", x3, t2), c.call(f2mPrefix + "_add", x2, t2, t2), c.call(f2mPrefix + "_add", x2, x3, AUX), c.call(f2mPrefix + "_mul", AUX, t2, t2), c.call(f2mPrefix + "_mulNR", tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t2, AUX, t2), c.call(f2mPrefix + "_add", tmp, tmp, t3), // // t4 + t5*y = (z4 + z5*y)^2 = c^2 // tmp = z4 * z5; // t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; // t5 = tmp + tmp; c.call(f2mPrefix + "_mul", x4, x5, tmp), c.call(f2mPrefix + "_mulNR", x5, t4), c.call(f2mPrefix + "_add", x4, t4, t4), c.call(f2mPrefix + "_add", x4, x5, AUX), c.call(f2mPrefix + "_mul", AUX, t4, t4), c.call(f2mPrefix + "_mulNR", tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t4, AUX, t4), c.call(f2mPrefix + "_add", tmp, tmp, t5), // For A // z0 = 3 * t0 - 2 * z0 c.call(f2mPrefix + "_sub", t0, x0, r0), c.call(f2mPrefix + "_add", r0, r0, r0), c.call(f2mPrefix + "_add", t0, r0, r0), // z1 = 3 * t1 + 2 * z1 c.call(f2mPrefix + "_add", t1, x1, r1), c.call(f2mPrefix + "_add", r1, r1, r1), c.call(f2mPrefix + "_add", t1, r1, r1), // For B // z2 = 3 * (xi * t5) + 2 * z2 c.call(f2mPrefix + "_mul", t5, c.i32_const(pBls12381Twist), AUX), c.call(f2mPrefix + "_add", AUX, x2, r2), c.call(f2mPrefix + "_add", r2, r2, r2), c.call(f2mPrefix + "_add", AUX, r2, r2), // z3 = 3 * t4 - 2 * z3 c.call(f2mPrefix + "_sub", t4, x3, r3), c.call(f2mPrefix + "_add", r3, r3, r3), c.call(f2mPrefix + "_add", t4, r3, r3), // For C // z4 = 3 * t2 - 2 * z4 c.call(f2mPrefix + "_sub", t2, x4, r4), c.call(f2mPrefix + "_add", r4, r4, r4), c.call(f2mPrefix + "_add", t2, r4, r4), // z5 = 3 * t3 + 2 * z5 c.call(f2mPrefix + "_add", t3, x5, r5), c.call(f2mPrefix + "_add", r5, r5, r5), c.call(f2mPrefix + "_add", t3, r5, r5), ); } function buildCyclotomicExp(exponent, isExpNegative, fnName) { const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) ); const pExponentNafBytes = module.alloc(exponentNafBytes); // const pExponent = module.alloc(utils.bigInt2BytesLE(exponent, n8)); const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName); f.addParam("x", "i32"); f.addParam("r", "i32"); f.addLocal("bit", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const x = c.getLocal("x"); const res = c.getLocal("r"); const inverse = c.i32_const(module.alloc(ftsize)); f.addCode( c.call(ftmPrefix + "_conjugate", x, inverse), c.call(ftmPrefix + "_one", res), c.if( c.teeLocal("bit", c.i32_load8_s(c.i32_const(exponentNafBytes.length-1), pExponentNafBytes)), c.if( c.i32_eq( c.getLocal("bit"), c.i32_const(1) ), c.call(ftmPrefix + "_mul", res, x, res), c.call(ftmPrefix + "_mul", res, inverse, res), ) ), c.setLocal("i", c.i32_const(exponentNafBytes.length-2)), c.block(c.loop( c.call(prefix + "__cyclotomicSquare", res, res), c.if( c.teeLocal("bit", c.i32_load8_s(c.getLocal("i"), pExponentNafBytes)), c.if( c.i32_eq( c.getLocal("bit"), c.i32_const(1) ), c.call(ftmPrefix + "_mul", res, x, res), c.call(ftmPrefix + "_mul", res, inverse, res), ) ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); if (isExpNegative) { f.addCode( c.call(ftmPrefix + "_conjugate", res, res), ); } } function buildFinalExponentiation() { buildCyclotomicSquare(); buildCyclotomicExp(finalExpZ, finalExpIsNegative, "w0"); const f = module.addFunction(prefix+ "_finalExponentiation"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const elt = c.getLocal("x"); const res = c.getLocal("r"); const t0 = c.i32_const(module.alloc(ftsize)); const t1 = c.i32_const(module.alloc(ftsize)); const t2 = c.i32_const(module.alloc(ftsize)); const t3 = c.i32_const(module.alloc(ftsize)); const t4 = c.i32_const(module.alloc(ftsize)); const t5 = c.i32_const(module.alloc(ftsize)); const t6 = c.i32_const(module.alloc(ftsize)); f.addCode( // let mut t0 = f.frobenius_map(6) c.call(ftmPrefix + "_frobeniusMap6", elt, t0), // let t1 = f.invert() c.call(ftmPrefix + "_inverse", elt, t1), // let mut t2 = t0 * t1; c.call(ftmPrefix + "_mul", t0, t1, t2), // t1 = t2.clone(); c.call(ftmPrefix + "_copy", t2, t1), // t2 = t2.frobenius_map().frobenius_map(); c.call(ftmPrefix + "_frobeniusMap2", t2, t2), // t2 *= t1; c.call(ftmPrefix + "_mul", t2, t1, t2), // t1 = cyclotomic_square(t2).conjugate(); c.call(prefix + "__cyclotomicSquare", t2, t1), c.call(ftmPrefix + "_conjugate", t1, t1), // let mut t3 = cycolotomic_exp(t2); c.call(prefix + "__cyclotomicExp_w0", t2, t3), // let mut t4 = cyclotomic_square(t3); c.call(prefix + "__cyclotomicSquare", t3, t4), // let mut t5 = t1 * t3; c.call(ftmPrefix + "_mul", t1, t3, t5), // t1 = cycolotomic_exp(t5); c.call(prefix + "__cyclotomicExp_w0", t5, t1), // t0 = cycolotomic_exp(t1); c.call(prefix + "__cyclotomicExp_w0", t1, t0), // let mut t6 = cycolotomic_exp(t0); c.call(prefix + "__cyclotomicExp_w0", t0, t6), // t6 *= t4; c.call(ftmPrefix + "_mul", t6, t4, t6), // t4 = cycolotomic_exp(t6); c.call(prefix + "__cyclotomicExp_w0", t6, t4), // t5 = t5.conjugate(); c.call(ftmPrefix + "_conjugate", t5, t5), // t4 *= t5 * t2; c.call(ftmPrefix + "_mul", t4, t5, t4), c.call(ftmPrefix + "_mul", t4, t2, t4), // t5 = t2.conjugate(); c.call(ftmPrefix + "_conjugate", t2, t5), // t1 *= t2; c.call(ftmPrefix + "_mul", t1, t2, t1), // t1 = t1.frobenius_map().frobenius_map().frobenius_map(); c.call(ftmPrefix + "_frobeniusMap3", t1, t1), // t6 *= t5; c.call(ftmPrefix + "_mul", t6, t5, t6), // t6 = t6.frobenius_map(); c.call(ftmPrefix + "_frobeniusMap1", t6, t6), // t3 *= t0; c.call(ftmPrefix + "_mul", t3, t0, t3), // t3 = t3.frobenius_map().frobenius_map(); c.call(ftmPrefix + "_frobeniusMap2", t3, t3), // t3 *= t1; c.call(ftmPrefix + "_mul", t3, t1, t3), // t3 *= t6; c.call(ftmPrefix + "_mul", t3, t6, t3), // f = t3 * t4; c.call(ftmPrefix + "_mul", t3, t4, res), ); } function buildFinalExponentiationOld() { const f = module.addFunction(prefix+ "_finalExponentiationOld"); f.addParam("x", "i32"); f.addParam("r", "i32"); const exponent = 322277361516934140462891564586510139908379969514828494218366688025288661041104682794998680497580008899973249814104447692778988208376779573819485263026159588510513834876303014016798809919343532899164848730280942609956670917565618115867287399623286813270357901731510188149934363360381614501334086825442271920079363289954510565375378443704372994881406797882676971082200626541916413184642520269678897559532260949334760604962086348898118982248842634379637598665468817769075878555493752214492790122785850202957575200176084204422751485957336465472324810982833638490904279282696134323072515220044451592646885410572234451732790590013479358343841220074174848221722017083597872017638514103174122784843925578370430843522959600095676285723737049438346544753168912974976791528535276317256904336520179281145394686565050419250614107803233314658825463117900250701199181529205942363159325765991819433914303908860460720581408201373164047773794825411011922305820065611121544561808414055302212057471395719432072209245600258134364584636810093520285711072578721435517884103526483832733289802426157301542744476740008494780363354305116978805620671467071400711358839553375340724899735460480144599782014906586543813292157922220645089192130209334926661588737007768565838519456601560804957985667880395221049249803753582637708560n; const pExponent = module.alloc(utils.bigInt2BytesLE( exponent, 544 )); const c = f.getCodeBuilder(); f.addCode( c.call(ftmPrefix + "_exp", c.getLocal("x"), c.i32_const(pExponent), c.i32_const(544), c.getLocal("r")), ); } const pPreP = module.alloc(prePSize); const pPreQ = module.alloc(preQSize); function buildPairingEquation(nPairings) { const f = module.addFunction(prefix+ "_pairingEq"+nPairings); for (let i=0; i<nPairings; i++) { f.addParam("p_"+i, "i32"); f.addParam("q_"+i, "i32"); } f.addParam("c", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const resT = c.i32_const(module.alloc(ftsize)); const auxT = c.i32_const(module.alloc(ftsize)); f.addCode(c.call(ftmPrefix + "_one", resT )); for (let i=0; i<nPairings; i++) { f.addCode(c.call(prefix + "_prepareG1", c.getLocal("p_"+i), c.i32_const(pPreP) )); f.addCode(c.call(prefix + "_prepareG2", c.getLocal("q_"+i), c.i32_const(pPreQ) )); // Checks f.addCode( c.if( c.i32_eqz(c.call(g1mPrefix + "_inGroupAffine", c.i32_const(pPreP))), c.ret(c.i32_const(0)) ), c.if( c.i32_eqz(c.call(g2mPrefix + "_inGroupAffine", c.i32_const(pPreQ))), c.ret(c.i32_const(0)) ) ); f.addCode(c.call(prefix + "_millerLoop", c.i32_const(pPreP), c.i32_const(pPreQ), auxT )); f.addCode(c.call(ftmPrefix + "_mul", resT, auxT, resT )); } f.addCode(c.call(prefix + "_finalExponentiation", resT, resT )); f.addCode(c.call(ftmPrefix + "_eq", resT, c.getLocal("c"))); } function buildPairing() { const f = module.addFunction(prefix+ "_pairing"); f.addParam("p", "i32"); f.addParam("q", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const resT = c.i32_const(module.alloc(ftsize)); f.addCode(c.call(prefix +