Skip to content

Commit

Permalink
Implement verifymessage RPC.
Browse files Browse the repository at this point in the history
  • Loading branch information
ortutay committed Aug 22, 2014
1 parent 6793bb2 commit 139d9cb
Showing 1 changed file with 63 additions and 1 deletion.
64 changes: 63 additions & 1 deletion rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/conformal/btcchain"
"github.com/conformal/btcdb"
"github.com/conformal/btcec"
"github.com/conformal/btcjson"
"github.com/conformal/btcnet"
"github.com/conformal/btcscript"
Expand Down Expand Up @@ -155,6 +156,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"submitblock": handleSubmitBlock,
"validateaddress": handleValidateAddress,
"verifychain": handleVerifyChain,
"verifymessage": handleVerifyMessage,
}

// list of commands that we recognise, but for which btcd has no support because
Expand Down Expand Up @@ -200,7 +202,6 @@ var rpcAskWallet = map[string]struct{}{
"settxfee": struct{}{},
"signmessage": struct{}{},
"signrawtransaction": struct{}{},
"verifymessage": struct{}{},
"walletlock": struct{}{},
"walletpassphrase": struct{}{},
"walletpassphrasechange": struct{}{},
Expand Down Expand Up @@ -3143,6 +3144,67 @@ func handleVerifyChain(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{})
return err == nil, nil
}

// handleVerifyMessage implements the verifymessage command.
func handleVerifyMessage(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*btcjson.VerifyMessageCmd)

// Decode the provided address.
addr, err := btcutil.DecodeAddress(c.Address, activeNetParams.Params)
if err != nil {
return nil, btcjson.Error{
Code: btcjson.ErrInvalidAddressOrKey.Code,
Message: fmt.Sprintf("%s: %v",
btcjson.ErrInvalidAddressOrKey.Message, err),
}
}

// Only P2PKH addresses are valid for signing.
if _, ok := addr.(*btcutil.AddressPubKeyHash); !ok {
return nil, btcjson.Error{
Code: btcjson.ErrType.Code,
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.Error{
Code: btcjson.ErrParse.Code,
Message: fmt.Sprintf("Malformed base64 encoding: %v", err),
}
}

// Validate the signature - this just shows that it was valid at all.
// we will compare it with the key next.
pk, wasCompressed, err := btcec.RecoverCompact(btcec.S256(), sig,
btcwire.DoubleSha256([]byte("Bitcoin Signed Message:\n"+c.Message)))
if err != nil {
// Mirror Bitcoin Core behavior, which treats error in RecoverCompact as
// invalid signature.
return false, nil
}

// Reconstruct the pubkey hash.
btcPK := (*btcec.PublicKey)(pk)
var serializedPK []byte
if wasCompressed {
serializedPK = btcPK.SerializeCompressed()
} else {
serializedPK = btcPK.SerializeUncompressed()
}
address, err := btcutil.NewAddressPubKey(serializedPK,
activeNetParams.Params)
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
}

// parseCmd parses a marshaled known command, returning any errors as a
// btcjson.Error that can be used in replies. The returned cmd may still
// be non-nil if b is at least a valid marshaled JSON-RPC message.
Expand Down

0 comments on commit 139d9cb

Please sign in to comment.