def test_read_opcode(): assert read_opcode(get_stream(get_bytes([b"\x08", b"1" * 8 ]))) == (b"\x08", b"1" * 8) assert read_opcode( get_stream(get_bytes([OP_PUSHDATA1, b"\x4c", b"1" * 76]))) == (OP_PUSHDATA1, b"1" * 76) assert read_opcode(get_stream(get_bytes([OP_PUSHDATA2, pack('<H' ,256), b"1" * 256]))) == \ (OP_PUSHDATA2, b"1" * 256) p = b"1" * 65537 l = OP_PUSHDATA4 + pack('<L', 65537) + p assert read_opcode(get_stream(l)) == (OP_PUSHDATA4, p)
def decode_gcs(h): stream = get_stream(h) L = var_int_to_int(read_var_int(stream)) P = var_int_to_int(read_var_int(stream)) s = deque() s_append = s.append last = 0 gcs_filter = bitarray(endian='big') gcs_filter.frombytes(stream.read()) f = 0 for i in range(L): q = 0 r = 0 while gcs_filter[f]: q += 1 f += 1 f += 1 c = P - 1 while c >= 0: r = r << 1 if gcs_filter[f]: r += 1 f += 1 c -= 1 delta = (q << P) + r last += delta s_append(last) return s
def get_multisig_public_keys(script): pub_keys = [] s = get_stream(script) o, d = read_opcode(s) while o: o, d = read_opcode(s) if d: pub_keys.append(d) return pub_keys
def get_multisig_public_keys(script, hex=False): script = get_bytes(script) pub_keys = [] s = get_stream(script) o, d = read_opcode(s) while o: o, d = read_opcode(s) if d: pub_keys.append(d.hex() if hex else d) return pub_keys
def __get_multisig_script_sig__(self, script_sig, keys, signatures, script_code, redeem_script, n, amount=None): sig_map = {keys[i]:signatures[i] for i in range(len(keys))} pub_keys = get_multisig_public_keys(redeem_script) p2wsh = True if isinstance(script_sig, list) else False if not p2wsh: s = get_stream(script_sig) o, d = read_opcode(s) while o: o, d = read_opcode(s) if d and is_valid_signature_encoding(d): for i in range(4): sighash = self.sig_hash(n, script_pub_key=script_code, sighash_type=d[-1]) sighash = s2rh(sighash) if isinstance(sighash, str) else sighash pk = public_key_recovery(d[:-1], sighash, i, hex=0) if pk in pub_keys: sig_map[pk] = d break # recreate script sig r = [OP_0] for k in pub_keys: try: r.append(op_push_data(sig_map[k])) except: pass r += [op_push_data(redeem_script)] else: for w in script_sig: if isinstance(w, str): w = bytes.fromhex(w) if w and is_valid_signature_encoding(w): d = w[:-1] for i in range(4): sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=w[-1]) pk = public_key_recovery(d, sighash, i, hex=0) if pk in pub_keys: sig_map[pk] = w break r = [b""] for k in pub_keys: try: r.append(sig_map[k]) except: pass r += [redeem_script] return r
def delete_from_script(script, sub_script): """ Decode OP_CODE or subscript from script. :param script: target script in bytes or HEX encoded string. :param sub_script: sub_script which is necessary to remove from target script in bytes or HEX encoded string. :return: script in bytes or HEX encoded string corresponding to the format of target script. """ s_hex = isinstance(script, str) script = get_bytes(script) sub_script = get_bytes(sub_script) stream = get_stream(script) if not sub_script: return script.hex() if s_hex else script r = b'' offset = 0 skip_until = 0 o, d = read_opcode(stream) while o: if script[offset:offset + len(sub_script)] == sub_script: skip_until = offset + len(sub_script) r += d[len(sub_script) - 1:] if d is not None else b"" if offset >= skip_until: r += o if d is not None: if o == OP_PUSHDATA1: r += bytes([len(d)]) elif o == OP_PUSHDATA2: r += pack('<H', len(d)) elif o == OP_PUSHDATA4: r += pack('<L', len(d)) r += d offset += 1 if d is not None: offset += len(d) if o == OP_PUSHDATA1: offset += 1 elif o == OP_PUSHDATA2: offset += 2 elif o == OP_PUSHDATA4: offset += 4 o, d = read_opcode(stream) return r.hex() if s_hex else r
def decode_huffman(h): if h: stream = get_stream(h) c = var_int_to_int(read_var_int(stream)) freq = dict() for i in range(c): key = var_int_to_int(read_var_int(stream)) freq[key] = i + 1 codes = huffman_code(huffman_tree(freq)) l = var_int_to_int(read_var_int(stream)) delta_bit_length = var_int_to_int(read_var_int(stream)) d = bitarray() d.frombytes(stream.read(l)) while d.length() > (l * 8 - delta_bit_length): d.pop() return d.decode(codes) return []
def __get_bare_multisig_script_sig__(self, script_sig, script_pub_key, keys, signatures, n): sig_map = {keys[i]:signatures[i] for i in range(len(keys))} pub_keys = get_multisig_public_keys(script_pub_key) s = get_stream(script_sig) o, d = read_opcode(s) while o: o, d = read_opcode(s) if d and is_valid_signature_encoding(d): for i in range(4): sighash = self.sig_hash(n, script_pub_key=script_pub_key, sighash_type=d[-1]) sighash = s2rh(sighash) if isinstance(sighash, str) else sighash pk = public_key_recovery(d[:-1], sighash, i, hex=0) if pk in pub_keys: sig_map[pk] = d break # recreate script sig r = [OP_0] for k in pub_keys: try: r.append(op_push_data(sig_map[k])) except: pass return r
def decode_dhcs(h): # Delta-Hoffman coded set stream = get_stream(h) # read code_table_1 c = var_int_to_int(read_var_int(stream)) code_table_1 = dict() for i in range(c): key = var_int_to_int(read_var_int(stream)) l = var_int_to_int(read_var_int(stream)) code = bitarray([bool(k) for k in stream.read(l)]) code_table_1[key] = code # read code_table_2 c = var_int_to_int(read_var_int(stream)) code_table_2 = dict() for i in range(c): key = var_int_to_int(read_var_int(stream)) l = var_int_to_int(read_var_int(stream)) code = bitarray([bool(k) for k in stream.read(l)]) code_table_2[key] = code # read compressed deltas deltas_bits_len_1 = var_int_to_int(read_var_int(stream)) deltas_bits_len_2 = var_int_to_int(read_var_int(stream)) deltas_byte_len = deltas_bits_len_2 // 8 + int(bool(deltas_bits_len_2 % 8)) r = stream.read(deltas_byte_len) deltas = bitarray() deltas.frombytes(r) while deltas.length() > deltas_bits_len_2: deltas.pop() # Huffman decode round 1 r = deltas.decode(code_table_2) deltas_string = bytearray() for i in range(int(len(r) / 2)): deltas_string += bytes([(r[i * 2] << 4) + r[i * 2 + 1]]) # Huffman decode round 2 r = bitarray() r.frombytes(bytes(deltas_string)) while r.length() > deltas_bits_len_1: r.pop() deltas_bits = r.decode(code_table_1) d_filter_bit_len = var_int_to_int(read_var_int(stream)) d_filter_byte_len = d_filter_bit_len // 8 + int(bool(d_filter_bit_len % 8)) r = stream.read(d_filter_byte_len) d_filter = bitarray() d_filter.frombytes(r) while d_filter.length() > d_filter_bit_len: d_filter.pop() f = 0 f_max = d_filter.length() decoded_set = set() last = 0 for bits in deltas_bits: d = 0 while bits > 0 and f < f_max: bits -= 1 d = d << 1 if d_filter[f]: d += 1 f += 1 last += d decoded_set.add(last) return decoded_set