简体   繁体   English

如何从R ||中的散列消息和签名正确恢复ECDSA公钥 S || V格式?

[英]How do I recover ECDSA public key correctly from hashed message and signature in R || S || V format?

I have used the following code to generate an ecdsa key-pair( privKey and pubKey ), encode them and then decode them back: https://stackoverflow.com/a/41315404/1901320 . 我使用以下代码生成ecdsa密钥对( privKeypubKey ),对它们进行编码然后将其解码回来: httpspubKey

Next I create a hash for a message ( txnData.Payload() is of type []byte ) using crypto.Keccak256() and sign it using crypto.Sign() from Ethereum's crypto package ( github.com/ethereum/go-ethereum/crypto ). 接下来,我创建哈希用于消息( txnData.Payload()的类型为[]byte )使用crypto.Keccak256()并使用签名crypto.Sign()从复仇的加密封装( github.com/ethereum/go-ethereum/crypto )。 This creates a 65 bit ECDSA signature in R || 这在R ||中创建了65位ECDSA签名 S || S || V format. V格式。

    hashData := crypto.Keccak256(txnData.Payload)
    sig, _ := crypto.Sign(hashData, privKey)

    pkey, _ := crypto.Ecrecover(hashData, sig) // This and pubKey do not match

When I try to get back the public key from the hashData and the ECDSA signature using crypto.Ecrecover() and compare it with the public key pubKey corresponding to the privKey used to create the signature, I find that the public keys do not match. 当我尝试使用crypto.Ecrecover()hashData和ECDSA签名中crypto.Ecrecover()并将其与用于创建签名的privKey对应的公钥pubKey进行比较时,我发现公钥不匹配。 This doesn't seem like something that should happen. 这似乎不应该发生。 Any idea as to where I am going wrong with this? 知道我在哪里出错吗?

Here's a complete working example of how to generate and verify signatures using go-ethereum. 这是一个完整的工作示例,说明如何使用go-ethereum生成和验证签名。

package main

import (
    "bytes"
    "crypto/ecdsa"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/common/hexutil"
    "github.com/ethereum/go-ethereum/crypto"
)

func main() {
    privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.PublicKey

    publicKeyBytes := crypto.FromECDSAPub(&publicKey)

    data := []byte("hello")
    hash := crypto.Keccak256Hash(data)
    fmt.Println(hash.Hex()) // 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8

    signature, err := crypto.Sign(hash.Bytes(), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(hexutil.Encode(signature)) // 0x789a80053e4927d0a898db8e065e948f5cf086e32f9ccaa54c1908e22ac430c62621578113ddbb62d509bf6049b8fb544ab06d36f916685a2eb8e57ffadde02301

    sigPublicKey, err := crypto.Ecrecover(hash.Bytes(), signature)
    if err != nil {
        log.Fatal(err)
    }

    matches := bytes.Equal(sigPublicKey, publicKeyBytes)
    fmt.Println(matches) // true

    sigPublicKeyECDSA, err := crypto.SigToPub(hash.Bytes(), signature)
    if err != nil {
        log.Fatal(err)
    }

    sigPublicKeyBytes := crypto.FromECDSAPub(sigPublicKeyECDSA)
    matches = bytes.Equal(sigPublicKeyBytes, publicKeyBytes)
    fmt.Println(matches) // true

    signatureNoRecoverID := signature[:len(signature)-1] // remove recovery id
    verified := crypto.VerifySignature(publicKeyBytes, hash.Bytes(), signatureNoRecoverID)
    fmt.Println(verified) // true
}

Check out the Ethereum Development with Go guide book for more examples on using go-ethereum. 有关使用go-ethereum的更多示例,请查看以太坊开发与Go指南。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM