MODP group modulus derivation [was: Re: I can has SHA-1 hashes for RFC 2409/3526 MODP groups?]
Daniel Kahn Gillmor <[email protected]>
| Newsgroups | gmane.ietf.tls,gmane.ietf.secsh |
|---|---|
| Message-ID | <[email protected]> |
On 03/08/2014 01:12 PM, Mark D. Baushke wrote:
> You raise a good point. Folks with 'bc -l' should be able to verify the
> MODP groups.
The k-bit MODP discrete-log moduli is formulated as the smallest
safe-prime that meets the form:
2^k - 2^(k-64) - 1 + 2^64 * { [2^(k-130) pi] + N }
where N is a positive integer.
More colloquially, this is: 64 bits of 0xFF, followed by (k-128) bits of
pi, followed by 64 more bits of 0xFF. I don't know why this sequence
was selected. Does anyone have any pointers to reasons you might want
the modulus structured this way?
Given a bit-length k, The attached python program tests all integers N
in sequence, stopping at the first safe-prime. For example:
0 dkg@alice:~$ python3 ./gen-modp.py 768
searching for 768-bit safe-prime modulus, starting at:
FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
E485B576 625E7EC6 F44C42E9 A637ED6B FFFFFFFF FFFFFFFF
added 0x248b6 * 2^64 (decimal: 149686 * 2^64)
The prime is: 2^768 - 2^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF
0 dkg@alice:~$
Thus far, I've used it to generate the moduli for these groups:
* 768-bit (MODP 1)
* 1024-bit (MODP 2)
* 1536-bit (MODP 5)
* 2048-bit (MODP 14)
* 3072-bit (MODP 15)
i haven't yet generated these (mainly due to time):
* 4096-bit (MODP 16)
* 6144-bit (MODP 17)
* 8192-bit (MODP 18)
Regards,
--dkg
_______________________________________________
TLS mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/tls
gen-modp.py
(text/x-python, 3 KB)
#!/usr/bin/python # Author: Daniel Kahn Gillmor <[email protected]> # Date: 2014-03-11 # derive p for the default groups in RFC 3526 and RFC 5996 # these RFCs use a particular approach to derive the prime modulus, # based only on the size of the prime desired, and on the digits of pi. # this code performs the same search pattern and verifies the result. # Usage: # $ python3 gen-modp.py 1024 # this will generate the 1024-bit modulus found in RFC 5996. import sys import gmpy2 def breakup(s,k): '''return string s broken into chunks of size k''' return (s[0+n:k+n] for n in range(0,len(s),k)) def displayhex(mpz,stream): '''write an mpz to stream in the form preferred by the MODP RFC's''' h = hex(mpz)[2:].upper() # strip leading 0x linelen = 48 if len(h) == 6144//4: linelen += 8 # section 6 of RFC 3526 is unusually-formatted for x in breakup(h,linelen): for y in breakup(x,8): stream.write(" " + y) stream.write("\n") def t_pi(n): '''return an mpz containing the first n bits of pi''' gmpy2.get_context().precision=n+1 return gmpy2.mpz(gmpy2.floor((gmpy2.mpz(1) << (n-2)) * gmpy2.const_pi(n+1))) def checkanswer(bitsize,inc): '''Given a number of bits and an selected offset, verify that the expected result of the MODP modulus selection scheme is a safe prime. We're using probabilistic primality testing here, but leaning hard on the test, making sure it's expensive and much more thorough than the default tests used during selection. ''' one = gmpy2.mpz(1) val = (one << bitsize) - (one << (bitsize-64)) - one + \ ((one<<64)* (t_pi(bitsize - 128) + inc)) if not (gmpy2.is_prime(val, bitsize) and \ gmpy2.is_prime((val-1)//2,bitsize)): raise Exception("expensive primality tests contradicted "+\ "the cheap ones!") print("The prime is: 2^%d - 2^%d - 1 + 2^64 * { [2^%d pi] + %d }"%\ (bitsize, bitsize-64, bitsize-(64+66), inc)) displayhex(val, sys.stdout) def search(bitsize): '''search for a prime with bitsize bits, using the pattern established by the MODP RFC's. ''' bits = gmpy2.mpz(0xffffffffffffffff) # 64 bits of 0xff # the remaining bits of pi # 64 bits of 0xff # then count up until we find a prime base = (bits << (bitsize-64)) + (t_pi(bitsize-128) << 64) + bits print("searching for %d-bit safe-prime modulus, starting at:"%(bitsize,)) displayhex(base,sys.stdout) inc = 1 # initial offset started to clear the middle bits for pi while not gmpy2.is_prime(base) \ or not gmpy2.is_prime((base-1)>>1): if (inc % 17) == 1: sys.stdout.write("\radding 0x%x * 2^64"%(inc)) inc += 1 base += 2**64 sys.stdout.write("\radded 0x%x * 2^64 (decimal: %d * 2^64)\n"%\ (inc,inc)) return inc if sys.argv.__len__() > 1: target = int(sys.argv[1]) else: target = 768 inc = search(target) checkanswer(target,inc)
signature.asc
(application/pgp-signature, 1010 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 Comment: Using GnuPG with Icedove - http://www.enigmail.net/ iQJ8BAEBCgBmBQJTH4rfXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRFQjk2OTEyODdBN0FEREUzNzU3RDkxMUVB NTI0MDFCMTFCRkRGQTVDAAoJEKUkAbEb/fpcEOoQAOhJcRyP/9gOVqGLdzU4NJ2C +oJL5QZO6YXRMHN3AAjmX3iA7ccVx2xCNf99+vrleh11kC7lagZ3yqN2ZjufOpUg 0Rd3lg3n4FiOfjksqP36D8gDfoRsZmQgLA7qS+MNd8W80o3j3DR3uoyNZgtEYdMK natwJnSx6gVm2FzeU3BAe+AVFJyjVEPj7AypjvbbI/C2qajlD27vh/d0Dj9CECCe SGNcfPBQICNL/Pqr0xZbC/JUfvJ0lviCQkU1eJ5OTExa5P+6cVLMdN3oEINr7C7C TO7twz3OQgCfDBEM8DOMSGBq+3O6L8dOjFPb734sNBnFYggeAdpRlBI1sRxo2r5m eNq87LCFpX5YrWgL6KEXwmHhyDED8jRigs9OhDink2pQsXx3hLAodSWAy7VSLj+g fPp0dIO3flKicoIyEzt7LYxr3/QGtFqpv0H0+gJ6OhNpWpGWzT0ZiAEIyx1QLGoN mi0b/WnMEqEX6AvEzdUU3QcucxMOiJFZXqZcsuoAtu6H8OUPElG8Prw9ygWuT8g1 4iKtScMbUzMcBUfXVRIQaFcY5L3X0/o0nbhGBvWiiDRBbVG0zQeLQoqQ1uwvcKN9 /1MFCOyAFrUxRj7TDQECzrvgYAmXoYc7Mk9RVKPbrHjzaRXG5LjvAvPDMebsnDqA 7zSjlCDJfAnFM7I7/kX4 =1yQN -----END PGP SIGNATURE-----