golang实现ecc密钥对与[]byte类型转换

网友投稿 1863 2022-10-03

golang实现ecc密钥对与[]byte类型转换

golang实现ecc密钥对与[]byte类型转换

以太坊的接口真香~

之前一直无法实现原因是getKey()方法的生成密钥用的curve参数为ellipitic.P256()。

func getKey() (*ecdsa.PrivateKey, error) { prk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return prk, err } return prk, nil}

应该使用以太坊实现的S256(),基于secp256k1实现的curve。

func getKey() (*ecdsa.PrivateKey, error) { prk, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) if err != nil { return prk, err } return prk, nil}

FromECDSA和ToECDSA源码如下:

// ToECDSA creates a private key with the given D value.func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) { return toECDSA(d, true)}// ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost// never be used unless you are sure the input is valid and want to avoid hitting// errors due to bad origin encoding (0 prefixes cut off).func ToECDSAUnsafe(d []byte) *ecdsa.PrivateKey { priv, _ := toECDSA(d, false) return priv}// toECDSA creates a private key with the given D value. The strict parameter// controls whether the key's length should be enforced at the curve size or// it can also accept legacy encodings (0 prefixes).func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) { priv := new(ecdsa.PrivateKey) priv.PublicKey.Curve = S256() if strict && 8*len(d) != priv.Params().BitSize { return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize) } priv.D = new(big.Int).SetBytes(d) // The priv.D must < N if priv.D.Cmp(secp256k1N) >= 0 { return nil, fmt.Errorf("invalid private key, >=N") } // The priv.D must not be zero or negative. if priv.D.Sign() <= 0 { return nil, fmt.Errorf("invalid private key, zero or negative") } priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d) if priv.PublicKey.X == nil { return nil, errors.New("invalid private key") } return priv, nil}// FromECDSA exports a private key into a binary dump.func FromECDSA(priv *ecdsa.PrivateKey) []byte { if priv == nil { return nil } return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)}

FromECDSAPuk和UnmarshalPubkey源码如下:

// UnmarshalPubkey converts bytes to a secp256k1 public key.func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { x, y := elliptic.Unmarshal(S256(), pub) if x == nil { return nil, errInvalidPubkey } return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil}func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil } return elliptic.Marshal(S256(), pub.X, pub.Y)}

密钥跟[]byte能够相互转换后,那么密钥保存就能够较为容易实现了,把[]byte封装到数据库就ok。

下面为具体代码:

package mainimport ( "crypto/ecdsa" //"crypto/elliptic" //"crypto/rand" //"encoding/hex" "crypto/rand" "fmt" "github.com/ethereum/go-ethereum/crypto" "math/big")func getKey() (*ecdsa.PrivateKey, error) { prk, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) if err != nil { return prk, err } return prk, nil}func eccSign(data []byte, prk *ecdsa.PrivateKey) ([]byte, error) { r, s, err := ecdsa.Sign(rand.Reader, prk, data) if err != nil { return nil, err } params := prk.Curve.Params() curveOrderByteSize := params.P.BitLen() / 8 rBytes, sBytes := r.Bytes(), s.Bytes() signature := make([]byte, curveOrderByteSize*2) copy(signature[curveOrderByteSize-len(rBytes):], rBytes) copy(signature[curveOrderByteSize*2-len(sBytes):], sBytes) return signature, nil}func eccVerify(data, signature []byte, puk *ecdsa.PublicKey) bool { curveOrderByteSize := puk.Curve.Params().P.BitLen() / 8 r, s := new(big.Int), new(big.Int) r.SetBytes(signature[:curveOrderByteSize]) s.SetBytes(signature[curveOrderByteSize:]) return ecdsa.Verify(puk, data, r, s)}func main() { data := "00007f1f64109f1df066db39cdcfd7bb2343a02bf8a3054399f4772ed640300e" prk, err := getKey() puk := prk.PublicKey if err != nil { panic(err) } //bdata := []byte(data) bprk := crypto.FromECDSA(prk) bpuk := crypto.FromECDSAPub(&puk) lprk, err := crypto.ToECDSA(bprk) lpuk, err := crypto.UnmarshalPubkey(bpuk) fmt.Println(prk) fmt.Println(lprk) fmt.Println(puk) fmt.Println(*lpuk) //测试是否转换成功 eccData, err := eccSign([]byte(data), prk) if err != nil { panic(err) } fmt.Println(eccVerify([]byte(data), eccData, lpuk)) // fmt.Println(data)}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:LeetCode-155. Min Stack
下一篇:小程序可以在ipad上打开吗(ipad上怎么使用小程序)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~