OP_CHECKSIG
The entire transaction’s outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise.
from ecc import ( S256Point, Signature, ) def op_checksig(stack, z): if len(stack) < 1: return False sec_pubkey = stack.pop() der_signature = stack.pop()[:-1] try: point = S256Point.parse(sec_pubkey) sig = Signature.parse(der_signature) except (ValueError, SyntaxError) as e: return False if point.verify(z, sig): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
class S256Point(Point): @classmethod def parse(self, sec_bin): if sec_bin[0] == 4: x = int.from_bytes(sec_bin[1:33], 'big') y = int.from_bytes(sec_bin[33:65], 'big') return S256Point(x=x, y=y) is_even = sec_bin[0] == 2 x = S256Field(int.from_bytes(sec_bin[1:], 'big')) alpha = x**3 + S256Field(B) beta = alpha.sqrt() if beta.num % 2 == 0: even_beta = beta odd_beta = S256Field(P - beta.num) else: even_beta = S256Field(P - beta.num) odd_beta = beta if is_even: return S256Point(x, even_beta) else: return S256Point(x, odd_beta) class Signature: @classmethod def parse(cls, signature_bin): s = BytesIO(signature_bin) compound = s.read(1)[0] if compound != 0x30: raise SyntaxError("Bad Signature") length = s.read(1)[0] if length + 2 != len(signature_bin): raise SyntaxError("Bad Signature Length") marker = s.read(1)[0] if marker != 0x02: raise SyntaxError("Bad Signature") rlength = s.read(1)[0] r = int.from_bytes(s.read(rlength), 'big') marker = s.read(1)[0] if marker != 0x02: raise SyntaxError("Bad Signature") slength = s.read(1)[0] s = int.from_bytes(s.read(slength), 'big') if len(signature_bin) != 6 + rlength + slength: raise SyntaxError("Signature too long") return cls(r, s) class S256Point(Point): def verify(self, z, sig): s_inv = pow(sig.s, N - 2, N) u = z * s_inv % N v = sig.r * s_inv % N total = u * G + v * self return total.x.num == sig.r