6. előadás Faktorizációs technikák közepes méretű osztókra Dr. Kallós Gábor 2016 2017 1 Tartalom Feladatok, megjegyzések Irodalom 2
Eml.: Próbaosztásos algoritmus (teljes felbontás) 14-18 jegyű számokig használható jól (gyors gépen esetleg valamivel tovább) Efelett reménytelenül lelassul Ötlet: Túl sokat akarunk egyben! (Szerényebb cél is elég lenne) Döntés: a szám nem prím (biztosan tudjuk) Bontsuk szét két valódi osztója szorzatára! (És ezekkel dolgozunk majd tovább) Feltételezés: n a négyzetgyökéhez viszonylag közeli két faktorra bomlik Az algoritmus a négyzetgyök közeléből indulva keres valódi osztót Alapötlet: Ha n = x 2 y 2, akkor n = (x y) (x + y), és a felbontásunk sikeres Az is igaz, hogy ha n ptlan, akkor n minden felbontása előáll ily módon Legyen ugyanis n = a b, ahol n, a és b ptlanok. Legyen x = (a + b)/2, y = (a b)/2. Ekkor x 2 y 2 = (a 2 + 2 a b + b 2 a 2 + 2 a b b 2 )/4 = a b = n. Az algoritmus működése: Bekérünk egy ptlan n-et, és keresünk olyan x-et, y-t, amire n = x 2 y 2. Kezdetben legyen x = n, y pedig 0, és növeljük y-t addig, amíg x 2 y 2 n lesz. Ha =, akkor kész vagyunk, ha <, akkor x-et növeljük, és iterálunk. Addig folytatjuk ezt, amíg sikeresek nem leszünk. Mostani megvalósítás: u = 2x + 1 és v = 2y + 1-et választunk, x és y eggyel való növelése u és v 2-vel való növelését jelenti 3 Feladat: Nézzük meg az algoritmus működését n = 21-re! Lépések: gy := 5, u := 11, Csináljuk meg ugyanezt 51 = 3 17-re! Az algoritmus előnyei Nincs benne osztási és szorzási művelet, extrém gyorsan végrehajtható egy ciklus Ha valóban a szám négyzetgyöke körül van faktor, akkor igen hatékony Hátrányok Kedvezőtlen esetekben nagyon sok lépés kellhet Pl. 1 783 647 329 = 84 449 21 121 felbontásához 10 551 x_loop és 31 664 y_loop Ha n prím, akkor ez az algoritmus nagyon rossz választás Javítási lehetőség: Ha x 2 n nem teljes négyzet, akkor úgysem találhatunk jó y-t! (x eldobható) Ez az algo. nagyon sikeres modern módszerek alapja Kraitchik ötlete (20. sz.): Keressünk véletlen x és y számokat, amelyekre x 2 y 2 (mod n). Ekkor n (x 2 y 2 ) és lnko(n, x y) jó eséllyel valódi osztó. Hogyan keressük őket? (Lánctört algoritmus Morrison-Brillhart módszer, kvadratikus szita) 4
Cél: Általánosan használható jó algoritmus, amely határozottan túllép a próbaosztásos algoritmus nagyságrendjén, és talál faktort (10 7 10 15 környékén) (A lánctört algoritmus és a kvadratikus szita inkább még nagyobb faktorok leválasztására jó) Alapötlet: Legyen n összetett, és d egy ismeretlen valódi osztója. Legyen f(x) egyszerű irreducibilis polinom. (A gyakorlatban pl. x 2 + 1 jól használható.) Induljunk egy x 0 egésztől, és készítsük el az x i = f (x i 1 ) mod n sorozatot. [Pl. x 0 = 2, f(x) = x 2 + 1, n = 1133-ra: x 0 = 2, x 1 = 5, x 2 = 26, x 3 = 677, x 4 = 598, x 5 = 710, stb.] Legyen y i = x i mod d. [Esetünkben d = 11-gyel: y 0 = 2, y 1 = 5, y 2 = 4, y 3 = 6, y 4 = 4, y 5 = 6, y 6 = 4, stb.] Mivel x i f (x i 1 ) (mod n), ezért y i f (y i 1 ) (mod d). Csak véges sok mod d ekv.osztály van (d darab), ezért előbb-utóbb y i = y j lesz, i j-re. Ezután már ciklizálni fogunk a továbbiakban (y i + t = y j + t lesz, poz. t-re). (Az y i -k/x i -k sorozatának rajzáról kapta a nevét az algoritmus.) Ha y i = y j, akkor x i x j (mod d), azaz d (x i ). Szinte biztosan x i x j, és ekkor lnko(n, x i ) az n egy valódi osztója. 5 Probléma: Mivel d-t nem ismerjük, ezért az y i -ket (és y i = y j -ket) nem tudjuk meghatározni De (eml.): y i + t = y j + t végtelen sok esetben teljesül, így a végtelen sok párból kellene egyet megtalálni Ha a ciklus c hosszú, akkor a farok elhagyása után már bármelyik (i, j) pár jó, amire c (j i) A megoldás így az, hogy rengeteg (i, j) párt megnézünk (akár: egy jó stratégiával), és mindegyikre kiszámítjuk lnko(n, x i )-t Javaslat (R. Brent, 1980): Ne kelljen tárolni nagyon sok x i értéket, vizsgáljuk csak a következő különbségeket: x 1 x 3, x 3 x 6, x 3 x 7, x 7 x 12, x 7 x 12, x 7 x 13, x 7 x 15, n+ 1 n 1 n+ 1 általánosan: x, és 2 2 2 1 2 n x 1 j j Fontos: A koordináták közti különbség mindig csak eggyel nő A kis indexektől haladunk a nagyok felé (előbb-utóbb elhagyjuk a farkot ) Mivel tipikusan nagyon sok lnko számítást kell elvégezni (akár: tízezreket), ezért célszerű több, pl. 10 egymás utáni (x i ) (mod n) szorzatát venni, és erre végezni az lnko számítást Ha n szorzat, akkor általában egy tényező osztója, ilyenkor válasszunk másik alappolinomot 6
Az algoritmus nem talál biztosan megoldást, ill. lehet, hogy nagyonnagyon sokára talál csak osztót! Célszerűen: leállítási/kilépési lehetőség biztosítása (pl. 10000 vagy 100000 ciklusonként) Prímszámokra tilos futtatni! Feladat: Elemzés (próbafuttatás) kis n-re, pl. n = 253-ra (= 11 23) 7 Az algoritmus működése n = 253-ra (= 11 23) c = 1 x1 = 2, x2 = 5 range = 1 # compute diff # ciklus 1-től 1-ig x2 = 5 5 + 1 = 26 # x3 pr = (2 26) mod 253 = 229 lnko(253, 229) 1 # reset x1 = 26 range = 2 # ciklus 1-től 2-ig x2 = 26 26 + 1 mod 253 = 171 # x4 x2 = 171 171 + 1 mod 253 = 147 # x5 # compute diff # ciklus 1-től 2-ig x2 = 147 147 + 1 mod 253 = 105 # x6 pr = (26 105) mod 253 = 174 lnko(253, 174) 1 x2 = 105 105 + 1 mod 253 = 147 # x7 pr = (26 147) mod 253 = 132 lnko(253, 132) 11 (kész a felbontás) *Feladat (Maple): Keressünk olyan összetett számokat, amelyekre a 'pollard' opció gyorsabb felbontást ad, mint az alapértelmezett módszer! 8
Hatékonysági elemzés (összehasonlítás a próbaosztásos módszerrel) Kis prímosztókra a Pollard-ró algoritmus kevéssé hatékony Kisebb egészekre (öt-hétjegyű számok) nem érdemes még bevetni *Vizsgálat: Hány iteráció (m(p)) alatt találja meg a Pollard-ró algoritmus a következő prímosztókat (p)? (legnagyobb hatjegyű prímek) Eredmény (Knuth): m(p) várható értéke kb. 2 p, és m(p) soha nem lépi túl a 12 p-t, ha p < 10 6 *A próbaosztásos algoritmus futási ideje arányos max( p )-vel, ahol p t az n szám t 1, p t legnagyobb prímosztója Ha egy prímtesztet is bevetünk a felbontás előtt, akkor p t 1 -gyel arányos * futási ideje arányos p t 1 -gyel, végeredményben a lépésszám általában jóval n 1/4 alatt van Konklúzió: majdnem minden 12 jegyű számot kevesebb mint 2000 iterációval tényezőkre bont, ezzel szemben a próbaosztásos algoritmusnak ehhez mintegy 100.000 osztást kell elvégezni 9 Alapötlet: Fermat kis tételét használjuk, miszerint: 2 p 1 1 (mod p). Tegyük fel, hogy a felbontandó n számnak van egy olyan tulajdonságú p prímfaktora, hogy p 1 minden prímosztója kicsi, pl. kisebb mint 10000. Konkrétan azzal a megkötéssel dolgozunk, hogy p 1 10000!. Mivel a hatványozás modulo n gyors művelet, ki tudjuk számolni m = 2 10000! mod n-t meglehetősen gyorsan: 2 10000! = ( (((2 1 ) 2 ) 3 ) 4 ) 10000. Mivel p 1 10000!, ezért 2 p 1 1 (mod p) miatt m 1 (mod p) is igaz, azaz p (m 1). Nagyon jó esélyünk van arra, hogy n (m 1), azaz g = lnko(m 1, n) az n szám valódi osztója lesz. Nem kell 2-nek lenni az alapnak, választható más c szám is lnko(c, n) = 1-gyel Mivel nem tudjuk, hogy a 10000-et mennyire kell megközelítenünk ahhoz, hogy megtaláljuk n első (vagy: összes szükséges) prímosztóját, ezért rendszeresen ellenőrizzük lnko(c k! 1, n)-t. Ha ez 1, akkor folytatjuk; ha ez n, akkor minden osztót felkaptunk egyszerre, ezért vagy visszalépés kell, vagy más c alap, vagy más algoritmus. Ha erre 1 < lnko < n, akkor megvan a keresett osztó. 10
Alkalmazás előtt: Mint a Pollard-ró algoritmusnál, n-ről tudnunk kell már, hogy nem prím, és ellenőriztük, hogy nincs kis prímosztója Ha p 1-nek csak nagy prímosztói vannak, akkor az algoritmus kudarcot vall! 11 Feladat: Elemzés (próbafuttatás) kis n-re, pl. n = 253-ra (= 11 23) m = 2 # ciklus 1-től -ig m = 2 1 mod 253 = 2 lnko(1, 253) = 1 m = 2 2 mod 253 = 4 lnko(3, 253) = 1 m = 8; lnko(7, 253) = 1 m = 16; lnko(15, 253) = 1 m = 32; lnko(31, 253) = 1 m = 64; lnko(63, 253) = 1 m = 2 7 mod 253 = 128 lnko(127, 253) = 1 # a 127 prím m = 2 8 mod 253 = 256 mod 253 = 3 lnko(2, 253) = 1 m = 2 9 mod 253 = 6 lnko(5, 253) = 1 m = 2 10 mod 253 = 12 lnko(11, 253) = 11 További elemzés Kis prímekre az algoritmus pazarló, ezeket sokkal magasabb hatványon vesszük figyelembe, mint szükséges Ezt javítva kb. 8-szoros gyorsítás érhető el Ha p az n legkisebb prímosztója, akkor az algoritmusnak átlagosan p 1 legnagyobb prímosztója db ciklust kell megtennie (Eml.: n 0,63 átlagosan ) Ezért max = 10000-rel 2 millió körülig általában minden osztót megtalálunk Néha jóval nagyobbakat is Ez az algoritmus az oka, hogy az RSA-nál kellett a megkötés p 1-re és q 1-re 12
Feladatok, megjegyzések Megjegyzés az algoritmusokhoz A korábbi algoritmusok (Fermat eljárása is) teljesen pontosan előre leírható, determinisztikus működésűek A most megismertek (Pollard eljárásai) véletlenszerűséget visznek a rendszerbe, nem lehetünk biztosak benne, hogy adott idő alatt valóban találunk osztót (valószínűségi algoritmusok) Az első (ókori) algoritmusok még alkalmasak voltak prímtesztre és faktorizációra is, a továbbiakban a két feladat teljesen szétválik Feladatok Bontsuk fel (beépített v. saját) Pollard-ró és Pollard (p 1) algoritmussal a következő számokat: 785.994.771.137 950.161.333.249 2.506.741.191.739 227.793.195.071.137 Hasonlítsuk össze a futási időket! Válasszunk 100 db egymást követő számot 500 és 2000 között, ezek lesznek az n-ek. Minden n-re készítsük el az y 0 = 2, y 1 = (2 2 + 1) mod n,, (y 2 i+1 + 1) mod n sorozatot, egészen addig, amíg az értékek nem ismétlődnek. Milyen összefüggést tapasztalunk a ciklusok hossza és n négyzetgyöke között? Határozzuk meg, hogy kb. hány jegye van 10000!-nak! Melyik 2-nek az a legnagyobb hatványa, ami osztja a 10000! számot? 13 Ajánlott irodalom David M. Bressoud: Factorization and Primality Testing, Springer, New York, 1989 Joachim Gathen, Jürgen Gerhard: Modern Computer Algebra (3rd ed.), Cambridge Univ. Press, 2013 Donald E. Knuth: A számítógép-programozás művészete 2. (2. kiadás), Műszaki Könyvkiadó, Budapest, 1994 Katona Gyula, Recski András, Szabó Csaba: A számítástudomány alapjai, Typotex Kiadó, Budapest, 2003 Maple User Manual, Maplesoft, 2013 Matlab Symbolic Math Toolbox User s Guide, MathWorks, 2013 Iványi Antal (szerk.): Informatikai algoritmusok 1., ELTE Eötvös Kiadó, Budapest, 2004 14