14 """A search algorithm over the space of all bytestrings."""
16 from __future__
import absolute_import
17 from __future__
import division
18 from __future__
import print_function
26 from examples.python.cancellation
import hash_name_pb2
28 _LOGGER = logging.getLogger(__name__)
33 """Calculates hamming distance between strings of equal length."""
35 for char_a, char_b
in zip(a, b):
42 """Calculates the minimum hamming distance between between the target
43 and any substring of the candidate.
46 candidate: The string whose substrings will be tested.
47 target: The target string.
50 The minimum Hamming distance between candidate and target.
53 if len(target) >
len(candidate):
54 raise ValueError(
"Candidate must be at least as long as target.")
58 if min_distance
is None or distance < min_distance:
59 min_distance = distance
64 hasher = hashlib.sha1()
66 return base64.b64encode(hasher.digest()).
decode(
'ascii')
70 """Signifies the request has exceeded configured limits."""
74 """Generates a stream containing all bytestrings of a given length.
77 length: A positive integer length.
80 All bytestrings of length `length`.
82 for digits
in itertools.product(
range(_BYTE_MAX), repeat=length):
83 yield b
''.join(struct.pack(
'B', i)
for i
in digits)
87 """Generates a stream containing all possible bytestrings.
89 This generator does not terminate.
92 All bytestrings in ascending order of length.
94 for bytestring
in itertools.chain.from_iterable(
103 interesting_hamming_distance=None):
104 """Find candidate strings.
106 Search through the space of all bytestrings, in order of increasing length,
107 indefinitely, until a hash with a Hamming distance of `maximum_distance` or
111 target: The search string.
112 ideal_distance: The desired Hamming distance.
113 stop_event: An event indicating whether the RPC should terminate.
114 maximum_hashes: The maximum number of hashes to check before stopping.
115 interesting_hamming_distance: If specified, strings with a Hamming
116 distance from the target below this value will be yielded.
119 Instances of HashNameResponse. The final entry in the stream will be of
120 `maximum_distance` Hamming distance or less from the target string,
121 while all others will be of less than `interesting_hamming_distance`.
124 ResourceLimitExceededError: If the computation exceeds `maximum_hashes`
129 if stop_event.is_set():
133 if interesting_hamming_distance
is not None and distance <= interesting_hamming_distance:
135 yield hash_name_pb2.HashNameResponse(
136 secret=base64.b64encode(secret),
137 hashed_name=candidate_hash,
138 hamming_distance=distance)
139 elif distance <= ideal_distance:
141 yield hash_name_pb2.HashNameResponse(
142 secret=base64.b64encode(secret),
143 hashed_name=candidate_hash,
144 hamming_distance=distance)
147 if hashes_computed == maximum_hashes: