package rpc import ( "bytes" "encoding/base64" "github.com/daglabs/btcd/btcec" "github.com/daglabs/btcd/btcjson" "github.com/daglabs/btcd/util" "github.com/daglabs/btcd/util/daghash" "github.com/daglabs/btcd/wire" ) // handleVerifyMessage implements the verifyMessage command. func handleVerifyMessage(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.VerifyMessageCmd) // Decode the provided address. params := s.cfg.DAGParams addr, err := util.DecodeAddress(c.Address, params.Prefix) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInvalidAddressOrKey, Message: "Invalid address or key: " + err.Error(), } } // Only P2PKH addresses are valid for signing. if _, ok := addr.(*util.AddressPubKeyHash); !ok { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCType, Message: "Address is not a pay-to-pubkey-hash address", } } // Decode base64 signature. sig, err := base64.StdEncoding.DecodeString(c.Signature) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCParse.Code, Message: "Malformed base64 encoding: " + err.Error(), } } // Validate the signature - this just shows that it was valid at all. // we will compare it with the key next. var buf bytes.Buffer wire.WriteVarString(&buf, "Bitcoin Signed Message:\n") wire.WriteVarString(&buf, c.Message) expectedMessageHash := daghash.DoubleHashB(buf.Bytes()) pk, wasCompressed, err := btcec.RecoverCompact(btcec.S256(), sig, expectedMessageHash) if err != nil { // Mirror Bitcoin Core behavior, which treats error in // RecoverCompact as invalid signature. return false, nil } // Reconstruct the pubkey hash. var serializedPK []byte if wasCompressed { serializedPK = pk.SerializeCompressed() } else { serializedPK = pk.SerializeUncompressed() } address, err := util.NewAddressPubKeyHashFromPublicKey(serializedPK, params.Prefix) if err != nil { // Again mirror Bitcoin Core behavior, which treats error in public key // reconstruction as invalid signature. return false, nil } // Return boolean if addresses match. return address.EncodeAddress() == c.Address, nil }