github.com/decred/dcrlnd@v0.7.6/input/signdescriptor.go (about)

     1  package input
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"io"
     7  
     8  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     9  	"github.com/decred/dcrd/txscript/v4"
    10  	"github.com/decred/dcrd/wire"
    11  	"github.com/decred/dcrlnd/keychain"
    12  )
    13  
    14  var (
    15  	// ErrTweakOverdose signals a SignDescriptor is invalid because both of its
    16  	// SingleTweak and DoubleTweak are non-nil.
    17  	ErrTweakOverdose = errors.New("sign descriptor should only have one tweak")
    18  )
    19  
    20  // SignDescriptor houses the necessary information required to successfully sign
    21  // a given output. This struct is used by the Signer interface in order to gain
    22  // access to critical data needed to generate a valid signature.
    23  type SignDescriptor struct {
    24  	// KeyDesc is a descriptor that precisely describes *which* key to use
    25  	// for signing. This may provide the raw public key directly, or
    26  	// require the Signer to re-derive the key according to the populated
    27  	// derivation path.
    28  	KeyDesc keychain.KeyDescriptor
    29  
    30  	// SingleTweak is a scalar value that will be added to the private key
    31  	// corresponding to the above public key to obtain the private key to
    32  	// be used to sign this input. This value is typically derived via the
    33  	// following computation:
    34  	//
    35  	//  * derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
    36  	//
    37  	// NOTE: If this value is nil, then the input can be signed using only
    38  	// the above public key. Either a SingleTweak should be set or a
    39  	// DoubleTweak, not both.
    40  	SingleTweak []byte
    41  
    42  	// DoubleTweak is a private key that will be used in combination with
    43  	// its corresponding private key to derive the private key that is to
    44  	// be used to sign the target input. Within the Lightning protocol,
    45  	// this value is typically the commitment secret from a previously
    46  	// revoked commitment transaction. This value is in combination with
    47  	// two hash values, and the original private key to derive the private
    48  	// key to be used when signing.
    49  	//
    50  	//  * k = (privKey*sha256(pubKey || tweakPub) +
    51  	//        tweakPriv*sha256(tweakPub || pubKey)) mod N
    52  	//
    53  	// NOTE: If this value is nil, then the input can be signed using only
    54  	// the above public key. Either a SingleTweak should be set or a
    55  	// DoubleTweak, not both.
    56  	DoubleTweak *secp256k1.PrivateKey
    57  
    58  	// WitnessScript is the full script required to properly redeem the
    59  	// output. This field will only be populated if a p2sh
    60  	// output is being signed.
    61  	//
    62  	// On Decred this is usually referred to as the "redeemScript".
    63  	WitnessScript []byte
    64  
    65  	// Output is the target output which should be signed. The PkScript and
    66  	// Value fields within the output should be properly populated,
    67  	// otherwise an invalid signature may be generated.
    68  	Output *wire.TxOut
    69  
    70  	// HashType is the target sighash type that should be used when
    71  	// generating the final sighash, and signature.
    72  	HashType txscript.SigHashType
    73  
    74  	// InputIndex is the target input within the transaction that should be
    75  	// signed.
    76  	InputIndex int
    77  }
    78  
    79  // WriteSignDescriptor serializes a SignDescriptor struct into the passed
    80  // io.Writer stream.
    81  //
    82  // NOTE: We assume the SigHashes and InputIndex fields haven't been assigned
    83  // yet, since that is usually done just before broadcast by the witness
    84  // generator.
    85  func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
    86  	err := binary.Write(w, binary.BigEndian, sd.KeyDesc.Family)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	err = binary.Write(w, binary.BigEndian, sd.KeyDesc.Index)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	err = binary.Write(w, binary.BigEndian, sd.KeyDesc.PubKey != nil)
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	if sd.KeyDesc.PubKey != nil {
   101  		serializedPubKey := sd.KeyDesc.PubKey.SerializeCompressed()
   102  		if err := wire.WriteVarBytes(w, 0, serializedPubKey); err != nil {
   103  			return err
   104  		}
   105  	}
   106  
   107  	if err := wire.WriteVarBytes(w, 0, sd.SingleTweak); err != nil {
   108  		return err
   109  	}
   110  
   111  	var doubleTweakBytes []byte
   112  	if sd.DoubleTweak != nil {
   113  		doubleTweakBytes = sd.DoubleTweak.Serialize()
   114  	}
   115  	if err := wire.WriteVarBytes(w, 0, doubleTweakBytes); err != nil {
   116  		return err
   117  	}
   118  
   119  	if err := wire.WriteVarBytes(w, 0, sd.WitnessScript); err != nil {
   120  		return err
   121  	}
   122  
   123  	if err := writeTxOut(w, sd.Output); err != nil {
   124  		return err
   125  	}
   126  
   127  	var scratch [4]byte
   128  	binary.BigEndian.PutUint32(scratch[:], uint32(sd.HashType))
   129  	if _, err := w.Write(scratch[:]); err != nil {
   130  		return err
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  // ReadSignDescriptor deserializes a SignDescriptor struct from the passed
   137  // io.Reader stream.
   138  func ReadSignDescriptor(r io.Reader, sd *SignDescriptor) error {
   139  	err := binary.Read(r, binary.BigEndian, &sd.KeyDesc.Family)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	err = binary.Read(r, binary.BigEndian, &sd.KeyDesc.Index)
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	var hasKey bool
   149  	err = binary.Read(r, binary.BigEndian, &hasKey)
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	if hasKey {
   155  		pubKeyBytes, err := wire.ReadVarBytes(r, 0, 34, "pubkey")
   156  		if err != nil {
   157  			return err
   158  		}
   159  		sd.KeyDesc.PubKey, err = secp256k1.ParsePubKey(pubKeyBytes)
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	singleTweak, err := wire.ReadVarBytes(r, 0, 32, "singleTweak")
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	// Serializing a SignDescriptor with a nil-valued SingleTweak results
   171  	// in deserializing a zero-length slice. Since a nil-valued SingleTweak
   172  	// has special meaning and a zero-length slice for a SingleTweak is
   173  	// invalid, we can use the zero-length slice as the flag for a
   174  	// nil-valued SingleTweak.
   175  	if len(singleTweak) == 0 {
   176  		sd.SingleTweak = nil
   177  	} else {
   178  		sd.SingleTweak = singleTweak
   179  	}
   180  
   181  	doubleTweakBytes, err := wire.ReadVarBytes(r, 0, 32, "doubleTweak")
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	// Serializing a SignDescriptor with a nil-valued DoubleTweak results
   187  	// in deserializing a zero-length slice. Since a nil-valued DoubleTweak
   188  	// has special meaning and a zero-length slice for a DoubleTweak is
   189  	// invalid, we can use the zero-length slice as the flag for a
   190  	// nil-valued DoubleTweak.
   191  	if len(doubleTweakBytes) == 0 {
   192  		sd.DoubleTweak = nil
   193  	} else {
   194  		sd.DoubleTweak = secp256k1.PrivKeyFromBytes(doubleTweakBytes)
   195  	}
   196  
   197  	// Only one tweak should ever be set, fail if both are present.
   198  	if sd.SingleTweak != nil && sd.DoubleTweak != nil {
   199  		return ErrTweakOverdose
   200  	}
   201  
   202  	witnessScript, err := wire.ReadVarBytes(r, 0, 500, "witnessScript")
   203  	if err != nil {
   204  		return err
   205  	}
   206  	sd.WitnessScript = witnessScript
   207  
   208  	txOut := &wire.TxOut{}
   209  	if err := readTxOut(r, txOut); err != nil {
   210  		return err
   211  	}
   212  	sd.Output = txOut
   213  
   214  	var hashType [4]byte
   215  	if _, err := io.ReadFull(r, hashType[:]); err != nil {
   216  		return err
   217  	}
   218  	sd.HashType = txscript.SigHashType(binary.BigEndian.Uint32(hashType[:]))
   219  
   220  	return nil
   221  }