Serializing Signature not compatible with other lib
filefilegoadmin opened this issue · comments
Hey,
I have a situation where I am using a javascript module (https://github.com/paulmillr/noble-curves) to sign data using secp256k1
.
The sig is sent to backend which is written in go and uses your lib to verify data but returns false without any error.
Seems like one of these 2 libs are wrong
I tried to compare the signature output of both libs, and they are different. both are in DER format
Can you provide signature output from both libraries? Use a random private key, message for that.
Sure,
Privkey hex: "0x47cbcbdb60923dcb2d401fc8ea5c5cdb95d50999337a7f4a324f7690db688265"
data, _ := hexutil.Decode("0x01")
with dcrd
:
0x3045022100891a5f7262c55b49eadcf354f01d7f9b7959ae6b04bf766ef94fba740399dfa20220687021ca4ca4283fa3aff6de1949345fd613458a8c6139e3a0137ad64bed31a6
with noble
:
0x304402201004b8c479934967c830750d3c22835c5adfcba9cb62247b39090b89ee236b86022032761afe89dc96e4239fb655b70e5c43c199518d6cad596cf214a182fd4dab61
the message being signed is to be cryptographically hashed to a 32-byte value. ecdsa.Sign takes this hash as a parameter.
What hash function are you using?
@filefilegoadmin yeah, outputs match with noble option {prehash: true}
. Default secp input is NOT hashed.
func TestSign3099(t *testing.T) {
privkeyBytes, err := hex.DecodeString("47cbcbdb60923dcb2d401fc8ea5c5cdb95d50999337a7f4a324f7690db688265")
if err != nil {
t.Fatal(err)
}
privkey := secp256k1.PrivKeyFromBytes(privkeyBytes)
message := []byte{01}
// bad bad bad
sig := Sign(privkey, message)
t.Logf("%x", sig.Serialize())
// better
messageHash := sha256.Sum256(message)
sig = Sign(privkey, messageHash[:])
t.Logf("%x", sig.Serialize())
}
$ go test -v -run TestSign3099
=== RUN TestSign3099
signature_test.go:1084: 304402201004b8c479934967c830750d3c22835c5adfcba9cb62247b39090b89ee236b86022032761afe89dc96e4239fb655b70e5c43c199518d6cad596cf214a182fd4dab61
signature_test.go:1089: 3045022100891a5f7262c55b49eadcf354f01d7f9b7959ae6b04bf766ef94fba740399dfa20220687021ca4ca4283fa3aff6de1949345fd613458a8c6139e3a0137ad64bed31a6
--- PASS: TestSign3099 (0.01s)
PASS
ok github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa 0.021s
I'm surprised we don't panic or error or something when the input is not a 32-byte value.
By rfc6979 it's not required for an input to be 32-byte value. Any hash function can be used, such as sha256/192 - which is not 32-byte. Setting some arbitrary length limit also doesn't make sense.
If you only target Bitcoin, then yes, it must always be 32-byte. Ethereum, for example, uses keccak256.
I'm surprised we don't panic or error or something when the input is not a 32-byte value.
There is nothing in the ecdsa
specification nor RFC6979 that requires the input to be a hash of a specific size nor for it to even be a hash at all. It is highly recommended to hash the data however.
That makes sense, thanks both.
Closing this since it does not appear to be an issue (with either lib).