TelegramPWA/src/lib/gramjs/crypto/Factorizator.js
2022-05-06 17:56:12 +01:00

97 lines
2.5 KiB
JavaScript

const BigInt = require('big-integer');
const { modExp } = require('../Helpers');
class Factorizator {
/**
* Calculates the greatest common divisor
* @param a {BigInteger}
* @param b {BigInteger}
* @returns {BigInteger}
*/
static gcd(a, b) {
while (b.neq(BigInt.zero)) {
const temp = b;
b = a.remainder(b);
a = temp;
}
return a;
}
/**
* Factorizes the given number and returns both the divisor and the number divided by the divisor
* @param pq {BigInteger}
* @returns {{p: *, q: *}}
*/
static factorize(pq) {
if (pq.remainder(2)
.equals(BigInt.zero)) {
return {
p: BigInt(2),
q: pq.divide(BigInt(2)),
};
}
let y = BigInt.randBetween(BigInt(1), pq.minus(1));
const c = BigInt.randBetween(BigInt(1), pq.minus(1));
const m = BigInt.randBetween(BigInt(1), pq.minus(1));
let g = BigInt.one;
let r = BigInt.one;
let q = BigInt.one;
let x = BigInt.zero;
let ys = BigInt.zero;
let k;
while (g.eq(BigInt.one)) {
x = y;
for (let i = 0; BigInt(i)
.lesser(r); i++) {
y = (modExp(y, BigInt(2), pq)).add(c)
.remainder(pq);
}
k = BigInt.zero;
while (k.lesser(r) && g.eq(BigInt.one)) {
ys = y;
const condition = BigInt.min(m, r.minus(k));
for (let i = 0; BigInt(i)
.lesser(condition); i++) {
y = (modExp(y, BigInt(2), pq)).add(c)
.remainder(pq);
q = q.multiply(x.minus(y)
.abs())
.remainder(pq);
}
g = Factorizator.gcd(q, pq);
k = k.add(m);
}
r = r.multiply(2);
}
if (g.eq(pq)) {
// eslint-disable-next-line no-constant-condition
while (true) {
ys = (modExp(ys, BigInt(2), pq)).add(c)
.remainder(pq);
g = Factorizator.gcd(x.minus(ys)
.abs(), pq);
if (g.greater(1)) {
break;
}
}
}
const p = g;
q = pq.divide(g);
return p < q ? {
p,
q,
} : {
p: q,
q: p,
};
}
}
module.exports = Factorizator;