CARP хеш в Python

Я пытаюсь реализовать хэш CARP в Python, как описано в следующем проекте IETF:

http://tools.ietf.org/html/draft-vinod-carp-v1-03

В частности:

3.1. Хэш-функция

Хеш-функция выводит 32-разрядные целые числа без знака на основе строки ввода ASCII с нулевым символом в конце. Имя компьютера и доменные имена URL, протокол и имена компьютеров каждого прокси-члена-члена должны оцениваться в нижнем регистре, поскольку эта часть URL не учитывает регистр.

Поскольку необратимость и сильные криптографические функции не нужны для этого приложения, используется очень простая и быстрая хэш-функция, основанная на побитовом операторе левого поворота.

Для (каждый символ в URL): URL_Hash += _rotl(URL_Hash, 19) + char;

Хэши прокси-членов вычисляются аналогичным образом:

Для (каждый символ в MemberProxyName): MemberProxy_Hash += _rotl(MemberProxy_Hash, 19) + char;

Имена членов Becaues часто похожи друг на друга, их хеш-значения дополнительно распределяются по хеш-пространству с помощью следующих дополнительных операций:

MemberProxy_Hash + = MemberProxy_Hash * 0x62531965; MemberProxy_Hash = _rotl (MemberProxy_Hash, 21);

3.2. Хэш-комбинация

Хэши объединяются путем сначала эксклюзивного или (XOR) хэша URL-адреса по имени машины, а затем умножения на константу и выполнения побитового вращения.

Все конечные и промежуточные значения представляют собой 32-разрядные целые числа без знака.

Combined_Hash = (URL_hash ^ MemberProxy_Hash); Combined_Hash + = Combined_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

2 ответа

Решение

Не беспокойся с NumPy Uint32. Просто используйте стандартный Python int, Ограничить результат операций по мере необходимости result &= 0xFFFFFFFF удалить ненужные старшие биты.

def key_hash(data):
    # hash should be a 32-bit unsigned integer
    hashed = 0
    for char in data:
        # hashed += ((hashed << 19) + ord(char)) & 0xFFFFFFFF
        # the above is wrong; it's not masking the final addition.
        hashed = (hashed + (hashed << 19) + ord(char)) & 0xFFFFFFFF
    return hashed

Вы могли бы сделать только одну заключительную маскировку, но это было бы довольно медленно при длинном вводе в качестве промежуточного hashed было бы довольно большое количество.

Кстати, вышеописанное не будет очень хорошей хэш-функцией. rot в rotl значит вращаться, а не сдвигаться.

Тебе нужно

# hashed += ((hashed << 19) + (hashed >> 13) + ord(char)) & 0xFFFFFFFF
# the above is wrong; it's not masking the final addition.
hashed = (hashed + (hashed << 19) + (hashed >> 13) + ord(char)) & 0xFFFFFFFF

Изменить... сравнение; этот код:

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 khash(data):
    h = 0
    for c in data:
        assert 0 <= h <= 0xFFFFFFFF
        h = (h + (h << 19) + (h >> 13) + ord(c)) & 0xFFFFFFFF
    assert 0 <= h <= 0xFFFFFFFF
    return h

guff = "twas brillig and the slithy toves did whatever"
print "yours: %08X" % key_hash(guff)
print "mine : %08X" % khash(guff)

производит:

yours: A20352DB4214FD
mine : DB4214FD

Следующее работает для меня, хотя, возможно, немного не в духе:

from numpy import uint32

def key_hash(data):
    # hash should be a 32-bit unsigned integer
    hashed = uint32()
    for char in data:
        hashed += hashed << uint32(19) + uint32(ord(char))
    return hashed

x = key_hash("testkey")
print type(x)

Проблема в том, что числа приводятся к большему количеству бит, а не к меньшему.

Другие вопросы по тегам