lnwallet: update testSignOutputUsingTweaks to exercise new key derivation

This commit is contained in:
Olaoluwa Osuntokun 2017-07-29 19:37:08 -07:00
parent 9edc335049
commit eca8dd1076
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2

@ -1130,106 +1130,143 @@ func testTransactionSubscriptions(miner *rpctest.Harness, w *lnwallet.LightningW
} }
} }
func testSignOutputPrivateTweak(r *rpctest.Harness, w *lnwallet.LightningWallet, t *testing.T) { func testSignOutputUsingTweaks(r *rpctest.Harness,
t.Logf("Running private tweak test") alice, _ *lnwallet.LightningWallet, t *testing.T) {
// We'd like to test the ability of the wallet's Signer implementation // We'd like to test the ability of the wallet's Signer implementation
// to be able to sign with a private key derived from tweaking the // to be able to sign with a private key derived from tweaking the
// specific public key. This scenario exercises the case when the // specific public key. This scenario exercises the case when the
// wallet needs to sign for a sweep of a revoked output. // wallet needs to sign for a sweep of a revoked output, or just claim
// any output that pays to a tweaked key.
// First, generate a new public key under th control of the wallet, // First, generate a new public key under the control of the wallet,
// then generate a revocation key using it. // then generate a revocation key using it.
pubkey, err := w.NewRawKey() pubKey, err := alice.NewRawKey()
if err != nil { if err != nil {
t.Fatalf("unable to obtain public key: %v", err) t.Fatalf("unable to obtain public key: %v", err)
} }
revocation := bytes.Repeat([]byte{2}, 32)
revocationKey := lnwallet.DeriveRevocationPubkey(pubkey, revocation)
// With the revocation key generated, create a pkScript that pays to // As we'd like to test both single tweak, and double tweak spends,
// the revocation key using a simple p2wkh script. // we'll generate a commitment pre-image, then derive a revocation key
pubkeyHash := btcutil.Hash160(revocationKey.SerializeCompressed()) // and single tweak from that.
revokeAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubkeyHash, commitPreimage := bytes.Repeat([]byte{2}, 32)
&chaincfg.SimNetParams) commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
if err != nil { commitPreimage)
t.Fatalf("unable to create addr: %v", err)
}
revokeScript, err := txscript.PayToAddrScript(revokeAddr)
if err != nil {
t.Fatalf("unable to generate script: %v", err)
}
// With the script fully assemebld, instruct the wallet to fund the revocationKey := lnwallet.DeriveRevocationPubkey(pubKey, commitPoint)
// output with a newly creaed transaction. commitTweak := lnwallet.SingleTweakBytes(commitPoint, pubKey)
revokeOutput := &wire.TxOut{
Value: btcutil.SatoshiPerBitcoin,
PkScript: revokeScript,
}
txid, err := w.SendOutputs([]*wire.TxOut{revokeOutput})
if err != nil {
t.Fatalf("unable to create output: %v", err)
}
// Query for the transaction generated above so we can located the tweakedPub := lnwallet.TweakPubKey(pubKey, commitPoint)
// index of our output.
tx, err := r.Node.GetRawTransaction(txid)
if err != nil {
t.Fatalf("unable to query for tx: %v", err)
}
var outputIndex uint32
if bytes.Equal(tx.MsgTx().TxOut[0].PkScript, revokeScript) {
outputIndex = 0
} else {
outputIndex = 1
}
/// WIth the index located, we can create a transaction spending the // As we'd like to test both single and double tweaks, we'll repeat
//referenced output. // the same set up twice. The first will use a regular single tweak,
sweepTx := wire.NewMsgTx(2) // and the second will use a double tweak.
sweepTx.AddTxIn(&wire.TxIn{ baseKey := pubKey
PreviousOutPoint: wire.OutPoint{ for i := 0; i < 2; i++ {
Hash: tx.MsgTx().TxHash(), var tweakedKey *btcec.PublicKey
Index: outputIndex, if i == 0 {
}, tweakedKey = tweakedPub
}) } else {
tweakedKey = revocationKey
}
// Now we can populate the sign descriptor which we'll use to generate // Using the given key for the current iteration, we'll
// the signature. Within the descriptor we set the private tweak value // generate a regular p2wkh from that.
// as the key in the script is derived based on this tweak value and pubkeyHash := btcutil.Hash160(tweakedKey.SerializeCompressed())
// the key we originally generated above. keyAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubkeyHash,
signDesc := &lnwallet.SignDescriptor{ &chaincfg.SimNetParams)
PubKey: pubkey, if err != nil {
PrivateTweak: revocation, t.Fatalf("unable to create addr: %v", err)
WitnessScript: revokeScript, }
Output: revokeOutput, keyScript, err := txscript.PayToAddrScript(keyAddr)
HashType: txscript.SigHashAll, if err != nil {
SigHashes: txscript.NewTxSigHashes(sweepTx), t.Fatalf("unable to generate script: %v", err)
InputIndex: 0, }
}
// With the descriptor created, we use it to generate a signature, then // With the script fully assembled, instruct the wallet to fund
// manually create a valid witness stack we'll use for signing. // the output with a newly created transaction.
spendSig, err := w.Signer.SignOutputRaw(sweepTx, signDesc) newOutput := &wire.TxOut{
if err != nil { Value: btcutil.SatoshiPerBitcoin,
t.Fatalf("unable to generate signature: %v", err) PkScript: keyScript,
} }
witness := make([][]byte, 2) txid, err := alice.SendOutputs([]*wire.TxOut{newOutput})
witness[0] = append(spendSig, byte(txscript.SigHashAll)) if err != nil {
witness[1] = revocationKey.SerializeCompressed() t.Fatalf("unable to create output: %v", err)
sweepTx.TxIn[0].Witness = witness }
// Finally, attempt to validate the completed transaction. This should // Query for the transaction generated above so we can located
// succeed if the wallet was able to properly generate the proper // the index of our output.
// private key. tx, err := r.Node.GetRawTransaction(txid)
vm, err := txscript.NewEngine(revokeScript, if err != nil {
sweepTx, 0, txscript.StandardVerifyFlags, nil, t.Fatalf("unable to query for tx: %v", err)
nil, int64(btcutil.SatoshiPerBitcoin)) }
if err != nil { var outputIndex uint32
t.Fatalf("unable to create engine: %v", err) if bytes.Equal(tx.MsgTx().TxOut[0].PkScript, keyScript) {
} outputIndex = 0
if err := vm.Execute(); err != nil { } else {
t.Fatalf("revocation spend invalid: %v", err) outputIndex = 1
}
// With the index located, we can create a transaction spending
// the referenced output.
sweepTx := wire.NewMsgTx(2)
sweepTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: wire.OutPoint{
Hash: tx.MsgTx().TxHash(),
Index: outputIndex,
},
})
sweepTx.AddTxOut(&wire.TxOut{
Value: 1000,
PkScript: keyScript,
})
// Now we can populate the sign descriptor which we'll use to
// generate the signature. Within the descriptor we set the
// private tweak value as the key in the script is derived
// based on this tweak value and the key we originally
// generated above.
signDesc := &lnwallet.SignDescriptor{
PubKey: baseKey,
WitnessScript: keyScript,
Output: newOutput,
HashType: txscript.SigHashAll,
SigHashes: txscript.NewTxSigHashes(sweepTx),
InputIndex: 0,
}
// If this is the first, loop, we'll use the generated single
// tweak, otherwise, we'll use the double tweak.
if i == 0 {
signDesc.SingleTweak = commitTweak
} else {
signDesc.DoubleTweak = commitSecret
}
// With the descriptor created, we use it to generate a
// signature, then manually create a valid witness stack we'll
// use for signing.
spendSig, err := alice.Cfg.Signer.SignOutputRaw(sweepTx, signDesc)
if err != nil {
t.Fatalf("unable to generate signature: %v", err)
}
witness := make([][]byte, 2)
witness[0] = append(spendSig, byte(txscript.SigHashAll))
witness[1] = tweakedKey.SerializeCompressed()
sweepTx.TxIn[0].Witness = witness
// Finally, attempt to validate the completed transaction. This
// should succeed if the wallet was able to properly generate
// the proper private key.
vm, err := txscript.NewEngine(keyScript,
sweepTx, 0, txscript.StandardVerifyFlags, nil,
nil, int64(btcutil.SatoshiPerBitcoin))
if err != nil {
t.Fatalf("unable to create engine: %v", err)
}
if err := vm.Execute(); err != nil {
t.Fatalf("spend #%v is invalid: %v", i, err)
}
} }
} }