z can be calculated more easily from the raw transaction.
To get z this way, you have to simply delete all the script signatures in the raw transaction. Then place the script_pubkey of the input you are trying to evaluate where the script_sig used to be. (in the case of a multi-signature transaction you have to replace the scriptSigs for the correspondent redeem script).
This has to be done for each input, so the raw transaction will contain no script_sigs at all, and only one script_pubkey (where the script_sig was for the input being evaluated).
Then, you have to append the type of sig_hash which is almost always SIGHASH_ALL at the end of the raw transaction. The sighash field has 4 bytes of length and SIGHASH_ALL has the code value of 1, which is represented by
01000000 in hexadecimal which is 1 in little endian.
After you empty all the script_sigs, and put the script_pubkey of the input being evaluated, and also append the
01000000 at the end of the raw transaction, you can procede to calculate the double SHA256 (HASH256) of the modified raw transaction. Check out https://en.bitcoin.it/wiki/OP_CHECKSIG.
The outcome of this hash will be interpreted as a big-endian integer, and that will be your z for the particular input.
You have to repeat this for every input, so there is a different z for each input.
To evaluate your signatures (r,s), you will have to use the mathematical formula of the ECDSA which is:
A) uG + vP = R.
B) kG = R.
C) u=z/s; v=r/s
G is the originating point of the secp256k1. https://en.bitcoin.it/wiki/Secp256k1
P is the point of the public key on the curve.
u and v are integer scalars and, therefore, uG and vP are points on the curve.
R is just another point in the curve as a result of the addition of the other 2 points uG and vP , and will be the point that will verify the signature.
If you already have r and s (as is implied from your question), and you already calculated z, then you can calculate u and v from the formulas in C. Once you get u and v, and since you have your Public key P and G is defined by the secp256k1, then you can procede to calculate R from formula A. Just remember that this addition happens on the curve which is also on a finite field.
Once you get R, you will extract the x coordinate of this point on the curve which has to be exactly the same as r from the signature. If they match, the signature is correct.
If you want some code to get z, here is a function from an excellent book called Programming Bitcoin by Jimmy Song :
def sig_hash(self, input_index):
s = int_to_little_endian(self.version, 4)
s += encode_varint(len(self.tx_ins))
for i, tx_in in enumerate(self.tx_ins):
if i == input_index:
s += TxIn(
s += TxIn(
s += encode_varint(len(self.tx_outs))
for tx_out in self.tx_outs:
s += tx_out.serialize()
s += int_to_little_endian(self.locktime, 4)
s += int_to_little_endian(SIGHASH_ALL, 4)
h256 = hash256(s)
return int.from_bytes(h256, 'big')
However, you will have to take into account that this is just for the basic case of a P2PKH. In a P2SH transaction you will have a small variation.