--- /dev/null
+// generate P, Q, G parameters of DSA with verifiable, deterministic algorithm
+package main
+
+import (
+ "crypto/dsa"
+ "crypto/sha1"
+ "fmt"
+ "io"
+ "log"
+ "math/big"
+)
+
+const usage = "usage: ./genpqg"
+
+type prng struct {
+ state []byte
+}
+
+// seed is from
+// od -An -tx1 -N20 /dev/urandom |sed 's/^ //;s/[^ ]*/0x&,/g'
+var r = &prng{[]byte{
+ 0xef, 0xba, 0x22, 0x1b, 0x07, 0x2c, 0xe8, 0x2f, 0xbe, 0x20, 0x77, 0x5d, 0xd0, 0x5c, 0x33, 0xd5,
+ 0xee, 0x66, 0x27, 0x0f,
+}}
+
+// iterated sha1 generator
+func (r *prng) Read(p []byte) (n int, err error) {
+ h := sha1.New()
+ h.Write(r.state)
+ r.state = h.Sum()
+ n = copy(p, r.state)
+ return
+}
+
+// copied from crypto/dsa and slightly modified the generation of q
+const numMRTests = 64
+
+func GenerateParameters(params *dsa.Parameters, rand io.Reader) (err error) {
+ // This function doesn't follow FIPS 186-3 exactly in that it doesn't
+ // use a verification seed to generate the primes. The verification
+ // seed doesn't appear to be exported or used by other code and
+ // omitting it makes the code cleaner.
+
+ L := 1024
+ N := 160
+ qBytes := make([]byte, N/8)
+ pBytes := make([]byte, L/8)
+
+ q := new(big.Int)
+ p := new(big.Int)
+ rem := new(big.Int)
+ one := new(big.Int)
+ one.SetInt64(1)
+
+GeneratePrimes:
+ for {
+ // make q > 2^160 - 2^81 so sha1 sum of random bytes
+ // are in [1, q-1] with high probability
+ for i := 0; i < 10; i++ {
+ qBytes[i] = 0xff
+ }
+ _, err = io.ReadFull(rand, qBytes[10:])
+ if err != nil {
+ return
+ }
+ qBytes[len(qBytes)-1] |= 1
+ q.SetBytes(qBytes)
+
+ if !big.ProbablyPrime(q, numMRTests) {
+ continue
+ }
+
+ for i := 0; i < 4*L; i++ {
+ _, err = io.ReadFull(rand, pBytes)
+ if err != nil {
+ return
+ }
+
+ pBytes[len(pBytes)-1] |= 1
+ pBytes[0] |= 0x80
+
+ p.SetBytes(pBytes)
+ rem.Mod(p, q)
+ rem.Sub(rem, one)
+ p.Sub(p, rem)
+ if p.BitLen() < L {
+ continue
+ }
+
+ if !big.ProbablyPrime(p, numMRTests) {
+ continue
+ }
+
+ params.P = p
+ params.Q = q
+ break GeneratePrimes
+ }
+ }
+
+ h := new(big.Int)
+ h.SetInt64(2)
+ g := new(big.Int)
+
+ pm1 := new(big.Int).Sub(p, one)
+ e := new(big.Int).Div(pm1, q)
+
+ for {
+ g.Exp(h, e, p)
+ if g.Cmp(one) == 0 {
+ h.Add(h, one)
+ continue
+ }
+
+ params.G = g
+ return
+ }
+
+ panic("unreachable")
+}
+
+func main() {
+ params := new(dsa.Parameters)
+ err := GenerateParameters(params, r)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("P: %X\nQ: %X\nG: %X\n", params.P, params.Q, params.G)
+}