In 1987 plaatste Chris Cole een bericht op de sci.crypt Usenet-groep:
Toen ik aan Caltech studeerde, liet professor Feynman me drie geheime berichten zien waarmee een collega-wetenschapper in Los Alamos hem had uitgedaagd, en die hij niet had kunnen kraken. Ik slaagde er zelf ook niet in om ze te kraken, en dus plaats ik ze nu online zodat iedereen op het Internet ook eens kan proberen.
De volgende dag had Jack Morrison van het Jet Propulsion Laboratory (NASA) het eerste van de drie berichten al ontcijferd. Het bleek een eenvoudig transpositiecijfer te zijn dat een passage in het Middel-Engels uit The Canterbury Tales verbergt.
Over heel de wereld bogen fanaten van geheime codes zich over de twee andere berichten — die de Feynman Ciphers gedoopt werden — maar gedurende 75 jaar wist niemand ze te ontcijferen. Tot David Vierra op 27 mei 2023 in een blogpost liet weten dat hij de code gekraakt had. De cijfertekst van Feynman Cipher #2
XUKEXWSLZJUAXUNKIGWFSOZRAWURORKXAOSLHROB XBTKCMUWDVPTFBLMKEFVWMUXTVTWUIDDJVZKBRMC WOIWYDXMLUFPVSHAGSVWUFWORCWUIDUJCMVTTBEI TUNOJUZAORXLORSVRZSVVFSQXOCMUWPYTRLGBMCY POJCLRIYTVFCCMUWUFPOXCNMCIWMSKPXEDQIYKLK MXFPBMCMVRCJUMVRKWURKPSEEIWZVXULEIOETOOF WKBIUXPXUGOWLFPWUSCH
bleek een passage te zijn uit het gedicht Terence, This is Stupid Stuff (1896) van A.E. Houseman. De klare tekst leest als
Why, if 'tis dancing you would be,
There is brisker pipes than poetry.
Say, for what were hop-yards meant,
Or why was Burton built on Trent?
Oh many a peer of England brews
Livelier liquor than the Muse,
And malt does more than Milton can
To justify God's ways to man.
Ale, man, ale's the stuff to drink
For fellows whom it hurts to think
Om het bericht te coderen wordt gebruikgemaakt van twee substitutiecijfers met deze twee sleutels:
klare tekst: ABCDEFGHIJKLMNOPQRSTUVWXYZ sleutel #1: MANYREQUSTHVBCIDFOLWGZXPKJ sleutel #2: JHAZTENYXMLOCUFBQVKPSGWRDI
De sleutel van een substitutiecijfer bestaat uit een permutatie van de letters van het alfabet: alle letters van het alfabet komen dus één keer in de sleutel voor, maar in een willekeurige volgorde. Om een klare tekst te versleutelen met een substitutiecijfer wordt de $$i$$-de letter in het alfabet gecodeerd als de $$i$$-de letter in de sleutel. Bij sleutel #1 wordt de letter A bijvoorbeeld gecodeerd als de letter M, de letter B als de letter A, de letter C als de letter N, enzoverder. Om de cijfertekst te ontsleutelen worden de letters in de omgekeerde richting vervangen.
Bij Feynman Cipher #2 werden de woorden van het gedicht versleuteld met een substitutiecijfer dat alterneert tussen sleutel #1 en sleutel #2. Het eerst woord van elke regel wordt versleuteld met sleutel #1, het tweede woord met sleutel #2, het derde woord met sleutel #1, het vierde woord met sleutel #2, enzoverder. Omdat we bij elke regel voor het eerste woord altijd beginnen met sleutel #1, komt het dus voor dat twee opeenvolgende woorden sleutel #1 gebruiken (het laatste woord op een regel en het eerste woord op de volgende regel). Daarbij worden de woorden op de regel bepaald als de langst mogelijke reeksen van opeenvolgende letters (hoofdletters en kleine letters). Bovendien wordt de versleuteling van woorden met een even aantal letters omgekeerd geschreven. Dit is hoe de woorden op de eerste versregel worden versleuteld:
klare tekst: why if tis dancing you would be sleutel #1: XUK WSL KIG AR sleutel #2: XE ZJUAXUN WFSOZ omkeringen: EX RA cijfertekst: XUK EX WSL ZJUAXUN KIG WFSOZ RA
Dit is hoe de woorden op de tweede versregel worden versleuteld:
klare tekst: there is brisker pipes than poetry sleutel #1: WUROR AOSLHRO WUMC sleutel #2: XK BXBTK BFTPVD omkeringen: KX CMUW DVPTFB cijfertekst: WUROR KX AOSLHRO BXBTK CMUW DVPTFB
Feynman Cipher #3 werd op exact dezelfde manier versleuteld.
Voor deze opgave moet je twee klassen definiëren: Substitutie en Olum.
Definieer een klasse Substitutie waarmee substitutiecijfers kunnen voorgesteld worden. Bij het aanmaken van een nieuw substitutiecijfer $$\mathcal{S}$$ (Substitutie) moet de sleutel (str) voor de substitutie doorgegeven worden. Als die sleutel geen permutatie is van de letters van het alfabet (waarbij we geen onderscheid maken tussen hoofdletters en kleine letters), dan moet een AssertionError opgeworpen worden met de boodschap ongeldige sleutel. Om berichten te kunnen versleutelen en ontsleutelen moet je op een substitutiecijfer $$\mathcal{S}$$ (Substitutie) minstens deze twee methoden kunnen aanroepen:
Een methode codeer waaraan een klare tekst (str) moet doorgegeven worden. De methode moet de corresponderende cijfertekst (str) teruggeven volgens substitutiecijfer $$\mathcal{S}$$. Daarbij worden kleine letters gecodeerd als kleine letters, en hoofdletters als hoofdletters. Alle karakters van de klare tekst die geen letter zijn, blijven gewoon op hun plaats staan in de cijfertekst.
Een methode decodeer waaraan een cijfertekst (str) moet doorgegeven worden. De methode moet de corresponderende klare tekst (str) teruggeven volgens substitutiecijfer $$\mathcal{S}$$. Daarbij worden kleine letters gedecodeerd als kleine letters, en hoofdletters als hoofdletters. Alle karakters van de cijfertekst die geen letter zijn, blijven gewoon op hun plaats staan in de klare tekst.
Definieer een klasse Olum waarmee tekstbestanden die bestaan uit meerdere regels klare tekst kunnen versleuteld worden volgens het cijfer waarmee de Feynman Ciphers #2 en #3 versleuteld werden. Bij het aanmaken van een nieuw cijfer $$\mathcal{O}$$ (Olum) moeten sleutel #1 (str) en sleutel #2 (str) voor de twee onderliggende substitutiecijfers doorgegeven worden. Als minstens één van die sleutels geen permutatie is van de letters van het alfabet (waarbij we geen onderscheid maken tussen hoofdletters en kleine letters), dan moet een AssertionError opgeworpen worden met de boodschap ongeldige sleutel. Om tekstbestanden die bestaan uit meerdere regels te kunnen versleutelen, moet je op een cijfer $$\mathcal{O}$$ (Olum) minstens deze twee methoden kunnen aanroepen:
Een methode codeer_regel waaraan een regel klare tekst (str) moet doorgegeven worden. De methode moet de corresponderende cijfertekst (str) teruggeven volgens cijfer $$\mathcal{O}$$. We herhalen nog eens dat de woorden op de regel bepaald worden als de langst mogelijke reeksen van opeenvolgende letters (hoofdletters en kleine letters), en dat de versleuteling van woorden met een even aantal letters omgekeerd geschreven wordt. De cijfertekst wordt dan bekomen door de versleutelingen van alle individuele woorden op de regel samen te voegen zonder scheidingsteken, en om te zetten naar hoofdletters. Karakters op de regel die geen deel uitmaken van woorden, worden dus niet opgenomen in de cijfertekst.
Een methode codeer waaraan de locatie (str) moet doorgegeven worden van een tekstbestand dat uit meerdere regels klare tekst bestaat. De methode heeft een tweede optionele parameter waaraan een tweede bestandslocatie (str) kan doorgegeven worden. De methode heeft een derde optionele parameter breedte waaraan een natuurlijk getal w (int; $$w > 0$$; standaardwaarde: 40) kan doorgegeven worden. De methode moet de cijfertekst die correspondeert met de inhoud van het eerste tekstbestand (eerste argument) wegschrijven naar het tweede tekstbestand (tweede argument). Die cijfertekst wordt bekomen door de inviduele regels in het eerste tekstbestand te versleutelen volgens cijfer $$\mathcal{O}$$ (cfr. methode codeer_regel), die cijferteksten samen te voegen zonder scheidingstekens, en het resultaat uit te schrijven in regels van lengte $$w$$ (enkel de laatste regel mag minder letters bevatten). Als er niet expliciet een bestandslocatie wordt doorgegeven aan de tweede parameter, dan moet de methode de cijfertekst uitschrijven (print).
In deze interactieve sessie gaan we ervan uit dat de tekstbestanden houseman1896.txt en feynman1953.txt zich in de huidige directory bevinden.
>>> substitutie1 = Substitutie('MANYREQUSTHVBCIDFOLWGZXPKJ')
>>> substitutie1.codeer("Why, if 'tis dancing you would be,")
"Xuk, se 'wsl ymcnscq kig xigvy ar,"
>>> substitutie1.decodeer("Xuk, se 'wsl ymcnscq kig xigvy ar,")
"Why, if 'tis dancing you would be,"
>>> substitutie2 = Substitutie('JHAZTENYXMLOCUFBQVKPSGWRDI')
>>> substitutie2.codeer("Why, if 'tis dancing you would be,")
"Wyd, xe 'pxk zjuaxun dfs wfsoz ht,"
>>> substitutie2.decodeer("Wyd, xe 'pxk zjuaxun dfs wfsoz ht,")
"Why, if 'tis dancing you would be,"
>>> Substitutie('abcdefghijklmnopqrstuvwyz') # letter x ontbreekt
Traceback (most recent call last):
AssertionError: ongeldige sleutel
>>> Substitutie('abcdefghijklmnopqrstuvwxyza') # letter a komt twee keer voor
Traceback (most recent call last):
AssertionError: ongeldige sleutel
>>> cijfer = Olum('MANYREQUSTHVBCIDFOLWGZXPKJ', 'JHAZTENYXMLOCUFBQVKPSGWRDI')
>>> cijfer.codeer_regel("Why, if 'tis dancing you would be,")
'XUKEXWSLZJUAXUNKIGWFSOZRA'
>>> cijfer.codeer_regel('There is brisker pipes than poetry.')
'WURORKXAOSLHROBXBTKCMUWDVPTFB'
>>> cijfer.codeer('houseman1896.txt')
XUKEXWSLZJUAXUNKIGWFSOZRAWURORKXAOSLHROB
XBTKCMUWDVPTFBLMKEFVWMUXTVTWUIDDJVZKBRMC
WOIWYDXMLUFPVSHAGSVWUFWORCWUIDUJCMVTTBEI
TUNOJUZAORXLORSVRZSVVFSQXOCMUWPYTRLGBMCY
POJCLRIYTVFCCMUWUFPOXCNMCIWMSKPXEDQIYKLK
MXFPBMCMVRCJUMVRKWURKPSEEIWZVXULEIOETOOF
WKBIUXPXUGOWLFPWUSCH
>>> cijfer.codeer('houseman1896.txt', 'feynman_cipher_#2.txt')
>>> cijfer.codeer('feynman1953.txt', breedte=33)
WURVFXGJYTHEIZXSQXOBGSVRUDOOJXATB
KTARVIXPYTMYABMVUFXPXKUJVPLSDVTGN
GOSIGLWURPKFCVGELLRNNGLPYTFVTPXAJ
OSCWRODORWMWSICLFKEMOTGJYCRRAOJVN
TODVMNSQIVICRBICRUDCSKXYPDMDROJUZ
ICRVFWXIFPXIVVIEPYTDOIAVRBOOXWRAK
PSZXTZKVROSWCRCFVEESOLWKTOBXAUXVB
>>> cijfer.codeer('feynman1953.txt', 'feynman_cipher_#3.txt', breedte=33)
>>> Olum('abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwyz') # letter x ontbreekt in tweede sleutel
Traceback (most recent call last):
AssertionError: ongeldige sleutel
>>> Olum('abcdefghijklmnopqrstuvwxyza', 'abcdefghijklmnopqrstuvwxyz') # letter a komt 2× voor in eerste sleutel
Traceback (most recent call last):
AssertionError: ongeldige sleutel
David Vierra ontdekte ook dat de cijfertekst van Feynman Cipher #3
WURVFXGJYTHEIZXSQXOBGSVRUDOOJXATBKTARVIX PYTMYABMVUFXPXKUJVPLSDVTGNGOSIGLWURPKFCV GELLRNNGLPYTFVTPXAJOSCWRODORWMWSICLFKEMO TGJYCRRAOJVNTODVMNSQIVICRBICRUDCSKXYPDMD ROJUZICRVFWXIFPXIVVIEPYTDOIAVRBOOXWRAKPS ZXTZKVROSWCRCFVEESOLWKTOBXAUXVB
versleuteld werd met exact hetzelfde cijfer en exact dezelfde sleutels als Feynman Cipher #2. De klare tekst bestaat uit de eerste drie zinnen in de inleiding van Richard Feynman's artikel Atomic Theory of the λ Transition in Helium (1953):
The behavior of liquid helium, especially below the lambda transition, is very curious.
The most successful theoretical interpretations so far, have been largely phenomenological.
In this paper and one or two to follow, the problem will be studied entirely from first principles.
Wie stelde de Feynman Ciphers op? In 2021 suggereerde Nick Pelling dat het wel eens om professor Paul Olum zou kunnen gaan. Feynman's beschrijving van Olum's humor in zijn biografie lijkt zeker overeen te komen met iemand die een bericht in het Midden-Engels zou kiezen. Na het decoderen van de laatste twee Feynman Ciphers bleef Nick Pelling nog steeds overtuigd dat hij de auteur was. Maar zelfs Olum's zoon kon geen definitief uitsluitsel geven.
Feynman R (1953). Atomic Theory of the λ Transition in Helium. The Physical Review 91(6), 1291–1301.
Relkin PW (2022). Solving the Olum 1 cipher. Cryptologia 46(4), 291–301.
Relkin PW (2023). Solving the Olum 2 cipher: a new approach to cryptanalysis of transposition ciphers. Cryptologia 47(1), 38–47.