UNPKG

wasmcurves

Version:

elliptic curves implementations in wasm

1,062 lines (896 loc) 33.3 kB
/* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see <https://www.gnu.org/licenses/>. */ const buildInt = require("./build_int.js"); const utils = require("./utils.js"); const buildExp = require("./build_timesscalar"); const buildBatchInverse = require("./build_batchinverse"); const buildBatchConvertion = require("./build_batchconvertion"); const buildBatchOp = require("./build_batchop"); const { bitLength, modInv, modPow, isPrime, isOdd, square } = require("./bigint.js"); module.exports = function buildF1m(module, _q, _prefix, _intPrefix) { const q = BigInt(_q); const n64 = Math.floor((bitLength(q - 1n) - 1)/64) +1; const n32 = n64*2; const n8 = n64*8; const prefix = _prefix || "f1m"; if (module.modules[prefix]) return prefix; // already builded const intPrefix = buildInt(module, n64, _intPrefix); const pq = module.alloc(n8, utils.bigInt2BytesLE(q, n8)); const pR2 = module.alloc(utils.bigInt2BytesLE(square(1n << BigInt(n64*64)) % q, n8)); const pOne = module.alloc(utils.bigInt2BytesLE((1n << BigInt(n64*64)) % q, n8)); const pZero = module.alloc(utils.bigInt2BytesLE(0n, n8)); const _minusOne = q - 1n; const _e = _minusOne >> 1n; // e = (p-1)/2 const pe = module.alloc(n8, utils.bigInt2BytesLE(_e, n8)); const _ePlusOne = _e + 1n; // e = (p-1)/2 const pePlusOne = module.alloc(n8, utils.bigInt2BytesLE(_ePlusOne, n8)); module.modules[prefix] = { pq: pq, pR2: pR2, n64: n64, q: q, pOne: pOne, pZero: pZero, pePlusOne: pePlusOne }; function buildOne() { const f = module.addFunction(prefix+"_one"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_copy", c.i32_const(pOne), c.getLocal("pr"))); } function buildAdd() { const f = module.addFunction(prefix+"_add"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.call(intPrefix+"_add", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSub() { const f = module.addFunction(prefix+"_sub"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.call(intPrefix+"_sub", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")), c.drop(c.call(intPrefix+"_add", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))) ) ); } function buildNeg() { const f = module.addFunction(prefix+"_neg"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call(prefix + "_sub", c.i32_const(pZero), c.getLocal("x"), c.getLocal("r")) ); } function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX), c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne) ) ); } function buildSign() { const f = module.addFunction(prefix+"_sign"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.if ( c.call(intPrefix + "_isZero", c.getLocal("x")), c.ret(c.i32_const(0)) ), c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX), c.if( c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne)), c.ret(c.i32_const(-1)) ), c.ret(c.i32_const(1)) ); } function buildMReduct() { const carries = module.alloc(n32*n32*8); const f = module.addFunction(prefix+"_mReduct"); f.addParam("t", "i32"); f.addParam("r", "i32"); f.addLocal("np32", "i64"); f.addLocal("c", "i64"); f.addLocal("m", "i64"); const c = f.getCodeBuilder(); const np32 = Number(0x100000000n - modInv(q, 0x100000000n)); f.addCode(c.setLocal("np32", c.i64_const(np32))); for (let i=0; i<n32; i++) { f.addCode(c.setLocal("c", c.i64_const(0))); f.addCode( c.setLocal( "m", c.i64_and( c.i64_mul( c.i64_load32_u(c.getLocal("t"), i*4), c.getLocal("np32") ), c.i64_const("0xFFFFFFFF") ) ) ); for (let j=0; j<n32; j++) { f.addCode( c.setLocal("c", c.i64_add( c.i64_add( c.i64_load32_u(c.getLocal("t"), (i+j)*4), c.i64_shr_u(c.getLocal("c"), c.i64_const(32)) ), c.i64_mul( c.i64_load32_u(c.i32_const(pq), j*4), c.getLocal("m") ) ) ) ); f.addCode( c.i64_store32( c.getLocal("t"), (i+j)*4, c.getLocal("c") ) ); } f.addCode( c.i64_store32( c.i32_const(carries), i*4, c.i64_shr_u(c.getLocal("c"), c.i64_const(32)) ) ); } f.addCode( c.call( prefix+"_add", c.i32_const(carries), c.i32_add( c.getLocal("t"), c.i32_const(n32*4) ), c.getLocal("r") ) ); } function buildMul() { const f = module.addFunction(prefix+"_mul"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); f.addLocal("c0", "i64"); f.addLocal("c1", "i64"); f.addLocal("np32", "i64"); for (let i=0;i<n32; i++) { f.addLocal("x"+i, "i64"); f.addLocal("y"+i, "i64"); f.addLocal("m"+i, "i64"); f.addLocal("q"+i, "i64"); } const c = f.getCodeBuilder(); const np32 = Number(0x100000000n - modInv(q, 0x100000000n)); f.addCode(c.setLocal("np32", c.i64_const(np32))); const loadX = []; const loadY = []; const loadQ = []; function mulij(i, j) { let X,Y; if (!loadX[i]) { X = c.teeLocal("x"+i, c.i64_load32_u( c.getLocal("x"), i*4)); loadX[i] = true; } else { X = c.getLocal("x"+i); } if (!loadY[j]) { Y = c.teeLocal("y"+j, c.i64_load32_u( c.getLocal("y"), j*4)); loadY[j] = true; } else { Y = c.getLocal("y"+j); } return c.i64_mul( X, Y ); } function mulqm(i, j) { let Q,M; if (!loadQ[i]) { Q = c.teeLocal("q"+i, c.i64_load32_u(c.i32_const(0), pq+i*4 )); loadQ[i] = true; } else { Q = c.getLocal("q"+i); } M = c.getLocal("m"+j); return c.i64_mul( Q, M ); } let c0 = "c0"; let c1 = "c1"; for (let k=0; k<n32*2-1; k++) { for (let i=Math.max(0, k-n32+1); (i<=k)&&(i<n32); i++) { const j= k-i; f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulij(i,j) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } for (let i=Math.max(1, k-n32+1); (i<=k)&&(i<n32); i++) { const j= k-i; f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulqm(i,j) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } if (k<n32) { f.addCode( c.setLocal( "m"+k, c.i64_and( c.i64_mul( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), c.getLocal("np32") ), c.i64_const("0xFFFFFFFF") ) ) ); f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulqm(0,k) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } if (k>=n32) { f.addCode( c.i64_store32( c.getLocal("r"), (k-n32)*4, c.getLocal(c0) ) ); } [c0, c1] = [c1, c0]; f.addCode( c.setLocal(c1, c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), n32*4-4, c.getLocal(c0) ) ); f.addCode( c.if( c.i32_wrap_i64(c.getLocal(c1)), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSquare() { const f = module.addFunction(prefix+"_square"); f.addParam("x", "i32"); f.addParam("r", "i32"); f.addLocal("c0", "i64"); f.addLocal("c1", "i64"); f.addLocal("c0_old", "i64"); f.addLocal("c1_old", "i64"); f.addLocal("np32", "i64"); for (let i=0;i<n32; i++) { f.addLocal("x"+i, "i64"); f.addLocal("m"+i, "i64"); f.addLocal("q"+i, "i64"); } const c = f.getCodeBuilder(); const np32 = Number(0x100000000n - modInv(q, 0x100000000n)); f.addCode(c.setLocal("np32", c.i64_const(np32))); const loadX = []; const loadQ = []; function mulij(i, j) { let X,Y; if (!loadX[i]) { X = c.teeLocal("x"+i, c.i64_load32_u( c.getLocal("x"), i*4)); loadX[i] = true; } else { X = c.getLocal("x"+i); } if (!loadX[j]) { Y = c.teeLocal("x"+j, c.i64_load32_u( c.getLocal("x"), j*4)); loadX[j] = true; } else { Y = c.getLocal("x"+j); } return c.i64_mul( X, Y ); } function mulqm(i, j) { let Q,M; if (!loadQ[i]) { Q = c.teeLocal("q"+i, c.i64_load32_u(c.i32_const(0), pq+i*4 )); loadQ[i] = true; } else { Q = c.getLocal("q"+i); } M = c.getLocal("m"+j); return c.i64_mul( Q, M ); } let c0 = "c0"; let c1 = "c1"; let c0_old = "c0_old"; let c1_old = "c1_old"; for (let k=0; k<n32*2-1; k++) { f.addCode( c.setLocal(c0, c.i64_const(0)), c.setLocal(c1, c.i64_const(0)), ); for (let i=Math.max(0, k-n32+1); (i<((k+1)>>1) )&&(i<n32); i++) { const j= k-i; f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulij(i,j) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } // Multiply by 2 f.addCode( c.setLocal(c0, c.i64_shl( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), c.i64_const(1) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.i64_shl( c.getLocal(c1), c.i64_const(1) ), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); if (k%2 == 0) { f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulij(k>>1, k>>1) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } // Add the old carry if (k>0) { f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), c.i64_and( c.getLocal(c0_old), c.i64_const(0xFFFFFFFF) ), ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ), c.getLocal(c1_old) ) ) ); } for (let i=Math.max(1, k-n32+1); (i<=k)&&(i<n32); i++) { const j= k-i; f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulqm(i,j) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } if (k<n32) { f.addCode( c.setLocal( "m"+k, c.i64_and( c.i64_mul( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), c.getLocal("np32") ), c.i64_const("0xFFFFFFFF") ) ) ); f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), mulqm(0,k) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } if (k>=n32) { f.addCode( c.i64_store32( c.getLocal("r"), (k-n32)*4, c.getLocal(c0) ) ); } f.addCode( c.setLocal( c0_old, c.getLocal(c1) ), c.setLocal( c1_old, c.i64_shr_u( c.getLocal(c0_old), c.i64_const(32) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), n32*4-4, c.getLocal(c0_old) ) ); f.addCode( c.if( c.i32_wrap_i64(c.getLocal(c1_old)), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSquareOld() { const f = module.addFunction(prefix+"_squareOld"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r"))); } function buildToMontgomery() { const f = module.addFunction(prefix+"_toMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix+"_mul", c.getLocal("x"), c.i32_const(pR2), c.getLocal("r"))); } function buildFromMontgomery() { const pAux2 = module.alloc(n8*2); const f = module.addFunction(prefix+"_fromMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_copy", c.getLocal("x"), c.i32_const(pAux2) )); f.addCode(c.call(intPrefix + "_zero", c.i32_const(pAux2 + n8) )); f.addCode(c.call(prefix+"_mReduct", c.i32_const(pAux2), c.getLocal("r"))); } function buildInverse() { const f = module.addFunction(prefix+ "_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_fromMontgomery", c.getLocal("x"), c.getLocal("r"))); f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))); f.addCode(c.call(prefix + "_toMontgomery", c.getLocal("r"), c.getLocal("r"))); } // Calculate various valuse needed for sqrt let _nqr = 2n; if (isPrime(q)) { while (modPow(_nqr, _e, q) !== _minusOne) _nqr = _nqr + 1n; } let s2 = 0; let _t = _minusOne; while ((!isOdd(_t))&&(_t !== 0n)) { s2++; _t = _t >> 1n; } const pt = module.alloc(n8, utils.bigInt2BytesLE(_t, n8)); const _nqrToT = modPow(_nqr, _t, q); const pNqrToT = module.alloc(utils.bigInt2BytesLE((_nqrToT << BigInt(n64*64)) % q, n8)); const _tPlusOneOver2 = (_t + 1n) >> 1n; const ptPlusOneOver2 = module.alloc(n8, utils.bigInt2BytesLE(_tPlusOneOver2, n8)); function buildSqrt() { const f = module.addFunction(prefix+ "_sqrt"); f.addParam("n", "i32"); f.addParam("r", "i32"); f.addLocal("m", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); const c = f.getCodeBuilder(); const ONE = c.i32_const(pOne); const C = c.i32_const(module.alloc(n8)); const T = c.i32_const(module.alloc(n8)); const R = c.i32_const(module.alloc(n8)); const SQ = c.i32_const(module.alloc(n8)); const B = c.i32_const(module.alloc(n8)); f.addCode( // If (n==0) return 0 c.if( c.call(prefix + "_isZero", c.getLocal("n")), c.ret( c.call(prefix + "_zero", c.getLocal("r")) ) ), c.setLocal("m", c.i32_const(s2)), c.call(prefix + "_copy", c.i32_const(pNqrToT), C), c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(pt), c.i32_const(n8), T), c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(ptPlusOneOver2), c.i32_const(n8), R), c.block(c.loop( c.br_if(1, c.call(prefix + "_eq", T, ONE)), c.call(prefix + "_square", T, SQ), c.setLocal("i", c.i32_const(1)), c.block(c.loop( c.br_if(1, c.call(prefix + "_eq", SQ, ONE)), c.call(prefix + "_square", SQ, SQ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )), c.call(prefix + "_copy", C, B), c.setLocal("j", c.i32_sub(c.i32_sub( c.getLocal("m"), c.getLocal("i")), c.i32_const(1)) ), c.block(c.loop( c.br_if(1, c.i32_eqz(c.getLocal("j"))), c.call(prefix + "_square", B, B), c.setLocal("j", c.i32_sub(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.setLocal("m", c.getLocal("i")), c.call(prefix + "_square", B, C), c.call(prefix + "_mul", T, C, T), c.call(prefix + "_mul", R, B, R), c.br(0) )), c.if( c.call(prefix + "_isNegative", R), c.call(prefix + "_neg", R, c.getLocal("r")), c.call(prefix + "_copy", R, c.getLocal("r")), ) ); } function buildIsSquare() { const f = module.addFunction(prefix+"_isSquare"); f.addParam("n", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const ONE = c.i32_const(pOne); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.if( c.call(prefix + "_isZero", c.getLocal("n")), c.ret(c.i32_const(1)) ), c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(pe), c.i32_const(n8), AUX), c.call(prefix + "_eq", AUX, ONE) ); } function buildLoad() { const f = module.addFunction(prefix+"_load"); f.addParam("scalar", "i32"); f.addParam("scalarLen", "i32"); f.addParam("r", "i32"); f.addLocal("p", "i32"); f.addLocal("l", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); const c = f.getCodeBuilder(); const R = c.i32_const(module.alloc(n8)); const pAux = module.alloc(n8); const AUX = c.i32_const(pAux); f.addCode( c.call(intPrefix + "_zero", c.getLocal("r")), c.setLocal("i", c.i32_const(n8)), c.setLocal("p", c.getLocal("scalar")), c.block(c.loop( c.br_if(1, c.i32_gt_u(c.getLocal("i"), c.getLocal("scalarLen"))), c.if( c.i32_eq(c.getLocal("i"), c.i32_const(n8)), c.call(prefix + "_one", R), c.call(prefix + "_mul", R, c.i32_const(pR2), R) ), c.call(prefix + "_mul", c.getLocal("p"), R, AUX), c.call(prefix + "_add", c.getLocal("r"), AUX, c.getLocal("r")), c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(n8))), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(n8))), c.br(0) )), c.setLocal("l", c.i32_rem_u( c.getLocal("scalarLen"), c.i32_const(n8))), c.if(c.i32_eqz(c.getLocal("l")), c.ret([])), c.call(intPrefix + "_zero", AUX), c.setLocal("j", c.i32_const(0)), c.block(c.loop( c.br_if(1, c.i32_eq(c.getLocal("j"), c.getLocal("l"))), c.i32_store8( c.getLocal("j"), pAux, c.i32_load8_u(c.getLocal("p")), ), c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(1))), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.if( c.i32_eq(c.getLocal("i"), c.i32_const(n8)), c.call(prefix + "_one", R), c.call(prefix + "_mul", R, c.i32_const(pR2), R) ), c.call(prefix + "_mul", AUX, R, AUX), c.call(prefix + "_add", c.getLocal("r"), AUX, c.getLocal("r")), ); } function buildTimesScalar() { const f = module.addFunction(prefix+"_timesScalar"); f.addParam("x", "i32"); f.addParam("scalar", "i32"); f.addParam("scalarLen", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.call(prefix + "_load", c.getLocal("scalar"), c.getLocal("scalarLen"), AUX), c.call(prefix + "_toMontgomery", AUX, AUX), c.call(prefix + "_mul", c.getLocal("x"), AUX, c.getLocal("r")), ); } function buildIsOne() { const f = module.addFunction(prefix+"_isOne"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode( c.ret(c.call(intPrefix + "_eq", c.getLocal("x"), c.i32_const(pOne))) ); } module.exportFunction(intPrefix + "_copy", prefix+"_copy"); module.exportFunction(intPrefix + "_zero", prefix+"_zero"); module.exportFunction(intPrefix + "_isZero", prefix+"_isZero"); module.exportFunction(intPrefix + "_eq", prefix+"_eq"); buildIsOne(); buildAdd(); buildSub(); buildNeg(); buildMReduct(); buildMul(); buildSquare(); buildSquareOld(); buildToMontgomery(); buildFromMontgomery(); buildIsNegative(); buildSign(); buildInverse(); buildOne(); buildLoad(); buildTimesScalar(); buildBatchInverse(module, prefix); buildBatchConvertion(module, prefix + "_batchToMontgomery", prefix + "_toMontgomery", n8, n8); buildBatchConvertion(module, prefix + "_batchFromMontgomery", prefix + "_fromMontgomery", n8, n8); buildBatchConvertion(module, prefix + "_batchNeg", prefix + "_neg", n8, n8); buildBatchOp(module, prefix + "_batchAdd", prefix + "_add", n8, n8); buildBatchOp(module, prefix + "_batchSub", prefix + "_sub", n8, n8); buildBatchOp(module, prefix + "_batchMul", prefix + "_mul", n8, n8); module.exportFunction(prefix + "_add"); module.exportFunction(prefix + "_sub"); module.exportFunction(prefix + "_neg"); module.exportFunction(prefix + "_isNegative"); module.exportFunction(prefix + "_isOne"); module.exportFunction(prefix + "_sign"); module.exportFunction(prefix + "_mReduct"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_square"); module.exportFunction(prefix + "_squareOld"); module.exportFunction(prefix + "_fromMontgomery"); module.exportFunction(prefix + "_toMontgomery"); module.exportFunction(prefix + "_inverse"); module.exportFunction(prefix + "_one"); module.exportFunction(prefix + "_load"); module.exportFunction(prefix + "_timesScalar"); buildExp( module, prefix + "_exp", n8, prefix + "_mul", prefix + "_square", intPrefix + "_copy", prefix + "_one", ); module.exportFunction(prefix + "_exp"); module.exportFunction(prefix + "_batchInverse"); if (isPrime(q)) { buildSqrt(); buildIsSquare(); module.exportFunction(prefix + "_sqrt"); module.exportFunction(prefix + "_isSquare"); } module.exportFunction(prefix + "_batchToMontgomery"); module.exportFunction(prefix + "_batchFromMontgomery"); // console.log(module.functionIdxByName); return prefix; };