decred / dcrd

Decred daemon in Go (golang).

Home Page:https://decred.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

Ref:
paulmillr/noble-curves#30

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).