|
|
|
@ -19,6 +19,7 @@ from __future__ import print_function |
|
|
|
|
|
|
|
|
|
import base64 |
|
|
|
|
import hashlib |
|
|
|
|
import itertools |
|
|
|
|
import logging |
|
|
|
|
import struct |
|
|
|
|
|
|
|
|
@ -32,7 +33,7 @@ def _get_hamming_distance(a, b): |
|
|
|
|
"""Calculates hamming distance between strings of equal length.""" |
|
|
|
|
distance = 0 |
|
|
|
|
for char_a, char_b in zip(a, b): |
|
|
|
|
if char_a.lower() != char_b.lower(): |
|
|
|
|
if char_a != char_b: |
|
|
|
|
distance += 1 |
|
|
|
|
return distance |
|
|
|
|
|
|
|
|
@ -49,8 +50,11 @@ def _get_substring_hamming_distance(candidate, target): |
|
|
|
|
The minimum Hamming distance between candidate and target. |
|
|
|
|
""" |
|
|
|
|
min_distance = None |
|
|
|
|
if len(target) > len(candidate): |
|
|
|
|
raise ValueError("Candidate must be at least as long as target.") |
|
|
|
|
for i in range(len(candidate) - len(target) + 1): |
|
|
|
|
distance = _get_hamming_distance(candidate[i:i + len(target)], target) |
|
|
|
|
distance = _get_hamming_distance(candidate[i:i + len(target)].lower(), |
|
|
|
|
target.lower()) |
|
|
|
|
if min_distance is None or distance < min_distance: |
|
|
|
|
min_distance = distance |
|
|
|
|
return min_distance |
|
|
|
@ -75,20 +79,8 @@ def _bytestrings_of_length(length): |
|
|
|
|
Yields: |
|
|
|
|
All bytestrings of length `length`. |
|
|
|
|
""" |
|
|
|
|
digits = [0] * length |
|
|
|
|
while True: |
|
|
|
|
for digits in itertools.product(range(_BYTE_MAX), repeat=length): |
|
|
|
|
yield b''.join(struct.pack('B', i) for i in digits) |
|
|
|
|
digits[-1] += 1 |
|
|
|
|
i = length - 1 |
|
|
|
|
while digits[i] == _BYTE_MAX + 1: |
|
|
|
|
digits[i] = 0 |
|
|
|
|
i -= 1 |
|
|
|
|
if i == -1: |
|
|
|
|
# Terminate the generator since we've run out of strings of |
|
|
|
|
# `length` bytes. |
|
|
|
|
raise StopIteration() # pylint: disable=stop-iteration-return |
|
|
|
|
else: |
|
|
|
|
digits[i] += 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _all_bytestrings(): |
|
|
|
@ -99,11 +91,9 @@ def _all_bytestrings(): |
|
|
|
|
Yields: |
|
|
|
|
All bytestrings in ascending order of length. |
|
|
|
|
""" |
|
|
|
|
length = 1 |
|
|
|
|
while True: |
|
|
|
|
for bytestring in _bytestrings_of_length(length): |
|
|
|
|
yield bytestring |
|
|
|
|
length += 1 |
|
|
|
|
for bytestring in itertools.chain.from_iterable( |
|
|
|
|
_bytestrings_of_length(length) for length in itertools.count()): |
|
|
|
|
yield bytestring |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search(target, |
|
|
|
|