我正在尝试在 Python 中实现 CARP 哈希,如以下 IETF 草案中所述:
https://datatracker.ietf.org/doc/html/draft-vinod-carp-v1-03#section-3.1
具体来说:
3.1。哈希函数
散列函数基于以零结尾的 ASCII 输入字符串输出 32 位无符号整数。URL 的机器名称和域名、协议以及每个成员代理的机器名称应以小写形式计算,因为 URL 的该部分不区分大小写。
由于此应用程序不需要不可逆性和强大的加密功能,因此使用了一个非常简单且快速的基于按位左旋转运算符的散列函数。
对于(URL 中的每个字符): URL_Hash += _rotl(URL_Hash, 19) + char ;
成员代理哈希以类似的方式计算:
对于(MemberProxyName 中的每个字符): MemberProxy_Hash += _rotl(MemberProxy_Hash, 19) + char ;
由于成员名称通常彼此相似,因此它们的哈希值通过以下附加操作进一步分布在哈希空间中:
MemberProxy_Hash += MemberProxy_Hash * 0x62531965 ; MemberProxy_Hash = _rotl (MemberProxy_Hash, 21) ;
3.2. 哈希组合
哈希通过首先异或 (XOR) URL 哈希与机器名称组合,然后乘以常数并执行按位旋转。
所有最终值和中间值都是 32 位无符号整数。
Combined_Hash = (URL_hash ^ MemberProxy_Hash) ; 组合哈希 += 组合哈希 * 0x62531965 ; Combined_Hash = _rotl(Combined_Hash, 21) ;
我尝试使用 numpy 创建 32 位无符号整数。第一个问题是在实现左位移时出现的。Numpy 自动将结果重新转换为 64 位无符号整数。对于任何会溢出 32 位的算术都是一样的。
例如:
from numpy import uint32
def key_hash(data):
# hash should be a 32-bit unsigned integer
hashed = uint32()
for char in data:
hashed += hashed << 19 + ord(char)
return hashed
x = key_hash("testkey")
print type(x)
回报:
输入“numpy.int64”
关于如何将这一切限制为 32 位空间的任何提示?此外,我对规范如何执行其中一些操作(如“MemberProxy_Hash += MemberProxy_Hash * 0x62531965”)在计算哈希时将永远适合 32 位感到有些困惑。
编辑:
根据反馈,听起来正确的解决方案是:
def key_hash(data):
# hash should be a 32-bit unsigned integer
hashed = 0
for char in data:
hashed += ((hashed << 19) + (hashed >> 13) + ord(char)) & 0xFFFFFFFF
return hashed
def server_hash(data):
# hash should be a 32-bit unsigned integer
hashed = 0
for char in data:
hashed += ((hashed << 19) + (hashed >> 13) + ord(char)) & 0xFFFFFFFF
hashed += (hashed * 0x62531965) & 0xFFFFFFFF
hashed = ((hashed << 21) + (hashed >> 11)) & 0xFFFFFFFF
return hashed
def hash_combination(key_hash, server_hash):
# hash should be a 32-bit unsigned integer
combined_hash = (key_hash ^ server_hash) & 0xFFFFFFFF
combined_hash += (combined_hash * 0x62531965) & 0xFFFFFFFF
return combined_hash
编辑#2:
另一个固定版本。
def rotate_left(x, n, maxbit=32):
# assumes 32 bit
x = x & (2 ** maxbit - 1)
return ((x << n) | (x >> (maxbit - n)))
def key_hash(data):
# hash should be a 32-bit unsigned integer
hashed = 0
for char in data:
hashed = (hashed + rotate_left(hashed, 19) + ord(char))
return hashed
def server_hash(data):
# hash should be a 32-bit unsigned integer
hashed = 0
for char in data:
hashed = (hashed + rotate_left(hashed, 19) + ord(char))
hashed = hashed + hashed * 0x62531965
hashed = rotate_left(hashed, 21)
return hashed
def hash_combination(key_hash, server_hash):
# hash should be a 32-bit unsigned integer
combined_hash = key_hash ^ server_hash
combined_hash = combined_hash + combined_hash * 0x62531965
return combined_hash & 0xFFFFFFFF