Skip to content

Commit e7ed630

Browse files
committed
rpcserver: add BIP-322 verification and signing
1 parent 9af421b commit e7ed630

1 file changed

Lines changed: 37 additions & 40 deletions

File tree

rpcserver.go

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
3232
"github.com/btcsuite/btcd/btcjson"
3333
"github.com/btcsuite/btcd/btcutil"
34+
"github.com/btcsuite/btcd/btcutil/bip322"
3435
"github.com/btcsuite/btcd/btcutil/message"
3536
"github.com/btcsuite/btcd/chaincfg"
3637
"github.com/btcsuite/btcd/chaincfg/chainhash"
@@ -3590,7 +3591,24 @@ func handleSignMessageWithPrivKey(s *rpcServer, cmd interface{}, closeChan <-cha
35903591
}
35913592
}
35923593

3593-
3594+
// If an address was provided, use BIP-322 signing.
3595+
if c.Address != nil {
3596+
addr, err := btcutil.DecodeAddress(*c.Address, s.cfg.ChainParams)
3597+
if err != nil {
3598+
return nil, &btcjson.RPCError{
3599+
Code: btcjson.ErrRPCInvalidAddressOrKey,
3600+
Message: "Invalid address: " + err.Error(),
3601+
}
3602+
}
3603+
sig, err := bip322.Sign(wif.PrivKey, addr, c.Message)
3604+
if err != nil {
3605+
return nil, &btcjson.RPCError{
3606+
Code: btcjson.ErrRPCInvalidParameter,
3607+
Message: "BIP-322 signing failed: " + err.Error(),
3608+
}
3609+
}
3610+
return sig, nil
3611+
}
35943612

35953613
sig := ecdsa.SignCompact(wif.PrivKey, message.Hash(c.Message), wif.CompressPubKey)
35963614
return base64.StdEncoding.EncodeToString(sig), nil
@@ -3756,53 +3774,32 @@ func handleVerifyMessage(s *rpcServer, cmd interface{}, closeChan <-chan struct{
37563774
}
37573775
}
37583776

3759-
// Only P2PKH addresses are valid for signing.
3760-
if _, ok := addr.(*btcutil.AddressPubKeyHash); !ok {
3761-
return nil, &btcjson.RPCError{
3762-
Code: btcjson.ErrRPCType,
3763-
Message: "Address is not a pay-to-pubkey-hash address",
3764-
}
3777+
// Try legacy (BIP-137) verification first.
3778+
valid, err := message.Verify(addr, c.Message, c.Signature)
3779+
if err == nil {
3780+
return valid, nil
37653781
}
37663782

3767-
// Decode base64 signature.
3768-
sig, err := base64.StdEncoding.DecodeString(c.Signature)
3783+
// Try BIP-322 verification.
3784+
valid, err = bip322.Verify(addr, c.Message, c.Signature)
37693785
if err != nil {
3770-
return nil, &btcjson.RPCError{
3771-
Code: btcjson.ErrRPCParse.Code,
3772-
Message: "Malformed base64 encoding: " + err.Error(),
3786+
switch {
3787+
case errors.Is(err, bip322.ErrInconclusive):
3788+
return nil, &btcjson.RPCError{
3789+
Code: btcjson.ErrRPCInvalidAddressOrKey,
3790+
Message: "Invalid signature: " + err.Error(),
3791+
}
3792+
case errors.Is(err, bip322.ErrMalformedSignature):
3793+
return nil, &btcjson.RPCError{
3794+
Code: btcjson.ErrRPCParse.Code,
3795+
Message: "Malformed base64 encoding: " + err.Error(),
3796+
}
37733797
}
3774-
}
37753798

3776-
// Validate the signature - this just shows that it was valid at all.
3777-
// we will compare it with the key next.
3778-
var buf bytes.Buffer
3779-
wire.WriteVarString(&buf, 0, messageSignatureHeader)
3780-
wire.WriteVarString(&buf, 0, c.Message)
3781-
expectedMessageHash := chainhash.DoubleHashB(buf.Bytes())
3782-
pk, wasCompressed, err := ecdsa.RecoverCompact(sig,
3783-
expectedMessageHash)
3784-
if err != nil {
3785-
// Mirror Bitcoin Core behavior, which treats error in
3786-
// RecoverCompact as invalid signature.
3787-
return false, nil
3788-
}
3789-
3790-
// Reconstruct the pubkey hash.
3791-
var serializedPK []byte
3792-
if wasCompressed {
3793-
serializedPK = pk.SerializeCompressed()
3794-
} else {
3795-
serializedPK = pk.SerializeUncompressed()
3796-
}
3797-
address, err := btcutil.NewAddressPubKey(serializedPK, params)
3798-
if err != nil {
3799-
// Again mirror Bitcoin Core behavior, which treats error in public key
3800-
// reconstruction as invalid signature.
38013799
return false, nil
38023800
}
38033801

3804-
// Return boolean if addresses match.
3805-
return address.EncodeAddress() == c.Address, nil
3802+
return valid, nil
38063803
}
38073804

38083805
// handleVersion implements the version command.

0 commit comments

Comments
 (0)