<p><code>CHashWriter</code> does <a href="https://github.com/bitcoin/bitcoin/blob/e1bf5470f919cf212703466411968916db8ae61f/src/hash.h#L144" rel="nofollow noreferrer">serialisation</a> differently for different types of objects. <a href="https://github.com/bitcoin/bitcoin/blob/master/src/serialize.h" rel="nofollow noreferrer"><code>src/serialize.h</code></a> describes this different behaviour in detail.</p>
<p>Here's a simple version for the new table bucketing algorithm in python. <code>get_group()</code> assumes normal ipv4 addresses as input here.</p>
<pre><code>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(&quot;41f758f2e5cc078d3795b4fc0cb60c2d735fa92cc020572bdc982dd2d564d11b&quot;)
addr = &quot;250.1.2.1&quot;
src = &quot;250.1.2.1&quot;
bucket = get_new_bucket(key, addr, src)
print(&quot;bucket is&quot;, bucket) # 786
</code></pre>

CC BY-SA 4.0
2023-02-01T10:21:51.433Z
2023-02-01T10:21:51.433Z
stratospher
<p>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.</p>
<pre><code>uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) &lt;&lt; nKey &lt;&lt; GetKey()).GetCheapHash();
</code></pre>
<p>I know that the hash1 value is the last 64 bits of the hash value converted into an int.</p>
<p>How could I recreate the following part in python?(I know the individual values)</p>
<pre><code>(CHashWriter(SER_GETHASH, 0) &lt;&lt; nKey &lt;&lt; GetKey()).GetCheapHash()
</code></pre>

<bitcoin-core><bitcoind><bitcoin-core-development>
Serialize data to get buckets
Vinay Shetty
# Serialize data to get buckets

(Asked by: username_0 on 2022-10-08)

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()

```

**Tags:** bitcoin-core, bitcoind, bitcoin-core-development


---

## 1 answers

### Answer by username_1 on 2023-02-01. Score: 3

`CHashWriter` does [serialisation](https://github.com/bitcoin/bitcoin/blob/e1bf5470f919cf212703466411968916db8ae61f/src/hash.h#L144) differently for different types of objects. [`src/serialize.h`](https://github.com/bitcoin/bitcoin/blob/master/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

```


---

