#fhe #lattice #tfhe #run-time

parasol_runtime

This crate supports the Parasol CPU, providing key generation, encryption, and FHE evaluation functionality

1 unstable release

Uses new Rust 2024

new 0.9.0 Apr 11, 2025

#1551 in Cryptography


Used in parasol_cpu

AGPL-3.0-only

5MB
30K SLoC

Rust 25K SLoC // 0.0% comments OpenCL 2K SLoC Metal Shading Language 1K SLoC // 0.1% comments CUDA 1K SLoC // 0.1% comments WebGPU Shader Language 805 SLoC // 0.1% comments Python 44 SLoC

Parasol Runtime

This crate contains the Sunscreen Parasol runtime, which supports running programs over encrypted data with the Parasol processor. This crate provides key generation, encryption, and decryption functionality. Additionally, you can use the fluent module to directly compose and run TFHE circuit bootstrapping circuits:

use crate::{
    fluent::{FheCircuitCtx, PackedUInt}, ComputeKey, Encryption, Evaluation, L1GgswCiphertext, L1GlweCiphertext, PublicKey, SecretKey, UOpProcessor, DEFAULT_128
};
use std::sync::Arc;

fn multiply_16_bit() {
    // Generate our keys.
    let sk = SecretKey::generate_with_default_params();
    let ck = Arc::new(ComputeKey::generate_with_default_params(&sk));
    let pk = PublicKey::generate(&DEFAULT_128, &sk);

    // Generate the things needed to encrypt data and run our circuit.
    let enc = Encryption::new(&DEFAULT_128);
    let eval = Evaluation::new(ck, &DEFAULT_128, &enc);
    let (mut proc, flow_control) = UOpProcessor::new(16384, None, &eval, &enc);

    // Encrypt our 2 16-bit unsigned inputs, each packed into a single GLWE ciphertext. 
    let a = PackedUInt::<16, L1GlweCiphertext>::encrypt(42, &enc, &pk);
    let b = PackedUInt::<16, L1GlweCiphertext>::encrypt(16, &enc, &pk);

    // Build a circuit that first `unpack()`s each encrypted value into 16 ciphertexts.
    // Next, we convert our encrypted values to L1GgswCiphertext, which will insert 
    // circuit bootstrapping operations.
    // The fluent types ensure at compile time that you only create valid graphs
    // and guarantees you've `convert()`ed ciphertexts appropriately.
    let ctx = FheCircuitCtx::new();
    let a = a
        .graph_input(&ctx)
        .unpack(&ctx)
        .convert::<L1GgswCiphertext>(&ctx);
    let b = b
        .graph_input(&ctx)
        .unpack(&ctx)
        .convert::<L1GgswCiphertext>(&ctx);

    // With our data in GGSW form, we can now multiply the two encrypted integers, which will result in
    // L1GlweCiphertexts that we re`pack()` into a single ciphertext.
    let c = a
        .mul::<L1GlweCiphertext>(&b, &ctx)
        .pack(&ctx, &enc)
        .collect_output(&ctx, &enc);

    proc.run_graph_blocking(&ctx.circuit.borrow(), &flow_control);

    assert_eq!(c.decrypt(&enc, &sk), 672);
}

Dependencies

~19MB
~359K SLoC