2023-08-23 10:51:57 +02:00
|
|
|
package blob
|
2018-07-10 22:42:05 -07:00
|
|
|
|
|
|
|
import (
|
2019-01-10 15:35:15 -08:00
|
|
|
"bytes"
|
2018-07-10 22:42:05 -07:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/binary"
|
|
|
|
"io"
|
|
|
|
"testing"
|
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
2023-05-31 08:21:56 +02:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
2019-01-10 15:35:15 -08:00
|
|
|
"github.com/btcsuite/btcd/txscript"
|
2023-08-23 10:51:57 +02:00
|
|
|
"github.com/btcsuite/btcd/wire"
|
2019-01-16 15:47:43 +01:00
|
|
|
"github.com/lightningnetwork/lnd/input"
|
2023-08-23 10:51:57 +02:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet"
|
2018-07-10 22:42:05 -07:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2020-09-15 12:43:26 -04:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-07-10 22:42:05 -07:00
|
|
|
)
|
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
const csvDelay = uint32(144)
|
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
func makePubKey() *btcec.PublicKey {
|
|
|
|
priv, _ := btcec.NewPrivateKey()
|
|
|
|
return priv.PubKey()
|
2018-07-10 22:42:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func makeSig(i int) lnwire.Sig {
|
2023-01-16 19:33:21 -08:00
|
|
|
var sigBytes [64]byte
|
|
|
|
binary.BigEndian.PutUint64(sigBytes[:8], uint64(i))
|
|
|
|
|
|
|
|
sig, _ := lnwire.NewSigFromWireECDSA(sigBytes[:])
|
2018-07-10 22:42:05 -07:00
|
|
|
return sig
|
|
|
|
}
|
|
|
|
|
2018-10-29 14:23:31 -07:00
|
|
|
func makeAddr(size int) []byte {
|
|
|
|
addr := make([]byte, size)
|
|
|
|
if _, err := io.ReadFull(rand.Reader, addr); err != nil {
|
|
|
|
panic("unable to create addr")
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr
|
|
|
|
}
|
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
func makeSchnorrSig(i int) lnwire.Sig {
|
|
|
|
var sigBytes [64]byte
|
|
|
|
binary.BigEndian.PutUint64(sigBytes[:8], uint64(i))
|
|
|
|
|
|
|
|
sig, _ := lnwire.NewSigFromSchnorrRawSignature(sigBytes[:])
|
|
|
|
|
|
|
|
return sig
|
|
|
|
}
|
|
|
|
|
2018-10-26 18:01:07 -07:00
|
|
|
type descriptorTest struct {
|
2018-07-10 22:42:05 -07:00
|
|
|
name string
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion Type
|
|
|
|
decVersion Type
|
2018-10-29 14:23:31 -07:00
|
|
|
sweepAddr []byte
|
2023-08-23 10:51:57 +02:00
|
|
|
revPubKey *btcec.PublicKey
|
|
|
|
delayPubKey *btcec.PublicKey
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToLocalSig lnwire.Sig
|
|
|
|
hasCommitToRemote bool
|
2023-08-23 10:51:57 +02:00
|
|
|
commitToRemotePubKey *btcec.PublicKey
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToRemoteSig lnwire.Sig
|
|
|
|
encErr error
|
|
|
|
decErr error
|
2018-10-26 18:01:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var descriptorTests = []descriptorTest{
|
2018-07-10 22:42:05 -07:00
|
|
|
{
|
|
|
|
name: "to-local only",
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion: TypeAltruistCommit,
|
|
|
|
decVersion: TypeAltruistCommit,
|
2018-10-29 14:23:31 -07:00
|
|
|
sweepAddr: makeAddr(22),
|
2023-08-23 10:51:57 +02:00
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "to-local and p2wkh",
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion: TypeRewardCommit,
|
|
|
|
decVersion: TypeRewardCommit,
|
2018-10-29 14:23:31 -07:00
|
|
|
sweepAddr: makeAddr(22),
|
2023-08-23 10:51:57 +02:00
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
|
|
|
hasCommitToRemote: true,
|
2023-08-23 10:51:57 +02:00
|
|
|
commitToRemotePubKey: makePubKey(),
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToRemoteSig: makeSig(2),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unknown encrypt version",
|
2019-01-10 15:35:11 -08:00
|
|
|
encVersion: 0,
|
2023-08-23 10:51:57 +02:00
|
|
|
decVersion: TypeAltruistCommit,
|
2018-10-29 14:23:31 -07:00
|
|
|
sweepAddr: makeAddr(34),
|
2023-08-23 10:51:57 +02:00
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
2023-08-23 10:51:57 +02:00
|
|
|
encErr: ErrUnknownBlobType,
|
2018-07-10 22:42:05 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unknown decrypt version",
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion: TypeAltruistCommit,
|
2019-01-10 15:35:11 -08:00
|
|
|
decVersion: 0,
|
2018-10-29 14:23:31 -07:00
|
|
|
sweepAddr: makeAddr(34),
|
2023-08-23 10:51:57 +02:00
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-07-10 22:42:05 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
2023-08-23 10:51:57 +02:00
|
|
|
decErr: ErrUnknownBlobType,
|
2018-07-10 22:42:05 -07:00
|
|
|
},
|
2018-10-29 14:23:31 -07:00
|
|
|
{
|
|
|
|
name: "sweep addr length zero",
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion: TypeAltruistCommit,
|
|
|
|
decVersion: TypeAltruistCommit,
|
2018-10-29 14:23:31 -07:00
|
|
|
sweepAddr: makeAddr(0),
|
2023-08-23 10:51:57 +02:00
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-10-29 14:23:31 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "sweep addr max size",
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion: TypeAltruistCommit,
|
|
|
|
decVersion: TypeAltruistCommit,
|
|
|
|
sweepAddr: makeAddr(MaxSweepAddrSize),
|
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-10-29 14:23:31 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "sweep addr too long",
|
2023-08-23 10:51:57 +02:00
|
|
|
encVersion: TypeAltruistCommit,
|
|
|
|
decVersion: TypeAltruistCommit,
|
|
|
|
sweepAddr: makeAddr(MaxSweepAddrSize + 1),
|
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
2018-10-29 14:23:31 -07:00
|
|
|
commitToLocalSig: makeSig(1),
|
2023-08-23 10:51:57 +02:00
|
|
|
encErr: ErrSweepAddressToLong,
|
2018-10-29 14:23:31 -07:00
|
|
|
},
|
2023-05-31 08:21:56 +02:00
|
|
|
{
|
|
|
|
name: "taproot to-local only",
|
|
|
|
encVersion: TypeAltruistTaprootCommit,
|
|
|
|
decVersion: TypeAltruistTaprootCommit,
|
|
|
|
sweepAddr: makeAddr(34),
|
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
|
|
|
commitToLocalSig: makeSchnorrSig(1),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "taproot to-local and to-remote",
|
|
|
|
encVersion: TypeAltruistTaprootCommit,
|
|
|
|
decVersion: TypeAltruistTaprootCommit,
|
|
|
|
sweepAddr: makeAddr(34),
|
|
|
|
revPubKey: makePubKey(),
|
|
|
|
delayPubKey: makePubKey(),
|
|
|
|
commitToLocalSig: makeSchnorrSig(1),
|
|
|
|
hasCommitToRemote: true,
|
|
|
|
commitToRemotePubKey: makePubKey(),
|
|
|
|
commitToRemoteSig: makeSchnorrSig(2),
|
|
|
|
},
|
2018-07-10 22:42:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestBlobJusticeKitEncryptDecrypt asserts that encrypting and decrypting a
|
|
|
|
// plaintext blob produces the original. The tests include negative assertions
|
|
|
|
// when passed invalid combinations, and that all successfully encrypted blobs
|
|
|
|
// are of constant size.
|
|
|
|
func TestBlobJusticeKitEncryptDecrypt(t *testing.T) {
|
2018-10-26 18:01:07 -07:00
|
|
|
for _, test := range descriptorTests {
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
testBlobJusticeKitEncryptDecrypt(t, test)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testBlobJusticeKitEncryptDecrypt(t *testing.T, test descriptorTest) {
|
2023-08-23 10:51:57 +02:00
|
|
|
commitmentType, err := test.encVersion.CommitmentType(nil)
|
|
|
|
if err != nil {
|
|
|
|
require.ErrorIs(t, err, test.encErr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
breachInfo := &lnwallet.BreachRetribution{
|
2023-05-31 08:21:56 +02:00
|
|
|
RemoteDelay: csvDelay,
|
2023-08-23 10:51:57 +02:00
|
|
|
KeyRing: &lnwallet.CommitmentKeyRing{
|
|
|
|
ToLocalKey: test.delayPubKey,
|
|
|
|
ToRemoteKey: test.commitToRemotePubKey,
|
|
|
|
RevocationKey: test.revPubKey,
|
|
|
|
},
|
2018-10-26 18:01:07 -07:00
|
|
|
}
|
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
kit, err := commitmentType.NewJusticeKit(
|
|
|
|
test.sweepAddr, breachInfo, test.hasCommitToRemote,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
kit.AddToLocalSig(test.commitToLocalSig)
|
|
|
|
kit.AddToRemoteSig(test.commitToRemoteSig)
|
|
|
|
|
2018-10-26 18:01:07 -07:00
|
|
|
// Generate a random encryption key for the blob. The key is
|
|
|
|
// sized at 32 byte, as in practice we will be using the remote
|
|
|
|
// party's commitment txid as the key.
|
2023-08-23 10:51:57 +02:00
|
|
|
var key BreachKey
|
|
|
|
_, err = rand.Read(key[:])
|
2022-05-05 20:11:50 +00:00
|
|
|
require.NoError(t, err, "unable to generate blob encryption key")
|
2018-10-26 18:01:07 -07:00
|
|
|
|
|
|
|
// Encrypt the blob plaintext using the generated key and
|
|
|
|
// target version for this test.
|
2023-08-23 10:51:57 +02:00
|
|
|
ctxt, err := Encrypt(kit, key)
|
|
|
|
require.ErrorIs(t, err, test.encErr)
|
|
|
|
|
|
|
|
if test.encErr != nil {
|
2018-10-26 18:01:07 -07:00
|
|
|
// If the test expected an encryption failure, we can
|
|
|
|
// continue to the next test.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that all encrypted blobs are padded out to the same
|
|
|
|
// size: 282 bytes for version 0.
|
2023-08-23 10:51:57 +02:00
|
|
|
require.Len(t, ctxt, Size(kit))
|
2018-10-26 18:01:07 -07:00
|
|
|
|
|
|
|
// Decrypt the encrypted blob, reconstructing the original
|
|
|
|
// blob plaintext from the decrypted contents. We use the target
|
|
|
|
// decryption version specified by this test case.
|
2023-08-23 10:51:57 +02:00
|
|
|
boj2, err := Decrypt(key, ctxt, test.decVersion)
|
|
|
|
require.ErrorIs(t, err, test.decErr)
|
|
|
|
|
|
|
|
if test.decErr != nil {
|
2018-10-26 18:01:07 -07:00
|
|
|
// If the test expected an decryption failure, we can
|
|
|
|
// continue to the next test.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the decrypted blob properly reports whether it has
|
|
|
|
// a to-remote output or not.
|
|
|
|
if boj2.HasCommitToRemoteOutput() != test.hasCommitToRemote {
|
|
|
|
t.Fatalf("expected blob has_to_remote to be %v, got %v",
|
|
|
|
test.hasCommitToRemote, boj2.HasCommitToRemoteOutput())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the original blob plaintext matches the
|
|
|
|
// one reconstructed from the encrypted blob.
|
2023-08-23 10:51:57 +02:00
|
|
|
require.Equal(t, kit, boj2)
|
2018-07-10 22:42:05 -07:00
|
|
|
}
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2020-09-15 12:43:44 -04:00
|
|
|
type remoteWitnessTest struct {
|
|
|
|
name string
|
2023-08-23 10:51:57 +02:00
|
|
|
blobType Type
|
2020-09-15 12:43:44 -04:00
|
|
|
expWitnessScript func(pk *btcec.PublicKey) []byte
|
2023-05-31 08:21:56 +02:00
|
|
|
expWitnessStack func(sig input.Signature) wire.TxWitness
|
|
|
|
createSig func(*btcec.PrivateKey, []byte) input.Signature
|
2020-09-15 12:43:44 -04:00
|
|
|
}
|
|
|
|
|
2019-01-10 15:35:15 -08:00
|
|
|
// TestJusticeKitRemoteWitnessConstruction tests that a JusticeKit returns the
|
|
|
|
// proper to-remote witnes script and to-remote witness stack. This should be
|
|
|
|
// equivalent to p2wkh spend.
|
|
|
|
func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
|
2020-09-15 12:43:44 -04:00
|
|
|
tests := []remoteWitnessTest{
|
|
|
|
{
|
|
|
|
name: "legacy commitment",
|
2023-08-23 10:51:57 +02:00
|
|
|
blobType: TypeAltruistCommit,
|
2020-09-15 12:43:44 -04:00
|
|
|
expWitnessScript: func(pk *btcec.PublicKey) []byte {
|
|
|
|
return pk.SerializeCompressed()
|
|
|
|
},
|
2023-05-31 08:21:56 +02:00
|
|
|
expWitnessStack: func(
|
|
|
|
sig input.Signature) wire.TxWitness {
|
|
|
|
|
|
|
|
sigBytes := append(
|
|
|
|
sig.Serialize(),
|
|
|
|
byte(txscript.SigHashAll),
|
|
|
|
)
|
|
|
|
|
|
|
|
return [][]byte{sigBytes}
|
|
|
|
},
|
|
|
|
createSig: func(priv *btcec.PrivateKey,
|
|
|
|
digest []byte) input.Signature {
|
|
|
|
|
|
|
|
return ecdsa.Sign(priv, digest)
|
|
|
|
},
|
2020-09-15 12:43:44 -04:00
|
|
|
},
|
|
|
|
{
|
2023-08-23 10:51:57 +02:00
|
|
|
name: "anchor commitment",
|
|
|
|
blobType: TypeAltruistAnchorCommit,
|
2020-09-15 12:43:44 -04:00
|
|
|
expWitnessScript: func(pk *btcec.PublicKey) []byte {
|
|
|
|
script, _ := input.CommitScriptToRemoteConfirmed(pk)
|
|
|
|
return script
|
|
|
|
},
|
2023-05-31 08:21:56 +02:00
|
|
|
expWitnessStack: func(
|
|
|
|
sig input.Signature) wire.TxWitness {
|
|
|
|
|
|
|
|
sigBytes := append(
|
|
|
|
sig.Serialize(),
|
|
|
|
byte(txscript.SigHashAll),
|
|
|
|
)
|
|
|
|
|
|
|
|
return [][]byte{sigBytes}
|
|
|
|
},
|
|
|
|
createSig: func(priv *btcec.PrivateKey,
|
|
|
|
digest []byte) input.Signature {
|
|
|
|
|
|
|
|
return ecdsa.Sign(priv, digest)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "taproot commitment",
|
|
|
|
blobType: TypeAltruistTaprootCommit,
|
|
|
|
expWitnessScript: func(pk *btcec.PublicKey) []byte {
|
|
|
|
tree, _ := input.NewRemoteCommitScriptTree(pk)
|
|
|
|
|
|
|
|
return tree.SettleLeaf.Script
|
|
|
|
},
|
|
|
|
expWitnessStack: func(
|
|
|
|
sig input.Signature) wire.TxWitness {
|
|
|
|
|
|
|
|
return [][]byte{sig.Serialize()}
|
|
|
|
},
|
|
|
|
createSig: func(priv *btcec.PrivateKey,
|
|
|
|
digest []byte) input.Signature {
|
|
|
|
|
|
|
|
sig, _ := schnorr.Sign(priv, digest)
|
|
|
|
|
|
|
|
return sig
|
|
|
|
},
|
2020-09-15 12:43:44 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
|
|
|
test := test
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
testJusticeKitRemoteWitnessConstruction(t, test)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
func testJusticeKitRemoteWitnessConstruction(t *testing.T,
|
|
|
|
test remoteWitnessTest) {
|
2020-09-15 12:43:44 -04:00
|
|
|
|
2019-01-10 15:35:15 -08:00
|
|
|
// Generate the to-remote pubkey.
|
2022-02-23 14:48:00 +01:00
|
|
|
toRemotePrivKey, err := btcec.NewPrivateKey()
|
2023-08-23 10:51:57 +02:00
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
revKey, err := btcec.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
toLocalKey, err := btcec.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Sign a message using the to-remote private key. The exact message
|
|
|
|
// doesn't matter as we won't be validating the signature's validity.
|
|
|
|
digest := bytes.Repeat([]byte("a"), 32)
|
2023-05-31 08:21:56 +02:00
|
|
|
rawToRemoteSig := test.createSig(toRemotePrivKey, digest)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Convert the DER-encoded signature into a fixed-size sig.
|
|
|
|
commitToRemoteSig, err := lnwire.NewSigFromSignature(rawToRemoteSig)
|
2020-09-15 12:43:26 -04:00
|
|
|
require.Nil(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
commitType, err := test.blobType.CommitmentType(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
breachInfo := &lnwallet.BreachRetribution{
|
|
|
|
KeyRing: &lnwallet.CommitmentKeyRing{
|
|
|
|
ToRemoteKey: toRemotePrivKey.PubKey(),
|
|
|
|
RevocationKey: revKey.PubKey(),
|
|
|
|
ToLocalKey: toLocalKey.PubKey(),
|
|
|
|
},
|
2019-01-10 15:35:15 -08:00
|
|
|
}
|
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
justiceKit, err := commitType.NewJusticeKit(nil, breachInfo, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
justiceKit.AddToRemoteSig(commitToRemoteSig)
|
|
|
|
|
2019-01-10 15:35:15 -08:00
|
|
|
// Now, compute the to-remote witness script returned by the justice
|
|
|
|
// kit.
|
2023-08-23 10:51:57 +02:00
|
|
|
_, witness, _, err := justiceKit.ToRemoteOutputSpendInfo()
|
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Assert this is exactly the to-remote, compressed pubkey.
|
2020-09-15 12:43:44 -04:00
|
|
|
expToRemoteScript := test.expWitnessScript(toRemotePrivKey.PubKey())
|
2023-08-23 10:51:57 +02:00
|
|
|
require.Equal(t, expToRemoteScript, witness[1])
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
// Compute the expected signature.
|
|
|
|
expWitnessStack := test.expWitnessStack(rawToRemoteSig)
|
2023-08-23 10:51:57 +02:00
|
|
|
require.Equal(t, expWitnessStack, witness[:1])
|
2019-01-10 15:35:15 -08:00
|
|
|
}
|
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
type localWitnessTest struct {
|
|
|
|
name string
|
|
|
|
blobType Type
|
|
|
|
expWitnessScript func(delay, rev *btcec.PublicKey) []byte
|
|
|
|
expWitnessStack func(sig input.Signature) wire.TxWitness
|
|
|
|
witnessScriptIndex int
|
|
|
|
createSig func(*btcec.PrivateKey, []byte) input.Signature
|
|
|
|
}
|
|
|
|
|
2019-01-10 15:35:15 -08:00
|
|
|
// TestJusticeKitToLocalWitnessConstruction tests that a JusticeKit returns the
|
|
|
|
// proper to-local witness script and to-local witness stack for spending the
|
|
|
|
// revocation path.
|
|
|
|
func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
|
2023-05-31 08:21:56 +02:00
|
|
|
tests := []localWitnessTest{
|
|
|
|
{
|
|
|
|
name: "legacy commitment",
|
|
|
|
blobType: TypeAltruistCommit,
|
|
|
|
expWitnessScript: func(delay,
|
|
|
|
rev *btcec.PublicKey) []byte {
|
|
|
|
|
|
|
|
script, _ := input.CommitScriptToSelf(
|
|
|
|
csvDelay, delay, rev,
|
|
|
|
)
|
|
|
|
|
|
|
|
return script
|
|
|
|
},
|
|
|
|
expWitnessStack: func(
|
|
|
|
sig input.Signature) wire.TxWitness {
|
|
|
|
|
|
|
|
sigBytes := append(
|
|
|
|
sig.Serialize(),
|
|
|
|
byte(txscript.SigHashAll),
|
|
|
|
)
|
|
|
|
|
|
|
|
return [][]byte{sigBytes, {1}}
|
|
|
|
},
|
|
|
|
witnessScriptIndex: 2,
|
|
|
|
createSig: func(priv *btcec.PrivateKey,
|
|
|
|
digest []byte) input.Signature {
|
|
|
|
|
|
|
|
return ecdsa.Sign(priv, digest)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "anchor commitment",
|
|
|
|
blobType: TypeAltruistAnchorCommit,
|
|
|
|
expWitnessScript: func(delay,
|
|
|
|
rev *btcec.PublicKey) []byte {
|
|
|
|
|
|
|
|
script, _ := input.CommitScriptToSelf(
|
|
|
|
csvDelay, delay, rev,
|
|
|
|
)
|
|
|
|
|
|
|
|
return script
|
|
|
|
},
|
|
|
|
witnessScriptIndex: 2,
|
|
|
|
expWitnessStack: func(
|
|
|
|
sig input.Signature) wire.TxWitness {
|
|
|
|
|
|
|
|
sigBytes := append(
|
|
|
|
sig.Serialize(),
|
|
|
|
byte(txscript.SigHashAll),
|
|
|
|
)
|
|
|
|
|
|
|
|
return [][]byte{sigBytes, {1}}
|
|
|
|
},
|
|
|
|
createSig: func(priv *btcec.PrivateKey,
|
|
|
|
digest []byte) input.Signature {
|
|
|
|
|
|
|
|
return ecdsa.Sign(priv, digest)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "taproot commitment",
|
|
|
|
blobType: TypeAltruistTaprootCommit,
|
|
|
|
expWitnessScript: func(delay,
|
|
|
|
rev *btcec.PublicKey) []byte {
|
|
|
|
|
|
|
|
script, _ := input.NewLocalCommitScriptTree(
|
|
|
|
csvDelay, delay, rev,
|
|
|
|
)
|
|
|
|
|
|
|
|
return script.RevocationLeaf.Script
|
|
|
|
},
|
|
|
|
witnessScriptIndex: 1,
|
|
|
|
expWitnessStack: func(
|
|
|
|
sig input.Signature) wire.TxWitness {
|
|
|
|
|
|
|
|
return [][]byte{sig.Serialize()}
|
|
|
|
},
|
|
|
|
createSig: func(priv *btcec.PrivateKey,
|
|
|
|
digest []byte) input.Signature {
|
|
|
|
|
|
|
|
sig, _ := schnorr.Sign(priv, digest)
|
|
|
|
|
|
|
|
return sig
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
|
|
|
test := test
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testJusticeKitToLocalWitnessConstruction(t, test)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testJusticeKitToLocalWitnessConstruction(t *testing.T,
|
|
|
|
test localWitnessTest) {
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Generate the revocation and delay private keys.
|
2022-02-23 14:48:00 +01:00
|
|
|
revPrivKey, err := btcec.NewPrivateKey()
|
2023-08-23 10:51:57 +02:00
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
delayPrivKey, err := btcec.NewPrivateKey()
|
2023-08-23 10:51:57 +02:00
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Sign a message using the revocation private key. The exact message
|
|
|
|
// doesn't matter as we won't be validating the signature's validity.
|
|
|
|
digest := bytes.Repeat([]byte("a"), 32)
|
2023-05-31 08:21:56 +02:00
|
|
|
rawRevSig := test.createSig(revPrivKey, digest)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Convert the DER-encoded signature into a fixed-size sig.
|
|
|
|
commitToLocalSig, err := lnwire.NewSigFromSignature(rawRevSig)
|
2023-08-23 10:51:57 +02:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
commitType, err := test.blobType.CommitmentType(nil)
|
2023-08-23 10:51:57 +02:00
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
breachInfo := &lnwallet.BreachRetribution{
|
|
|
|
RemoteDelay: csvDelay,
|
|
|
|
KeyRing: &lnwallet.CommitmentKeyRing{
|
|
|
|
RevocationKey: revPrivKey.PubKey(),
|
|
|
|
ToLocalKey: delayPrivKey.PubKey(),
|
|
|
|
},
|
2019-01-10 15:35:15 -08:00
|
|
|
}
|
|
|
|
|
2023-08-23 10:51:57 +02:00
|
|
|
justiceKit, err := commitType.NewJusticeKit(nil, breachInfo, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
justiceKit.AddToLocalSig(commitToLocalSig)
|
|
|
|
|
2019-01-10 15:35:15 -08:00
|
|
|
// Compute the expected to-local script, which is a function of the CSV
|
|
|
|
// delay, revocation pubkey and delay pubkey.
|
2023-05-31 08:21:56 +02:00
|
|
|
expToLocalScript := test.expWitnessScript(
|
|
|
|
delayPrivKey.PubKey(), revPrivKey.PubKey(),
|
2019-01-10 15:35:15 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Compute the to-local script that is returned by the justice kit.
|
2023-08-23 10:51:57 +02:00
|
|
|
_, witness, err := justiceKit.ToLocalOutputSpendInfo()
|
|
|
|
require.NoError(t, err)
|
2019-01-10 15:35:15 -08:00
|
|
|
|
|
|
|
// Assert that the expected to-local script matches the actual script.
|
2023-05-31 08:21:56 +02:00
|
|
|
require.Equal(t, expToLocalScript, witness[test.witnessScriptIndex])
|
2019-01-10 15:35:15 -08:00
|
|
|
|
2023-05-31 08:21:56 +02:00
|
|
|
// Finally, validate the witness.
|
|
|
|
expWitnessStack := test.expWitnessStack(rawRevSig)
|
|
|
|
require.Equal(t, expWitnessStack, witness[:test.witnessScriptIndex])
|
2019-01-10 15:35:15 -08:00
|
|
|
}
|