modular: Tonneli-Shanks refactoring

This commit is contained in:
Paul Miller 2023-01-12 19:38:42 +00:00
parent 069452dbe7
commit bfe929aac3
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B

@ -69,7 +69,8 @@ export function invert(number: bigint, modulo: bigint): bigint {
} }
// Tonelli-Shanks algorithm // Tonelli-Shanks algorithm
// https://eprint.iacr.org/2012/685.pdf (page 12) // Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)
// Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks
export function tonelliShanks(P: bigint) { export function tonelliShanks(P: bigint) {
// Legendre constant: used to calculate Legendre symbol (a | p), // Legendre constant: used to calculate Legendre symbol (a | p),
// which denotes the value of a^((p-1)/2) (mod p). // which denotes the value of a^((p-1)/2) (mod p).
@ -101,29 +102,26 @@ export function tonelliShanks(P: bigint) {
return function tonelliSlow<T>(Fp: Field<T>, n: T): T { return function tonelliSlow<T>(Fp: Field<T>, n: T): T {
// Step 0: Check that n is indeed a square: (n | p) must be ≡ 1 // Step 0: Check that n is indeed a square: (n | p) must be ≡ 1
if (Fp.pow(n, legendreC) !== Fp.ONE) throw new Error('Cannot find square root'); if (Fp.pow(n, legendreC) !== Fp.ONE) throw new Error('Cannot find square root');
let s = S; let r = S;
let g = Fp.pow(Fp.create(Z as any as T), Q); // will update both x and b
let x = Fp.pow(n, Q1div2); // first guess at the square root
let b = Fp.pow(n, Q); // first guess at the fudge factor
let c = pow(Z, Q, P); let t2: typeof Fp.ZERO;
let r = Fp.pow(n, Q1div2); while (!Fp.equals(Fp.sub(b, Fp.ONE), Fp.ZERO)) {
let t = Fp.pow(n, Q); t2 = Fp.square(b);
let m;
let t2 = Fp.ZERO; for (m = 1; m < r; m++) {
while (!Fp.equals(Fp.sub(t, Fp.ONE), Fp.ZERO)) { if (Fp.equals(t2, Fp.ONE)) break;
t2 = Fp.square(t); t2 = Fp.square(t2); // t2 *= t2
let i;
for (i = 1; i < s; i++) {
// stop if t2-1 == 0
if (Fp.equals(Fp.sub(t2, Fp.ONE), Fp.ZERO)) break;
// t2 *= t2
t2 = Fp.square(t2);
} }
let b = pow(c, BigInt(1 << (s - i - 1)), P); let ge = Fp.pow(g, BigInt(1 << (r - m - 1))); // ge = 2^(r-m-1)
r = Fp.mul(r, b); g = Fp.square(ge); // g = ge * ge
c = mod(b * b, P); x = Fp.mul(x, ge); // x *= ge
t = Fp.mul(t, c); b = Fp.mul(b, g); // b *= g
s = i; r = m;
} }
return r; return x;
}; };
} }