Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the CryptX CPAN distribution.

Report information
The Basics
Id: 89400
Status: open
Priority: 0/
Queue: CryptX

People
Owner: Nobody in particular
Requestors: MIK [...] cpan.org
Cc:
AdminCc: DANAJ [...] cpan.org

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Better primality testing in CryptX (libtomcrypt/libtommath)
This RT is based on Dana Jacobsen's comment in another RT: Show quoted text
> There are two issues. One is doing only 8 tests, which doesn't bother > me quite so much as the next. At 160 bits, 8 tests should give us a > better than 1e-15 chance of failure on random inputs (using > Damgård/Landrock/Pomerance calculations, which based on their table 1 > are conservative). If the input is chosen by an adversary, then only > 1.5e-5. That seems high to me. But this is just being lax with the > probability, which I wouldn't claim is "broken". > > My main issue is that it uses the first k prime bases for its tests. > If I have a random number from 1 to 1M and ask you to guess it, your > chances are 1 in 1 million. But if I never change my number, and > you're allowed to keep guessing and talk to everyone else who's > played, then the chances are no longer 1 in 1M, and once you know my > number then you can guess it every time. That's essentially what > using a fixed set of bases is doing. There are known numbers that > pass the first 168 prime bases. Arnault in 1994 wrote a paper showing > how to construct numbers that pass many given bases. > > This is a big issue if you're exposing the is-prime function to > anything that can select its number (e.g. a user like Perl 6 does). > For DSA use it doesn't seem obviously as bad since the input numbers > are not user-chosen, but cryptography is a bad place to say "I can't > think of how the known weakness can be exploited, so I guess it's ok." > > We could: > > - prove the primality. Fantastic for security, but requires a non- > trivial implementation (For Crypt::DSA::GMP I'm using > Math::Prime::Util::GMP) and is always going to be a performance > concern. With MPU:GMP, it's almost free for < 256-bit, but gets quite > noticeable after 1024 or so bits, and probably too slow for this > application once in the 4096-bit range. WraithX has a nice APRCL > implementation that looks promising also. Both are in GMP however, > and would be quite a bit of work to put in libtommath. > > - BPSW + optional number of random [2, n-2] M-R bases. In my opinion > the best solution, meets FIPS requirements, and good performance. > This is what I'm doing in Crypt::DSA::GMP when not proving primality. > See next item. > > - BPSW. Requires adding a Lucas test to libtommath, which isn't too > hard (~40-100 lines of code), but you have to get it integrated into > libtommath. ltm is kind of built around the idea of multiple M-R > tests, which is a very 1980's way to do things. By itself BPSW isn't > FIPS compliant, though it is what almost all math packages use now. > FIPS wants some extra M-R tests. > > - M-R with random (in range [2,n-2]) bases. FIPS compliant, though > they want a huge number of bases if you're not using a Lucas test. > > > While random bases prevent a lot of crytographic attacks, it makes > debugging more of a problem since you can't reproduce any failure. > Since the BPSW test has no known counterexamples, it's unlikely to > ever come up if you do that first.
I have put some ideas in a special branch at: https://github.com/DCIT/perl-CryptX/tree/better-primes The central point (partly stolen from Math-Prime-Util-GMP) is: https://github.com/DCIT/perl-CryptX/blob/better-primes/src/ltm/bn_mp_prime_is_prime.c I have newly added: https://github.com/DCIT/perl-CryptX/blob/better-primes/src/ltm/bn_mp_prime_miller_rabin_random.c The Lucas test is not implemented yet but should go to https://github.com/DCIT/perl-CryptX/blob/better-primes/src/ltm/bn_mp_prime_lucas.c It it completely untested, just proof of concept to show the idea. There are couple of things I am not sure about: 1/ we are testing (in this order) whether - A is a known prime (we know the first N primes) => then PRIME - A is divisible by any of the first N primes => then composite - A < N-th-prime^2 => then PRIME (here is a bug in code) - one MR test with base 2 => on failure: composite - Lucas test => on failure: composite - several MR tests with random base from [2, A-2] => on failure: composite - if all tests pass => then PRIME is it OK? 2/ As the same routine is used for generating RSA keys and DSA params it would be nice to determine the number of MR tests with random base from bit length of A. However FIPS.186-4 tables C.1, C.2 and C.3 are still a bit unclear to me. 3/ And of course Lucas implementation is missing. Dana, I would appreciate any help with this issue.
I have granted you push priv to our perl-CryptX repo. Branch better-primes is open for any ideas/improvements :)
Subject: Re: [rt.cpan.org #89400] Better primality testing in CryptX (libtomcrypt/libtommath)
Date: Thu, 10 Oct 2013 22:13:49 -0700
To: bug-CryptX [...] rt.cpan.org
From: Dana Jacobsen <dana.jacobsen [...] gmail.com>
I've got a bunch of other stuff I need to work on first, but I'll try to make some time for this. Right now I'll add an email with some thoughts. I'll label the steps from your (1): (a) A is a known prime (we know the first N primes) => then PRIME (b) A is divisible by any of the first N primes => then composite (c) A < N-th-prime^2 => then PRIME (here is a bug in code) Yes, step (c) doesn't look right: Given the sizes involved, we should be safe asking if A*A < Pn where Pn is the Nth prime. It should be mixed in with (b). There are lots of ways of doing these steps, each with different performance / readability tradeoffs. MPU::GMP does them in a very simple way, mostly because small values will typically go through the more optimized native-integer methods from MPU. - GCD. With GMP, doing a GCD with a primorial is typically the fastest solution for large inputs. I have no idea for libtommath if this would be true. Thjs is just a speedup over a simple trial division loop. - Steps (b)+(c) with (a) only for tiny values. So something like: if (A < 11) { return (n in (2,3,5,7)) ? 2 : 0 } return 0 if A % 2 == 0 || A % 3 == 0 || A % 5 == 0; for each small prime p starting at 7 { return 1 if p*p > A return 0 if A % p == 0; } return 1 if maxp * maxp < A // note that if maxp goes over 65536 then we need to use isqrt(A) instead. - Use a bit array like MPU's util.c to handle step (a). This stores the first 10,000 primes in 334 bytes. Probably overkill for crypto use as we don't need to shave a couple microseconds off the time for small primes. - Mix (a), (b), (c) together a little. E.g. from MPU's primality.c: if (n < 11) { if (n == 2 || n == 3 || n == 5 || n == 7) return 2; else return 0; } if (!(n%2) || !(n%3) || !(n%5) || !(n%7)) return 0; if (n < 121) /* 11*11 */ return 2; if (!(n%11) || !(n%13) || !(n%17) || !(n%19) || !(n%23) || !(n%29) || !(n%31) || !(n%37) || !(n%41) || !(n%43) || !(n%47) || !(n%53)) return 0; if (n < 3481) /* 59*59 */ return 2; This is slightly faster than the simple (b)+(c) but only if we're counting cycles for native integers. I guess we need to know what the goals are: - Fast for small inputs (e.g. under 2^64) - Fast for multi-hundred-digit inputs, especially next_prime - Adequate and simple code Trying to speed everything up adds complication, especially when dealing with multiple size scales. I think just the simple (b)+(c) is best for now. (d) one MR test with base 2 => on failure: composite (e) Lucas test => on failure: composite We have a choice of: - standard Lucas test, as shown in FIPS 186-4 C.3.3. That implementation is not very efficient, by the way. - strong Lucas test. The false positives are a strict subset of the standard test and it runs as fast as the standard test, so honestly there is no reason not to use it. Baillie and Wagstaff's paper recommends this. - extra strong Lucas test or "almost extra strong" Lucas test. See http://www.sti15.com/nt/pseudoprimes.html. Typically faster and fewer pseudoprimes. The weaker version has been used by Pari for years. There are no known pseudoprimes for any of them, and various math packages use different versions. We'd be fine with the any of them, though I don't see why one would use the non-strong test. I chose the extra strong test because it's faster than the standard and strong test, infinitesimally slower than the almost-extra-strong test, and seems to have the strongest result. (f) several MR tests with random base from [2, A-2] => on failure: composite We could put these here or after (d) -- it probably doesn't matter unless the Lucas test is particularly slow relative to the MR test. For the extra tests in MPU's is_prime I chose a number I thought was appropriate based on some probabilities, and chosen not spend too much time. Some people make the argument that we shouldn't bother with any extra tests until we find a BPSW counterexample, but I figured I'd add something. For large inputs (e.g. over 10k digits, so over 33k bits) even a single M-R test takes a noticeable amount of time. For cryptographic purposes I think we shouldn't be quite so dismissive, especially for keys. You could look at what I did in Crypt::DSA::GMP where I'm trying to follow FIPS 186-4 appendix C (for DSA, so table C.1). Their table for RSA isn't nearly as simple. Usually I've used a method like B.3.1.A for random prime generation -- I've never used B.3.1.B, which I believe is trying to make sure p and q are strong primes. Some thoughts: - Why step (d)? Because it means any false positive must be a BPSW counterexample. If we had horrible luck with the random number generator for the random bases, it still must pass base 2. This is, however, my opinion -- I don't think there is consensus on this. - What about duplicates in step (f)? We could store the bases and make sure we choose at least enough independent ones. This is a problem if they ask for 10M bases or something silly. For large sizes it seems overkill anyway, unless our PRNG is hacked. - The number of extra tests is based on the bit size and desired security level. The smaller the size or more security, the more tests. Ideally we'd have a function that takes either A or log2(A) and returns a number of extra tests, then verify that the return values are >= the FIPS values. (g) if all tests pass => then PRIME On Thu, Oct 10, 2013 at 2:26 PM, Karel Miko via RT <bug-CryptX@rt.cpan.org>wrote: Show quoted text
> Queue: CryptX > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=89400 > > > I have put some ideas in a special branch at: > https://github.com/DCIT/perl-CryptX/tree/better-primes > > The central point (partly stolen from Math-Prime-Util-GMP) is: > > https://github.com/DCIT/perl-CryptX/blob/better-primes/src/ltm/bn_mp_prime_is_prime.c > > I have newly added: > > https://github.com/DCIT/perl-CryptX/blob/better-primes/src/ltm/bn_mp_prime_miller_rabin_random.c > > The Lucas test is not implemented yet but should go to > > https://github.com/DCIT/perl-CryptX/blob/better-primes/src/ltm/bn_mp_prime_lucas.c > > It it completely untested, just proof of concept to show the idea. > > There are couple of things I am not sure about: > > 1/ we are testing (in this order) whether > - A is a known prime (we know the first N primes) => then PRIME > - A is divisible by any of the first N primes => then composite > - A < N-th-prime^2 => then PRIME (here is a bug in code) > - one MR test with base 2 => on failure: composite > - Lucas test => on failure: composite > - several MR tests with random base from [2, A-2] => on failure: > composite > - if all tests pass => then PRIME > is it OK? > > 2/ As the same routine is used for generating RSA keys and DSA params it > would be nice to determine the number of MR tests with random base from bit > length of A. However FIPS.186-4 tables C.1, C.2 and C.3 are still a bit > unclear to me. > > 3/ And of course Lucas implementation is missing. > > Dana, I would appreciate any help with this issue. >
On 2013-10-11 01:14:08, dana.jacobsen@gmail.com wrote: Show quoted text
> (c) A < N-th-prime^2 => then PRIME (here is a bug in code) > > Yes, step (c) doesn't look right: Given the sizes involved, we should
Saw this by accident, it's late, and maybe I am a bit dense, but (c) looks fine to me: if a number has no factors <= q and is <= q**2, then it must be prime, as otherwise one of its factors would be <= q.
On Mon Mar 17 17:24:18 2014, MLEHMANN wrote: Show quoted text
> On 2013-10-11 01:14:08, dana.jacobsen@gmail.com wrote: >
> > (c) A < N-th-prime^2 => then PRIME (here is a bug in code) > > > > Yes, step (c) doesn't look right: Given the sizes involved, we should
> > Saw this by accident, it's late, and maybe I am a bit dense, but (c) looks > fine to me: if a number has no factors <= q and is <= q**2, then it must > be prime, as otherwise one of its factors would be <= q.
There was a defect in the code at that time, where it would return true if the variable was *equal* to P^2. The Nov 13 code on that branch now does the < comparison.
To make sure it's clear, the defect was in the test feature branch, not on any released code. I also see that my October reply was very much a brain dump as I read through the code, and could have used more clarity. I also need to get back to this.