Développer un coprocesseur FHE sur TEE à l’aide de JavaScript

xcRom1.dot ⭕️
Phala & PhalaWorld Français
9 min readJul 18, 2024

FHE (Fully Homomorphic Encryption) possède une riche histoire dans le domaine de la cryptographie, gagnant son nom grâce à sa capacité distinctive à effectuer des calculs directement sur des données chiffrées sans exposer le contenu original. Aujourd’hui, il est utilisé dans de nombreux secteurs pour traiter des informations sensibles sans compromettre la vie privée des utilisateurs, notamment dans des domaines tels que la médecine, l’IA et, en particulier, la blockchain. Sur la blockchain, il offre une solution unique pour préserver la confidentialité des utilisateurs sur un grand livre ouvert, un défi qui n’est pas correctement relevé par les Zero-Knowledge Proofs (preuves de connaissance zéro).

Le schéma entièrement homomorphe révolutionnaire, présenté par Craig Gentry en 2009, a introduit la quintessence du concept de bootstrapping (consultez son Paper pour une explication simple). De grandes entreprises telles que Google et Microsoft proposent des solutions FHE sur mesure, permettant aux utilisateurs d’exécuter des calculs FHE sur leurs services cloud respectifs. Dans le même temps, des start-ups émergentes comme Zama ont été les premières à proposer des solutions FHE utilisant le schéma TFHE, qui accomplit remarquablement le bootstrapping en quelques dizaines de millisecondes seulement.

Source: Zama blog: Homomorphic Encryption 101

Dans cet article, nous allons analyser les risques de sécurité existant dans le schéma actuel de gestion des clés FHE. Ensuite, nous étudierons comment nous pouvons intégrer les environnements d’exécution de confiance (TEE) dans l’écosystème en tant que solution d’authentification à deux facteurs (2FA). Nous expliquerons également comment les développeurs peuvent s’appuyer sur les TEE pour mettre en place une gestion des clés FHE fiable et sécurisée grâce à notre technologie révolutionnaire.

Le MPC est l’un des principaux facteurs déterminants de la FHE.

Avant d’entrer dans le vif du sujet, il est important de préciser que le MPC (plus précisément, le MPC basé sur la signature de seuil) ne fait pas intrinsèquement partie du système FHE. Cependant, lorsque des projets entreprennent de construire une plateforme de calcul confidentielle (telle qu’une blockchain basée sur fhEVM), ils intègrent souvent un réseau MPC pour gérer la clé globale. Cette clé globale est utilisée pour chiffrer les données de tous les utilisateurs.

Pourquoi une clé globale est-elle nécessaire pour les calculs basés sur la FHE ?

Pour comprendre pourquoi, il faut d’abord comprendre ce qu’implique le calcul FHE, en citant l’ouvrage Homomorphic Encryption 101 de Zama :

Appliqué au chiffrement, cela signifie que le fait d’opérer sur des textes en clair (c’est-à-dire des données non chiffrées) ou sur des textes chiffrés (c’est-à-dire des données chiffrées) produira un résultat équivalent — en clair lorsqu’on opère sur des textes en clair et sous une forme chiffrée lorsqu’on opère sur des textes chiffrés. Par exemple, étant donné deux cryptogrammes c₁ et c₂ chiffrant respectivement les cryptogrammes x₁ et x₂, il existe une opération publique ⊕ telle que c₃=c₁ ⊕ c₂ est un chiffrement de x₃=x₁+x₂.

Il convient de noter que l’opération ⊕ ne peut être appliquée que lorsque c₁ et c₂ sont chiffrés avec la même clé. Cela est vrai même si les textes clairs sous-jacents x₁ et x₂ proviennent d’utilisateurs différents.

Prenons un cas d’utilisation réel : nous développons un jeton ERC20 confidentiel. Supposons qu’il existe une fonction_mintEncrypted(address to, inEuint128 memory encryptedAmount) qui mint une quantité spécifiéeamount de jetons à une certaine adresse. Dans cette fonction, nous devons mettre à jour le totalEncryptedSupply ode ce token, comme indiqué ci-dessous. Il serait impossible d’effectuer cette opération sur totalEncryptedSupply à chaque fois si le encryptedAmountn’est pas crypté avec la même clé :

function _mintEncrypted(address to, inEuint128 memory encryptedAmount) internal {
euint128 amount = FHE.asEuint128(encryptedAmount);
_encBalances[to] = _encBalances[to] + amount;
totalEncryptedSupply = totalEncryptedSupply + amount;
}

Source: https://github.com/FhenixProtocol/fhenix-contracts/blob/9e17d0ade2117a27ecda7b5d39847c06f458b68f/contracts/experimental/token/FHERC20/FHERC20.sol#L100-L103

Voici un aperçu de l’architecture des rollups FEVM de Phenix, où le réseau Threshold (Service) est reconnu comme le réseau MPC utilisé.

Source: https://www.fhenix.io/fhe-rollups-scaling-confidential-smart-contracts-on-ethereum-and-beyond-whitepaper/

Comme nous l’avons mentionné plus haut, en raison de la pratique d’écriture d’une application FHE, la clé est globalement utilisée par tous les utilisateurs pour crypter les données qu’ils envoient au serveur FHE, qui s’exécutera dans un état de cryptage. Ainsi, toute la sécurité du système repose sur la sécurité du réseau MPC et, comme nous le savons tous, les vérités du réseau MPC sont les suivantes :

  • Plus il y a de nœuds, plus la latence est importante.
  • Moins il y a de nœuds, plus il faut d’hypothèses de confiance.

Cela dit, il existe un risque de collusion inhérent au système actuel de PPM que l’on ne peut ignorer. Toutefois, cela ne signifie pas que nous ne pouvons rien faire pour atténuer le risque potentiel. Au contraire, nous pouvons ajouter un TEE comme 2FA pour couvrir le risque en déplaçant la gestion des clés vers le TEE (Trusted Execution Environments, une technologie permettant d’exécuter le programme dans une zone isolée à l’intérieur du CPU, prouvant que le programme est immuable et d’accès limité).

Pourquoi choisir TEE ?

Dans le monde de la blockchain, il y a un effort persistant pour établir la confiance sur la base d’assurances cryptographiques. Dans ce contexte, nous pourrions générer des preuves à connaissance nulle (comme les SNARK) pour chaque opération de cryptage/décryptage FHE afin de garantir que les données sont correctement traitées. Cependant, l’échange de données en temps réel introduit une surcharge substantielle par rapport aux opérations en texte clair, et les SNARK sont généralement encore plus coûteux en termes de calcul que l’opération qu’ils sont censés prouver.

C’est ce qui rend nécessaire l’utilisation de l’outil TEE. Par rapport à l’approche cryptographique, la solution matérielle mise en œuvre par le TEE n’ajoute pas de calcul supplémentaire, mais déplace simplement le calcul original dans un environnement isolé au sein de l’unité centrale. En implémentant le TEE dans la génération de clés et le décryptage de données, nous évitons des entraves significatives à la performance. Cela crée un environnement plus efficace et plus sûr pour la gestion des clés FHE.

Comme illustré ci-dessus, les nœuds MPC du système FHE sont maintenant exécutés à l’intérieur de TEE, au lieu de produire une preuve TEE lorsqu’ils agissent comme 2FA pour les zk-rollups, ici TEE est utilisé pour protéger la progression de la génération de clés dans le réseau MPC, et le cycle de vie complet de la clé est conservé à l’intérieur de TEE et ne sera jamais révélé au monde extérieur, plus important encore, la clé ne peut pas être touchée par l’homme, même d’une seule pièce. Le TEE lui-même peut garantir que le programme qu’il exécute est vérifiable, il est impossible pour quelqu’un de manipuler l’état. En outre, le transfert de données entre le TEE et le client est sécurisé par la communication TLS.

L’utilisation de l’ETA comme 2FA permet de réduire le risque d’une manière économique :

  • Si le TEE n’est pas compromis, il n’y a aucune chance de collusion ;
  • Si le TEE est compromis, ce n’est qu’en cas de collusion entre les nœuds que le système est rompu.

Avant de rédiger cet article, nous avons lancé une discussion sur le Forum de recherche Ethereum pour expliquer notre solution. Nous avons intégré la majeure partie du contenu de cette discussion dans cet article. Cependant, vous pouvez obtenir plus d’informations, telles que les avantages et les inconvénients de l’incorporation de TEE, en cliquant ici.

Voyons maintenant comment on peut exécuter la gestion des clés FHE — dans ce contexte, la transition entre la génération/le partage des clés et le déchiffrement des données au sein de TEE — à l’aide de JavaScript.

Création d’un système de gestion de clés FHE avec JavaScript

Nous disposons d’un Runtime JS personnalisé basé sur QuickJS. Le code JavaScript peut être déployé sur les travailleurs Phala TEE. Nous avons conçu une machine virtuelle WASM basée sur wasmtime, pour faciliter son exécution dans SGX avec le SDK Gramine.

Tout d’abord, vous devrez faire quelques préparations avant d’exécuter l’exemple complet, même si vous ne faites que développer et que vous n’avez pas de machine SGX à votre disposition. Nous supposons que vous avez déjà installé la chaîne d’outils Rust sur votre machine. Si ce n’est pas le cas, vous pouvez vous référer à ce tutoriel. Pour exécuter un exemple de programme JavaScript, suivez les instructions de ce README du dépôt GitHub. Une fois que vous êtes familiarisé avec le tutoriel, explorons comment construire la gestion de clés FHE avec le paquetage Zama TFHE wasm binding.

Pour l’instant, nous n’avons tenté de générer des clés qu’avec la bibliothèque TFHE de Zama, mais en théorie, toute autre bibliothèque devrait fonctionner de la même manière. Zama a fourni une liaison WASM pour sa bibliothèque tfhe-rs, qui exporte des API client pour prendre en charge la génération de clés, le cryptage et le décryptage. Cela simplifie considérablement la tâche et nécessite une compréhension minimale des détails sous-jacents du FHE. Après avoir créé un projet avec npm, votre première étape sera d’installer les dépendances.

$ npm install node-tfhe

Ensuite, importez les modules nécessaires que vous utiliserez ultérieurement.

import {
CompactFheUint8List,
TfheCompactPublicKey,
TfheConfigBuilder,
TfheClientKey,
ShortintParameters,
ShortintParametersName,
} from "node-tfhe";

Générons maintenant la clé FHE à l’aide deTfheClientKey. Dans cette fonction, nous renvoyons un clientKey et unepublicKey. La publicKey est utilisé pour crypter les données envoyées au serveur FHE pour le calcul, et la clientKey sert de clé privée correspondante utilisée pour décrypter les résultats renvoyés par le serveur FHE.

function createTfheKeypair() {
const block_params = new ShortintParameters(
ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS,
);
const config = TfheConfigBuilder.default()
.use_custom_parameters(block_params)
.build();
const clientKey = TfheClientKey.generate(config);
let publicKey = TfheCompactPublicKey.new(clientKey);
publicKey = TfheCompactPublicKey.deserialize(publicKey.serialize());
return { clientKey, publicKey };
};

Une fois la paire de clés générée, vous pouvez crypter les données à l’aide de celle-ci. Nous avons donné ici un exemple de cryptage uint8 et expliqué comment le décrypter à l’aide de la clé privée.

const value = 100;
const encrypted = encryptUint8(value, publicKey);
console.log(`Encrypted: ${encrypted}`);

// You can sent it to FHE server for computing
// const encrypted = callServer(encrypted);

const compactList = CompactFheUint8List.deserialize(encrypted);
let encryptedList = compactList.expand();
encryptedList.forEach((v) => {
const decrypted = v.decrypt(clientKey);
console.log(`Decrypted: ${decrypted}`);
});

Le déploiement du code nécessite quelques configurations supplémentaires. Consultez l’exemple complet sur notre dépôt GitHub.

Travaux futurs

Pour développer un réseau MPC entièrement fonctionnel à l’aide de JavaScript, plusieurs aspects importants doivent encore être abordés. Le plus important d’entre eux est le partage des clés entre plusieurs nœuds à l’aide d’un protocole de partage sécurisé tel que le schéma de partage du secret de Shamir. Nous étudions activement des solutions et effectuons des tests de référence dans ce domaine. Dès que nous aurons progressé, nous prévoyons de partager nos conclusions avec la communauté. En jetant les bases dès maintenant et en relevant les défis, nous pensons ouvrir la voie à une solution avancée de gestion des clés FHE.

Glossaire

SGX (Software Guard Extensions)

Le Software Guard Extensions (SGX) d’Intel est un ensemble de codes d’instruction liés à la sécurité qui mettent en œuvre des environnements d’exécution de confiance (TEE), permettant à des parties d’un programme d’être exécutées dans un environnement sécurisé et isolé (enclave SGX) et protégées du système hôte lui-même.

Gramine

Un système d’exploitation de bibliothèque open-source (anciennement appelé Graphene-SGX), conçu pour permettre l’exécution d’applications Linux non modifiées dans un environnement sûr et efficace, en s’appuyant principalement sur SGX pour la sécurité.

QuickJS

QuickJS est un petit moteur Javascript intégrable. Il prend en charge la spécification ES2020, y compris les modules, les générateurs asynchrones et la prise en charge complète de l’annexe B (compatibilité Web héritée). Il comprend également un petit binaire pour la REPL JavaScript de base et l’exécution de scripts JavaScript.

À propos de Phala Network

Phala Network est un coprocesseur pour l’IA alimenté par DePIN. Construisant à la pointe de l’innovation avec son contrat AI-Agent, Phala transforme les agents d’IA décentralisés. En tant que puissant réseau DePIN, la proposition de valeur centrale de Phala est de fournir un calcul vérifiable basé sur un réseau TEE décentralisé. Le contrat AI-Agent est la principale plateforme de développement sur le réseau TEE de Phala.

Restez à l’écoute pour d’autres mises à jour, car nous continuons à repousser les limites de ce qui est possible avec l’IA sécurisée et le traitement des données.

🍽 — Website | Twitter | Github

🥤 — Discord | Forum | Telegram |Italiano |Français | Persian | Korean

--

--