UNPKG

@toruslabs/ffjavascript

Version:

Finite Field Library in Javascript

168 lines (140 loc) 3.79 kB
'use strict'; var scalar = require('./scalar.js'); // Check here: https://eprint.iacr.org/2012/685.pdf function buildSqrt(F) { if (F.m % 2 == 1) { if (scalar.eq(scalar.mod(F.p, 4), 1)) { if (scalar.eq(scalar.mod(F.p, 8), 1)) { if (scalar.eq(scalar.mod(F.p, 16), 1)) { // alg7_muller(F); alg5_tonelliShanks(F); } else if (scalar.eq(scalar.mod(F.p, 16), 9)) { alg4_kong(F); } else { throw new Error("Field withot sqrt"); } } else if (scalar.eq(scalar.mod(F.p, 8), 5)) { alg3_atkin(F); } else { throw new Error("Field withot sqrt"); } } else if (scalar.eq(scalar.mod(F.p, 4), 3)) { alg2_shanks(F); } } else { const pm2mod4 = scalar.mod(scalar.pow(F.p, F.m / 2), 4); if (pm2mod4 == 1) { alg10_adj(F); } else if (pm2mod4 == 3) { alg9_adj(F); } else { alg8_complex(F); } } } function alg5_tonelliShanks(F) { F.sqrt_q = scalar.pow(F.p, F.m); F.sqrt_s = 0; F.sqrt_t = scalar.sub(F.sqrt_q, 1); while (!scalar.isOdd(F.sqrt_t)) { F.sqrt_s = F.sqrt_s + 1; F.sqrt_t = scalar.div(F.sqrt_t, 2); } let c0 = F.one; while (F.eq(c0, F.one)) { const c = F.random(); F.sqrt_z = F.pow(c, F.sqrt_t); c0 = F.pow(F.sqrt_z, 2 ** (F.sqrt_s - 1)); } F.sqrt_tm1d2 = scalar.div(scalar.sub(F.sqrt_t, 1), 2); F.sqrt = function (a) { const F = this; if (F.isZero(a)) return F.zero; let w = F.pow(a, F.sqrt_tm1d2); const a0 = F.pow(F.mul(F.square(w), a), 2 ** (F.sqrt_s - 1)); if (F.eq(a0, F.negone)) return null; let v = F.sqrt_s; let x = F.mul(a, w); let b = F.mul(x, w); let z = F.sqrt_z; while (!F.eq(b, F.one)) { let b2k = F.square(b); let k = 1; while (!F.eq(b2k, F.one)) { b2k = F.square(b2k); k++; } w = z; for (let i = 0; i < v - k - 1; i++) { w = F.square(w); } z = F.square(w); b = F.mul(b, z); x = F.mul(x, w); v = k; } return F.geq(x, F.zero) ? x : F.neg(x); }; } function alg4_kong(F) { F.sqrt = function () { throw new Error("Sqrt alg 4 not implemented"); }; } function alg3_atkin(F) { F.sqrt = function () { throw new Error("Sqrt alg 3 not implemented"); }; } function alg2_shanks(F) { F.sqrt_q = scalar.pow(F.p, F.m); F.sqrt_e1 = scalar.div(scalar.sub(F.sqrt_q, 3), 4); F.sqrt = function (a) { if (this.isZero(a)) return this.zero; // Test that have solution const a1 = this.pow(a, this.sqrt_e1); const a0 = this.mul(this.square(a1), a); if (this.eq(a0, this.negone)) return null; const x = this.mul(a1, a); return F.geq(x, F.zero) ? x : F.neg(x); }; } function alg10_adj(F) { F.sqrt = function () { throw new Error("Sqrt alg 10 not implemented"); }; } function alg9_adj(F) { F.sqrt_q = scalar.pow(F.p, F.m / 2); F.sqrt_e34 = scalar.div(scalar.sub(F.sqrt_q, 3), 4); F.sqrt_e12 = scalar.div(scalar.sub(F.sqrt_q, 1), 2); F.frobenius = function (n, x) { if (n % 2 == 1) { return F.conjugate(x); } else { return x; } }; F.sqrt = function (a) { const F = this; const a1 = F.pow(a, F.sqrt_e34); const alfa = F.mul(F.square(a1), a); const a0 = F.mul(F.frobenius(1, alfa), alfa); if (F.eq(a0, F.negone)) return null; const x0 = F.mul(a1, a); let x; if (F.eq(alfa, F.negone)) { x = F.mul(x0, [F.F.zero, F.F.one]); } else { const b = F.pow(F.add(F.one, alfa), F.sqrt_e12); x = F.mul(b, x0); } return F.geq(x, F.zero) ? x : F.neg(x); }; } function alg8_complex(F) { F.sqrt = function () { throw new Error("Sqrt alg 8 not implemented"); }; } module.exports = buildSqrt;