123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- // Copyright (c) 2013-2015 The btcsuite developers
- // Use of this source code is governed by an ISC
- // license that can be found in the LICENSE file.
- package txscript
- import (
- "github.com/pkt-cash/pktd/btcutil/er"
- "github.com/pkt-cash/pktd/txscript/opcode"
- "github.com/pkt-cash/pktd/txscript/params"
- "github.com/pkt-cash/pktd/txscript/parsescript"
- "github.com/pkt-cash/pktd/txscript/scriptbuilder"
- "github.com/pkt-cash/pktd/btcec"
- "github.com/pkt-cash/pktd/btcutil"
- "github.com/pkt-cash/pktd/chaincfg"
- "github.com/pkt-cash/pktd/wire"
- )
- // RawTxInWitnessSignature returns the serialized ECDA signature for the input
- // idx of the given transaction, with the hashType appended to it. This
- // function is identical to RawTxInSignature, however the signature generated
- // signs a new sighash digest defined in BIP0143.
- func RawTxInWitnessSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int,
- amt int64, subScript []byte, hashType params.SigHashType,
- key *btcec.PrivateKey) ([]byte, er.R) {
- parsedScript, err := parsescript.ParseScript(subScript)
- if err != nil {
- return nil, er.Errorf("cannot parse output script: %v", err)
- }
- hash, err := calcWitnessSignatureHash(parsedScript, sigHashes, hashType, tx,
- idx, amt)
- if err != nil {
- return nil, err
- }
- signature, err := key.Sign(hash)
- if err != nil {
- return nil, er.Errorf("cannot sign tx input: %s", err)
- }
- return append(signature.Serialize(), byte(hashType)), nil
- }
- // WitnessSignature creates an input witness stack for tx to spend BTC sent
- // from a previous output to the owner of privKey using the p2wkh script
- // template. The passed transaction must contain all the inputs and outputs as
- // dictated by the passed hashType. The signature generated observes the new
- // transaction digest algorithm defined within BIP0143.
- func WitnessSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int, amt int64,
- subscript []byte, hashType params.SigHashType, privKey *btcec.PrivateKey,
- compress bool) (wire.TxWitness, er.R) {
- sig, err := RawTxInWitnessSignature(tx, sigHashes, idx, amt, subscript,
- hashType, privKey)
- if err != nil {
- return nil, err
- }
- pk := (*btcec.PublicKey)(&privKey.PublicKey)
- var pkData []byte
- if compress {
- pkData = pk.SerializeCompressed()
- } else {
- pkData = pk.SerializeUncompressed()
- }
- // A witness script is actually a stack, so we return an array of byte
- // slices here, rather than a single byte slice.
- return wire.TxWitness{sig, pkData}, nil
- }
- // RawTxInSignature returns the serialized ECDSA signature for the input idx of
- // the given transaction, with hashType appended to it.
- func RawTxInSignature(tx *wire.MsgTx, idx int, subScript []byte,
- hashType params.SigHashType, key *btcec.PrivateKey) ([]byte, er.R) {
- hash, err := CalcSignatureHash(subScript, hashType, tx, idx)
- if err != nil {
- return nil, err
- }
- signature, err := key.Sign(hash)
- if err != nil {
- return nil, er.Errorf("cannot sign tx input: %s", err)
- }
- return append(signature.Serialize(), byte(hashType)), nil
- }
- // SignatureScript creates an input signature script for tx to spend BTC sent
- // from a previous output to the owner of privKey. tx must include all
- // transaction inputs and outputs, however txin scripts are allowed to be filled
- // or empty. The returned script is calculated to be used as the idx'th txin
- // sigscript for tx. subscript is the PkScript of the previous output being used
- // as the idx'th input. privKey is serialized in either a compressed or
- // uncompressed format based on compress. This format must match the same format
- // used to generate the payment address, or the script validation will fail.
- func SignatureScript(tx *wire.MsgTx, idx int, subscript []byte, hashType params.SigHashType, privKey *btcec.PrivateKey, compress bool) ([]byte, er.R) {
- sig, err := RawTxInSignature(tx, idx, subscript, hashType, privKey)
- if err != nil {
- return nil, err
- }
- pk := (*btcec.PublicKey)(&privKey.PublicKey)
- var pkData []byte
- if compress {
- pkData = pk.SerializeCompressed()
- } else {
- pkData = pk.SerializeUncompressed()
- }
- return scriptbuilder.NewScriptBuilder().AddData(sig).AddData(pkData).Script()
- }
- func p2pkSignatureScript(tx *wire.MsgTx, idx int, subScript []byte, hashType params.SigHashType, privKey *btcec.PrivateKey) ([]byte, er.R) {
- sig, err := RawTxInSignature(tx, idx, subScript, hashType, privKey)
- if err != nil {
- return nil, err
- }
- return scriptbuilder.NewScriptBuilder().AddData(sig).Script()
- }
- // signMultiSig signs as many of the outputs in the provided multisig script as
- // possible. It returns the generated script and a boolean if the script fulfills
- // the contract (i.e. nrequired signatures are provided). Since it is arguably
- // legal to not be able to sign any of the outputs, no error is returned.
- func signMultiSig(tx *wire.MsgTx, idx int, subScript []byte, hashType params.SigHashType,
- addresses []btcutil.Address, nRequired int, kdb KeyDB) ([]byte, bool) {
- // We start with a single OP_FALSE to work around the (now standard)
- // but in the reference implementation that causes a spurious pop at
- // the end of OP_CHECKMULTISIG.
- builder := scriptbuilder.NewScriptBuilder().AddOp(opcode.OP_FALSE)
- signed := 0
- for _, addr := range addresses {
- key, _, err := kdb.GetKey(addr)
- if err != nil {
- continue
- }
- sig, err := RawTxInSignature(tx, idx, subScript, hashType, key)
- if err != nil {
- continue
- }
- builder.AddData(sig)
- signed++
- if signed == nRequired {
- break
- }
- }
- script, _ := builder.Script()
- return script, signed == nRequired
- }
- func sign(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
- subScript []byte, hashType params.SigHashType, kdb KeyDB, sdb ScriptDB) ([]byte,
- ScriptClass, []btcutil.Address, int, er.R) {
- class, addresses, nrequired, err := ExtractPkScriptAddrs(subScript,
- chainParams)
- if err != nil {
- return nil, NonStandardTy, nil, 0, err
- }
- switch class {
- case PubKeyTy:
- // look up key for address
- key, _, err := kdb.GetKey(addresses[0])
- if err != nil {
- return nil, class, nil, 0, err
- }
- script, err := p2pkSignatureScript(tx, idx, subScript, hashType,
- key)
- if err != nil {
- return nil, class, nil, 0, err
- }
- return script, class, addresses, nrequired, nil
- case PubKeyHashTy:
- // look up key for address
- key, compressed, err := kdb.GetKey(addresses[0])
- if err != nil {
- return nil, class, nil, 0, err
- }
- script, err := SignatureScript(tx, idx, subScript, hashType,
- key, compressed)
- if err != nil {
- return nil, class, nil, 0, err
- }
- return script, class, addresses, nrequired, nil
- case ScriptHashTy:
- script, err := sdb.GetScript(addresses[0])
- if err != nil {
- return nil, class, nil, 0, err
- }
- return script, class, addresses, nrequired, nil
- case MultiSigTy:
- script, _ := signMultiSig(tx, idx, subScript, hashType,
- addresses, nrequired, kdb)
- return script, class, addresses, nrequired, nil
- case NullDataTy:
- return nil, class, nil, 0,
- er.New("can't sign NULLDATA transactions")
- default:
- return nil, class, nil, 0,
- er.Errorf("can't sign unknown transactions: class = [%v]", class)
- }
- }
- // mergeScripts merges sigScript and prevScript assuming they are both
- // partial solutions for pkScript spending output idx of tx. class, addresses
- // and nrequired are the result of extracting the addresses from pkscript.
- // The return value is the best effort merging of the two scripts. Calling this
- // function with addresses, class and nrequired that do not match pkScript is
- // an error and results in undefined behavior.
- func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
- pkScript []byte, class ScriptClass, addresses []btcutil.Address,
- nRequired int, sigScript, prevScript []byte) []byte {
- // TODO: the scripthash and multisig paths here are overly
- // inefficient in that they will recompute already known data.
- // some internal refactoring could probably make this avoid needless
- // extra calculations.
- switch class {
- case ScriptHashTy:
- // Remove the last push in the script and then recurse.
- // this could be a lot less inefficient.
- sigPops, err := parsescript.ParseScript(sigScript)
- if err != nil || len(sigPops) == 0 {
- return prevScript
- }
- prevPops, err := parsescript.ParseScript(prevScript)
- if err != nil || len(prevPops) == 0 {
- return sigScript
- }
- // assume that script in sigPops is the correct one, we just
- // made it.
- script := sigPops[len(sigPops)-1].Data
- // We already know this information somewhere up the stack.
- class, addresses, nrequired, _ :=
- ExtractPkScriptAddrs(script, chainParams)
- // regenerate scripts.
- sigScript, _ := unparseScript(sigPops)
- prevScript, _ := unparseScript(prevPops)
- // Merge
- mergedScript := mergeScripts(chainParams, tx, idx, script,
- class, addresses, nrequired, sigScript, prevScript)
- // Reappend the script and return the result.
- builder := scriptbuilder.NewScriptBuilder()
- builder.AddOps(mergedScript)
- builder.AddData(script)
- finalScript, _ := builder.Script()
- return finalScript
- case MultiSigTy:
- return mergeMultiSig(tx, idx, addresses, nRequired, pkScript,
- sigScript, prevScript)
- // It doesn't actually make sense to merge anything other than multiig
- // and scripthash (because it could contain multisig). Everything else
- // has either zero signature, can't be spent, or has a single signature
- // which is either present or not. The other two cases are handled
- // above. In the conflict case here we just assume the longest is
- // correct (this matches behavior of the reference implementation).
- default:
- if len(sigScript) > len(prevScript) {
- return sigScript
- }
- return prevScript
- }
- }
- // mergeMultiSig combines the two signature scripts sigScript and prevScript
- // that both provide signatures for pkScript in output idx of tx. addresses
- // and nRequired should be the results from extracting the addresses from
- // pkScript. Since this function is internal only we assume that the arguments
- // have come from other functions internally and thus are all consistent with
- // each other, behavior is undefined if this contract is broken.
- func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []btcutil.Address,
- nRequired int, pkScript, sigScript, prevScript []byte) []byte {
- // This is an internal only function and we already parsed this script
- // as ok for multisig (this is how we got here), so if this fails then
- // all assumptions are broken and who knows which way is up?
- pkPops, _ := parsescript.ParseScript(pkScript)
- sigPops, err := parsescript.ParseScript(sigScript)
- if err != nil || len(sigPops) == 0 {
- return prevScript
- }
- prevPops, err := parsescript.ParseScript(prevScript)
- if err != nil || len(prevPops) == 0 {
- return sigScript
- }
- // Convenience function to avoid duplication.
- extractSigs := func(pops []parsescript.ParsedOpcode, sigs [][]byte) [][]byte {
- for _, pop := range pops {
- if len(pop.Data) != 0 {
- sigs = append(sigs, pop.Data)
- }
- }
- return sigs
- }
- possibleSigs := make([][]byte, 0, len(sigPops)+len(prevPops))
- possibleSigs = extractSigs(sigPops, possibleSigs)
- possibleSigs = extractSigs(prevPops, possibleSigs)
- // Now we need to match the signatures to pubkeys, the only real way to
- // do that is to try to verify them all and match it to the pubkey
- // that verifies it. we then can go through the addresses in order
- // to build our script. Anything that doesn't parse or doesn't verify we
- // throw away.
- addrToSig := make(map[string][]byte)
- sigLoop:
- for _, sig := range possibleSigs {
- // can't have a valid signature that doesn't at least have a
- // hashtype, in practice it is even longer than this. but
- // that'll be checked next.
- if len(sig) < 1 {
- continue
- }
- tSig := sig[:len(sig)-1]
- hashType := params.SigHashType(sig[len(sig)-1])
- pSig, err := btcec.ParseDERSignature(tSig, btcec.S256())
- if err != nil {
- continue
- }
- // We have to do this each round since hash types may vary
- // between signatures and so the hash will vary. We can,
- // however, assume no sigs etc are in the script since that
- // would make the transaction nonstandard and thus not
- // MultiSigTy, so we just need to hash the full thing.
- hash := calcSignatureHash(pkPops, hashType, tx, idx)
- for _, addr := range addresses {
- // All multisig addresses should be pubkey addresses
- // it is an error to call this internal function with
- // bad input.
- pkaddr := addr.(*btcutil.AddressPubKey)
- if pkaddr == nil {
- panic("mergeMultiSig: pkaddr == nil")
- }
- pubKey := pkaddr.PubKey()
- if pubKey == nil {
- panic("mergeMultiSig: pubKey == nil")
- }
- // If it matches we put it in the map. We only
- // can take one signature per public key so if we
- // already have one, we can throw this away.
- if pSig.Verify(hash, pubKey) {
- aStr := addr.EncodeAddress()
- if _, ok := addrToSig[aStr]; !ok {
- addrToSig[aStr] = sig
- }
- continue sigLoop
- }
- }
- }
- // Extra opcode to handle the extra arg consumed (due to previous bugs
- // in the reference implementation).
- builder := scriptbuilder.NewScriptBuilder().AddOp(opcode.OP_FALSE)
- doneSigs := 0
- // This assumes that addresses are in the same order as in the script.
- for _, addr := range addresses {
- sig, ok := addrToSig[addr.EncodeAddress()]
- if !ok {
- continue
- }
- builder.AddData(sig)
- doneSigs++
- if doneSigs == nRequired {
- break
- }
- }
- // padding for missing ones.
- for i := doneSigs; i < nRequired; i++ {
- builder.AddOp(opcode.OP_0)
- }
- script, _ := builder.Script()
- return script
- }
- // KeyDB is an interface type provided to SignTxOutput, it encapsulates
- // any user state required to get the private keys for an address.
- type KeyDB interface {
- GetKey(btcutil.Address) (*btcec.PrivateKey, bool, er.R)
- }
- // KeyClosure implements KeyDB with a closure.
- type KeyClosure func(btcutil.Address) (*btcec.PrivateKey, bool, er.R)
- // GetKey implements KeyDB by returning the result of calling the closure.
- func (kc KeyClosure) GetKey(address btcutil.Address) (*btcec.PrivateKey,
- bool, er.R) {
- return kc(address)
- }
- // ScriptDB is an interface type provided to SignTxOutput, it encapsulates any
- // user state required to get the scripts for an pay-to-script-hash address.
- type ScriptDB interface {
- GetScript(btcutil.Address) ([]byte, er.R)
- }
- // ScriptClosure implements ScriptDB with a closure.
- type ScriptClosure func(btcutil.Address) ([]byte, er.R)
- // GetScript implements ScriptDB by returning the result of calling the closure.
- func (sc ScriptClosure) GetScript(address btcutil.Address) ([]byte, er.R) {
- return sc(address)
- }
- // SignTxOutput signs output idx of the given tx to resolve the script given in
- // pkScript with a signature type of hashType. Any keys required will be
- // looked up by calling getKey() with the string of the given address.
- // Any pay-to-script-hash signatures will be similarly looked up by calling
- // getScript. If previousScript is provided then the results in previousScript
- // will be merged in a type-dependent manner with the newly generated.
- // signature script.
- func SignTxOutput(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
- pkScript []byte, hashType params.SigHashType, kdb KeyDB, sdb ScriptDB,
- previousScript []byte) ([]byte, er.R) {
- sigScript, class, addresses, nrequired, err := sign(chainParams, tx,
- idx, pkScript, hashType, kdb, sdb)
- if err != nil {
- return nil, err
- }
- if class == ScriptHashTy {
- // TODO keep the sub addressed and pass down to merge.
- realSigScript, _, _, _, err := sign(chainParams, tx, idx,
- sigScript, hashType, kdb, sdb)
- if err != nil {
- return nil, err
- }
- // Append the p2sh script as the last push in the script.
- builder := scriptbuilder.NewScriptBuilder()
- builder.AddOps(realSigScript)
- builder.AddData(sigScript)
- sigScript, _ = builder.Script()
- // TODO keep a copy of the script for merging.
- }
- // Merge scripts. with any previous data, if any.
- mergedScript := mergeScripts(chainParams, tx, idx, pkScript, class,
- addresses, nrequired, sigScript, previousScript)
- return mergedScript, nil
- }
|