Merge pull request #3812 from guggero/sign-custom

signrpc: sign and verify messages with custom key
This commit is contained in:
Olaoluwa Osuntokun 2019-12-11 18:51:55 -08:00 committed by GitHub
commit 338175534e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 495 additions and 50 deletions

@ -4,6 +4,7 @@ package signrpc
import (
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/macaroons"
)
@ -30,4 +31,8 @@ type Config struct {
// job of the signer RPC server is simply to proxy valid requests to
// the active signer instance.
Signer input.Signer
// KeyRing is an interface that the signer will use to derive any keys
// for signing messages.
KeyRing keychain.SecretKeyRing
}

@ -472,6 +472,194 @@ func (m *InputScriptResp) GetInputScripts() []*InputScript {
return nil
}
type SignMessageReq struct {
/// The message to be signed.
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
/// The key locator that identifies which key to use for signing.
KeyLoc *KeyLocator `protobuf:"bytes,2,opt,name=key_loc,json=keyLoc,proto3" json:"key_loc,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SignMessageReq) Reset() { *m = SignMessageReq{} }
func (m *SignMessageReq) String() string { return proto.CompactTextString(m) }
func (*SignMessageReq) ProtoMessage() {}
func (*SignMessageReq) Descriptor() ([]byte, []int) {
return fileDescriptor_4ecd772f6c7ffacf, []int{8}
}
func (m *SignMessageReq) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SignMessageReq.Unmarshal(m, b)
}
func (m *SignMessageReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SignMessageReq.Marshal(b, m, deterministic)
}
func (m *SignMessageReq) XXX_Merge(src proto.Message) {
xxx_messageInfo_SignMessageReq.Merge(m, src)
}
func (m *SignMessageReq) XXX_Size() int {
return xxx_messageInfo_SignMessageReq.Size(m)
}
func (m *SignMessageReq) XXX_DiscardUnknown() {
xxx_messageInfo_SignMessageReq.DiscardUnknown(m)
}
var xxx_messageInfo_SignMessageReq proto.InternalMessageInfo
func (m *SignMessageReq) GetMsg() []byte {
if m != nil {
return m.Msg
}
return nil
}
func (m *SignMessageReq) GetKeyLoc() *KeyLocator {
if m != nil {
return m.KeyLoc
}
return nil
}
type SignMessageResp struct {
//*
//The signature for the given message in the DER format.
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SignMessageResp) Reset() { *m = SignMessageResp{} }
func (m *SignMessageResp) String() string { return proto.CompactTextString(m) }
func (*SignMessageResp) ProtoMessage() {}
func (*SignMessageResp) Descriptor() ([]byte, []int) {
return fileDescriptor_4ecd772f6c7ffacf, []int{9}
}
func (m *SignMessageResp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SignMessageResp.Unmarshal(m, b)
}
func (m *SignMessageResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SignMessageResp.Marshal(b, m, deterministic)
}
func (m *SignMessageResp) XXX_Merge(src proto.Message) {
xxx_messageInfo_SignMessageResp.Merge(m, src)
}
func (m *SignMessageResp) XXX_Size() int {
return xxx_messageInfo_SignMessageResp.Size(m)
}
func (m *SignMessageResp) XXX_DiscardUnknown() {
xxx_messageInfo_SignMessageResp.DiscardUnknown(m)
}
var xxx_messageInfo_SignMessageResp proto.InternalMessageInfo
func (m *SignMessageResp) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
type VerifyMessageReq struct {
/// The message over which the signature is to be verified.
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
/// The DER encoded signature to be verified over the given message.
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
/// The public key the signature has to be valid for.
Pubkey []byte `protobuf:"bytes,3,opt,name=pubkey,proto3" json:"pubkey,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *VerifyMessageReq) Reset() { *m = VerifyMessageReq{} }
func (m *VerifyMessageReq) String() string { return proto.CompactTextString(m) }
func (*VerifyMessageReq) ProtoMessage() {}
func (*VerifyMessageReq) Descriptor() ([]byte, []int) {
return fileDescriptor_4ecd772f6c7ffacf, []int{10}
}
func (m *VerifyMessageReq) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VerifyMessageReq.Unmarshal(m, b)
}
func (m *VerifyMessageReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_VerifyMessageReq.Marshal(b, m, deterministic)
}
func (m *VerifyMessageReq) XXX_Merge(src proto.Message) {
xxx_messageInfo_VerifyMessageReq.Merge(m, src)
}
func (m *VerifyMessageReq) XXX_Size() int {
return xxx_messageInfo_VerifyMessageReq.Size(m)
}
func (m *VerifyMessageReq) XXX_DiscardUnknown() {
xxx_messageInfo_VerifyMessageReq.DiscardUnknown(m)
}
var xxx_messageInfo_VerifyMessageReq proto.InternalMessageInfo
func (m *VerifyMessageReq) GetMsg() []byte {
if m != nil {
return m.Msg
}
return nil
}
func (m *VerifyMessageReq) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *VerifyMessageReq) GetPubkey() []byte {
if m != nil {
return m.Pubkey
}
return nil
}
type VerifyMessageResp struct {
/// Whether the signature was valid over the given message.
Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *VerifyMessageResp) Reset() { *m = VerifyMessageResp{} }
func (m *VerifyMessageResp) String() string { return proto.CompactTextString(m) }
func (*VerifyMessageResp) ProtoMessage() {}
func (*VerifyMessageResp) Descriptor() ([]byte, []int) {
return fileDescriptor_4ecd772f6c7ffacf, []int{11}
}
func (m *VerifyMessageResp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VerifyMessageResp.Unmarshal(m, b)
}
func (m *VerifyMessageResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_VerifyMessageResp.Marshal(b, m, deterministic)
}
func (m *VerifyMessageResp) XXX_Merge(src proto.Message) {
xxx_messageInfo_VerifyMessageResp.Merge(m, src)
}
func (m *VerifyMessageResp) XXX_Size() int {
return xxx_messageInfo_VerifyMessageResp.Size(m)
}
func (m *VerifyMessageResp) XXX_DiscardUnknown() {
xxx_messageInfo_VerifyMessageResp.DiscardUnknown(m)
}
var xxx_messageInfo_VerifyMessageResp proto.InternalMessageInfo
func (m *VerifyMessageResp) GetValid() bool {
if m != nil {
return m.Valid
}
return false
}
func init() {
proto.RegisterType((*KeyLocator)(nil), "signrpc.KeyLocator")
proto.RegisterType((*KeyDescriptor)(nil), "signrpc.KeyDescriptor")
@ -481,48 +669,59 @@ func init() {
proto.RegisterType((*SignResp)(nil), "signrpc.SignResp")
proto.RegisterType((*InputScript)(nil), "signrpc.InputScript")
proto.RegisterType((*InputScriptResp)(nil), "signrpc.InputScriptResp")
proto.RegisterType((*SignMessageReq)(nil), "signrpc.SignMessageReq")
proto.RegisterType((*SignMessageResp)(nil), "signrpc.SignMessageResp")
proto.RegisterType((*VerifyMessageReq)(nil), "signrpc.VerifyMessageReq")
proto.RegisterType((*VerifyMessageResp)(nil), "signrpc.VerifyMessageResp")
}
func init() { proto.RegisterFile("signrpc/signer.proto", fileDescriptor_4ecd772f6c7ffacf) }
var fileDescriptor_4ecd772f6c7ffacf = []byte{
// 562 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x53, 0x4f, 0x8f, 0xd3, 0x3e,
0x10, 0x55, 0xb7, 0xbf, 0x36, 0xdd, 0x49, 0xd2, 0x1f, 0x98, 0x0a, 0x02, 0x08, 0x51, 0x22, 0x2d,
0xea, 0x01, 0x5a, 0x51, 0x10, 0x12, 0x9c, 0xd0, 0x82, 0x56, 0xac, 0xba, 0xd2, 0x4a, 0x6e, 0x4f,
0x5c, 0xa2, 0x34, 0x35, 0xa9, 0x95, 0x34, 0xf1, 0xc6, 0x0e, 0x69, 0x6e, 0x7c, 0x07, 0xbe, 0x30,
0x1a, 0x3b, 0xfd, 0x07, 0x9c, 0x9a, 0xf7, 0x3c, 0x33, 0xef, 0x79, 0x5e, 0x0d, 0x03, 0xc9, 0xe3,
0xac, 0x10, 0xd1, 0x04, 0x7f, 0x59, 0x31, 0x16, 0x45, 0xae, 0x72, 0x62, 0x35, 0xac, 0xff, 0x15,
0x60, 0xc6, 0xea, 0x9b, 0x3c, 0x0a, 0x55, 0x5e, 0x90, 0x67, 0x00, 0x09, 0xab, 0x83, 0xef, 0xe1,
0x86, 0xa7, 0xb5, 0xd7, 0x1a, 0xb6, 0x46, 0x1d, 0x7a, 0x9e, 0xb0, 0xfa, 0x4a, 0x13, 0xe4, 0x29,
0x20, 0x08, 0x78, 0xb6, 0x62, 0x5b, 0xef, 0x4c, 0x9f, 0xf6, 0x12, 0x56, 0x5f, 0x23, 0xf6, 0x43,
0x70, 0x67, 0xac, 0xfe, 0xc2, 0x64, 0x54, 0x70, 0x81, 0xc3, 0x7c, 0x70, 0x8b, 0xb0, 0x0a, 0xb0,
0x63, 0x59, 0x2b, 0x26, 0xf5, 0x3c, 0x87, 0xda, 0x45, 0x58, 0xcd, 0x58, 0x7d, 0x89, 0x14, 0x79,
0x05, 0x16, 0x9e, 0xa7, 0x79, 0xa4, 0xe7, 0xd9, 0xd3, 0x07, 0xe3, 0xc6, 0xd9, 0xf8, 0x60, 0x8b,
0x76, 0x13, 0xfd, 0xed, 0x7f, 0x84, 0xce, 0x62, 0x7b, 0x5b, 0x2a, 0x32, 0x80, 0xce, 0x8f, 0x30,
0x2d, 0x99, 0x1e, 0xd9, 0xa6, 0x06, 0xa0, 0x3d, 0x91, 0x04, 0x46, 0x5f, 0x8f, 0x73, 0x68, 0x4f,
0x24, 0x73, 0x8d, 0xfd, 0x5f, 0x67, 0xd0, 0x9f, 0xf3, 0x38, 0x3b, 0x32, 0xf8, 0x06, 0xd0, 0x7d,
0xb0, 0x62, 0x32, 0xd2, 0x83, 0xec, 0xe9, 0xc3, 0x63, 0xf5, 0x43, 0x25, 0x45, 0x93, 0x08, 0xc9,
0x0b, 0x70, 0x24, 0xcf, 0xe2, 0x94, 0x05, 0xaa, 0x62, 0x61, 0xd2, 0xa8, 0xd8, 0x86, 0x5b, 0x20,
0x85, 0x25, 0xab, 0xbc, 0x5c, 0xee, 0x4b, 0xda, 0xa6, 0xc4, 0x70, 0xa6, 0xe4, 0x02, 0xfa, 0x15,
0x57, 0x19, 0x93, 0x72, 0xe7, 0xf6, 0x3f, 0x5d, 0xe4, 0x36, 0xac, 0xb1, 0x4c, 0x5e, 0x42, 0x37,
0x2f, 0x95, 0x28, 0x95, 0xd7, 0xd1, 0xee, 0xfa, 0x7b, 0x77, 0x7a, 0x0b, 0xb4, 0x39, 0x25, 0x1e,
0x60, 0x9c, 0xeb, 0x50, 0xae, 0x3d, 0x6b, 0xd8, 0x1a, 0xb9, 0x74, 0x07, 0xc9, 0x73, 0xb0, 0x79,
0x26, 0x4a, 0xd5, 0x44, 0xd6, 0xd3, 0x91, 0x81, 0xa6, 0x4c, 0x68, 0x11, 0x58, 0xb8, 0x14, 0xca,
0xee, 0xc8, 0x10, 0x1c, 0x8c, 0x4b, 0x6d, 0x4f, 0xd2, 0x82, 0x22, 0xac, 0x16, 0x5b, 0x13, 0xd6,
0x7b, 0x00, 0x34, 0xa0, 0x17, 0x26, 0xbd, 0xb3, 0x61, 0x7b, 0x64, 0x4f, 0x1f, 0xed, 0x3d, 0x9d,
0x2e, 0x97, 0x9e, 0xcb, 0x06, 0x4b, 0xff, 0x02, 0x7a, 0x46, 0x44, 0x0a, 0xf2, 0x18, 0x7a, 0xa8,
0x22, 0x79, 0x8c, 0x0a, 0xed, 0x91, 0x43, 0xad, 0x22, 0xac, 0xe6, 0x3c, 0x96, 0xfe, 0x15, 0xd8,
0xd7, 0xe8, 0xac, 0xb9, 0xbd, 0x07, 0x56, 0xb3, 0x8e, 0x5d, 0x61, 0x03, 0xf1, 0x5f, 0x2a, 0x79,
0x7c, 0x1a, 0x34, 0xca, 0x35, 0x49, 0xdf, 0xc0, 0xff, 0x47, 0x73, 0xb4, 0xea, 0x07, 0x70, 0xcd,
0x1e, 0x4c, 0x8f, 0x99, 0x68, 0x4f, 0x07, 0x7b, 0xf3, 0xc7, 0x0d, 0x0e, 0x3f, 0x00, 0x39, 0xfd,
0xd9, 0x82, 0xee, 0x5c, 0x3f, 0x1d, 0xf2, 0x0e, 0x5c, 0xfc, 0xba, 0xd5, 0x5b, 0xa7, 0x61, 0x45,
0xee, 0x9d, 0x5c, 0x9e, 0xb2, 0xbb, 0x27, 0xf7, 0xff, 0x60, 0xa4, 0x20, 0x9f, 0x80, 0x7c, 0xce,
0x37, 0xa2, 0x54, 0xec, 0xf8, 0x76, 0x7f, 0xb7, 0x7a, 0xff, 0x34, 0xc3, 0xa4, 0xb8, 0x9c, 0x7c,
0x7b, 0x1d, 0x73, 0xb5, 0x2e, 0x97, 0xe3, 0x28, 0xdf, 0x4c, 0x52, 0x1e, 0xaf, 0x55, 0xc6, 0xb3,
0x38, 0x63, 0xaa, 0xca, 0x8b, 0x64, 0x92, 0x66, 0xab, 0x49, 0xba, 0x7f, 0xe2, 0x85, 0x88, 0x96,
0x5d, 0xfd, 0xc8, 0xdf, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x80, 0x01, 0xce, 0xe1, 0xfc, 0x03,
0x00, 0x00,
// 676 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcb, 0x6e, 0xd3, 0x40,
0x14, 0x55, 0x13, 0xf2, 0xe8, 0x75, 0xdc, 0xc7, 0x50, 0x15, 0xb7, 0x80, 0x08, 0x96, 0x8a, 0x82,
0x04, 0x89, 0x08, 0x08, 0x09, 0x56, 0xa8, 0xa0, 0x8a, 0xaa, 0x45, 0x45, 0x93, 0x8a, 0x45, 0x37,
0x91, 0xe3, 0x4c, 0x9d, 0x91, 0x1d, 0x7b, 0xea, 0x19, 0xe3, 0xf8, 0x17, 0xd8, 0xf2, 0xc3, 0x68,
0x1e, 0x49, 0xec, 0xf0, 0x90, 0x58, 0xc5, 0xe7, 0xce, 0x9d, 0x73, 0x8f, 0xcf, 0xb9, 0x31, 0x1c,
0x70, 0x1a, 0xc4, 0x29, 0xf3, 0x07, 0xf2, 0x97, 0xa4, 0x7d, 0x96, 0x26, 0x22, 0x41, 0x2d, 0x53,
0x75, 0x3f, 0x03, 0x5c, 0x90, 0xe2, 0x32, 0xf1, 0x3d, 0x91, 0xa4, 0xe8, 0x31, 0x40, 0x48, 0x8a,
0xf1, 0xad, 0x37, 0xa7, 0x51, 0xe1, 0x6c, 0x75, 0xb7, 0x7a, 0x0d, 0xbc, 0x1d, 0x92, 0xe2, 0x4c,
0x15, 0xd0, 0x43, 0x90, 0x60, 0x4c, 0xe3, 0x29, 0x59, 0x38, 0x35, 0x75, 0xda, 0x0e, 0x49, 0x71,
0x2e, 0xb1, 0xeb, 0x81, 0x7d, 0x41, 0x8a, 0x4f, 0x84, 0xfb, 0x29, 0x65, 0x92, 0xcc, 0x05, 0x3b,
0xf5, 0xf2, 0xb1, 0xbc, 0x31, 0x29, 0x04, 0xe1, 0x8a, 0xaf, 0x83, 0xad, 0xd4, 0xcb, 0x2f, 0x48,
0x71, 0x2a, 0x4b, 0xe8, 0x05, 0xb4, 0xe4, 0x79, 0x94, 0xf8, 0x8a, 0xcf, 0x1a, 0xde, 0xef, 0x1b,
0x65, 0xfd, 0xb5, 0x2c, 0xdc, 0x0c, 0xd5, 0xb3, 0xfb, 0x1e, 0x1a, 0xd7, 0x8b, 0xab, 0x4c, 0xa0,
0x03, 0x68, 0x7c, 0xf7, 0xa2, 0x8c, 0x28, 0xca, 0x3a, 0xd6, 0x40, 0xca, 0x63, 0xe1, 0x58, 0xcf,
0x57, 0x74, 0x1d, 0xdc, 0x66, 0xe1, 0x48, 0x61, 0xf7, 0x67, 0x0d, 0x76, 0x46, 0x34, 0x88, 0x4b,
0x02, 0x5f, 0x81, 0x54, 0x3f, 0x9e, 0x12, 0xee, 0x2b, 0x22, 0x6b, 0x78, 0x58, 0x9e, 0xbe, 0xee,
0xc4, 0x52, 0xa4, 0x84, 0xe8, 0x29, 0x74, 0x38, 0x8d, 0x83, 0x88, 0x8c, 0x45, 0x4e, 0xbc, 0xd0,
0x4c, 0xb1, 0x74, 0xed, 0x5a, 0x96, 0x64, 0xcb, 0x34, 0xc9, 0x26, 0xab, 0x96, 0xba, 0x6e, 0xd1,
0x35, 0xdd, 0x72, 0x02, 0x3b, 0x39, 0x15, 0x31, 0xe1, 0x7c, 0xa9, 0xf6, 0x9e, 0x6a, 0xb2, 0x4d,
0x55, 0x4b, 0x46, 0xcf, 0xa0, 0x99, 0x64, 0x82, 0x65, 0xc2, 0x69, 0x28, 0x75, 0x3b, 0x2b, 0x75,
0xca, 0x05, 0x6c, 0x4e, 0x91, 0x03, 0x32, 0xce, 0x99, 0xc7, 0x67, 0x4e, 0xab, 0xbb, 0xd5, 0xb3,
0xf1, 0x12, 0xa2, 0x27, 0x60, 0xd1, 0x98, 0x65, 0xc2, 0x44, 0xd6, 0x56, 0x91, 0x81, 0x2a, 0xe9,
0xd0, 0x7c, 0x68, 0x49, 0x53, 0x30, 0xb9, 0x43, 0x5d, 0xe8, 0xc8, 0xb8, 0xc4, 0xa2, 0x92, 0x16,
0xa4, 0x5e, 0x7e, 0xbd, 0xd0, 0x61, 0xbd, 0x05, 0x90, 0x02, 0x94, 0x61, 0xdc, 0xa9, 0x75, 0xeb,
0x3d, 0x6b, 0xf8, 0x60, 0xa5, 0xa9, 0x6a, 0x2e, 0xde, 0xe6, 0x06, 0x73, 0xf7, 0x04, 0xda, 0x7a,
0x08, 0x67, 0xe8, 0x08, 0xda, 0x72, 0x0a, 0xa7, 0x81, 0x9c, 0x50, 0xef, 0x75, 0x70, 0x2b, 0xf5,
0xf2, 0x11, 0x0d, 0xb8, 0x7b, 0x06, 0xd6, 0xb9, 0x54, 0x66, 0xde, 0xde, 0x81, 0x96, 0xb1, 0x63,
0xd9, 0x68, 0xa0, 0xdc, 0x52, 0x4e, 0x83, 0x6a, 0xd0, 0x72, 0x9c, 0x49, 0xfa, 0x12, 0x76, 0x4b,
0x3c, 0x6a, 0xea, 0x3b, 0xb0, 0xb5, 0x0f, 0xfa, 0x8e, 0x66, 0xb4, 0x86, 0x07, 0x2b, 0xf1, 0xe5,
0x0b, 0x1d, 0xba, 0x06, 0xdc, 0xfd, 0xaa, 0xd7, 0xe6, 0x0b, 0xe1, 0xdc, 0x0b, 0x88, 0x34, 0x6a,
0x0f, 0xea, 0x73, 0x1e, 0x18, 0x7f, 0xe4, 0xe3, 0x7f, 0x6e, 0xf1, 0x00, 0x76, 0x2b, 0x8c, 0x9c,
0xa1, 0x47, 0xa0, 0xec, 0xf2, 0x44, 0x96, 0x12, 0x43, 0xbc, 0x2e, 0xb8, 0x37, 0xb0, 0xf7, 0x8d,
0xa4, 0xf4, 0xb6, 0xf8, 0xa7, 0x88, 0x0a, 0x47, 0x6d, 0x83, 0x03, 0x1d, 0x42, 0x93, 0x65, 0x93,
0x90, 0x14, 0x66, 0x1f, 0x0d, 0x72, 0x9f, 0xc3, 0xfe, 0x06, 0x37, 0x67, 0xe6, 0xef, 0x45, 0xa7,
0x8a, 0xbe, 0x8d, 0x35, 0x18, 0xfe, 0xa8, 0x41, 0x73, 0xa4, 0x3e, 0x22, 0xe8, 0x0d, 0xd8, 0xf2,
0xe9, 0x4a, 0xed, 0x1f, 0xf6, 0x72, 0xb4, 0x57, 0x59, 0x03, 0x4c, 0xee, 0x8e, 0xf7, 0x37, 0x2a,
0x9c, 0xa1, 0x0f, 0x80, 0x3e, 0x26, 0x73, 0x96, 0x09, 0x52, 0xce, 0xf9, 0xf7, 0xab, 0xce, 0x1f,
0x63, 0xd1, 0x0c, 0x56, 0xc9, 0x3a, 0x54, 0x5d, 0xbe, 0xb5, 0x3b, 0x25, 0x86, 0x4d, 0xa7, 0xcf,
0xc0, 0xae, 0xbc, 0x2f, 0x3a, 0x5a, 0xb5, 0x6e, 0x7a, 0x7c, 0x7c, 0xfc, 0xb7, 0x23, 0xce, 0x4e,
0x07, 0x37, 0x2f, 0x03, 0x2a, 0x66, 0xd9, 0xa4, 0xef, 0x27, 0xf3, 0x41, 0x44, 0x83, 0x99, 0x88,
0x69, 0x1c, 0xc4, 0x44, 0xe4, 0x49, 0x1a, 0x0e, 0xa2, 0x78, 0x3a, 0x88, 0x56, 0x9f, 0xdd, 0x94,
0xf9, 0x93, 0xa6, 0xfa, 0xf0, 0xbe, 0xfe, 0x15, 0x00, 0x00, 0xff, 0xff, 0x09, 0xde, 0xe5, 0x7f,
0x90, 0x05, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -559,6 +758,20 @@ type SignerClient interface {
//in the TxOut field, the value in that same field, and finally the input
//index.
ComputeInputScript(ctx context.Context, in *SignReq, opts ...grpc.CallOption) (*InputScriptResp, error)
//*
//SignMessage signs a message with the key specified in the key locator. The
//returned signature is DER encoded.
//
//The main difference to SignMessage in the main RPC is that a specific key is
//used to sign the message instead of the node identity private key.
SignMessage(ctx context.Context, in *SignMessageReq, opts ...grpc.CallOption) (*SignMessageResp, error)
//*
//VerifyMessage verifies a signature over a message using the public key
//provided. The signature must be DER encoded.
//
//The main difference to VerifyMessage in the main RPC is that the public key
//used to sign the message does not have to be a node known to the network.
VerifyMessage(ctx context.Context, in *VerifyMessageReq, opts ...grpc.CallOption) (*VerifyMessageResp, error)
}
type signerClient struct {
@ -587,6 +800,24 @@ func (c *signerClient) ComputeInputScript(ctx context.Context, in *SignReq, opts
return out, nil
}
func (c *signerClient) SignMessage(ctx context.Context, in *SignMessageReq, opts ...grpc.CallOption) (*SignMessageResp, error) {
out := new(SignMessageResp)
err := c.cc.Invoke(ctx, "/signrpc.Signer/SignMessage", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *signerClient) VerifyMessage(ctx context.Context, in *VerifyMessageReq, opts ...grpc.CallOption) (*VerifyMessageResp, error) {
out := new(VerifyMessageResp)
err := c.cc.Invoke(ctx, "/signrpc.Signer/VerifyMessage", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// SignerServer is the server API for Signer service.
type SignerServer interface {
//*
@ -611,6 +842,20 @@ type SignerServer interface {
//in the TxOut field, the value in that same field, and finally the input
//index.
ComputeInputScript(context.Context, *SignReq) (*InputScriptResp, error)
//*
//SignMessage signs a message with the key specified in the key locator. The
//returned signature is DER encoded.
//
//The main difference to SignMessage in the main RPC is that a specific key is
//used to sign the message instead of the node identity private key.
SignMessage(context.Context, *SignMessageReq) (*SignMessageResp, error)
//*
//VerifyMessage verifies a signature over a message using the public key
//provided. The signature must be DER encoded.
//
//The main difference to VerifyMessage in the main RPC is that the public key
//used to sign the message does not have to be a node known to the network.
VerifyMessage(context.Context, *VerifyMessageReq) (*VerifyMessageResp, error)
}
func RegisterSignerServer(s *grpc.Server, srv SignerServer) {
@ -653,6 +898,42 @@ func _Signer_ComputeInputScript_Handler(srv interface{}, ctx context.Context, de
return interceptor(ctx, in, info, handler)
}
func _Signer_SignMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SignMessageReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SignerServer).SignMessage(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/signrpc.Signer/SignMessage",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SignerServer).SignMessage(ctx, req.(*SignMessageReq))
}
return interceptor(ctx, in, info, handler)
}
func _Signer_VerifyMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VerifyMessageReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SignerServer).VerifyMessage(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/signrpc.Signer/VerifyMessage",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SignerServer).VerifyMessage(ctx, req.(*VerifyMessageReq))
}
return interceptor(ctx, in, info, handler)
}
var _Signer_serviceDesc = grpc.ServiceDesc{
ServiceName: "signrpc.Signer",
HandlerType: (*SignerServer)(nil),
@ -665,6 +946,14 @@ var _Signer_serviceDesc = grpc.ServiceDesc{
MethodName: "ComputeInputScript",
Handler: _Signer_ComputeInputScript_Handler,
},
{
MethodName: "SignMessage",
Handler: _Signer_SignMessage_Handler,
},
{
MethodName: "VerifyMessage",
Handler: _Signer_VerifyMessage_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "signrpc/signer.proto",

@ -13,17 +13,17 @@ message KeyLocator {
}
message KeyDescriptor {
/**
The raw bytes of the key being identified. Either this or the KeyLocator
must be specified.
*/
bytes raw_key_bytes = 1;
/**
The raw bytes of the key being identified. Either this or the KeyLocator
must be specified.
*/
bytes raw_key_bytes = 1;
/**
The key locator that identifies which key to use for signing. Either this
or the raw bytes of the target key must be specified.
*/
KeyLocator key_loc = 2;
/**
The key locator that identifies which key to use for signing. Either this
or the raw bytes of the target key must be specified.
*/
KeyLocator key_loc = 2;
}
message TxOut {
@ -119,6 +119,38 @@ message InputScriptResp {
repeated InputScript input_scripts = 1;
}
message SignMessageReq {
/// The message to be signed.
bytes msg = 1;
/// The key locator that identifies which key to use for signing.
KeyLocator key_loc = 2;
}
message SignMessageResp {
/**
The signature for the given message in the fixed-size LN wire format.
*/
bytes signature = 1;
}
message VerifyMessageReq {
/// The message over which the signature is to be verified.
bytes msg = 1;
/**
The fixed-size LN wire encoded signature to be verified over the given
message.
*/
bytes signature = 2;
/// The public key the signature has to be valid for.
bytes pubkey = 3;
}
message VerifyMessageResp {
/// Whether the signature was valid over the given message.
bool valid = 1;
}
service Signer {
/**
SignOutputRaw is a method that can be used to generated a signature for a
@ -130,7 +162,7 @@ service Signer {
If we are unable to sign using the specified keys, then an error will be
returned.
*/
rpc SignOutputRaw(SignReq) returns (SignResp);
rpc SignOutputRaw (SignReq) returns (SignResp);
/**
ComputeInputScript generates a complete InputIndex for the passed
@ -144,5 +176,23 @@ service Signer {
in the TxOut field, the value in that same field, and finally the input
index.
*/
rpc ComputeInputScript(SignReq) returns (InputScriptResp);
rpc ComputeInputScript (SignReq) returns (InputScriptResp);
/**
SignMessage signs a message with the key specified in the key locator. The
returned signature is fixed-size LN wire format encoded.
The main difference to SignMessage in the main RPC is that a specific key is
used to sign the message instead of the node identity private key.
*/
rpc SignMessage (SignMessageReq) returns (SignMessageResp);
/**
VerifyMessage verifies a signature over a message using the public key
provided. The signature must be fixed-size LN wire format encoded.
The main difference to VerifyMessage in the main RPC is that the public key
used to sign the message does not have to be a node known to the network.
*/
rpc VerifyMessage (VerifyMessageReq) returns (VerifyMessageResp);
}

@ -11,12 +11,13 @@ import (
"path/filepath"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire"
"google.golang.org/grpc"
"gopkg.in/macaroon-bakery.v2/bakery"
)
@ -37,6 +38,10 @@ var (
Entity: "signer",
Action: "generate",
},
{
Entity: "signer",
Action: "read",
},
}
// macPermissions maps RPC calls to the permissions they require.
@ -49,6 +54,14 @@ var (
Entity: "signer",
Action: "generate",
}},
"/signrpc.Signer/SignMessage": {{
Entity: "signer",
Action: "generate",
}},
"/signrpc.Signer/VerifyMessage": {{
Entity: "signer",
Action: "read",
}},
}
// DefaultSignerMacFilename is the default name of the signer macaroon
@ -383,3 +396,84 @@ func (s *Server) ComputeInputScript(ctx context.Context,
return resp, nil
}
// SignMessage signs a message with the key specified in the key locator. The
// returned signature is fixed-size LN wire format encoded.
func (s *Server) SignMessage(ctx context.Context,
in *SignMessageReq) (*SignMessageResp, error) {
if in.Msg == nil {
return nil, fmt.Errorf("a message to sign MUST be passed in")
}
if in.KeyLoc == nil {
return nil, fmt.Errorf("a key locator MUST be passed in")
}
// Derive the private key we'll be using for signing.
keyLocator := keychain.KeyLocator{
Family: keychain.KeyFamily(in.KeyLoc.KeyFamily),
Index: uint32(in.KeyLoc.KeyIndex),
}
privKey, err := s.cfg.KeyRing.DerivePrivKey(keychain.KeyDescriptor{
KeyLocator: keyLocator,
})
if err != nil {
return nil, fmt.Errorf("can't derive private key: %v", err)
}
// The signature is over the sha256 hash of the message.
digest := chainhash.HashB(in.Msg)
// Create the raw ECDSA signature first and convert it to the final wire
// format after.
sig, err := privKey.Sign(digest)
if err != nil {
return nil, fmt.Errorf("can't sign the hash: %v", err)
}
wireSig, err := lnwire.NewSigFromSignature(sig)
if err != nil {
return nil, fmt.Errorf("can't convert to wire format: %v", err)
}
return &SignMessageResp{
Signature: wireSig.ToSignatureBytes(),
}, nil
}
// VerifyMessage verifies a signature over a message using the public key
// provided. The signature must be fixed-size LN wire format encoded.
func (s *Server) VerifyMessage(ctx context.Context,
in *VerifyMessageReq) (*VerifyMessageResp, error) {
if in.Msg == nil {
return nil, fmt.Errorf("a message to verify MUST be passed in")
}
if in.Signature == nil {
return nil, fmt.Errorf("a signature to verify MUST be passed " +
"in")
}
if in.Pubkey == nil {
return nil, fmt.Errorf("a pubkey to verify MUST be passed in")
}
pubkey, err := btcec.ParsePubKey(in.Pubkey, btcec.S256())
if err != nil {
return nil, fmt.Errorf("unable to parse pubkey: %v", err)
}
// The signature must be fixed-size LN wire format encoded.
wireSig, err := lnwire.NewSigFromRawSignature(in.Signature)
if err != nil {
return nil, fmt.Errorf("failed to decode signature: %v", err)
}
sig, err := wireSig.ToSignature()
if err != nil {
return nil, fmt.Errorf("failed to convert from wire format: %v",
err)
}
// The signature is over the sha256 hash of the message.
digest := chainhash.HashB(in.Msg)
valid := sig.Verify(digest, pubkey)
return &VerifyMessageResp{
Valid: valid,
}, nil
}

@ -116,6 +116,10 @@ var (
Entity: "invoices",
Action: "read",
},
{
Entity: "signer",
Action: "read",
},
}
// writePermissions is a slice of all entities that allow write

@ -132,6 +132,9 @@ func (s *subRPCServerConfigs) PopulateDependencies(cc *chainControl,
subCfgValue.FieldByName("Signer").Set(
reflect.ValueOf(cc.signer),
)
subCfgValue.FieldByName("KeyRing").Set(
reflect.ValueOf(cc.keyRing),
)
case *walletrpc.Config:
subCfgValue := extractReflectValue(subCfg)