2016-12-14 - One-Time Pad
(original .ipynb)
test_input_str = "abc"
puzzle_input_str = "qzyelonm"
from hashlib import md5
def has_triplet(md5_hash):
for i, c in enumerate(md5_hash):
if i >= len(md5_hash) - 2:
break
if md5_hash[i+1] == c and md5_hash[i+2] == c:
return c
return None
def plain_hash(input_str):
m = md5()
to_encode = (input_str).encode()
m.update(to_encode)
return m.hexdigest()
def find_key(input_str, hasher):
hashes = []
index = 0
while index <= 1000:
hashes.append((index, hasher(input_str + str(index))))
index += 1
keys = 0
while True:
prev_index, md5_hash = hashes.pop(0)
if triplet := has_triplet(md5_hash):
quintuplet = 5 * triplet
for _, other_md5_hash in hashes:
if quintuplet in other_md5_hash:
keys += 1
if keys == 64:
return prev_index
break
hashes.append((index, hasher(input_str + str(index))))
index += 1
return -1
def part_one(input_str):
return find_key(input_str, plain_hash)
assert 22728 == part_one(test_input_str)
print("part one:", part_one(puzzle_input_str))
part one: 15168
def stretched_hash(to_hash):
n = 2016
while n >= 0:
to_hash = plain_hash(to_hash)
n -= 1
return to_hash
def part_two(input_str):
return find_key(input_str, stretched_hash)
assert 22551 == part_two(test_input_str)
print("part two:", part_two(puzzle_input_str))
part two: 20864