• Tidak ada hasil yang ditemukan

Checking the Signature

Perhaps the trickiest part of validating a transaction is the process of checking its sig‐

natures. A transaction typically has at least one signature per input. If there are multi‐

sig outputs being spent, there may be more than one. As we learned in Chapter 3, the ECDSA signature algorithm requires the public key P, the signature hash z, and the signature (r,s). Once these are known, the process of verifying the signature is pretty simple, as we already coded in Chapter 3:

Validating Transactions | 131

>>> from ecc import S256Point, Signature

>>> sec = bytes.fromhex('0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e\

213bf016b278a')

>>> der = bytes.fromhex('3045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031c\

cfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9\

c8e10615bed')

>>> z = 0x27e0c5994dec7824e56dec6b2fcb342eb7cdb0d0957c2fce9882f715e85d81a6

>>> point = S256Point.parse(sec)

>>> signature = Signature.parse(der)

>>> print(point.verify(z, signature)) True

SEC public keys and DER signatures are in the stack when a command like OP_CHECK SIG is executed, making getting the public key and signature pretty straightforward (see Chapter 6). The hard part is getting the signature hash. A naive way to do this would be to hash the transaction serialization as shown in Figure 7-1. Unfortunately, we can’t do that, since the signature is part of the ScriptSig and a signature can’t sign itself.

Figure 7-1. A signature is in the yellow highlighted part, or the ScriptSig

Instead, we modify the transaction before signing it. That is, we compute a different signature hash for each input. The procedure is as follows.

Step 1: Empty all the ScriptSigs

The first step is to empty all the ScriptSigs when checking the signature (Figure 7-2).

The same procedure is used for creating the signature, except the ScriptSigs are usu‐

ally already empty.

Figure 7-2. Empty each input’s ScriptSig (in yellow highlighted field, now 00)

Note that this example has only one input, so only that input’s ScriptSig is emptied, but it’s possible to have more than one input. In that case, each of those would be emptied.

Step 2: Replace the ScriptSig of the input being signed with the previous ScriptPubKey

Each input points to a previous transaction output, which has a ScriptPubKey. Recall the diagram from Chapter 6, shown again in Figure 7-3.

Figure 7-3. Combining the ScriptPubKey and ScriptSig

We take the ScriptPubKey that the input is pointing to and put that in place of the empty ScriptSig (Figure 7-4). This may require a lookup on the blockchain, but in practice the signer already knows the ScriptPubKey, as the input is one where the signer has the private key.

Figure 7-4. Replace the ScriptSig (yellow highlighted field) for one of the inputs with the previous ScriptPubKey

Step 3: Append the hash type

Last, we add a 4-byte hash type to the end. This is to specify what the signature is authorizing. The signature can authorize this input to go with all the other inputs and outputs (SIGHASH_ALL), go with a specific output (SIGHASH_SINGLE), or go with any output whatsoever (SIGHASH_NONE). The latter two have some theoretical use cases, but in practice, almost every transaction is signed with SIGHASH_ALL. There’s also a rarely used hash type called SIGHASH_ANYONECANPAY that can be combined with any of the previous three, which we won’t get into here. For SIGHASH_ALL, the final transac‐

tion must have the exact outputs that were signed or the input signature is invalid.

The integer corresponding to SIGHASH_ALL is 1 and this has to be encoded in little- endian over 4 bytes, which makes the modified transaction look like Figure 7-5.

Validating Transactions | 133

Figure 7-5. Append the hash type (SIGHASH_ALL), or the brown 01000000

The hash256 of this modified transaction is interpreted as a big-endian integer to produce z. The code for converting the modified transaction to z looks like this:

>>> from helper import hash256

>>> modified_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914\

bd1d96a3f5f71bf8303c6a989c7d1000000001976a914a802fc56c704ce87c42d7c92eb75e7896\

bdc41ae88acfeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02\

e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288a\

c1943060001000000')

>>> h256 = hash256(modified_tx)

>>> z = int.from_bytes(h256, 'big')

>>> print(hex(z))

0x27e0c5994dec7824e56dec6b2fcb342eb7cdb0d0957c2fce9882f715e85d81a6

Now that we have our z, we can take the public key in SEC format and the signature in DER format from the ScriptSig to verify the signature:

>>> from ecc import S256Point, Signature

>>> sec = bytes.fromhex('0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e\

213bf016b278a')

>>> der = bytes.fromhex('3045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031c\

cfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9\

c8e10615bed')

>>> z = 0x27e0c5994dec7824e56dec6b2fcb342eb7cdb0d0957c2fce9882f715e85d81a6

>>> point = S256Point.parse(sec)

>>> signature = Signature.parse(der)

>>> point.verify(z, signature) True

We can code this transaction validation process into a method for Tx. Thankfully, the Script engine can already handle signature verification (see Chapter 6), so our task here is to glue everything together. We need z, or the signature hash, to pass into the evaluate method and we need to combine the ScriptSig and ScriptPubKey.

Quadratic Hashing

The signature hashing algorithm is inefficient and wasteful. The quadratic hashing problem states that time required to calculate the signature hashes increases quadratically with the number of inputs in a transaction. Specifically, not only will the number of hash256 operations for calculating z increase on a per-input basis, but in addition, the length of the transaction will increase, slowing down each hash256 operation because the entire signature hash will need to be calculated anew for each input.

This was particularly obvious with the biggest transaction mined to date:

bb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2 b4e3e08

This transaction had 5,569 inputs and 1 output and took many miners over a minute to validate, as the signature hashes for the transaction were expensive to calculate.

Segwit (Chapter 13) fixes this with a different way of calculating the signature hash, which is specified in BIP0143.

Exercise 1

Write the sig_hash method for the Tx class.

Exercise 2

Write the verify_input method for the Tx class. You will want to use the TxIn.script_pubkey, Tx.sig_hash, and Script.evaluate methods.

Dokumen terkait