Digrafid is een versleutelingsmethode die gebruikmaakt van twee $$3 \times 9$$ roosters. Elk rooster bevat een permutatie van de 26 letters van het alfabet plus de spatie. Elke letter van het alfabet komt dus juist één keer in een rooster voor en er is ook één cel die een spatie bevat. Bij het werken met roosters wordt geen onderscheid gemaakt tussen hoofdletters en kleine letters.

Een rooster wordt gevuld aan de hand van een sleutel die enkel uit letters en spaties bestaat. Eerst worden de cellen van links naar rechts en van boven naar onder gevuld met de opeenvolgende karakters van de sleutel. Hierbij wordt elk karakter slechts één keer gebruikt: herhalingen van hetzelfde karakter worden genegeerd. Daarna worden de overige cellen gevuld met de resterende karakters: een spatie en de opeenvolgende letters van het alfabet voor zover die nog niet in het rooster voorkwamen. De twee roosters hieronder werden respectievelijk gevuld met sleutels Anakin Skywalker (links) en Padme Amidala (rechts).

rooster:Anakin Skywalker
Rooster dat gevuld werd aan de hand van sleutel Anakin Skywalker.
rooster:Padme Amidala
Rooster dat gevuld werd aan de hand van sleutel Padme Amidala.

De rijen van een rooster worden van boven naar onder genummerd vanaf nul. Analoog worden de kolommen van links naar rechts genummerd vanaf nul. Daardoor kunnen we de positie van een cel in het rooster voorstellen als $$(r, k)$$, met $$r$$ het rijnummer en $$k$$ het kolomnummer.

Stel nu dat we het bericht

Someday▪I▪will▪be▪the▪most▪powerful▪Jedi▪ever

willen coderen. Voor de duidelijkheid hebben we de spaties in deze plaintext (het bericht dat moet gecodeerd worden) voorgesteld door zwarte vierkanten (▪). De plaintext wordt opgedeeld in niet-overlappende digrafen (twee opeenvolgende letters) en opeenvolgende digrafen worden per drie gegroepeerd. Als de lengte van de plaintext geen zesvoud is dan worden de digrafen in de onvolledige laatste groep aangevuld met letters X.

So me da — y▪ I▪ wi — ll ▪b e▪ — th e▪ mo — st ▪p ow — er fu l▪ — Je di ▪e — ve rX XX

Elke digraaf $$\alpha\beta$$ correspondeert één-op-één met een triplet $$(k_{\alpha}, r_{\alpha\beta}, k_{\beta})$$ dat gevormd wordt op basis van de positie $$(r_{\alpha}, k_{\alpha})$$ van het karakter $$\alpha$$ in het eerste rooster en de positie $$(r_{\beta}, k_{\beta})$$ van het karakter $$\beta$$ in het tweede rooster, waarbij $$r_{\alpha\beta} = 3 \times r_{\alpha} + r_{\beta}$$.

Het verband tussen digraaf $$\alpha\beta$$ en triplet $$(k_{\alpha}, r_{\alpha\beta}, k_{\beta})$$ wordt weergegeven in onderstaande figuur. Daarbij wordt het eerste rooster horizontaal weergegeven en het tweede rooster verticaal. Daartussen staat een $$3 \times 3$$ rooster (donkergrijze achtergrond) waarin de getallen 0 tot en met 8 ingevuld worden. Het middelste getal $$r_{\alpha\beta}$$ van het triplet staat in het $$3 \times 3$$ rooster op het snijpunt van de rij $$r_{\alpha}$$ waarop $$\alpha$$ staat in het eerste rooster en de (verticale) rij $$r_{\beta}$$ waarop $$\beta$$ staat in het tweede rooster. Zo correspondeert digraaf SO bijvoorbeeld met het triplet $$(5, 1, 7)$$.

digrafid
Digrafid versleuteling die gebruikmaakt van twee roosters die gevuld werden met sleutelwoorden Anakin Skywalker en Padma Amidala.

Analoog corresponderen de volgende twee digrafen ME en DA van de eerste groep respectievelijk met de tripletten $$(0, 6, 4)$$ en $$(4, 3, 1)$$. Deze tripletten worden verticaal onder de corresponderende digrafen van de eerste groep geschreven (aangegeven met blauwe pijlen).

coderen/decoderen
Coderen en decoderen van het bericht Someday I will be the most powerful Jedi ever met een digrafid-versleuteling met twee roosters die gevuld werden met sleutelwoorden Anakin Skywalker en Padma Amidala.

Tenslotte worden voor elke groep horizontaal en van boven naar onder drie nieuwe tripletten uitgelezen (aangegeven met groene pijlen), die op hun beurt omgezet worden naar hun corresponderende digraaf. Voor de eerste groep uit bovenstaand voorbeeld correspondeert het bovenste triplet $$(5, 0, 4)$$ met digraaf SE, het middelste triplet $$(1, 6, 3)$$ met digraaf OM en het onderste triplet $$(7, 4, 1)$$ met digraaf HF. Dit zijn meteen de eerste drie digrafen van de ciphertext (het gecodeerde bericht). De overige groepen van drie digrafen worden op analoge manier gecodeerd.

Digrafid is een symmetrische versleutelingsmethode: de ciphertext coderen levert terug de plaintext op. Dezelfde procedure kan dus zowel gebruikt worden om berichten te coderen als om berichten te decoderen.

Opgave

Definieer een klasse Rooster waarmee roosters kunnen voorgesteld worden die gebruikt worden door digrafid-versleutelingen. Bij het aanmaken van een nieuw rooster (Rooster) moet de sleutel $$s$$ (str) doorgegeven worden waarmee het rooster gevuld wordt.

Als er een rooster (Rooster) wordt doorgegeven aan de ingebouwde functie str, dan moet een stringvoorstelling (str) van het rooster teruggegeven worden. Daarin vormt elke rij (van boven naar onder) een afzonderlijke regel met een oplijsting (van links naar rechts) van de karakters in de opeenvolgende van cellen op die rij. Daarbij worden alle letters voorgesteld in hoofdletters.

Voorts moet de klasse Rooster minstens de volgende methoden ondersteunen:

Definieer ook nog een klasse Digrafid waarmee digrafid-versleutelingen kunnen voorgesteld worden. Bij het aanmaken van een nieuwe versleuteling (Digrafid) moeten de twee sleutels $$s_1$$ (str) en $$s_2$$ (str) doorgegeven worden waarmee de roosters van de versleuteling gevuld worden. De klasse Digrafid moet minstens de volgende methoden ondersteunen:

Je mag ervan uitgaan dat er enkel geldige argumenten aan de methoden doorgegeven worden, zonder dat dit expliciet moet gecontroleerd worden.

Voorbeeld

>>> rooster = Rooster('Anakin Skywalker')
>>> print(rooster)
ANKI SYWL
ERBCDFGHJ
MOPQTUVXZ
>>> rooster.positie('A')
(0, 0)
>>> rooster.positie('H')
(1, 7)
>>> rooster.positie('z')
(2, 8)
>>> rooster.karakter(0, 0)
'A'
>>> rooster.karakter(1, 7)
'H'
>>> rooster.karakter(2, 8)
'Z'

>>> rooster = Rooster('Padme Amidala')
>>> print(rooster)
PADME ILB
CFGHJKNOQ
RSTUVWXYZ
>>> rooster.positie('P')
(0, 0)
>>> rooster.positie('H')
(1, 3)
>>> rooster.positie('z')
(2, 8)
>>> rooster.karakter(0, 0)
'P'
>>> rooster.karakter(1, 3)
'H'
>>> rooster.karakter(2, 8)
'Z'

>>> digrafid = Digrafid('Anakin Skywalker', 'Padme Amidala')
>>> digrafid.triplet('So')
(5, 1, 7)
>>> digrafid.triplet('me')
(0, 6, 4)
>>> digrafid.triplet('da')
(4, 3, 1)
>>> digrafid.digraaf(5, 1, 7)
'SO'
>>> digrafid.digraaf(0, 6, 4)
'ME'
>>> digrafid.digraaf(4, 3, 1)
'DA'
>>> digrafid.digraaf(5, 0, 4)
'SE'
>>> digrafid.digraaf(1, 6, 3)
'OM'
>>> digrafid.digraaf(7, 4, 1)
'HF'
>>> digrafid.codeer('Someday I will be the most powerful Jedi ever')
'SEOMHFGLAPFXJCAMXW PHLCYFFKBK EZFRE JJCPTEYOGZTI'
>>> digrafid.decodeer('SEOMHFGLAPFXJCAMXW PHLCYFFKBK EZFRE JJCPTEYOGZTI')
'SOMEDAY I WILL BE THE MOST POWERFUL JEDI EVERXXX'

>>> digrafid = Digrafid('Darth Vader', 'Admiral Motti')
>>> digrafid.codeer('I find your lack of faith disturbing')
'TNIILD MQPM VLIBOKAFIIVTHID LTUZVRJR'
>>> digrafid.decodeer('TNIILD MQPM VLIBOKAFIIVTHID LTUZVRJR')
'I FIND YOUR LACK OF FAITH DISTURBING'