def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # Exercise 1.1: get the relevant input tx_in = self.tx_ins[input_index] # Exercise 6.2: get the number of signatures required. This is available in tx_in.script_sig.num_sigs_required() if tx_in.script_sig.type() == 'blank': if tx_in.script_pubkey().type() == 'p2wpkh': sigs_required = 1 # TODO: refactor # witness program verification if hash160(tx_in.script_witness[1]) != tx_in.script_pubkey().elements[-1]: return False point = S256Point.parse(tx_in.script_witness[1]) der, hash_type = tx_in.der_signature() signature = Signature.parse(der) z = self.sig_hash(input_index, hash_type) if not point.verify(z, signature): return False #elif tx_in.script_pubkey().type() == 'p2wsh': # sigs_required = 1 # point = S256Point.parse(tx_in.script_witness[1]) # der, hash_type = tx_in.der_signature() # signature = Signature.parse(der) # z = self.sig_hash(input_index, hash_type) # if not point.verify(z, signature): # return False else: raise RuntimeError("other witness type not yet supported") else: sigs_required = tx_in.script_sig.num_sigs_required() # Exercise 6.2: iterate over the sigs required and check each signature for sig_num in range(sigs_required): # Exercise 1.1: get the point from the sec format (tx_in.sec_pubkey()) # Exercise 6.2: get the sec_pubkey at current signature index (check sec_pubkey function) point = S256Point.parse(tx_in.sec_pubkey(index=sig_num)) # Exercise 1.1: get the der sig and hash_type from input # Exercise 6.2: get the der_signature at current signature index (check der_signature function) der, hash_type = tx_in.der_signature(index=sig_num) # Exercise 1.1: get the signature from der format signature = Signature.parse(der) # Exercise 1.1: get the hash to sign z = self.sig_hash(input_index, hash_type) # Exercise 1.1: use point.verify on the hash to sign and signature if not point.verify(z, signature): return False return True
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # get the relevant input tx_in = self.tx_ins[input_index] # get the number of signatures required. This is available in tx_in.script_sig.num_sigs_required() sigs_required = tx_in.script_sig.num_sigs_required() # iterate over the sigs required and check each signature for sig_num in range(sigs_required): # get the point from the sec format sec = tx_in.sec_pubkey(index=sig_num) # get the sec_pubkey at current signature index point = S256Point.parse(sec) # get the der sig and hash_type from input # get the der_signature at current signature index der, hash_type = tx_in.der_signature(index=sig_num) # get the signature from der format signature = Signature.parse(der) # get the hash to sign if tx_in.is_segwit(): h160 = hash160(tx_in.script_sig.redeem_script()) if h160 != tx_in.script_pubkey(self.testnet).elements[1]: return False pubkey_h160 = tx_in.script_sig.redeem_script()[-20:] if pubkey_h160 != point.h160(): return False z = self.sig_hash_bip143(input_index, hash_type) else: z = self.sig_hash(input_index, hash_type) # use point.verify on the hash to sign and signature if not point.verify(z, signature): return False return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): der_signatures.append(stack.pop()[:-1]) stack.pop() try: points = [S256Point.parse(sec) for sec in sec_pubkeys] sigs = [Signature.parse(der) for der in der_signatures] for sig in sigs: if len(points) == 0: print("signatures no good or not in right order") return False while points: point = points.pop(0) if point.verify(z, sig): break stack.append(encode_num(1)) except (ValueError, SyntaxError): return False return True
def op_checksig(stack, z): # check that there are at least 2 elements on the stack if len(stack) < 2: return False # the top element of the stack is the SEC pubkey pubkey = stack.pop() # the next element of the stack is the DER signature # take off the last byte of the signature as that's the hash_type #맨 뒤에 하나만 빼고 가져오기 #der 서명에는 r, s를 직렬화 der_sig = stack.pop()[:-1] # parse the serialized pubkey and signature into objects try: point = S256Point.parse(pubkey) sig = Signature.parse(der_sig) except (ValueError, SyntaxError) as e: return False # verify the signature using S256Point.verify() # push an encoded 1 or 0 depending on whether the signature verified #서명에는 r, s가 포함되어 있음 #u = x/s #v = r/s #uG + vP = R #R.x = s 이면 서명이 유효함 if point.verify(z, sig): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
def op_checksig(stack, z): # check that there are at least 2 elements on the stack if len(stack) < 1: return False # the top element of the stack is the SEC pubkey sec_pubkey = stack.pop() # the next element of the stack is the DER signature der_signature_bytes = stack.pop() der_signature = der_signature_bytes[:-1] # take off the last byte of the signature as that's the hash_type hash_type = der_signature_bytes[-1] # parse the serialized pubkey and signature into objects pk = S256Point.parse(sec_pubkey) signature = Signature.parse(der_signature) # verify the signature using S256Point.verify() # push an encoded 1 or 0 depending on whether the signature verified if pk.verify(z, signature): stack.append(encode_num(1)) return True else: stack.append(encode_num(0)) return False
def op_checkmultisig(stack, z): # m of n multi-sig if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n+1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m+1: return False der_signatures = [] for _ in range(m): der_signatures.append(stack.pop()[:-1]) stack.pop() # Off-by-One bug try: pubPoints = [S256Point.parse(sec) for sec in sec_pubkeys] sigs = [Signature.parse(der) for der in der_signatures] for sig in sigs: if len(pubPoints) == 0: return False while pubPoints: pubPoint = pubPoints.pop(0) if pubPoint.verify(z, sig): break stack.append(encode_num(1)) except (ValueError, SyntaxError): return False return True
def op_checksig(stack, z): # check that there are at least 2 elements on the stack if len(stack) < 2: return False # the top element of the stack is the SEC pubkey pubkey_bin = stack.pop() # the next element of the stack is the DER signature sig_bin = stack.pop() # take off the last byte of the signature as that's the hash_type hash_type = sig_bin[-1] sig_bin = sig_bin[:-1] # parse the serialized pubkey and signature into objects pubkey = S256Point.parse(pubkey_bin) sig = Signature.parse(sig_bin) # verify the signature using S256Point.verify() valid = pubkey.verify(z, sig) # push an encoded 1 or 0 depending on whether the signature verified stack.append(encode_num(1) if valid else encode_num(0)) return True
def test_example_4(self): sec = bytes.fromhex('0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a') der = bytes.fromhex('3045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed') z = 0x27e0c5994dec7824e56dec6b2fcb342eb7cdb0d0957c2fce9882f715e85d81a6 point = S256Point.parse(sec) signature = Signature.parse(der) self.assertTrue(point.verify(z, signature))
def op_checksig(stack, z): # check that there are at least 2 elements on the stack if len(stack) < 2: return False # the top element of the stack is the SEC pubkey sec_pubkey = stack.pop() # the next element of the stack is the DER signature # take off the last byte of the signature as that's the hash_type # We will explain what this means when we explain validation of transactions next!!! Please be patient! # More at https://en.bitcoin.it/wiki/OP_CHECKSIG der_signature = stack.pop()[:-1] # parse the serialized pubkey and signature into objects try: point = S256Point.parse(sec_pubkey) sig = Signature.parse(der_signature) except (ValueError, SyntaxError): #print('Parse fail', point) return False # verify the signature using S256Point.verify() # push an encoded 1 or 0 depending on whether the signature verified if point.verify(z, sig): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
def op_checksig(stack, z): # check that there are at least 2 elements on the stack if len(stack) < 2: return False # the top element of the stack is the SEC pubkey sec_pubkey = stack.pop() print(f'stack sec:{sec_pubkey.hex()}') # the next element of the stack is the DER signature der_signature = stack.pop()[:-1] print(f'stack der:{der_signature}') # take off the last byte of the signature as that's the hash_type hash_type = der_signature[-1:] print(f'hash_type:{hash_type.hex()}') # parse the serialized pubkey and signature into objects try: point = S256Point.parse(sec_pubkey) der_signature = Signature.parse(der_signature) print(f'point:{point}') print(f'sig:{der_signature}') except (ValueError, SyntaxError) as e: return False if point.verify(z, der_signature): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
def test_exercise_2(self): der = bytes.fromhex( '304402201f62993ee03fca342fcb45929993fa6ee885e00ddad8de154f268d98f083991402201e1ca12ad140c04e0e022c38f7ce31da426b8009d02832f0b44f39a6b178b7a1' ) sec = bytes.fromhex( '0204519fac3d910ca7e7138f7013706f619fa8f033e6ec6e09370ea38cee6a7574' ) z = int.from_bytes(hash256(b'ECDSA is awesome!'), 'big') sig = Signature.parse(der) point = S256Point.parse(sec) self.assertTrue(point.verify(z, sig))
def test_der(self): testcases = ( (1, 2), (randint(0, 2**256), randint(0, 2**255)), (randint(0, 2**256), randint(0, 2**255)), ) for r, s in testcases: sig = Signature(r, s) der = sig.der() sig2 = Signature.parse(der) self.assertEqual(sig2.r, r) self.assertEqual(sig2.s, s)
def op_checksig(stack, z): if len(stack) < 2: return False sec_pubkey = stack.pop() der_signature = stack.pop()[:-1] point = S256Point.parse(sec_pubkey) sig = Signature.parse(der_signature) if point.verify(z, sig): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False # n is the number of public keys n = decode_num(stack.pop()) if len(stack) < n + 1: return False # get all the public keys into a list. pubkeys = [] for _ in range(n): pubkeys.append(stack.pop()) if len(stack) < 1: return False # m is the number of signatures m = decode_num(stack.pop()) # m + 2 because of the additional element at the bottom of the stack that is added. if len(stack) < m + 1: return False # get all the signatures. signatures = [] for _ in range(m): # take off last byte, which is the hashtype signatures.append(stack.pop()[:-1]) if len(stack) < 1: return False # we remove the last element from the stack (the one included because the off by one error) stack.pop() # verify all the signatures against all pubkeys. If a signature isn't valid for any pubkeys, fail. try: sigs = [Signature.parse(signature) for signature in signatures] points = [S256Point.parse(pubkey) for pubkey in pubkeys] except (ValueError, SyntaxError) as e: LOGGER.info(e) return False # variable to count the number of valid signatures. count = 0 # in the next loop, we check that each signature is valid for a pubkey. while len(points) > 0: # point is popped so each signature can only be valid for 1 point. point = points.pop() for sig in sigs: # if the signature is valid for this pubkey, increase the count and break from the while # to check next signature. if point.verify(z, sig): count += 1 # if the number of valid signatures is m = each signature is valid for some pubkey, then script is valid. if count == m: stack.append(encode_num(1)) # else, script should fail. else: stack.append(encode_num(0)) return True
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # get the relevant input tx_in = self.tx_ins[input_index] # parse the point from the sec format (tx_in.sec_pubkey()) point = S256Point.parse(tx_in.sec_pubkey()) # parse the signature from the der format (tx_in.der_signature()) signature = Signature.parse(tx_in.der_signature()) # get the hash type from the input (tx_in.hash_type()) hash_type = tx_in.hash_type() # get the sig_hash (z) z = self.sig_hash(input_index, hash_type) # use point.verify on the z and signature return point.verify(z, signature)
def op_checksig(stack, z): if len(stack) < 2: return False pub_sec = stack.pop() sig_der = stack.pop()[:-1] # except hash_type try: pub_point = S256Point.parse(pub_sec) sig = Signature.parse(sig_der) except (ValueError, SyntaxError) as e: return False if pub_point.verify(z, sig): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
def test_example_5(self): h256 = hash256( bytes.fromhex( '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c56870000000001000000' )) z = int.from_bytes(h256, 'big') point = S256Point.parse( bytes.fromhex( '022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb70' )) sig = Signature.parse( bytes.fromhex( '3045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a89937' )) self.assertTrue(point.verify(z, sig))
def op_checksig(stack, z): if len(stack) < 2: 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
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' inp = self.tx_ins[input_index] sigs_required = inp.script_sig.num_sigs_required() for sig_num in range(sigs_required): # get the point from the sec format point = S256Point.parse(inp.sec_pubkey(index=sig_num)) # get the input signature der, sighash = inp.der_signature(index=sig_num) signature = Signature.parse(der) # get the hash to sign z = self.hash_to_sign(input_index, sighash) # verify the hash and signature are good if not point.verify(z, signature): return False return True
def test_exercise_3(self): hex_tx = '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c568700000000' hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71' hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e754022' hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae' sec = bytes.fromhex(hex_sec) der = bytes.fromhex(hex_der) redeem_script = Script.parse(BytesIO(bytes.fromhex(hex_redeem_script))) stream = BytesIO(bytes.fromhex(hex_tx)) tx_obj = Tx.parse(stream) tx_obj.tx_ins[0].script_sig = redeem_script s = tx_obj.serialize() + int_to_little_endian(SIGHASH_ALL, 4) z = int.from_bytes(hash256(s), 'big') point = S256Point.parse(sec) sig = Signature.parse(der) self.assertTrue(point.verify(z, sig))
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # get the relevant input tx_in = self.tx_ins[input_index] # get the sec_pubkey at current signature index point = S256Point.parse(tx_in.sec_pubkey()) # get the der sig and hash_type from input # get the der_signature at current signature index der, hash_type = tx_in.der_signature() # get the signature from der format signature = Signature.parse(der) # get the hash to sign z = self.sig_hash_bip143(input_index, hash_type) # use point.verify on the hash to sign and signature if not point.verify(z, signature): return False return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): der_signatures.append(stack.pop()[:-1]) # <1> stack.pop() try: # <2> # end::source1[] # parse all the points # parse all the signatures # loop through the signatures # if we have no more points, signatures are no good # we loop until we find the point which works with this signature # get the current point from the list of points # we check if this signature goes with the current point # the signatures are valid, so push a 1 to the stack # tag::source1[] # points = [S256Point.parse(sec) for sec in sec_pubkeys] points = [] sigs = [] for sec in range(len(sec_pubkeys)): points.append(S256Point.parse(sec_pubkeys[sec])) for sig in range(len(der_signatures)): sigs.append(Signature.parse(der_signatures[sig])) for sig in sigs: if len(points) == 0: return False while points: point = points.pop(0) if point.verify(z, sig): break stack.append(encode_num(1)) except (ValueError, SyntaxError): return False return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): der_signatures.append(stack.pop()[:-1]) # <1> stack.pop() # <2> try: # end::source1[] # parse all the points # parse all the signatures # loop through the signatures # if we have no more points, signatures are no good # we loop until we find the point which works with this signature # get the current point from the list of points # we check if this signature goes with the current point # the signatures are valid, so push a 1 to the stack # tag::source1[] #raise NotImplementedError # <3> pub_key_points = [] for pub_key in sec_pubkeys: point = S256Point.parse(pub_key) pub_key_points.append(point) signatures = [] for der_sig in der_signatures: sig = Signature.parse(der_sig) signatures.append(sig) for sig in signatures: if not valid_sig(sig, pub_key_points, z): stack.append(encode_num(0)) return False except (ValueError, SyntaxError): return False stack.append(encode_num(1)) return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): # signature is assumed to be using SIGHASH_ALL der_signatures.append(stack.pop()[:-1]) # OP_CHECKMULTISIG bug stack.pop() try: # parse the sec_pubkeys into an array of points points = [S256Point.parse(sec) for sec in sec_pubkeys] # parse the der_signatures into an array of signatures sigs = [Signature.parse(der) for der in der_signatures] # loop through the signatures for sig in sigs: # bail early if we don't have any points left if len(points) == 0: # add a 0 to the stack using encode_num(0) stack.append(encode_num(0)) # return True return True # while we have points while points: # get the point at the front (points.pop(0)) point = points.pop(0) # see if this point can verify this sig with this z if point.verify(z, sig): # break if so, this sig is valid! break # if we made it this far, we have to add a 1 to the stack # use encode_num(1) stack.append(encode_num(1)) except (ValueError, SyntaxError): return False return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): der_signatures.append(stack.pop()[:-1]) # <1> stack.pop() # <2> try: # parse all the points parsed_points = [S256Point.parse(p) for p in sec_pubkeys] # parse all the signatures parsed_signatures = [Signature.parse(s) for s in der_signatures] # loop through the signatures valid_sigs = 0 for sig in parsed_signatures: # if we have no more points, signatures are no good if len(parsed_points) == 0: return False # we loop until we find the point which works with this signature for i, p in enumerate(parsed_points): print(i) # get the current point from the list of points # we check if this signature goes with the current point if p.verify(z, sig): parsed_points.pop(i) valid_sigs += 1 # the signatures are valid, so push a 1 to the stack if valid_sigs == len(parsed_signatures): stack.pop(encode_num(1)) except (ValueError, SyntaxError): return False return True
def test_sig_hash_bip143(self): raw_tx = unhexlify( '0100000001fd5145175fafdee6d20ac376e376cf26d933848ba5aa177d0d163a462fb3f183010000006b483045022100f49a17e80098bc057e319b890bdc42fe7224e7f6beb69a650102f802239be154022069742f504fdd52906c14d0d18ff0808e01146813775602163ec10d419270c1c541210223f1c80f382f086e2af7ad9d05227d94b6cf292596b9853f04a91194048f9048ffffffff0236820100000000001976a914dc10e999a5f18eb510feec09206d1812fa24a9c288ac5c058049000000001976a91421704f258089af191df1a4abed2b48ec11d6063e88ac00000000' ) stream = BytesIO(raw_tx) tx = Tx.parse(stream) tx_in = tx.tx_ins[0] raw_tx2 = unhexlify( '010000000185037eb5531900f2f450e55cd950c509310229c0444e318a8811eecfa3b5c183010000006b483045022100f4a6e308ff7846bd19d394ec1b7263e051f2a60e6819feb006cdb9047bdd21a502206d969dfb5dfee3e53ed1a79b441d1cc2b7b8fe945ac7507c3b5e180565fbaead4121037765d8921f9559a6f03d620a1687a57e5b4ecb9efa5b41fc44555da0a376f81affffffff021ffc6c00000000001976a914fe1f6bea216c790c30d07f52966850268a3f90a788acfc8b8149000000001976a9142563b8536a228ec866e1c1084044a7730e53758888ac00000000' ) stream2 = BytesIO(raw_tx2) tx2 = Tx.parse(stream2) tx_in._value = tx2.tx_outs[1].amount tx_in._script_pubkey = tx2.tx_outs[1].script_pubkey.serialize() der, hash_type = tx_in.der_signature() sec = tx_in.sec_pubkey() sig = Signature.parse(der) point = S256Point.parse(sec) z = tx.sig_hash_bip143(0, hash_type) self.assertTrue(point.verify(z, sig)) self.assertTrue(tx.verify_input(0)) self.assertTrue(tx.verify()) raw_tx = unhexlify( '01000000066f267f335a54abf404c66a7a6e9ed3d77566a09ce11632f57029a677f42c6095000000006b483045022100fb0b16699c9b0984345c7860e208c04694aaa5117c8306082cfafc58b53e489a02203cd53408f1f8c8ff29701a9d1f6960b2dc5e1039f0eea949c5a886ac367e1e38412102fdcae0e5a55b20c8d3cbdf451d39f6d47daa50f884ed0ffcf0ae0adfeec4abb9ffffffff4ceb6a2894b19b96fedd543750bf7307805a2f6ca189c8c42d1abbe2930235fa000000006a4730440220794c269d519b567aa694de6dcde1d09dffa30b69dc18a619ce9ea65f239899150220156394f70f405c0710851490b9f21dc8a23931fbdc8a70ea51f73e9b00274a5c412103b708cd0b3329cff03611b0155384d1d4f40cb3aa30f82d8f4a34da044c868058ffffffff15053ac5123a25e0adf0ed998dfb710fff827861ac1a4c6601be8034179350ab000000006a473044022020e7b448318fa44b977d557b639aaf3a9666cf6d8dd446bd7812e752ddfcd1d302207159d22c2e379b77b0514b8e0767d0e9fff7063a659c268d605be436f65703884121031a97eb1664ceffa32988f7ea7c6726d681f1385b9765be1a40d6083fba4e6c69ffffffff2e1fb2ad94461104b147ffe95d0534eb98495c45831547b70eae652ac6cf52d0000000006b483045022100b0ce5496d51673f82430eee24c57f7f2f2631e5b9b32c78bbd79e1cbf3f6297b02201c807ecfa86c1c493e83f1235a19e4426da651e8f76c2f4b41ceebf1222a9291412102e4aa3631fd0b4a877c7c0a040b8211636f743c392ce17e6f266beb1b62490af9ffffffff311368bcf1bac2ae2e906bd7e84e9b45da861a63154ae5c3d69840f65486ba86000000006b483045022100d5f63c5284604eefb942fa9710f8d5b5bccf431e63c496237a0c41eb5c6debf102202bda17f3b7406b9c41f44c7377261413cfa144489a70a40e9e9126b3e7f2fc734121032e413587a71814365b7912eac3a052d8ac0c5f2351d3d84863a02bafefd41f19ffffffff2e9e219c5a68079891a8d2b00bfcf3772fa605997773c2c516bb5ac99aa8ee06000000006a47304402207b6e0d96d0ce538fb54fcb1731a35632b6e40efde834ce45ee22f0c0f5baa886022009327de37e3fb657af29161d265db558869c09e295e84ddb2f686a492db0015a41210389c44f336f7c8cc3096f8f40bc5bdbffea24da9e26649dbe6b862d7d369698d0ffffffff0102b84f05000000001976a9145c52250125494685f133df34f47fb88799b2903588ac00000000' ) stream = BytesIO(raw_tx) tx = Tx.parse(stream) inputs = ( ('18Lk6CB2WSpc4BVbxWhZrxLaYaJA2XVtyU', 24285000), ('13xY6E2tnBC5eGFCkayAUdVVcuGkFPoebJ', 824730), ('1BjFmsA4StiDa9xjAwahFXNpzR6SfXxBFD', 7583000), ('1Nn5QirD9iFT5kSF35XN8E3SX3SJM1daPL', 13150000), ('1HE8AdXHkP2bbnKmgENET4iyCHncP7rd7G', 32850000), ('1J3BgNjoqeR5JhHzC2rgorzBXTmdbmYcau', 10422900), ) for i, data in enumerate(inputs): addr, value = data tx_in = tx.tx_ins[i] i += 1 h160 = decode_base58(addr) tx_in._value = value tx_in._script_pubkey = p2pkh_script(h160) self.assertTrue(tx.verify())
def op_checksig(stack, z): # check to see if there's at least 2 elements if len(stack) < 2: return False # get the sec_pubkey with stack.pop() sec_pubkey = stack.pop() # get the der_signature with stack.pop()[:-1] (last byte is removed) der_signature = stack.pop()[:-1] # parse the sec format pubkey with S256Point point = S256Point.parse(sec_pubkey) # parse the der format signature with Signature sig = Signature.parse(der_signature) # verify using the point, z and signature # if verified add encode_num(1) to the end, otherwise encode_num(0) if point.verify(z, sig): stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True
def op_checkmultisig(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): der_signatures.append(stack.pop()[:-1]) # <1> stack.pop() # <2> try: # end::source1[] # parse all the points points = [S256Point.parse(sec_pubkey) for sec_pubkey in sec_pubkeys] # parse all the signatures signatures = [Signature.parse(der) for der in der_signatures] # loop through the signatures for sig in signatures: # if we have no more points, signatures are no good if not points: return False # we loop until we find the point which works with this signature while points: # get the current point from the list of points point = points.pop(0) # we check if this signature goes with the current point if point.verify(z, sig): break # the signatures are valid, so push a 1 to the stack if points: return False stack.append(encode_num(1)) # tag::source1[] except (ValueError, SyntaxError): return False return True
def op_checkmultisig2(stack, z): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False sec_pubkeys = [] for _ in range(n): sec_pubkeys.append(stack.pop()) m = decode_num(stack.pop()) if len(stack) < m + 1: return False der_signatures = [] for _ in range(m): # signature is assumed to be using SIGHASH_ALL der_signatures.append(stack.pop()[:-1]) # OP_CHECKMULTISIG bug stack.pop() try: # parse all the points points = [S256Point.parse(sec) for sec in sec_pubkeys] # parse all the signatures sigs = [Signature.parse(der) for der in der_signatures] # loop through the signatures for sig in sigs: # if we have no more points, signatures are no good if len(points) == 0: LOGGER.info("signatures no good or not in right order") return False # we loop until we find the point which works with this signature while points: # get the current point from the list of points point = points.pop(0) # we check if this signature goes with the current point if point.verify(z, sig): break # the signatures are valid, so push a 1 to the stack stack.append(encode_num(1)) except (ValueError, SyntaxError): return False return True
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # Exercise 1.1: get the relevant input tx_in = self.tx_ins[input_index] # Exercise 6.2: get the number of signatures required. This is available in tx_in.script_sig.num_sigs_required() sigs_required = tx_in.script_sig.num_sigs_required() # Exercise 6.2: iterate over the sigs required and check each signature for sig_num in range(sigs_required): # Exercise 1.1: get the point from the sec format (tx_in.sec_pubkey()) # Exercise 6.2: get the sec_pubkey at current signature index (check sec_pubkey function) point = S256Point.parse(tx_in.sec_pubkey(index=sig_num)) # Exercise 1.1: get the der sig and hash_type from input # Exercise 6.2: get the der_signature at current signature index (check der_signature function) der, hash_type = tx_in.der_signature(index=sig_num) # Exercise 1.1: get the signature from der format signature = Signature.parse(der) # Exercise 1.1: get the hash to sign z = self.sig_hash(input_index, hash_type) # Exercise 1.1: use point.verify on the hash to sign and signature if not point.verify(z, signature): return False return True