mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
317 lines
9.7 KiB
Go
317 lines
9.7 KiB
Go
package input
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/txscript"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/lightningnetwork/lnd/keychain"
|
|
)
|
|
|
|
var (
|
|
// ErrTweakOverdose signals a SignDescriptor is invalid because both of its
|
|
// SingleTweak and DoubleTweak are non-nil.
|
|
ErrTweakOverdose = errors.New("sign descriptor should only have one tweak")
|
|
)
|
|
|
|
// SignDescriptor houses the necessary information required to successfully
|
|
// sign a given segwit output. This struct is used by the Signer interface in
|
|
// order to gain access to critical data needed to generate a valid signature.
|
|
type SignDescriptor struct {
|
|
// KeyDesc is a descriptor that precisely describes *which* key to use
|
|
// for signing. This may provide the raw public key directly, or
|
|
// require the Signer to re-derive the key according to the populated
|
|
// derivation path.
|
|
KeyDesc keychain.KeyDescriptor
|
|
|
|
// SingleTweak is a scalar value that will be added to the private key
|
|
// corresponding to the above public key to obtain the private key to
|
|
// be used to sign this input. This value is typically derived via the
|
|
// following computation:
|
|
//
|
|
// * derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
|
|
//
|
|
// NOTE: If this value is nil, then the input can be signed using only
|
|
// the above public key. Either a SingleTweak should be set or a
|
|
// DoubleTweak, not both.
|
|
SingleTweak []byte
|
|
|
|
// DoubleTweak is a private key that will be used in combination with
|
|
// its corresponding private key to derive the private key that is to
|
|
// be used to sign the target input. Within the Lightning protocol,
|
|
// this value is typically the commitment secret from a previously
|
|
// revoked commitment transaction. This value is in combination with
|
|
// two hash values, and the original private key to derive the private
|
|
// key to be used when signing.
|
|
//
|
|
// * k = (privKey*sha256(pubKey || tweakPub) +
|
|
// tweakPriv*sha256(tweakPub || pubKey)) mod N
|
|
//
|
|
// NOTE: If this value is nil, then the input can be signed using only
|
|
// the above public key. Either a SingleTweak should be set or a
|
|
// DoubleTweak, not both.
|
|
DoubleTweak *btcec.PrivateKey
|
|
|
|
// TapTweak is a 32-byte value that will be used to derive a taproot
|
|
// output public key (or the corresponding private key) from an
|
|
// internal key and this tweak. The transformation applied is:
|
|
// * outputKey = internalKey +
|
|
// tagged_hash("tapTweak", internalKey || tapTweak)
|
|
//
|
|
// When attempting to sign an output derived via BIP 86, then this
|
|
// field should be an empty byte array.
|
|
//
|
|
// When attempting to sign for the key spend path of an output key that
|
|
// commits to an actual script tree, the script root should be used.
|
|
TapTweak []byte
|
|
|
|
// WitnessScript is the full script required to properly redeem the
|
|
// output. This field should be set to the full script if a p2wsh
|
|
// output is being signed. For p2wkh it should be set to the hashed
|
|
// script (PkScript).
|
|
WitnessScript []byte
|
|
|
|
// SignMethod specifies how the input should be signed. Depending on the
|
|
// selected method, either the TapTweak, WitnessScript or both need to
|
|
// be specified.
|
|
SignMethod SignMethod
|
|
|
|
// Output is the target output which should be signed. The PkScript and
|
|
// Value fields within the output should be properly populated,
|
|
// otherwise an invalid signature may be generated.
|
|
Output *wire.TxOut
|
|
|
|
// HashType is the target sighash type that should be used when
|
|
// generating the final sighash, and signature.
|
|
HashType txscript.SigHashType
|
|
|
|
// SigHashes is the pre-computed sighash midstate to be used when
|
|
// generating the final sighash for signing.
|
|
SigHashes *txscript.TxSigHashes
|
|
|
|
// PrevOutputFetcher is an interface that can return the output
|
|
// information on all UTXOs that are being spent in this transaction.
|
|
// This MUST be set when spending Taproot outputs.
|
|
PrevOutputFetcher txscript.PrevOutputFetcher
|
|
|
|
// ControlBlock is a fully serialized control block that contains the
|
|
// merkle proof necessary to spend a taproot output. This may
|
|
// optionally be set if the SignMethod is
|
|
// input.TaprootScriptSpendSignMethod. In which case, this should be an
|
|
// inclusion proof for the WitnessScript.
|
|
ControlBlock []byte
|
|
|
|
// InputIndex is the target input within the transaction that should be
|
|
// signed.
|
|
InputIndex int
|
|
}
|
|
|
|
// SignMethod defines the different ways a signer can sign, given a specific
|
|
// input.
|
|
type SignMethod uint8
|
|
|
|
const (
|
|
// WitnessV0SignMethod denotes that a SegWit v0 (p2wkh, np2wkh, p2wsh)
|
|
// input script should be signed.
|
|
WitnessV0SignMethod SignMethod = 0
|
|
|
|
// TaprootKeySpendBIP0086SignMethod denotes that a SegWit v1 (p2tr)
|
|
// input should be signed by using the BIP0086 method (commit to
|
|
// internal key only).
|
|
TaprootKeySpendBIP0086SignMethod SignMethod = 1
|
|
|
|
// TaprootKeySpendSignMethod denotes that a SegWit v1 (p2tr)
|
|
// input should be signed by using a given taproot hash to commit to in
|
|
// addition to the internal key.
|
|
TaprootKeySpendSignMethod SignMethod = 2
|
|
|
|
// TaprootScriptSpendSignMethod denotes that a SegWit v1 (p2tr) input
|
|
// should be spent using the script path and that a specific leaf script
|
|
// should be signed for.
|
|
TaprootScriptSpendSignMethod SignMethod = 3
|
|
)
|
|
|
|
// String returns a human-readable representation of the signing method.
|
|
func (s SignMethod) String() string {
|
|
switch s {
|
|
case WitnessV0SignMethod:
|
|
return "witness_v0"
|
|
case TaprootKeySpendBIP0086SignMethod:
|
|
return "taproot_key_spend_bip86"
|
|
case TaprootKeySpendSignMethod:
|
|
return "taproot_key_spend"
|
|
case TaprootScriptSpendSignMethod:
|
|
return "taproot_script_spend"
|
|
default:
|
|
return fmt.Sprintf("unknown<%d>", s)
|
|
}
|
|
}
|
|
|
|
// PkScriptCompatible returns true if the given public key script is compatible
|
|
// with the sign method.
|
|
func (s SignMethod) PkScriptCompatible(pkScript []byte) bool {
|
|
switch s {
|
|
// SegWit v0 can be p2wkh, np2wkh, p2wsh.
|
|
case WitnessV0SignMethod:
|
|
return txscript.IsPayToWitnessPubKeyHash(pkScript) ||
|
|
txscript.IsPayToWitnessScriptHash(pkScript) ||
|
|
txscript.IsPayToScriptHash(pkScript)
|
|
|
|
case TaprootKeySpendBIP0086SignMethod, TaprootKeySpendSignMethod,
|
|
TaprootScriptSpendSignMethod:
|
|
|
|
return txscript.IsPayToTaproot(pkScript)
|
|
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// WriteSignDescriptor serializes a SignDescriptor struct into the passed
|
|
// io.Writer stream.
|
|
//
|
|
// NOTE: We assume the SigHashes and InputIndex fields haven't been assigned
|
|
// yet, since that is usually done just before broadcast by the witness
|
|
// generator.
|
|
func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
|
|
err := binary.Write(w, binary.BigEndian, sd.KeyDesc.Family)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = binary.Write(w, binary.BigEndian, sd.KeyDesc.Index)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = binary.Write(w, binary.BigEndian, sd.KeyDesc.PubKey != nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if sd.KeyDesc.PubKey != nil {
|
|
serializedPubKey := sd.KeyDesc.PubKey.SerializeCompressed()
|
|
if err := wire.WriteVarBytes(w, 0, serializedPubKey); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := wire.WriteVarBytes(w, 0, sd.SingleTweak); err != nil {
|
|
return err
|
|
}
|
|
|
|
var doubleTweakBytes []byte
|
|
if sd.DoubleTweak != nil {
|
|
doubleTweakBytes = sd.DoubleTweak.Serialize()
|
|
}
|
|
if err := wire.WriteVarBytes(w, 0, doubleTweakBytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := wire.WriteVarBytes(w, 0, sd.WitnessScript); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := writeTxOut(w, sd.Output); err != nil {
|
|
return err
|
|
}
|
|
|
|
var scratch [4]byte
|
|
binary.BigEndian.PutUint32(scratch[:], uint32(sd.HashType))
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadSignDescriptor deserializes a SignDescriptor struct from the passed
|
|
// io.Reader stream.
|
|
func ReadSignDescriptor(r io.Reader, sd *SignDescriptor) error {
|
|
err := binary.Read(r, binary.BigEndian, &sd.KeyDesc.Family)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = binary.Read(r, binary.BigEndian, &sd.KeyDesc.Index)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var hasKey bool
|
|
err = binary.Read(r, binary.BigEndian, &hasKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if hasKey {
|
|
pubKeyBytes, err := wire.ReadVarBytes(r, 0, 34, "pubkey")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sd.KeyDesc.PubKey, err = btcec.ParsePubKey(pubKeyBytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
singleTweak, err := wire.ReadVarBytes(r, 0, 32, "singleTweak")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Serializing a SignDescriptor with a nil-valued SingleTweak results
|
|
// in deserializing a zero-length slice. Since a nil-valued SingleTweak
|
|
// has special meaning and a zero-length slice for a SingleTweak is
|
|
// invalid, we can use the zero-length slice as the flag for a
|
|
// nil-valued SingleTweak.
|
|
if len(singleTweak) == 0 {
|
|
sd.SingleTweak = nil
|
|
} else {
|
|
sd.SingleTweak = singleTweak
|
|
}
|
|
|
|
doubleTweakBytes, err := wire.ReadVarBytes(r, 0, 32, "doubleTweak")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Serializing a SignDescriptor with a nil-valued DoubleTweak results
|
|
// in deserializing a zero-length slice. Since a nil-valued DoubleTweak
|
|
// has special meaning and a zero-length slice for a DoubleTweak is
|
|
// invalid, we can use the zero-length slice as the flag for a
|
|
// nil-valued DoubleTweak.
|
|
if len(doubleTweakBytes) == 0 {
|
|
sd.DoubleTweak = nil
|
|
} else {
|
|
sd.DoubleTweak, _ = btcec.PrivKeyFromBytes(doubleTweakBytes)
|
|
}
|
|
|
|
// Only one tweak should ever be set, fail if both are present.
|
|
if sd.SingleTweak != nil && sd.DoubleTweak != nil {
|
|
return ErrTweakOverdose
|
|
}
|
|
|
|
witnessScript, err := wire.ReadVarBytes(r, 0, 500, "witnessScript")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sd.WitnessScript = witnessScript
|
|
|
|
txOut := &wire.TxOut{}
|
|
if err := readTxOut(r, txOut); err != nil {
|
|
return err
|
|
}
|
|
sd.Output = txOut
|
|
|
|
var hashType [4]byte
|
|
if _, err := io.ReadFull(r, hashType[:]); err != nil {
|
|
return err
|
|
}
|
|
sd.HashType = txscript.SigHashType(binary.BigEndian.Uint32(hashType[:]))
|
|
|
|
return nil
|
|
}
|