|
| 1 | +# Day Twenty-Five: Combo Breaker |
| 2 | + |
| 3 | +* [Problem statement](https://adventofcode.com/2020/day/25) |
| 4 | +* [Solution code](https://github.com/abyala/advent-2020-clojure/blob/master/src/advent_2020_clojure/day25.clj) |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +After 24 days of code hacking, our final puzzle is a little password hacking. True to form, the final day's |
| 9 | +puzzle is pretty simple, I assume because the coordinator of Advent Of Code wants to dissuade folks from |
| 10 | +banging our heads against the wall on Christmas day. |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## Part 1 |
| 15 | + |
| 16 | +There's not much to say here. We're given a cryptographic transformation algorithm that our private keys |
| 17 | +operate on a number of times to generate some output. Two systems, a key card and a door, both apply the |
| 18 | +cryptographic transformation on a common, widely-known secret to generate their public keys, which we are |
| 19 | +given as input. Then both the card and the door use their own private key (the looping factor) on the other's |
| 20 | +public key to generate the answer, ostensibly the shared encryption key. Because both the card and the door |
| 21 | +should generate the same encryption key, we only have to calculate it for either the card or the door, but my |
| 22 | +test case asserts that the two are equal. |
| 23 | + |
| 24 | +Because cracking the private key and generating the encryption key use the same transformation algorithm, |
| 25 | +I created `crypto-transform`, which generates an infinite sequence of transformation on its `subject-number` |
| 26 | +input. On each iteration, we take the previous value (starting with `1`), multiply it by the `subject-number`, |
| 27 | +and take the remainder after dividing by `20201227`. |
| 28 | + |
| 29 | +```clojure |
| 30 | +(defn crypto-transform [subject-number] |
| 31 | + (iterate #(-> (* % subject-number) (rem 20201227)) 1)) |
| 32 | +``` |
| 33 | + |
| 34 | +Then to crack the private key, we need to figure out how many loops through the transformation function it |
| 35 | +takes to generate the public key. We just use `keep-indexed` to find the first iteration when the output |
| 36 | +equals the public key, pulling out the index that represents the iteration number. |
| 37 | + |
| 38 | +```clojure |
| 39 | +(defn crack-private-key [subject-number public-key] |
| 40 | + (->> (crypto-transform subject-number) |
| 41 | + (keep-indexed (fn [idx v] (when (= v public-key) idx))) |
| 42 | + first)) |
| 43 | +``` |
| 44 | + |
| 45 | +Finally, given the two public keys, we can determine the encryption key, which is the goal of part 1. |
| 46 | +We start with the sequence of transformations of the second public key, looping the number of times equal |
| 47 | +to the first private key, which we get by calling `crack-private-key`. And again, the test code verifies |
| 48 | +this, rather than the application code, but `(part1 key1 key2)` equals `(part1 key2 key1)`. |
| 49 | + |
| 50 | +```clojure |
| 51 | +(defn part1 [key1-pub key2-pub] |
| 52 | + (->> (crypto-transform key2-pub) |
| 53 | + (drop (crack-private-key 7 key1-pub)) |
| 54 | + first)) |
| 55 | +``` |
| 56 | + |
| 57 | +--- |
| 58 | + |
| 59 | +## Part 2 |
| 60 | + |
| 61 | +There is no part 2. By finishing the first 49th stars, we get the 50th for free. Congratulations to all |
| 62 | +who participated in Advent Of Code this year! And a huge thanks to [@ericwastl](https://twitter.com/ericwastl) |
| 63 | +for putting together yet another fantastic coding event! |
0 commit comments