Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lnrpc: add tagged hash option to signer.SignMessage/VerifyMessage rpcs #8106

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -66,6 +66,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 @@ -107,5 +110,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