Implement signmessagewithprivkey JSON-RPC command
Reuse the Bitcoin message signature header const also in verifymessage.
This commit is contained in:
parent
b68c50e33c
commit
d2c0123bef
4 changed files with 180 additions and 93 deletions
|
@ -806,6 +806,24 @@ func NewSetGenerateCmd(generate bool, genProcLimit *int) *SetGenerateCmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignMessageWithPrivKeyCmd defines the signmessagewithprivkey JSON-RPC command.
|
||||||
|
type SignMessageWithPrivKeyCmd struct {
|
||||||
|
PrivKey string // base 58 Wallet Import format private key
|
||||||
|
Message string // Message to sign
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSignMessageWithPrivKey returns a new instance which can be used to issue a
|
||||||
|
// signmessagewithprivkey JSON-RPC command.
|
||||||
|
//
|
||||||
|
// The first parameter is a private key in base 58 Wallet Import format.
|
||||||
|
// The second parameter is the message to sign.
|
||||||
|
func NewSignMessageWithPrivKey(privKey, message string) *SignMessageWithPrivKeyCmd {
|
||||||
|
return &SignMessageWithPrivKeyCmd{
|
||||||
|
PrivKey: privKey,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StopCmd defines the stop JSON-RPC command.
|
// StopCmd defines the stop JSON-RPC command.
|
||||||
type StopCmd struct{}
|
type StopCmd struct{}
|
||||||
|
|
||||||
|
@ -971,6 +989,7 @@ func init() {
|
||||||
MustRegisterCmd("searchrawtransactions", (*SearchRawTransactionsCmd)(nil), flags)
|
MustRegisterCmd("searchrawtransactions", (*SearchRawTransactionsCmd)(nil), flags)
|
||||||
MustRegisterCmd("sendrawtransaction", (*SendRawTransactionCmd)(nil), flags)
|
MustRegisterCmd("sendrawtransaction", (*SendRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("setgenerate", (*SetGenerateCmd)(nil), flags)
|
MustRegisterCmd("setgenerate", (*SetGenerateCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("signmessagewithprivkey", (*SignMessageWithPrivKeyCmd)(nil), flags)
|
||||||
MustRegisterCmd("stop", (*StopCmd)(nil), flags)
|
MustRegisterCmd("stop", (*StopCmd)(nil), flags)
|
||||||
MustRegisterCmd("submitblock", (*SubmitBlockCmd)(nil), flags)
|
MustRegisterCmd("submitblock", (*SubmitBlockCmd)(nil), flags)
|
||||||
MustRegisterCmd("uptime", (*UptimeCmd)(nil), flags)
|
MustRegisterCmd("uptime", (*UptimeCmd)(nil), flags)
|
||||||
|
|
|
@ -1186,6 +1186,20 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
GenProcLimit: btcjson.Int(6),
|
GenProcLimit: btcjson.Int(6),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "signmessagewithprivkey",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("signmessagewithprivkey", "5Hue", "Hey")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewSignMessageWithPrivKey("5Hue", "Hey")
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"signmessagewithprivkey","params":["5Hue","Hey"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.SignMessageWithPrivKeyCmd{
|
||||||
|
PrivKey: "5Hue",
|
||||||
|
Message: "Hey",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "stop",
|
name: "stop",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
|
49
rpcserver.go
49
rpcserver.go
|
@ -166,6 +166,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
||||||
"searchrawtransactions": handleSearchRawTransactions,
|
"searchrawtransactions": handleSearchRawTransactions,
|
||||||
"sendrawtransaction": handleSendRawTransaction,
|
"sendrawtransaction": handleSendRawTransaction,
|
||||||
"setgenerate": handleSetGenerate,
|
"setgenerate": handleSetGenerate,
|
||||||
|
"signmessagewithprivkey": handleSignMessageWithPrivKey,
|
||||||
"stop": handleStop,
|
"stop": handleStop,
|
||||||
"submitblock": handleSubmitBlock,
|
"submitblock": handleSubmitBlock,
|
||||||
"uptime": handleUptime,
|
"uptime": handleUptime,
|
||||||
|
@ -3435,6 +3436,52 @@ func handleSetGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text used to signify that a signed message follows and to prevent
|
||||||
|
// inadvertently signing a transaction.
|
||||||
|
const messageSignatureHeader = "Bitcoin Signed Message:\n"
|
||||||
|
|
||||||
|
// handleSignMessageWithPrivKey implements the signmessagewithprivkey command.
|
||||||
|
func handleSignMessageWithPrivKey(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||||
|
c := cmd.(*btcjson.SignMessageWithPrivKeyCmd)
|
||||||
|
|
||||||
|
wif, err := btcutil.DecodeWIF(c.PrivKey)
|
||||||
|
if err != nil {
|
||||||
|
message := "Invalid private key"
|
||||||
|
switch err {
|
||||||
|
case btcutil.ErrMalformedPrivateKey:
|
||||||
|
message = "Malformed private key"
|
||||||
|
case btcutil.ErrChecksumMismatch:
|
||||||
|
message = "Private key checksum mismatch"
|
||||||
|
}
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !wif.IsForNet(s.cfg.ChainParams) {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||||
|
Message: "Private key for wrong network",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
wire.WriteVarString(&buf, 0, messageSignatureHeader)
|
||||||
|
wire.WriteVarString(&buf, 0, c.Message)
|
||||||
|
messageHash := chainhash.DoubleHashB(buf.Bytes())
|
||||||
|
|
||||||
|
sig, err := btcec.SignCompact(btcec.S256(), wif.PrivKey,
|
||||||
|
messageHash, wif.CompressPubKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &btcjson.RPCError{
|
||||||
|
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||||
|
Message: "Sign failed",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(sig), nil
|
||||||
|
}
|
||||||
|
|
||||||
// handleStop implements the stop command.
|
// handleStop implements the stop command.
|
||||||
func handleStop(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
func handleStop(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||||
select {
|
select {
|
||||||
|
@ -3615,7 +3662,7 @@ func handleVerifyMessage(s *rpcServer, cmd interface{}, closeChan <-chan struct{
|
||||||
// Validate the signature - this just shows that it was valid at all.
|
// Validate the signature - this just shows that it was valid at all.
|
||||||
// we will compare it with the key next.
|
// we will compare it with the key next.
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
wire.WriteVarString(&buf, 0, "Bitcoin Signed Message:\n")
|
wire.WriteVarString(&buf, 0, messageSignatureHeader)
|
||||||
wire.WriteVarString(&buf, 0, c.Message)
|
wire.WriteVarString(&buf, 0, c.Message)
|
||||||
expectedMessageHash := chainhash.DoubleHashB(buf.Bytes())
|
expectedMessageHash := chainhash.DoubleHashB(buf.Bytes())
|
||||||
pk, wasCompressed, err := btcec.RecoverCompact(btcec.S256(), sig,
|
pk, wasCompressed, err := btcec.RecoverCompact(btcec.S256(), sig,
|
||||||
|
|
|
@ -559,6 +559,12 @@ var helpDescsEnUS = map[string]string{
|
||||||
"setgenerate-generate": "Use true to enable generation, false to disable it",
|
"setgenerate-generate": "Use true to enable generation, false to disable it",
|
||||||
"setgenerate-genproclimit": "The number of processors (cores) to limit generation to or -1 for default",
|
"setgenerate-genproclimit": "The number of processors (cores) to limit generation to or -1 for default",
|
||||||
|
|
||||||
|
// SignMessageWithPrivKeyCmd help.
|
||||||
|
"signmessagewithprivkey--synopsis": "Sign a message with the private key of an address",
|
||||||
|
"signmessagewithprivkey-privkey": "The private key to sign the message with",
|
||||||
|
"signmessagewithprivkey-message": "The message to create a signature of",
|
||||||
|
"signmessagewithprivkey--result0": "The signature of the message encoded in base 64",
|
||||||
|
|
||||||
// StopCmd help.
|
// StopCmd help.
|
||||||
"stop--synopsis": "Shutdown btcd.",
|
"stop--synopsis": "Shutdown btcd.",
|
||||||
"stop--result0": "The string 'btcd stopping.'",
|
"stop--result0": "The string 'btcd stopping.'",
|
||||||
|
@ -730,6 +736,7 @@ var rpcResultTypes = map[string][]interface{}{
|
||||||
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
||||||
"sendrawtransaction": {(*string)(nil)},
|
"sendrawtransaction": {(*string)(nil)},
|
||||||
"setgenerate": nil,
|
"setgenerate": nil,
|
||||||
|
"signmessagewithprivkey": {(*string)(nil)},
|
||||||
"stop": {(*string)(nil)},
|
"stop": {(*string)(nil)},
|
||||||
"submitblock": {nil, (*string)(nil)},
|
"submitblock": {nil, (*string)(nil)},
|
||||||
"uptime": {(*int64)(nil)},
|
"uptime": {(*int64)(nil)},
|
||||||
|
|
Loading…
Add table
Reference in a new issue