Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Breaking the Unbreakable Code Whose Breaking Wo...

Ajina Slater
December 27, 2024
4

Breaking the Unbreakable Code Whose Breaking Won World War II

Ajina Slater

December 27, 2024
Tweet

Transcript

  1. ENIGMA T HE UNBRE A KABLE D 5 W HOSE

    BRE A KING : W ON WORLD WAR T I SN CUYRB S JCNER V 5 O PLKI ODU W RCNS : Z AD SDERT STT M PYMSPQ it's been a long day, good day but long, so if you're able, please stand up for a second we're going to do a little stretch, get some blood fl owing, a few endorphins pumping diving into the pool
  2. t h o u g h t b o t

    I work at a place called thoughtbot
  3. You may have learned in the 1930s and 40s, there

    was a war Involving many nations and peoples across the globe so many in fact, they called it a "World War" the second of its kind
  4. the particulars of the con fl ict are not what

    we're going to discuss today If you're interested in the period, I believe there have been a few movies, tv shows, even books where you can fi nd out more
  5. For our purposes today all that's important is you know

    that on opposing sides of the con fl ict were Germany and the United Kingdom.
  6. and at the time, long distance communication was done in

    morse code over radio and could be intercepted by an opponent.. in much the same way we "intercept" the local top 40 station...the messages needed to be encrypted
  7. the German solution for encryption was this, the Enigma machine

    not that much bigger than a typewriter, Enigma would encipher a given message before it was sent over the airwaves
  8. The receiver of the message would also have an Enigma,

    given the same settings that encoded the transmission, they could reconstruct the original message
  9. The British solution for *DE*crypting was this, Bletchley Park. Housed

    at this estate in Buckinghamshire was Britain's GC&CS: Government Code and Cipher School Their work kept secret until the 1970s, several thousand men and women, mostly women, mostly college aged, were tasked with cracking the German encyphering system.
  10. If you know of Bletchley, the story you've likely heard

    is his Alan Turing, of the Turing Test, Turing Machines, Turing Patterns, the negative proof of the Entscheidungsproblem
  11. Turing realized that a quirk of the Enigma's wiring could

    be exploited, and designed a special-purpose computational engine that was made real by the engineering brilliance of Harold Keen and the British Tabulating Machine Company
  12. Bletchley's secret weapon was christened "Bombe" on 108 cacophonous rotating

    drums crunched through 17,576 possible enigma settings in just 20 minutes
  13. T he Se c re tƒ L ives o f

    ‹ C odebr e ak e rs $ S incla i r ‹ M c Ka y If you're interested in hearing more about what it was like to be a part of Bletchley's operation.. I would recommend "The Secret Lives of Codebreakers" by Sinclair McKay
  14. The enigma was operated by German communications agents working in

    pairs, ⭐ one to operate the keyboard, entering the message.As a key was pressed ⭐ the corresponding letter would light up on the lampboard and be written down by the second. It worked like this...
  15. A A A A It's a simple electric circuit. If

    you're unfamiliar, think of the wire as a tube that carries electricity. When the switch is down, ⭐ the signal fl ows, when that signal touches a light, it will illuminate.
  16. A A A Now imagine there are more of these

    simple circuits, 26 in all
  17. A A A B B B C C C D

    D D B C D A A to A, B to B,
  18. A B C D A C D B B C

    D If the connections between the key and and light are changed
  19. B C D A C D A A B B

    C D Then the signal would be encoded. Press the "A" key ⭐ and "B" lights up. Knowing what letters connected, you would be able to decode it as well. That's the job of the enigma's encryption mechanism, it physically swaps the electrical connection between the key and the light.
  20. A B C D E F G H I J

    K L M N O S A B C D E F G H I J K L M N O S W X Y Z maybe you've made a code like this before
  21. A B C D E F G H I J

    K L M N O S A B C D E F G H I J K L M N O S W X Y Z W X Y Z when one letter is replaced by another like this it's known as a substitution cypher
  22. A B C D E F G H I J

    K L M N O S A B C D E F G H I J K L M N O S but no matter how much the key is scrambled, substitution cyphers are trivial to break. Enigma was more
  23. L e ft R i gh t each has 26

    electrical contacts on each side ⭐ and could be turned to set the machine at any of those positions.
  24. internally a wire goes from a contact on ⭐ one

    side to a di ff erent contact on the other
  25. so the signal might come in to ⭐ index 0

    on the right side, and be wired to index 8 on the left, ⭐ then 2 to 21, ⭐ 3 to 14 etc
  26. A A A B C D E F G H

    I J K L M N O S A B C D E F G H I J K L M N O S D if it remained as simple as a substitution cypher, it would be just as easy to decode
  27. I

  28. I I I I I I so Enigma accepted three

    rotors, each with di ff erent internal connections
  29. I I I I I I I V V and

    there weren't only 3 rotors but a set of 5 to choose from
  30. I I I I I I I V V and

    those 5 could be entered in any order for 60 possible combinations
  31. I I I I I I I V V and

    those 5 could be entered in any order for 60 possible combinations
  32. I I I I I I I V V and

    those 5 could be entered in any order for 60 possible combinations
  33. I I I I I I I V V and

    those 5 could be entered in any order for 60 possible combinations
  34. I I I I I I I V V and

    those 5 could be entered in any order for 60 possible combinations
  35. I I I I V I I I V when

    mounted on the internal spindle, the rotors' 26 connection points lined up, and a signal could be sent through them
  36. A A 0 5 4 8 coming in from the

    keyboard and be switched to di ff erent indexes by each rotor in turn
  37. A A B E after the three rotors came a

    special symmetric rotor called ⭐ a re fl ector. here if 1 becomes 10, 10 becomes 1. ⭐ after passing through the re fl ector, the signal would be carried back on a di ff erent path of connections.
  38. A B E A this is how enigma both encrypted

    and decrypted, because the path of the signal is symmetrical, typing the cipher character will return the original ⭐ but no matter how many times a letter is changed, it's weak if A always becomes E
  39. B E A A J so the rotors ⭐ rotated

    after each character ⭐ the signal taking a new path through. the same key pressed twice in a row would yield two di ff erent encoded letters.
  40. techniques that make a substitution cypher easy to break rely

    on repetition...are useless now. A key that changes not once a day, not once a message, but once per KEYSTROKE
  41. and they didn't all rotate at the same speed. the

    second wheel wouldn't advance until the fi rst one made a full revolution.. and so on. (self advances)
  42. that means Enigma is a polyalphabetic cypher with a new

    key every letter based on the starting settings.
  43. at the front of each device was a plugboard with

    a connection for each letter. Up to 10 combinations could be made with short cables
  44. A A E H cables that would change the signal's

    value between the keyboard and rotor mechanism ⭐ e ff ectively making small arbitrary changes to the cypher's key
  45. In order for the German military to all be speaking

    the same cypher, a chart would be sent out from High command, prescribing which settings should be used on a given day. Essential coordination, because only by sharing the same starting settings would agents be able to communicate. The chart included
  46. which of the fi ve rotors to use and in

    which order ⭐ the starting positions of the rotors ⭐ and the ten pairs of plugboard connections
  47. 1 , 05 4,5 5 87 0 7 3 63

    1 5 2 848 954 6 5 2 6 9 9 778 68 23 2 8 84 6 8 5 4 8094 9 5 73 2 0 15 22 7 1 5 8, 9 6 2, 5 5 5 , 2 1 7 , 6 5 ! ( ! 21 0 2 ! ( ! . . 1 ! 2 6 3 . . combining all these options takes the possible settings to an astronomical ⭐ 150 million million million. portable electromechanical encryption equivalent to a 67 bit encryption key.
  48. It's a remarkable object. that's a key word today-- object.

    Because Enigma will be our platform to explore principles of Object Oriented Programming, O.O.P. oop.
  49. a strength of which is said to be how it

    "models the real world." but objects in the real world are very di ff erent than objects in a codebase
  50. Enigma on the other hand.. is a physical device. it

    has _moving parts_. Actual objects that each perform a part of the larger whole by sending messages ..along a wire to other objects.
  51. i n si d e B l e tch ley'

    s c o debr ea k ing op e r a t i o n If the image we're supposed to have of OOP is objects sending messages, Enigma might as well be its mascot
  52. a Tu r in g - W elc hman B

    o m be we can recreate this mechanism in code, without abstracting our conception of an object beyond recognition
  53. B l et c hl e y Par k co

    d e b r eake rs reu nio n 2 0 0 9 because we could literally hold in our hands the pieces of an encryption algorithm
  54. T wo Truth sƒ o f So ftwa r e

    Dev e l o p me 1 . Requi r e me n ts wi l l ch an . 2 . We wi l l n e ve r k n ow l es t H we do r ig h t now . Let's go big right from the start with two Truths of software development ⭐ requirements will change. And this is good. If nothing needs to change, there probably aren't any users, and we'll need to fi nd another job ⭐ we will never know less than we do right now because we don't know HOW things will change
  55. T wo Truth sƒ o f So ftwa r e

    Dev e l o p me 1 . Requi r e me n ts wi l l ch an . 2 . We wi l l n e ve r k n ow l es t H we do r ig h t now . and it's frustrating when we can't make changes, right? When a new feature request comes along and we can't deliver it to users because it would be too hard to implement?
  56. T wo Truth sƒ o f So ftwa r e

    Dev e l o p me 1 . Requi r e me n ts wi l l ch an . 2 . We wi l l n e ve r k n ow l es t H we do r ig h t now . That's an awful feeling. We don't want to be there. but if we don't know anything.. and it's all going to change.. how CAN we build anything?
  57. O b j ect O r i en t ed

    De s ign object oriented design is one strategy to do just that
  58. m a k ing c h a ng e e

    asi e r 5 b y manag i n g d ep end e ncie s O b j ect O r i en t ed De s ign OO design is about making change easier by managing dependencies.
  59. S in gle R e s po ns ibi l

    i i A c lass s h ou l d hav eƒ o n l y one r es p on sib i lity , 0 o n e reas o n t o c han g e Single Responsibility Principle: we'll gather together the things that change for the same reasons and separate those that change for di ff erent reasons
  60. A bs tract i o n E x p ose

    t h e inte n t o f a n e n o t the i m pl e me nta t ion. Abstraction: we'll manage the complexity of implementation by substituting a more-easy-to-reason-about representation
  61. E nc apsul a t io n P r e

    vent e x t e r nal c o de f r b i n v o l v e d w i t h t h e i w o r kings o f a n obj e ct. Encapsulation: Object's internal data should change on that object's own terms
  62. D ep enden c y I nv ers i o

    H i g h-lev e l m o du les shou ld o i m p ort a n y th i ng fr o m lo w- v m o d ules. B ot h s hou l d de pe i n t erfac e s . Dependency Inversion: conventional architecture would have utility modules (low-level) consumed by higher-level ones, but we'll invert this thinking and increase reuse from top to bottom through interfaces
  63. O pe n / C l o se d Pri

    n c S o f tware e nt i ti es s houl d f o r exte n s io n , but clos ed ¡ f o r modi f i ca t io n. Open/Closed Principle: an object should allow its behavior to be extended without modifying it's own code.
  64. s ma ll si m p le o bje c

    t 5 s en ding m e ss ag es All of this in service of 'small simple objects sending messages'
  65. A Minitest test suite is made of Ruby classes and

    methods, tests we write will be de fi ned inside a class that inherits from Minitest::Test we can get things moving by thinking at a high level. What does our Enigma need to do?
  66. Minitest is not a DSL, tests are methods in our

    class whose names start with the word test.
  67. we'll initialize an instance of our Enigma class and call

    a cypher method asserting that it returns a string, and that string is not the one we started with.
  68. Terminal.app # Running... F 1 runs, 2 assertions, 1 failures,

    0 errors, 0 skips > ruby enigma_test.rb We invoke the test fi le from the command line. By requiring 'minitest/autorun' like we have, Minitest will fi nd all the runnable subclasses and tell them to do their thing. ⭐ which right now is to fail
  69. Terminal.app ruby enigma_test.rb # Running... F 1 runs, 2 assertions,

    1 failures, 0 errors, 0 skips > There isn't any code yet, so if that had passed, we would KNOW its a bad test.
  70. Terminal.app ruby enigma_test.rb # Running... FF 2 runs, 4 assertions,

    2 failures, 0 errors, 0 skips > we can make sure it's not "A", and that cyphering "B" isn't the same result. Is this test going to pass? ⭐ No! of course not
  71. Add an Alphabet constant, and a substitution key, with the

    order of real World War II enigma rotors
  72. we'll make use of the rotor being an array. Get

    the index of the message character from the Alphabet then through that-- a letter from the rotor.
  73. Terminal.app ruby enigma_test.rb # Running... .. 2 runs, 4 assertions,

    0 failures, 0 errors, 0 skips > and we do it three times! Show us the tests! ⭐ Nailed it!
  74. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Adds initial Enigma class w/ cypher method
  75. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Made use of Test Driven Development flow, and set up initial Enigma file and functionality. Made use of Test Driven Development fl ow, and set up initial Enigma fi le and functionality.
  76. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Made use of Test Driven Development flow, and set up initial Enigma file and functionality. The person in the front row over here really liked it. The person in the front row over here really liked it.
  77. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Made use of Test Driven Development flow, and set up initial Enigma file and functionality. The person in the front row over here really liked it. He was nodding _a lot_. He was nodding _a lot_
  78. If you need a primer on writing useful commit messages,

    ⭐ I hear this talk is pretty good.
  79. Tests are green, let's refactor. Red, Green, Refactor. But this

    is not a talk about TDD. ⭐ this is tho, you should watch this later
  80. oh for sure but to make sure we're on the

    right track we should ask ourselves, "are these lines going to change for the same reason?"
  81. Are they doing the same thing, do they have the

    same responsibility? Yes, absolutely. They're responsible for how we convert a character into it's matching integer.
  82. So we gather together things that change for the same

    reason, to create a single source of truth
  83. Terminal.app ruby enigma_test.rb # Running... .. 2 runs, 4 assertions,

    0 failures, 0 errors, 0 skips > replace all the `ALPHABET.index` calls with our new method, and radio for backup ⭐ Situation green, 10-4 good buddy, over and out
  84. by introducing a translate method, we create the source of

    truth for using the rotors. If that needs to change, we can change it in one place, rather than three.
  85. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # on branch RubyConf Extracts alpha_index and translate to private methods Did it work? Commit! ⭐ Extracts alpha_index and translate to private methods.
  86. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # on branch RubyConf Extracts alpha_index and translate to private methods We gathered the lines that would change for the same reason. We gathered the lines that would change for the same reason.
  87. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # on branch RubyConf Extracts alpha_index and translate to private methods We gathered the lines that would change for the same reason. Guided by The Single Responsibility Principle to create a single source of truth for those behaviors. Guided by The Single Responsibility Principle to create a single source of truth for those behaviors.
  88. One bene fi t from extracting methods is: we get

    to name things. Then what the Enigma class is really up to is easier to see.
  89. We can see its translating, cyphering, that's what we expect

    the Enigma to do.. but it's also handling input?
  90. Enigma converts letters to numbers AND uses those numbers to

    get a new string. Words like AND, OR, ALSO, used in describing our class can be a sign that it's doing too much.
  91. let's create a new collaborator where indexing IS its purpose.

    If we think of the actual Enigma, maybe that's the keyboard.
  92. test that it converts letter to alpha index. that's the

    behavior we're trying to move to the keyboard. Some simple assertions, do the letters change the way we would expect?
  93. Terminal.app ruby keyboard_test.rb # Running... . 1 runs, 2 assertions,

    0 failures, 0 errors, 0 skips > Simple Green! back to Enigma
  94. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    > # Running... ... 3 runs, 6 assertions, 0 failures, 0 errors, 0 skips we're at a point where all the pieces should fi t together again, but do our tests agree? ⭐ oh! we also have more than one test fi le now, so we'll use a little ruby command line magic to run every fi le that ends in `_test.rb` ⭐ magni fi cent
  95. A A A G H E Aƒ Bƒ Cƒ Dƒ

    E Iƒ Fƒ Gƒ Cƒ Bƒ Eƒ Dƒ Hƒ A Aƒ Bƒ Cƒ Dƒ Eƒ Fƒ Gƒ Hƒ I Fƒ Gƒ Hƒ I Hƒ Fƒ Eƒ Dƒ Gƒ Aƒ Iƒ Bƒ C Cƒ Dƒ Iƒ Hƒ Aƒ Dƒ Eƒ Bƒ F Dƒ Eƒ Aƒ Cƒ Fƒ Bƒ Gƒ Iƒ H 0 5 4 8 A I Because we're converting alpha to int and back between each rotor, we're not correctly following the connections through our device. ⭐ How do we correct? ⭐ integers the whole way through, convert only up front and at the end.
  96. to convert just once and stay an integer until the

    end. (fox) what do the tests say..
  97. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ... 3 runs, 6 assertions, 0 failures, 0 errors, 0 skips > ooh kermit was wrong. so easy bein' green.
  98. its the keyboard but in reverse. not alphabet dot index

    -> get integer, it's start with an integer -> get back to the letter
  99. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... .... 4 runs, 8 assertions, 0 failures, 0 errors, 0 skips > greener than Al Gore on Arbor Day
  100. let's try this-- I'll say "did it work?" you say

    "commit!" 👆 did it work? 👉 (commit!) alright. some of you were paying attention. some of you weren't. s'okay... I'll get over it.... eventually. (( SKIP SUCCESS KID IF NO RESPONSE AT ALL ))
  101. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts alpha/int translation to classes of their own (again) 👆 did it work? 👉 (commit!) ⭐ alright! I'm not the only person that thinks this looks like a young Patton Oswalt, am I? This commit.. extracts alpha/int translation to classes of their own
  102. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts alpha/int translation to classes of their own (again) 👆 did it work? 👉 (commit!) ⭐ alright! This commit.. extracts alpha/int translation to classes of their own
  103. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts alpha/int translation to classes of their own Before this, Enigma methods contained the code that implemented the behavior, preventing flexibility and reuse. Before this, Enigma methods contained the code that implemented the behavior, preventing fl exibility and reuse.
  104. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts alpha/int translation to classes of their own Before this, Enigma methods contained the code that implemented the behavior, preventing flexibility and reuse. We extracted self-contained functionality, replacing the specific code with a message sent to new collaborators. We extracted self-contained functionality, replacing the speci fi c code with a message sent to new collaborators.
  105. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts alpha/int translation to classes of their own Before this, Enigma methods contained the code that implemented the behavior, preventing flexibility and reuse. We extracted self-contained functionality, replacing the specific code with a message sent to new collaborators. This abstraction makes Enigma lighter, easier to understand, and opens it to new functionality. The Smaller classes offer utility and reuse to other parts of a larger system. This abstraction makes Enigma lighter, easier to understand, and opens it to new functionality. The Smaller classes o ff er utility and reuse to other parts of a larger system.
  106. test that it encyphers according to settings Enigma's settings would

    be changed by the operator, so let's add that
  107. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... .F... 5 runs, 9 assertions, 1 failures, 0 errors, 0 skips > and a failure is the precise result we expected here, we have written no new code.
  108. We've begun replacing the literal references to arrays with an

    abstraction that allows this class to be much less involved in the implementation
  109. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ..... 5 runs, 9 assertions, 0 failures, 0 errors, 0 skips > green like Donatello. ...ninja turtle, not sculptor.
  110. There's an object hiding in this class, and it's not

    even hiding very well. Because what is an object? It's a combination of data with behavior.
  111. and besides, look at this method! It's a method that

    just calls another method by smooshing together its arguments. Keyboard and integer arrays have made this obsolete.
  112. Let's not let that object stay and hide, it deserves

    a day in the sun, and Enigma doesn't need that extra implementation.
  113. test that it translates based on its key. which in

    the real one is a little mess of wires between the right and left sides of the rotor
  114. and use a simpli fi ed key rather than the

    whole enigma set because this is enough to have a good test. Don't over complicate it, it's only going one step.
  115. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... .....E 6 runs, 11 assertions, 0 failures, 1 errors, 0 skips > and we expected that, this is predetermined after all... and we have the wrong number of arguments to `.new`
  116. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ...... 6 runs, 11 assertions, 0 failures, 0 errors, 0 skips > hoo-oo! emerald green
  117. But Enigma is still using the old way, let's use

    the new rotor class instead. ⭐ Well the good news is the rotor _arrays_ are already arguments
  118. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... .EE.E. 6 runs, 11 assertions, 0 failures, 3 errors, 0 skips > errors errors errors
  119. instead of Enigma sending a message to itself, we have

    collaborators. Small Simple Objects Sending Messages, Enigma sends the message to each rotor in turn.
  120. 0 5 4 8 each message sent to a rotor

    is ⭐ one ⭐ two ⭐ three
  121. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ...... 6 runs, 11 assertions, 0 failures, 0 errors, 0 skips > y'just love to see it
  122. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts Rotor class This commit extracts rotor class
  123. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts Rotor class The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does
  124. Terminal.app Extracts Rotor class The things that don't align to

    Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does Orchestrates and conducts the communication between these different pieces so they can stay separate from each other. # Please enter the commit message for your changes. Lines starting Orchestrates and conducts the communication between these di ff erent pieces so they can stay separate from each other.
  125. Terminal.app # Please enter the commit message for your changes.

    Lines starting Extracts Rotor class The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does Orchestrates and conducts the communication between these different pieces so they can stay separate from each other. A rotor doesn't have to know what comes before or after it, and Enigma doesn't know how the work gets done. That's Dependency Inversion at work. A rotor doesn't have to know what comes before or after it, and Enigma doesn't know how the work gets done. That's Dependency Inversion at work.
  126. test that it encyphers a phrase correctly, no longer single

    character strings. ....to the command line!
  127. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... E...... 7 runs, 12 assertions, 0 failures, 1 errors, 0 skips > sounds about right but... lets get rid of that red.
  128. it already does one character, call up our friend `.map`,

    do that for all the characters and that should work, right?
  129. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ....... 7 runs, 12 assertions, 0 failures, 0 errors, 0 skips > the tests agree!
  130. We're still missing some key functionality, right? As it is,

    even with a phrase.. it's just a substitution cypher. Can't have that.
  131. thest no repeats in consecutive cypers. if we cypher "A",

    then cypher "A" again, it should not be the same result twice in a row.
  132. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ..FF..... 9 runs, 14 assertions, 2 failures, 0 errors, 0 skips > 2 failures
  133. If Enigma is our coordinator, rotor position doesn't seem to

    fi t there... ⭐ how about the rotors themselves?
  134. we want to know that the rotor can step one

    position, but also that it's not going to fall o ff the end of the key.
  135. and here we advance advance advance. we should prefer our

    tests be straightforward. Coming along and reading this test later when we've forgotten what we wrote shouldn't take a lot of energy. minitest, you have anything to say?
  136. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... .FF...FF... 11 runs, 20 assertions, 4 failures, 0 errors, 0 skips > gross
  137. Position is data internal to the rotor, no accessor methods

    to be modi fi ed directly from outside, not even any public api revealing there is an instance variable
  138. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... .E....FF... 11 runs, 20 assertions, 2 failures, 1 errors, 0 skips > now position is part of how we calculate what index to return ⭐ and it passes the fi rst test
  139. this is neat. ruby has a method that moves the

    fi rst index in an array to the back, with an argument for how many times to rotate. also notice, does anybody else get to see this method? nope. private. ⭐ 🌈 encapsulation🌈
  140. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ......FF... 11 runs, 20 assertions, 2 failures, 0 errors, 0 skips > rotor is good, enigma will have to wait another moment.
  141. Let's give it a default value, that way we don't

    have to update every `Rotor.new` in the codebase
  142. and after a full rotation, it needs to let the

    next rotor in line tick over.
  143. By not specifying a method tied to HOW & WHEN,

    we leave fl exibility for future rotors to decide di ff erently, and to do it without changing a line of code outside the rotor.
  144. because by the end of the war, there were rotors

    with two notches to tick over, or some not after a full rotation.
  145. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ........FF... 13 runs, 22 assertions, 2 failures, 0 errors, 0 skips > the rotor tests pass, and we have what we need to make the enigma tests function so back we go
  146. ...like St Andrews we are on the GREEN! (golf reference,

    I apologize) ⭐ (resetting) 🙏 let's refactor.
  147. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ............. 13 runs, 22 assertions, 0 failures, 0 errors, 0 skips > ...like St Andrews we are on the GREEN! (golf reference, I apologize) ⭐ (resetting) 🙏 let's refactor.
  148. future coders will know these are not meant for re-use,

    and aren't tested in isolation, these messages are internal memo only.
  149. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ............. 13 runs, 22 assertions, 0 failures, 0 errors, 0 skips > how'd we hold up? ⭐ Ver! di! gris! oh Verdigris? that's the green patina on copper..like the statue of liberty. this is getting away from me.
  150. 👆 did it work? 👉 /commit!/ (if they're into it:

    hold hand to ear, "i can't hear you"... this is fun, y'all got to try this sometime)
  151. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior this commit implements rotor stepping behavior
  152. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior With new behavior, Enigma is no longer a weak substitution cypher With new behavior, Enigma is no longer a weak substitution cypher
  153. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior With new behavior, Enigma is no longer a weak substitution cypher We safeguarded the rotor's internal data, only allowing it to change via a method without exposing how the behavior is accomplished. We safeguarded the rotor's internal data, only allowing it to change via a method without exposing how the behavior is accomplished.
  154. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior With new behavior, Enigma is no longer a weak substitution cypher By encapsulating this information, we're also protecting Rotor's collaborators from the responsibility of knowing this is what Rotors do. We safeguarded the rotor's internal data, only allowing it to change via a method without exposing how the behavior is accomplished. By encapsulating this information, we're also protecting Rotor's collaborators from the responsibility of knowing this is what Rotors do.
  155. When I think about the Enigma machine, it's made up

    of three di ff erent high-level parts working together. The Keyboard, The Lampboard, and the encyphering mechanism.
  156. The core is the rotors, but there's more to it.

    There's the mechanism that advances the rotors, the re fl ector, and the Spindle that the rotors sit on. We need a new small simple object to send messages to.
  157. Instead of passing rotors to Enigma, we'll pass rotors into

    the spindle and the spindle to Enigma.
  158. this test causes the fi rst rotor to complete a

    full turn, and we're asserting the second rotor got the signal
  159. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ...EE.......... 15 runs, 24 assertions, 0 failures, 2 errors, 0 skips > yeah that was never gonna work
  160. Navy Enigmas used four rotors at a time, Army and

    Air Force used 3, if its not hardcoded ours will have the same fl exibility.
  161. We don't know how many rotors, so we'll iterate with

    my favorite ennumerable method, reduce. Have you been introduced? to reduce?
  162. Its the same game in `advance_rotor`, except that... except and

    if the step_signal is true, the rotor advances and sends its step_signal down the line.
  163. also please don't use a ternary here unless you are

    also running out of room on your slides.
  164. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ............. 14 runs, 24 assertions, 0 failures, 0 errors, 0 skips > we are so green we get mistaken for the incredible hulk
  165. We are abstracting so well, we're abstracting away what class

    that is. No depending on any class whatsoever
  166. if someone wants to use this class, they don't even

    have to use a Spindle, the modules are loosely coupled and whole new functionality doesn't NEED to change code in this fi le!
  167. We know less now than we ever will... but because

    of OO design, it doesn't even matter. Just.. pass in a di ff erent transformer. Want to use elliptic curve cryptography? go right ahead. Want to use MD5? 1993 called and they want their algorithm back but you can! I'm excited! are you excited? [[ front row's excited! ]]
  168. Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb

    # Running... ............. 14 runs, 24 assertions, 0 failures, 0 errors, 0 skips > green green green.. green like, i dunno all the little dots in the terminal
  169. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility This commit abstracts encyphering away from Enigma's responsibility.
  170. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Enigma is Open for Extension and Closed for Modi fi cation, enabling painless re-use in ways we don't have to try and predict.
  171. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... Lead by OO Design principles we built a replica Enigma that is easy and fun to work with.
  172. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like using tech and ideas that stand on the shoulders of giants like
  173. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing Alan Turing
  174. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing, John von Neumann John von Neumann
  175. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing, John von Neumann, Grace Hopper Grace Hopper
  176. Terminal.app # Please enter the commit message for your changes.

    Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing, John von Neumann, Grace Hopper and Yukihiro Matsumoto. and Yukihiro Matsumoto ⭐ what a ride!
  177. S ingl e Re s ponsi b i l i

    ty Single Responsibility: Objects and methods that strive for a cohesive uni fi ed purpose.
  178. S ingl e Re s ponsi b i l i

    ty A bstr acti o n Abstraction: Relocating implementation, replacing with a simpler-to-reason-about representation
  179. S ingl e Re s ponsi b i l i

    ty A bstr acti o n E ncap sula t ion Encapsulation: An object should respond, react and update on its own terms.
  180. S ingl e Re s ponsi b i l i

    ty A bstr acti o n E ncap sula t ion D epen denc y Inve r s i o n Dependency Inversion: Higher level objects operate without being involved in the speci fi cs of those they send messages to.
  181. S ingl e Re s ponsi b i l i

    ty A bstr acti o n E ncap sula t ion O pen/ Clos e d D epen denc y Inve r s i o n Open for extension and closed for modi fi cation...because we don't even need to!
  182. S ingl e Re s ponsi b i l i

    ty A bstr acti o n E ncap sula t ion O pen/ Clos e d D epen denc y Inve r s i o n all in service of
  183. S m a l l S i m p l

    e O b j e c t s S e n d i n M e s s a g e s small simple objects sending messages
  184. C hang e is hard. B ut i t do

    e sn't h a v e t but it doesn't have to be
  185. R e ad i ng t h e R uby

    ¡ o n R a il s d ocu ment a t i o n H . . .b u t l i k e f or f u n s i es F o un d w h e r eve r yo u g e t y ou r p odc asts , b u t h ey t r y O verc a s t - > c o de im a g e s m ade w i t h c o m e s a y h i a t t h e t h o u g h t b o t b o o t h If you want to chat about more features to implement with Enigma, we didn't even get to the re fl ector or the plugboard, or a lampboard that returns html instead of a string, or a keyboard that's an api endpoint, or maybe you too have feelings about how Turing was murdered by his own government? or want to chat about Bletchley Park.. or like.. Object Orientation.. I'm going to be hanging around the thoughtbot booth a lot tomorrow, come say hi.