2013-03-26 2 views
0

Я ищу, чтобы сравнить биты хеша в Python3, как часть системы Hashcash. Так, например, я хочу знать, если первые N битов в SHA256 хеша 0.Какой самый быстрый способ сравнить бит хэша в Python3?

Прямо сейчас, я это делаю на основе шестнадцатеричном версии

if newhash.hexdigest()[0:4] == '0000' 

Но это не позвольте мне быть таким же гранулированным, как я хочу - я бы предпочел сравнить исходные биты, что позволяет мне более точно сравнивать количество совпадающих 0.

я получить битовые значения для сравнения с помощью свернутой хмеля

bin(int(h.hexdigest(), 16))[2:] 

, но это, кажется, что это не может быть самым быстрым/правильный способ сделать это.

Я оценил бы какие-либо рекомендации на правом/правильный способ сделать это;)

Спасибо,

-CPD

+0

Подсчет ведущих нулей ([поиск наиболее значимого битового набора] (http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious)) может быть оптимизирован относительно сравнения бит в целом. – jfs

ответ

0

Вы можете получить первые 8 байт дайджеста распакованы, как это :

bin(struct.unpack('>Q', h.digest()[:8])[0]) 

, но я не уверен, если это быстрее, и это не будет удобно для остальных битов. В Python бит-twiddling непросто.

0

Если вы можете иметь дело с индексацией битами справа, типа целого числа в gmpy2 поддерживает нарезку, чтобы получить доступ к отдельным битам:

>>> x=gmpy2.mpz(12345) 
>>> x.digits(2) 
'11000000111001' 
>>> x[2:5].digits(2) 
'110' 

Если вам нужно изменить отдельные биты, gmpy2 включает в себя изменяемый целочисленный тип, который позволяет вы должны изменить бит на месте.

Отказ от ответственности: Я поддерживаю gmpy2.

1

Чтобы проверить выбранные биты числа равны нулю, вам необходимо and номер с предвычисленными маской, которая имеет все эти биты, установленные, и сравнить результат к нулю. Маска, которая проверяет первые бит n номера m, представляет собой номер, который состоит из n 1s, за которым следует m - n 0s в двоичном формате.

def mask(n, m): 
    return ((1 << n) - 1) << (m - n) 

def test_0bits(digest_bytes, n_bits): 
    m = 8 * len(digest_bytes) 
    digest_num = int.from_bytes(digest_bytes, 'big') 
    return digest_num & mask(n_bits, m) == 0 

>>> test_0bits(b'\123\456', 3) # 001 010 011 100 101 110 
False 
>>> test_0bits(b'\023\456', 3) # 000 010 011 100 101 110 
True 

Если продолжать называть test_bits с тем же числом бит, вы можете предвычисления маски и хранить ее в качестве модуля уровня «постоянная».

Смежные вопросы