Bitcoin source reading - content of signature (signing < message >)

The most commonly used transaction mode in bitcoin: the composition of the signed content "message" in P2P KH

1, Unlocking and locking script (P2PKH: payment to public key hash)


The figure above shows the unlocking process of P2P KH transaction. It is also the most commonly used transaction mode of bitcoin.
Record the generation of sig.

2, Creation of transactions

1. Whether the available UTXO traversing its own address is greater than the amount of the transaction.
2 Calculation of transaction fee
 3 if utxo > = fee + amount is available, start organizing transactions.
	1> Generate TxOut output one by one and add it to the array (including transfer address and change address).
	2> TxIn is generated from UTXO and added to the array.
	3> Sign the TxIn in the TxIn array one by one.
	4> Send transaction information.

TxIn is signed one by one, including the following types:
The following table information is taken from: btcd source parsing signature mechanism (1) - basic knowledge
"Signature types", more accurately known as Signature Hash Types, mainly include four basic types: sighash ũ all, sighash ũ none, sighash ũ single, sighash ũ anyonecanpay

Basic types Simple description purpose
SIGHASH_ALL message contains all output Default type, most widely used
SIGHASH_NONE message does not contain any output Allow anyone to spend this money by building output
SIGHASH_SINGLE message contains a specific (corresponding to the input) output Ensure that your output is not tampered with, but allow other people's output to be changed
SIGHASH_ANYONECANPAY message contains the current input Allow anyone to build input, that is, allow anyone to enter amount into the transaction

It's easy to find that the first three (sighash ﹐ all, sighash ﹐ none, sighash ﹐ single) are mainly used to limit output, while sighash ﹐ anyonecanpay is used to limit input. In any signature, you need to specify one of the first three (optionally) to be decorated with sighash ﹣ anyonecanpay.

classification Combination type Simple description purpose
No modification class SIGHASH_ALL message contains all input and output Default type, most widely used
No modification class SIGHASH_NONE message contains all input, not any output Allow anyone to spend this money by building output
No modification class SIGHASH_SINGLE message contains all input and specific (corresponding to input) output Ensure that your output is not tampered with, but allow other people's output to be changed
Modified class SIGHASH_ALL | SIGHASH_ANYONECANPAY message contains all output and current input Often used to fund "crowdfunding"
Modified class SIGHASH_NONE | SIGHASH_ANYONECANPAY message contains only the current input, not any output Allow anyone to enter the amount and anyone to spend it
Modified class SIGHASH_SINGLE | SIGHASH_ANYONECANPAY message contains only the current input and the corresponding output Allow anyone to input the amount, and ensure that the corresponding output is not tampered with

Here we focus on the most common form, SIGHASH_ALL

3, Organization process of signature content (message) (sighash_alltype)

1 hashPrevouts; // All the transaction id(hash) and sequence n of UTXO referenced in the input (vin array) are summed up and the hash obtained by sha256 is done.
2 hashSequence; // After summarizing all the nsequences in the above figure, do the hash obtained by sha256.
3 hashOutputs;  // After the nValue and scriptPubKey of all output (vout array) are summarized, the hash obtained by sha256 is done.

In addition to the above three variables, there are other information components, including nVersion, Nin (how many inputs in total), and so on.

4, Source related

Function call process:
Where Solver( )Function to get whether the script locking mode is P2PKH or P2SH, etc.
CWallet::CreateTransaction(… ) -> ProduceSignature(… ) -> SignStep(… ) -> Solver(… ) ->Sign1(… ) -> TransactionSignatureCreator::CreateSig(… ) -> SignatureHash(… )And CKey::Sign( );
Here is the SignatureHash() function

uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
    assert(nIn < txTo.vin.size());

    if (sigversion == SIGVERSION_WITNESS_V0) {
        uint256 hashPrevouts;
        uint256 hashSequence;
        uint256 hashOutputs;
        const bool cacheready = cache && cache->ready;

		// Obtain the above three main data
        if (!(nHashType & SIGHASH_ANYONECANPAY)) {
            hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
        }

        if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
            hashSequence = cacheready ? cache->hashSequence : GetSequenceHash(txTo);
        }


        if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
            hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo);
        } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
            CHashWriter ss(SER_GETHASH, 0);
            ss << txTo.vout[nIn];
            hashOutputs = ss.GetHash();
        }

		// Summarize all used signature data (message) including the above three main data
        CHashWriter ss(SER_GETHASH, 0);
        // Version
        ss << txTo.nVersion;
        // Input prevouts/nSequence (none/all, depending on flags)
        ss << hashPrevouts;
        ss << hashSequence;
        // The input being signed (replacing the scriptSig with scriptCode + amount)
        // The prevout may already be contained in hashPrevout, and the nSequence
        // may already be contain in hashSequence.
        ss << txTo.vin[nIn].prevout;
        ss << scriptCode;
        ss << amount;
        ss << txTo.vin[nIn].nSequence;
        // Outputs (none/one/all, depending on flags)
        ss << hashOutputs;
        // Locktime
        ss << txTo.nLockTime;
        // Sighash type
        ss << nHashType;

        return ss.GetHash();
    }

The generation process of three main data: hashPrevouts, hashSequence, and hashOutputs:

uint256 GetPrevoutHash(const CTransaction& txTo) {
    CHashWriter ss(SER_GETHASH, 0);
    for (const auto& txin : txTo.vin) {
        ss << txin.prevout; // prevout is of type COutPoint
    }
    return ss.GetHash();
}

class COutPoint
{
public:
    uint256 hash;
    uint32_t n;
	...
    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    // Serialize hash and n into byte stream s
    inline void SerializationOp(Stream& s, Operation ser_action) {
        READWRITE(hash);
        READWRITE(n);
    }
    ...
};

uint256 GetSequenceHash(const CTransaction& txTo) {
    CHashWriter ss(SER_GETHASH, 0);
    for (const auto& txin : txTo.vin) {
        ss << txin.nSequence; // nSequence is of type int
    }
    return ss.GetHash();
}

uint256 GetOutputsHash(const CTransaction& txTo) {
    CHashWriter ss(SER_GETHASH, 0);
    for (const auto& txout : txTo.vout) {
        ss << txout; // txout is of type CTxOut
    }
    return ss.GetHash();
}

class CTxOut
{
public:
    CAmount nValue;
    CScript scriptPubKey;
	...
    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    // Serialize nValue and scriptPubKey into byte streams
    inline void SerializationOp(Stream& s, Operation ser_action) {
        READWRITE(nValue);
        READWRITE(scriptPubKey);
    }
    ...
};

CKey::Sign() function is the process of signing using secp256k1 elliptic curve encryption function library:

bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const 
{
    if (!fValid)
        return false;
    vchSig.resize(72);
    size_t nSigLen = 72;
    unsigned char extra_entropy[32] = {0};
    WriteLE32(extra_entropy, test_case);
    secp256k1_ecdsa_signature sig;
    int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr);
    assert(ret);
    secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)vchSig.data(), &nSigLen, &sig);
    vchSig.resize(nSigLen);
    return true;
}

After obtaining all the contents that need to be signed through the SignatureHash() function, call the Key::Sign() function to sign. Then update the signature information to the scriptSig field in vin, and it is finished.

*Note: This article is for personal notes. If there is something wrong, please correct it.

Welcome to the official account of idler's casual talk. We look forward to sharing technology with you.

27 original articles published, 35 praised, 130000 visitors+
Private letter follow

Posted by sitestem on Mon, 09 Mar 2020 23:47:52 -0700