Sean McLemon | Advent of Code

Home | Czech | Blog | GitHub | Advent Of Code | Notes


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