package main

import (
	"bytes"
	"crypto/dsa"
	"crypto/rand"
	"fmt"
	"math/big"
)

func extract(priv *dsa.PrivateKey, r, s *big.Int, hash []byte) string {
	z := new(big.Int).SetBytes(hash)
	h := new(big.Int).Mod(z, priv.Parameters.Q)
	ns := new(big.Int).ModInverse(s, priv.Parameters.Q)
	xr := new(big.Int).Mul(priv.X, r)
	k := new(big.Int).Add(h, xr)
	num := new(big.Int).Mul(ns, k)
	msg := new(big.Int).Mod(num, priv.Parameters.Q)
	return string(msg.Bytes())
}

func main() {
	priv := new(dsa.PrivateKey)
	err := dsa.GenerateParameters(&priv.Parameters, rand.Reader, dsa.L1024N160)
	fmt.Println(err)
	err = dsa.GenerateKey(priv, rand.Reader)
	fmt.Println(err)
	hash := []byte("hello")
	msg := []byte("0000000000000000world")
	buf := bytes.NewBuffer(msg)
	r, s, err := dsa.Sign(buf, priv, hash)
	fmt.Println(r, s, err)
	fmt.Println(dsa.Verify(&priv.PublicKey, hash, r, s))
	msg1 := extract(priv, r, s, hash)
	fmt.Println(msg1)
}
