From a8b4fb0be7c27f5f193bf7fa16c11690307edfcb Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Fri, 15 Jan 2021 22:32:32 -0800 Subject: [PATCH 1/7] Setup Day 25 --- AdventOfCode2020.cabal | 2 ++ src/Day25/README.md | 47 ++++++++++++++++++++++++++++++++++++++ src/Day25/Solution.hs | 7 ++++++ test/Day25/SolutionSpec.hs | 14 ++++++++++++ test/Day25/input.txt | 2 ++ 5 files changed, 72 insertions(+) create mode 100644 src/Day25/README.md create mode 100644 src/Day25/Solution.hs create mode 100644 test/Day25/SolutionSpec.hs create mode 100644 test/Day25/input.txt diff --git a/AdventOfCode2020.cabal b/AdventOfCode2020.cabal index fbf87bd..91336c1 100644 --- a/AdventOfCode2020.cabal +++ b/AdventOfCode2020.cabal @@ -54,6 +54,7 @@ library Day20.Solution Day21.Solution Day24.Solution + Day25.Solution Practice.Foldable Template.Solution other-modules: @@ -103,6 +104,7 @@ test-suite AdventOfCode2020-test Day20.SolutionSpec Day21.SolutionSpec Day24.SolutionSpec + Day25.SolutionSpec Practice.FoldableSpec Template.SolutionSpec Paths_AdventOfCode2020 diff --git a/src/Day25/README.md b/src/Day25/README.md new file mode 100644 index 0000000..1b714a2 --- /dev/null +++ b/src/Day25/README.md @@ -0,0 +1,47 @@ +## Day 25: Combo Breaker + +You finally reach the check-in desk. Unfortunately, their registration systems are currently offline, and they cannot check you in. Noticing the look on your face, they quickly add that tech support is already on the way! They even created all the room keys this morning; you can take yours now and give them your room deposit once the registration system comes back online. + +The room key is a small [RFID][1] card. Your room is on the 25th floor and the elevators are also temporarily out of service, so it takes what little energy you have left to even climb the stairs and navigate the halls. You finally reach the door to your room, swipe your card, and - _beep_ \- the light turns red. + +Examining the card more closely, you discover a phone number for tech support. + +"Hello! How can we help you today?" You explain the situation. + +"Well, it sounds like the card isn't sending the right command to unlock the door. If you go back to the check-in desk, surely someone there can reset it for you." Still catching your breath, you describe the status of the elevator and the exact number of stairs you just had to climb. + +"I see! Well, your only other option would be to reverse-engineer the cryptographic handshake the card does with the door and then inject your own commands into the data stream, but that's definitely impossible." You thank them for their time. + +Unfortunately for the door, you know a thing or two about cryptographic handshakes. + +The handshake used by the card and the door involves an operation that _transforms_ a _subject number_ . To transform a subject number, start with the value `1` . Then, a number of times called the _loop size_ , perform the following steps: + +- Set the value to itself multiplied by the _subject number_ . +- Set the value to the remainder after dividing the value by _`20201227`_ . + +The card always uses a specific, secret _loop size_ when it transforms a subject number. The door always uses a different, secret loop size. + +The cryptographic handshake works like this: + +- The _card_ transforms the subject number of _`7`_ according to the _card's_ secret loop size. The result is called the _card's public key_ . +- The _door_ transforms the subject number of _`7`_ according to the _door's_ secret loop size. The result is called the _door's public key_ . +- The card and door use the wireless RFID signal to transmit the two public keys (your puzzle input) to the other device. Now, the _card_ has the _door's_ public key, and the _door_ has the _card's_ public key. Because you can eavesdrop on the signal, you have both public keys, but neither device's loop size. +- The _card_ transforms the subject number of _the door's public key_ according to the _card's_ loop size. The result is the _encryption key_ . +- The _door_ transforms the subject number of _the card's public key_ according to the _door's_ loop size. The result is the same _encryption key_ as the _card_ calculated. + +If you can use the two public keys to determine each device's loop size, you will have enough information to calculate the secret _encryption key_ that the card and door use to communicate; this would let you send the `unlock` command directly to the door! + +For example, suppose you know that the card's public key is `5764801` . With a little trial and error, you can work out that the card's loop size must be _`8`_ , because transforming the initial subject number of `7` with a loop size of `8` produces `5764801` . + +Then, suppose you know that the door's public key is `17807724` . By the same process, you can determine that the door's loop size is _`11`_ , because transforming the initial subject number of `7` with a loop size of `11` produces `17807724` . + +At this point, you can use either device's loop size with the other device's public key to calculate the _encryption key_ . Transforming the subject number of `17807724` (the door's public key) with a loop size of `8` (the card's loop size) produces the encryption key, _`14897079`_ . (Transforming the subject number of `5764801` (the card's public key) with a loop size of `11` (the door's loop size) produces the same encryption key: _`14897079`_ .) + +_What encryption key is the handshake trying to establish?_ + +## Link + +[https://adventofcode.com/2020/day/25][2] + +[1]: https://en.wikipedia.org/wiki/Radio-frequency_identification +[2]: https://adventofcode.com/2020/day/25 diff --git a/src/Day25/Solution.hs b/src/Day25/Solution.hs new file mode 100644 index 0000000..474a43b --- /dev/null +++ b/src/Day25/Solution.hs @@ -0,0 +1,7 @@ +module Day25.Solution where + +part1 :: String -> String +part1 = head . lines + +part2 :: String -> String +part2 = head . lines diff --git a/test/Day25/SolutionSpec.hs b/test/Day25/SolutionSpec.hs new file mode 100644 index 0000000..fcd5ff6 --- /dev/null +++ b/test/Day25/SolutionSpec.hs @@ -0,0 +1,14 @@ +module Day25.SolutionSpec (spec) where + +import Day25.Solution +import Test.Hspec + +spec :: Spec +spec = parallel $ do + xit "solves Part 1" $ do + input <- readFile "./test/Day25/input.txt" + part1 input `shouldBe` "hello_santa" + + xit "solves Part 2" $ do + input <- readFile "./test/Day25/input.txt" + part2 input `shouldBe` "hello_santa" diff --git a/test/Day25/input.txt b/test/Day25/input.txt new file mode 100644 index 0000000..c2d1055 --- /dev/null +++ b/test/Day25/input.txt @@ -0,0 +1,2 @@ +13135480 +8821721 From bb513670248b67c8947ef849584986d67dec66cd Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Sat, 16 Jan 2021 14:50:54 -0800 Subject: [PATCH 2/7] Solve part 1 --- src/Day25/NOTES.md | 61 ++++++++++++++++++++++++++++++++++++++ src/Day25/Solution.hs | 25 +++++++++++++++- test/Day25/SolutionSpec.hs | 29 ++++++++++++++++-- 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 src/Day25/NOTES.md diff --git a/src/Day25/NOTES.md b/src/Day25/NOTES.md new file mode 100644 index 0000000..38ee18d --- /dev/null +++ b/src/Day25/NOTES.md @@ -0,0 +1,61 @@ +## NOTES + +`transform subjectNumber loopSize` appears to be `subjectNumber ^ loopSize mod 20201227` + +https://www.wolframalpha.com/input/?i=%287+%5E+x%29+mod+20201227 + +```hs +(7 ^ x) mod 20201227 +x = floor (log 20201227 / log 7) +``` + +### HandShake steps + +```hs + +-- cardsPublicKey' = transform 7 +-- doorsPublicKey' = transform 7 + +-- = crack 7 cardsPublicKey +-- = crack 7 doorsPublicKey + +-- encryptionKey = transform doorsPublicKey +-- encryptionKey = transform cardsPublicKey + +-- encryptionKey = transform doorsPublicKey (crack 7 cardsPublicKey) +-- encryptionKey = transform cardsPublicKey (crack 7 doorsPublicKey) +``` + +```hs + +cardsPublicKey :: Int +cardsPublicKey = 5764801 + +doorsPublicKey :: Int +doorsPublicKey = 17807724 + +>>> transform 7 8 +5764801 + +>>> crack 7 cardsPublicKey +8 + +>>> transform 7 11 +17807724 + +>>> crack 7 doorsPublicKey +11 + +>>> transform doorsPublicKey (crack 7 cardsPublicKey) +14897079 + +>>> transform cardsPublicKey (crack 7 doorsPublicKey) +14897079 +``` + +## Seed values + +I still don't know how to solve equations that have `mod` and wolfram alpha +does. + +I got the `seed` value from here: https://www.wolframalpha.com/input/?i=%287%5Ex%29+mod+20201227%3D13135480 diff --git a/src/Day25/Solution.hs b/src/Day25/Solution.hs index 474a43b..17cade2 100644 --- a/src/Day25/Solution.hs +++ b/src/Day25/Solution.hs @@ -1,7 +1,30 @@ module Day25.Solution where +import Advent.Utils + part1 :: String -> String -part1 = head . lines +part1 = show . findEncryptionKey 7 1591838 . readPublicKeys part2 :: String -> String part2 = head . lines + +type LoopSize = Integer + +type SubjectNumber = Integer + +readPublicKeys :: String -> (Integer, Integer) +readPublicKeys = asPair . map read . lines + where + asPair (a : b : _) = (a, b) + asPair _ = undefined + +transform :: SubjectNumber -> LoopSize -> SubjectNumber +transform subjectNumber privateKey = (subjectNumber ^ privateKey) `mod` 20201227 + +crack :: LoopSize -> Integer -> SubjectNumber -> SubjectNumber +crack loopSize privateKey publicKey + | transform loopSize privateKey == publicKey = privateKey + | otherwise = undefined + +findEncryptionKey :: LoopSize -> Integer -> (Integer, Integer) -> Integer +findEncryptionKey loopSize seed (a, b) = transform b (crack loopSize seed a) diff --git a/test/Day25/SolutionSpec.hs b/test/Day25/SolutionSpec.hs index fcd5ff6..225e83e 100644 --- a/test/Day25/SolutionSpec.hs +++ b/test/Day25/SolutionSpec.hs @@ -5,10 +5,35 @@ import Test.Hspec spec :: Spec spec = parallel $ do - xit "solves Part 1" $ do + it "solves Part 1" $ do input <- readFile "./test/Day25/input.txt" - part1 input `shouldBe` "hello_santa" + part1 input `shouldBe` "8329514" xit "solves Part 2" $ do input <- readFile "./test/Day25/input.txt" part2 input `shouldBe` "hello_santa" + + let cardsPrivateKey = 8 + let cardsPublicKey = 5764801 + let doorsPrivateKey = 11 + let doorsPublicKey = 17807724 + let encryptionKey = 14897079 + describe "transform" $ do + context "given cardsPrivateKey" $ + it "is cardsPublicKey" $ do + transform 7 cardsPrivateKey `shouldBe` cardsPublicKey + context "given doorsPrivateKey" $ + it "is doorsPublicKey" $ do + transform 7 doorsPrivateKey `shouldBe` doorsPublicKey + describe "crack" $ do + context "given cardsPublicKey" $ + it "is cardsPrivateKey" $ do + crack 7 11 cardsPublicKey `shouldBe` cardsPrivateKey + context "given doorsPublicKey" $ + it "is doorsPrivateKey" $ do + crack 7 11 doorsPublicKey `shouldBe` doorsPrivateKey + describe "findEncryptionKey" $ do + it "is the encryptionKey" $ do + findEncryptionKey 7 11 (doorsPublicKey, cardsPublicKey) `shouldBe` encryptionKey + it "is the encryptionKey" $ do + findEncryptionKey 7 11 (cardsPublicKey, doorsPublicKey) `shouldBe` encryptionKey From 8e462b69190f52918512b419f5af361582be7a77 Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Sat, 16 Jan 2021 14:53:18 -0800 Subject: [PATCH 3/7] Update specs --- test/Day25/SolutionSpec.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Day25/SolutionSpec.hs b/test/Day25/SolutionSpec.hs index 225e83e..1a1c3a8 100644 --- a/test/Day25/SolutionSpec.hs +++ b/test/Day25/SolutionSpec.hs @@ -28,12 +28,12 @@ spec = parallel $ do describe "crack" $ do context "given cardsPublicKey" $ it "is cardsPrivateKey" $ do - crack 7 11 cardsPublicKey `shouldBe` cardsPrivateKey + crack 7 cardsPrivateKey cardsPublicKey `shouldBe` cardsPrivateKey context "given doorsPublicKey" $ it "is doorsPrivateKey" $ do - crack 7 11 doorsPublicKey `shouldBe` doorsPrivateKey + crack 7 doorsPrivateKey doorsPublicKey `shouldBe` doorsPrivateKey describe "findEncryptionKey" $ do it "is the encryptionKey" $ do - findEncryptionKey 7 11 (doorsPublicKey, cardsPublicKey) `shouldBe` encryptionKey + findEncryptionKey 7 doorsPrivateKey (doorsPublicKey, cardsPublicKey) `shouldBe` encryptionKey it "is the encryptionKey" $ do - findEncryptionKey 7 11 (cardsPublicKey, doorsPublicKey) `shouldBe` encryptionKey + findEncryptionKey 7 cardsPrivateKey (cardsPublicKey, doorsPublicKey) `shouldBe` encryptionKey From 19913ebdb22613660cdff2225ae24225231b2b7e Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Sat, 16 Jan 2021 14:53:49 -0800 Subject: [PATCH 4/7] Update readme to include part 2 --- src/Day25/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Day25/README.md b/src/Day25/README.md index 1b714a2..d7610f4 100644 --- a/src/Day25/README.md +++ b/src/Day25/README.md @@ -39,9 +39,24 @@ At this point, you can use either device's loop size with the other device's pub _What encryption key is the handshake trying to establish?_ +## Part Two + +The light turns green and the door unlocks. As you collapse onto the bed in your room, your pager goes off! + +"It's an emergency!" the Elf calling you explains. "The [soft serve][2] machine in the cafeteria on sub-basement 7 just failed and you're the only one that knows how to fix it! We've already dispatched a reindeer to your location to pick you up." + +You hear the sound of hooves landing on your balcony. + +The reindeer carefully explores the contents of your room while you figure out how you're going to pay the _50 stars_ you owe the resort before you leave. Noticing that you look concerned, the reindeer wanders over to you; you see that it's carrying a small pouch. + +"Sorry for the trouble," a note in the pouch reads. Sitting at the bottom of the pouch is a gold coin with a little picture of a starfish on it. + +Looks like you only needed _49 stars_ after all. + ## Link -[https://adventofcode.com/2020/day/25][2] +[https://adventofcode.com/2020/day/25][3] [1]: https://en.wikipedia.org/wiki/Radio-frequency_identification -[2]: https://adventofcode.com/2020/day/25 +[2]: https://en.wikipedia.org/wiki/Soft_serve +[3]: https://adventofcode.com/2020/day/25 From 968853c2306df9bd35401503fb6b1db826517b6c Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Sun, 17 Jan 2021 18:46:58 -0800 Subject: [PATCH 5/7] Update readme to include links to solution --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 730af99..c39cb8f 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,10 @@ Solutions to adventofcode.com/2020 | [PR #38](https://github.com/manuphatak/HaskellAdventOfCode2020/pull/38) | Day 22: Crab Combat | [src/Day22/Solution.hs](src/Day22/Solution.hs) | [test/Day22/SolutionSpec.hs](test/Day22/SolutionSpec.hs) | | [PR #40](https://github.com/manuphatak/HaskellAdventOfCode2020/pull/40) | Day 23: Crab Cups | `[in progress, 2 stars]` | `[in progress]` | | [PR #44](https://github.com/manuphatak/HaskellAdventOfCode2020/pull/44) | Day 24: Lobby Layout | [src/Day24/Solution.hs](src/Day24/Solution.hs) | [test/Day24/SolutionSpec.hs](test/Day24/SolutionSpec.hs) | -| [PR #45](https://github.com/manuphatak/HaskellAdventOfCode2020/pull/45) | Day 25: Combo Breaker | `[in progress, 1 star ]` | `[in progress]` | +| [PR #45](https://github.com/manuphatak/HaskellAdventOfCode2020/pull/45) | Day 25: Combo Breaker | [src/Day25/Solution.hs](src/Day25/Solution.hs) | [test/Day25/SolutionSpec.hs](test/Day25/SolutionSpec.hs) | - ## Run tests From 24ee23e5d1a7968d74dc9734d01044c7fd92dffe Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Sun, 17 Jan 2021 18:48:49 -0800 Subject: [PATCH 6/7] Use explicit imports --- src/Day25/Solution.hs | 11 ++++++++--- test/Day25/SolutionSpec.hs | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Day25/Solution.hs b/src/Day25/Solution.hs index 17cade2..a776850 100644 --- a/src/Day25/Solution.hs +++ b/src/Day25/Solution.hs @@ -1,6 +1,11 @@ -module Day25.Solution where - -import Advent.Utils +module Day25.Solution + ( crack, + findEncryptionKey, + part1, + part2, + transform, + ) +where part1 :: String -> String part1 = show . findEncryptionKey 7 1591838 . readPublicKeys diff --git a/test/Day25/SolutionSpec.hs b/test/Day25/SolutionSpec.hs index 1a1c3a8..c845582 100644 --- a/test/Day25/SolutionSpec.hs +++ b/test/Day25/SolutionSpec.hs @@ -1,6 +1,12 @@ module Day25.SolutionSpec (spec) where import Day25.Solution + ( crack, + findEncryptionKey, + part1, + part2, + transform, + ) import Test.Hspec spec :: Spec From 02f29054fcc1957f52a2369bfc9e0d354c7ced3e Mon Sep 17 00:00:00 2001 From: Manu Phatak Date: Mon, 18 Jan 2021 08:58:49 -0800 Subject: [PATCH 7/7] Remove part 2 --- src/Day25/Solution.hs | 4 ---- test/Day25/SolutionSpec.hs | 5 ----- 2 files changed, 9 deletions(-) diff --git a/src/Day25/Solution.hs b/src/Day25/Solution.hs index a776850..735b5e2 100644 --- a/src/Day25/Solution.hs +++ b/src/Day25/Solution.hs @@ -2,7 +2,6 @@ module Day25.Solution ( crack, findEncryptionKey, part1, - part2, transform, ) where @@ -10,9 +9,6 @@ where part1 :: String -> String part1 = show . findEncryptionKey 7 1591838 . readPublicKeys -part2 :: String -> String -part2 = head . lines - type LoopSize = Integer type SubjectNumber = Integer diff --git a/test/Day25/SolutionSpec.hs b/test/Day25/SolutionSpec.hs index c845582..f577f59 100644 --- a/test/Day25/SolutionSpec.hs +++ b/test/Day25/SolutionSpec.hs @@ -4,7 +4,6 @@ import Day25.Solution ( crack, findEncryptionKey, part1, - part2, transform, ) import Test.Hspec @@ -15,10 +14,6 @@ spec = parallel $ do input <- readFile "./test/Day25/input.txt" part1 input `shouldBe` "8329514" - xit "solves Part 2" $ do - input <- readFile "./test/Day25/input.txt" - part2 input `shouldBe` "hello_santa" - let cardsPrivateKey = 8 let cardsPublicKey = 5764801 let doorsPrivateKey = 11