UNPKG

@kotevode/ffjavascript

Version:

Finite Field Library in Javascript

167 lines (138 loc) 4.28 kB
import * as Scalar from "./scalar.js"; // Check here: https://eprint.iacr.org/2012/685.pdf export default 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"); }; }