TFHE-rs uses WASM to expose a JS binding to the client-side primitives, like key generation and encryption, of the Boolean and shortint modules.
There are several limitations at this time. Due to a lack of threading support in WASM, key generation can be too slow to be practical for bigger parameter sets.
Some parameter sets lead to FHE keys that are too big to fit in the 2GB memory space of WASM. This means that some parameter sets are virtually unusable.
First steps using TFHE-rs JS on WASM API
Setting-up TFHE-rs JS on WASM API for use in nodejs programs.
To build the JS on WASM bindings for TFHE-rs, you need to install wasm-pack in addition to a compatible (>= 1.65) rust toolchain.
In a shell, then run the following to clone the TFHE-rs repo (one may want to checkout a specific tag, here the default branch is used for the build):
$gitclonehttps://github.com/zama-ai/tfhe-rs.gitCloninginto'tfhe-rs'......Resolvingdeltas:100% (3866/3866), done.$cdtfhe-rs$cdtfhe$ rustup run wasm-pack build --release --target=nodejs --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api
[INFO]: Compiling to Wasm......[INFO]: :-) Your wasm pkg is ready to publish at ...
The command above targets nodejs. A binding for a web browser can be generated as well using --target=web. This use case will not be discussed in this tutorial.
Both Boolean and shortint features are enabled here, but it's possible to use one without the other.
After the build, a new directory pkg is present in the tfhe directory.
Commented code to generate keys for shortint and encrypt a ciphertext
Be sure to update the path of the required clause in the example below for the TFHE package that was just built.
// Here import assert to check the decryption went well and panic otherwiseconstassert=require('node:assert').strict;// Import the Shortint module from the TFHE-rs package generated earlierconst { Shortint } =require("/path/to/built/tfhe/pkg");functionshortint_example() {// Get pre-defined parameters from the shortint module to manage messages with 4 bits of useful// information in total (2 bits of "message" and 2 bits of "carry")let params =Shortint.get_parameters(2,2);// Create a new secret ClientKey, this must not be sharedconsole.log("Generating client keys...")let cks =Shortint.new_client_key(params);// Encrypt 3 in a ciphertextconsole.log("Encrypting 3...")let ct =Shortint.encrypt(cks,BigInt(3));// Demonstrate ClientKey serialization (for example saving it on disk on the user device)let serialized_cks =Shortint.serialize_client_key(cks);// Deserializationlet deserialized_cks =Shortint.deserialize_client_key(serialized_cks);// Demonstrate ciphertext serialization to send over the networklet serialized_ct =Shortint.serialize_ciphertext(ct);// Deserialize a ciphertext received over the network for examplelet deserialized_ct =Shortint.deserialize_ciphertext(serialized_ct);// Decrypt with the deserialized objectsconsole.log("Decrypting ciphertext...")let decrypted =Shortint.decrypt(deserialized_cks, deserialized_ct);// Check decryption works as expectedassert.deepStrictEqual(decrypted,BigInt(3));console.log("Decryption successful!")// Generate public evaluation keys, also called ServerKeyconsole.log("Generating compressed ServerKey...")let sks =Shortint.new_compressed_server_key(cks);// Can be serialized to send over the network to the machine doing the evaluationlet serialized_sks =Shortint.serialize_compressed_server_key(sks);let deserialized_sks =Shortint.deserialize_compressed_server_key(serialized_sks);console.log("All done!")}shortint_example();
The example.js script can then be run using node, like so: