UNPKG

wasmcurves

Version:

elliptic curves implementations in wasm

574 lines (466 loc) 19.7 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 buildExp = require("./build_timesscalar"); const buildBatchInverse = require("./build_batchinverse"); module.exports = function buildF3m(module, mulNonResidueFn, prefix, f1mPrefix) { if (module.modules[prefix]) return prefix; // already builded const f1n8 = module.modules[f1mPrefix].n64*8; module.modules[prefix] = { n64: module.modules[f1mPrefix].n64*3 }; function buildAdd() { const f = module.addFunction(prefix+"_add"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_add", x0, y0, r0), c.call(f1mPrefix+"_add", x1, y1, r1), c.call(f1mPrefix+"_add", x2, y2, r2), ); } 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 x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_timesScalar", x0, c.getLocal("scalar"), c.getLocal("scalarLen"), r0), c.call(f1mPrefix+"_timesScalar", x1, c.getLocal("scalar"), c.getLocal("scalarLen"), r1), c.call(f1mPrefix+"_timesScalar", x2, c.getLocal("scalar"), c.getLocal("scalarLen"), r2), ); } function buildSub() { const f = module.addFunction(prefix+"_sub"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_sub", x0, y0, r0), c.call(f1mPrefix+"_sub", x1, y1, r1), c.call(f1mPrefix+"_sub", x2, y2, r2), ); } function buildNeg() { const f = module.addFunction(prefix+"_neg"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_neg", x0, r0), c.call(f1mPrefix+"_neg", x1, r1), c.call(f1mPrefix+"_neg", x2, r2), ); } function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.if( c.call(f1mPrefix+"_isZero", x2), c.if( c.call(f1mPrefix+"_isZero", x1), c.ret(c.call(f1mPrefix+"_isNegative", x0)), c.ret(c.call(f1mPrefix+"_isNegative", x1)) ) ), c.ret(c.call(f1mPrefix+"_isNegative", x2)) ); } function buildMul() { const f = module.addFunction(prefix+"_mul"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const cd = f.getCodeBuilder(); const a = cd.getLocal("x"); const b = cd.i32_add(cd.getLocal("x"), cd.i32_const(f1n8)); const c = cd.i32_add(cd.getLocal("x"), cd.i32_const(2*f1n8)); const A = cd.getLocal("y"); const B = cd.i32_add(cd.getLocal("y"), cd.i32_const(f1n8)); const C = cd.i32_add(cd.getLocal("y"), cd.i32_const(2*f1n8)); const r0 = cd.getLocal("r"); const r1 = cd.i32_add(cd.getLocal("r"), cd.i32_const(f1n8)); const r2 = cd.i32_add(cd.getLocal("r"), cd.i32_const(2*f1n8)); const aA = cd.i32_const(module.alloc(f1n8)); const bB = cd.i32_const(module.alloc(f1n8)); const cC = cd.i32_const(module.alloc(f1n8)); const a_b = cd.i32_const(module.alloc(f1n8)); const A_B = cd.i32_const(module.alloc(f1n8)); const a_c = cd.i32_const(module.alloc(f1n8)); const A_C = cd.i32_const(module.alloc(f1n8)); const b_c = cd.i32_const(module.alloc(f1n8)); const B_C = cd.i32_const(module.alloc(f1n8)); const aA_bB = cd.i32_const(module.alloc(f1n8)); const aA_cC = cd.i32_const(module.alloc(f1n8)); const bB_cC = cd.i32_const(module.alloc(f1n8)); const AUX = cd.i32_const(module.alloc(f1n8)); f.addCode( cd.call(f1mPrefix + "_mul", a, A, aA), cd.call(f1mPrefix + "_mul", b, B, bB), cd.call(f1mPrefix + "_mul", c, C, cC), cd.call(f1mPrefix + "_add", a, b, a_b), cd.call(f1mPrefix + "_add", A, B, A_B), cd.call(f1mPrefix + "_add", a, c, a_c), cd.call(f1mPrefix + "_add", A, C, A_C), cd.call(f1mPrefix + "_add", b, c, b_c), cd.call(f1mPrefix + "_add", B, C, B_C), cd.call(f1mPrefix + "_add", aA, bB, aA_bB), cd.call(f1mPrefix + "_add", aA, cC, aA_cC), cd.call(f1mPrefix + "_add", bB, cC, bB_cC), cd.call(f1mPrefix + "_mul", b_c, B_C, r0), cd.call(f1mPrefix + "_sub", r0, bB_cC, r0), cd.call(mulNonResidueFn, r0, r0), cd.call(f1mPrefix + "_add", aA, r0, r0), cd.call(f1mPrefix + "_mul", a_b, A_B, r1), cd.call(f1mPrefix + "_sub", r1, aA_bB, r1), cd.call(mulNonResidueFn, cC, AUX), cd.call(f1mPrefix + "_add", r1, AUX, r1), cd.call(f1mPrefix + "_mul", a_c, A_C, r2), cd.call(f1mPrefix + "_sub", r2, aA_cC, r2), cd.call(f1mPrefix + "_add", r2, bB, r2), ); } function buildSquare() { const f = module.addFunction(prefix+"_square"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const A = c.getLocal("x"); const B = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const C = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); const s0 = c.i32_const(module.alloc(f1n8)); const ab = c.i32_const(module.alloc(f1n8)); const s1 = c.i32_const(module.alloc(f1n8)); const s2 = c.i32_const(module.alloc(f1n8)); const bc = c.i32_const(module.alloc(f1n8)); const s3 = c.i32_const(module.alloc(f1n8)); const s4 = c.i32_const(module.alloc(f1n8)); f.addCode( c.call(f1mPrefix + "_square", A, s0), c.call(f1mPrefix + "_mul", A, B, ab), c.call(f1mPrefix + "_add", ab, ab, s1), c.call(f1mPrefix + "_sub", A, B, s2), c.call(f1mPrefix + "_add", s2, C, s2), c.call(f1mPrefix + "_square", s2, s2), c.call(f1mPrefix + "_mul", B, C, bc), c.call(f1mPrefix + "_add", bc, bc, s3), c.call(f1mPrefix + "_square", C, s4), c.call(mulNonResidueFn, s3, r0), c.call(f1mPrefix + "_add", s0, r0, r0), c.call(mulNonResidueFn, s4, r1), c.call(f1mPrefix + "_add", s1, r1, r1), c.call(f1mPrefix + "_add", s0, s4, r2), c.call(f1mPrefix + "_sub", s3, r2, r2), c.call(f1mPrefix + "_add", s2, r2, r2), c.call(f1mPrefix + "_add", s1, r2, r2), ); } function buildToMontgomery() { const f = module.addFunction(prefix+"_toMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_toMontgomery", x0, r0), c.call(f1mPrefix+"_toMontgomery", x1, r1), c.call(f1mPrefix+"_toMontgomery", x2, r2) ); } function buildFromMontgomery() { const f = module.addFunction(prefix+"_fromMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_fromMontgomery", x0, r0), c.call(f1mPrefix+"_fromMontgomery", x1, r1), c.call(f1mPrefix+"_fromMontgomery", x2, r2) ); } function buildCopy() { const f = module.addFunction(prefix+"_copy"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_copy", x0, r0), c.call(f1mPrefix+"_copy", x1, r1), c.call(f1mPrefix+"_copy", x2, r2), ); } function buildZero() { const f = module.addFunction(prefix+"_zero"); f.addParam("x", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_zero", x0), c.call(f1mPrefix+"_zero", x1), c.call(f1mPrefix+"_zero", x2), ); } function buildOne() { const f = module.addFunction(prefix+"_one"); f.addParam("x", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_one", x0), c.call(f1mPrefix+"_zero", x1), c.call(f1mPrefix+"_zero", x2), ); } function buildEq() { const f = module.addFunction(prefix+"_eq"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8)); f.addCode( c.i32_and( c.i32_and( c.call(f1mPrefix+"_eq", x0, y0), c.call(f1mPrefix+"_eq", x1, y1), ), c.call(f1mPrefix+"_eq", x2, y2) ) ); } function buildIsZero() { const f = module.addFunction(prefix+"_isZero"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.i32_and( c.i32_and( c.call(f1mPrefix+"_isZero", x0), c.call(f1mPrefix+"_isZero", x1) ), c.call(f1mPrefix+"_isZero", x2) ) ); } function buildInverse() { const f = module.addFunction(prefix+"_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); const t0 = c.i32_const(module.alloc(f1n8)); const t1 = c.i32_const(module.alloc(f1n8)); const t2 = c.i32_const(module.alloc(f1n8)); const t3 = c.i32_const(module.alloc(f1n8)); const t4 = c.i32_const(module.alloc(f1n8)); const t5 = c.i32_const(module.alloc(f1n8)); const c0 = c.i32_const(module.alloc(f1n8)); const c1 = c.i32_const(module.alloc(f1n8)); const c2 = c.i32_const(module.alloc(f1n8)); const t6 = c.i32_const(module.alloc(f1n8)); const AUX = c.i32_const(module.alloc(f1n8)); f.addCode( c.call(f1mPrefix+"_square", x0, t0), c.call(f1mPrefix+"_square", x1, t1), c.call(f1mPrefix+"_square", x2, t2), c.call(f1mPrefix+"_mul", x0, x1, t3), c.call(f1mPrefix+"_mul", x0, x2, t4), c.call(f1mPrefix+"_mul", x1, x2, t5), c.call(mulNonResidueFn, t5, c0), c.call(f1mPrefix+"_sub", t0, c0, c0), c.call(mulNonResidueFn, t2, c1), c.call(f1mPrefix+"_sub", c1, t3, c1), c.call(f1mPrefix+"_sub", t1, t4, c2), c.call(f1mPrefix+"_mul", x2, c1, t6), c.call(f1mPrefix+"_mul", x1, c2, AUX), c.call(f1mPrefix+"_add", t6, AUX, t6), c.call(mulNonResidueFn, t6, t6), c.call(f1mPrefix+"_mul", x0, c0, AUX), c.call(f1mPrefix+"_add", AUX, t6, t6), c.call(f1mPrefix+"_inverse", t6, t6), c.call(f1mPrefix+"_mul", t6, c0, r0), c.call(f1mPrefix+"_mul", t6, c1, r1), c.call(f1mPrefix+"_mul", t6, c2, r2) ); } function buildSign() { const f = module.addFunction(prefix+"_sign"); f.addParam("x", "i32"); f.addLocal("s", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.setLocal("s" , c.call( f1mPrefix + "_sign", x2)), c.if( c.getLocal("s"), c.ret(c.getLocal("s")) ), c.setLocal("s" , c.call( f1mPrefix + "_sign", x1)), c.if( c.getLocal("s"), c.ret(c.getLocal("s")) ), c.ret(c.call( f1mPrefix + "_sign", x0)) ); } function buildIsOne() { const f = module.addFunction(prefix+"_isOne"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8*2)); f.addCode( c.ret( c.i32_and( c.i32_and( c.call(f1mPrefix + "_isOne", x0), c.call(f1mPrefix + "_isZero", x1) ), c.call(f1mPrefix + "_isZero", x2) ) ) ); } buildIsZero(); buildIsOne(); buildZero(); buildOne(); buildCopy(); buildMul(); buildSquare(); buildAdd(); buildSub(); buildNeg(); buildSign(); buildToMontgomery(); buildFromMontgomery(); buildEq(); buildInverse(); buildTimesScalar(); buildIsNegative(); module.exportFunction(prefix + "_isZero"); module.exportFunction(prefix + "_isOne"); module.exportFunction(prefix + "_zero"); module.exportFunction(prefix + "_one"); module.exportFunction(prefix + "_copy"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_square"); module.exportFunction(prefix + "_add"); module.exportFunction(prefix + "_sub"); module.exportFunction(prefix + "_neg"); module.exportFunction(prefix + "_sign"); module.exportFunction(prefix + "_fromMontgomery"); module.exportFunction(prefix + "_toMontgomery"); module.exportFunction(prefix + "_eq"); module.exportFunction(prefix + "_inverse"); buildBatchInverse(module, prefix); buildExp( module, prefix + "_exp", f1n8*3, prefix + "_mul", prefix + "_square", prefix + "_copy", prefix + "_one" ); module.exportFunction(prefix + "_exp"); module.exportFunction(prefix + "_timesScalar"); module.exportFunction(prefix + "_batchInverse"); module.exportFunction(prefix + "_isNegative"); return prefix; };