public List <long> FindRoots(Polynomial polynomial, long mod) { if (mod < 100) { var bruteForceMethod = new BruteforceRootFinder(); return(bruteForceMethod.FindRoots(polynomial, mod)); } var result = new List <long>(); var gcd = new PolynomialGcd(); var polyMath = new PolynomialMath(mod); var x = new Polynomial(new BigInteger[] { 0, 1 }); var powX = polyMath.ModPow(x, mod, polynomial); var h = polyMath.Sub(powX, x); var g = gcd.Calculate(polynomial, h, mod); if (g.Value(0) % mod == 0) { result.Add(0); g = polyMath.Div(g, new Polynomial(new BigInteger[] { 0, 1 })); } Roots(g, mod, result); return(result); }
public bool IsIrreducible(Polynomial poly, BigInteger mod) { var factors = new List <int>(); var deg = poly.Deg; if (deg % 2 == 0) { factors.Add(2); } for (int i = 3; i <= deg; i += 2) { if (deg % i == 0) { factors.Add(i); } } var polyMath = new PolynomialMath(mod); var x = new Polynomial(new BigInteger[] { 0, 1 }); var xPow = polyMath.ModPow(x, BigInteger.Pow(mod, deg), poly); var bigPoly = polyMath.Sub(xPow, x); if (bigPoly.Deg != -1) { return(false); } var polynomialGcd = new PolynomialGcd(); foreach (var factor in factors) { xPow = polyMath.ModPow(x, BigInteger.Pow(mod, deg / factor), poly); bigPoly = polyMath.Sub(xPow, x); var gcd = polynomialGcd.Calculate(bigPoly, poly, mod); if (gcd.Deg != 0 || (gcd[0] + mod) % mod != 1) { return(false); } } return(true); }
void Roots(Polynomial polynomial, long mod, List <long> roots) { if (polynomial.Deg < 1) { return; } if (polynomial.Deg == 2) { if (mod % 2 == 0) { for (long i = 0; i < mod; i++) { if (polynomial.Value(i) % mod == 0) { roots.Add(i); } } } else { var a = polynomial[2]; var b = polynomial[1]; var c = polynomial[0]; var sqrt = new ModularSqrt(); var inverse = new ModularInverse(); var inv2A = inverse.Inverse(2 * a, mod); var tmp = inv2A * b; var root = sqrt.Sqrt(tmp * tmp - inverse.Inverse(a, mod) * c, mod); roots.Add((long)((-tmp + root) % mod)); roots.Add((long)((-tmp - root) % mod)); } return; } if (polynomial.Deg == 1) { var lc = (polynomial[1] + mod) % mod; if (lc == 1) { roots.Add((long)(-polynomial[0])); } else if (lc == mod - 1) { roots.Add((long)(polynomial[0])); } else { var inverse = new ModularInverse(); roots.Add((long)(-polynomial[0] * inverse.Inverse(polynomial[1], mod))); } return; } var polyMath = new PolynomialMath(mod); var arr = new BigInteger[2]; arr[0] = _random.Next() % mod; arr[1] = 1; var h = new Polynomial(arr); h = polyMath.ModPow(h, (mod - 1) / 2, polynomial); h[0] = h[0] - 1; var gcd = new PolynomialGcd(); var g = gcd.Calculate(polynomial, h, mod); while (g.Deg == 0 || g == h) { arr[0] = _random.Next() % mod; h = new Polynomial(arr); h = polyMath.ModPow(h, (mod - 1) / 2, polynomial); h[0] -= 1; g = gcd.Calculate(polynomial, h, mod); } Roots(g, mod, roots); Roots(polyMath.Div(polynomial, g), mod, roots); }