Si bien el cifrado homomórfico completo (FHE) se logró originalmente en 2009, está comenzando a recibir más atención ahora que el poder de cómputo se ha puesto al día con sus demandas computacionales; sin embargo, el objetivo del cifrado homomórfico se remonta a una década.
Una búsqueda superficial encontrará múltiples definiciones para ello. Esta es la más directa y sucinta:
Una forma de cifrado que permite el cálculo de textos cifrados generando un resultado cifrado que, cuando se descifra, coincide con el resultado de las operaciones como si se hubieran realizado en texto sin formato.
— Massimo Bertaccini ( Algoritmos criptográficos )
Considere esa declaración por un momento. El cifrado homomórfico permite realizar operaciones en valores cifrados de modo que los resultados descifrados produzcan el resultado de las operaciones como si se hubieran realizado en los valores originales no cifrados. La primera mención que encontré es On Data Banks and Privacy Homomorphisms (1978) en la que los autores intentan evitar que los programadores del sistema accedan a los datos financieros confidenciales almacenados en un sistema local mediante un servicio remoto de tiempo compartido.
Los datos financieros confidenciales se almacenan en el banco de datos. Los servicios de tiempo compartido que computan los datos no implementan la seguridad adecuada. Los programadores del sistema tienen acceso a los datos financieros. El documento dice:
Use un homomorfismo de privacidad especial para cifrar sus datos de modo que la computadora de tiempo compartido pueda operar con los datos sin la necesidad de descifrarlos primero.
Dicho de otro modo, quiero eliminar el tratamiento de mis datos sin ceder el acceso a los mismos.
Para decirlo de otra manera, function(A, B) = function (A , B
) donde A and B
son valores cifrados de A y B, respectivamente. Esto permite que terceros calculen datos cifrados y proporcionen los resultados sin tener conocimiento del valor original. Con RSA, se pueden multiplicar dos valores cifrados con la misma clave y el producto se puede descifrar para obtener el producto de los valores cifrados.
Obtenga 5_6 usando RSA(5)_ RSA(6):
RSA(5) = (5^17) módulo 3233 = 3096
RSA(6) = (6^17) módulo 3233 = 824
3096*824 = 254864
RSA^-1(254864) = 254864^2753 (modificación 3233) = 30
5*6 = 30
Sin embargo, esto no funciona para la suma. RSA es un esquema de cifrado parcialmente homomórfico (PHE) en el sentido de que solo admite la multiplicación. La siguiente línea de tiempo muestra la progresión desde los esquemas (PHE) hasta el cifrado algo homomórfico (SHWE), que permite combinaciones limitadas de suma y multiplicación. Estas operaciones podrían repetirse hasta cinco veces antes de llegar a un resultado no válido. Luego apareció el primer esquema FHE de Craig Gentry que permitía sumas y multiplicaciones repetidas sin pérdida de fidelidad.
Desde 2009, los esquemas y bibliotecas de FHE han proliferado.
Biblioteca | esquemas | Idioma | Licencia |
---|---|---|---|
BFV... BGV... CKKS | Envoltorio C++/C# | MIT | |
Abrir FHE | BFV, BGV, CKKS, DM, CGGI | C++ | Licencia BSD de 2 cláusulas |
CKKS | C++ | Creative Commons 3.0 | |
TFHE (toroide) | Óxido | BSD-3-Cláusula-Borrar | |
TFHE | Óxido | BSD-3-Cláusula-Borrar | |
BFV... BGV... CKKS | Vamos | apache 2.0 | |
N/A: utiliza SEAL, PALISADE, HLib | Python, ventana acoplable | apache 2.0 |
Microsoft SEAL (Simple Encrypted Arithmetic Library) se desarrolla en C++ 17 junto con un contenedor de C#. Lanzado originalmente en 2015, todavía está en desarrollo activo. El repositorio de github incluye ejemplos detallados de C# que deben explorarse si está interesado en profundizar más.
Estos esquemas son compatibles con SEAL e incluyen operaciones homomórficas de suma, división, resta y exponenciación, pero no de división.
Brakerski-Gentry-Vaikuntanathan (BGV)/Fan-Vercauteren (BFV)
Números enteros (largos)
Usar si la precisión es un requisito
El cálculo es más lento que CKKS
Los valores cifrados con BGV se pueden usar con valores cifrados con BFV
Los valores cifrados con BGV/BVF no se pueden utilizar con valores cifrados con CKKS
Revisión de esquemas de cifrado homomórfico para campos finitos
Estos ejemplos usan el paquete Microsoft.Research.SEALNet Nuget y el esquema CKKS. Los rastreadores de salud, como FitBit y AppleHeath, requieren renunciar a un poco de privacidad. Recopilan información personal como el número de pasos y las coordenadas geográficas de los movimientos del usuario, la frecuencia de los latidos del corazón y otras estadísticas vitales. Con el cifrado homomórfico, estos agregadores de métricas de salud aún pueden operar con nuestros datos sin tener acceso a los datos sin procesar.
En este ejemplo simple, el cliente envía métricas de carrera que incluyen la distancia y el tiempo. El servidor agrega los datos cifrados y calcula la velocidad promedio.
Para comenzar, el cliente crea una clave pública y la comparte con el servidor. Se utiliza para cifrar datos y también para realizar operaciones aritméticas en datos cifrados. Tanto el cliente como el servidor usan un cifrador. El cliente genera y retiene una clave privada utilizada para el descifrado utilizada por el acertadamente llamado Decryptor .
Una parte malintencionada que intercepte los datos podría usar la clave pública en los datos cifrados y devolvérsela a la persona que llama falsificando el servidor. El servidor debe firmar el resultado y el cliente debe verificar la firma para asegurarse de que la devuelve una parte de confianza.
using Microsoft.Research.SEAL; protected SEALContext _context; private KeyGenerator _keyGenerator; private Encryptor _encryptor; private Decryptor _decryptor; protected IFitnessTrackerApiClient _apiClient; . . . _context = SEALUtils.GetContext(_config.Value.PolyModulusDegree, this.SchemeType); _keyGenerator = new KeyGenerator(_context); _keyGenerator.CreatePublicKey(out PublicKey publicKey); _keyGenerator.CreateRelinKeys(out RelinKeys relinKeys); _encryptor = new Encryptor(_context, _publicKey); _decryptor = new Decryptor(_context, _keyGenerator.SecretKey); . . . PublicKeyModelCKKS keyModelCKKS = new( SEALUtils.KeyToBase64String(_publicKey), SEALUtils.KeyToBase64String(relinKeys)); await _apiClient.SendPublicKeyCKKSAsync(keyModelCKKS);
Las claves de relinealización se pasan del cliente al servidor. Según Microsoft SEAL, no tienen otro significado semántico que el de reducir el tamaño del texto cifrado después de una operación de multiplicación.
En la línea de comando, el usuario ingresa el tiempo y la distancia.
Cada valor se codifica en PlainText, luego se cifra en Ciphertext y finalmente se codifica en base64 antes de enviarlo al servidor.
using Microsoft.Research.SEAL; var plaintext = new Plaintext(); _encoder.Encode(value, _scale, plaintext); var ciphertext = new Ciphertext(); _encryptor.Encrypt(value, ciphertext); using (var ms = new MemoryStream()) { ciphertext.Save(ms); return Convert.ToBase64String(ms.ToArray()); }
Dado que los esquemas de cifrado homomórfico no admiten la división (CKKS no es una excepción), el cliente debe ayudar al servidor. La fórmula de la velocidad es:
distancia/tiempo
Otra forma de escribirlo es,
distancia * (1/hora)
Entonces, el cliente envía:
RunItemCKKS metricsRequest = new( EncryptBase64(runItem.Distance), EncryptBase64(runItem.Time), EncryptBase64(1 / runItem.Time)); await _apiClient.AddNewRunningDistanceCKKSAsync(metricsRequest);
El servidor realiza una función de arranque similar creando un SEALContext utilizando solo la clave pública y las claves de relinealización, luego procesa la solicitud:
var distance = SEALUtils.BuildCiphertextFromBase64String(request.Distance, _sealContext); var time = SEALUtils.BuildCiphertextFromBase64String(request.Time, _sealContext); var timeReciprocal = SEALUtils.BuildCiphertextFromBase64String(request.TimeReciprocal, _sealContext); Ciphertext speed = new(); _evaluator.Multiply(distance, timeReciprocal, speed); _evaluator.RelinearizeInplace(speed, _relinKeys); _runListCKKS.Add(new EncryptedRunInfoCKKS(distance, time, speed));
Se usa un recíproco del tiempo para calcular la velocidad de la ejecución enviada y el método RelinearizeInplace reduce el tamaño del texto cifrado resultante . La distancia, el tiempo y la velocidad se guardan en una lista en memoria.
El método GetMetrics agrega la lista y devuelve:
número total de carreras
distancia total
Tiempo Total
velocidad media
public SummaryItemCKKS GetMetrics() { int count = _runListCKKS.Count; var totalDistanceCKKS = SumEncryptedValues(_runListCKKS.Select(m => m.Distance)); var totalTimeCKKS = SumEncryptedValues(_runListCKKS.Select(m => m.Time)); var totalSpeed = SumEncryptedValues(_runListCKKS.Select(m => m.Speed)); . . . protected Ciphertext SumEncryptedValues(IEnumerable<Ciphertext> encryptedData) { . . . Ciphertext encTotal = new(); _evaluator.AddMany(encryptedData, encTotal); return encTotal; . . . }
Para obtener la velocidad promedio, se usa el recíproco de la cuenta, así que en lugar de usar:
(suma de la velocidad)/número o carreras que usamos:
(suma de la velocidad) * (1/número de carreras)
Dado que el servidor realiza un seguimiento del número de envíos de ejecuciones, el número total de ejecuciones no es un valor cifrado. Ese valor sin cifrar se puede convertir a texto sin formato y usarse en una operación realizada en texto cifrado. Si bien este es un ejemplo simple, vale la pena señalar las implicaciones. El servidor puede proporcionar valores adicionales utilizados en los datos cifrados, lo que permite a los proveedores externos aplicar datos patentados a los cálculos con los datos cifrados proporcionados por el cliente.
En el siguiente ejemplo, el recuento total se convierte en un recíproco y se agrega a List<doble>. Las operaciones de CKKS esperan valores de lista cifrados, incluso si la lista solo contiene un único valor. Entonces, List<double> está codificado en PlainText . MultiplyPlainInplace multiplica la velocidad total por (1/número de ejecuciones), lo que da como resultado la velocidad promedio. Para ahorrar espacio, el resultado se aplica al texto cifrado totalSpeed y las claves de relinealización reducen el tamaño de la salida.
Plaintext encodedCountReciprocal = new(); List<double> averagePaceList = new(); double runCountReciprocal = 1 / (double)count; averagePaceList.Add(runCountReciprocal); _encoder.Encode(averagePaceList, _scale, encodedCountReciprocal); _evaluator.MultiplyPlainInplace(totalSpeed, encodedCountReciprocal); _evaluator.RelinearizeInplace(totalSpeed, _relinKeys);
Los valores se codifican en base64, se devuelven y se descifran en el cliente. El cliente da el paso adicional de convertir el texto sin formato descifrado en List<double> .
var payload = Convert.FromBase64String(encryptedDistanceText); using var ms = new MemoryStream(payload); var ciphertext = new Ciphertext(); ciphertext.Load(_context, ms); var decryptedText = new Plaintext(); _decryptor.Decrypt(cypherText, decryptedText); List<double> distanceList = new(); _encoder.Decode(decryptedText, distanceList);
El envío de los siguientes valores genera totales y el ritmo promedio calculado por un servicio que tabuló el total y el promedio sin descifrar los datos enviados por el cliente.
Millas | Hora |
---|---|
2.5 | 0:35:32.643 |
2.2 | 0:32:48.826 |
2.8 | 0:34:52.036 |
El servidor calcula los datos y devuelve las carreras totales, la distancia, el tiempo y el ritmo sin descifrar ninguno de los datos enviados.
Microsoft SEAL es un proyecto de Microsoft Research y no está listo para una aplicación de producción. Todas las clases implementan IDisposable y utilizan recursos no administrados. El código de producción necesitaría protegerse contra una fuga de memoria. La clase SEALContext no sigue el principio de responsabilidad única. Incluye métodos para BGV/BVF y CKKS. Además, CKKS admite operaciones con vectores, pero no sumas de vectores. Una sola List<double> se puede cifrar en un solo CipherText , pero no hay forma de sumar los valores en un solo CipherText. Se puede hacer con rotación vectorial , pero esa es una solución subóptima.
Este ejemplo de código de Fitness Tracker es una introducción simple a un tema complejo. Hay una serie de casos de uso convincentes con una lógica más complicada:
El cifrado homomórfico se ha utilizado en gran medida en el mundo académico y en prototipos. Las aplicaciones prácticas se han visto limitadas por la potencia informática requerida por los esquemas de cifrado homomórfico. La aceleración de GPU y los procesadores ASIC seguirán erosionando esta barrera. Intel está desarrollando el acelerador de hardware FHE , especialmente diseñado para esquemas de cifrado homomórfico, en colaboración con Microsoft y DARPA. NASDAQ también está financiando un proyecto de I+D que utiliza cifrado homomórfico con aprendizaje automático para la detección de fraudes. La comunidad FHE.org es un recurso excelente para los desarrollos más actuales en este espacio. Tiene un servidor Discord activo.
Todos los ejemplos de código de este artículo están disponibles en johniwasz/microsoft-seal-samples . Para obtener un ejemplo de Microsoft SEAL más detallado, consulte estos ejemplos de .NET .
También publicado aquí.