Salausmenetelmät Veikko Keränen, Jouko Teeriaho (RAMK, 2006) LUKUTEORIAA JA ALGORITMEJA 2. Eukleideen algoritmi à 2.1 Suurimman yhteisen tekijän tehokas laskutapa Tässä luvussa tarkastelemme annettujen lukujen suurimman yhteisen tekijän etsimistä tehokkaalla tavalla. Erinomaisen käyttökelpoinen menetelmä on Eukleideen algoritmi, joka on ikivanha, mutta ei vähääkään vanhanaikainen laskutapa. Nykyisen tietotekniikan aikakautena sen merkitys sovelluksissa on vain entisestään kasvanut. Olkoot a ja b positiivisia kokonaislukuja ja a b. Kirjoitetaan luku a jakoalgoritmin mukaiseen muotoon a = qb+ r, 0 r < b, (ks. Lause 1.1). Jokainen lukujen a ja b yhteinen tekijä, sanokaamme t, on selvästi luvun b ja jakojäännöksen r = a - qb yhteinen tekijä ja myös päinvastoin. Todellakin, jos a = t a' ja b = t b', missä t, a', b' œ +, niin (2.1) r = a - qb = (t a') q (t b') = t (a' q b'), ts. t on luvun r tekijä ja oletuksen mukaan myös luvun b tekijä. Toisaalta, jos b = t b' ja r = t r', missä t, b', r' œ +, niin (2.2) a = q b + r = q (t b') + (t r') = t (q b' + r'), ts. t on luvun a tekijä ja oletuksen mukaan myös luvun b tekijä. Merkitään d = sytha, bl. Edellä nähdyn nojalla d b ja d r, joten d sythb, rl. Vastaavasti, kuten kohdassa (2.2) nähtiin, sythb, rl sytha, bl, joten d = sytha, bl = sythb, rl, kun a = qb+ r, 0 r < b. Jos r = 0 (ja siis a = qb), saadaan tulos sytha, bl = b. Olkoon r 0. Jatketaan nyt samalla tavalla lukujen b ja r kanssa. Niinpä kirjoitamme a = q 1 b + r 1, b = q 2 r 1 + r 2, missä 0 r 2 < r 1. Kuten edellä näimme sytha, bl = sythb, r 1 L = sythr 1, r 2 L. Jatketaan menettelyä kunnes toinen argumentti r n-1 on ensimmäisen argumentin r n-2 tekijä (näin käy lopulta, koska r 1 > r 2 > r 3 > > r n-2 > r n-1 > r n = 0). Luku r n-1 on täsmälleen etsitty lukujen a ja b suurin yhteinen tekijä, ts. r n-1 = syt(a, b). Tämä algoritmi on nimeltään Eukleideen algoritmi (Euclid's Algorithm) ja se on erittäin nopea tapa laskea syt(a, b). Huomattavaa on, että sytha, bl löytyy ilman
Salakirjoitus 2 lukujen a ja b tekijöihinjakoa (jota suurten lukujen kyseessä ollen voi käytännössä olla mahdotonta löytää, vrt. RSA-haasteluvut käytä netissä hakusana: The RSA Challenge Numbers). Algoritmi 2.1 Yksinkertainen Eukleideen algoritmi syöte a, b positiivisia kokonaislukuja, a b while b > 0 do begin tulosta a aseta r = jakojäännös, kun a on jaettu luvulla b (siis r saadaan jakoyhtälöstä a = qb+ r, 0 r < b) aseta a = b aseta b = r end Käyttämällä Mathematica-funktioita While, Floor ja Print, yllä esitetty algoritmi voidaan ohjelmoida seuraavasti. Viimeinen nollasta eroava jakojäännös on sama kuin Algoritmin 2.1 lopussa tulostama luku a, joka puolestaan on syötteenä annettujen lukujen suurin yhteinen tekijä: a = 2345; b = 987; While@b 0, r = a Floor@a ê bd b; 8a, b< = 8b, r<; Print@8a, b<dd 8987, 371< 8371, 245< 8245, 126< 8126, 119< 8119, 7< 87, 0< Tämä algoritmi voitaisiin implementoida myös näin: Clear@fD; f@8a_, b_<d := 8b, r = a Floor@a ê bd b<; NestWhileList@f, 82345, 987<, Last@#D 0&D 882345, 987<, 8987, 371<, 8371, 245<, 8245, 126<, 8126, 119<, 8119, 7<, 87, 0<<
Salakirjoitus 3 Tarkastellaan vielä kahta yksityiskohtaista esimerkkiä. Esimerkki 2.1 Laske lukujen 129 ja 15 suurin yhteinen tekijä. Ratkaisu. Käytetään jakoyhtälöä a = qb+ r, 0 r < b, toistuvasti. Lisäksi sytha, bl = sythb, rl = sythr, r'l =.... Siispä Eukleideen algoritmin toiminta näyttää seuraavalta: 129 = 8 * 15 + 9 syt H129, 15L = syt H15, 9L 15 = 1 * 9 + 6 syt H15, 9L = syt H9, 6L 9 = 1 * 6 + 3 syt H9, 6L = syt H6, 3L 6 = 2 * 3 + 0 syt H6, 3L = syt H3, 0L = 3 Viimeinen nollasta eroava jakojäännös = 3 = syt(129, 15). Esimerkki 2.2 Laske lukujen 2345 ja 123 suurin yhteinen tekijä. Ratkaisu. Tässä saadaan tulokseksi syt = 1. Tämä tulos löydetään Eukleideen algoritmilla seuraavasti: 2345 = 19 * 123 + 8 123 = 15 * 8 + 3 8 = 2 * 3 + 2 3 = 1 * 2 + 1 2 = 2 * 1 + 0 Viimeinen nollasta eroava jakojäännös = 1 = syt(2345, 123). Harjoituksia 11 (a) Määritä d = syt(1233, 63). Välivaiheet tulee merkitä selkeästi näkyviin Tätä harjoitusta jatketaan vielä seuraavassa kohdassa 2.2 (esitä d muodossa d = s 1233 + t 63, missä s, t œ ). 12 (a) Määritä syt(2333, 187). Tätä harjoitusta jatketaan vielä seuraavassa kohdassa 2.2 (esitä d muodossa d = s 2333 + t 187, missä s, t œ ).
Salakirjoitus 4 à 2.2 Lineaarikombinaatio sytha, bl = ua+ vb Salakirjoituksissa lasketaan usein hyvin suurten lukujen, sanokaamme a, jakojäännöksillä - modulo jokin luku b. Tällaisten suurten lukujen a käänteisluvuilla (modulo b) on ensiarvoisen keskeinen merkitys, kuten tullaan näkemään. Lauseen 1.4 mukaan on olemassa kertoimet u ja v œ joiden avulla syt(a, b) voidaan esittää muodossa sytha, bl = ua+ vb. Siinä tapauksessa, että syt(a, b) = 1, kuten oli edellä Esimerkissä 2.2, tälle lineaarikombinaatiolle pätee u a + v b = 1. Tällöin saadaan u a = ( v) b + 1, ts. u a ª 1 (modulo b) ja siis u = a -1 (modulo b). Näin ollen lineaarikombinaatiota 1 = sytha, bl = ua+ vb voidaan suoraan käyttää hyväksi käänteisalkioiden a -1 (modulo b) laskemisessa. Edellä esiintynyt merkintä x ª y Hmod ml tarkoittaa, että m jakaa kokonaislukujen x ja y erotuksen x - y, ts. x - y = q m, eräälle q œ. Tällöin sanotaan, että x ja y ovat keskenään kongruentteja modulo m. Kongruensseja käsitellään laajemmin Kappaleessa 3. Kun Lauseen 1.4 mukaiset kertoimet u ja v halutaan löytää, ts. esittää syt(a, b) muodossa sytha, bl = ua+ vb, voidaan Algoritmia 2.1 muuntaa alla esitetyllä tavalla. Huomaa, että jättämällä pois symboleja u i ja v i sisältävät rivit, tämä (laajennettu) algoritmi palautuu yksinkertaiseen Eukleideen algoritmiin, jossa sytha, bl = sythr -1, r 0 L = sythr 0, r 1 L = sythr 1, r 2 L = = sythr n-1, r n L = sythr n-1,0l = r n-1. Algoritmin 2.2 oikeellisuuden todistus löytyy Liitteestä 1, jossa esitetään yksityiskohtaiseisesti tähän suoraviivaiseen tapaan johtavat tarkastelut. Liitteessä 1 nähdään lisäksi, että jakoalgoritmin tuottama jakojäännös r i voidaan esittää jokaisella askeleella muodossa u i a + v i b. Viimeisen jakojäännöksen r n ollessa nolla, on viimeinen nollasta eroava jakojäännös r n-1 juuri etsitty lineaarikombinaatio d = sytha, bl = r n-1 = ua+ vb. Algoritmi todistetaan matemaattisella induktiolla ja siitä esitetään käsinlaskuesimerkkejä. Edelleen lukija löytää Liitteestä 1 perustelut matriisien kertolaskun käytölle lineaarikombinaation laskemisessa. Lopuksi Liitteestä 1 löytyy kaikki välivaiheet esittävä Mathematica-ohjelma, jota Mathematica-ympäristön käyttäjät voivat kokeilla. Tuon ohjelman voi myös muuntaa johonkin toiseen ohjelmointiympäristöön. Algoritmi 2.2 Laajennettu Eukleideen algoritmi syöte a b > 0 alkuarvot r -1 = a; r 0 = b; u -1 = 1; u 0 = 0; v -1 = 0; v 0 = 1; n = 0; while r n > 0 do begin aseta n = n + 1; tulosta r n-2 = q n r n-1 + r n, r n-1 > r n 0; aseta u n = u n-2 - q n u n-1 ; aseta v n = v n-2 - q n v n-1 ; end aseta u = u n-1 ; v = v n-1 ; (2.2) sytha, bl = r n-1 = ua+ vb Todistus: Katso Liite 1 (Laajennettu Eukleideen algoritmi suoraviivainen tapa). Ñ
Salakirjoitus 5 Vaikka kannustammekin lukijaa perehtymään Liitteeseen 1, emme vaadi tällä salakirjoitusten peruskurssilla siinä esitettyjä perusteluja hallittavaksi loppukokeessa. Esitämme nyt kuitenkin yhden esimerkin tuossa liitteessä kirjoitetun laajennettueukleides-ohjelman toiminnasta (vrt. Esimerkki 2.1 yllä): laajennettueukleides@129, 15D Laajennettu Eukleideen algoritmi toimii seuraavasti: a = 129, b = 15 r -1 =129=q 1 *r 0 +r 1 =8*15+9; r 1 =9=u 1 a +v 1 b = H1L*129 + H-8L*15 r 0 =15=q 2 *r 1 +r 2 =1*9+6; r 2 =6=u 2 a +v 2 b = H-1L*129 + H9L*15 r 1 =9=q 3 *r 2 +r 3 =1*6+3; r 3 =3=u 3 a +v 3 b = H2L*129 + H-17L*15 r 2 =6=q 4 *r 3 +r 4 =2*3+0; r 4 =0=u 4 a +v 4 b = H-5L*129 + H43L*15 Viimeinen nollasta eroava jakojäännös = 3 = syth129, 15L. Lineaarikombinaatio: 3 = u a + v b = H2L*129 + H-17L*15. Lasketaan tämä lineaarikombinaatio nyt käsin toisella, aluksi ehkä helpommalla, tavalla. Ainakin tämä alhaalta ylöspäin etenevä laskutapa tulee hallita. Siis jompikumpi tapa kuuluu kurssin keskeisiin vaatimuksiin. Tavan - suoraviivainen ylhäältä alas (yllä), tai alhaalta ylös (alla) - voi valita itse sen mukaan kumpi tuntuu luontevalta. Esimerkki 2.3 Laske lukujen 129 ja 15 suurin yhteinen tekijä ja esitä se muodossa u*129 + v*15. Esimerkissä 2.1 laskimme jo, että viimeinen nollasta eroava jakojäännös = 3 = syt(129, 15). Toistamme tässä vielä nämä laskut: Hrivi 1L 129 = 8 * 15 + 9 Hrivi 2L 15 = 1 * 9 + 6 Hrivi 3L 9 = 1 * 6 + 3 Hrivi 4L 6 = 2 * 3 + 0 Lähdemme nyt liikkeelle riviltä 3, jossa on viimeinen nollasta eroava jakojäännös (syt = 3). Saadaan: 3 = 9-1*6 (rivi 3) Nyt riviltä 2 saadaan ratkaistuksi edeltävä jakojäännös 6 = 15-1*9. Sijoittamalla tämä laskematon lauseke (15-1*9) luvun 6 paikalle yllä, saadaan: 3 = 9-1*6 (rivi 3)
Salakirjoitus 6 = 9-1*(15-1*9) (rivi 2) = -1*15 + 2*9 (sievennys) Riviltä 1 saadaan jakojäännös 9 = 129-8*15. Sijoittamalla lauseke (129-8*15) luvun 9 paikalle edellä saatuun viimeiseen muotoon, saadaan: 3 = 9-1*6 (rivi 3) = 9-1*(15-1*9) (rivi 2) = -1*15 + 2*9 (sievennys) = -1*15 + 2*(129-8*15) (rivi 1) = 2*129 + (-17)*15 (sievennys) Siis kysytty lineaarikombinaatio on 3 = syt(129, 15) = u a + v b = 2*129 + (-17)*15. Huomattakoon vielä, että yllä sievennys tarkoitti sitä, että kootaan yhteen (so. esitetään yhden kertoimen avulla) jatkossa ylemmiltä riveiltä löytyvät jakojäännökset (3, 6, 9) tai luvut b ja a (15, 129). Esitettyjä kertolaskuja ei tule laskea loppuun, koska silloin menetettäisiin lausekkeiden rakenne. Laskemisen kannalta näitä lukuja käsitellään siis symboleina tai merkkijonoina. Samaa ajattelutapaa kannattaa käytää myös, jos kirjoittaa tämän algoritmin ohjelman muotoon symbolisen laskennan ohjelmointiympäristössä. Esimerkki 2.4 Laske lukujen 2345 ja 123 suurin yhteinen tekijä ja esitä se muodossa u*2345 + v*123. Esimerkissä 2.2 laskimme jo, että viimeinen nollasta eroava jakojäännös = 1 = syt(2345, 123). Toistamme vielä nämä laskut: Hrivi 1L 2345 = 19 * 123 + 8 Hrivi 2L 123 = 15 * 8 + 3 Hrivi 3L 8 = 2 * 3 + 2 Hrivi 4L 3 = 1 * 2 + 1 Hrivi 5L 2 = 2 * 1 + 0 Laskemme nyt kysytyn lineaarikombinaation seuraavasti: 1 = 3-1*2 (rivi 4) = 3-1*(8-2*3) (rivi 3) = -1*8 + 3*3 (sievennys) = -1*8 + 3*(123-15*8) (rivi 2) = 3*123-46*8 (sievennys) = 3*123-46*(2345-19*123) (rivi 1) = -46*2345 + (3 + (-46)(-19))*123 (sievennys) = -46*2345 + 877*123 (sievennys) Siis kysytty lineaarikombinaatio on 1 = syt(2345, 123) = u a + v b = (-46)*2345 + 877*123. Mathematicassa tämä laajennettu Eukleideen algoritmi on standardi funktio ExtendedGCD. Lukujen suuruusjärjestyksestä käyttäjän ei tarvitse huolehtia:
Salakirjoitus 7 a = 963; b = 4320; ExtendedGCD@a, bd 89, 8 157, 35<< Todellakin 9 = syt(963, 4320) = 157*963 + 35*4320. Harjoituksia 11 Määritä syt(1233, 63) ja esitä se muodossa s 1233 + t 63, missä s, t œ. Välivaiheet tulee merkitä selkeästi näkyviin 12 Määritä syt(2333, 187) ja esitä se muodossa s 2333 + t 187, missä s, t œ. 12' Lisäharjoitus. Valitse itse luvut a ja b. Laske valitsemillasi luvuilla d = syt(a, b) ja esitä d muodossa d = s a + t b, missä s, t œ. à 2.3 Eukleideen algoritmin kompleksisuus Päätämme tämän kappaleen Eukleideen algoritmin kompleksisuuden tarkasteluun. Olkoon a > b 1. Verrataan algoritmin toiminnan nopeutta luvun b arvoon. Algoritmin toiminta on hitaimmillaan silloin, kun jakojäännös r k pienenee kussakin askeleessa r k-2 = q k r k-1 + r k mahdollisimman vähän. Tällaiseen tilanteeseen joudutaan, jos r k-2 = r k-1 + r k aina kun 2 k n - 1, ts. jos jokaisella askeleella (ensimmäistä askelta a = q 1 b + r 1 lukuunottamatta) osamäärä q k saa arvon 1 edellyttäen, että se on ylipäätään mahdollista. Tällöin on myös voimassa r n-2 = 2 r n-1, kun r n = 0. Toisin sanoen, sellainen luvun a pienin arvo (a > b 1), jolle sytha, bl:n laskeminen vie n - 2 askelta (so. riviä) saadaan, kun a = F n ja b = F n-1, missä jono HF i L i 0 on kuuluisa Fibonacci-lukujono, joka määritellään asettamalla F 0 = 0, F 1 = 1 ja F i+2 = F i+1 + F i aina kun i 0. Jonon alku on siis: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,.... Alla Mathematican toiminta kohdistuu toistuvasti listoihin, jotka koostuvat kahdesta peräkkäisestä Fibonacci-luvusta (tässä käytetään Nest-funktiota). Näin saadaan menetelmä Fibonacci-lukujen laskemiseksi. Tässä esimerkissä lasketaan F 99 ja F 100, jotka ovat jo hyvin suuria lukuja: f@8u_, v_<d := 8v, u + v< n = 99; Nest@f, 80, 1<, nd 8218922995834555169026, 354224848179261915075< Voidaan käyttää myös Mathematican sisäänrakennettua funktiota: Fibonacci. Fibonacci@100D 354224848179261915075 Tarkastellaan vielä yllä esitettyä analyysiä kirjoittamalla Mathematicalla funktio sytiteroinnit. Siinä käytetään jakojäännöksen laskemiseen valmista funktiota Mod:
Salakirjoitus 8 sytiteroinnit@n_integer? Positive, m_integer? PositiveD := Module@ 8a = n, b = m, r, t = 0<, While@ b > 0, r = Mod@a, bd; 8a, b, t< = 8b, r, t + 1<D; td n = 100; sytiteroinnit@fibonacci@nd, Fibonacci@n 1DD 98 Siis tosiaankin sytha, bl:n laskeminen vie tapauksessa n = 100 juuri nuo aiemmin mainitut n - 2 askelta, kun a = F n ja b = F n-1. Kokeillaan vielä tapausta n = 10. Tässäkin tapauksessa Eukleideen algoritmin toiminta päättyy 8 askeleessa, ts. tarvitaan 8 riviä. Tässä Fibonacci-luvut ovat seuraavat: 8Fibonacci@10D, Fibonacci@9D< 855, 34< Eukleideen algoritmi päättyy rivillä numero 8: Hrivi 1L 55 = 1 * 34 + 21 Hrivi 2L 34 = 1 * 21 + 13 Hrivi 3L 21 = 1 * 13 + 8 Hrivi 4L 13 = 1 * 8 + 5 Hrivi 5L 8 = 1 * 5 + 3 Hrivi 6L 5 = 1 * 3 + 2 Hrivi 7L 3 = 1 * 2 + 1 Hrivi 8L 2 = 2 * 1 + 0 Asettamalla F n = cf n Fibonacci-lukujen määrittelyrelaatiossa F i+2 = F i+1 + F i, saadaaan f 2 = f + 1, jonka nollakohdat ovat: 1 è!!! 5 ÅÅÅÅÅÅÅÅÅÅÅÅÅÅ. Esitämme ilman todistusta seuraavan ylärajan Eukleideen algoritmin kompleksisuudelle. 2 Se voidaan todistaa induktiolla luvun a suhteen (erottelemalla tapaukset b ÅÅÅÅÅ a ÅÅÅÅÅ < b < a). f ja a f Lause 2.3 Eukleideen algoritmin kompleksisuus Olkoot a ja b positiivisia kokonaislukuja, a > b 1 ja olkoon f = 1 + è!!! 5 ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ. Tällöin 2 Eukleideen algoritmin tarvitsema iteraatioiden lukumäärä syt(a, b):n laskemiseksi on korkeintaan 1 + log f b. Testataan tätä vielä yhdellä suhteellisen suurella luvun b arvolla:
Salakirjoitus 9 a = Fibonacci@1000D; b = Fibonacci@999D; sytiteroinnit@a, bd Ceiling@Log@H1 + Sqrt@5DL ê 2,bDD 998 998 Ja vielä yhdellä suhteellisen pienellä luvun b arvolla: a = Fibonacci@1000D; b = 100; sytiteroinnit@a, bd Ceiling@Log@H1 + Sqrt@5DL ê 2,bDD 3 10 Käytännössä Eukleideen algoritmi toimii usein paljon nopeammin, kuin mitä Lauseen 2.3 yläraja antaisi aiheen odottaa. Kaikki etätehtävät kappaleeseen 2 2. Eukleideen algoritmi 2.1 2 Suurimman yhteisen tekijän tehokas laskutapa ja lineaarikombinaatio sytha, bl = ua+ vb 11 Määritä syt(1233, 63) ja esitä se muodossa s 1233 + t 63, missä s, t œ. Välivaiheet tulee merkitä selkeästi näkyviin 12 Määritä syt(2333, 187) ja esitä se muodossa s 2333 + t 187, missä s, t œ. 12' Lisäharjoitus. Valitse itse luvut a ja b. Laske valitsemillasi luvuilla d = syt(a, b) ja esitä d muodossa d = s a + t b, missä s, t œ.