Über die Implementierung kryptographischer Primitive mittels sicherer Multiagentenberechnungen Christoph Amma 30. Januar 2007 Inhaltsverzeichnis 1 Einleitung 1.1 Grundlegenden Definitionen und Notationen . . . . . . . . . . . . 1.2 Aufbau der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . 2 3 4 2 Kryptographische Grundlagen 2.1 Secret Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Verifiable Secret Sharing . . . . . . . . . . . . . . . . . . . . . . . 2.3 Sichere Mehrparteienberechnungen . . . . . . . . . . . . . . . . . 4 4 5 6 3 Simulation boolescher Schaltkreise 3.1 Boolesche Operatoren . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Geheime Vergleiche . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 8 4 Kontrollstrukturen und einfache Operationen 4.1 Bedingte Verzweigungen . . . . . . . . . . . . . 4.2 Schleifen . . . . . . . . . . . . . . . . . . . . . . 4.3 Berechnung nichtlinearer Funktionen . . . . . . 4.3.1 Funktionsinterpolation . . . . . . . . . . 4.3.2 Vergleiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 14 14 15 15 5 Langzahlarithmetik 5.1 Basisoperationen . . . . . . . . . . . . . . . . . . . . . . . 5.1.1 Division und Modulo . . . . . . . . . . . . . . . . . 5.1.2 Addition und Multiplikation von Kurzzahlen . . . 5.1.3 Geheime Vergleiche . . . . . . . . . . . . . . . . . . 5.2 Rechnen mit Langzahlen auf arithmetischen Schaltkreisen 5.2.1 Addition . . . . . . . . . . . . . . . . . . . . . . . . 5.2.2 Subtraktion . . . . . . . . . . . . . . . . . . . . . . 5.2.3 Multiplikation . . . . . . . . . . . . . . . . . . . . 5.2.4 Kurze Division mit Rest . . . . . . . . . . . . . . . 5.2.5 Verzweigungen . . . . . . . . . . . . . . . . . . . . 5.2.6 Division mit Rest . . . . . . . . . . . . . . . . . . . 5.2.7 Modulare Exponentiation . . . . . . . . . . . . . . 5.3 Binärer Fall . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 Aufwand der Operationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 17 17 18 19 21 21 21 22 23 23 24 28 29 30 . . . . . . . . . . 30 32 6 RSA 6.1 Arithmetischer Schaltkreis über dem Ring Zpq . . . . . . . . . . . . . . . . . . . . . . . . . 7 AES 35 8 Abschlussdiskussion 37 1 1 Einleitung Mobile Softwareagenten sollen in den zukünftigen Rechnernetzen alltägliche Aufgaben für ihre Besitzer übernehmen. Bei einem Agenten handelt es sich dabei um ein autonomes Programm, welches nicht auf dem Rechner seines Besitzers ausgeführt wird. Der Agent operiert autonom im Netz und kann sich dabei von Host zu Host bewegen (migrieren). Die Hosts führen das Programm des Agenten aus. Der Agent wird also nicht von einem stationären Rechner aus über das Netzwerk Serverdienste in Anspruch nehmen, sondern die Server direkt besuchen und die Dienste auf dem System selbst in Anspruch nehmen. Die Möglichkeiten der Anwendungen reichen von der Informationsbeschaffung und Filterung bis hin zur Recherche von günstigen Angeboten eines Produktes und dem anschliessenden Erwerb. Damit sich dieses Konzept durchsetzen kann, muss unabdingbar die Sicherheit eines solchen Agenten gewährleistet werden. Dieses Problem ist bisher noch nicht befriedigend gelöst. Die Daten eines Agenten sollten im Allgemeinen geheim, die gesammelten Informationen nicht einsehbar und das Programm des Agenten sollte unmanipulierbar sein. Die Rechner, auf denen der Agent ausgeführt wird, sind in der Regel nicht vertrauenswürdig. Die Betreiber hätten sogar in vielen Einsatzszenarien einen Vorteil durch eine Manipulation oder Analyse der Agenten. Unter diesen Vorraussetzungen ist es schwierig, einerseits ein Programm auf einen fremden Rechner zu migrieren, und anderseits eine Analyse bzw. gezielte Manipulation von Code und Daten zu verhindern. Ein Schutz vor Manipulation ist grundsätzlich unmöglich, da der ausführende Host physikalisch uneingeschränkten Zugriff auf den Agenten haben muss. Allerdings sollte eine unbemerkte Manipulation verhindert werden. Nach einer Manipulation sollte der Agent in einen definierten Zustand, zum Beispiel die Terminierung, übergehen. Dies ist allerdings schwierig, da ein Agent im Allgemeinen nicht feststellen kann, ob er manipuliert wurde. Ein einzelner Agent, der nur mit seinem Host interagiert, kann niemals sichere Berechnungen nach oben genannten Anforderungen durchführen, was Algesheimer et.al. in [ACCK01] zeigen. Es muss also Interaktion mit mindestens einer dritten Instanz stattfinden. Vorschläge hierfür sind entweder eine einzelne vertrauenswürdige dritte Partei oder eine Gruppe von Agenten, die sich gegenseitig sichern. Eine einzelne universelle vertauenswürdige Instanz steht dem Konzept der Autonomie der Agenten entgegen, da hier eine Abhängigkeit besteht, die nicht kontrollierbar ist. Bisherige Ansätze, eine sich selbst sichernde Gruppe von Agenten zu verwenden sind entweder nicht vollständig sicher, gehen von zu starken Rahmenbedingungen aus oder wurden nicht zu Ende gedacht. Meist wurde versucht, mittels kryprographischer Techniken, alle erdenklichen Angriffe zu verhindern. Die Problematik dieses Ansatzes ist offensichtlich, da man im Allgemeinen nicht alle möglichen Angriffe angeben kann. Endsuleit und Mie verfolgen in [EM03] ebenfalls einen Ansatz, der auf Gruppen von Agenten basiert. Sie erlauben allerdings im Gegensatz zu anderen Verfahren explizit alle Arten von Angriffen. Die Agentenallianz ist so konzipiert, dass trotz erfolgter Angriffe das korrekte Ergebnis berechnet und die Privatheit der Daten gewahrt bleibt, solange eine gewisse Schwelle korrekter und unmanipulierter Agenten nicht unterschritten wird. Endsuleit und Mie benützen ein Verifiable Secret Sharing Scheme (VSS), um die Daten der Agenten verteilt und somit geheim zu speichern und ein darauf basierendes Protokoll für 2 sichere Mehrparteienberechnung1, um auf den Daten Berechnungen ausführen zu können. Das Protokoll realisiert einen arithmetischen Schaltkreis über einem endlichen Körper. Dabei können verteilte Daten lokal addiert werden, zur Multiplikation von verteilten Daten ist jedoch Kommunikation zwischen den Agenten nötig. In dem vorgeschlagenen Modell kann eine gewisse Anzahl, hier bis zu einem Drittel, der Agenten unter feindlicher Kontrolle stehen, ohne die korrekte Ausführung des Programms oder die Privatheit der Daten zu gefährden. Alle Protokolle (VSS und MPC) kommen aus der Kryptographie, das heisst deren Sicherheit kann als ausreichend analysiert bzw. sogar bewiesen gelten. In der vorliegenden Arbeit untersuche ich die tatsächliche Praktikabilität dieses Ansatzes. Da im Allgemeinen die Komplexität des Verfahrens für beliebige Anwendungen zu hoch ist, beschäftige ich mich mit der Analyse wichtiger Kryptographischer Primitive, wie RSA und AES. Hierfür bestimme ich, ob und mit welchem Aufwand sich diese Verfahren auf einem arithmetischen Schaltkreis, also letztlich auf dem vorgeschlagenen Protokoll, implementieren lassen. Motivation ist einerseits die Notwendigkeit, daß eine Agentenallianz diese Verfahren, wie z.B. die Erstellung digitaler Signaturen, ausführen kann. Anderseits soll an diesen Anwendungen beispielhaft untersucht werden, wie sich allgemein formulierte Programme und Algorithmen auf einen arithmetischen Schaltkreis transformieren lassen und damit für eine solche Agentenallianz implementieren lassen. Ich untersuche, wie sich einfache Kontrollstrukturen, wie Schleifen und Verzweigungen, implementieren lassen. Ausserdem gebe ich ein Verfahren zur geheimen Berechnung beliebiger nichtlinearer Funktionen an. Dies liefert auch eine Möglichkeit geheime Werte zu vergleichen. Neben der Realisierbarkeit interessiert natürlich auch der Aufwand der Verfahren. Mit Aufwand ist immer der Kommunikationsaufwand gemeint, da die Kommunikation unter den Agenten und damit das Netzwerk der beschränkende Faktor sein wird und nicht die Rechenkapazität der ausführenden Hosts. Ich gebe weder ein allgemeines Verfahren für die Transformation, noch eine allgemeine Abschätzung des Aufwandes an. Vielmehr werden Einzelprobleme, die sich bei der Umsetzung der kryptographischen Verfahren ergeben, detaillierter betrachtet und gelöst. Im Besonderen wird dabei im Zuge der Umsetzung von RSA auf dem Schaltkreis auf die Implementierung einer Langzahlarithmetik eingegangen. Die Ergebnisse liefern einen Eindruck, wie praktikabel oder unpraktikabel der vorgeschlagene Ansatz tatsächlich ist. Man wird sehen, dass sich beide Verfahren mit vertretbarem Aufwand umsetzen lassen. Allerdings werden in beiden Fällen Besonderheiten des jeweiligen Algorithmus ausgenutzt. 1.1 Grundlegenden Definitionen und Notationen Ich werde nun einige wichtige Begriffe definieren. Ein durch das benutzte Secret Sharing Scheme kodierter Wert wird im weiteren als verteilter Wert oder geheimer Wert bezeichnet. Ein nicht verteilter Wert wird als Skalar bezeichnet. Ein arithmetischer Schaltkreis besteht nur aus Additions-, Multiplikations und Skalarmultiplikationsgattern. Ein Skalarmultiplikationsgatter multipliziert einen Skalar mit einem weiteren Skalar oder einem verteilten Wert. Ein Multiplikationsgatter multipliziert zwei verteilte Werte. Ein Additionsgatter kann beliebige Werte addieren. Im weiteren ist mit einem arithmetischen 1 engl. Multipartycomputation, MPC 3 Schaltkreis immer ein arithmetischer Schaltkreis über einem endlichen Körper gemeint. Ein arithmetischer Ausdruck ist eine direkt auf einem arithmetischen Schaltkreis berechenbare Formel. Diese besteht nur aus mit Plus und Mal verknüpften verteilten Werten und Skalaren. Die Multiplikationsaufwands-Funktion M(A) ist für einen arithmetischer Ausdruck A als die Anzahl der Multiplikationen verteilter Werte in dem Ausdruck A definiert. Jede verteilte Kommunikation erfordert nach Hirt-Maurer bei n Agenten das Senden von 2n Körperelementen pro Agent und damit 2n2 im Gesamten. Die Anzahl kommunizierter Körperelemente für einen arithmetischen Ausdruck A ist somit 2M(A)n2 . Die Kommunikationskomplexität ist die wesentliche Größe, da die lokale Rechenkapazität der Hostst im Gegensatz zum Kommunikationsnetz nicht der beschränkende Faktor sein wird. Die Funktion M ist daher das entscheidende Aufwandsmaß. 1.2 Aufbau der Arbeit Die Arbeit besteht aus sieben weiteren Abschnitten. Im nächsten führe ich die für das Verständnis nötigen Grundlagen des secret sharing und der Mehrparteienberechnung ein. Im dritten Abschnitt gehe ich auf die Möglichkeit ein, einen booleschen Schaltkreis mittels des gegebenen arithmetischen Schaltkreises zu simulieren und gebe damit ein erstes Verfahren an, mit dem theoretisch jedes beliebige Programm von einer Agentenallianz ausgeführt werden kann. Praktisch hat dieses Verfahren allerdings einen zu hohen Aufwand. Im vierten Abschnitt behandle ich daher die Umsetzung einiger einfacher Kontrollstrukturen direkt auf einem arithmetischen Schaltkreis. Im fünften Abschnitt führe ich eine Langzahlarithmetik auf dem Schaltkreis ein. Und in den letzten zwei Abschnitten untersuche ich mit den erarbeiteten Lösungen die Umsetzung und insbesondere die Komplexität von RSA und AES für eine Agentenallianz. Im letzen Abschnitt diskutiere ich die Ergebnisse hinsichtlich praktischer Bedeutung und Anwendbarkeit auf andere Probleme. 2 2.1 Kryptographische Grundlagen Secret Sharing Um einen Wert geheim über mehrere Parteien verteilt zu speichern, wird ein sogenanntes Secret Sharing benutzt. Ein solches Sharing ermöglicht es, einen Wert derart unter allen Agenten zu verteilen, dass kein einzelner Agent Informationen über den ursprünglichen Wert erfährt. Jeder Agent erhält gewissermaßen einen Teil der Information, ein sogenanntes share. Erst das Zusammenführen einer festgelegten Anzahl dieser shares ermöglicht die Rekonstruktion des kodierten Wertes. Für das vorgestellte Protokoll wird das Secret Sharing nach Shamir [Sha79] über einem endlichen Körper verwendet. Dabei werden die Werte mithilfe von Polynomen aufgeteilt. Die Anzahl der Agenten sei mit n bezeichnet, t sei die maximale Anzahl von Agenten, die böswillig kooperieren kann, ohne das Geheimnis rekonstruieren zu können. Eine beliebige Teilmenge von t + 1 oder mehr Agenten kann das Geheimnis rekonstruieren. 4 Verteilen eines Geheimnisses Ein Geheimnis wird durch ein Polynom repräsentiert, dass an der Stelle 0 den geheimen Wert annimmt. Jeder Agent erhält einen Punkt des Polynoms. Über diese Punkte können die Agenten später das Polynom und damit das Geheimnis rekonstruieren. Genauer erhält jeder Agent Ai einen festen Wert αi zugewiesen, mit αi 6= αj , i, j ∈ {1, . . . , n} für i 6= j und αi 6= 0. Dieser Wert ist die Stützstelle eines Agenten. Um ein Geheimnis s verteilt zu speichern, wird ein zufälliges Polynom S vom Grad t und der Form S(x) = Σti=1 ai xi + s gewählt. Jeder Agent Ai erhält nun sein Share si mit si = S(αi ). Rekonstruktion des Geheimnisses Eine Teilmenge von t + 1 beliebigen Agenten kann nun mithilfe ihrer Shares das Polynom S(x) interpolieren und damit das Geheimnis s = S(0) berechnen. Die Berechnung von S(x) kann mittels Lagrange Interpolation erfolgen. Eine Einführung in das Interpolationsverfahren nach Lagrange gibt beispielsweise [HH94], Kapitel 5, Abschnitt 2.1. Es sei I = {0, . . . , k} mit #I = t + 1 eine Indexmenge für t + 1 beliebige Agenten. Es gilt S(x) = X si l i mit li = i∈I Y j∈I j6=i αj . αj − αi (1) Das Polynom S(x) kann dadurch eindeutig berechnet werden. Eine Menge von t oder weniger Agenten kann keinerlei Informationen über das Geheimnis gewinnen. 2.2 Verifiable Secret Sharing Das gerade vorgestellte Secret Sharing ist nicht robust gegen Angreifer, die Werte manipulieren. Liefert einer der t + 1 Agenten zur Rekonstruktion einen falschen Wert, dann wird auch ein falsches Polynom interpoliert. Um den Wert eines Geheimnisses zu rekonstruieren sind grundsätzlich t + 1 korrekte Shares notwendig, da mit diesen das Verteilungspolynom interpoliert werden kann. Berlekamp und Welch geben in [BW86] ein Verfahren an, mit dem das Polynom S(x) immer noch effizient berechnet werden kann, auch wenn k < (n − t)/2 Shares falsch sind. Da höchstens t Agenten manipuliert sind, gilt k ≤ t. Das gesuchte korrekte Polynom sei mit f (x) bezeichnet. Der rekonstruierende Agent erhält von den anderen Agenten deren Shares (αi , yi ). Er berechnet nun das Fehlerpolynom E(x), E 6= 0 vom Grad kleiner gleich k und das Polynom B(x) := f (x) · E(x) vom Grad kleiner gleich t + k. Es gilt somit B(αi ) = yi · E(αi ) für i = 1, ..., n . Falls eine Lösung für dieses lineare Gleichungssystem existiert, so liefert sie das gesuchte Polynom f = B/E. Berlekamp und Welch zeigen, dass immer eine Lösung existiert und diese auch eindeutig ist. Der rekonstruierende Agent muss also das Gleichungssystem lösen, wobei der Leitkoeffizient von E auf eins gesetzt wird um die Bedingung E 6= 0 sicherzustellen. Des weiteren ist der Wert von k 5 nicht bekannt, allerdings gilt auf jeden Fall k ≤ t. Für k wird deshalb einfach k = t gesetzt, da dies der maximale Wert ist. Das zu lösende LGS lautet demnach ! t−1 2t X X j el αli für i = 1, ..., n (2) bj αi = yi αti · j=0 2.3 l=0 Sichere Mehrparteienberechnungen Protokolle für sichere Mehrparteienberechnungen erlauben es einer Menge von n Parteien eine bestimmte Funktion gemeinsam zu berechnen, selbst wenn bis zu t Parteien feindlich, bzw. unter feindlicher Kontrolle sind. Dabei bleiben die Eingaben und sämtliche Zwischenergebnisse geheim. Hirt und Maurer liefern in [HM01] ein effizientes Protokoll, um Mehrparteienberechnungen auf einem arithmetischen Schaltkreis über einem endlichen Körper F durchzuführen. Für n Agenten können t < n/3 korrumpierte Agenten toleriert werden. Das heisst, das Protokoll ist sicher und robust bis zu dieser Grenze. Es basiert auf dem oben vorgestellten Verifiable Secret Sharing, das heisst, alle geheimen Werte werden nach Shamir unter den Agenten verteilt gespeichert. Rechnen mit Shares Zwei geheime Werte können lokal ohne Kommunikation zwischen den Agenten addiert und mit einem öffentlichen Skalar, also einem nicht verteilten Wert, multipliziert werden. Die Addition zweier Geheimnisse g, h mit Polynomen G(x), H(x) kann einfach durch lokale Addition der Shares berechnet werden. Dies entspricht der Addition der zwei Polynome, die durch die Shares definiert werden. Das resultierende Polynom A(x) = G(x)+H(x) kodiert das Ergebnis der Addition, da A(0) = G(0) + H(0) = g + h gilt. Die Multiplikation mit einem öffentlichen Skalar, also einem nicht verteilten Wert, funktioniert analog. Die Shares werden lokal mit dem Skalar multipliziert. Auch die Multiplikation zweier Geheimnisse m = g · h funktioniert im Prinzip durch die Multiplikation der Shares, allerdings handelt es sich dabei um eine Polynommultiplikation, das heisst, die resultierenden Shares definieren ein Polynom M (x) mit Grad 2t. Der Grad der Verteilungspolynome ist allerdings nach oben durch t beschränkt, da immer t + 1 Agenten ein Geheimnis rekonstruieren können müssen. Um trotzdem geheime Werte multiplizieren zu können schlagen Gennaro et.al. in [GRR98] ein entsprechendes Protokoll vor. Dieses Protokoll ermöglicht die Multiplikation geheimer Werte bei gleichbleibenden Grad, allerdings ist dafür Kommunikation unter den Agenten nötig, das heisst, das Ergebnis kann nicht lokal auf den Shares berechnet werden. Das Protokoll von Hirt-Maurer Die Addition und Multiplikation mit Skalaren werden wie oben beschrieben lokal berechnet. Für die Multiplikationsgatter wird eine Vorberechnung durchgeführt, um die Multiplikation später zu vereinfachen. Für jedes Multiplikationsgatter wird ein Tripel (a, b, c) verteilt berechnet, wobei a und b Zufallszahlen sind und c = a·b gilt. Die Agenten verfügen nur über die Shares des Tripels, a, b, c sind also geheime Werte. Für die Berechnung von c wird das oben genannte Multiplikationsverfahren von Gennaro et.al. verwendet. Das Protokoll umfasst Teilprotokolle, um manipulierte Agenten in dieser Phase auszuschliessen. Die eigentliche Multiplikation zweier verteilter Zahlen x, y ∈ F 6 läuft nach folgendem Verfahren ab. Das Produkt wird zu xy = ((x − a) + a)((y − b) + b) = (x − a)(y − b) + (x − a)b + (y − b)a + c umgeformt. Dabei wird eines der vorberechneten Tripel (a, b, c) verbraucht. Die Agenten berechnen die Differenzen dx := x−a und dy := y−b und rekonstruieren die Geheimnisse, also die tatsächlichen Werte von dx und dy . Dabei wird keine Information über x oder y bekannt, da a und b zufällige verteilte Werte sind. Nun kann jeder Agent lokal über die Formel xy = dx dy + dx b + dy a + c sein Share des Produkts berechnen. Da dx und dy bekannt sind, müssen nur noch Skalarmultiplikationen und Additionen berechnet werden. Das Protokoll hat eine wahrscheinlich optimale Kommunikationskomplexität von O(mn2 ), wobei m die Anzahl der Multiplikationsgatter und n die Anzahl der Agenten bezeichnet. 3 Simulation boolescher Schaltkreise Ich betrachte nun die Problematik allgemein formulierte Programme und Algorithmen auf dem arithmetischen Schaltkreis auszuführen. In Programmen stehen Vergleiche und Kontrollstrukturen, wie Verzweigungen und Schleifen, zur Verfügung, in dem Schaltkreis allerdings nur einfache Additions- und Multiplikationsgatter. Die Elemente der Programmiersprache müssen also durch einen Schaltkreis ausgedrückt werden. Ein Prozessor tut genau dies mittels eines booleschen Schaltkreises. Die einfachste Methode, beliebige Programme auf einem arithmetischen Schaltkreis auszuführen, ist demnach die Simulation eines booleschen Schaltkreises. Der Wertebereich der Variablen ist also beschränkt auf {0, 1}. Im wesentlichen muss dann natürlich eine binäre Logik wie in einem Prozessor implementiert werden um die Programme darauf auszuführen. 3.1 Boolesche Operatoren Das Eins- und Nullelement des Körpers entsprechen dem Eins- und Nullelement im boolschen Schaltkreis. Da (∧, ¬) ein vollständiges Operatorensystem bilden, ist es ausreichend diese beiden Operatoren durch Funktionen im arithmetischen Schaltkreis darzustellen. boolscher Ausdruck a∧b ¬a arithmetische Formel f (a, b) = a · b f (a) = 1 − a Dass sich diese Funktionen entsprechen, ist leicht einzusehen. In unserem Falle verteilter geheimer Werte bleiben diese auch in dem simulierten boolschen Schaltkreis geheim. Der Operator AND benötigt eine Multiplikation und hat somit einen Kommunikationsaufwand von 2n2 , während die Negation keine Kommunikation erfordert. Weitere Operatoren, wie OR, lassen sich durch die bereits definierten Operatoren darstellen (a ∨ b = a ∧ b). Die daraus resultierende arithmetische Formel ist a + b − ab. Der Kommunikationsaufwand des OR Operators ist somit gleich dem des AND Operators 2n2 . 7 Die Simulation eines booleschen Schaltkreises erfordert die softwareseitige Implementierung typischer Schaltungen in Prozessoren, wie zum Beispiel Addierer, Multiplizierer, usw., da alle Zahlen im Binärsystem vorliegen. Der Vorteil, mit einem arithmetischen Schaltkreis beliebige Berechnungen über einem endlichen Körper beliebiger Größe auszuführen, geht verloren. Aus diesem Grund nenne ich diesen Ansatz hier nur, um zu zeigen daß damit theoretisch alle Programme auf einem arithmetischen Schaltkreis ausführbar sind. Der Aufwand ist allerdings praktisch sehr hoch. 3.2 Geheime Vergleiche Für binäre Werte ist es nun einfach, Vergleichsoperatoren geheim umzusetzen, da nur der entsprechende boolesche Ausdruck in einen arithmetischen umgewandelt werden muss. Das Ergebnis eines solchen Vergleichs ist entsprechend der verteilte binäre Ergebniswert. Für den Gleichheits- und Größeroperator sind die entsprechenden booleschen und arithmetischen Ausdrücke in der Tabelle angegeben. Operator = > boolescher Ausdruck (¬a ∧ ¬b) ∨ (a ∧ b) a ∨ ¬b arithmetische Formel 1-a-b+ab(1+a+b-ab) a − ab Der Vergleich auf Gleichheit benötigt 2 Multiplikationen und hat damit einen Kommunikationsaufwand von 4n2 . Der Größer Operator benötigt eine Multiplikation und hat einen Kommunikationsaufwand von 2n2 . 4 Kontrollstrukturen und einfache Operationen Im folgenden Kapitel wird die Umsetzung von Kontrollstrukturen auf einen arithmetischen Schaltkreis untersucht. Ich behandle zuerst Verzweigungen und Schleifen als Grundbausteine von Programmen. Danach gehe ich auf Vergleiche geheimer Werte ein. Das Grundproblem bei Verzweigungen und Schleifen ist der mögliche Informationsverlust. So darf zum Beispiel bei einer Verzweigung mit geheimer Bedingung aus dem Programmablauf nicht rekonstruierbar sein, welcher Zweig tatsächlich ausgeführt wurde. Denn wäre dies nachvollziehbar, so wäre sofort auch die Bedingung bekannt. Ähnlich besteht bei einer Schleife mit geheimer Abbruchbedingung das Problem, dass über die Anzahl der Schleifendurchläufe die Abbruchbedingung rekonstruiert werden kann. Diese Probleme kann man lösen, indem man alle möglichen Fälle der Programmausführung durchrechnet, allerdings nur die tatsächlich relevanten Fälle ins Ergebnis der Berechnung einbezieht. Bei Vergleichen geheimer Zahlen stellt sich das Problem, dass die einzelnen Shares keinerlei Rückschlüsse über eine Ordnungsrelation der geheimen Werte zulassen. Ich führe eine allgemeine Methode ein, nichtlineare Funktionen auf einem Schaltkreis darzustellen. Da ein Vergleich von zwei geheimen Zahlen eine nichtlineare Funktion in den Wertebereich {0, 1} ist, kann man das Problem damit lösen. 4.1 Bedingte Verzweigungen Eine bedingte Verzweigung kann im Schaltkreis berechnet werden, allerdings müssen immer beide Fälle der Verzweigung berechnet werden, da ansonsten die 8 Bedingung öffentlich wird. Die Bedingung b ist ein verteilter boolscher Wert, es gilt also b ∈ {0, 1}. Die Variablen a1 und a2 seien öffentliche oder verteilte Werte, x eine verteilte Variable. Es soll die bedingte Verzweigung wenn b dann x ← a1 sonst x ← a2 berechnet werden. Dazu wird der dann Zweig mit dem Ergebnis der Bedingung b, und der sonst Zweig mit 1−b, also der Negation der Bedingung, multipliziert. Auf diese Weise wird der korrekte Zweig ausgewählt. Der arithmetische Ausdruck hierfür lautet x = ba1 + (1 − b)a2 . Diese Form der Berechnung lässt keinerlei Rückschlüsse zu, welcher Zweig ausgewählt wurde, also welchen Wert die Bedingung b hat. Es findet also kein Informationsverlust statt. Um die bedingte Verzweigung wenn b dann x ← a1 zu berechnen, muss entsprechend der Ausdruck x = ba1 + (1 − b)x berechnet werden. Durch den fehlenden sonst Zweig spart man keine Multiplikation. Es muss immer auch der Zweig, indem keine Veränderung der Variable auftritt, berechnet werden, da in jedem Fall ein Wert zugewiesen werden muss. Eine Verzweigungsoperation wird deshalb mit if bezeichnet, egal ob es sich um eine wenn-dann oder um eine wenn-dann-sonst Verzeigung handelt. Pro Variablenzuweisung innerhalb einer Verzweigung sind zwei Multiplikationen erforderlich. Der Multiplikationsaufwand einer bedingten Verzweigung ist also M(if) = 2 Sei nun B der arithmetische Ausdruck, welcher die Bedingung b ergibt und seien A1 , A2 die arithmetischen Ausdrücke, die die Werte a1 und a2 ergeben. Der Gesamtmultiplikationsaufwand einer bedingten Verzweigung ist damit für jede Variable, der ein Wert zugewiesen wird, M(ifA1 ,A2 ) = M(A1 ) + M(A2 ) + 2 . Hinzu kommt der einmalige Aufwand M(B) zur Auswertung der Bedingung. Dieser wird nicht in die obige Formel mit einberechnet, da die Bedingung für mehrere Variablenzuweisungen in der gleichen Verzweigung nur einmal berechnet werden muss. Bei verschachtelten Verzweigungen muss ebenfalls jeder mögliche Fall berechnet werden. Ich betrachte beispielhaft das in Abbildung 4.1 dargestellte Programm. Die Bedingungen Bij und die Ausdrücke Aij sind arithmetische Ausdrücke. Man beachte, dass sie die Variable x selbst enthalten können. Aus diesem Grund können die Ausdrücke nicht im Vorhinein ausgewertet werden, um danach die Verzweigung zu berechnen. Ein erster Ansatz eine solche verschachtelte Verzweigung in arithmetische Ausdrücke umzuwandeln bestünde darin, die Zuweisungen sukzessive von aussen nach innen in Ausdrücke umzuwandeln. Dabei ist die Reihenfolge der Abarbeitung wesentlich, da sich ein geänderter Wert 9 wenn B11 dann x ← A11 ; wenn B21 dann x ← A21 ; sonst x ← A22 ; sonst x ← A12 ; wenn B22 dann x ← A23 ; sonst x ← A24 ; Abbildung 1: Programm mit einer Verzweigung der Tiefe zwei mit Zuweisungen an x in jeder Ebene und Verzweigung. der Variable x in den Folgeausdrücken auswirken kann. Die entsprechenden Ausdrücke wären dann b11 x b12 b22 x = B11 = B11 A11 + (1 − B11 )A12 = B21 = B22 = b11 (b21 A21 + (1 − b21 A22 ) + (1 − b11 )(b22 A23 + (1 − b24 )A24 ) Die Berechnung der äußeren Verzweigung ist nicht notwendig, durch Vorberechnung aller Zwischenergebnisse und korrekte Substitution dieser in die folgenden Ausdrücke kann darauf verzichtet werden. Die entsprechenden Ausdrücke sind dann b11 = B11 a11 a12 = = A11 A12 b21 b22 = = a21 a22 = = B21 [x ← a11 ] B22 [x ← a12 ] a23 a24 = = x = A21 [x ← a11 ] A22 [x ← a11 ] A23 [x ← a12 ] A24 [x ← a12 ] b11 (b21 a21 + (1 − b21 )a22 ) + (1 − b11 )(b22 a23 + (1 − b22 )a24 ) , wobei die Substitutionen immer in eckigen Klammern hinter dem Ausdrück angegeben sind. Auf diese Weise können alle arithmetischen Ausdrücke in einer Verzweigung vorberechnet werden. Dadurch spart man in diesem Fall zwei Multiplikationen. Beispiel 1. In dem Programm aus Abbildung 4.1 seien die folgende Ausdrücke 10 b11 b11 a12 b21 a21 b22 a22 b21 a24 a23 a21 a22 (b) (a) Abbildung 2: (a) Ein vollständiger Verzweigungsbaum der Tiefe 2. (b) Ein minimaler Verzweigungsbaum der Tiefe 2. Alle vorkommenden Ausdrücke in Zuweisungen und Bedingnungen sind schon ausgewertet und die entsprechenden Substitutionen durchgeführt. Die Ergebnisse der äusseren Zuweisungen sind nicht dargestellt, da sie für die weitere Berechnung der Verzweigung nicht benötigt werden. gegeben. Die Berechnung des Vergleiches für die Bedingung B21 wird in Abschnitt vorgestellt. A11 A21 = a+b = x+c A22 B21 = x−c = x>d Die vorberechneten und substituierten Ausdrücke lauten dann entsprechend: a11 = a+b b21 a21 = = a22 = a11 > d a11 − c a11 + c Eine vollständige Verzweigung der Tiefe 2 benötigt also 6 Multiplikationen, zuzüglich des Aufwandes für die Berechnung der Ausdrücke in den Zuweisungen und der Bedingungen. Vollständig bedeutet, dass bis zu einer gegebenen Tiefe jeder Ausdruck wieder eine Verzweigung ist. Für verschachtelte Verzweigungen beliebiger Tiefe funktioniert das Verfahren analog. Die Ausdrücke werden sukzessive in die innerste Verzweigung substituiert und dann der enstprechende Ausdruck für die Verzweigung berechnet. Allgemein lässt sich eine solche geschachtelte Verzweigung als Binärbaum darstellen. Ein Knoten entspricht der Bedingungen einer Verzweigung, die linke Kante eines Knotens entspricht dem dann Zweig, die rechte dem sonst Zweig. Die Kanten werden mit den Ergebnissen der arithmetischen Ausdrücken, die in der Verzweigung zu berechnen sind, markiert. Die Blätter des Baumes sind unmarkiert und können ignoriert werden. Abbildung 2(a) zeigt einen solchen Baum der Tiefe 2 für eine vollständige Verzweigung. Der Baum ist in diesem 11 Fall ebenfalls vollständig. Ein minimaler Baum einer gegebenen Tiefe hat in jeder Verschachtelungstiefe nur eine Verzweigung, Abbildung 2(b) zeigt den entsprechenden minimalen Baum für die Tiefe 2. Der entsprechende arithmetische Ausdruck für diesen Baum ist b11 (b21 a21 + (1 − b21 )a22 ) + (1 − b11 )a12 . Es sind also vier Multiplikationen nötig. Ich bestimme die Anzahl der Multiplikationen für diese beiden Fälle in Abhängigkeit der Verschachtelungstiefe, um eine obere und untere Schranke des Aufwandes für eine Verzweigung zu erhalten. T (x) bezeichne im weiteren die Anzahl der Multiplikationen für die Verzweigung in Abhängigkeit der Tiefe x, ohne die Auswertung der arithmetischen Ausdrücke für die Bedingungen und Zuweisungen. Ich betrachte zuerst den Fall der vollständigen Verzweigung. Anhand des Baumes lässt sich leicht sehen, dass für die nächste Verzweigungstiefe die Anzahl der Verzweigungen verdoppelt wird und noch eine weitere Verzweigung hinzukommt. Anschaulich wird der bisherige Baum dupliziert und die beiden Bäume über eine Verzweigung verbunden. Die entsprechende Rekurrenzrelation ist demnach T (1) = T (n + 1) = 2 2T (n) + 2 Satz 2. Eine Zuweisung innerhalb einer vollständig verschachtelten Verzweigung der Tiefe n benötigt T (n) = 2n+1 − 2 Multiplikationen. Beweis. Der Beweis erfolgt induktiv. Sei n die Tiefe der Verzweigung, dann gilt für n = 1 T (1) = 22 − 2 = 2 . Die Rekurrenzrelation lautet T (n + 1) = 2T (n) + 2 . Es gelte die Induktionsannahme T (n) = 2n+1 − 2 für ein n ∈ N. Damit ergibt sich für n → n + 1 T (n + 1) = 2T (n) + 2 = 2(2n+1 − 2) + 2 = 2 · 2n+1 − 4 + 2 = 2n+2 − 2 . Für den minimalen Aufwand einer verschachtelten Verzweigung gilt die Rekurrenzrelation T (1) = T (n + 1) = 2 T (n) + 2 , da für eine um eins höhere Verzweigungstiefe genau eine Verzweigung hinzu kommt. Satz 3. Eine Zuweisung innerhalb einer minimal verschachtelten Verzweigung der Tiefe n benötigt T (n) = 2n Multiplikationen. 12 Beweis. Der Beweis erfolgt ebenfalls induktiv. Sei n die Tiefe der Verzweigung, dann gilt für n = 1 T (1) = 2 · 1 = 2 . Die Rekurrenzrelation lautet T (n + 1) = T (n) + 2 . Es gelte die Annahme T (n) = 2n für ein n ∈ N, damit ergibt sich für n → n + 1 T (n + 1) = T (n) + 2 = 2n + 2 = 2(n + 1) . Satz 2 und Satz 3 liefern obere und untere Schranken für den Multiplikationsaufwand T (n) einer Verzweigung der Tiefe n. Für eine Verzweigung der Tiefe n gilt also 2n ≤ T (n) ≤ 2n+1 − 2 (3) Beispiel 4. Ich betrachte als Beispiel eine verschachtelte Verzweigung aus Algorithmus 6 (Seite 26) Zeilen 9 bis 13. Das Programm hat die Form: wenn b1 dann q ← q − 1; c ← c + v; wenn b2 dann q ← q − 1; Zuerst werden die Ausdrücke in der äußeren Verzweigung in die innere Verzweigung substituiert. Zu beachten ist, dass auch in dem im Programm fehlenden sonst Fall substituiert werden muss. Die Zuweisung an c bleibt stehen, da die Variable in der inneren Verzweigung nicht mehr vorkommt. Bezüglich der Variable c handelt es sich hier nur um eine Verzweigung der Tiefe 1. Nach der Substitution hat das Programm die Form: wenn b1 dann c ← c + v; wenn b2 dann q ← q − 2; sonst q ← q − 1; sonst c ← c; Nun kann für die Berechnung von q und c ein arithmetischer Ausdruck angegeben werden. Die Ausdrücke lauten: q = c = b1 (b2 (q − 2) + (1 − b2 )(q − 1)) + (1 − b1 )q b1 (c + v) + (1 − b1 )c Es werden also insgesamt 6 Multiplikationen benötigt. 13 4.2 Schleifen Bei Schleifen mit geheimen Abbruchbedingungen stellt sich das gleiche Problem wie bei den Verzweigungen. Es müssen alle möglichen Fälle, also Durchläufe, berechnet werden. Würde die Schleife gemäß der Abbruchbedingung beendet, käme es zu einem Informationsverlust. Ein potentieller Angreifer könnte die Anzahl der Durchläufe bestimmen und damit Rückschlüsse über die in der Abbruchbedingung vorkommenden Variablen ziehen. Das folgende Beispiel demonstriert dies. Beispiel 5. Ich betrachte die Schleife mit der geheimen Variablen x und y. solange x > c tue y ←y+d x←x−e Bricht die Schleife tatsächlich ab, wenn die Bedingung x ≤ c eintritt, ist die Anzahl der Durchläufe D bekannt. Man weiss damit, dass der Wert von y nach Ausführung der Schleife ynach = yvor +D ·d ist. Wäre die Anzahl der Durchläufe der Schleife nicht bekannt, dann kennt man den Wert von y nach Ausführung der Schleife nicht, selbst wenn dieser vor Ausführung der Schleife bekannt war. Auch über den Wert von x bekommt man Informationen, falls die Schleife abbricht. In diesem Fall ist die Differenz zwischen x vor der Schleife und c bekannt und man weiss dass nach der Schleife xnach = xvor − e · D gilt. Dass nach der Schleife x ≤ c gilt, ist immer bekannt, auch wenn die Anzahl der Durchläufe geheim bleibt. Eine Schleife mit geheimer Abbruchbedingung kann im Schaltkreis dargestellt werden. Die Schleife wird in diesem Fall maximal oft ausgeführt und über Multiplikation mit der Bedingung und deren Komplement werden die ungewollten Durchläufe wieder ausgeblendet. Eine Schleife der Form solange B tue x ← A1 deren maximale Anzahl an Iterationen k betrage, kann in die Ausdruckssequenz x = x = .. . x = b1 A1 + (1 − b1 )x, b2 A2 + (1 − b2 )x, bk Ak + (1 − bk )x umgewandelt werden. Die Variable bi bezeichne dabei das Ergebnis der Auswertung von B in der i-ten Iteration. Dies entspricht k bedingten Verzweigungen oder einer minimalen verschachtelten Verzweigung der Tiefe k. Der Multiplikationsaufwand beträgt 2k Multiplikationen. 4.3 Berechnung nichtlinearer Funktionen Da ein arithmetischer Schaltkreis nur über Additions- und Multiplikationsgatter verfügt, lassen sich damit nur lineare Funktionen direkt darstellen. Man will 14 natürlich aber auch nichtlineare Funktionen berechnen können. Ich betrachte eine beliebige n-stellige Funktion der Form f : Fn → F, (x1 , . . . , xn ) → y Für die von mir betrachteten Verfahren genügt die Beschränkung des Wertebereichs auf eine Dimension. Grundsätzlich ist aber auch ein mehrdimensionaler Wertebereich kein Problem. Da F ein endlicher Körper ist, ist auch der Definitions- und Wertebereich der Funktion f endlich. Genauer hat der Definitionsbereich die Größe |F|n und der Wertebereich die Größe |F|. Es gibt also genau |F|n Wertepaare, die die Funktion vollständig definieren. Diese Wertepaare definieren auf eindeutige Weise ein Polynom P vom Gesamtgrad |F|n − 1. Da es sich bei dem Polynom P um eine lineare Abbildung handelt kann es direkt im Schaltkreis berechnet werden. Damit läßt sich also prinzipiell jede beliebige Funktion berechnen. 4.3.1 Funktionsinterpolation Ich stelle das Verfahren der Berechnung von nichtlinearen Funktionen mittels interpolierter Polynome detaillierter dar und bestimme den Multiplikationsaufwand einer solchen Berechnung. Dabei beschränke ich mich auf den Fall einstelliger Funktionen, also Funktionen der Form f : F → F, da nur diese in der weiteren Arbeit benötigt werden. Ich betrachte also eine beliebige Funktion f : F → F, f (x) = y . Die Funktion ist bekannt und damit auch alle Werte, die sie annimmt. Man kennt also die Paare (x, f (x)) für alle x ∈ F. Diese definieren ein Polynom p vom Grad d = |F| − 1 mit der Eigenschaft p(x) = f (x), ∀x ∈ F . Das Polynom hat die Form p(x) = αd xd + αd−1 xd−1 + . . . + α1 x + α0 , αi ∈ F. Der Koeffizientenvektor (αd , αd−1 , . . . , α0 ) ist öffentlich und jedem Agenten bekannt. Damit können die Agenten die Funktion f gemeinsam berechnen, es muss lediglich das Polynom an der entsprechenden Stelle ausgewertet werden. Geheime Multiplikationen sind nur für die Berechnung der Potenzen von x notwendig. Die jeweils nächsthöhere Potenz kann aus der vorhergehende durch eine Multiplikation gemäß xk+1 = xk · x für alle x ∈ N berechnet werden. Insgesamt sind demnach d − 1 = |F| − 2 verteilte Mulitplikationen nötig. 4.3.2 Vergleiche Vergleiche geheimer Werte sind nicht einfach zu realisieren. Die Shares der einzelnen Agenten stehen bezüglich einer Ordnungsrelation in keinem Zusammenhang zu den tatsächlichen geheimen Werten. Ein Vergleich auf Gleichheit kann allerdings auf die Berechnung des multiplikativ Inversen eines Körperelements zurückgeführt werden. Es gilt x · x−1 = 1 , x ∈ F/{0} . 15 Ich definiere nun eine Funktion inv zur Berechnung des Inversen, die auch für die 0 definiert ist −1 x falls x 6= 0 inv(x) = 0 sonst Damit kann nun eine Funktion eq mit eq(a, b) = 1 − ((a − b) · inv(a − b)) zum Vergleich zweier Zahlen angegeben werden, denn es gilt 1 falls a = b eq(a, b) = 0 sonst Die Berechnung der Funktion inv kann gemäß dem Verfahren in Abschnitt 4.3.1 durch ein interpolierendes Polynom berechnet werden. Damit ergibt sich ein Multiplikationsaufwand für die Gleichheitsfunktion von M(eq) = M(inv) + 1 = |F| − 1 . Ein Vergleich auf Ungleichheit kann einfach durch Negierung des Ergebnisses der Gleichheitsfunktion erfolgen. Die Negation wurde bereits in Abschnitt 3.1 vorgestellt, ich führe sie hier noch einmal unter dem Bezeichner not(x) = 1 − x , x ∈ {0, 1} ein. Der Ungleichheitsoperator neq(x, y) kann dann als neq(a, b) = not(eq(a, b)) dargestellt werden. Es gilt M(neq) = M(eq) = |F| − 1 Ob eine Zahl grösser oder kleiner als eine andere ist, läßt sich nicht ohne weiteres feststellen, da ein endlicher Körper keine Ordnung hat. Eine Möglichkeit ist natürlich auch hier wieder die Interpolation durch ein Polynom. In diesem Fall muss allerdings eine Funktion in zwei Variablen interpoliert werden, was auch zu einem Interpolationspolynom in zwei Variablen führt. Unter Umständen gibt es aber noch effizientere Verfahren. Ich werde in Abschnitt 5.1.3 in Zusammenhang mit der Einführung einer Langzahlarithmetik eine effizientere Möglichkeit vorstellen, die aber nicht im Allgemeinen funktioniert. Da sie für die Betrachtungen in dieser Arbeit aber ausreicht, werde ich das allgemeine Verfahren nicht genauer analysieren. 5 Langzahlarithmetik Da für Primitive der Public-Key Kryptographie große Zahlen benötigt werden soll im Folgenden eine Langzahlarithmetik auf dem arithmetischen Schaltkreis über dem Körper F aufgebaut werden. Ich nehme für F einen Primkörper der Ordnung p an. Eine LangzahlP a wird wie üblich bezüglich einer Basis B dargen−1 stellt und hat die Form a = i=0 ai B i , n ist die Stelligkeit. Die größte noch darstellbare Zahl im Körper muss B 2 − 1 sein. Dieser Wert ist momentan noch 16 nicht direkt nachvollziehbar, damit wird aber sichergestellt, dass bei den für die Langzahlarithmetik nötigen Verknüfungen von Zahlen nie eine Reduktion modulo p im Körper F kommt. Damit soll eine Einbettung in die ganzen Zahlen simuliert werden. Es ergibt sich der Zusammenhang p B 2 − 1 < p ⇔ B 2 < p + 1 ⇔ B < ⌊ p + 1⌋ √ Die größtmögliche Basis im Körper Fp ist somit B = ⌊ p + 1⌋. Wir betten also ein Stellenwertsystem zur Basis B in unseren Körper F ein. Die Menge B := {0, .., B − 1} beinhaltet die möglichen Werte einer Ziffer in einer Langzahl. Eine einstellige Zahl wird auch als Kurzzahl bezeichnet. Die nachfolgenden Algorithmen und ihr jeweiliger Aufwand Aufwände gelten nur für B ≥ 3. Auf den Spezialfall B = 2 gehe ich in Abschnitt 5.3 genauer ein, da dieser Fall auch einfachere Algorithmen für die Langzahlarithmetik ermöglicht. 5.1 Basisoperationen Um eine Langzahlarithmetik auf einem arithmetischen Schaltkreis zu implementieren sind folgende Operationen notwendig: 1. Die Division mit Rest von Kurzzahlen. Für gegebende a, b ∈ B soll q, r ∈ B mit a = b·q +r berechenbar sein. Das entspricht den Operatoren a div b = ⌊a/b⌋ und a mod b = a mod b. 2. Addition und Multiplikation zweier Kurzzahlen mit Übertrag. 3. Vergleich zweier Kurzzahlen auf Gleichheit, Grösser und Kleiner. 4. Die Division einer zweistelligen Zahl durch eine einstellige Zahl für den Fall, dass das Ergebnis, also der Quotient, wieder einstellig ist. Also q = ⌊(a1 · B + a0 )/b⌋ mit a0 , a1 , b ∈ B und der Vorraussetzung, dass auch q ∈ B gilt. Diese Operation wird für die Implementierung einer Langzahldivision benötigt. Ich führe nun verschiedene Operationen ein, deren Notation einem einheitlichen Schema folgt. Alle Operationen werden in Proportionalschrift dargestellt (z.B. op). Die Anzahl der Argumente, die aus verteilten Werten bestehen können, wird als Zahl hinter der Operation angeben (z.B. op1 oder op2). Hat die Anzahl geheimer Argumente keinen Einfluss auf den Aufwand wird die Zahl weggelassen (z.B. op). Handelt es sich um eine Operation, deren Argumente aus Langzahlen bestehen, wird zusätzlich der Buchstabe l vorangestellt (z.B. lop1). 5.1.1 Division und Modulo Ich untersuche den Aufwand für die div und mod Operationen in verschieden Varianten. Die Funktionen div1 und mod1 bezeichnen die Division und Reduktion im Falle, dass nur ein Operand geheim ist und der andere feststeht. Für die Langzahlarithmetik ist der Divisor auf B festgesetzt. Es gilt also div1 : {0, . . . , B 2 − 1} → B, 17 x 7→ ⌊x/B⌋ und mod1 : {0, . . . , B 2 − 1} → B, x 7→ ⌊x mod B⌋ Dies ermöglicht eine effizientere Berechnung gegenüber dem Fall, dass beide Operanden geheim sind. Die Festlegung auf B als Divisor ergibt sich durch die spätere Anwendung, der Aufwand ist für jede Wahl gleich. Die Funktionen für zwei geheime Operanden werden für die Langzahlarithmetik nicht benötigt. Der Übertrag einer Addition oder Multiplikation kann einfach mittels Division des Egebnisses durch B berechnet werde. Oft wird der erste Operand nur aus dem eingeschränkten Wertebereich {0, .., 2B − 1} statt {0, .., B 2 − 1} stammen. Der Wert 2B − 1 ist das maximale Ergebnis einer einstelligen Addition plus einem eventuellen Übertrag, da (B − 1) + (B − 1) + 1 = 2B − 1 gilt. Die Funktionen rediv1 und remod1 bezeichnen die Division und Modulo-Operation auf dem eingeschränkten Wertebereich, ebenfalls mit der Basis B als zweitem festen Operanden. Es gilt also rediv1 : {0, . . . , 2B − 1} → {0, 1}, x 7→ ⌊x/B⌋ und remod1 : {0, . . . , 2B − 1} → {0, . . . , B − 1}, x 7→ x mod B Diese Funktionen werden wie in Abschnitt 4.3.1 beschrieben durch Polynome dargestellt. Für die verschiedenen div und mod Operationen ergibt sich damit folgender Multiplikationsaufwand: M(div1) = M(mod1) = M(rediv1) = M(remod1) = B2 − 2 2B − 2 Oft werden bei einer Division sowohl der Quotient, als auch der Rest als Ergebnis benötigt. Der Rest kann lokal ohne Multiplikationsaufwand aus dem Quotienten berechnet werden, denn für a div B = q gilt a mod B = a − q · B. Die Berechnung von Quotient und Rest wird mit divmod bezeichnet und es gilt M(divmod1) = M(div1) = B 2 − 2 M(redivmod1) = M(rediv1) = 2B − 2 5.1.2 Addition und Multiplikation von Kurzzahlen Die Addition zweier einstelliger Zahlen kann lokal ausgeführt werden. Das Ergebnis muss aber bezüglich B reduziert werden. Es müssen Übertrag und Rest bestimmt werden, also eine Division und eine Modulo Operation durchgeführt werden. Hier kann das eingeschränkte redivmod1 verwendet werden, da das Ergebnis einer Addition höchstens (B − 1) + (B − 1) = 2B − 2 ist. Ob eines oder beide Argumente geheim sind, spielt für den Aufwand keine Rolle. Die Addition sei mit add bezeichnet und hat einen Aufwand von M(add) = M(redivmod1) = 2B − 2 . Die Multiplikation benötigt eine verteilte Multiplikation zur Berechnung des Ergebnisses, falls beide Zahlen geheim sind. Ausserdem wird wieder eine Kombination aus Division und Modulo Operation für die Berechnung des Übertrags 18 und des Restes benötigt, in diesem Falle eine divmod1 Operation, da das maximale Ergebnis hier (B − 1) · (B − 1) = B 2 − 2B + 1 beträgt. Die Multiplikation wird mit mul bezeichnet und hat einen Aufwand von M(mul1) = M(divmod1) = B 2 − 2 für den Fall eines geheimen Operanden und M(mul2) = M(divmod1) + 1 = B 2 − 1 für den Fall zweier geheimer Operanden. 5.1.3 Geheime Vergleiche Die Vergleichsoperatoren <, >, ≤, ≥ können für geheime Kurzzahlen a, b mit einer Division, genauer, einer rediv1 Operation, berechnet werden. Die folgende Tabelle gibt die entsprechenden arithmetischen Ausdrücke für die Operatoren an. Das Ergebnis der Ausdrücke ist jeweils ein verteilter boolescher Wert. a>b (B − 1 + a − b) rediv1 B a≥b (B + a − b) rediv1 B a<b 1 − ((B + a − b) rediv1 B) a ≤ b 1 − ((B − 1 + a − b) rediv1 B) Da a, b einstellige Zahlen mit a, b ∈ B = {0, .., B − 1} sind, liegen die durch B zu dividierenden Ausdrücke für a > b und a ≤ b im Intervall [0, 2B − 2] und für a ≥ b und a < b im Intervall [1, 2B − 1]. Damit kann an dieser Stelle die rediv1 Operation benutzt werden. Der Wertebereich von rediv1 ist um eins größer als hier benötigt. Der Klarheit und Einfachheit halber benütze ich die Funktion hier aber trotzdem, eine Optimierung an dieser Stelle hat keine signifikante Auswirkung. Alle vier Operatoren haben also einen Aufwand von M(rediv1) = 2B − 2. Gleichheit und Ungleichheit lassen sich durch den ≥ und ≤ Operator über den Zusammenhang a = b ⇔ (a ≥ b) ∧ (a ≤ b) darstellen, benötigen dann aber die doppelte Anzahl an Multiplikationen plus dem Aufwand für die UNDVerknüpfung. Die UND-Verknüpfung kann wie in Abschnitt 3.1 dargestellt mit einer Multiplikation realisiert werden. Allerdings fällt kein weiterer Speicherbedarf an. Die in Abschnitt 4.3.2 vorgestellte generelle Methode benötigt |F| − 1 Multiplikatioen. Man kann den Gleichheitsoperator aber auch direkt über ein Polynom berechnen. Die Differenz a − b ist 0, falls a und b gleich sind und ungleich 0, falls sie ungleich sind. Das Ergebnis von a − b liegt im Intervall [−(B − 1), B − 1] und die Berechnung des zugehörigen Polynoms vom Grad 2B − 2 benötigt damit 2B − 3 Multiplikationen. Um alle Vergleichsoperatoren mit einheitlichem Aufwand betrachten zu können, setze ich den Aufwand auch auf 2B − 2 fest. Die Anzahl geheimer Operatoren ist unerheblich, da der Aufwand für die Subtraktion davon nicht abhängt. Die Vergleichsoperatoren {<, >, ≤, ≥, =} seien als Oberbegriff mit cmp bezeichnet und es gilt somit M(cmp) = 2B − 2 . Für die Division von Langzahlen werden wir einen Vergleich zwischen einer Zahl a ∈ {0, .., (B − 1)2 } und einer Zahl b ∈ {0, ..., B 2 − 1} berechnen 19 Algorithmus 1 : Vergleich auf Kleiner Eingabe : a = (an−1 ...a0 ), b = (bn−1 ...b0 ) Ausgabe : r = 1 falls a < b, r = 0 sonst 1 r ← 0; 2 für i ← 0 bis n − 1 tue 3 wenn ai < bi dann 4 r ← 1; 5 sonst 6 wenn ai > bi dann 7 r ← 0; müssen (siehe Algorithmus 6, Zeile 9). Ein Vorgehen wie oben dargestellt ist nicht möglich, da Überläufe nicht mehr eindeutig festgestellt werden können. Eine direkte Berechnung der Funktion über ein Polynom wäre sehr aufwendig, da beide Argumente des Vergleichs geheim sind und damit ein Polynom in zwei Variablen ausgewertet werden müsste. Eine andere Möglichkeit ist, die Operanden zu erst in zweistellige Langzahlen umzuwandeln und dann zu vergleichen. Für die Umwandlung einer Zahl x ∈ 0, . . . , B 2 − 1 in eine zweistellige Langzahl (y1 y0 ) werden die einzelnen Stellen folgendermassen berechnet: y1 = x/B, y0 = x mod B Die Berechnung benötigt eine Division und eine Modulo Operation und hat damit einen Aufwand von M(divmod1) Multiplikationen. Ein Verfahren zum Vergleich zweier Langzahlen gebe ich in Algorithmus 1 exemplarisch für den < Operator an. Für die anderen Operatoren funktioniert das Verfahren analog. Die Stellen der Langzahlen werden paarweise verglichen, angefangen von der niederwertigsten Stelle. Im Normalfall würde man bei der höchstwertigen Stelle beginnen und abbrechen, sobald das Ergebnis klar ist. Da die Langzahlen aber aus geheimen Werten bestehen, kann nicht vorher abgebrochen werden. Die boolsche Variable r gibt zu jedem Zeitpunkt an, ob a < b gilt. Sie wird mit 0 initialisiert. Gilt nun für eine Stelle ai < bi , ist a bis zu dieser Stelle kleiner als b und r wird auf 1 gesetzt. Gilt ai > bi , ist a bis zu dieser Stelle größer als b und r wird auf 0 gesetzt und gilt ai = bi bleibt der Wert von r gleich, da diese Stelle keine Veränderung der Relation beider Zahlen bringt. Die Auswertung der beiden Bedingungen in Zeile 3 und 6 benötigt jeweils M(cmp) Multiplikationen, das Ergebnis ihrer Auswertung sei mit b1 und b2 bezeichnet. Die Verzweigung wird durch den arithmetischen Ausdruck r = b1 · 1 + (1 − b1 )(b2 · 0 + (1 − b2 )r) dargestellt. Dieser lässt sich zu r = b1 − (1 − b1 )(1 − b2 )r vereinfachen und benötigt damit nur 2 Multiplikationen. Die Schleife hat n Durchläufe und es ergibt sich damit ein Gesamtaufwand von M(lcmpn ) = n(2M(cmp) + 2) = n(4B − 2) = 4Bn − 2n . 20 Der Gesamtaufwand für die Umwandlung und den Vergleich der Zahlen beträgt also 2M(divmod1) + M(lcmp2 ) = 2(B 2 − 2) + 2(4B − 2) = 2B 2 + 8B − 8 . 5.2 Rechnen mit Langzahlen auf arithmetischen Schaltkreisen Im folgenden Abschnitt werde ich nun die Grundrechenarten (Addition, Subtraktion, Multiplikation und Division), sowie die modulare Exponentiation auf geheimen Langzahlen einführen. Ich setze dafür die aus [Knu98], [Wel98] und [Cor01] entnommenen Standardverfahren auf einem arithmetischen Schaltkreis um. Es seien im folgenden a, b Langzahlen in b-adischer Darstellung mit Basis B. 5.2.1 Addition Die Addition entspricht der Schuladdition. Für jede Stelle muss eine einstellige Addition mit Reduktion und Übertragsbildung durchgeführt werden. Hierzu reichen die eingeschränkten rediv1 und remod1 Operationen aus. Es muss also pro Stelle eine Division und eine lokale Multiplikation zur Berechnung des Restes ausgeführt werden. In Algorithmus 2 wird das Verfahren dargestellt. Für eine Addition von zwei n-stelligen Zahlen ergibt das einen Multiplikationsaufwand von M(laddn ) = n · M(redivmod1) = 2Bn − 2n . Der Aufwand hängt dabei immer von der Zahl mit den meisten Stellen ab, ist eine Zahl kürzer bringt das keinen Vorteil, da der Algorithmus trotzdem komplett durchgerechnet werden muss. Algorithmus 2 : ladd Eingabe : a = (an−1 . . . a0 ), b = (bn−1 . . . b0 ) Ausgabe : s = (sn . . . s0 ) = a + b 1 c ← 0; 2 für i ← 0 bis n − 1 tue 3 si ← (ai + bi + c) mod B; 4 c ← (ai + bi + c)/B; 5 sn ← c; 5.2.2 Subtraktion Algorithmus 3 subtrahiert zwei Langzahlen a und b voneinander. Das Verfahren setzt im wesentlichen die Schulmethode um. In Zeile 3 wird die aktuelle Stelle berechnet, in Zeile 4 wird die Borge für diese Stelle berechnet. Für den Fall a > b beinhaltet s das Ergebnis der Subtraktion und es gilt c = 0. Für a < b ist das Ergebnis negativ. Das Ergebnis s ist dann das B-Komplement der 21 Algorithmus 3 : lsub Eingabe : a = (an−1 ...a0 ), b = (bn−1 ...b0 ) Ausgabe : s = (csn−1 ...s0 ) = a − b 1 c ← 0; 2 für i ← 0 bis n − 1 tue 3 si ← B + ai − bi − c mod B; 4 c ← 1 − (B + ai − bi − c)/B; Subtraktion und es gilt c = 1, das heisst, der letzte Übertrag ist eins. Falls a = b gilt, sind alle Ergebnisstellen null und es gilt auch c = 0. Die Addition von B auf das Subtraktionsergebnis in Zeile 3 und 4 ist notwendig, damit das Ergebnis der Berechnung im Intervall [0, B−1] liegt. Ansonsten kann es zu einem Unterlauf im Körper kommen und die Resultate der div und mod Operationen wären unbrauchbar. Es genügen wieder die eingeschränkten rediv1 und remod1 Operationen, da 0 ≤ B +ai −bi −c < 2B gilt. Eine Subtraktion zweier n-stelliger Zahlen hat damit einen Aufwand von M(lsubn ) = n · M(redivmod1) = 2Bn − 2n . Auch hier hängt der Aufwand, wie bei der Addition, nur von der Zahl mit den meisten Stellen ab. 5.2.3 Multiplikation Das einfachste Verfahren zur Multiplikation zweier Langzahlen orientiert sich an der Schulmethode und hat einen zeitlichen Aufwand von O(n2 ). Mit der Karatsuba-Multiplikation oder der FFT existieren hierfür schnellere Verfahren, ich stelle nur die Umsetzung des einfachen Verfahrens in Algorithmus 4 vor. Wie in der Schulmethode werden über die zwei Schleifen alle Stellen miteinander multipliziert (Zeile 5). In der Variable c ist der Übertrag aus der vorhergehenden Stelle gespeichert. Im Unterschied zur Schulmethode werden nicht erst alle Multiplikationen ausgeführt, um danach die Ergebnisse zu addieren, sondern die Ergebnisse der Multiplikation werden für jede Stelle gleich fortlaufend aufaddiert. In der Variable w werden diese Werte für jede Stelle gespeichert. Am Ende des Algorithmus steht in w das Gesamtergebnis. Der Schleifenrumpf (Zeilen 5 bis 7) benötigt M(divmod1) + 1 Multiplikationen. Insgesamt wird der Schleifenrumpf m · n mal durchlaufen, wobei m und n die Stelligkeiten der beiden Langzahlen sind. Es ergibt sich ein Multiplikationsaufwand von M(lmul2m,n ) = mn(M(divmod1) + 1) = B 2 mn − mn. Für die Multiplikation einer öffentlichen Langzahl mit einer geheimen kann der gleiche Algorithmus verwendet werden, allerdings ist die Multiplikation in Zeile 5 dann öffentlich, womit der Schleifenrumpf nur M(divmod1) Multiplikationen benötigt. Der Gesamtaufwand beträgt dann mnM(divmod1) für die Stelligkeiten m und n. Es ist dabei nicht relevant, welche der beiden Zahlen öffentlich und welche geheim ist. Es gilt also: M(lmul1m,n ) = mnM(divmod1) = B 2 mn − 2mn 22 Algorithmus 4 : lmul Eingabe : u = (um−1 ...u0 ), v = (vn−1 ...v0 ) Ausgabe : w = u · v = (wm+n−1 ...w0 ) 1 w ← 0; 2 für i ← 0 bis m − 1 tue 3 c ← 0; 4 für j ← 0 bis n − 1 tue 5 t ← ui · vj + wi+j + c; 6 c ← t/B; 7 wi+j ← t mod B; wj+m ← c; 8 5.2.4 Kurze Division mit Rest Bevor ich die allgemeine Division mit Rest vorstelle, betrachte ich den Spezialfall einer Division mit einstelligem Divisor. Diese Operation sei mit shdiv2 bezeichnet und kann effizienter als eine Langzahldivision mit beliebig langem Divisor ausgeführt werden. Wie man im nächsten Abschnitt noch sehen wird, muss bei der allgemeinen Langzahldivision aufwendig bestimmt werden, wie oft der Divisor in die führenden ein oder zwei Stellen des Dividenden passt. Dies kann im Falle eines einstelligen Divisors einfach durch eine div Operation berechnet werden. Das in Algorithmus 5 vorgestellte Verfahren liefert den Quotient und den Rest. Das Verfahren entspricht exakt der Schulmethode. Für jede Stelle wird geteilt und ein eventueller Rest in die nächste Stelle übertragen. Der Schleifenrumpf benötigt M(divmod1) Multiplikationen bei m Iterationen. Es ergibt sich also M(shdiv1) = mM(divmod1) = B 2 m − 2m für die Anzahl der Multiplikationen. Ich betrachte nur den Fall eines öffentlich bekannten Divisors, eine Division zweier geheimer Zahlen wird in dieser Arbeit nicht benötigt. Die kurze Division liefert damit die letzte benötigte Basisoperation, die Division einer zweistelligen Zahl durch eine einstellige, um die allgemeine Langzahldivision durchzuführen. 5.2.5 Verzweigungen Verzweigungen mit Langzahlzuweisungen benötigen ebenfalls eine gesonderte Betrachtung. Es handelt sich dabei zwar nicht um eine Rechenart, ich gehe aber trotzdem an dieser Stelle darauf ein, da für die Division mit Langzahlen solche Verzweigungen berechnet werden müssen. Die in Abschnitt 4.1 vorgestellte Methode zur Berechnung von bedingten Verzweigungen im arithmetischen Schaltkreis ist grundsätzlich auch auf Langzahlen anwendbar. Die nötigen Verfahren zur Addition und Multiplikation von Langzahlen wurden in den vorhergehenden Abschnitten entwickelt. Die für eine Verzweigung nötigen Berechnungen 2 Abk. für short divison, engl. kurze Division 23 Algorithmus 5 : shdiv Eingabe : u = (um−1 ...u0 ), v Ausgabe : q = (qm−1 ...q0 ), r mit u = q · v + r 1 r ← 0; 2 q ← 0; 3 für i ← m − 1 bis 0 tue 4 qi ← (ui + rB)/v; 5 r ← (ui + rB) mod v; lassen sich aber effizienter als mit den Standardverfahren durchführen. Für die Langzahl a = (an−1 ...a0 ), die ausgewertete Bedingung b ∈ {0, 1} und die arithmetischen Ausdrücke A1 , A2 betrachte ich die Verzweigung wenn b dann a ← A1 sonst a ← A2 Dabei seien r = (rn−1 ...r0 ) und s = (sn−1 ...s0 ) die Ergebnisse von A1 und A2 . Zu berechnen ist also der Ausdruck (an−1 ...a0 ) = b · (rn−1 ...r0 ) + (1 − b)(sn−1 ...s0 ) . (4) Bei den Multiplikationen handelt es sich einmal um eine Multiplikation mit dem Faktor 1 und einmal mit 0. Da es in diesen Spezialfällen nicht zu Überträgen kommen kann, können alle Stellen mit dem Faktor durchmultipliziert werden, ohne dass ein Übertrag und Rest berechnet werden muss. Gleichung 4 lässt sich demnach folgendermassen schreiben: (an−1 ...a0 ) = (b · rn−1 ...b · r0 ) + ((1 − b)sn−1 ...(1 − b)s0 ) Damit benötigt eine Langzahlzuweisung innerhalb einer bedingten Verzweigung 2n Multiplikationen, wobei n die Stelligkeit ist, zuzüglich des Aufwandes für die Addition. Es ergibt sich M(lifn ) = 2n + M(laddn ) = 2Bn . 5.2.6 Division mit Rest Um die Grundrechenarten zu vervollständigen, fehlt nun noch die allgemeine Division von Langzahlen. Dies ist auch die aufwendigste Operation. Auch hierbei wird prinzipiell die Schulmethode benützt, allerdings ist die Umsetzung in einen Algorithmus ein wenig schwieriger, da beim Rechnen von Hand für jede Ergebnisstelle eine Abschätzung getroffen wird, die nun in ein algorithmisches Verfahren umgesetzt werden muss. Letzlich reduziert sich das Problem darauf, eine n+1-stellige Zahl durch den n-stelligen Divisor zu teilen. Dies liefert jeweils eine Ergebnisstelle. Man betrachte das klassische Verfahren. Um die Zahl 355938 durch 427 zu teilen, dividiert man 3559 durch 427, was 8 Rest 133 ergibt. Die 8 ist die erste Ergebnisstelle und man fährt fort indem man an den Rest eine weitere Stelle anhängt und damit 1333 durch 427 teilt, was 3 Rest 52 ergibt. Nun wird noch 528 durch 427 geteilt, was 1 Rest 101 ergibt und man erhält als 24 Gesamtergebnis 831 Rest 101. Die Berechnung der einzelnen Ergebnisstellen, ist bereits eine Langzahldivision. Ein Mensch schätzt hier eine Lösung relativ leicht ab, da der Dividend nur um eine Stelle größer als der Divisor ist. In [Knu98] ist ein präzises Verfahren zur Berechnung des Quotienten angegeben. Seien u = (un un−1 . . . u0 ) und v = (vn−1 . . . v0 ) Langzahlen, wobei u dem aktuellen Dividend und v dem Divisor entspricht und es gilt u/v < B. Aufgabe ist es nun also den Quotienten q mit q = ⌊u/v⌋ zu bestimmen. Knuth gibt folgende Näherung q̂ für q an un B + un−1 q̂ = min ,B − 1 vn − 1 Theoreme A und B in [Knu98], Kapitel 4.3.1 besagen, dass falls vn−1 ≥ ⌊B/2⌋ ist, so gilt für q̂ q̂ − 2 ≤ q ≤ q̂ Die Näherung q̂ ist in diesem Fall damit nie kleiner als q und höchstens 2 zu groß. Um die Bedingung vn−1 ≥ ⌊B/2⌋ zu erfüllen, werden u und v mit ⌊B/(vn−1 +1)⌋ multipliziert. Diese Normalisierung ändert den Quotienten u/v nicht und erhöht die Stellenanzahl in v nicht. Die Stellenanzahl von u erhöht sich möglicherweise um eins. Durch diese Normalisierung ist die Bedingung immer erfüllt (siehe [Knu98], Kapitel 4.3.1, exercise 23). n−1 ⌋, B − 1). Man kann die Wahl von Man wähle wie oben q̂ = min(⌊ un B+u vn −1 q̂ noch weiter verbessern, so dass in jedem Fall entweder q̂ = q oder q̂ = q + 1 gilt, q̂ also maximal um eins zu groß ist. Dies erreicht man, indem man testet, ob q̂vn−2 > (un B + un−1 − q̂vn−1 )B + un−2 gilt. Wenn nicht, wird q̂ um eins vermindert und der Test wiederholt. Damit werden alle Fälle, in denen q̂ um zwei zu groß ist und fast alle, in denen q̂ um eins zu groß ist, ausgeschlossen (siehe [Knu98], Kap. 4.3.1, Aufgabe 19,20). Mit diesen Vorüberlegungen kann nun ein Verfahren zur Langzahldivision angegeben werden. Für zwei Langzahlen u = (um+n−1 . . . u0 ) und v = (vn−1 . . . v0 ) sei q = (qm . . . q0 ) = ⌊u/v⌋ der Quotient und r = (rn−1 . . . r0 ) = u mod v der Rest der Division von u durch v. Das Verfahren zur Berechnung von q und r ist nun: 1. Normalisierung: Berechne den Skalierungsfaktor d = ⌊B/(vn−1 + 1)⌋ und setze (um+n um+n−1 . . . u0 ) = d(um+n−1 . . . u0 ) und (vn−1 . . . v0 ) = d(vn−1 . . . v0 ). 2. Initialisierung: Setze j = m, über diese Variable wird iteriert, das Ergebnis der Division hat m + 1 Stellen. 3. Berechnung der nächsten Quotientenstelle: Setze un B + un−1 ,B − 1 . q̂ = min vn − 1 Teste ob q̂vn−2 > (un B + un−1 − q̂vn−1 )B + un−2 gilt, wenn nicht, setze q̂ = q̂ − 1 und wiederhole den Test. 4. Multiplizieren und Subtrahieren: Setze (uj+n uj+n−1 . . . u0 ) = (uj+n uj+n−1 . . . u0 ) − q̂(vn−1 . . . v0 ) . 25 Falls das Ergebnis negativ ist, war q̂ um eins zu groß. In diesem Fall setze q̂ = q̂ − 1 und u = u + v. Setze qj = q̂. 5. Iteration: Setze j = j − 1. Falls j ≥ 0 gehe zu Schritt 3. 6. Denormalisierung: In der Variable (qm . . . q0 ) steht der gesuchte Quotient. Setze r = ⌊(un−1 . . . u0 )/d⌋, dies ist der gesuchte Rest. Algorithmus 6 gibt ein entsprechendes Programm für die Langzahldivision in Pseudocode an. Die Normalisierung findet in den Zeilen 1 bis 3 statt. In den Zeilen 5 bis 7 wird die Näherung der Quotientenstelle nach Schritt 3 berechnet und direkt in qj gespeichert, eine Zwischenvariable q̂ wird nicht benötigt. Sie ist in der informellen Beschreibung des Verfahrens nur der Übersichtlichkeit halber vorhanden. In Zeile 8 wird der Rest für das genäherte q berechnet. Dieser wird für den Test aus Schritt 3 benötigt, er entspricht dort dem geklammerten Ausdruck. Der Test selbst wird in den Zeilen 9 bis 13 durchgeführt. Hier ist zu beachten, dass nach der ersten Korrektur von qj der neue Rest aus dem alten durch Addition von vn−1 berechnet wird, das spart eine Multiplikation. Das Multiplizieren und Subtrahieren (Schritt 4) wird in den Zeilen 14 bis 17 durchgeführt. Hier ist zu beachten, dass die Ergebnislangzahl (uj+n+1 . . . uj ) Algorithmus 6 : ldiv Eingabe : u = (um+n−1 ...u0 ), v = (vn−1 ...v0 ) Ausgabe : q = (qm ...q0 ), r = (rn−1 ...r0 ) mit u = q · v + r /* Normalisierung 1 d ← B/(vn−1 + 1); 2 u ← d · u; 3 v ← d · v; 4 für j ← m bis 0 tue /* Berechnung der nächsten Quotientenstelle 5 qj ← (uj+n B + uj+n−1 )/vn−1 ; 6 wenn qj ≥ B dann 7 qj ← B − 1; 8 9 10 11 12 13 14 15 16 17 18 19 */ */ c ← uj+n B + uj+n−1 − qj vn−1 ; wenn qj vn−2 > Bc + uj+n−2 dann qj ← qj − 1; c ← c + vn−1 ; wenn qj vn−2 > Bc + uj+n−2 dann qj ← qj − 1; /* Multiplizieren und Subtrahieren (uj+n+1 ...uj ) = (uj+n ...uj ) − qj (0vn−1 ...v0 ); wenn uj+n+1 = 1 dann qj ← qj − 1; (uj+n ...uj ) = (uj+n ...uj ) + (0vn−1 ...v0 ); /* Denormalisierung (un−1 ...u0 ) = (un−1 ...u0 )/d; r ← (un−1 ...u0 ); */ */ 26 1 0 0 2 M(lmul1m+n,1) B 2 (m + n) − 2m − 2n 3 0 0 4 m + 1 Wiederholungen Zeile 5 - 17 5 M(shdiv12 ) 2B 2 − 4 6 M(cmp) 2B − 2 7 2 2 8 0 0 9 2M(divmod1) + M(lcmp2 ) 2B 2 + 8B − 8 10 0 0 11 2 2 12 2M(divmod1) + M(lcmp2 ) 2B 2 + 8B − 8 13 4 4 14 M(lsubn+1 ) + M(lmul11,n ) B 2 n + 2Bn + 2B − 4n − 2 15 M(cmp) 2B − 2 16 2 2 17 M(laddn+1 ) + M(lifn+1 ) 4Bn + 4B − 2n − 2 18 M(shdiv1n ) B 2 n − 2n Tabelle 1: Aufwand der Langzahldivision gegeben durch die benötigten verteilten Multiplikationen für jede Zeile von Algorithmus 6. vorne eine Stelle mehr besitzt, als auf den ersten Eindruck nötig scheint, hat. In dieser Stelle steht eine 1, falls das Ergebnis der Subtraktion negativ war, sonst eine 0 (siehe Abschnitt 5.2.2). Nach dieser Stelle wird also verzweigt und falls das Ergebnis negativ ist, dann ist qj um eins zu groß und wird anschliessend in Zeile 16 um eins reduziert. In den Stellen (uj+n . . . uj ) steht dann das BKomplement des Ergebnisses, dieses kann dann einfach durch Rückaddition von (vn−1 . . . v0 ) korrigiert werden. Ein eventueller Übertrag kann ignoriert werden, er würde sich mit der Borge aus der Subtraktion ausgleichen. Ich bestimme nun den Aufwand für den Fall eines öffentlich bekannten Divisors, da dies der für RSA interessante Fall ist. Bei der Normalisierung wird eine Langzahl mit einem öffentlich bekannten Skalar multipliziert. Die Operationen in Zeile 1 und 3 haben öffentliche Operanden. Bei der Berechnung der Quotientenstelle ist bei der Auswertung der Bedingungen in Zeile 9 und 12 zu beachten dass der Ausdruck Bc + uj+n−2 im Intervall [0, .., B 2 ) liegt. Die zu vergleichenden Zahlen werden wie in Abschnitt 5.1.3 beschrieben, in zweistellige Langzahlen umgewandelt und dann verglichen. Die gesamte Verzweigung von Zeile 9 bis Zeile 13 wurde schon in Abschnitt 4.1 exemplarisch in arithmetische Ausdrücke umgewandelt. Bei der Multiplikation und Subtraktion ist zu beachten, dass in Zeile 17 eine Langzahlzuweisung innerhalb einer Verzweigung steht. Diese wird wie in Abschnitt 5.2.5 gezeigt behandelt. Die Denormalisierung benötigt noch eine shdiv Operation. Tabelle 1 gibt den Aufwand für jede Zeile an. Es ergibt sich damit der Gesamtaufwand von M(ldivm,n ) = mnB 2 + 3nB 2 + 7mB 2 + 6B 2 + 6mnB + 6nB + 26mB + 26B − 6mn − 10n − 20m − 18 27 Multiplikationen. Für den Spezialfall m = 0, also der Division gleich langer Zahlen ergibt sich ein Aufwand von M(ldiv10,n ) = 3nB 2 + 6B 2 + 6nB + 26B − 10n − 18 Multiplikationen. 5.2.7 Modulare Exponentiation Als letzte Rechenoperation betrachte ich die Exponentiation zweier Langzahlen a und b modulo einer Zahl n, also die Berechnung von ab (mod n). Dies wird auch als modulare Exponentiation bezeichnet. Diese Operation wird für die Implementierung des RSA-Verfahrens benötigt, ich betrachte nur den hierfür benötigten Fall des öffentlich bekannten Modulus. Der Exponent sei ausserdem in Binärdarstellung gegeben, also als geheime Langzahl zur Basis 2. Ein effizientes Verfahren zur Berechnung ist der Square and Multiply Algorithmus. Dieser bietet sich besonders an, da er einfach auf einem arithmetischen Schaltkreis zu implementieren ist. Ich gebe ihn in Algorithmus 7 an (siehe auch [Cor01], Kapitel 31.6). Das zugrunde liegende Verfahren lässt sich leicht veranschaulichen. Es sei der Exponent b in Binärdarstellung gegeben, also b = Σki=0 bi ∗ 2i . Es gilt nun ab k = ab0 +2b1 +...2 = = a1·b0 · a2·b1 · . . . · a2 ·bk ab0 (ab1 (. . . (abn−1 (abn )2 )2 . . . )2 )2 bk k (5) Der Algorithmus berechnet nun den Ausdruck (5) von innen nach aussen, indem in jeder Iteration quadriert wird und je nachdem, ob bi eins oder null ist, mit a multipliziert wird. Dieser Algorithmus soll nun auf dem arithmetischen Schaltkreis implementiert werden. Die Basis a der Exponentiation ist entweder öffentlich oder geheim, der Exponent b ist immer geheim und damit auch die Variable d, in der am Ende des Algorithmus das Ergebnis steht. Damit sind auch sämtliche Zwischenergebnisse geheim. Die Zahlen a, b und n sind groß, müssen also praktisch durch Langzahlen dargestellt werden. Für eine Langzahl x, gebe lB (x) die Stelligkeit von x zur Basis B an. Die Länge l2 (n) wird vorgegeben3 3 Die Zahl n entspricht in RSA der Schlüssellänge und ist ein fest gewählter Wert. Algorithmus 7 : modulare Exponentiation Eingabe : a, b, n Ausgabe : ab mod n 1 d ← 1; 2 Sei (bk , bk−1 , ..., b0 ) die Binärdarstellung von b; 3 für i ← k bis 0 tue 4 d ← (d · d) mod n; 5 wenn bi = 1 dann 6 d ← (d · a) mod n; 7 return d; 28 und es muss B lB (n) ≥ 2l2 (n) gelten, um alle Zahlen darstellen zu können. Damit berechnet sich die Stelligkeit der Langzahlen zur Basis B durch m l (n) · ln 2 l 2 l2 (n) . = lB (n) = logB 2 ln B Der Exponent b liegt in verteilter binärer Form vor, wobei (bk−1 bk−2 ...b0 ) die Binärdarstellung von b sei. Das heisst jedes Bit bi von b wird als verteilter Wert gespeichert. Die bedingte Verzweigung in Zeile 5 und 6 kann damit durch d = bi ((d · a) mod n) + (1 − bi )d dargestellt werden. Dieser Ausdruck kann durch Ausklammern von d noch vereinfacht werden, dadurch kann eine Multiplikation für die Verzweigung gespart werden: d = d(bi a + (1 − bi )) mod n Da bi ein boolescher Wert ist, also bi ∈ {0, 1} gilt, kann das Produkt bi a einfacher als eine reguläre Langzahlmultiplikation berechnet werden. Bei einer Multiplikation mit 0 oder 1 können keine Überträge auftreten und es sind somit nur lB (n) geheime Multiplikationen für die Berechnung des Ergebnisses nötig. In Abschnitt 5.2.5 ist diese Vereinfachung im Rahmen der Verzweigungen mit Langzahlen detaillierter dargestellt. Die Addition erfordert eine laddn Operation. Da einer der Summanden immer gleich null ist, kann sich die Stellenzahl durch die Addition nicht erhöhen. Damit hat das Ergebnis der Addition immer die Stelligkeit von a, da während der Berechnung nicht klar ist, welcher Summand gleich null ist. Für d gilt lB (d) ≤ lB (n), für die Aufwandsbestimmung nehme ich lB (d) = lB (n) an, dies gilt für fast alle Iterationen. Die Größe von a in Bit ist l2 (a) und es gilt l2 (a) ≤ l2 (n). Mit den in Abschnitt 5 eingeführten Langzahlfunktionen ergibt sich für die modulare Exponentiation ein Aufwand von M(modexp) = k M(lmullB (n),lB (n) ) + M(ldivlB (n),lB (n) ) + lb (a) + M(laddlB (a) ) + M(lmullB (n),lB (a) ) + M(ldivlB (a),lB (n) ) . Falls a öffentlich ist, kann die lmul1 Operation verwendet werden, ansonsten muss die lmul2 Operation verwendet werden. Auf die Division hat dies keine Auswirkung, da der Modulus in unserem Fall immer öffentlich ist. 5.3 Binärer Fall Wählt man als Basis B = 2, gelten die ausgewerteten Komplexitäten in Tabelle 2 nicht mehr, da die Ergebnisse die Ergebnisse der Addition und Multiplikation zweier einstelliger Zahlen einschliesslich möglicher Überträge im Intervall [0, 3] liegen. Eine auf einen kleineren Wertebereich eingeschränkte Division entfällt und es gilt damit M(div1) = M(rediv1) = 2 Im F2 lässt sich zudem die Division vereinfachen. Da jede Quotientenstelle entweder eins oder null ist, muss nicht aufwendig berechnet werden, wie oft der Divisor in den momentanen Rest der Division passt. Man kann einfach jede 29 Algorithmus 8 : bldiv Eingabe : u = (um+n−1 ...u0 )2 , v = (vn−1 ...v0 )2 Ausgabe : q = (qm ...q0 )2 , r = (rn−1 ...r0 )2 mit u = v · q + r 1 c ← 0; 2 für i ← m bis 0 tue 3 wenn c = 0 dann 4 (c ui+n−1 . . . ui ) ← (ui+n−1 . . . ui ) − (vn−1 . . . v0 ); 5 sonst 6 (c ui+n−1 . . . ui ) ← (ui+n−1 . . . ui ) + (vn−1 . . . v0 ); 7 8 9 10 11 qi ← 1 − c; wenn c = 0 dann (rn−1 . . . r0 ) ← (un−1 . . . u0 ); sonst (rn−1 . . . r0 ) ← (un−1 . . . u0 ) + (vn−1 . . . v0 ); Quotientenstelle mit eins annehmen und falls nach dem multiplizieren und subtrahieren das Ergebnis negativ ist, kann der Schritt rückgängig gemacht werden und die nächste Stelle des Dividenten mit betrachtet werden. Algorithmus 8 stellt das Verfahren dar. Da die Variable l aus {0, 1} ist, können die Bedingungen in Zeile 2 und 7 durch Berechnung von 1 − l lokal ausgewertet werde. Es ergibt sich ein Aufwand von M(bldiv1m,n ) = 8mn + 13n . 5.4 Aufwand der Operationen Tabelle 2 gibt eine Übersicht über die einzelnen Operationen und ihrem Multiplikationsaufwand, basierend auf der vorgestellten Langzahlarithmetik zur Basis B. Der Aufwand aller Operationen ist nicht von der Körpergröße abhängig, das heisst die Anzahl der Multiplikationen bleibt gleich. Allerdings erhöht sich das kommunizierte Datenvolumen, da bei einem größeren Körper die Elemente des Körpers in größeren Datenpaketen gespeichert und verschickt werden müssen. 6 RSA Eine mögliche Anwendung einer Agentenallianz wäre die geheime Berechnung einer Signatur. Eine digitale Signatur ersetzt eine konventionelle Unterschrift. Mit ihrer Hilfe kann die Herkunft einer Nachricht oder eines Dokuments eindeutig verifiziert werden. Eine Agentenallianz könnte damit beispielsweise einen Kaufvertrag unterschreiben. Aufgrund der Verbreitung von RSA, soll der Aufwand einer RSA-Signatur auf einem arithmetischen Schaltkreis untersucht werden. Für eine Einführung in RSA empfehle ich [Sch96] oder [Cor01], ich gebe hier nur eine Zusammenfassung des Verfahrens. Ich gehe kurz auf die Verschlüsselung von Daten mittels RSA ein und darauf aufbauend auf die Verwendung von RSA zur Erstellung digitaler Signaturen. RSA ist ein public key Kryptoverfahren. Das heißt, ein Schlüssel besteht aus einem Paar, dem öffentlichen Schlüssel (P, n) und dem privaten Schlüssel (S, n). Der öffentliche Schlüssel wird öffentlich zugänglich 30 Funktion logische negation logisch oder, und if ifA1 ,A2 div1, mod1 rediv1, remod1 divmod1 redivmod1 add mul1 mul2 cmp ∈ {<, >, ≤, ≥, =, 6=} lcmpn lifn laddn lsubn lmul1m,n lmul2m,n shdiv1n ldiv1m,n Operationen 0 1 2 M(A1 ) + M(A2 ) + 2 Multiplikationen 0 1 2 B2 − 2 2B − 2 div1 B2 − 2 rediv1 2B − 2 redivmod1 2B − 2 divmod1 B2 − 2 divmod1 + 1 B2 − 1 2B − 2 2n(cmp + 1) 4Bn − 2n laddn + 2n 2Bn n · redivmod1 2Bn − 2n n · redivmod1 2Bn − 2n mn · divmod1 B 2 mn − 2mn mn · divmod1 + mn B 2 mn − mn ndivmod1 B 2 n − 2n 2 2 mnB + 3nB + 7mB 2 + 6B 2 + 6mnB + 6nB + 26mB + 26B − 6mn − 10n − 20m − 18 Tabelle 2: Multiplikationsaufwand der einzelnen Langzahloperationen gemacht, der private Schlüssel wird vom Besitzer geheim gehalten. Die Schlüssel definieren Funktionen, die auf eine Nachricht m angewendet werden können. Die Funktionen seien mit P () und S() bezeichnet. Die Funktionen sind zueinander invers, das heißt, es gilt m m = S(P (m)) = P (S(m)) . Ich stelle die Kommunikation anhand der zwei üblichen Parteien Alice und Bob dar. Habe nun Alice das Schlüsselpaar (SA , PA ) und Bob das Paar (SB , PB ). Will nun Bob eine Nachricht m an Alice verschicken, dann verschlüsselt er diese mit Alices öffentlichem Schlüssel und erhält damit das Chiffrat c = PA (m). und sendet c an Alice. Alice kann nun mit ihrem privaten Schlüssel die Originalnachricht durch m = SA (c) berechnen. Eine digitale Signatur kann ebenfalls mithilfe des Schlüsselpaares berechnet werden. Will Alice zum Beispiel Bob eine signierte Nachricht m′ schicken, dann berechnet sie einen Hash-Wert H(m′ ) der Nachricht. Dadurch wird die Nachricht auf eine durch die Hash-Funktion festgelegte Länge gekürzt. Dann berechnet sie die Signatur s = SA (H(m′ )) und schickt diese mitsamt der Nachricht an Bob. Bob kann nun überprüfen, ob die Nachricht von Alice kommt, indem er die Gleichung H(m′ ) = PA (s) prüft. Für RSA werden die Schlüssel nun nach dem folgenden Verfahren berechnet. 1. Man wählt zwei große Primzahlen p und q mit p 6= q. Groß bedeutet in 31 diesem Fall beispielsweise 1024 Bit. Die Sicherheit des Verfahrens hängt von der hier gewählten Größe ab. 2. Berechne n = p · q, dieser Wert wird als RSA-Modulus bezeichnet. 3. Wähle eine kleine, ungerade ganze Zahl e, die teilerfremd zu φ(n) ist. φ ist die Eulersche Phi-Funktion und es gilt φ(n) = (p − 1)(q − 1). 4. Berechne d als das multiplikitativ Inverse zu e modulo φ(n), d existiert und ist eindeutig definiert. 5. Der öffentliche Schlüssel ist P = (e, n). 6. Der private Schlüssel ist S = (d, n). Die durch die Schlüssel definierten Funktionen sind nun P (x) = xe mod n und S(x) = xd mod n, wobei der Definitionsbereich beider Funktionen [0, n − 1] ist. Die Nachricht muss also kleiner als der Modulus sein. Die Sicherheit des Verfahrens beruht auf der Schwierigkeit, große Zahlen in ihre Primfaktoren zu zerlegen. Die Größe von n ist ein Maß für die Sicherheit der RSA Verschlüsselung. Üblich sind hier Größen von 1024 bis 4096 Bit. In unserem Szenario wird der geheime Schlüssel unter den Agenten verteilt geheim gespeichert. Um nun eine digitale Signatur einer Nachricht m zu berechnen, wird der Hash-Wert H(m) der Nachricht berechnet und dieser danach mit dem geheimen Schlüssel verschlüsselt. Auf die Berechnung des Hashwertes gehe ich hier nicht ein. Es muss also H(m)d mod n berechnet werden. Der geheim Schlüssel soll während der Berechnung natürlich stehts geheim bleiben. Der Kommunikationsaufwand ergibt sich also direkt über den Aufwand der modularen Exponentiation (siehe Kapitel 5.2.7). Tabelle 3 gibt den Kommunikationsaufwand für verchiedene RSA-Moduli und verschiedene Basen der Langzahlen an. Dabei muss beachtet werden, dass die Nachricht kleienr sein muss, als der Modulus. In der Tabelle sind beide Werte nur in Bitlängen angegeben. Dies entspricht letztlich der Betrachtung des worst case, nämlich dass Nachricht und Modulus die gleiche Länge in Bit haben. Den optimalen Aufwand bekommt man für die Wahl kleiner Basen. Man sieht deutlich, dass das Verfahren bei diesen kommunizierten Datenmengen nicht praktisch einsetzbar ist. Auch die Optimierung für die Basis B = 2 bringen keinen nennenswerten Vorteil. Allerdings erhält man für die Basis B = 2 noch das beste Ergebnis. Die Angabe der Größe der Datenmengen bezieht sich nur auf die Datenmenge, die ein Agent mit einem anderen austauscht. Für die Bestimmung der tatsächlichen Größe muss der angegebene Wert noch mit der Anzahl der Agenten zum Quadrat multipliziert werden. Für alle aufgeführten Basen wird angenommen, dass ein Byte pro Feldelement kommuniziert wird. In einem realen Szenario käme noch der Kommunikationsoverhead hinzu. 6.1 Arithmetischer Schaltkreis über dem Ring Zpq Betrachtet man den RSA Algorithmus bietet sich die Möglichkeit an, im Ring Zn = Zpq zu rechnen. Auf diese Weise wäre die Rechnung modulo n gewissermassen umsonst, also ohne weiteren Aufwand, gegeben. Eine verteilte Langzahlarithmetik würde ebenfalls entfallen. Die verteilten Werte wären natürlich immer noch so groß, dass sie als Langzahlen dargestellt werden müssten, aber 32 Modulus Nachricht Basis 1024 1024 3 1024 1024 4 1024 1024 5 1024 1024 6 1024 1024 128 1024 1024 256 2048 2048 3 2048 2048 4 Optimierung für B = 2 1024 1024 2 2048 2048 2 Multiplikationen 12, 3 · 109 13.2 · 109 14, 7 · 109 16, 4 · 109 767, 3 · 109 2312, 1 · 109 98, 0 · 109 104, 7 · 109 Kommunikation 23, 0n2GB 24, 5n2GB 27, 3n2GB 30, 6n2GB 1429, 2n2GB 4306, 6n2GB 182, 5n2GB 195, 0n2GB 11, 3 · 109 90, 3 · 109 21, 0n2GB 168, 2n2GB Tabelle 3: RSA-Signatur mit Langzahlarithmetik: Multiplikationen und übertragene Datenmengen, n bezeichnet die Anzahl der Agenten. Für die Datenmengen wird angenommen, dass für jede, der in der Tabelle aufgeführten Basen, ein Byte pro Feldelement kommuniziert wird. Es wird der worst case betrachtet, indem Modulus und Nachricht die gleiche Länge in Bit haben. Zu beachten ist, dass der Modulus trotzdem immer größer als die Nachricht sein muss. die entsprechenden Langzahloperationen könnten lokal ohne Kommunikation durchgeführt werden. Zu beachten ist, dass im Ring Zpq Nullteiler existieren, es gibt also Elemente, die kein multiplikativ Inverses haben, durch die also nicht dividiert werden kann. In Abschnitt 2.3 wurde erwähnt, dass für jedes Multiplikationsgatter ein Tripel von Zahlen erzeugt wird, unter dessen Verwendung die Multiplikation dann durchgeführt werden kann. Inverse Elemente werden im Protokoll von Hirt Maurer bei dieser Tripelerzeugung und bei der Rekonstruktion von Geheimnissen benötigt. Für die Tripelerzeugung müssen Lagrangepolynome an der Stelle 0 ausgewertet werden. Genauer müssen die Polynome wi = n Y j=1 j6=i αj αj − αi für i = 1, ..n (6) berechnet werden. Die Differenzen der αi müssen demnach invertierbar sein, es muss also (αi − αj ) ∈ Z∗pq mit i, j = 1, ..., n , i 6= j gelten. Allerdings können die αi von Anfang an so gewählt werden, dass obige Bedingung erfüllt ist, da es sich um öffentliche einem Agenten von Anfang an fest zugewiesene Werte handelt. Die Agenten können entsprechend auch schon die Inversen der Differenzen mitgeliefert bekommen. Bei der Rekonstruktion von Geheimnissen muss nach Gleichung 2 auf Seite 6 ein lineares Gleichungssystem der Größe 3t + 1 gelöst werden. Hierfür müssen ebenfalls Inverse berechnet werden. Die Rekonstruktion von Geheimnissen ist bei jeder geheimen Multiplikation notwendig. Solange nicht versucht wird von einem Nullteiler das Inverse zu berechnen, kann man in Zpq rechnen, wie in einem Körper und das Protokoll funktioniert 33 wie bisher. Ist ein zu invertierendes Element allerdings ein Nullteiler bricht das Protokoll mit einem Fehler ab und das Programm der Agenteallianz oder zumindest ein Teil davon kann nicht weiter ausgeführt werden. Es stellt sich die Frage, mit welcher Wahrscheinlichkeit dieser Fehler, also das Auftreten eines Nullteilers in Zpq auftritt. Die Größe der Enheitengruppe ist |Z∗pq | = (p − 1)(q − 1) und damit gibt es pq − (p − 1)(q − 1) = p + q − 1 Nullteiler. Diese sind gerade {0, p, 2p, . . . , (q − 1)p, q, 2q, . . . , (p − 1)q} . Ich nehme an, dass alle Zahlen aus Zpq mit gleicher √ Wahrscheinlichkeit in dem Gleichungssystem auftreten und nähere p und q mit n an. Dies wird natürlich nie exakt zutreffen, ist aber für die weitere Betrachtung eine sinnvolle Näherung. Die Wahrscheinlichkeit, einen Nullteiler in Zpq mit einem Versuch zu finden, ist damit 1 1 1 p+q−1 = + − P (x 6∈ Z∗pq ) = pq q p pq Ich nehme an, dass p ≈ n/2 und q ≈ n/2. Damit gilt ungefähr 2 P (x 6∈ Z∗pq ) ≈ √ . n Die Möglichkeit, dass während des Protokolldurchlaufs ein Nullteiler zu invertieren ist, kann also vernachlässigt werden. Zur Berechnung des Chiffrats wird wieder Algorithmus 7 (modulare Exponentiation) benutzt. Der Kommunikationsaufwand verringert sich erheblich, da die Modulo-Rechnung natürlich entfällt. Die Nachricht a nehme ich wieder als öffentlich an. Damit müssen pro Schleifendurchgang zwei Multiplikationen von geheimen Zahlen, einmal die Quadrierung und einmal die Verzweigung, die durch Ausklammern von d durch eine Multiplikation berechenbar ist. Die entsprechenden arithmetischen Ausdrücke für die Anweisungen innerhalb der Schleife lauten dann d d ← d·d ← d(bi a + (1 − bi )) Der Multiplikationsaufwand beträgt damit bei k Iterationen M(modexpZpq) = 2k . Man erinnere sich, dass für jedes Bit des Schlüssels ein Schleifendurchlauf stattfindet, k ist also die Schlüssellänge in Bit. Bei einer Schlüssellänge von 1024 bit müssen also 2048 verteilte Multiplikationen berechnet werden. Die einzelnen Feldelemente haben ebenfalls eine Länge von 1024 bit (= 128 byte). Dies gibt ein Datenvolumen von insgesamt 2048 · 128 · n2 = 262144 · n2 Byte = 0, 25 · n2 M Byte Das ergibt bei 10 Agenten ein kommuniziertes Datenvolumen von 25MB. Dies stellt eine wesentliche Verbesserung gegenüber dem vorgestellten, auf Langzahlarithmetik basierenden Verfahren dar. Tabelle 4 gibt die benötigten Zeiten für eine Signatur für heute übliche Internetzugänge an. 34 Typ Nutzer Downstream/s Upstream/s s/Signatur T1 prof. 1 GBit 1 GBit 0.0021 ADSL privat 16 MBit 1 MBit 2.1 SDSL geschätl. 2 MBit 2 MBit 1.04 Kabel geschäftl. 20 MBit 10 MBit 0.21 Kabel privat 6 MBit 600 KBit 3.5 Tabelle 4: Benötigte Zeit für eine Signatur 7 AES Als Beispiel einer symetrischen Chiffre soll der verbreitete AES4 auf einem arithmetischen Schaltkreis umgesetzt werden. Ich werde nur einen kurzen Überblick über den Algorithmus geben, für eine detaillierte Beschreibung des Verfahrens siehe [DR99] oder [Bra02], Kapitel 3.2.2.1.2. AES ist ein iteratives Blockchiffre. Der Eingabedatenblock wird dabei in jeder Iteration den gleichen Transformationen unterzogen und mit dem Schlüssel verknüpft. Das Verfahren kann mit unterschiedlichen Block- und Schlüssellängen umgehen, ich beschränke mich hier auf den Fall einer Block- und Schlüssellänge von 256 Bit. Dies ist jeweils der maximal mögliche Wert. Für diesen Fall werden 14 Iterationen durchgeführt. AES arbeitet über dem Körper GF (28 ), ein Element des Körpers kann also durch ein Byte repräsentiert werden. Ein Datenblock wird in vierdimensionale Spaltenvektoren aufgeteilt, wobei jeder Eintrag einem Byte entspricht. Die Spaltenvekoren werden in einer Matrix A mit 8 Spalten angeordnet: a00 a01 .. a07 a10 a11 .. a17 A := (7) a20 a21 .. a27 a30 a31 .. a37 Diese Matrix wird nun für jede Iteration in vier Schritten transformiert. Es wird nacheinander eine Bitmustertransformatione, eine Spaltentransformation und eine Zeilentransformation durchgeführt. Anschliessend wird noch der Schlüssel addiert. Bitmustertransformation: Jeder Eintrag der Matrix wird einzeln transformiert. Zuerst wird jedes Byte durch sein multiplikativ Inverses ersetzt. bij = a−1 ij (8) Dann wird eine lineare Transformation (über GF (2)) der Bits durchgeführt: 1 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 b0 c0 1 1 1 0 0 0 1 1 0 b1 c 1 0 1 1 1 1 0 0 0 1 · . + (9) .. = . . 1 1 1 1 1 0 0 0 . 0 0 1 1 1 1 1 0 0 1 b7 c7 0 0 1 1 1 1 1 0 1 0 0 0 1 1 1 1 1 0 4 engl. Advanced Encryption Standard 35 Diese zwei Transformationen können in einer Substitutionstabelle5 mit 256 Einträgen zusammengefasst werden. Die Gesamttransformation wird mit TB : GF (28 ) → GF (28 ) bezeichnet. Zeilentransformation: Die drei unteren Zeilen der Matrix werden zyklisch nach links verschoben. Die zweite Zeile wird um 1, die dritte um 3 und die vierte um 4 Positionen verschoben. Spaltentransformation: Jeder Spaltenvektor wird über eine Matrixmultiplikation abgebildet: a0 b0 2 3 1 1 b 1 1 2 3 1 a1 = (10) b 2 1 1 2 3 · a2 a3 b3 3 1 1 2 Schlüsseladdition: Zuletzt wird der Schlüssel addiert. Dieser wird hierzu wie auch der Datenblock als Matrix aufgefasst und die Matrizen werden addiert. Allerdings wird nicht der Originalschlüssel addiert. Der Originalschlüssel wird zu Anfang auf eine Länge von 256 ∗ (14 + 1) Bits expandiert und anschliessend in Blöcke von 256 Bit aufgespalten. Dies sind nun die Schlüssel für die einzelnen Iterationen. Da eine initiale Schlüsseladdition stattfindet wird ein Schlüssel mehr benötigt, als Iterationen stattfinden. Die Schlüsselexpansion ist in Algorithmus 9 dargestellt. Dabei gibt nk die Anzahl der Spaltenvektoren des Schlüssels, nb die Anzahl der Spaltenvektoren eines Datenblockes und nr die Anzahl der Iterationen an. Es gilt in unserem Fall nk = nb = 8 und nr = 14. Die Funktion c(x) gibt eine Konstante zurück, deren Berechnung hier für unsere Zwecke nicht interessant ist, da sie keinerlei geheime Multiplikationen erfordert. Die Transformation TR permutiert einen Spaltenvektor in der Form (a, b, c, d) → (b, c, d, a). Algorithmus 9 : SchlüsselExpansion Eingabe : Key[nk ] (Schlüssel als Feld von Spaltenvektoren) Ausgabe : ExKey[nb (nr + 1)] (Spaltenvektoren des expandierten Schlüssels) für i ← 0 bis nk − 1 tue ExKey[i] ← Key[i]; für i ← nk bis nb (nr + 1) − 1 tue temp ← ExKey[i − 1]; wenn i mod nk = 0 dann temp ← TB (TR (temp) + c(i/nk ); sonst wenn i mod nk = 4 dann temp ← TB (temp); ExKey[i] = ExKey[i − nk ] + temp; Um AES auf dem arithmetischen Schaltkreis zu implementieren, liegen zwei Möglichkeiten nahe. Zum einen kann man den Körper GF (28 ) als Grundkörper des Schaltkreises nehmen oder man wählt den GF (2) und rechnet auf Bitebene. Ich untersuche den Aufwand beider Möglichkeiten 5 auch S-Box genannt 36 Der arithmetische Schaltkreis kann über beliebigen Körpern aufgebaut werden, die Wahl des GF (28 ) bringt keinerlei Einschränkungen mit sich. Allerdings kann die Bittransformation nicht auf den Shares berechnet werden, da die einzelnen Bits nicht zugänglich sind. Die Berechnung des multiplikativ Inversen ist ebenfalls nicht durchführbar. Die komplette Transformation muss aus diesem Grund interpoliert werden und benötigt damit 254 Multiplikationen (da 256 mögliche Eingabewerte) für jedes der 32 Byte. Die Zeilentransformation benötigt keine Multiplikationen, da es sich um ein einfaches Verschieben von Körperelementen handelt. Die Spaltentransformation benötigt pro Spaltenvektor 16 Multiplikationen, also 4 pro Byte. Bei der Schlüsselexpansion ist die Bittransformation TB die einzige Operation, die Multiplikationen erfordert. Die Permutation TR , die Berechung der Bedingungen für die Verzweigungen und die Berechnung der Funktion c(x) können lokal durchgeführt werden. Es bleibt also nur noch zu bestimmen, wie oft die Bittransformation TB ausgeführt wird. Die Schleife wird insgesamt 112 mal durchlaufen. Damit wird jede Bedingung in der Verzweigung genau 112/8 = 14 mal wahr, was auf insgesamt 28 Bittransformationen führt. Damit ergibt sich ein Gesamtmultiplikationsaufwand von 14(32 · 254 + 4 · 32) + 28 · 254 = 122696 und einem kommunizierten Datenvolumen von 245392 · n2 Byte. Im Fall von 10 Agenten ergibt das entsprechend 2, 45MB pro Agent und 24, 5MB im Gesamten. Das Rechnen im GF (2) bringt keine Vorteile, da die Berechnung des Inversen ebenfalls interpoliert werden muss und sich ansonsten der Aufwand der Operationen erhöht und nicht verringert. Man könnte zwar die Matrixmultiplikation in Gleichung 9 berechnen, hat dadurch aber keinen Vorteil, da man sich die Interpolation in diesem Schritt nicht sparen kann. 8 Abschlussdiskussion Da ich nur beispielhaft an einzelnen Algorithmen die Realisierbarkeit für Agentenallianzen geprüft habe, ist es nicht möglich, allgemeine Aussagen zu treffen. Allerdings zeigt die Umsetzung des Standart RSA Verfahrens eindeutig die Grenzen der Allianzen. Der Kommunikationsaufwand ist sicher noch für einige Jahre zu hoch, um ein solches Programm auf einer Allianz praktisch auszuführen. Daraus kann man schließen, dass auch andere an sich effizient berechenbare Algorithmen, nach einer Transformation auf eine Agentenallianz nicht mehr praktisch berechenbar sind. Anderseits sieht man an AES und der Implementierung von RSA über einem Ring, dass in Spezialfällen ein Algorithmus durchaus effizient implementiert werden kann. Grundlage ist in beiden Fällen eine geschickte Wahl des Körpers oder eben des Rings im Falle von RSA. Offen wäre hier noch das Problem, ob und wie man einzelne geheime Werte von der Darstellung in einem Körper in die Darstellung in einem anderen Körper transformiert. Diese Notwendigkeit entsteht möglicherweise, wenn man einzelne Algorithmen aus Effizienzgründen über speziellen Körpern implementiert. 37 Letztlich wäre es schön ein allgemeines Verfahren zur Hand zu haben, mit dem beliebige Programme möglichst effizient auf arithmetische Schaltkreise zur Berechnung durch Agentenallianzen transformiert werden können. Der in dieser Arbeit verfolgte Ansatz, Kontrollstrukturen eins zu eins umzusetzen mag zwar anschaulich, aber nicht unbedingt effizient sein. Aus meiner Sicht, wird man momentan nur sehr kleine und geeignete Programmteile von den Agenten verteilt berechnen lassen. Dies wären dann die besonders sicherheitsrelevanten Funktionen. Trotz verbleibender Probleme beim Kommunikationsaufwand ist der Ansatz der Agentenallianzen nicht uninteressant, da es der einzige existierende Ansatz ist, Sicherheit und Robustheit für mobile Softwareagenten zu garantieren. 38 Literatur [ACCK01] Joy Algesheimer, Christian Cachin, Jan Camenisch, and Günter Karjoth. Cryptographic security for mobile code. In IEEE Symposium on Security and Privacy, pages 2–11, 2001. [Bra02] Gilbert Brands. Verschlüsselungsalgorithmen. Vieweg, 1. aufl. edition, 2002. [BW86] E. R. Berlekamp and L. Welch. Error correction of algebraic block codes. US Patent Number 4,633470, 1986. [Cor01] Thomas H. Cormen. Introduction to algorithms. MIT Press, 2. ed. edition, 2001. [DR99] J. Daemen and V. Rijmen. Aes proposal: Rijndael, 1999. http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf. [EM03] Regine Endsuleit and Thilo Mie. Secure multi-agent computations. In Hamid R. Arabnia and Youngsong Mun, editors, Security and Management, pages 149–155. CSREA Press, 2003. [GRR98] Rosario Gennaro, Michael O. Rabin, and Tal Rabin. Simplified vss and fact-track multiparty computations with applications to threshold cryptography. In PODC, pages 101–111, 1998. [HH94] Günther Hämmerlin and Karl-Heinz Hoffmann. Numerische Mathematik. Springer, 4., nochmals durchges. aufl. edition, 1994. [HM01] Martin Hirt and Ueli M. Maurer. Robustness for free in unconditional multi-party computation. In Joe Kilian, editor, CRYPTO, volume 2139 of Lecture Notes in Computer Science, pages 101–118. Springer, 2001. [Knu98] Donald E. Knuth. The art of computer programming, volume 2. Addison-Wesley, 3. ed. edition, 1998. [Sch96] Bruce Schneier. Applied cryptography. Wiley, 2. ed. edition, 1996. [Sha79] Adi Shamir. How to share a secret. Commun. ACM, 22(11):612–613, 1979. [Wel98] Michael Welschenbach. Kryptographie in C und C++. Springer, 1998. 39