Generating a safe prime number with n bits using Golang
[Primes Home][Home]
In cryptography, we often search for safe primes. A safe prime (p) - or also known as a Sophie Germain prime - is safe when \(2p+1\) is also prime. Sophie Germain was a French mathematician and who used safe primes to investigate Fermat's Last Theorem. Overall safe primes are used in cryptography, as they are robust against attacks within discrete log methods (such as for the Diffie Hellman methods).
|
Outline
Sophie Germain (born 1776 in Paris) was a French mathematician and who used safe primes to investigate Fermat's Last Theorem. She gained her knowledge of mathematics by studying the works of Euler and communicated her ideas with other famous mathematics scholars including Legendre and Gauss.
In fact, at the time, she faced great resistance in her studies, including from her parent who confiscated her candles and took away her clothes, in order to stall her research. Sophie also hid her gender when communicating with Gauss and used the pseudonym of M. LeBlanc. But, against all the obstacles she faced, she overcame them and even learnt Greek and Latin so that she could read about the works of Euler and Newton.
Sophie Germain prime
A Sophie Germain prime (\(p\)) is a prime number which also generates a prime at \(2p + 1\). Thus 11 is a Sophie Germain prime, and where 23 is a safe prime. But 17 is not a Sophie Germain prime, as we get 35 for 2x17+1, and which can be factorized. These primes have been seen as being important when selecting prime numbers to be used in the RSA method. For this, we create a public modulus (N) and which is the multiplication of two large prime numbers (\(p\) and \(q\)). If these prime numbers are weak, it can make the factorization of N easier.
The first few Sophie Germain primes are 2, 3, 5, 11, 23, and 29, and which lead to the safe primes of 5, 7, 11, 23, 47 and 59. We can create a Golang program to generate a random prime number with n bits, and then test it to see if it is safe:
ppackage main import ( "crypto/rand" "fmt" "math" "math/big" "os" "strconv" ) func main() { bits := 16 count:=0 argCount := len(os.Args[1:]) if argCount > 0 { bits, _ = strconv.Atoi(os.Args[1]) } if bits < 3 { fmt.Printf("We need at least three bits") } var p *big.Int p1:= new(big.Int) checks := int(math.Max(float64(bits)/16, 8)) for { p, _ = rand.Prime(rand.Reader, int(bits)-1) p1.Set(p) p.Add(p.Lsh(p, 1), big.NewInt(1)) count=count+1 if p.ProbablyPrime(checks) { fmt.Printf("Bits:\t\t%d\n", bits) fmt.Printf("Selections:\t%d", count) fmt.Printf("\nPrime:\t\t%s\n", p1) fmt.Printf("Safe prime:\t%s", p) break } } }
With this, we shift \(p\) by one position to the left, and is equivalent to a \(2.p\), and where we can add 1:
p.Add(p.Lsh(p, 1), big.NewInt(1))
A sample run for a 96-bit prime is:
Bits: 96 Selections: 13 Prime: 37053578410686858579548491583 Safe prime: 74107156821373717159096983167
A sample prime for 512 bits is:
Bits: 512 Selections: 216 Prime: 6215641074915422390891487240873485166396563079583149872792235087315853337457206134539638799981401165118482893105922463329240778055363535077155714487851623 Safe prime: 12431282149830844781782974481746970332793126159166299745584470174631706674914412269079277599962802330236965786211844926658481556110727070154311428975703247