Vous êtes sur la page 1sur 69

Desciframiento RSA desde un punto de vista

Mecánico Cuántico aplicado en Grid

Miguel David Alba Charry

Tesis preparada en requerimiento para el


grado de Ingeniero de Sistemas

Director
Yezid Enrique Donoso Meisel, Ph.D.

Universidad de los Andes


Departmento de Ingenierı́a de Sistemas y computación
Bogotá D.C.
Diciembre 2009
Agradecimientos.
A mi familia, amigos, a todas las personas especiales que estuvieron
a mi lado durante la elaboración de este trabajo, y a Marcela.

i
Prólogo

En este trabajo de tesis se detalla el modelaje, implementación y estudio de una posible forma
de descifrar RSA en un computador clásico basados en la Mecánica Cuántica. El fin es determinar
las vulnerabilidades inherentes al sistema de encripción de llaves públicas RSA, y ası́ poder dis-
cernir sobre su efectividad. El modelaje del algoritmo es hecho sobre la noción del potencial de la
Grid del departamento usando Globus Alliance y Condor Project, que permiten el uso de múltiples
procesadores con el fin de llegar a la solución en el menor tiempo. Se comparan los resultados del
algoritmo propuesto contra el mejor algoritmo existente para factorizar un número, y se discuten
las discrepancias las cuales incluyen la superioridad del mejor algoritmo clásico debido a la inefi-
ciencia de algunas operaciones que cuánticamente no se calculan explı́citamente como se hace en
el algoritmo adaptado a la computación clásica.

II
Índice general

Prólogo II

Introducción 1

1. RSA: el Problema de la Factorización y Computación Cuántica 3


1.1. RSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1. ¿Qué es? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2. Principios Teóricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.3. Funcionamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2. Computación Cuántica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1. El Qubit y El Algorı́tmo de Shor . . . . . . . . . . . . . . . . . . . . . . . 8

2. Diseño y Especificación 11
2.1. Definición del problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2. Especificaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3. Desarrollo del Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3.1. Fuentes de Información . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.2. Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3. Implementación 17
3.1. Descripción de la Implementación . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2. Implementación en C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2.1. MCD-C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2.2. Potenciación-C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.3. Exponenciación Modular-C++ . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.4. Orden-C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.5. Main-C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.3. Implementación con Librerı́a GMP . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.3.1. Orden-GMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.3.2. Main-GMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.4. Trabajos (jobs) en CONDOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4. Análisis y Validación 30
4.1. Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.1. Fase de Pruebas I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.2. Resultados y Análisis I . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.1.3. Fase de Pruebas II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.4. Resultados y Análisis Fase II . . . . . . . . . . . . . . . . . . . . . . . . . 32

III
Comentarios Finales 36

Anexos 38
5.1. Gráficas de Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

Bibliografia 61

IV
Indice de Códigos

1. MCD Binario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2. Exponenciación Binaria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3. Exponenciación Modular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4. Orden de f (x) = ax (mód b) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5. Factorizar en primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6. Orden de f (x) = ax (mód b) usando GMP . . . . . . . . . . . . . . . . . . . . . 25
7. Factorizar en primos con GMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
8. Trabajos en CONDOR (moo.condor) . . . . . . . . . . . . . . . . . . . . . . . . . 28

V
Índice de figuras

4.1. Tiempo para Factorizar N=88637 . . . . . . . . . . . . . . . . . . . . . . . . . . . 32


4.2. Tiempo para Factorizar N=88544111 . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.3. Tiempo para Factorizar N=224929877 . . . . . . . . . . . . . . . . . . . . . . . . 34
4.4. Tiempo para Factorizar N=1176621989 . . . . . . . . . . . . . . . . . . . . . . . 35
5.5. Tiempo para Factorizar 17897 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.6. Tiempo para Factorizar 40753 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.7. Tiempo para Factorizar 52907 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.8. Tiempo para Factorizar 88637 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.9. Tiempo para Factorizar 95129 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.10. Tiempo para Factorizar 97183 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.11. Tiempo para Factorizar 112451 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.12. Tiempo para Factorizar 126629 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.13. Tiempo para Factorizar 223733 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.14. Tiempo para Factorizar 333967 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.15. Tiempo para Factorizar 3080681 . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.16. Tiempo para Factorizar 6980653 . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.17. Tiempo para Factorizar 19783333 . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.18. Tiempo para Factorizar 31363807 . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.19. Tiempo para Factorizar 42446629 . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.20. Tiempo para Factorizar 88544111 . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.21. Tiempo para Factorizar 109822469 . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.22. Tiempo para Factorizar 224929877 . . . . . . . . . . . . . . . . . . . . . . . . . . 57
5.23. Tiempo para Factorizar 631563797 . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.24. Tiempo para Factorizar 1176621989 . . . . . . . . . . . . . . . . . . . . . . . . . 59

VI
Índice de tablas

1.1. Relación entre la Computación y la Fı́sica. . . . . . . . . . . . . . . . . . . . . . . 7

4.1. Números a Factorizar en la Fase I . . . . . . . . . . . . . . . . . . . . . . . . . . 31


4.2. Numeros a Factorizar en la Fase II . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.3. Resultados para Factorizar 17897 . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.4. Resultados para Factorizar 40753 . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.5. Resultados para Factorizar 52907 . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.6. Resultados para Factorizar 88637 . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.7. Resultados para Factorizar 95129 . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.8. Resultados para Factorizar 97183 . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.9. Resultados para Factorizar 112451 . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.10. Resultados para Factorizar 126629 . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.11. Resultados para Factorizar 223733 . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.12. Resultados para Factorizar 333967 . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.13. Resultados para Factorizar 3080681 . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.14. Resultados para Factorizar 6980653 . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.15. Resultados para Factorizar 19783333 . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.16. Resultados para Factorizar 31363807 . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.17. Resultados para Factorizar 42446629 . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.18. Resultados para Factorizar 88544111 . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.19. Resultados para Factorizar 109822469 . . . . . . . . . . . . . . . . . . . . . . . . 56
5.20. Resultados para Factorizar 224929877 . . . . . . . . . . . . . . . . . . . . . . . . 57
5.21. Resultados para Factorizar 631563797 . . . . . . . . . . . . . . . . . . . . . . . . 58
5.22. Resultados para Factorizar 1176621989 . . . . . . . . . . . . . . . . . . . . . . . 59

VII
Introducción

La transmisión de información en forma segura tratando de mantener una alta confidencialidad


ha sido una constante preocupación para los hombres, todo esto como un resultado de problemas
de comunicación militar, territorial, ideológicos, polı́ticos, entre otros. De manera indiscutible e
incluso fundamental, “Debe ser que tan pronto como una cultura ha alcanzado un cierto nivel,
probablemente medido por su nivel de alfabetización, la criptografı́a aparece de forma espontánea
[...] Las múltiples necesidades y deseos de los humanos que demandan privacidad entre dos o más
personas en el medio de la vida social debe inevitablemente llevar hacia la criptologı́a allı́ en donde
los hombres prosperan y donde quieran escribir...” [1]. En otras palabras la privacidad es inherente
entre los humanos, y estamos dispuestos a mejorarla tanto como podamos con tal de mantener nue-
stros intereses asegurados.

Kahn muestra uno de los métodos que más ha sido usado por criptógrafos para cifrar men-
sajes; llamados sistemas de llame simétrica o pública -también conocidos como de llave secreta.
Un ejemplo de éste método es reemplazar cada sı́mbolo en un texto plano por una combinación
arbitraria de letras y otros sı́mbolos; pero, antes que el intercambio del criptograma suceda con la
estructura mencionada previamente, debe haber un intercambio -de manera no cifrada- de la in-
formación necesaria para descifrar el mensaje. No se puede estar seguro de que el intercambio de
información no ha sido interceptado.

Sin embargo, estas deficiencias son eliminadas por medio del sistema de llaves asimétricas o
públicas, de modo que usa dos llaves. Por ejemplo, en el evento que Alice y Bob quieran trans-
mitirse información, la llave usada por Bob para cifrar la información no es la misma que Al-
ice usará para descifrar el criptograma recibido. El sistema asimétrico (RSA) es uno de los más
comúnmente usados en la actualidad para cifrar información. El inmenso esfuerzo que un espı́a
debe realizar con la ayuda de un computador clásico y ası́ encontrar las llaves para luego descifrar
el mensaje mediante la descomposición en sus factores primos un numero supremamente grande es
la fuente del éxito de RSA, ya que no hay un computador que factorice un numero de 400 dı́gitos
en pocos años.

Usando Mecánica Cuántica mostraremos cómo RSA puede ser descifrado mediante el aprovechamien-
to de efectos cuánticos en gran escala compleja como el enredamiento e interferencia. Lo que quer-
emos lograr entonces, es estudiar cómo por medio de la Mecánica Cuántica podrı́amos resolver
el problema de la factorización y aplicar una posible implementación de un algoritmo cuántico
adaptado a la Computación Clásica usando una Grid. Resultando en un posible mejoramiento al
comparar sobre el mejor algoritmo actual para factorizar un número.

Durante la etapa de diseño estudiamos los puntos claves para hacer eficiente el algoritmo. La
implementación la hicimos sobre C-Unix por razones de desempeño, durante la segunda etapa de la

1
implementación usamos unas librerı́as que manejan números mucho más grandes de lo que C nativo
puede. Aunque no logramos una mejora respecto al mejor algoritmo resultó interesante notar cómo,
siguiendo el método cuántico, con ciertos números especiales obtenemos un desempeño bastante
similar al mejor algoritmo clásico. La construcción del proyecto se sigue de acuerdo a:

En el capı́tulo 1 se da una descripción general sobre el estado del arte en el tema de factor-
ización de números, ası́ como el funcionamiento de RSA. Además, una breve introducción a
la computación cuántica.

En el capı́tulo 2 se desarrolla el diseño del problema basados en el algorı́tmo cuántico.

En el capı́tulo 3 se muestra los detalles de la implementación desarrollada.

En el capı́tulo 4 se muestran los análisis del programa hecho ejecutandose dentro de la grid.

Se finaliza con unos comentarios finales, en donde se concluye y se dan direcciones futuras
sobre esta investigación y su extensión.

2
Capı́tulo 1

RSA: el Problema de la Factorización y


Computación Cuántica

Iniciamos el proyecto introduciendo el propósito del proyecto y el problema a resolver. Esto in-
cluye una descripción del sistema de encripción RSA, cómo funciona y el porqué de su efectividad
en contraste a los sistemas de encripción privados o de llaves simétricas. Además ilustraremos cómo
el potencial del algoritmo de encripción RSA puede ser fácilmente roto bajo regı́menes Mecánico
Cuánticos. Para esto, entonces mostraremos brevemente cómo se relaciona la Fı́sica con la Com-
putación lo cual, en principio, es poco notorio ya que usualmente se relaciona con las matemáticas.
Esto dará paso a explicar la teorı́a que está detrás de la computación cuántica y su enfoque a
la resolución del problema planteado. Además veremos cómo podrı́a enriquecerse el sistema de
encripción actual de tal modo que se vuelva a prueba de computadores cuánticos puede tornar in-
vestigación futura en el campo de la encripción.

Durante el estudio del sistema de encripción RSA se encuentran los principios necesarios para
que el sistema de encripción pueda funcionar apropiadamente, en esencia lo que se necesita en
teorı́a, es una Función de una sola dirección (o One-way Function, en Inglés) y una Función Trampa
(Trapdoor Function). Los conocimientos básicos que se necesitaran para entender el funcionamien-
to del sistema de encripción RSA no van más allá de aquellos aprendidos en un curso básico de
teorı́a de números; el fin es mostrar y describir los pasos que alguien debe seguir con el fin de
encriptar vı́a RSA ası́ como el proceso de des-encripción.

1.1. RSA
El proyecto va a estar dedicado a la des-encripción o el rompimiento del sistema RSA por
medio de técnicas distintas a la forma que se hace actualmente, las cuales van a ser detalladas más
adelante. El proyecto está enmarcado en un medio en el que la información es un bien, y como
tal representa valor para las personas u organizaciones que lo manejan. Estas entidades procuran
al máximo mantener una alta confidencialidad de la misma como ya lo mencionaba Kahn [1] y
estudiar los puntos de quiebre es de vital importancia ya que es allı́ en donde los maleantes van
a dirigir sus esfuerzos con tal de obtener información que no les corresponde. Muchos bancos
y/o entidades que manejen el dinero de otras personas, como tiendas en internet, subastas, entre
otros, usan el sistema de encripción mencionado, ya que ha demostrado ser de gran efectividad y
prácticamente imposible de romper.

3
1.1.1. ¿Qué es?
El algoritmo de encripción fue públicamente descrito en 1977 por Ronald Rivest, Adi Shamir,
y Leonard Adleman en el MIT. En su tiempo este fue el primer algoritmo -concreto- de encripción
de llave pública el cual es mejor que los sistemas de llave simétricos, los cuáles eran usados am-
pliamente en la antigüedad. 1 El sistema privado de encripción funciona mediante la sustitución de
sı́mbolos por sı́mbolos. Sin embargo, la información para descifrar el mensaje ya cifrado debe ser
transmitida o intercambiada entre los interesados en forma no cifrada; los interesados no pueden
estar seguros que la información no ha sido interceptada. Más aún clásicamente no podemos garan-
tizar la ausencia de un espı́a, ni cuantificar qué tanto obtuvo del mensaje.

Las deficiencias notadas en un sistema privado son eliminadas gracias al uso de llaves simétri-
cas, en el cual la llave que usa el interesado en cifrar la información no será la misma que usará el
remitente de la misma para descifrarla. RSA básicamente usa dos llaves, una pública y una privada;
la privada para descifrar y la pública para encriptar.

1.1.2. Principios Teóricos


Para un funcionamiento óptimo RSA usa el principio de Funciones en una dirección las cuáles
son fáciles de calcular, pero su operación inversa es difı́cil. Por ejemplo, sea f una función, la
descripción de f es conocida. Dado un x, serı́a trivial calcular f (x). Sin embargo, dado un y en
el rango de f , es difı́cil encontrar el x tal que f (x) = y. Suponga a manera de ejemplo que a y
b son número de 150 bits, resultarı́a fácil calcular c = a∗b, paro dado c es difı́cil de determinar a y b.

Las Funciones Trampa son Funciones en una dirección pero con una “trampa”, esto es infor-
mación adicional que puede desbloquear el problema inverso. En pocas palabras, una función es de
tipo trampa si:

1. Es una función en una dirección.

2. Para una llave pública y, f (x, y) es vista como una función fy (x) de x que mapea n bits
a m (n) bits. Luego existe un algoritmo eficiente que, al tener como entrada hy, fy (x) , zi
produce un x0 tal que fy (x0 ) = fy (x), para alguna trampa z.

Estamos, entonces, interesados en una función E (p, Le ) que transforme el texto plano p en
uno encriptado c el cual resultarı́a de poco sentido para un observador, luego dicha función es una
función en un sentido. Por ejemplo, si Alice y Bob quieren comunicarse de manera segura, Alice
puede usar esta función para encriptar su mensaje antes de enviárselo a Bob. Claramente, Bob
necesita de la función inversa de tal forma que pueda recuperar el mensaje original, la cual serı́a
una función secreta D (E (p, Le ) , Ld ) obteniendo p. Es por esto que necesitamos una función tipo
trampa. El sistema de encripción RSA usa una Función trampa en un sentido basada en la aritmética
modular.2
1
De hecho es bastante intuitivo el sistema, y tenemos conciencia que es seguro, pues es una transformación que
se aplica a la información que se quiere transmitir entre un par o un grupo de personas y todos conocen la forma de
descifrarlo.
2
Veamos que f (x) = g x (mód p) es una función en una dirección bastante efectiva, teniendo un g fijo y con
módulo p, siendo primo. Esta función es bastante difı́cil de invertir (ya que no se conocen trampas). Sin embargo,
f (x) = xe (mód N ) con e fijo y con módulo, en donde N es compuesto, es una función en una dirección, y con e y
N especı́ficos tiene una trampa!

4
1.1.3. Funcionamiento
Supongamos que entre Alice y Bob quieren transmitirse información de manera segura. En
este caso va a ser Bob el que le va a enviar información a Alice, por lo tanto Alice necesita crear
sus llaves, tanto pública como privada y ası́ usar el criptosistema RSA [2]; ella usa el siguiente
procedimiento:

1. Selecciona un par de números primos p y q grandes.

2. Calcula el producto N ≡ pq.

3. Selecciona un número aleatorio pequeño e impar, e, el cual es coprimo a ϕ (N ) = (p − 1) (q − 1).

4. Calcula d, que es el inverso multiplicativo de e, módulo ϕ (N ).3

5. La llave Pública RSA es el par P = (e, N ). La llave Secreta es el par S = (d, N ).

Ahora Bob cuenta con lo necesario para poderle mandar en forma segura su mensaje a Alice
usando como llave pública (e, N ). Suponemos que la longitud del mensaje de Bob es de blog (N )c
bits y que cualquier mensaje de longitud superior a esta cantidad, puede ser dividido en bloques de
blog (N )c y usar el mismo procedimiento. Para uno de estos bloques, Bob calcula:

E (M ) = E e (módN ) (1.1.1)

Ahora Bob tiene E (M ) que es el mensaje M cifrado, que ahora será enviado a Alice. Para que
Alice pueda descifrar el mensaje, debe usar en principio su llave Privada de des-encripción (d, N )
y elevar el mensaje a la d-ésima potencia:

D (E (M )) = E (M )e (módN ) (1.1.2)
De esta forma Alice recupera el mensaje y puede estar segura que, inclusive, si alguien tiene la
llave pública o supo cómo Bob pasó su mensaje original a números, un espı́a no podrı́a leer el men-
saje, ya que carecerı́a de coherencia dentro del lenguaje. Sin entrar en detalles vamos a suponer,
para que el sistema funcione, que siempre que D (E (M )) = M (módN ), en otras palabras, que
siempre que usemos la función de des-encripción, esta nos retornará el mensaje original.

Ejemplo
Con el fin de motivar la discusión daremos un ejemplo numérico. Supongamos que Bob quiere
mandarle un mensaje a Alice, M será 5678. Alice debe preparar lo necesario para que se transmita
por medio de RSA:

1. Supongamos que selecciona p = 109 y q = 127, por lo tanto N = 13843. 4

2. Calcula ϕ (N ) = ϕ (13843) = (109 − 1) (127 − 1) = 13608, y un e = 11 co-primo.

3. Ahora d = 12371, ed = 136081 = 1 (mód 13608).


3
Esto es un d que satisfaga ed = 1 (mód ϕ (N ))
4
El par de números primos elegidos al azar no son tan grandes. Sin embargo es a modo de ilustración y funciona
del mismo modo sin importar la longitud de los mismos.

5
4. La llave Pública es (11, 13843). La llave Secreta será entonces (12371, 13843)

Ahora que Bob tiene esta información puede mandarle el mensaje c ya encriptado a Alice
usando la llave pública (11, 13843) y la ecuación 1.1.1:

c = M e (módN )
c = (5678)11 (mód13843)
c = 8029

Bob ahora puede mandar de manera segura el mensaje a Alice y esperar a que ella lo lea. La
forma en que Alice recupera el mensaje original es mediante la ecuación 1.1.2, ası́:

M = cd (módN )
M = (8029)12371 (mód13843)
M = 5678

Como hemos visto el sistema es bastante sencillo de implementar. En el caso que Bob quiera
mandar un mensaje que contenga letras lo que él deberı́a hacer es simplemente hacer un cambio
a números de cada una de las letras y la publique, no importa que sea público o privado. Ya que
si por ejemplo cambia cada letra por un número entonces bajo alguna transformación HOLA cor-
responderı́a a 5678. Vimos que luego de la encripción, el número resultante es 8029, si un espı́a
se obtiene tal número y además la transformación que hizo Bob para transformar HOLA en 5678
entonces va a obtener, claramente, un mensaje totalmente distinto.5

Un espı́a al darse cuenta de la situación descrita previamente estarı́a seguro que de nada le sirve
tratar de descifrar el mensaje con lo que usa Bob para volver texto en números. Como el algoritmo
para generar las llaves es conocido, entonces el espı́a se preocuparı́a por obtener la llave de des-
encripción privada (d, N ), y para esto necesita saber cómo hallar eficientemente d. Con ese valor,
ya vimos cómo des-encriptar, y usarı́a el mismo procedimiento 1.1.2.

Basándonos en la teorı́a, es fácil darse cuenta cómo Alice obtiene d. Uno de los métodos exis-
tentes6 , es usando Exponenciación Modular. En donde usando el Teorema de Euler tenemos que:

aϕ(N )−1 = a−1 (módN )

En el caso de Alice a juega el papel de e y d el inverso. Entonces lo que necesita el espı́a es poder
calcular ϕ (N ) y para esto son necesarios los factores primos de N , en otras palabras factorizar N .
Con estos factores, se vuelve trivial el cálculo de d y por ende la llave privada de des-encripción.

Es ampliamente conocido que el problema de factorización es intratable en la computación


clásica. Y es gracias a este hecho que el sistema de encripción RSA poco vulnerable hoy en dı́a,
ya que no existe un computador tal y como lo conocemos actualmente que resuelva el problema
5
En donde A → 5, L → 0, P → 2 y T → 9. De hecho este serı́a el procedimiento que deberı́a usar una persona
para enviar texto de manera cifrada.
6
El otro es el Algoritmo de Euclides Extendido

6
de la factorización eficientemente. Sin embargo, hay aproximaciones al problema de factorización
bastante rápidas aunque sin dejar una complejidad exponencial [3]. Los detalles de cómo funciona
el algoritmo conocido como “Number Field Sieve” esta por fuera del alcance de este trabajo, sin
embargo es remarcable notar su eficiencia ya que ha factorizado el número 2512 + 1 en cuatro meses
[4]. Más recientemente se ha logrado hacer una implementación usando los mismos principios
por Jason Papadopoulos [5] el cual ha podido ayudar a factorizar un número de 180 dı́gitos. Esta
implementación será la que usaremos para comparar lo que desarrollaremos a lo largo del proyecto.

1.2. Computación Cuántica


Esta sección no intenta de ninguna forma hacer un desarrollo amplio sobre la teorı́a que hay por
detrás de la factorización de un número desde un punto de vista Mecánico cuántico, pero sı́ proveer
lo necesario para evidenciar cómo a partir de esta se procedió con el diseño e implementación del
algoritmo, ası́ como las variantes y problemas encontrados. Sin embargo, es conveniente relacionar
las ciencias de la computación con la fı́sica.

El concepto actual de la computación proviene de las ideas del Matemático Alan Turing, en
particular el conjunto de computaciones de hoy en dı́a es el de la máquina abstracta Turing Univer-
sal la cual es el modelo de todos los computadores clásicos actuales. Es por esto que se considera
como una rama de las matemáticas. Sin embargo, extrayendo las ideas de Deutsch [6] que la teorı́a
de la computación siempre ha tenido bastante en común conceptualmente con la fı́sica.

Nuestro sistema, siendo el Computador, ejecuta un Cálculo. Cuándo hace un cálculo, este em-
pieza con una información de entrada la cual va a ser modificada de acuerdo a unas reglas que
rigen el sistema, que están fuertemente ligadas al hardware del computador. Por lo tanto, la salida
depende de la entrada y de las reglas que rigen operacionalmente al computador.

Por otra parte, los sistemas fı́sicos experimentan un movimiento o cambio entre dos estados o
tiempos; ya sea uno inicial y uno final, de acuerdo a unas leyes de movimiento que rigen el sistema.
Esto lleva a la conclusión a que el cambio de estado de un sistema fı́sico puede ser considerado
como un procesamiento de información, ya que el estado final depende de las condiciones iniciales
del sistema -estado inicial o entrada en un computador- y puede decirse que se procesa de acuerdo
a unas reglas o condiciones del mismo; en el caso de la computación está regida por el hardware y
los lı́mites que fı́sicamente imponen sobre el mismo. El análisis previo puede resumirse en la tabla
1.1.

Computación Fı́sica
Computador Sistema Fı́sico
Cálculo Movimiento
Entrada Estado Inicial
Reglas Leyes de Movimiento
Salida Estado Final
Tabla 1.1: Relación entre la Computación y la Fı́sica.

La teorı́a de la computación puede entonces incorporarse a la fı́sica; de hecho ha sido incor-


porado por la teorı́a Cuántica de la Computación con el fin de resolver un problema crı́tico, el

7
crecimiento del poder computacional se doblará a un costo constante aproximadamente una vez
cada dos años (ley de Moore) [7]. Nielen y Chuang dicen al respecto:

“Una posible solución al problema [...] es cambiarse a un paradigma distinto de


computación. Uno de esos paradigmas es provisto por la teorı́a cuántica de la com-
putación, la cual está basada en la idea del uso de mecánica cuántica para ejecutar
cálculos, en vez de fı́sica clásica.” [7]

Es bastante motivante el hecho de poder hacer eficientemente cálculos por medio de la com-
putación cuántica como respuesta a las deficiencias presentes en su contra parte clásica. Como
mencionaré más adelante el problema de la factorización puede hacerse eficientemente en un com-
putador cuántico.

1.2.1. El Qubit y El Algorı́tmo de Shor


El bit es el concepto fundamental de la computación clásica, en este sentido el qubit7 es su
contraparte cuántica. Más aún, ası́ como el bit clásico tiene un estado 1 o 0 el bit cuántico también
tiene los estados

|1i , |0i .

Estos estados en la práctica forman una base, más estrictamente, una base computacional. Es
decir, cualquier estado posible puede ser hecho a partir de una combinación de estos dos. Un
fenómeno interesante de esto es que los estados |1i y |0i pueden superponerse; se denomina usual-
mente como Superposición Coherente

|Ψi = α |1i + β |0i (1.2.1)


Esto presenta una gran diferencia ya que la cantidad de posibles estados es colosal. Más aún,
sabemos que clásicamente podemos en n bits guardar 2n números en cualquier instante. Sin em-
bargo cuánticamente podemos en n bits guardar a todas los posibles 2n números. Supongamos
por ejemplo que clásicamente en una variable vamos a guardar un número de 10 bits, como es de
esperarse en esta variable solo tendremos dicho número. Sin embargo, en una variable cuántica
podrı́amos tener a todos los números de 10 bits; esto representa un incremento exponencial en in-
formación guardada y por lo tanto cualquier cálculo que se haga sobre esta superposición, es hecho
en paralelo haciendo que problemas complejos sean mucho más fáciles de resolver.

De lo mencionado previamente es importante notar que los efectos de superposición, enredamien-


to e interferencia, resultan ser la clave del desempeño de los distintos algoritmos que cuánticamente
se llevan a cabo como respuesta a los problemas que se enfrenta la computación clásica. Pasemos
al algoritmo por el cual estamos interesados.

Algoritmo de Shor
El algoritmo de Shor es apropiado para factorizar un número N en sus factores primos, incluso
para el problema del logaritmo discreto. El algoritmo usa la ayuda de la Transformación Cuántica
7
Es la forma compacta de Quantum Bit, en inglés, o Bit cuántico.

8
de Fourier. Ahora presentaremos la forma básica del algoritmo para encontrar los factores de N
reduciendo el problema a la búsqueda del orden de la función f (x) = ax (mód N ).
El pseudo algoritmo es [8]

1. Elegir un número x aleatorio que sea menor que N y co-primo.

2. Ahora, calcular el orden de x (mód N ), definido como el r mı́nimo dentro de un conjunto a


tal que al elevar x a la r-ésima potencia módulo N resulta igual a 1, siendo r distinto de 0;
r ← mı́n a : xa (mód N ) = 1.

3. Sı́, gcd xr/2 − 1, N = 1 será un factor no trivial de N y

4. Sı́, gcd xr/2 + 1, N = 1 será el otro factor de N .

Consideraremos ahora el problema de encontrar el periodo r de una función f (x) [9], con
f (x + r) = f (x). Particularmente vamos a considerar el caso en el que r divide a N , siendo esta
el número de puntos sobre los que la función f (x) es evaluada, esto es N/r = m, con m entero
y N = 2n . En el caso que no lo divida exactamente agrega unas complicaciones al problema que
no consideraremos ya que no cambia la idea general de lo que describiremos. Necesitamos dos
registros el primero es la superposición de los 2n − 1 posibles estados, el segundo guarda la función
f (x), luego el estado total resulta
n
2 −1
1 X
√ |xi |f (x)i (1.2.2)
2n x=0
De lo que mencionábamos previamente, la diferencia entre la computación clásica y la cuántica
es el paralelismo presente inherentemente en este régimen. Por lo tanto en el segundo estado va es-
tar contenido la evaluación de f (x) para todo x en una sola iteración. Luego de la evaluación de la
función ambos registros resultan enredados, y además no tenemos acceso directo a la información
de todos los valores de la función f (x). Con el propósito de entender lo que sigue, voy a introducir
un concepto de la mecánica cuántica denominado como una observación o medida de un estado. En
pocas palabras observar un estado significa extraer toda la información contenida en ese estado en
particular perdiendo toda información adicional que se encuentre en la superposición de los demás
estados ya que lo hemos observado8 . Un ejemplo famoso que puede evidenciar este hecho es el
gato de Schrödinger, en el que luego de exponer a un gato dentro de una caja tapada, no se sabı́a si
el gato estaba vivo o muerto, estos son los estados del gato, estar vivo o muerto, y medir el estado
del gato lleva a un resultado, sea vivo o muerto, sin embargo la información distinta al resultado,
digamos vivo, se ha perdido.

Con lo anterior en mente cuando hacemos una medición sobre el segundo registro, este se
colapsa a un estado particular f (x0 ),
m−1
1 X
√ |x0 + jri |f (x0 )i (1.2.3)
m j=0

en donde m = N/r es el número de los valores de x tal que f (x) = f (x0 ). Ahora, puesto que
r es el periodo de f (x) entonces f (x0 ) = f (x0 + r) = f (x0 + 2r) = . . . = f (x0 + (m − 1) r).
8
Esta es una definición muy burda y solo pretende ayudar al lector a entender cómo funciona el algoritmo. Re-
comiendo el libro de Cohen-Tannoudji, Diu y Laloe para aquellos que quieran profundizar en el tema de la mecánica
cuántica desde lo básico hasta temas avanzados [10]

9
Ya que el barrido de la sumatoria afecta el primer registro, podemos ignorar el segundo, luego de
aplicar la transformación cuántica de Fourier, tenemos:
r−1 
1 X 2πix0 k N
√ exp r k
r (1.2.4)
r k=0
Al medir el primer registro obtendremos un múltiplo de la forma λN/r del valor medido, dig-
amos c, esto satisface que c/N = λ/r, de la expresión conocemos N , y si λ y r no tienen factores en
común, es decir gcd (λ, r) = 1, entonces podremos reducir la fracción a una irreducible y entonces
determinaremos r.

10
Capı́tulo 2

Diseño y Especificación

2.1. Definición del problema


Como vimos en el capitulo pasado existe una forma de factorizar un número de manera alter-
nativa ya que se reduce el problema de la factorización al encontrar el orden de una función, en
particular ax (mód N ) en donde N es el número a factorizar y a un número aleatorio. Por lo tanto
el problema es factorizar un número encontrando su orden.

Con el fin de hallar el periodo nos veremos enfrentados entonces a hacer eficientemente la
exponenciación modular, exponenciación, sacar el máximo común divisor y en general a manejar
valores de números inmensos en memoria para lograr el objetivo.

2.2. Especificaciones
Lo necesario para el algoritmo adaptado es que calcule eficientemente el máximo común divi-
sor, potenciación, potenciación modular entre números dados.

Requerimientos Funcionales
En primera instancia es necesario que el usuario interesado en averiguar los factores primos
de un número, ingrese manualmente el número por el cual necesita el algoritmo. Este número no
deberı́a en principio tener una restricción adicional a la que sea, entero y que además sea mayor
que 0.
Para que el algoritmo funcione, necesitamos calcular el máximo común divisor. Esto es aquel
número, máximo, que divide a un conjunto de números generalmente. Para nuestro problema única-
mente nos limitaremos a calcular el máximo común divisor entre un par de números enteros, ası́ co-
mo se aprecia en el algoritmo de Shor 1.2.1. Esta función, la de calcular el máximo común divisor,
se usa en la mayorı́a de los requerimientos, por tal razón es imperativo tenerla.

También es necesario poder hacer la exponenciación de un número, es decir an = a


| ∗ a ∗ a ∗{za ∗ . . . ∗ a}
n
ya que a la hora de sacar uno de los factores debemos elevar el número elegido al azar a la mitad
del orden encontrado, luego de haberlo encontrado.

La exponenciación modular es tomar el módulo luego de obtener el resultado de la expo-


nenciación, es decir si queremos hacer: an (mód p), entonces intuitivamente pensamos en hacer

11
primero la exponenciación, ası́ como la vimos arriba, y luego sacar el módulo. Por ejemplo, 35
(mód 7), primero obtenemos el resultado de la exponenciación, 35 = 243 y ahora el módulo, 243
(mód 7) = 5. Aunque veremos que esta forma es válida, no es la mejor desde un punto de vista
computacional práctico.

Adicionalmente, necesitamos un generador de números aleatorios, ya que como parte esencial


del pseudo algoritmo reside en el hecho de tener como base para el inicio del proceso un número
aleatorio y menor que el número a factorizar. En adición a este hecho, es importante que el número
sea lo más aleatorio posible, es decir, al momento de repetir el proceso aquel número aleatorio
generado siempre sea distinto en cada iteración.

Por último, es indispensable que la implementación del algoritmo se ejecute lo más rápido
posible, luego necesitamos medir el tiempo que toma la factorización.

Requerimientos No Funcionales
La implementación final debe ser fácil de usar. Ası́ como tener un mı́nimo de interacción con
el usuario, ya que se espera que para números grandes el sistema se demore en dar el resultado, en
otras palabras muy usable. También, es indispensable tener suficiente memoria RAM en el sistema
en donde serán almacenados temporalmente los resultados de los distintos cálculos durante el pro-
ceso. Y por último, debe existir un lugar en donde los resultados puedan persistir en forma fı́sica
para una posterior evaluación.

Para el problema de la factorización, es indispensable que el resultado sea exacto, es deseable


entonces que siempre obtengamos como respuesta los factores que componen el número de entrada.
Puesto que la respuesta es fácil de verificar cualquier resultado erróneo serı́a fácilmente detectable,
ya que lo difı́cil, como se mencionó previamente, es encontrar dichos factores.

Las circunstancias en que el algoritmo podrı́a desarrollar respuestas falsas o inexactas proven-
drı́an de fallas en el sistema durante la ejecución del mismo, ya sea que se perturben los datos que
se manipulan de forma poco común o que se generen números aleatorios que no necesariamente
llevan a la respuesta y siempre se quede en un ciclo lo cual serı́a poco aceptable.

2.3. Desarrollo del Diseño


El proceso que seguimos para el desarrollo del diseño se dividió en varias etapas. La primera
se basó en recopilar información sobre las distintas formas de implementar eficientemente los dis-
tintos módulos, o métodos que la máquina finalmente debe usar, entre estos el máximo común
divisor, exponenciación, exponenciación modular y generación de números aleatorios. La segun-
da fase se centró en estudiar cómo funciona CONDOR, y en cómo mandar trabajos (jobs) a los
demás miembros de la Grid, básicamente la arquitectura de CONDOR. El tercero y último, revisar
profundamente el algoritmo cuántico para tomar una decisión final a la hora de hacer el modelaje.

12
2.3.1. Fuentes de Información
Fase I
Con el fin de desarrollar el diseño teniendo en cuenta las especificaciones resaltadas en la sec-
ción pasada, decidimos consultar un libro que estudie las diversas formas de implementar un algo-
ritmo en particular. El libro consultado es The Art of Computer Programming [11], el cual se ajusta
a lo que necesitábamos.

Empezamos buscando la mejor forma de calcular el máximo común divisor entre un par de
números. Un clásico, es usar el Algoritmo de Euclides y aunque existe una versión moderna del al-
goritmo, este no provee la suficiente eficiencia a nivel computacional, ya que siempre vamos a tener
que dividir en algún punto, lo cual resulta costoso. Entonces, deberı́a existir un algoritmo que usara
operaciones que para un computador sean fáciles de ejecutar. Luego de buscar las diferentes formas
de calcular el máximo común divisor, nos encontramos con un método binario el cual está basado
únicamente en operaciones de resta, prueba de paridad, y dividir a la mitad números pares; lo que
corresponderı́a a un corrimiento hacia la derecha en notación binaria. [12]

En cuanto a la exponenciación Knuth nos muestra un algoritmo binario para elevar a cualquier
potencia positiva, un número. La idea es expresar el exponente en su representación binaria e irlo
leyendo de izquierda a derecha y tomar decisiones respecto a si el bit es par o no. Sin embargo,
como Knuth nos menciona este proceso es poco frecuente en un computador, luego el algoritmo
es modificado para que se lea de derecha a izquierda. Para que surta el mismo efecto el exponente
se divide en dos sistemáticamente y si este resulta ser par o no, se eleva al cuadrado la base o se
multiplica por sı́ mismo.

Un tema de importante discusión es la exponenciación modular que debe hacerse de manera


eficiente. En esta situación Knuth no nos proporciona información que de solución al problema.
Sin embargo, conjunto al algoritmo que él nos propone combinándolo con un poco de teorı́a de
grupos podemos obtener un algoritmo eficiente para hacer la exponenciación modular de manera
distinta a como se presentó en la sección de requerimientos 2.2, ya que sacar el módulo del numero
que resulta luego de haber hecho la exponenciación puede ser inmanejable. En pocas palabras,
la operación entre números bajo el módulo forma un grupo cı́clico, y en adición, siempre que
apliquemos el módulo m a un número, el resultado siempre será menor que m y será un elemento
del grupo. Se sigue entonces que podrı́amos hacer luego de cada operación del algoritmo binario
para la exponenciación, una aplicación de la operación módulo y estar seguros que nos llevará al
mismo resultado como mostramos en la sección 2.2.

Fase II
CONDOR es un sistema de administración de cargas para trabajos intensivos computacional-
mente [13]. En adición, un usuario puede enviar trabajos paralelos o seriales por medio de CON-
DOR, estos trabajos pueden ser enviado basado en polı́ticas definidas por el usuario a un conjunto
de computadores que estén conectados por medio de CONDOR.

Dentro del sistema de administración CONDOR, se establece un computador maestro o Sched-


uler el cual se comporta como la central de distribución de trabajos a los demás computadores,
que comúnmente son denominados esclavos. Esta conexión entre computadores, ya que en prin-
cipio CONDOR podrı́a trabajar sobre la máquina en la cual está instalado -procesos en batch-, se

13
hace por medio de un intermediador que está diseñado particularmente para la creación de sistemas
Grid [14]. La combinación de estas dos tecnologı́as proporciona un ambiente descomunal para tipos
de trabajos en batch sobre múltiples computadores.

Por esta y otras razones, como por ejemplo la ayuda a muchas instituciones a desarrollar proyec-
tos en donde se aproveche el poder de múltiples supercomputadores haciendo cálculos en parale-
lo [15] [16], se han elegido estas dos herramientas para desarrollar este proyecto.

2.3.2. Diseño
Para determinar el diseño final elegido para el desarrollo del proyecto empezaremos por desvir-
tuar las alternativas que pasaron en consideración. Empezamos considerando el enfoque en el cual
queremos emular el comportamiento del paralelismo cuántico que se incluye en el algoritmo de
Shor; este considera el hecho de tener múltiples estados cuánticos por “separado” enredados dentro
de una gran función o estado.

Como vimos en la sección 1.2.1, cada estado dentro de la sumatoria nos representaba una can-
tidad considerable de información la cual existe, aunque no tengamos acceso a toda ella. Con el
fin de hacer más clara la idea, mostraré un ejemplo [17]. Vamos a factorizar el número 15 y hemos
obtenido como número aleatorio el 7:
1. Preparamos el estado total

15
1X
|xi |f (x)i
4 x=0

2. El cálculo de la función y la sumatoria resulta

1
(|0i |1i + |1i |7i + |2i |4i + |3i |13i + |4i |1i + . . . + |15i |13i)
4
Agrupando estados iguales lo que está entre los paréntesis

(|0i + |4i + |8i + |12i) |1i


+ (|1i + |5i + |9i + |13i) |7i
+ (|2i + |6i + |10i + |14i) |4i
+ (|3i + |7i + |11i + |15i) |13i

3. Luego de la transformación cuántica de Fourier, dentro del paréntesis queda

(|0i + |4i + |8i + |12i) |1i


+ (|0i + i |4i − |8i − i |12i) |7i
+ (|0i − |4i + |8i − |12i) |4i
+ (|0i − i |4i − |8i + i |12i) |13i

14
A partir de los resultados anteriores se puede hallar el orden 1 . Sin embargo, el punto de la
discusión tiene como objetivo mostrar que si bien la gran cantidad de datos en un único registro
cuántico que contiene la información necesaria para calcular el orden implı́citamente dentro de este
régimen, a la hora de implementar el algoritmo sobre un computador clásico, este deberá hacer to-
dos los cálculos necesarios para determinar aquellas entradas que describimos en los dos últimos
numerales previos. Esto quiere decir que, además de tener que calcular la exponenciación modular
de TODOS los términos2 , vamos a tener que guardarlo para poder hacer aquella factorización de
estados que contenı́an el resultado de dicha operación y luego poder tener el orden. Esta aprox-
imación resultarı́a extremadamente costosa, ya que la cantidad de información que tenemos que
guardar es proporcional a N ası́ como el número de operaciones que deberı́amos hacer.

Por el hecho anterior fue que decidimos no implementar la solución del problema de esa man-
era. Tenı́amos la opción de implementar cada estado que se representara en el algoritmo dentro de
un computador por separado dentro de la Grid, y aunque esto se asemejarı́a bastante al paralelismo
manejado cuánticamente, lo ideal serı́a que cada computador hiciera el cálculo de la función selec-
cionando equitativamente la exponenciación a manejar. El problema de esta aproximación reside
en que finalmente todos los computadores van a tener que trabajar en lo mismo, y cuando N sea
de magnitudes significativas, simplemente gran parte de los cálculos hechos serán de poca utilidad
pues solo nos representa un estado adicional dentro del total.

Otra aproximación considerada para resolver el problema eficientemente es que todos los com-
putadores que hacen parte de la grid se comunicaran entre ellos durante la ejecución del algoritmo.
Sin embargo, como se dijo antes todos estarı́an trabajando para llegar al resultado y en la circun-
stancia en que el numero a factorizar sea muy grande puede que no sea fructı́fero en adición a las
situaciones previamente mencionadas.

Elección Final
El diseño final sobre el cual va a estar montado todo el proyecto se generó como respuesta
a las deficiencias que se presentaban previamente. Aunque el enfoque parezca exhaustivo intenta
dilucidar un punto importante de una de las operaciones que se realizan en el algoritmo de Shor; la
exponenciación modular. Como vimos, el problema de la factorización podı́a reducirse al de encon-
trar el periodo de una función y en el enfoque cuántico ı́bamos a tener que, finalmente, hacer tantas
operaciones como el número a factorizar. Luego, si finalmente vamos a realizar tales operaciones,
porqué no hallar el orden al vuelo y ası́ efectuar menos operaciones que el algoritmo cuántico solo
que siguiendo su perspectiva.

A manera de ejemplo, remitámonos al segundo paso del ejemplo anterior 2.3.2, si lo hiciéramos
de manera explı́cita como sugiere el algoritmo cuántico, tendrı́amos que hacer 15 cálculos antes de
al menos hacer el tercer paso, y encontrar finalmente el orden. Sin embargo, mientras los calcu-
labamos, nos hubiésemos dado cuenta del orden de la función para a = 7, ya que los estados
|0i |1i y |4i |1i cumplen con la definición de orden, e inclusive ocurrió a la cuarta operación, en
otras palabras el orden es 4. Habı́amos dicho que el orden de una función se comporta como el
periodo, aquel número que hace que la función devuelva un mismo resultado, en el ejemplo 70
1
Para obtener una visión más detallada sobre los pasos que se realizaron recomiendo [18] [19] y la fuente del
ejemplo [17]
2
Desde el a0 (mód N ) hasta aN −1 (mód N )

15
(mód 15) = 74 (mód 15) = 1 lo que nos sugiere que 4 es el orden de la función con ese a. Este
hecho es bastante significativo, ya que realizamos y realizarı́amos una cantidad inferior de cálculos
para encontrar el orden.

Con lo anterior en mente, añadimos un elemento extra; el hecho que dependiendo de la elección
de a podrı́amos llegar al resultado deseado, factorizar el número de entrada en sus factores primos,
aún mas rápido. El argumento considera que aunque exista una altı́sima probabilidad al tomar un
número al azar menor que N y que sean co-primos, también existe una buena probabilidad de que
no lo sean y por lo tanto obtendrı́amos factores no triviales directamente. La forma que usamos para
aproximarnos a esta solución es usar cada máquina de la grid por separado, trabajando conjunta-
mente para encontrar los factores primos, solo que todas parten con un a distinto. Como nuestro
interés reside en competir contra el mejor algoritmo actual, por lo tanto es indispensable terminar
(factorizar) lo más pronto posible usando el enfoque mecánico cuántico.

El pseudo-algoritmo de la solución consiste en, dado un número positivo n hecho a partir de


dos primos f 1 y f 2, encuentra los factores que componen a n:

1. [Inicializar] Generar a de forma aleatoria, k, u, v ← 0, g ← M CD (a, n).

2. [g = 1?] En caso afirmativo, continúe al paso 3, de lo contrario o es el mismo n o es un factor


trivial por lo tanto f 1 ← g, f 2 ← v/g y finaliza.

3. [Orden] k ← orden (a, n) Calcular el orden de a y n como lo hace el algoritmo de Shor.

4. [k&1 = 0?] Esto pregunta si k es par, en caso afirmativo continua, de lo contrario se devuelve
al 1. Como es par, k ← k/2 y u ← ak − 1, v ← ak + 1.

5. [V erif icar] En f 1 ← M CD (u, n), f 2 ← M CD (v, n). Si f 1 o f 2 son resultan ser 1 o n,


vaya al paso 1, de lo contrario finaliza.

Con el algoritmo ya creado, estamos preparados para la implementación, que como se men-
cionó en la introducción se realizará en C/C++ sobre Condor para enviar los trabajos sobre la Grid
hecha en Globus.

16
Capı́tulo 3

Implementación

3.1. Descripción de la Implementación


En este capı́tulo mostraremos cómo implementamos la solución en C/C++ y en CONDOR. Em-
pezamos construyendo en C++ la solución de los distintos módulos o funciones que servirı́an dentro
del programa principal, incluyendo la obtención del Máximo Común Divisor, exponenciación mod-
ular, entre otros. Detallamos en cada una de estas funciones lo que hacemos con el fin de entender
mejor el código y ası́ pueda reutilizarse en un futuro.

Luego de la implementación del programa en C++, hacemos una implementación en C con la


librerı́a GMP la cual nos permite manejar números de tamaños colosales [20]. La librerı́a contiene
funciones que implementan eficientemente las distintas operaciones que necesitamos para la im-
plementación del algoritmo descrito en el capitulo 2 y ası́ encontrar los factores de números más
grandes que aquellos manejados nativamente por C.

Describiremos además, cómo usamos CONDOR para distribuir los trabajos en la GRID ası́ co-
mo las especificaciones de cada una de las máquinas dentro de la misma.

Etapas
Las etapas de la implementación fueron ordenadas por la importancia que representaban para el
proyecto, ası́ fue como empezamos la implementación eficiente del máximo común divisor entre un
par de números enteros positivos; es muy importante porque se usa finalmente para determinar los
factores. Luego implementamos la exponenciación, y la exponenciación modular como funciones
aparte. Con las funciones previamente definidas procedimos a implementar el cálculo del orden
de una función, en este caso de la función vista en el capitulo 1. Finalmente integramos todas la
funciones de acuerdo al pseudo algoritmo 2.3.2.

3.2. Implementación en C++


3.2.1. MCD-C++
Para la implementación del máximo común divisor nos basamos en el trabajo del Señor Knuth,
en donde estudia cómo eficientemente puede implementarse el cálculo de este valor. Describe

17
además, que aunque eficazmente varios algoritmos funcionan para determinar el máximo común di-
visor, en un computador clásico podemos eficientemente determinar el resultado ya que la división
entre 2, o la multiplicación por 2, inclusive determinar si un número es par o no corresponden
a operaciones básicas que el procesador maneja naturalmente como un corrimiento a la derecha,
izquierda, o AND.

Código 1: Máximo Común Divisor Binario


1 /**
2 *Función que retorna el máximo común divisor de u, y v;
3 *ambos deben ser enteros y retorna un entero.
4 **/

6 long long int gcd(long long int u, long long int v)


7 {
8 int k=0, pot=1, p=1;
9 long int t, n1=0, n2=1;

11 if(u == 0 || v == 0)
12 {
13 return u|v;
14 }

16 while(pot==1)
17 {
18 if((u & 1)==0 && (v & 1)==0)
19 {
20 k++;
21 u>>=1;
22 v>>=1;
23 }
24 else
25 {
26 pot=0;
27 }
28 }

30 if((u & 1) == 1) // inicialización


31 {
32 t = -v;
33 if((t & 1)==0)
34 {
35 n1=1;
36 }
37 else if(n1!=1) //max(u,v)
38 {
39 if(t>0)
40 {
41 u = t;
42 }
43 else

18
44 {
45 v = -t;
46 }

48 t = u - v; //restar

50 if(t != 0)
51 {
52 n1=1;
53 }
54 else n1=0;
55 }
56 }
57 else
58 {
59 t = u;
60 n1=1;
61 }

63 while(n1==1)
64 {
65 t>>=1; // dividir t en 2
66 n1=0;

68 if((t & 1)==0) // t par?


69 {
70 n1=1;
71 }
72 else if(n1!=1) //max(u,v)
73 {
74 if(t>0)
75 {
76 u = t;
77 }
78 else
79 {
80 v = -t;
81 }

83 t = u - v; //restar

85 if(t != 0)
86 {
87 n1=1;
88 }
89 else n1=0;
90 }
91 }

93 if(k != 0 )
94 {

19
95 while(n2 <= k)
96 {
97 p <<= 1;
98 n2++;
99 }
100 return p*u;
101 }
102 else return u;
103 }

Aunque el código anterior es relativamente más largo que una implementación del Algoritmo
de Euclides, las operaciones que ejecuta son realmente eficientes. Por ejemplo entre la lı́nea 16 y la
28, se usa el operador & de C para verificar que sea par el número, y >> para hacer un corrimiento
a la derecha en una unidad, es decir dividir entre 2.

3.2.2. Potenciación-C++
Ası́ como para la implementación nos basamos en Knuth, para la potenciación no sucede al-
go diferente. Esta potenciación como mencionamos en el capitulo anterior puede hacerse bastante
rápido una vez sabemos que lo único que debemos hacer es dividir entre 2 y multiplicar por la base
un número.

Código 2: Exponenciación Binaria


1 /**
2 *Devuelve el resultado de calcular xˆ{n}, tanto x como n
3 *son enteros positivos.
4 **/
5 long long int potencia(long long int x, unsigned n)
6 {
7 long long int p;
8 long long int r;

10 p = x;
11 r = 1;
12 while (n > 0)
13 {
14 if (n & 1){
15 r *= p;
16 n-=1;
17 }
18 p *= p;
19 n >>= 1;
20 }

22 return r;
23 }

Con esta forma de operar matemáticamente a dos números, la base y el exponente, está garan-
tizado que se ejecutan menos cálculos que de la forma tradicional (i.e. multiplicar la base tantas
veces como indica el exponente).

20
3.2.3. Exponenciación Modular-C++
El código 2 nos permite darnos cuenta de lo mencionado en la sección 2.3.1. Lo importante
es notar que en la lı́nea 15 y 18 del código 2 potemos directamente calcular el módulo y estar
seguros que el resultado nos dará el mismo al que obtendrı́amos luego de tener el resultado final
de la exponenciación y después tomar el módulo. Esto sucede porque la operación módulo forma
un grupo cı́clico y por lo tanto siempre que lo tomemos bajo la misma operación nos acercaremos
gradualmente al resultado final.
Código 3: Exponenciación Modular Binaria
1 /**
2 *Devuelve el resultado de calcular xˆ{n}mod(b), x, n y b
3 *son enteros positivos.
4 **/
5 long long int modPot(long long int x, unsigned n, long long int b)
6 {
7 long long int p;
8 long long int r;

10 p = x;
11 r = 1;
12 while (n > 0)
13 {
14 if (n & 1){
15 r *= p;
16 r = r %b;
17 n-=1;
18 }
19 p *= p;
20 p = p %b;
21 n >>= 1;
22 }

24 return r;
25 }

De esta manera tenemos una forma eficiente de calcular la exponenciación modular combinando
la teorı́a de grupos con el algoritmo binario para hacer la exponenciación.

3.2.4. Orden-C++
Por los argumentos que dimos en la sección 2.3.2 debemos calcular el orden usando la función
modPot hasta que encontremos el periodo de la función. Aunque el resultado lo obtengamos de
manera exhaustiva, es de esta forma que podemos lograr encontrar el orden usando menos cálculos
y menos memoria.
Código 4: Orden de la función f (x) = ax (mód b)
1 /**
2 *Devuelve en cont (contador) el orden de la función f(x)=aˆ{x}mod(b)
3 *a y b (b:= el número a factorizar) son enteros positivos.
4 **/

21
5 unsigned orden(long long int a, long long int b)
6 {
7 int i=1;
8 long long int res;
9 unsigned cont=0;
10 res=modPot(a,cont,b);

12 do
13 {
14 cont++;
15 res=modPot(a,cont,b);

17 }while(i!=res);

19 return cont;
20 }

Junto con las demás funciones definidas a lo largo del capı́tulo, es hora de implementar el
programa completo integrando todas las funciones y teniendo en cuenta el pseudo algoritmo de la
sección 2.3.2.

3.2.5. Main-C++
El siguiente es la implementación del programa para factorizar un número que es ingresado por
el usuario y este devuelve los factores.
Código 5: Factorizar en Primos
1 //para linux:
2 //compilar como gcc -o <nom ejecutable> <nombre.cpp> -lstdc++
3 //ejecutar como ./<nom ejecutable> <número a factorizar>
4 //#include "stdafx.h" //comentar esta lı́nea para que funcione en linux
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <iostream>
8 #include <math.h>
9 #include <time.h>
10 #include <unistd.h> //comentar esta lı́nea para que funcione en windows
11 #include <pthread.h> //comentar esta lı́nea para que funcione en windows

13 using namespace std;

15 //
16 //
17 // Insertar las funciones previamente declaradas acá.
18 //
19 //

21 /**
22 *Devuelve por consola un par de factores que componen al número
23 *n=p.q ingresado por consola como argumentos al momento de llamar
24 *el programa ya compilado.

22
25 **/
26 int main(int argc, char* argv[])
27 {

30 long long int u, v, gd, f1, f2, anterior=1;


31 unsigned ord, tt=1;

33 v=atoll(argv[1]); //número ingresado al llamar el programa

35 while(tt==1)
36 {
37 //para tener un numero aleatorio bueno
38 time_t seconds;
39 time(&seconds);
40 srand((unsigned int) seconds);

42 u=1;
43 while(u==1||u==0||u==anterior) //nos aseguramos que el numero
generado
44 u = rand() %v;
//no sea el mismo que el anterior

46 anterior = u;
47 if(u==0) gd=v;
48 else if(u==1) gd=v;
49 else {
50 gd=gcd(u,v); //resultado de llamar a la función gcd

52 cout << "Numero generado: " << u <<endl;


53 }

55 if(gd==1) //si el número generado y el número a factorizar son co-


primos
56 {
57 ord = orden(u, v); //resultado de llamar a la función orden

59 if((ord & 1)==0) //es necesario que el orden sea par, para que
funcione.
60 {
61 cout << "orden:" << ord <<endl;
62 ord>>=1;
63 f1 = potencia(u,ord)-1;
64 f2 = potencia(u,ord)+1;
65 f1 = gcd(v, f1);
66 f2 = gcd(v, f2);

68 if(f1==1||f2==v||f1==v||f2==1)
69 {
70 tt=1;
71 }

23
72 else
73 {
74 cout << "factor 1: " << f1 <<endl;
75 cout << "factor 2: " << f2 <<endl;
76 tt=0;
77 }
78 }
79 }
80 else if(gd==v)//el máximo común divisor es el numero a factorizar
mismo
81 {
82 tt=1;
83 }
84 else //es un factor trivial
85 {
86 f1 = gd;
87 f2 = v/gd;
88 cout << "factor 1: " << f1 <<endl;
89 cout << "factor 2: " << f2 <<endl;
90 tt=0;
91 }
92 }

94 return 0;
95 }

3.3. Implementación con Librerı́a GMP


El código 5 funciona perfectamente para números pequeños. Sin embargo, luego de unas prue-
bas realizadas al tratar de factorizar números de alrededor 5 cifras el programa no funcionaba, lo
que nos hizo pensar que se debı́a a un problema de tamaños manejados por C++. Entonces em-
pezamos a usar GMP.

A la hora de usar GMP, es importante tener en cuenta que muchas de las operaciones que
nosotros definimos como funciones, es decir MCD, Potenciación y Potenciación Modular, ya se
hacen eficientemente en esta librerı́a. Por lo que únicamente nos esperaba implementar el cálculo
del orden, y el main con esta nueva librerı́a.

A la hora de usar GMP hay que tener unos cuantos aspectos presentes. El primero, toda vari-
able que se instancie debe ser inicializada explı́citamente, ası́ como debe ser igualmente des-
referenciada. Las funciones funcionan un poco distinto a como lo venı́amos haciendo, ya que el
valor en donde queda guardado el resultado es pasado por referencia.

3.3.1. Orden-GMP
Esta función básicamente emula el funcionamiento de la que creamos previamente implemen-
tado en el código 4. En este caso como argumentos los mismos números, solo que por referencia se

24
pasa la variable (ord) en la que quedará el resultado, es decir el orden de la función.

Código 6: Orden de la función f (x) = ax (mód b) usando la librerı́a GMP


1 /**
2 *Asigna a ord, el orden de la función aˆ{ord}mod(b), en donde
3 *a:=número aleatorio, b:= el número a factorizar y ord son enteros
positivos.
4 *ord debe llegar en 0.
5 **/
6 void orden(mpz_t a, mpz_t b, mpz_t ord)
7 {
8 mpz_t res;
9 mpz_init(res);

11 mpz_powm(res,a,ord,b); //deja en res el resultado de (aˆorden)mod(b


)

13 do
14 {
15 mpz_add_ui(ord, ord,1);//le suma a ord, una unidad.
16 mpz_powm(res,a,ord,b); //deja en res el resultado de (aˆorden)
mod(b)

18 }while(mpz_cmp_ui(res,1)!=0);

20 mpz_clear(res);
21 }

El uso de GMP simplificó significativamente la tarea de programar varias de las funciones que
usábamos en el programa que factoriza un número dado.

3.3.2. Main-GMP
Con este programa, obtenemos los factores primos que hacen a un número n = p ∗ q. Cabe
resaltar que la lógica es la misma que usamos en el código 5 e igualmente basados en 2.3.2.

Código 7: Factorizar en Primos usando GMP


1 #include <stdio.h>
2 #include <gmp.h>
3 #include <time.h>
4 //
5 //
6 // Insertar la función previamente declarada acá.
7 //
8 //

10 /**
11 *Devuelve por consola un par de factores que componen al número

25
12 *n=p.q ingresado por consola como argumentos al momento de llamar
13 *el programa ya compilado.
14 **/int main (int argc, char* argv[]) {

16 //Variables generales
17 unsigned long int i, seed;
18 int tt=1;
19 //Variables de Tiempo
20 time_t seconds, ini, fin;

22 //variables GMP
23 /*u:= numero aleatorio, v:= numero a factorizar,
24 anterior:= numero aleatorio anterior, gcd := máximo común divisor,
25 ord := orden, f1,f2:= factores, r_state:= para generar numero aleatorio
26 */
27 mpz_t u,v, anterior, gcd, ord, f1, f2;
28 gmp_randstate_t r_state;

30 //se inicializa anterior


31 mpz_init(anterior);

33 //se inicializa el numero a factorizar


34 mpz_init(v);
35 mpz_set_ui(v, atoll(argv[1]));

38 ini=clock();//incia medición del tiempo


39 while(tt==1)
40 {
41 //
42 time(&seconds);
43 srand((unsigned int) seconds);
44 //
45 seed = rand();
46 gmp_randinit_default(r_state);
47 gmp_randseed_ui(r_state, seed);

49 mpz_init(u);
50 mpz_init(gcd);
51 mpz_init(ord);
52 mpz_init(f1);
53 mpz_init(f2);

55 mpz_set_ui(u,1);
56 while(mpz_cmp_ui(u,1)==0||mpz_cmp_ui(u,0)==0||mpz_cmp(u,anterior)==0)
57 {
58 mpz_urandomm(u,r_state,v);
59 gmp_printf("numero aleatorio: %Zd\n", u);
60 }

62 mpz_set(anterior, u);

26
63 mpz_set_ui(ord,0);
64 mpz_gcd(gcd, u, v);

66 if(mpz_cmp_ui(gcd,1)==0)
67 {

69 orden(u,v,ord);

71 if(mpz_even_p(ord)!=0)
72 {
73 mpz_divexact_ui(ord,ord,2);

75 mpz_pow_ui(f1, u, mpz_get_ui(ord));
76 mpz_set(f2,f1);

78 mpz_sub_ui(f1,f1,1);
79 mpz_add_ui(f2,f2,1);

81 mpz_gcd(f1, v, f1);
82 mpz_gcd(f2, v, f2);

84 if(mpz_cmp_ui(f1,1)==0||mpz_cmp_ui(f2,1)==0||mpz_cmp(f1,v)==0||
mpz_cmp(f2,v)==0)
85 {
86 tt=1;
87 }
88 else
89 {
90 gmp_printf("Factor 1: %Zd\n", f1);
91 gmp_printf("Factor 2: %Zd\n", f2);
92 fin=clock();//terminamos medición del tiempo
93 tt=0;
94 }
95 }
96 }
97 else if(mpz_cmp(gcd,v)==0)
98 {
99 tt=1;
100 }
101 else
102 {
103 mpz_set(f1,gcd);
104 mpz_divexact(v,v,gcd);
105 mpz_set(f2,v);
106 gmp_printf("Factor 1: %Zd\n", f1);
107 gmp_printf("Factor 2: %Zd\n", f2);
108 fin=clock();
109 tt=0;
110 }

112 gmp_randclear(r_state);

27
113 mpz_clear(u);
114 mpz_clear(gcd);
115 mpz_clear(ord);
116 mpz_clear(f1);
117 mpz_clear(f2);
118 }
119 mpz_clear(v);
120 mpz_clear(anterior);

122 printf("Tiempo(ms): %6.3Lf\n",(long double)(fin-ini)/(CLOCKS_PER_SEC


/1000));

124 return 0;
125 }

3.4. Trabajos (jobs) en CONDOR


Vale la pena mostrar cómo hicimos para distribuir los distintos trabajos sobre la grid. CONDOR
se encarga de mandar trabajos a los computadores que están en la grid de acuerdo a un archivo que
le indica qué hacer y bajo qué polı́ticas. Esta información está contenida en un archivo .condor y
está escrito en un lenguaje propio de Condor. El formato de este archivo es similar al .properties
que se usa en JAVA.

Para cada una de las pruebas usamos el mismo archivo, en el cual se indica la ubicación del
ejecutable, el universo y bajo qué nombre y en qué lugar guarda los archivos de salida, de registro
y de error (Output, Log, Error). En estos archivos queda, lo que escribe el programa en la consola
(Output), el registro de qué máquina envió a cuál un trabajo, ası́ como su posterior resultado (Log),
y en caso de que el programa termine de manera no esperada registra este evento (Error). Además
el número de veces que enviará el trabajo a las distintas máquinas que componen la grid.

Código 8: Archivo .condor que indica a CONDOR cómo distribuir los trabajos.
1 #moo.condor
2 Universe = vanilla
3 initialdir = /usr/programa
4 Executable = /usr/programa/factor

6 Arguments = //insertar aquı́ el número a factorizar e.g. Arguments =


11766219

8 Log = /usr/prueba/factorLog.$(process)
9 Output = /usr/prueba/factorOut.$(process)
10 Error = /usr/prueba/factorError.$(process)

12 Queue 15

En el código anterior, aparece $(process) esto indica que el archivo, ya sea de Log, Output
o Error, tendrá un número que indica el lugar en la cola en el que ése proceso en particular estaba.

28
Esto ayuda a asociar los archivos de salida más fácilmente.

29
Capı́tulo 4

Análisis y Validación

4.1. Pruebas
Con el fin de determinar la eficiencia de nuestra implementación, decidimos realizar la fac-
torización de distintos números basados en el siguiente criterio. Elegimos una serie de números
producidos a partir de un par de números primos, distintos a los triviales, es decir 2, 3, 5 o 7; en
general escogimos números primos grandes, que como producto de su multiplicación resultara uno
con una cantidad de dı́gitos mayor a la de estos números.

El proceso se realizó en dos fases. La primera consistió en factorizar números que no superaran
un orden de magnitud superior al millón, midiendo sus tiempos y asegurándonos que la respuesta
producida por el programa fuese la correcta. Con el fin de verificar tal respuesta, se usaron dos
métodos; en primera instancia nosotros creamos los números, por lo tanto sabı́amos de antemano
cuáles eran sus factores. En segundo lugar usamos al sitio web WolframAlpha [21] que es un Mo-
tor de Conocimiento Computacional, el cual presta un servicio web para consultas de todo tipo
optimizadas para cálculos matemáticos1 . Cuando introducimos un número de los elegidos para las
pruebas en el banner de búsqueda, este nos retorna una cantidad descomunal de información detal-
lada que se relaciona con el número ingresado; incluyendo sus factores primos, en caso de tenerlos.

Durante la segunda fase, buscábamos factorizar números mucho más grandes y que estuvieran
dentro del rango, en magnitud, del billón. La forma de verificar los resultados es consistente con
las descritas en el párrafo anterior. La razón de elegir tales números era poner a prueba nuestro
algoritmo con números cada vez más y más grandes, sin dejar a un lado sus logros a la hora de fac-
torizar números de tamaño menor al que se usarı́a en ámbitos profesionales, en donde el estándar
es manipular números de más de 150 dı́gitos, luego para el orden manejado en las pruebas el tiem-
po no deberı́a superar el segundo, en caso contrario podrı́amos esperar una cantidad de tiempo
desmesurada para números como el mencionado previamente.

4.1.1. Fase de Pruebas I


Documentación
Con el ambiente listo en el laboratorio de redes, subimos el archivo moo.condor descrito pre-
viamente en 3.4 con su argumento cambiado a uno de los número elegidos. Estos números son los
1
Como es bien sabido Wolfram es la empresa creadora del software matemático Mathematica [22]

30
presentes en la Tabla 4.1.

17897
40753
52907
88637
95129
97183
112451
126629
223733
333967

Tabla 4.1: Números a Factorizar en la Fase I

Con este archivo en la máquina maestro de CONDOR, iniciamos sesión con el usuario globus
y nos ubicábamos en la carpeta designada a este usuario conteniendo los comandos ejecutables de
CONDOR. Usamos el comando ./condor submit <ruta del Archivo .condor>. Tras
presionar Enter, el Maestro envı́a los trabajos a las tres máquinas disponibles, que están en modo
esclavo. Para acceder a los resultados, nos dirigimos a los directorios compartidos, definidos en el
código 8. Ejecutamos este mismo procedimiento con todos los número presentes en la tabla 4.1.

4.1.2. Resultados y Análisis I


Presentamos los resultados obtenidos durante el proceso de pruebas realizado durante la eta-
pa de pruebas I en los Anexos. Los resultados están resumidos en forma de gráfico, en donde
mostramos lo que se demoró el algoritmo en determinar los factores que componen a los números
de la Tabla 4.1.

De la primera fase de pruebas, podemos ver que en ninguna de las pruebas, el tiempo supera
al segundo. La resolución elegida para medir el tiempo en el programa es en milisegundos. Dado
al rango elegido de los números a factorizar, podemos aseverar que en este rango existe una alta
probabilidad de encontrar los factores de un número, en menos de un segundo dependiendo del
número elegido al azar. Por ejemplo para factorizar al número 88637 (ver Tabla 4.1), en la mayorı́a
de los casos, el tiempo es menor que medio segundo, o 500 milisegundos, sin embargo cuando se
elige de forma aleatoria el número 10141, se demora mucho más que los demás números elegidos.
Esto es por dos razones que extraemos de los datos, la primera es que luego de las iteraciones cor-
respondientes con este número resulta un resultado invalidado por el programa y vuelve a elegir
aleatoriamente un número hasta que llegue al resultado esperado. En este caso particular luego de
14 iteraciones, elije al número 57242 el cual es co-primo con 886372 y eficazmente obtiene los re-
sultados esperados. Aun con este gran número de iteraciones a tan bajo nivel (i.e. número pequeño)
se hizo en un tiempo menor a un segundo. La segunda está directamente relacionada con el número
elegido, en caso que este luego de muchas iteraciones llegue al resultado, nos querrı́a decir que hay
una estrecha relación entre el número elegido y el orden de la función. Este argumento se sustenta
en todos los gráficos y los datos, aún cuando no hay iteraciones adicionales a la inicial, con algunos
números se llega al resultado más rápido que con otros aunque con una diferencia no muy notoria
2
Por lo tanto el resultado no es trivial.

31
y hasta despreciable, cuando tenemos que esperar menos de un segundo para obtener el resultado.

Figura 4.1: Tiempo para Factorizar N=88637

Los resultados en cuanto al tiempo, varı́an en la mayorı́a de los datos para esta primera fase.
Es decir, para un mismo número elegido al azar, el cálculo se realizó en un tiempo mayor a otro
mediante la elección del mismo número. Esto puede deberse a que durante una ejecución dentro de
un esclavo, los recursos no eran suficientes para efectuar la operación más eficientemente y eran
por consiguiente usados por el otro esclavo mientras hacia los cálculos para encontrar la solución.
Sin embargo, en todos los casos de esta primera fase, hay una diferencia de a lo sumo 10 milise-
gundos entre experimentos que eligen un mismo número aleatorio inicial para factorizar un número.

4.1.3. Fase de Pruebas II


Documentación
Con el mismo ambiente de la fase I en el laboratorio de redes, modificamos el archivo moo.condor
con los siguientes números como argumentos del archivo ası́ como se describió en 3.4. Los números
elegidos, son:
Con este archivo nuevamente modificado y ubicado en la máquina maestro de CONDOR,
seguimos los mismos pasos descritos en la fase I.

4.1.4. Resultados y Análisis Fase II


Durante la segunda fase, los resultados obtenidos nos muestran una serie de información funda-
mental para el análisis del proyecto. Un hecho importante es que superamos en el 93 % de los casos

32
3080681
6980653
19783333
31363807
42446629
88544111
109822469
224929877
631563797
1176621989

Tabla 4.2: Numeros a Factorizar en la Fase II

el segundo en tiempo de ejecución, el cual era nuestro lı́mite durante las pruebas. De hecho, la
tendencia del tiempo que pasa a medida que incrementamos el número a factorizar, aumenta igual-
mente. Sin embargo, como lo notamos en la Fase I existen números que resultan de la elección
aleatoria con un tiempo reducido en cuando a la ejecución del programa para obtener los factores
aún cuando este número es co-primo con el número a factorizar, lo que finalmente hace el cálculo
más difı́cil. Lo interesante en este caso, es que estos números nos dan una visión más clara de la
ventaja de usarlos. Por ejemplo al factorizar el número 88544111 (ver Figura 4.2, en promedio
se demora el programa un tiempo de 94952 milisegundos para encontrar los factores aún si tiene
que iterar más de una vez hasta que encuentre los factores primos. Cuando el programa obtuvo
29865109 se demoró tan solo alrededor de medio segundo en obtener los números que componı́an
a 88544111.

Figura 4.2: Tiempo para Factorizar N=88544111

Cuando la magnitud del número anteriormente escogido se duplicó, obtuvimos un resultado que

33
se sujeta a nuestras sospechas de la Fase I. El número a factorizar es 224929877 (ver Figura 4.3,
el tiempo mayor para encontrar los factores fue de casi media hora con 36373283 aleatoriamente
escogido. Sin embargo, cuando el programa eligió 43265289 se demoró tan solo 20 milisegundos,
superando todas nuestras expectativas.

Figura 4.3: Tiempo para Factorizar N=224929877

La relación presente de manera inherente en nuestro problema respecto al número a factorizar


y el número con el que empieza el programa a encontrar el par de factores primos es muy estrecha
a la hora de medir el tiempo de ejecución del programa, ya que se va a demorar, en principio3 , tanto
como necesite hasta encontrar el orden y es en base a estos dos números que el orden surge.

Basados en estos hechos buscamos confrontar nuestros resultados con las demás pruebas y
aunque no siempre obtuvimos tiempos satisfactorios, se podı́a encontrar un elemento dentro de es-
ta fase que resultara con un tiempo mı́nimo de ejecución; respecto a los valores aleatorios obtenidos
por el programa.

A pesar de los resultados encontrados previamente, incluyendo la relación entre los números,
evidenciamos un problema al poner a prueba el programa para que intentara factorizar el número
1176621989 (ver Figura 4.4. Dentro de nuestro número de iteraciones en solo dos oportunidades
llegó al resultado esperado, uno de ellos con un tiempo cercano a los 20 minutos en tiempo de
ejecución y el otro a los 5 minutos. En el resto de pruebas se generaba un error informando que la
librerı́a GMP no puede alocar memoria. Esto en principio no nos generaba un indicio sobre lo que
realmente pasaba ya que considerábamos4 que la librerı́a llenaba a cabalidad nuestras necesidades.
Examinando el algoritmo rigurosamente e intentando dilucidar en qué punto podrı́a fallar, la re-
spuesta daba como origen el orden mismo. Aunque no la generación como tal, pero lo que sucedı́a
3
Esto se evidencia en la arquitectura del programa
4
Y aun lo hacemos.

34
luego de tenerlo.

Figura 4.4: Tiempo para Factorizar N=1176621989

Dentro del algoritmo y luego su implementación en 2.3.2 y 3.3.2 respectivamente, vimos que la
memoria que usan las operaciones que el programa implementa, como la exponenciación modular
y el máximo común divisor, no superan al número más grande dentro de las entradas del programa
y las generadas por el mismo. El número más grande que el programa maneja es aquel ingresado
para ser factorizado n y el aleatorio a siempre será menor que este. Más aún, el orden puede ser
tan grande como n siendo n − 1 el valor que tome en el peor de los casos. Esto refleja un problema
dentro del algoritmo, ya que en el peor de los casos va a terminar haciendo una exponenciación -a
la hora determinar los factores teniendo previamente el orden-, de un número casi tan grande como
n y elevándolo a un número tan grande como este; ocupando una gran cantidad de espacio junto
con lo que ya venı́a haciendo.

Con el fin de verificar este hecho decidimos implementar un programa que únicamente se en-
cargara de ejecutar la exponenciación entre dos números indicando su base y el exponente, usando
la librerı́a GMP. Evidenciamos que al efectuar esta operación con números del orden mencionados
previamente, el tiempo consumido era muy significativo y el tamaño de lo que imprimı́a como re-
sultado superó por mucho lo que esperábamos. El manejar tal cantidad de información se vuelve
poco práctico ya que se mantienen en memoria ambos números que toca operar, y ası́ sacar los
factores primos del número a factorizar.

35
Conclusiones y Comentarios Finales

Conclusiones
Durante este trabajo nos preocupamos por implementar eficientemente una versión adaptada
del algoritmo de Shor, que como describimos, dentro del régimen cuántico resuelve el problema
de la factorización de un número eficientemente; de manera más rápida que el mejor algoritmo
clásico que conocemos5 . Lo anterior con el fin de analizar la efectividad con la que el sistema de
encripción de llaves públicas RSA funciona y su vigencia que indiscutiblemente mantiene actual-
mente. Su efectividad como vimos reside en el hecho de cuán intratable es clásicamente factorizar
un número de magnitudes colosales. Por lo cual creemos que por una cantidad considerable de
tiempo seguirá siendo la elección preferida por muchos a la hora de encriptar mensajes entre un par
de interesados.

Diseñamos la forma de implementar el algoritmo cuántico considerando limitaciones prácticas


que entran en juego a la hora de efectuar los cálculos rápidamente. El diseño estuvo fuertemente
influenciado por la arquitectura sobre la cual trabajamos, es decir una grid. El hecho de disponer de
varios computadores trabajando para hallar los factores primos nos indicó usarlos independiente-
mente para que dependiendo de condiciones iniciales distintas pudieran lograr el mismo resultado
solo que en un tiempo menor, en lo cual estamos inicialmente dependiendo para hacer la com-
paración contra el General Number Field Sieve. Este modelo incluye el conteo secuencial para
encontrar el orden de la función caracterı́stica para resolver el problema de la factorización desde
un punto de vista mecánico cuántico.

La implementación se realizó en C++ y en C usando GMP en el segundo caso. La razón in-


cluı́a el hecho de manejar números más grandes que aquellos manejados nativamente por C/C++,
puesto que la implementación realizada en C++ nos presentó dificultades en este tema, por lo que
finalmente nos vimos obligados a usar esta librerı́a. Este hecho nos permitió realizar las pruebas
necesarias para llegar a determinar la validez de nuestra implementación y su pertinencia en este
ámbito.

Durante la fase de pruebas buscábamos encontrar los factores de los números propuestos en
sus factores primos lo más rápido posible. Establecimos un tiempo lı́mite el cual considerábamos
crı́tico a la hora de evaluar el rendimiento de la implementación realizada. En base a este obtuvimos
resultados que nos condujeron a afirmar que el orden iba a depender del a inicialmente elegido. Por
lo tanto, buscar estos números que como resultado permiten que el algoritmo devuelva la respuesta
buscada de forma rápida, es una tarea en la cual podrı́a profundizarse. Encontramos además, que
aunque con el método del orden de manera eficaz encontramos la factorización prima, este número
-el que nos indica el periodo de la función- puede ser tan grande como el número que buscamos
5
Recomiendo referirse a Case [23] para aquellos que estén interesados en saber el funcionamiento de este algoritmo.

36
factorizar. Esto genera un problema a nivel práctico ya que uno de los pasos dentro del algoritmo
es hacer una exponenciación, la cual en el peor de los casos va a terminar generando un número
con billones de dı́gitos. Indicándonos que vamos a estar limitados por la memoria principal del
computador y, claramente por el tamaño del número a factorizar.

Durante la fase de pruebas, tanto la I como la II, se produjo en todos los experimentos resultados
que conducı́an a la identificación de aquellos factores primos que componı́an a los números elegidos
durante este par de etapas, menos en un caso. En este último solo fue satisfactoria en un par de
oportunidades, pero nos ayudó a dilucidar un problema que, como ya lo mencionamos, está presente
en el algoritmo y amerita un estudio futuro con el fin de abordar este problema el cual para un
ciertos números produce resultados favorables, en otras palabras el algoritmo es eficaz y eficiente
con estos números en particular. El hecho de tener complicaciones al manejar números muy grandes
en un único computador nos sugiere que el algoritmo podrı́a ser igualmente práctico si lográramos
manejar números mucho más grandes mientras incorporamos aquellos números que generan un
orden pequeño. Esto podrı́a hacerse intercomunicando procesos entre computadores y ası́ el tamaño
y las operaciones de la memoria podrı́an compartirse para lograr manejar números más grandes
que los ya manejados por GMP. Este nuevo diseño no cambiarı́a drásticamente la elección hecha
inicialmente, ya que finalmente vamos a designar a varios computadores dentro de la grid a que
calculen por separado los factores, solo que en este caso trabajarı́an un par o más computadores,
compartiendo los recursos.

Trabajo Futuro
Hemos seleccionado una lista que consideramos esencial a la hora de continuar en este proyecto:

El algoritmo puede ser significativamente optimizado a la hora de encontrar una heurı́sti-


ca que nos lleve a aquellos números que producen como orden de la función f (x) = ax
(mód n) un x pequeño6 , y ası́ efectuar menos operaciones a la hora de encontrar los factores
primos que componen al número a factorizar n.

Implementar una librerı́a en C o Java, que permita hacer representaciones de números y


cálculos sobre estos, usando los recursos de varios computadores que pertenezcan a una grid.
Esto puede hacerse por medio de MPI [24].

Durante la decisión de usar la arquitectura finalmente planteada tuvimos en cuenta cómo


funcionaba la arquitectura de CONDOR y GLOBUS para conectar una serie de computadores
dentro de una grid. Podrı́a resultar un nuevo diseño al tener en cuenta otras tecnologı́as,
por ejemplo peer-to-peer. Cada máquina podrı́a ser independiente y luego de determinar las
condiciones necesarias para iniciar un proceso distribuido de la tarea a asignar; a diferencia
de la arquitectura actual, una máquina es la que se encarga de enviar los trabajos.

Vimos que la Mecánica Cuántica permite factorizar un número eficientemente, y aunque


no existan aún Computadores Cuánticos, para cuando existan RSA no será una opción para
transmitir información de manera confidencial. Esto lleva a considerar el estudio de algorit-
mos que incluso en el régimen Cuántico no sean fáciles de invalidar.

6
Respecto al número a factorizar.

37
Anexos

5.1. Gráficas de Resultados


Presentamos los resultados de las pruebas con sus respectivas gráficas, para cada fase se indica
en una tabla el número aleatorio elegido por el programa, el tiempo que demoró en encontrar
los factores y, en la eventualidad que el número elegido no haya servido, el número con el que
finalmente se factorizó el número y sus iteraciones hasta encontrarlo.

Figura 5.5: Tiempo para Factorizar 17897

38
Iteraciones nFinal Aleatorio Tiempo
1 15374 3310 20
15877 0
3764 0
3764 0
1944 0
15877 0
13921 10
1944 0
15877 0
1944 0
13921 0
1 15301 11083 10
1 17711 17046 20
13921 0
1 15301 11083 10
Tabla 5.3: Resultados para Factorizar 17897

39
Figura 5.6: Tiempo para Factorizar 40753

40
Iteraciones Número Final Número Aleatorio Tiempo
16599 0
17273 20
17 25727 23796 700
17273 20
16599 0
20836 20
1 9986 31502 80
20836 20
1 25727 21257 40
1 9986 31502 80
20836 30
1 25727 21257 40
1 9986 31502 80
19689 30
1 25727 21257 20
Tabla 5.4: Resultados para Factorizar 40753

Figura 5.7: Tiempo para Factorizar 52907

41
Iteraciones Número Final Número Aleatorio Tiempo
37334 10
771 0
1 15159 26016 0
1 15159 26016 10
28278 30
3439 0
28278 30
14624 10
3439 0
28278 30
14624 20
3439 0
52030 40
14624 10
29685 50
Tabla 5.5: Resultados para Factorizar 52907

Figura 5.8: Tiempo para Factorizar 88637

42
Iteraciones Número Final Número Aleatorio Tiempo
5 45242 30743 410
7 16684 29064 200
2 38143 2355 170
77972 70
1 38143 75858 130
77972 60
1 57242 9685 50
70858 90
16684 60
45242 2355 140
16684 60
14 57242 10141 940
1 45242 2355 140
16684 60
Tabla 5.6: Resultados para Factorizar 88637

Figura 5.9: Tiempo para Factorizar 95129

43
Iteraciones Número Final Número Aleatorio Tiempo
1 88528 64891 200
24289 20
82535 10
11224 80
1 55350 79371 150
82535 0
1 10153 41492 20
84004 100
84004 90
19 55350 73535 910
71880 10
71880 20
11224 90
11224 90
71880 10
Tabla 5.7: Resultados para Factorizar 95129

Figura 5.10: Tiempo para Factorizar 97183

44
Iteraciones Número Final Número Aleatorio Tiempo
59711 0
63482 0
36270 61593 10
87578 0
8633 20
87578 0
57619 72435 10
25032 20
25032 30
36270 61593 10
56711 10
56711 30
87578 0
36270 61593 10
56711 30
Tabla 5.8: Resultados para Factorizar 97183

Figura 5.11: Tiempo para Factorizar 112451

45
Iteraciones Número Final Número Aleatorio Tiempo
91123 130
77064 80
28257 80
109905 30
43991 20
110865 0
28257 80
46296 110
59601 80
64140 120
46296 120
59601 80
64140 120
109905 20
64140 120
Tabla 5.9: Resultados para Factorizar 112451

Figura 5.12: Tiempo para Factorizar 126629

46
Iteraciones Número Final Número Aleatorio Tiempo
118389 30
1 33431 12363 100
1 48473 105228 140
25569 10
1 48473 105228 1470
1 33431 12363 100
25569 20
101 48643 60479 800
1 33431 12363 100
25569 0
25569 0
1 116639 108391 20
1 60707 46654 10
1 116639 108391 20
1 116639 108391 20
Tabla 5.10: Resultados para Factorizar 126629

Figura 5.13: Tiempo para Factorizar 223733

47
Iteraciones Número Final Número Aleatorio Tiempo
112986 0
150654 10
141997 10
150654 20
109553 130
1 40424 40325 20
150654 20
1 40424 40325 30
109553 110
150654 20
1 220751 52681 80
1 40424 40325 20
37042 110
1 220751 52681 90
55486 0
Tabla 5.11: Resultados para Factorizar 223733

Figura 5.14: Tiempo para Factorizar 333967

48
Iteraciones Número Final Número Aleatorio Tiempo
270195 0
157544 0
19180 100
264895 0
270195 0
19180 100
264895 0
200759 40
264895 0
200759 30
59091 120
264895 0
200759 40
192901 0
59091 80
Tabla 5.12: Resultados para Factorizar 333967

49
Iteraciones Número Final Número Aleatorio Tiempo
386012 480
179860 0
2758540 150
179860 0
2758540 150
179860 0
3053322 950
2502374 60
743737 20
2502374 60
743737 20
743737 20
2502374 70
2732003 30
132657 300
Tabla 5.13: Resultados para Factorizar 3080681

Figura 5.15: Tiempo para Factorizar 3080681

50
Figura 5.16: Tiempo para Factorizar 6980653

Iteraciones Número Final Número Aleatorio Tiempo


596873 2270
1575865 620
5303538 2480
4137785 3610
1 1471412 2932124 620
1 2227153 2721839 4120
2027412 3890
5253536 600
2737122 290
2737122 290
5215321 1930
1 2295225 6749779 2450
1148659 660
1148659 260
1938551 3850
Tabla 5.14: Resultados para Factorizar 6980653

51
Figura 5.17: Tiempo para Factorizar 19783333

Iteraciones Número Final Número Aleatorio Tiempo


15849779 3020
2 9874766 19067953 3920
1 5020445 7379133 3050
5663689 2020
5020445 370
1 9188029 17275731 2620
19294645 650
2902216 1940
1 9702739 8648758 2520
1 15686525 15491101 2400
2 8405159 14940012 6110
9702739 380
18444715 380
9438114 2180
18444715 380
Tabla 5.15: Resultados para Factorizar 19783333

52
Figura 5.18: Tiempo para Factorizar 31363807

Iteraciones Número Final Número Aleatorio Tiempo


1 29092423 1263273 54340
10075231 18540
22608501 43770
1 27537750 1482020 47150
930471 35940
22457165 35710
14160786 37980
1 22064670 27429277 55890
22064670 35810
18877080 36070
7711861 36190
1 26580766 10896072 19030
17016079 17880
1 27171827 3320943 56760
4821772 35640
Tabla 5.16: Resultados para Factorizar 31363807

53
Figura 5.19: Tiempo para Factorizar 42446629

Iteraciones Número Final Número Aleatorio Tiempo


42151975 50810
1 14803484 10338113 51100
1 38219831 87219831 73820
39401638 8810
5 34953080 27787892 122570
12114870 48770
14236019 52640
36621876 9580
2 19366895 33268221 64880
3 30504608 41359690 127000
7931717 220
7931717 220
35187417 52100
1 28901060 25368196 52130
1 10009843 40947350 60040
Tabla 5.17: Resultados para Factorizar 42446629

54
Figura 5.20: Tiempo para Factorizar 88544111

Iteraciones Número Final Número Aleatorio Tiempo


1 56305678 65583579 547000
3494081 52770
2 22771205 55838215 78940
75355408 16300
1 45236712 37741865 48940
80742890 3590
3 8535310 47911113 199260
45236712 34580
3 68264317 54344967 102720
38855148 53780
29865109 540
78046956 54180
1 33157767 46048446 113250
57784727 5260
45571246 113170
Tabla 5.18: Resultados para Factorizar 88544111

55
Figura 5.21: Tiempo para Factorizar 109822469

Iteraciones Número Final Número Aleatorio Tiempo


101314925 33090
104236843 4580
15570567 730
493364943 34300
57943003 33770
70586754 1460
62569919 980
49762410 32290
19282857 780
96488193 21560
62691488 20530
28557589 4180
31512247 33920
32873660 62000
Tabla 5.19: Resultados para Factorizar 109822469

56
Figura 5.22: Tiempo para Factorizar 224929877

Iteraciones Número Final Número Aleatorio Tiempo


4 77065311 197621688 644040
4 582942494 182314213 1048470
2 171526367 49396899 552870
7 105693957 36373283 1536710
117115774 291400
1 192194378 92147214 401090
3 51182826 176518252 571870
80909506 290940
3 41616778 150857830 728740
43265289 30
43265289 20
49828176 275940
51728701 292020
4 111189050 138035665 374710
106158836 1480
Tabla 5.20: Resultados para Factorizar 224929877

57
Figura 5.23: Tiempo para Factorizar 631563797

Iteraciones Número Final Número Aleatorio Tiempo


594667777 110740
457864953 461920
89207515 141520
51606093 52650
215964024 97660
219358537 138350
62698359 194940
235786057 135770
262589856 450380
139845650 127620
564193789 492070
369755893 100270
11970264 405010
224377615 445070
1 318862134 191860843 300720
Tabla 5.21: Resultados para Factorizar 631563797

58
Iteraciones Número Final Número Aleatorio Tiempo
198973529 284580
1138410736 1180520
Tabla 5.22: Resultados para Factorizar 1176621989

Figura 5.24: Tiempo para Factorizar 1176621989

59
Bibliografı́a

[1] D. Kahn, The Codebreakers: The Story of Secret Writing. Scribner, New York, 1996, p. 77.

[2] M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, 1st ed.
Cambridge University Press, October 2000, pp. 641–643.

[3] D. E. Knuth, Art of Computer Programming, Volume 2: Seminumerical Algorithms (3rd Edi-
tion) (Art of Computer Programming Volume 2), 3rd ed. Addison-Wesley Professional,
November 1997, p. 403.

[4] A. K. Lenstra, H. W. Lenstra, M. S. Manasse, and J. Pollard, “The factorization of the ninth
fermat number,” Mathematics of Computation, vol. 61, no. 203, pp. 319–349, 1993. [En
Lı́nea]. Disponible: http://www.jstor.org/stable/2152957

[5] Integer factorization source code. Accedido el 10 de Noviembre de 2009. [En Lı́nea].
Disponible: http://www.boo.net/∼jasonp/qs.html

[6] D. Deutsch, A. Ekert, and R. Lupacchini, “Machines, logic and quantum physics,” 1999. [En
Lı́nea]. Disponible: http://www.citebase.org/abstract?id=oai:arXiv.org:math/9911150

[7] M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, 1st ed.
Cambridge University Press, October 2000.

[8] ——, Quantum Computation and Quantum Information, 1st ed. Cambridge University Press,
October 2000, pp. 233 – 234.

[9] G. Benenti, G. Casati, and G. Strini, Principles of Quantum Computation And Information:
Basic Tools And Special Topics. River Edge, NJ, USA: World Scientific Publishing Co., Inc.,
2007.

[10] C. Cohen-Tannoudji, B. Diu, and F. Laloe, Quantum Mechanics (2 vol. set). Wiley-
Interscience, October 2006.

[11] D. E. Knuth, Art of Computer Programming, Volume 2: Seminumerical Algorithms (3rd Edi-
tion) (Art of Computer Programming Volume 2), 3rd ed. Addison-Wesley Professional,
November 1997.

[12] ——, Art of Computer Programming, Volume 2: Seminumerical Algorithms (3rd Edition) (Art
of Computer Programming Volume 2), 3rd ed. Addison-Wesley Professional, November
1997, p. 338.

[13] What is condor? Accedido el 17 de Noviembre de 2009. [En Lı́nea]. Disponible:


http://www.cs.wisc.edu/condor/description.html

60
[14] The globus alliance. Accedido el 17 de Noviembre de 2009. [En Lı́nea]. Disponible:
http://www.globus.org/

[15] Condor’s success stories. Accedido el 17 de Noviembre de 2009. [En Lı́nea]. Disponible:
http://www.cs.wisc.edu/condor/success/index.html

[16] Examples of the globus alliance’s impact. Accedido el 17 de Noviembre de 2009. [En Lı́nea].
Disponible: http://www.globus.org/alliance/impact/

[17] M. Hirvensalo, Quantum Computing, ser. Natural Computing Series. Springer, 2004.

[18] S. J. Lomonaco, “Shor’s quantum factoring algorithm,” 2000. [En Lı́nea]. Disponible:
http://arxiv.org/abs/quant-ph/0010034

[19] J. Gruska, Quantum Computing. Shoppenhangers Road, MaidenHead, Berkshire, SL6 2QL,
ENGLAND: McGraw-Hill, 1999.

[20] Gnu multiple precision arithmetic library. Accedido el 26 de Noviembre de 2009. [En Lı́nea].
Disponible: http://gmplib.org/

[21] Wolfram alpha. Accedido el 26 de Noviembre de 2009. [En Lı́nea]. Disponible:


http://www.wolframalpha.com/

[22] Wolfram research: Mathematica, technical and scientific software. Accedido el 26 de


Noviembre de 2009. [En Lı́nea]. Disponible: http://www.wolfram.com/

[23] M. Case. A beginner’s guide to the general number field sieve. Accedido el 30 de Noviembre
de 2009. [En Lı́nea]. Disponible: http://islab.oregonstate.edu/koc/ece575/03Project/Case/
paper.pdf

[24] Open mpi: Open source high performance computing. Accedido el 30 de Noviembre de
2009. [En Lı́nea]. Disponible: http://www.open-mpi.org/

61

Vous aimerez peut-être aussi