From af01571fc61dfab2f5813050dc59c40e7c00be20 Mon Sep 17 00:00:00 2001 From: Yaacov Akiba Slama Date: Sun, 28 Jun 2020 16:51:42 +0300 Subject: [PATCH] Let invoice.Encode receive a function which hashes itself the message Modify the SignCompact function passed to invoice.Encode to receive the message before it's hashed and hash it itself. With this modification, the SignMessage rpc function from the signrpc subserver can be used and an invoice can be encoded outside of lnd. --- lnrpc/invoicesrpc/addinvoice.go | 6 +++++- zpay32/encode.go | 4 ++-- zpay32/invoice.go | 6 +++--- zpay32/invoice_test.go | 7 ++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 573d2f381..7daf599cf 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -10,6 +10,7 @@ import ( "time" "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" "github.com/davecgh/go-spew/spew" @@ -387,7 +388,10 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, payReqString, err := payReq.Encode( zpay32.MessageSigner{ - SignCompact: cfg.NodeSigner.SignDigestCompact, + SignCompact: func(msg []byte) ([]byte, error) { + hash := chainhash.HashB(msg) + return cfg.NodeSigner.SignDigestCompact(hash) + }, }, ) if err != nil { diff --git a/zpay32/encode.go b/zpay32/encode.go index 9084e2305..92783f656 100644 --- a/zpay32/encode.go +++ b/zpay32/encode.go @@ -70,12 +70,11 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) { } toSign := append([]byte(hrp), taggedFieldsBytes...) - hash := chainhash.HashB(toSign) // We use compact signature format, and also encoded the recovery ID // such that a reader of the invoice can recover our pubkey from the // signature. - sign, err := signer.SignCompact(hash) + sign, err := signer.SignCompact(toSign) if err != nil { return "", err } @@ -95,6 +94,7 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) { "signature: %v", err) } + hash := chainhash.HashB(toSign) valid := signature.Verify(hash, invoice.Destination) if !valid { return "", fmt.Errorf("signature does not match " + diff --git a/zpay32/invoice.go b/zpay32/invoice.go index 8444e3eea..7f2d86c7a 100644 --- a/zpay32/invoice.go +++ b/zpay32/invoice.go @@ -100,11 +100,11 @@ var ( // MessageSigner is passed to the Encode method to provide a signature // corresponding to the node's pubkey. type MessageSigner struct { - // SignCompact signs the passed hash with the node's privkey. The - // returned signature should be 65 bytes, where the last 64 are the + // SignCompact signs the hash of the passed msg with the node's privkey. + // The returned signature should be 65 bytes, where the last 64 are the // compact signature, and the first one is a header byte. This is the // format returned by btcec.SignCompact. - SignCompact func(hash []byte) ([]byte, error) + SignCompact func(msg []byte) ([]byte, error) } // Invoice represents a decoded invoice, or to-be-encoded invoice. Some of the diff --git a/zpay32/invoice_test.go b/zpay32/invoice_test.go index 41687a690..389c350d7 100644 --- a/zpay32/invoice_test.go +++ b/zpay32/invoice_test.go @@ -101,9 +101,9 @@ var ( } testMessageSigner = MessageSigner{ - SignCompact: func(hash []byte) ([]byte, error) { + SignCompact: func(msg []byte) ([]byte, error) { sig, err := btcec.SignCompact(btcec.S256(), - testPrivKey, hash, true) + testPrivKey, chainhash.HashB(msg), true) if err != nil { return nil, fmt.Errorf("can't sign the "+ "message: %v", err) @@ -915,7 +915,8 @@ func TestInvoiceChecksumMalleability(t *testing.T) { privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) msgSigner := MessageSigner{ - SignCompact: func(hash []byte) ([]byte, error) { + SignCompact: func(msg []byte) ([]byte, error) { + hash := chainhash.HashB(msg) return btcec.SignCompact(btcec.S256(), privKey, hash, true) }, }