from binascii import hexlify, unhexlify
import struct
import io
SER_DEFAULT = 0
SER_ID = 0
class CompactSize(int):
def serialize(self, _stype=SER_DEFAULT):
assert self >= 0
if self < 253:
return struct.pack("<B", self)
if self < 2**16:
return struct.pack("<B", 253) + struct.pack("<H", self)
if self < 2**32:
return struct.pack("<B", 254) + struct.pack("<I", self)
if self < 2**64:
return struct.pack("<B", 255) + struct.pack("<Q", self)
raise Exception("Value too large for serializer")
def deserialize(self, f):
number = struct.unpack("<B", f.read(1))[0]
if number == 253:
number = struct.unpack("<H", f.read(2))[0]
elif number == 254:
number = struct.unpack("<I", f.read(4))[0]
elif number == 255:
number = struct.unpack("<Q", f.read(8))[0]
return CompactSize(number)
def deser_uint256(f):
if isinstance(f, bytes):
f = io.BytesIO(f)
r = 0
for i in range(8):
t = struct.unpack("<I", f.read(4))[0]
r += t << (i * 32)
return r
def ser_uint256(u, _stype=SER_DEFAULT):
rs = b""
for _ in range(8):
rs += struct.pack("<I", u & 0xFFFFFFFF)
u >>= 32
return rs
def deser_string(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
return f.read(nit)
def ser_string(s, _stype=SER_DEFAULT):
if len(s) < 253:
return struct.pack("B", len(s)) + s
if len(s) < 0x10000:
return struct.pack("<BH", 253, len(s)) + s
if len(s) < 0x100000000:
return struct.pack("<BI", 254, len(s)) + s
return struct.pack("<BQ", 255, len(s)) + s
def uint256_from_str(s):
if len(s) == 64:
s = unhexlify(s)
r = 0
t = struct.unpack("<IIIIIIII", s[:32])
for i in range(8):
r += t[i] << (i * 32)
return r
def uint256_from_bigendian(s):
if isinstance(s, str):
s = unhexlify(s)
r = 0
t = struct.unpack(">QQQQ", s[:32])
for i in t:
r = (r << 64) | i
return r
def uint256_from_compact(c):
nbytes = (c >> 24) & 0xFF
if nbytes <= 3:
v = (c & 0xFFFFFF) >> 8 * (3 - nbytes)
else:
v = (c & 0xFFFFFF) << (8 * (nbytes - 3))
return v
def compact_from_uint256(v):
nbytes = (v.bit_length() + 7) >> 3
compact = 0
if nbytes <= 3:
compact = (v & 0xFFFFFF) << 8 * (3 - nbytes)
else:
compact = v >> 8 * (nbytes - 3)
compact = compact & 0xFFFFFF
if compact & 0x00800000:
compact >>= 8
nbytes += 1
return compact | nbytes << 24
def deser_double(f):
return struct.unpack("<d", f.read(8))[0]
def ser_double(d):
return struct.pack("<d", d)
def deser_vector(f, c):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
r = []
for _ in range(nit):
if isinstance(c, type(lambda: True)):
t = c(f)
else: t = c()
t.deserialize(f)
r.append(t)
return r
def ser_vector(l, stype=SER_ID):
r = b""
if len(l) < 253:
r = struct.pack("B", len(l))
elif len(l) < 0x10000:
r = struct.pack("<BH", 253, len(l))
elif len(l) < 0x100000000:
r = struct.pack("<BI", 254, len(l))
else:
r = struct.pack("<BQ", 255, len(l))
for i in l:
r += i.serialize(stype)
return r
def deser_uint256_vector(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
r = []
for _ in range(nit):
t = deser_uint256(f)
r.append(t)
return r
def ser_uint256_vector(l):
r = b""
if len(l) < 253:
r = struct.pack("B", len(l))
elif len(l) < 0x10000:
r = struct.pack("<BH", 253, len(l))
elif len(l) < 0x100000000:
r = struct.pack("<BI", 254, len(l))
else:
r = struct.pack("<BQ", 255, len(l))
for i in l:
r += ser_uint256(i)
return r
def ser_hash32_vector(l):
r = b""
if len(l) < 253:
r = struct.pack("B", len(l))
elif len(l) < 0x10000:
r = struct.pack("<BH", 253, len(l))
elif len(l) < 0x100000000:
r = struct.pack("<BI", 254, len(l))
else:
r = struct.pack("<BQ", 255, len(l))
for i in l:
assert len(i) == 32
r += i
return r
def deser_hash32_vector(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
r = []
for _ in range(nit):
t = f.read(32)
r.append(t)
return r
def ser_compact_size(l):
r = b""
if l < 253:
r = struct.pack("B", l)
elif l < 0x10000:
r = struct.pack("<BH", 253, l)
elif l < 0x100000000:
r = struct.pack("<BI", 254, l)
else:
r = struct.pack("<BQ", 255, l)
return r
def deser_compact_size(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
return nit
def deser_varint(f):
num = 0
while True:
b = struct.unpack("<B", f.read(1))[0]
num = (num << 7) | (b & 0x7F)
if b & 0x80:
num += 1
else:
return num
def ser_varint(n):
ret = bytearray()
i = 0
ret.append(0)
while True:
ret[i] = ret[i] | (n & 0x7F)
if n <= 0x7F:
break
n = (n >> 7) - 1
i += 1
ret.append(0x80)
return bytes(reversed(ret))
def deser_string_vector(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
r = []
for _ in range(nit):
t = deser_string(f)
r.append(t)
return r
def ser_string_vector(l):
r = b""
if len(l) < 253:
r = struct.pack("B", len(l))
elif len(l) < 0x10000:
r = struct.pack("<BH", 253, len(l))
elif len(l) < 0x100000000:
r = struct.pack("<BI", 254, len(l))
else:
r = struct.pack("<BQ", 255, len(l))
for sv in l:
r += ser_string(sv)
return r
def deser_int_vector(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
elif nit == 254:
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
r = []
for _ in range(nit):
t = struct.unpack("<i", f.read(4))[0]
r.append(t)
return r
def ser_int_vector(l):
r = b""
if len(l) < 253:
r = struct.pack("B", len(l))
elif len(l) < 0x10000:
r = struct.pack("<BH", 253, len(l))
elif len(l) < 0x100000000:
r = struct.pack("<BI", 254, len(l))
else:
r = struct.pack("<BQ", 255, len(l))
for i in l:
r += struct.pack("<i", i)
return r
def serialize_script_num(value):
r = bytearray(0)
if value == 0:
return r
neg = value < 0
absvalue = -value if neg else value
while absvalue:
r.append(int(absvalue & 0xFF))
absvalue >>= 8
if r[-1] & 0x80:
r.append(0x80 if neg else 0)
elif neg:
r[-1] |= 0x80
return r
def from_hex(obj, hex_string):
obj.deserialize(io.BytesIO(unhexlify(hex_string.strip().encode("ascii"))))
return obj
def to_hex(obj):
if isinstance(obj, bytes):
return hexlify(obj)
return hexlify(obj.serialize()).decode("ascii")