op

py

School

University of Toronto, Scarborough *

*We aren’t endorsed by this school

Course

UCLCOMP163

Subject

Computer Science

Date

Nov 24, 2024

Type

py

Pages

17

Uploaded by BarristerLarkPerson679

Report
import hashlib from logging import getLogger from unittest import TestCase from ecc import ( S256Point, Signature, ) from helper import ( hash160, hash256, ) LOGGER = getLogger(__name__) def encode_num(num): if num == 0: return b'' abs_num = abs(num) negative = num < 0 result = bytearray() while abs_num: result.append(abs_num & 0xff) abs_num >>= 8 # if the top bit is set, # for negative numbers we ensure that the top bit is set # for positive numbers we ensure that the top bit is not set if result[-1] & 0x80: if negative: result.append(0x80) else: result.append(0) elif negative: result[-1] |= 0x80 return bytes(result) def decode_num(element): if element == b'': return 0 # reverse for big endian big_endian = element[::-1] # top bit being 1 means it's negative if big_endian[0] & 0x80: negative = True result = big_endian[0] & 0x7f else: negative = False result = big_endian[0] for c in big_endian[1:]: result <<= 8 result += c if negative: return -result else:
return result def op_0(stack): stack.append(encode_num(0)) return True def op_1negate(stack): stack.append(encode_num(-1)) return True def op_1(stack): stack.append(encode_num(1)) return True def op_2(stack): stack.append(encode_num(2)) return True def op_3(stack): stack.append(encode_num(3)) return True def op_4(stack): stack.append(encode_num(4)) return True def op_5(stack): stack.append(encode_num(5)) return True def op_6(stack): stack.append(encode_num(6)) return True def op_7(stack): stack.append(encode_num(7)) return True def op_8(stack): stack.append(encode_num(8)) return True def op_9(stack): stack.append(encode_num(9)) return True def op_10(stack):
stack.append(encode_num(10)) return True def op_11(stack): stack.append(encode_num(11)) return True def op_12(stack): stack.append(encode_num(12)) return True def op_13(stack): stack.append(encode_num(13)) return True def op_14(stack): stack.append(encode_num(14)) return True def op_15(stack): stack.append(encode_num(15)) return True def op_16(stack): stack.append(encode_num(16)) return True def op_nop(stack): return True def op_if(stack, items): if len(stack) < 1: return False # go through and re-make the items array based on the top stack element true_items = [] false_items = [] current_array = true_items found = False num_endifs_needed = 1 while len(items) > 0: item = items.pop(0) if item in (99, 100): # nested if, we have to go another endif num_endifs_needed += 1 current_array.append(item) elif num_endifs_needed == 1 and item == 103: current_array = false_items elif item == 104: if num_endifs_needed == 1: found = True break
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
else: num_endifs_needed -= 1 current_array.append(item) else: current_array.append(item) if not found: return False element = stack.pop() if decode_num(element) == 0: items[:0] = false_items else: items[:0] = true_items return True def op_notif(stack, items): if len(stack) < 1: return False # go through and re-make the items array based on the top stack element true_items = [] false_items = [] current_array = true_items found = False num_endifs_needed = 1 while len(items) > 0: item = items.pop(0) if item in (99, 100): # nested if, we have to go another endif num_endifs_needed += 1 current_array.append(item) elif num_endifs_needed == 1 and item == 103: current_array = false_items elif item == 104: if num_endifs_needed == 1: found = True break else: num_endifs_needed -= 1 current_array.append(item) else: current_array.append(item) if not found: return False element = stack.pop() if decode_num(element) == 0: items[:0] = true_items else: items[:0] = false_items return True def op_verify(stack): if len(stack) < 1: return False element = stack.pop() if decode_num(element) == 0: return False return True
def op_return(stack): return False def op_toaltstack(stack, altstack): if len(stack) < 1: return False altstack.append(stack.pop()) return True def op_fromaltstack(stack, altstack): if len(altstack) < 1: return False stack.append(altstack.pop()) return True def op_2drop(stack): if len(stack) < 2: return False stack.pop() stack.pop() return True def op_2dup(stack): if len(stack) < 2: return False stack.extend(stack[-2:]) return True def op_3dup(stack): if len(stack) < 3: return False stack.extend(stack[-3:]) return True def op_2over(stack): if len(stack) < 4: return False stack.extend(stack[-4:-2]) return True def op_2rot(stack): if len(stack) < 6: return False stack.extend(stack[-6:-4]) return True def op_2swap(stack): if len(stack) < 4: return False stack[-4:] = stack[-2:] + stack[-4:-2]
return True def op_ifdup(stack): if len(stack) < 1: return False if decode_num(stack[-1]) != 0: stack.append(stack[-1]) return True def op_depth(stack): stack.append(encode_num(len(stack))) return True def op_drop(stack): if len(stack) < 1: return False stack.pop() return True def op_dup(stack): if len(stack) < 1: return False stack.append(stack[-1]) return True def op_nip(stack): if len(stack) < 2: return False stack[-2:] = stack[-1:] return True def op_over(stack): if len(stack) < 2: return False stack.append(stack[-2]) return True def op_pick(stack): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1: return False stack.append(stack[-n - 1]) return True def op_roll(stack): if len(stack) < 1: return False n = decode_num(stack.pop()) if len(stack) < n + 1:
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
return False if n == 0: return True stack.append(stack.pop(-n - 1)) return True def op_rot(stack): if len(stack) < 3: return False stack.append(stack.pop(-3)) return True def op_swap(stack): if len(stack) < 2: return False stack.append(stack.pop(-2)) return True def op_tuck(stack): if len(stack) < 2: return False stack.insert(-2, stack[-1]) return True def op_size(stack): if len(stack) < 1: return False stack.append(encode_num(len(stack[-1]))) return True def op_equal(stack): if len(stack) < 2: return False element1 = stack.pop() element2 = stack.pop() if element1 == element2: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_equalverify(stack): return op_equal(stack) and op_verify(stack) def op_1add(stack): if len(stack) < 1: return False element = decode_num(stack.pop()) stack.append(encode_num(element + 1)) return True
def op_1sub(stack): if len(stack) < 1: return False element = decode_num(stack.pop()) stack.append(encode_num(element - 1)) return True def op_negate(stack): if len(stack) < 1: return False element = decode_num(stack.pop()) stack.append(encode_num(-element)) return True def op_abs(stack): if len(stack) < 1: return False element = decode_num(stack.pop()) if element < 0: stack.append(encode_num(-element)) else: stack.append(encode_num(element)) return True def op_not(stack): if len(stack) < 1: return False element = stack.pop() if decode_num(element) == 0: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_0notequal(stack): if len(stack) < 1: return False element = stack.pop() if decode_num(element) == 0: stack.append(encode_num(0)) else: stack.append(encode_num(1)) return True def op_add(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) stack.append(encode_num(element1 + element2)) return True def op_sub(stack):
if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) stack.append(encode_num(element2 - element1)) return True def op_booland(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element1 and element2: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_boolor(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element1 or element2: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_numequal(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element1 == element2: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_numequalverify(stack): return op_numequal(stack) and op_verify(stack) def op_numnotequal(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element1 == element2: stack.append(encode_num(0)) else: stack.append(encode_num(1)) return True
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
def op_lessthan(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element2 < element1: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_greaterthan(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element2 > element1: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_lessthanorequal(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element2 <= element1: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_greaterthanorequal(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element2 >= element1: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_min(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element1 < element2: stack.append(encode_num(element1)) else: stack.append(encode_num(element2)) return True
def op_max(stack): if len(stack) < 2: return False element1 = decode_num(stack.pop()) element2 = decode_num(stack.pop()) if element1 > element2: stack.append(encode_num(element1)) else: stack.append(encode_num(element2)) return True def op_within(stack): if len(stack) < 3: return False maximum = decode_num(stack.pop()) minimum = decode_num(stack.pop()) element = decode_num(stack.pop()) if element >= minimum and element < maximum: stack.append(encode_num(1)) else: stack.append(encode_num(0)) return True def op_ripemd160(stack): if len(stack) < 1: return False element = stack.pop() stack.append(hashlib.new('ripemd160', element).digest()) return True def op_sha1(stack): if len(stack) < 1: return False element = stack.pop() stack.append(hashlib.sha1(element).digest()) return True def op_sha256(stack): if len(stack) < 1: return False element = stack.pop() stack.append(hashlib.sha256(element).digest()) return True def op_hash160(stack): # check that there's at least 1 element on the stack if len(stack) < 1: return False # pop off the top element from the stack element = stack.pop() # push a hash160 of the popped off element to the stack h160 = hash160(element)
stack.append(h160) return True def op_hash256(stack): if len(stack) < 1: return False element = stack.pop() stack.append(hash256(element)) 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() # 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_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) as e: LOGGER.info(e) 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_checksigverify(stack, z): return op_checksig(stack, z) and op_verify(stack) 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()
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
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 op_checkmultisigverify(stack, z): return op_checkmultisig(stack, z) and op_verify(stack) def op_checklocktimeverify(stack, locktime, sequence): if sequence == 0xffffffff: return False if len(stack) < 1: return False element = decode_num(stack[-1]) if element < 0: return False if element < 500000000 and locktime > 500000000: return False if locktime < element: return False return True def op_checksequenceverify(stack, version, sequence): if sequence & (1 << 31) == (1 << 31): return False if len(stack) < 1: return False element = decode_num(stack[-1]) if element < 0: return False if element & (1 << 31) == (1 << 31): if version < 2: return False elif sequence & (1 << 31) == (1 << 31): return False elif element & (1 << 22) != sequence & (1 << 22): return False
elif element & 0xffff > sequence & 0xffff: return False return True class OpTest(TestCase): def test_op_hash160(self): stack = [b'hello world'] self.assertTrue(op_hash160(stack)) self.assertEqual( stack[0].hex(), 'd7d5ee7824ff93f94c3055af9382c86c68b5ca92') def test_op_checksig(self): z = 0x7c076ff316692a3d7eb3c3bb0f8b1488cf72e1afcd929e29307032997a838a3d sec = bytes.fromhex('04887387e452b8eacc4acfde10d9aaf7f6d9a0f975aabb10d006e4da568744d06c61 de6d95231cd89026e286df3b6ae4a894a3378e393e93a0f45b666329a0ae34') sig = bytes.fromhex('3045022000eff69ef2b1bd93a66ed5219add4fb51e11a840f404876325a1e8ffe052 9a2c022100c7207fee197d27c618aea621406f6bf5ef6fca38681d82b2f06fddbdce6feab601') stack = [sig, sec] self.assertTrue(op_checksig(stack, z)) self.assertEqual(decode_num(stack[0]), 1) def test_op_checkmultisig(self): z = 0xe71bfa115715d6fd33796948126f40a8cdd39f187e4afb03896795189fe1423c sig1 = bytes.fromhex('3045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bd dfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701') sig2 = bytes.fromhex('3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef5357 7d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201') sec1 = bytes.fromhex('022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb70') sec2 = bytes.fromhex('03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71') stack = [b'', sig1, sig2, b'\x02', sec1, sec2, b'\x02'] self.assertTrue(op_checkmultisig(stack, z)) self.assertEqual(decode_num(stack[0]), 1) OP_CODE_FUNCTIONS = { 0: op_0, 79: op_1negate, 81: op_1, 82: op_2, 83: op_3, 84: op_4, 85: op_5, 86: op_6, 87: op_7, 88: op_8, 89: op_9, 90: op_10, 91: op_11, 92: op_12, 93: op_13,
94: op_14, 95: op_15, 96: op_16, 97: op_nop, 99: op_if, 100: op_notif, 105: op_verify, 106: op_return, 107: op_toaltstack, 108: op_fromaltstack, 109: op_2drop, 110: op_2dup, 111: op_3dup, 112: op_2over, 113: op_2rot, 114: op_2swap, 115: op_ifdup, 116: op_depth, 117: op_drop, 118: op_dup, 119: op_nip, 120: op_over, 121: op_pick, 122: op_roll, 123: op_rot, 124: op_swap, 125: op_tuck, 130: op_size, 135: op_equal, 136: op_equalverify, 139: op_1add, 140: op_1sub, 143: op_negate, 144: op_abs, 145: op_not, 146: op_0notequal, 147: op_add, 148: op_sub, 154: op_booland, 155: op_boolor, 156: op_numequal, 157: op_numequalverify, 158: op_numnotequal, 159: op_lessthan, 160: op_greaterthan, 161: op_lessthanorequal, 162: op_greaterthanorequal, 163: op_min, 164: op_max, 165: op_within, 166: op_ripemd160, 167: op_sha1, 168: op_sha256, 169: op_hash160, 170: op_hash256, 172: op_checksig, 173: op_checksigverify, 174: op_checkmultisig, 175: op_checkmultisigverify,
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help
176: op_nop, 177: op_checklocktimeverify, 178: op_checksequenceverify, 179: op_nop, 180: op_nop, 181: op_nop, 182: op_nop, 183: op_nop, 184: op_nop, 185: op_nop, } OP_CODE_NAMES = { 0: 'OP_0', 76: 'OP_PUSHDATA1', 77: 'OP_PUSHDATA2', 78: 'OP_PUSHDATA4', 79: 'OP_1NEGATE', 81: 'OP_1', 82: 'OP_2', 83: 'OP_3', 84: 'OP_4', 85: 'OP_5', 86: 'OP_6', 87: 'OP_7', 88: 'OP_8', 89: 'OP_9', 90: 'OP_10', 91: 'OP_11', 92: 'OP_12', 93: 'OP_13', 94: 'OP_14', 95: 'OP_15', 96: 'OP_16', 97: 'OP_NOP', 99: 'OP_IF', 100: 'OP_NOTIF', 103: 'OP_ELSE', 104: 'OP_ENDIF', 105: 'OP_VERIFY', 106: 'OP_RETURN', 107: 'OP_TOALTSTACK', 108: 'OP_FROMALTSTACK', 109: 'OP_2DROP', 110: 'OP_2DUP', 111: 'OP_3DUP', 112: 'OP_2OVER', 113: 'OP_2ROT', 114: 'OP_2SWAP', 115: 'OP_IFDUP', 116: 'OP_DEPTH', 117: 'OP_DROP', 118: 'OP_DUP', 119: 'OP_NIP', 120: 'OP_OVER', 121: 'OP_PICK', 122: 'OP_ROLL', 123: 'OP_ROT', 124: 'OP_SWAP',
125: 'OP_TUCK', 130: 'OP_SIZE', 135: 'OP_EQUAL', 136: 'OP_EQUALVERIFY', 139: 'OP_1ADD', 140: 'OP_1SUB', 143: 'OP_NEGATE', 144: 'OP_ABS', 145: 'OP_NOT', 146: 'OP_0NOTEQUAL', 147: 'OP_ADD', 148: 'OP_SUB', 154: 'OP_BOOLAND', 155: 'OP_BOOLOR', 156: 'OP_NUMEQUAL', 157: 'OP_NUMEQUALVERIFY', 158: 'OP_NUMNOTEQUAL', 159: 'OP_LESSTHAN', 160: 'OP_GREATERTHAN', 161: 'OP_LESSTHANOREQUAL', 162: 'OP_GREATERTHANOREQUAL', 163: 'OP_MIN', 164: 'OP_MAX', 165: 'OP_WITHIN', 166: 'OP_RIPEMD160', 167: 'OP_SHA1', 168: 'OP_SHA256', 169: 'OP_HASH160', 170: 'OP_HASH256', 171: 'OP_CODESEPARATOR', 172: 'OP_CHECKSIG', 173: 'OP_CHECKSIGVERIFY', 174: 'OP_CHECKMULTISIG', 175: 'OP_CHECKMULTISIGVERIFY', 176: 'OP_NOP1', 177: 'OP_CHECKLOCKTIMEVERIFY', 178: 'OP_CHECKSEQUENCEVERIFY', 179: 'OP_NOP4', 180: 'OP_NOP5', 181: 'OP_NOP6', 182: 'OP_NOP7', 183: 'OP_NOP8', 184: 'OP_NOP9', 185: 'OP_NOP10', }