1

I am trying to recreate the bucketing algorithm of bitcoin using python, but I am stuck at this particular line because I am unable to recreate it using a simple double sha256.

uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();

I know that the hash1 value is the last 64 bits of the hash value converted into an int.

How could I recreate the following part in python?(I know the individual values)

(CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash()

1 Answer 1

3

CHashWriter does serialisation differently for different types of objects. src/serialize.h describes this different behaviour in detail.

Here's a simple version for the new table bucketing algorithm in python. get_group() assumes normal ipv4 addresses as input here.

ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP = 64
ADDRMAN_NEW_BUCKET_COUNT = 1024

def get_group(ip):
    ip_as_bytes = bytes(map(int, ip.split('.')))
    return bytes([1]) + ip_as_bytes[:2]

def double_hash(bytes):
    return sha256(sha256(bytes).digest()).digest()

def get_new_bucket(key, addr, src):
    addr_group = get_group(addr)
    src_group = get_group(src)
    hash1 =  int.from_bytes(double_hash(key + bytes([len(addr_group)]) + addr_group
                                            + bytes([len(src_group)]) + src_group)[:8], 'little')
    hash1 = hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
    hash2 = int.from_bytes(double_hash(key + bytes([len(src_group)]) + src_group
                                           + hash1.to_bytes(8, 'little'))[:8], 'little')
    return hash2 % ADDRMAN_NEW_BUCKET_COUNT

key = bytes.fromhex("41f758f2e5cc078d3795b4fc0cb60c2d735fa92cc020572bdc982dd2d564d11b")
addr = "250.1.2.1"
src = "250.1.2.1"
bucket = get_new_bucket(key, addr, src)
print("bucket is", bucket) # 786

Not the answer you're looking for? Browse other questions tagged or ask your own question.