// calcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) []byte { // The SigHashSingle signature type signs only the corresponding input // and output (the output with the same index number as the input). // // Since transactions can have more inputs than outputs, this means it // is improper to use SigHashSingle on input indices that don't have a // corresponding output. // // A bug in the original Satoshi client implementation means specifying // an index that is out of range results in a signature hash of 1 (as a // uint256 little endian). The original intent appeared to be to // indicate failure, but unfortunately, it was never checked and thus is // treated as the actual signature hash. This buggy behavior is now // part of the consensus and a hard fork would be required to fix it. // // Due to this, care must be taken by software that creates transactions // which make use of SigHashSingle because it can lead to an extremely // dangerous situation where the invalid inputs will end up signing a // hash of 1. This in turn presents an opportunity for attackers to // cleverly construct transactions which can steal those coins provided // they can reuse signatures. if hashType&sigHashMask == SigHashSingle && idx >= len(tx.TxOut) { var hash wire.ShaHash hash[0] = 0x01 return hash[:] } // Remove all instances of OP_CODESEPARATOR from the script. script = removeOpcode(script, OP_CODESEPARATOR) // Make a deep copy of the transaction, zeroing out the script for all // inputs that are not currently being processed. txCopy := tx.Copy() for i := range txCopy.TxIn { if i == idx { // UnparseScript cannot fail here because removeOpcode // above only returns a valid script. sigScript, _ := unparseScript(script) txCopy.TxIn[idx].SignatureScript = sigScript } else { txCopy.TxIn[i].SignatureScript = nil } } switch hashType & sigHashMask { case SigHashNone: txCopy.TxOut = txCopy.TxOut[0:0] // Empty slice. for i := range txCopy.TxIn { if i != idx { txCopy.TxIn[i].Sequence = 0 } } case SigHashSingle: // Resize output array to up to and including requested index. txCopy.TxOut = txCopy.TxOut[:idx+1] // All but current output get zeroed out. for i := 0; i < idx; i++ { txCopy.TxOut[i].Value = -1 txCopy.TxOut[i].PkScript = nil } // Sequence on all other inputs is 0, too. for i := range txCopy.TxIn { if i != idx { txCopy.TxIn[i].Sequence = 0 } } default: // Consensus treats undefined hashtypes like normal SigHashAll // for purposes of hash generation. fallthrough case SigHashOld: fallthrough case SigHashAll: // Nothing special here. } if hashType&SigHashAnyOneCanPay != 0 { txCopy.TxIn = txCopy.TxIn[idx : idx+1] idx = 0 } // The final hash is the double sha256 of both the serialized modified // transaction and the hash type (encoded as a 4-byte little-endian // value) appended. var wbuf bytes.Buffer txCopy.Serialize(&wbuf) binary.Write(&wbuf, binary.LittleEndian, hashType) return wire.DoubleSha256(wbuf.Bytes()) }
// Sort returns a new transaction with the inputs and outputs sorted based on // BIP LI01. The passed transaction is not modified and the new transaction // might have a different hash if any sorting was done. func Sort(tx *wire.MsgTx) *wire.MsgTx { txCopy := tx.Copy() sort.Sort(sortableInputSlice(txCopy.TxIn)) sort.Sort(sortableOutputSlice(txCopy.TxOut)) return txCopy }