Unified Parameters

In many real life scenarios, we want to run different programs on an encrypted data set.

Let's imagine we have a private version of 23andMe run by Service Provider. Service Provider (SP) sets up the protocol and thus is responsible for choosing the appropriate FHE scheme parameters with which the user will generate keys and then encrypt her data. SP chooses parameter set α based on wanting to run test_a on the user's data. They'd like to run the more complex test_b as well on the user's data. However, it turns out that parameter set α is not adequate for running test_b. One solution would be for the SP to figure out the appropriate parameter set for test_b—let's say this is parameter set β—and then ask the user to generate new keys and encrypt her data with respect to this new parameter set. A pretty bad solution right?

In this section, we'll see how to encrypt data in such a way that we can run multiple FHE programs on it; supporting this requires choosing scheme parameters that work for a set of pre-determined FHE programs.

Some other scenarios where you might want unified parameters include:

  • training on a private data set where you'd like to experiment with various algorithms
  • private inference where you may want to make various predictions using the same user-provided data set

Specifying multiple FHE programs

Let's assume we want to run function1, function2, and function3 on an encrypted data set.

#![allow(unused)]
fn main() {
use sunscreen::fhe_program;

#[fhe_program(scheme = "bfv")]
fn function1() {
}

#[fhe_program(scheme = "bfv")]
fn function2() {
}

#[fhe_program(scheme = "bfv")]
fn function3() {
}
}

As usual, we declare each of our functions as an FHE program with the appropriate attribute (#[fhe_program(scheme = "bfv")])).

use sunscreen::{fhe_program, Compiler, Error};

#[fhe_program(scheme = "bfv")]
fn function1() {
}

#[fhe_program(scheme = "bfv")]
fn function2() {
}

#[fhe_program(scheme = "bfv")]
fn function3() {
}

fn main() -> Result<(), Error> {
   let app = Compiler::new()
       .fhe_program(function1)
       .fhe_program(function2)
       .fhe_program(function3)
       .compile()?;

   Ok(())
}

When we invoke the compiler to build our programs, we pass in each of the programs individually. Behind the scenes, our compiler then chooses FHE scheme parameters that work for running any of the programs!