package main

import (
"bytes"
"compress/gzip"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/md5"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"math/big"
"prlife/tool"
"strings"
)
//楕圆曲线算法生成公钥,
func main(){
//测试根据随机key及楕圆曲线生成私钥和公钥
privateKey,publicKey:=newKeyPair()
fmt.Printf("私钥:%x\n",privateKey.D.Bytes())
fmt.Printf("公钥:%x\n",publicKey) //16进制表示
//根据指定key生成私钥和公钥
randKey := "20180619zafes20180619zafes20180619zafessss"
//randKey:=tool.GetRandomString(40)
prk, puk, err := getEcdsaKey(randKey)
if err != nil {
fmt.Println(err)
}
publicKey1 := append(puk.X.Bytes(), puk.Y.Bytes()...)
fmt.Printf("私钥为:%x 长度为:%d\n公钥为:%x,公钥长度为%d\n", prk.D.Bytes(), len(prk.D.Bytes()), publicKey1, len(publicKey1))

//签名
hashSign:=md5.Sum([]byte("caspar123"))
r1,s1,signerr:=ecdsa.Sign(rand.Reader,privateKey,hashSign[:])
if signerr != nil {
    fmt.Println(signerr)
}
signature:=append(r1.Bytes(),s1.Bytes()...)
fmt.Printf("签名后数据为:%x\n",signature)

 //验签
 //构造公钥对象
curve:=elliptic.P256()   //楕圆曲线
rawPubLen:=len(publicKey)
 x1:=big.Int{}
 y1:=big.Int{}
 x1.SetBytes(publicKey[:(rawPubLen/2)])
 y1.SetBytes(publicKey[(rawPubLen/2):])
 rawPub:=ecdsa.PublicKey{curve,&x1,&y1}
 rawVerifyResult:=ecdsa.Verify(&rawPub,hashSign[:],r1,s1)
 if(rawVerifyResult==true){
    fmt.Println("验证通过")
 }else{
     fmt.Println("验证失败")
 }

}
//根据随机key及楕圆曲线生成私钥和公钥
func newKeyPair()(*ecdsa.PrivateKey,[]byte){
curve:=elliptic.P256() //楕圆曲线
privateKey,err:=ecdsa.GenerateKey(curve,rand.Reader)
if(err!=nil){
fmt.Println(err)
}
publicKey:=append(privateKey.PublicKey.X.Bytes(),privateKey.PublicKey.Y.Bytes()...)
return privateKey,publicKey
}

/*
通过一个指定key创建公钥和私钥
随机key至少为36位
/
func getEcdsaKey(randKey string) (*ecdsa.PrivateKey, ecdsa.PublicKey, error) {
var err error

var prk *ecdsa.PrivateKey
var puk ecdsa.PublicKey
var curve elliptic.Curve
lenth := len(randKey)
if lenth < 224/8 {
    err = errors.New("私钥长度太短,至少为36位!")
    return prk, puk, err
}
if lenth > 521/8+8 {
    curve = elliptic.P521()
} else if lenth > 384/8+8 {
    curve = elliptic.P384()
} else if lenth > 256/8+8 {
    curve = elliptic.P256()
} else if lenth > 224/8+8 {
    curve = elliptic.P224()
}
//GenerateKey 生成公钥和私钥对。
//func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error)
//ecdsa.GenerateKey(curve,rand.Reader)
prk, err = ecdsa.GenerateKey(curve, strings.NewReader(randKey))
if err != nil {
    return prk, puk, err
}
puk = prk.PublicKey //ECDSA 公钥
return prk, puk, err

}