Skip to content

Commit

Permalink
Merge pull request #8106 from orbitalturtle/sign-tagged-hash-rpc
Browse files Browse the repository at this point in the history
lnrpc: add tagged hash option to signer.SignMessage/VerifyMessage rpcs
  • Loading branch information
Roasbeef authored Nov 7, 2023
2 parents e6fbaaf + 7ca96a6 commit dacb86f
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 235 deletions.
4 changes: 4 additions & 0 deletions docs/release-notes/release-notes-0.18.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
* [Deprecated](https://github.com/lightningnetwork/lnd/pull/7175)
`StatusUnknown` from the payment's rpc response in its status and replaced it
with `StatusInitiated` to explicitly report its current state.
* [Add an option to sign/verify a tagged
hash](https://github.com/lightningnetwork/lnd/pull/8106) to the
signer.SignMessage/signer.VerifyMessage RPCs.

## lncli Updates
## Code Health
Expand Down Expand Up @@ -111,5 +114,6 @@
* Elle Mouton
* Keagan McClelland
* Matt Morehouse
* Turtle
* Ononiwu Maureen Chiamaka
* Yong Yu
70 changes: 70 additions & 0 deletions itest/lnd_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package itest

import (
"bytes"
"context"
"crypto/sha256"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/keychain"
Expand Down Expand Up @@ -458,4 +460,72 @@ func runSignVerifyMessage(ht *lntest.HarnessTest, alice *node.HarnessNode) {
}
verifyResp = alice.RPC.VerifyMessageSigner(verifyReq)
require.True(ht, verifyResp.Valid, "failed to verify message")

// Now let's try signing and verifying a tagged hash.
tag := []byte("lightninginvoice_requestsignature")

signMsgReq = &signrpc.SignMessageReq{
Msg: aliceMsg,
KeyLoc: keyLoc,
SchnorrSig: true,
Tag: tag,
}
signMsgResp = alice.RPC.SignMessageSigner(signMsgReq)
customPubKey = deriveCustomizedKey()

verifyReq = &signrpc.VerifyMessageReq{
Msg: aliceMsg,
Signature: signMsgResp.Signature,
Pubkey: schnorr.SerializePubKey(customPubKey),
IsSchnorrSig: true,
Tag: tag,
}
verifyResp = alice.RPC.VerifyMessageSigner(verifyReq)
require.True(ht, verifyResp.Valid, "failed to verify message")

// Verify that both SignMessage and VerifyMessage error if a tag is
// provided but the Schnorr option is not set.
signMsgReq = &signrpc.SignMessageReq{
Msg: aliceMsg,
KeyLoc: keyLoc,
Tag: tag,
}

expectedErr := "tag can only be used when the Schnorr signature " +
"option is set"
ctxt := context.Background()
_, err := alice.RPC.Signer.SignMessage(ctxt, signMsgReq)
require.ErrorContains(ht, err, expectedErr)

verifyReq = &signrpc.VerifyMessageReq{
Msg: aliceMsg,
Signature: signMsgResp.Signature,
Pubkey: schnorr.SerializePubKey(customPubKey),
Tag: tag,
}

_, err = alice.RPC.Signer.VerifyMessage(ctxt, verifyReq)
require.ErrorContains(ht, err, expectedErr)

// Make sure that SignMessage throws an error if a BIP0340 or
// TapSighash tag is provided.
signMsgReq = &signrpc.SignMessageReq{
Msg: aliceMsg,
KeyLoc: keyLoc,
SchnorrSig: true,
Tag: []byte("BIP0340/challenge"),
}

_, err = alice.RPC.Signer.SignMessage(ctxt, signMsgReq)
require.ErrorContains(ht, err, "tag cannot have BIP0340 prefix")

signMsgReq = &signrpc.SignMessageReq{
Msg: aliceMsg,
KeyLoc: keyLoc,
SchnorrSig: true,
Tag: chainhash.TagTapSighash,
}

_, err = alice.RPC.Signer.SignMessage(ctxt, signMsgReq)
require.ErrorContains(ht, err, "tag cannot be TapSighash")
}
13 changes: 9 additions & 4 deletions keychain/btcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ func (b *BtcWalletKeyRing) SignMessageCompact(keyLoc KeyLocator,
//
// NOTE: This is part of the keychain.MessageSignerRing interface.
func (b *BtcWalletKeyRing) SignMessageSchnorr(keyLoc KeyLocator,
msg []byte, doubleHash bool, taprootTweak []byte) (*schnorr.Signature,
error) {
msg []byte, doubleHash bool, taprootTweak []byte,
tag []byte) (*schnorr.Signature, error) {

privKey, err := b.DerivePrivKey(KeyDescriptor{
KeyLocator: keyLoc,
Expand All @@ -472,10 +472,15 @@ func (b *BtcWalletKeyRing) SignMessageSchnorr(keyLoc KeyLocator,
privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak)
}

// If a tag was provided, we need to take the tagged hash of the input.
var digest []byte
if doubleHash {
switch {
case len(tag) > 0:
taggedHash := chainhash.TaggedHash(tag, msg)
digest = taggedHash[:]
case doubleHash:
digest = chainhash.DoubleHashB(msg)
} else {
default:
digest = chainhash.HashB(msg)
}
return schnorr.Sign(privKey, digest)
Expand Down
4 changes: 2 additions & 2 deletions keychain/derivation.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ type MessageSignerRing interface {
// hashing it first, with the private key described in the key locator
// and the optional Taproot tweak applied to the private key.
SignMessageSchnorr(keyLoc KeyLocator, msg []byte,
doubleHash bool, taprootTweak []byte) (*schnorr.Signature,
error)
doubleHash bool, taprootTweak []byte,
tag []byte) (*schnorr.Signature, error)
}

// SingleKeyMessageSigner is an abstraction interface that hides the
Expand Down
Loading

0 comments on commit dacb86f

Please sign in to comment.