public BigInteger[] Solve() { /* Solving a linear equation over a residue class is not so trivial if the modulus is not a prime. * This is because residue classes with a composite modulus is not a field, which means that not all elements * of this ring do have an inverse. * We cope with this problem by factorizing the modulus in its prime factors and solving gauss over them * separately (in the case of p^q (q>1) by using "hensel lifting"). * We can use the chinese remainder theorem to get the solution we need then. * But what happens if we aren't able to factorize the modulus completely, because this is to inefficient? * There is a simple trick to cope with that: * Try the gauss algorithm with the composite modulus. Either you have luck and it works out without a problem * (in this case we can just go on), or the gauss algorithm will have a problem inverting some number. * In the last case, we can search for the gcd of this number and the composite modulus. This gcd is a factor of the modulus, * so that solving the equation helped us finding the factorization. */ FiniteFieldGauss gauss = new FiniteFieldGauss(); HenselLifting hensel = new HenselLifting(); List <Msieve.Factor> modfactors = Msieve.TrivialFactorization(mod); List <KeyValuePair <BigInteger[], Msieve.Factor> > results; //Stores the partial solutions together with their factors bool tryAgain; try { do { results = new List <KeyValuePair <BigInteger[], Msieve.Factor> >(); tryAgain = false; for (int i = 0; i < modfactors.Count; i++) { if (modfactors[i].prime) //mod prime { if (modfactors[i].count == 1) { results.Add(new KeyValuePair <BigInteger[], Msieve.Factor>(gauss.Solve(MatrixCopy(), modfactors[i].factor), modfactors[i])); } else { results.Add(new KeyValuePair <BigInteger[], Msieve.Factor>(hensel.Solve(MatrixCopy(), modfactors[i].factor, modfactors[i].count), modfactors[i])); } } else //mod composite { //Try using gauss: try { BigInteger[] res = gauss.Solve(MatrixCopy(), modfactors[i].factor); results.Add(new KeyValuePair <BigInteger[], Msieve.Factor>(res, modfactors[i])); //Yeah, we had luck :) } catch (NotInvertibleException ex) { //We found a factor of modfactors[i]: BigInteger notInvertible = ex.NotInvertibleNumber; List <Msieve.Factor> morefactors = Msieve.TrivialFactorization(modfactors[i].factor / notInvertible); List <Msieve.Factor> morefactors2 = Msieve.TrivialFactorization(notInvertible); modfactors.RemoveAt(i); ConcatFactorLists(modfactors, morefactors); ConcatFactorLists(modfactors, morefactors2); tryAgain = true; break; } } } } while (tryAgain); } catch (LinearDependentException ex) { //We have to throw away dependent rows and try again later: Array.Sort(ex.RowsToDelete, (a, b) => (b - a)); foreach (int row in ex.RowsToDelete) { matrix.RemoveAt(row); } return(null); } BigInteger[] result = new BigInteger[size]; //"glue" the results together: for (int i = 0; i < size; i++) { List <KeyValuePair <BigInteger, BigInteger> > partSolItem = new List <KeyValuePair <BigInteger, BigInteger> >(); for (int c = 0; c < results.Count; c++) { partSolItem.Add(new KeyValuePair <BigInteger, BigInteger>(results[c].Key[i], BigInteger.Pow(results[c].Value.factor, results[c].Value.count))); } result[i] = CRT(partSolItem); } return(result); }