UNPKG

@toruslabs/ffjavascript

Version:

Finite Field Library in Javascript

144 lines (139 loc) 3.87 kB
import { eq, mod, pow, sub, isOdd, div } from './scalar.js'; // Check here: https://eprint.iacr.org/2012/685.pdf function buildSqrt(F) { if (F.m % 2 == 1) { if (eq(mod(F.p, 4), 1)) { if (eq(mod(F.p, 8), 1)) { if (eq(mod(F.p, 16), 1)) { // alg7_muller(F); alg5_tonelliShanks(F); } else if (eq(mod(F.p, 16), 9)) { alg4_kong(F); } else { throw new Error("Field withot sqrt"); } } else if (eq(mod(F.p, 8), 5)) { alg3_atkin(F); } else { throw new Error("Field withot sqrt"); } } else if (eq(mod(F.p, 4), 3)) { alg2_shanks(F); } } else { const pm2mod4 = mod(pow(F.p, F.m / 2), 4); if (pm2mod4 == 1n) { alg10_adj(F); } else if (pm2mod4 == 3n) { alg9_adj(F); } else { alg8_complex(F); } } } function alg5_tonelliShanks(F) { F.sqrt_q = pow(F.p, F.m); F.sqrt_s = 0; F.sqrt_t = sub(F.sqrt_q, 1); while (!isOdd(F.sqrt_t)) { F.sqrt_s = F.sqrt_s + 1; F.sqrt_t = 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 = div(sub(F.sqrt_t, 1), 2); F.sqrt = function (a) { if (this.isZero(a)) return this.zero; let w = this.pow(a, this.sqrt_tm1d2); const a0 = this.pow(this.mul(this.square(w), a), 2 ** (this.sqrt_s - 1)); if (this.eq(a0, this.negone)) return null; let v = this.sqrt_s; let x = this.mul(a, w); let b = this.mul(x, w); let z = this.sqrt_z; while (!this.eq(b, this.one)) { let b2k = this.square(b); let k = 1; while (!this.eq(b2k, this.one)) { b2k = this.square(b2k); k++; } w = z; for (let i = 0; i < v - k - 1; i++) { w = this.square(w); } z = this.square(w); b = this.mul(b, z); x = this.mul(x, w); v = k; } return this.geq(x, this.zero) ? x : this.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 = pow(F.p, F.m); F.sqrt_e1 = div(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 this.geq(x, this.zero) ? x : this.neg(x); }; } function alg10_adj(F) { F.sqrt = function () { throw new Error("Sqrt alg 10 not implemented"); }; } function alg9_adj(F) { F.sqrt_q = pow(F.p, F.m / 2); F.sqrt_e34 = div(sub(F.sqrt_q, 3), 4); F.sqrt_e12 = div(sub(F.sqrt_q, 1), 2); F.frobenius = function (n, x) { if (n % 2 == 1) { // @ts-expect-error - conjugate exists on extension fields, not F1 return F.conjugate(x); } else { return x; } }; F.sqrt = function (a) { const a1 = this.pow(a, this.sqrt_e34); const alfa = this.mul(this.square(a1), a); const a0 = this.mul(this.frobenius(1, alfa), alfa); if (this.eq(a0, this.negone)) return null; const x0 = this.mul(a1, a); let x; if (this.eq(alfa, this.negone)) { // @ts-expect-error - F sub-field and array mul exist on extension fields, not F1 x = this.mul(x0, [this.F.zero, this.F.one]); } else { const b = this.pow(this.add(this.one, alfa), this.sqrt_e12); x = this.mul(b, x0); } return this.geq(x, this.zero) ? x : this.neg(x); }; } function alg8_complex(F) { F.sqrt = function () { throw new Error("Sqrt alg 8 not implemented"); }; } export { buildSqrt as default };