op
py
keyboard_arrow_up
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
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',
}
Related Documents
Recommended textbooks for you
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337671385/9781337671385_smallCoverImage.jpg)
EBK JAVA PROGRAMMING
Computer Science
ISBN:9781337671385
Author:FARRELL
Publisher:CENGAGE LEARNING - CONSIGNMENT
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337102087/9781337102087_smallCoverImage.gif)
C++ Programming: From Problem Analysis to Program...
Computer Science
ISBN:9781337102087
Author:D. S. Malik
Publisher:Cengage Learning
Programming Logic & Design Comprehensive
Computer Science
ISBN:9781337669405
Author:FARRELL
Publisher:Cengage
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337102100/9781337102100_smallCoverImage.gif)
Microsoft Visual C#
Computer Science
ISBN:9781337102100
Author:Joyce, Farrell.
Publisher:Cengage Learning,
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337102124/9781337102124_smallCoverImage.gif)
Programming with Microsoft Visual Basic 2017
Computer Science
ISBN:9781337102124
Author:Diane Zak
Publisher:Cengage Learning
![Text book image](https://www.bartleby.com/isbn_cover_images/9781305503922/9781305503922_smallCoverImage.gif)
New Perspectives on HTML5, CSS3, and JavaScript
Computer Science
ISBN:9781305503922
Author:Patrick M. Carey
Publisher:Cengage Learning
Recommended textbooks for you
- EBK JAVA PROGRAMMINGComputer ScienceISBN:9781337671385Author:FARRELLPublisher:CENGAGE LEARNING - CONSIGNMENTC++ Programming: From Problem Analysis to Program...Computer ScienceISBN:9781337102087Author:D. S. MalikPublisher:Cengage LearningProgramming Logic & Design ComprehensiveComputer ScienceISBN:9781337669405Author:FARRELLPublisher:Cengage
- Microsoft Visual C#Computer ScienceISBN:9781337102100Author:Joyce, Farrell.Publisher:Cengage Learning,Programming with Microsoft Visual Basic 2017Computer ScienceISBN:9781337102124Author:Diane ZakPublisher:Cengage LearningNew Perspectives on HTML5, CSS3, and JavaScriptComputer ScienceISBN:9781305503922Author:Patrick M. CareyPublisher:Cengage Learning
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337671385/9781337671385_smallCoverImage.jpg)
EBK JAVA PROGRAMMING
Computer Science
ISBN:9781337671385
Author:FARRELL
Publisher:CENGAGE LEARNING - CONSIGNMENT
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337102087/9781337102087_smallCoverImage.gif)
C++ Programming: From Problem Analysis to Program...
Computer Science
ISBN:9781337102087
Author:D. S. Malik
Publisher:Cengage Learning
Programming Logic & Design Comprehensive
Computer Science
ISBN:9781337669405
Author:FARRELL
Publisher:Cengage
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337102100/9781337102100_smallCoverImage.gif)
Microsoft Visual C#
Computer Science
ISBN:9781337102100
Author:Joyce, Farrell.
Publisher:Cengage Learning,
![Text book image](https://www.bartleby.com/isbn_cover_images/9781337102124/9781337102124_smallCoverImage.gif)
Programming with Microsoft Visual Basic 2017
Computer Science
ISBN:9781337102124
Author:Diane Zak
Publisher:Cengage Learning
![Text book image](https://www.bartleby.com/isbn_cover_images/9781305503922/9781305503922_smallCoverImage.gif)
New Perspectives on HTML5, CSS3, and JavaScript
Computer Science
ISBN:9781305503922
Author:Patrick M. Carey
Publisher:Cengage Learning