Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inefficient square root #16

Open
GregoryMorse opened this issue Jul 23, 2023 · 5 comments
Open

Inefficient square root #16

GregoryMorse opened this issue Jul 23, 2023 · 5 comments
Assignees
Labels

Comments

@GregoryMorse
Copy link

GregoryMorse commented Jul 23, 2023

Description
During the square root in GNFSCore/SquareRoot/SquareFinder.cs, it will find the positive and negative roots via inverse modulo. Then it compares it to the positive and negative (inverse) original polynomial which does not actually do anything nor make sense. Finally it does not make use of this anyway, and uses a cartesian product and searches all 2^d values.

According to the thesis An Introduction to the General Number Field Sieve by Matthew E. Briggs cited here, the norm function should be used to disambiguate this. It is computed as alpha^((p^d-1)/(p-1) where alpha should be both of the potential roots. However I also cannot figure out how to get this to work, as it is unclear what is a positive versus negative norm. The key is being consistent across the splitting field. But trial and error is an oversight that should be correctable. Unfortunately I cannot find the details to get this working.

@AdamWhiteHat
Copy link
Owner

tl; dr: Yeah, you are correct; Something is broken with the final square root step. I am looking at that now. I spent several hours on it last night, and I plan to spend all of today on it as well. Ill probably keep plugging away at it until I get it working. There is some progress being made. Ive identified a problem area, due to your comments. I'm currently figuring out what to do about it and also busy looking through the literature and verifying my implementation in certain areas.

Thanks for bringing this to my attention. I was aware of it, I was just demotivated to find the issue, but you submitting a bug report and me knowing that other people are looking at it has motivated me once again. Well, and I have been meaning to take a look at this again. So thanks for the push.

It was working at one point in time, and then * something * changed and now the difference of two squares fails to yield non-trivial factors.
The code was under source control at the time, but I have scoured the commits but its not clear what changed to cause the issue. Any changes to the square root code was heavily scrutinized and I could not see the problem, so it may be that a change that lies elsewhere is the culprit, such as in the relations factorization or the matrix step.

You are correct that taking the cartesian product and trying every possible combination is wrong. This is an artifact left over from when I was flailing, trying to make the square root step produce factors again--evidence of my desperation at the time. I probably left it in because it works sometimes to find factors, although if it does its not by any principled approach or theory, its either brute forcing it or it could very well be that it does so entirely due to a numerical coincidence, and the fact that the reference/test numbers being factored are so small.

I'm not too sure what you mean by "positive and negative roots via inverse modulo", but by the fact that you say inverse modulo and say that I'm comparing them, I take this to mean in a method called AlgebraicSquareRoot, how I compare the startPolynomial with the resultSquared1 and the modulo inverse of the start polynomial with resultSquared1, looking for a match?

Yeah, you know, looking at it, that is odd and I'm not sure that's right. The first condition should be enough, where the square root polynomial found by the Tonelli-Shanks algorithm method (which I'm not calling Tonelli-Shanks , I'm calling FiniteFieldArithmetic.SquareRoot for some reason) and the modular inverse of that polynomial, when squared, should both be the same.

At any rate, I'm looking into it. I was able to get it working using Matthew E. Briggs' paper once, I'm sure I can get it working again.
Ill keep you informed.

@GregoryMorse
Copy link
Author

So that thesis seems to use the idea here: https://www.math.u-bordeaux.fr/~jcouveig/publi/Cou94-2.pdf

Taking the inverse of startPolynomial doesn't make any sense. It will never match.

Basically you can compute N(alpha) and Np(alpha)=alpha^((p^d-1)/(p-1)). N(alpha) isn't computed from your potentially wrongly signed square root.

The Briggs paper handwaves that important detail.

It's N(alpha)=N(f'(alpha))p1^fp1p2^fp2

Basically the result from the sieve as a square should be decomposed. In the same way as the exponents were determined when building the X matrix. Ord_p(N(a+b*alpha)). They are guaranteed to be even powers as the result is a square.

At least this is my interpretation. Also working on it. Interesting to hear your thoughts about it. Good examples are scarce for some of these detailed steps.

@GregoryMorse
Copy link
Author

Yea that solves it...

So when you are checking that prod(p)==(-b)^d*f(-b/a) you should save all the first-order p values!

Why? Because you can tabulate them after the fact, all of them have degree 1 by definition there, but if you count each prime, they will all end up with even powers after getting the result vector - you dont just want to compute prod(a+b*alpha)=beta^2 but also the order of each prime. For example I made a dictionary like so:

{2: 2, 67: 4, 7: 2, 31: 2, 61: 2, 73: 4, 41: 2, 89: 4, 79: 2, 23: 2, 43: 2, 29: 2}

Since my smooth pairs (a,b) found as the result were: { (-2, 1),(1, 1),(13, 1),(15, 1),(23, 1),(3, 2),(33, 2),(5, 3), (19, 4),(14, 5),(15, 7),(119, 11),(175, 13),(-1, 19),(49, 26) }

And corresponding to those smooth pairs were the following primes found during the smooth pair finding process:
[{2, 67}, {7}, {31}, {61, 7}, {73, 67}, {41}, {89, 79}, {89}, {89, 73}, {2, 61, 23}, {73, 23}, {89, 41, 67}, {43, 67, 79}, {73, 29, 31}, {43, 29}]

Now all those by definition have to be even, as they are squares. But we can halve them, and use them to compute the norm. Not sure if I explained this well, but this is the technique outlined in the paper. N(f'(alpha))*prod(all the primes to half the power) == root^((p^d-1)/(p-1)) gives the correct root. However, I cannot figure out N(f'(alpha)), this norm is ill defined in the papers. Too much hand waiving, the authors were not thorough.

The limitation to this approach, is the polynomial degree must be odd. Otherwise for even degree, perhaps the Cartesian product is necessary. Of course you dont need a full Cartesian product. You can probably fix one value as all negative or all positive will should both work. Its about consistency. So pivoting the first value would arbitrarily half the search space at least.

@GregoryMorse
Copy link
Author

Finally a paper that went through the details: https://infoscience.epfl.ch/record/164498/files/164498.PDF

N(f'(alpha)) can be computed via f'(alpha)^((p^d-1)/(p-1))

Will be interesting to see how you handle it. Not sure if you assume odd degree polynomials, but they can be handled quite efficiently compared to the even counterpart.

AdamWhiteHat added a commit that referenced this issue Aug 23, 2023
This check-in fixes several bugs, improves logging during the square root step and improved the speed of the polynomial modulus a polynomial routine.

The square root method seems to succeed with a much higher probability than previously, but not with the probability of 1/2 as expected.

However, this might just be an issue with small number factorizations, in that its not picking an  inert prime that is large enough.
The formula for picking an inert prime starting value returns a proportionately sized inert prime. However, the algorithm seems to only succeed for small values of N when the inert prime is a significant fraction of the value of N.

More test values of a reasonably appropriate (larger) size are needed to avoid factoring by numerical coincidence and to avoid the inert prime too small issue mentioned above.

More testing needed.

Full list of changes:
- Changed target framework from 6.0 to 5.0 (until I can be bothered to upgrade my windows to version 10, )
- Added static logging function delegate: GNFS.LogFunction
- Added a bunch more logging around the square root step, as well as other places.
- Legendre.SymbolSearch had a bug in it. I fixed the bug.
- Polynomial.ModMod had a horrible runtime. I was able to write a version that ran in a fraction of the time by avoiding needless array allocations and diligently using modulus everywhere to avoid large numbers.
- Normal.Algebraic now calculates things using the arbitrary precision arithmetic library BigRational. This is important for large polynomials such as used when factoring RSA-100, as the norm calculations using only decimals would begin to lose accuracy and then eventually throw an overflow exception.
- There was a bug with SmoothRelations_TargetQuantity, in that it was often less than SmoothRelationsRequiredForMatrixStep, sometimes by 1, and so would needlessly run an extra round of sieving.
- I added some safeguards around the RecursiveDelete function in TestGNFS, moved it to a reusable helper class and made each test class call that common helper class function.
- Removed some dead code.
@AdamWhiteHat
Copy link
Owner

AdamWhiteHat commented Aug 24, 2023

The main issue now is lies in step 5.9 (page 58) of Matthew E Briggs paper: Determining Applicable Finite Fields

The issue is the method Polynomial.Field.GCD is defective.
With this not working, the algorithm is unable to tell if f(x) is irreducible over Z/pZ, for some random 'inert' prime p.

IIRC, I really struggled to get this method implemented, and apparently its still not right. Nevermind, I was thinking of the multivariate polynomial GCD, which requires having to calculate the Grobner basis. A single variable polynomial GCD is pretty straight forward. Hopefully it there is just a silly bug I overlooked.

Once this is working correctly, I believe the GNFS algorithm will work, because the algorithm finds the factors for 45113 if it is handed the 3 primes in the worked example that makes applicable finite fields. as demonstrated in the SmallFactorizationTest_45113 test class in the test project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants