public void Test04_SquareRoot() { TestContext.WriteLine($"ENTER: {nameof(Test04_SquareRoot)}"); Assert.IsTrue(step03_passed, "IsTrue(step03_passed)"); Assert.IsNotNull(gnfs, "IsNotNull(gnfs)"); int maxSetSize = gnfs.CurrentRelationsProgress.FreeRelations.Max(lst => lst.Count); List <Relation> choosenRelationSet = gnfs.CurrentRelationsProgress.FreeRelations.Where(lst => lst.Count == maxSetSize).First(); SquareFinder squareRootFinder = new SquareFinder(gnfs, choosenRelationSet); squareRootFinder.CalculateRationalSide(); Tuple <BigInteger, BigInteger> foundFactors = squareRootFinder.CalculateAlgebraicSide(cancelToken); /* Non-trivial factors also recoverable by doing the following: * * BigInteger min = BigInteger.Min(squareRootFinder.RationalSquareRootResidue, squareRootFinder.AlgebraicSquareRootResidue); * BigInteger max = BigInteger.Max(squareRootFinder.RationalSquareRootResidue, squareRootFinder.AlgebraicSquareRootResidue); * BigInteger R = max - min; * BigInteger S = max + min; * BigInteger P = GCD.FindGCD(gnfs.N, S); * BigInteger Q = GCD.FindGCD(gnfs.N, R); * */ BigInteger P = foundFactors.Item1; BigInteger Q = foundFactors.Item2; Assert.AreNotEqual(1, P, "AreNotEqual(1, P)"); Assert.AreNotEqual(1, Q, "AreNotEqual(1, Q)"); Assert.AreEqual(new BigInteger(1811), P, "AreEqual(1811, P)"); Assert.AreEqual(new BigInteger(1777), Q, "AreEqual(1777, Q)"); step04_passed = true; TestContext.WriteLine($"{nameof(Test04_SquareRoot)} passed?: {step04_passed}"); TestContext.WriteLine($"LEAVE: {nameof(Test04_SquareRoot)}"); }
public static GNFS FindSquares(CancellationToken cancelToken, GNFS gnfs) { if (cancelToken.IsCancellationRequested) { return(gnfs); } Logging.LogMessage(); Logging.LogMessage($"# of solution sets: {gnfs.CurrentRelationsProgress.FreeRelations.Count}"); Logging.LogMessage(); BigInteger polyBase = gnfs.PolynomialBase; List <List <Relation> > freeRelations = gnfs.CurrentRelationsProgress.FreeRelations; // Below randomly selects a solution set to try and find a square root of the polynomial in. // Each time this step is stopped and restarted, it will try a different solution set. // Previous used sets are tracked with the List<int> triedFreeRelationIndices if (triedFreeRelationIndices.Count == freeRelations.Count) // If we have exhausted our solution sets, alert the user. Number wont factor for some reason. { Logging.LogMessage("ERROR: ALL RELATION SETS HAVE BEEN TRIED...?"); Logging.LogMessage($"If the number of solution sets ({freeRelations.Count}) is low, you may need to sieve some more and then re-run the matrix solving step."); Logging.LogMessage("If there are many solution sets, and you have tried them all without finding non-trivial factors, then something is wrong..."); Logging.LogMessage(); return(gnfs); } int freeRelationIndex = 0; do { freeRelationIndex = StaticRandom.Next(0, freeRelations.Count); }while (triedFreeRelationIndices.Contains(freeRelationIndex)); triedFreeRelationIndices.Add(freeRelationIndex); // Add current selection to our list List <Relation> selectedRelationSet = freeRelations[freeRelationIndex]; // Get the solution set SquareFinder squareRootFinder = new SquareFinder(gnfs, selectedRelationSet); // If you want to solve for a new solution set, create a new instance Logging.LogMessage($"Selected solution set # {freeRelationIndex + 1}"); Logging.LogMessage(); Logging.LogMessage($"Selected set (a,b) pairs (count: {selectedRelationSet.Count}): {string.Join(" ", selectedRelationSet.Select(rel => $"({rel.A},{rel.B})"))}"); Logging.LogMessage(); Logging.LogMessage(); Logging.LogMessage(); Logging.LogMessage($"ƒ'(m) = {squareRootFinder.PolynomialDerivative}"); Logging.LogMessage($"ƒ'(m)^2 = {squareRootFinder.PolynomialDerivativeSquared}"); Logging.LogMessage(); Logging.LogMessage("Calculating Rational Square Root."); Logging.LogMessage("Please wait..."); squareRootFinder.CalculateRationalSide(); Logging.LogMessage("Completed."); Logging.LogMessage(); Logging.LogMessage($"γ² = {squareRootFinder.RationalProduct} IsSquare? {squareRootFinder.RationalProduct.IsSquare()}"); Logging.LogMessage($"(γ · ƒ'(m))^2 = {squareRootFinder.RationalSquare} IsSquare? {squareRootFinder.RationalSquare.IsSquare()}"); Logging.LogMessage(); Logging.LogMessage(); Logging.LogMessage("Calculating Algebraic Square Root."); Logging.LogMessage("Please wait..."); Tuple <BigInteger, BigInteger> foundFactors = squareRootFinder.CalculateAlgebraicSide(cancelToken); BigInteger P = foundFactors.Item1; BigInteger Q = foundFactors.Item2; if (cancelToken.IsCancellationRequested && P == 1 && Q == 1) { Logging.LogMessage("Square root search aborted!"); return(gnfs); } Logging.LogMessage("Completed."); Logging.LogMessage(); Logging.LogMessage(); if (P != 1 || Q != 1) { Logging.LogMessage("NON-TRIVIAL FACTORS FOUND!"); Logging.LogMessage(); } IPolynomial S = squareRootFinder.S; IPolynomial SRingSquare = squareRootFinder.SRingSquare; BigInteger prodS = SRingSquare.Evaluate(polyBase); IPolynomial reducedS = Polynomial.Modulus(S, gnfs.N); BigInteger totalProdS = squareRootFinder.TotalS.Evaluate(polyBase) * squareRootFinder.PolynomialDerivative; BigInteger totalProdModN = totalProdS % gnfs.N; BigInteger prodSmodN = prodS % gnfs.N; List <BigInteger> algebraicNumberFieldSquareRoots = squareRootFinder.AlgebraicResults; BigInteger rationalSquareRoot = squareRootFinder.RationalSquareRootResidue; BigInteger algebraicSquareRoot = squareRootFinder.AlgebraicSquareRootResidue; Logging.LogMessage($"∏ Sᵢ ="); Logging.LogMessage($"{squareRootFinder.TotalS}"); Logging.LogMessage(); Logging.LogMessage($"∏ Sᵢ (mod ƒ) ="); Logging.LogMessage($"{reducedS}"); Logging.LogMessage(); Logging.LogMessage("Polynomial ring:"); Logging.LogMessage($"({string.Join(") * (", squareRootFinder.PolynomialRing.Select(ply => ply.ToString()))})"); Logging.LogMessage(); Logging.LogMessage("Primes:"); Logging.LogMessage($"{string.Join(" * ", squareRootFinder.AlgebraicPrimes)}"); // .RelationsSet.Select(rel => rel.B).Distinct().OrderBy(relB => relB)) Logging.LogMessage(); Logging.LogMessage(); Logging.LogMessage($"X² / ƒ(m) = {squareRootFinder.AlgebraicProductModF} IsSquare? {squareRootFinder.AlgebraicProductModF.IsSquare()}"); Logging.LogMessage(); Logging.LogMessage($""); Logging.LogMessage($"AlgebraicPrimes: {squareRootFinder.AlgebraicPrimes.FormatString(false)}"); Logging.LogMessage($"AlgebraicResults: {squareRootFinder.AlgebraicResults.FormatString(false)}"); Logging.LogMessage($""); Logging.LogMessage($"*****************************"); Logging.LogMessage($""); Logging.LogMessage($"AlgebraicSquareRootResidue: {squareRootFinder.AlgebraicSquareRootResidue}"); Logging.LogMessage($""); Logging.LogMessage($"AlgebraicNumberFieldSquareRoots: {algebraicNumberFieldSquareRoots.FormatString(false)}"); Logging.LogMessage($""); Logging.LogMessage($" RationalSquareRoot : {rationalSquareRoot}"); Logging.LogMessage($" AlgebraicSquareRoot: {algebraicSquareRoot} "); Logging.LogMessage($""); Logging.LogMessage($"*****************************"); Logging.LogMessage($"S (x) = {prodSmodN} IsSquare? {prodSmodN.IsSquare()}"); Logging.LogMessage(); Logging.LogMessage("Roots of S(x):"); Logging.LogMessage($"{{{string.Join(", ", squareRootFinder.RootsOfS.Select(tup => (tup.Item2 > 1) ? $"{tup.Item1}/{tup.Item2}" : $"{tup.Item1}"))}}}");