@@ -734,7 +734,7 @@ struct Factorizer {
734734 size_t rowLimit;
735735 bool isIncomplete;
736736 std::vector<size_t > smoothPrimes;
737- std::set <BigInteger> smoothNumberSet ;
737+ std::vector <BigInteger> residueKeys ;
738738 std::vector<BigInteger> smoothNumberKeys;
739739 std::vector<boost::dynamic_bitset<size_t >> smoothNumberValues;
740740 ForwardFn forwardFn;
@@ -798,11 +798,11 @@ struct Factorizer {
798798 // Make the candidate NOT a multiple on the wheels.
799799 const BigInteger z = forwardFn (y);
800800 // Make the candidate a perfect square.
801- const BigInteger candidate = (z * z);
802801 // The residue (mod N) needs to be smooth (but not a perfect square).
803802 // The candidate is guaranteed to be between toFactor and its square,
804803 // so subtracting toFactor is equivalent to % toFactor.
805- const boost::dynamic_bitset<size_t > rfv = factorizationParityVector (candidate - toFactor);
804+ const BigInteger residue = (z * z) - toFactor;
805+ const boost::dynamic_bitset<size_t > rfv = factorizationParityVector (residue);
806806 if (rfv.empty ()) {
807807 // The number is useless to us.
808808 continue ;
@@ -812,27 +812,23 @@ struct Factorizer {
812812 // If the candidate is already a perfect square,
813813 // we got lucky, and we might be done already.
814814 if (rfv.none ()) {
815- const BigInteger factor = solveCongruence (candidate);
816- if ((factor > 1U ) && (factor < toFactor)) {
817- // Success
818- isIncomplete = false ;
819-
820- return candidate ;
815+ // x^2 = y^2 % toFactor
816+ const BigInteger x = z;
817+ const BigInteger y = sqrt (residue);
818+ const BigInteger factor = gcd ( this -> toFactor , x - y) ;
819+ if ((factor > 1U ) && (factor < this -> toFactor )) {
820+ return factor ;
821821 }
822822 }
823823
824824 std::lock_guard<std::mutex> lock (batchMutex);
825- // Insert the number if it isn't found (in a binary search) of the accepted set.
826- if (smoothNumberSet.find (candidate) == smoothNumberSet.end ()) {
827- smoothNumberSet.insert (candidate);
828- smoothNumberKeys.push_back (candidate);
829- smoothNumberValues.push_back (rfv);
830- // If we have enough rows for Gaussian elimination already,
831- // so there's no reason to sieve any further.
832- if (smoothNumberKeys.size () > rowLimit) {
833- isIncomplete = false ;
834- smoothNumberSet.clear ();
835- }
825+ smoothNumberKeys.push_back (z);
826+ residueKeys.push_back (residue);
827+ smoothNumberValues.push_back (rfv);
828+ // If we have enough rows for Gaussian elimination already,
829+ // there's no reason to sieve any further.
830+ if (smoothNumberKeys.size () > rowLimit) {
831+ isIncomplete = false ;
836832 }
837833 }
838834
@@ -851,10 +847,10 @@ struct Factorizer {
851847 };
852848
853849 // Special thanks to https://github.com/NachiketUN/Quadratic-Sieve-Algorithm
854- BigInteger solveDependentRows (const GaussianEliminationResult& ger, const size_t & solutionColumnId)
850+ std::vector< size_t > solveDependentRows (const GaussianEliminationResult& ger, const size_t & solutionColumnId)
855851 {
856852 // Add the chosen row from Gaussian elimination solution
857- BigInteger solution = smoothNumberKeys[ ger.solutionColumns [solutionColumnId].second ] ;
853+ std::vector< size_t > solutionIds{ ger.solutionColumns [solutionColumnId].second } ;
858854 std::vector<size_t > indices;
859855
860856 // Get the first free row from Gaussian elimination results
@@ -874,33 +870,30 @@ struct Factorizer {
874870 }
875871 for (const size_t & i : indices) {
876872 if (smoothNumberValues[i][r]) {
877- solution *= smoothNumberKeys[i] ;
873+ solutionIds. push_back (i) ;
878874 break ;
879875 }
880876 }
881877 }
882878
883- return solution ;
879+ return solutionIds ;
884880 }
885881
886- BigInteger solveCongruence (const BigInteger& ySqr )
882+ BigInteger solveCongruence (const std::vector< size_t >& solutionIds )
887883 {
888884 // x^2 = y^2 % toFactor
889- const BigInteger x = sqrt (ySqr % this ->toFactor );
885+ BigInteger x = 1U ;
886+ BigInteger ySqr = 1U ;
887+ for (const size_t & id : solutionIds) {
888+ x *= smoothNumberKeys[id];
889+ ySqr *= residueKeys[id];
890+ }
890891 const BigInteger y = sqrt (ySqr);
891892 // Uncomment this to check our math:
892- // if ((x * x) != (ySqr % this->toFactor)) {
893+ // if ((x * x) != ((y * y) % this->toFactor)) {
893894 // throw "Mistake!";
894895 // }
895-
896- // Check congruence of squares
897- BigInteger factor = gcd (this ->toFactor , x + y);
898- if ((factor > 1U ) && (factor < this ->toFactor )) {
899- return factor;
900- }
901-
902- // Try x - y as well
903- factor = gcd (this ->toFactor , x - y);
896+ const BigInteger factor = gcd (this ->toFactor , x - y);
904897 if ((factor > 1U ) && (factor < this ->toFactor )) {
905898 return factor;
906899 }
0 commit comments