number-theory
Version:
Number theory functions for javascript.
65 lines (52 loc) • 1.71 kB
JavaScript
;
var _ = require('underscore');
var factor = require('./factor');
var squareRootModPrime = require('./square_root_mod_prime');
var jacobiSymbol = require('./jacobi_symbol');
var inverseMod = require('./inverse_mod');
var multiplyMod = require('./multiply_mod');
/**
* Find all square roots of a given number n modulo m.
* @param {Number} n A quadratic residue
* @param {Number} modulus A modulus
* @return {Array} Representatives of all square roots of n modulo m.
* @module number-theory
* @author Jim Fowler
*/
module.exports = function squareRootMod(n, modulus) {
var m = 1;
var results = [0];
factor(modulus).forEach(function (f) {
var p = f.prime;
var exponent = f.power;
var s = squareRootModPrime( n, p );
// Chinese remainder theorem
var combined = [];
if (jacobiSymbol(n, p) != 1) { return []; }
results.forEach(function (r) {
// find a lift of r mod m and s mod p
combined.unshift( r * p * inverseMod(p, m) + s * m * inverseMod(m, p) );
combined.unshift( r * p * inverseMod(p, m) - s * m * inverseMod(m, p) );
});
combined.sort();
results = _.unique(combined);
m = m * p;
var soFar = 1;
exponent--;
while (exponent > 0) {
var q = Math.pow( p, Math.min( soFar, exponent ) );
exponent -= Math.min( soFar, exponent );
// Hensel's lemma
// see: http://en.wikipedia.org/wiki/Hensel%27s_lemma
results = results.map(function (r) {
var A = -((r*r - n) / m);
var B = inverseMod(2 * r, q);
return r + m * multiplyMod(A, B, q);
});
m = m * q;
}
});
return results.map(function (r) {
return ((r % modulus) + modulus) % modulus;
});
};