Skip to content

Commit

Permalink
Merge pull request #11 from TrustworthyComputing/gpu-backends
Browse files Browse the repository at this point in the history
Merge GPU gates with main branch
  • Loading branch information
cgouert authored Nov 8, 2023
2 parents b9ea5a2 + f52f967 commit 19533a7
Show file tree
Hide file tree
Showing 8 changed files with 819 additions and 51 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ rand = "0.8.5"
rayon = "1.7.0"
termion = "2.0.1"
tfhe = { version = "0.4.1", features = ["boolean", "shortint", "integer", "x86_64-unix"] }
concrete-core = {git = "https://github.com/TrustworthyComputing/concrete-core", rev = "77f30a2", version = "=1.0.1", features=["backend_default", "backend_default_parallel", "backend_cuda", "x86_64", "concrete-cuda"], optional = true}
thiserror = "1.0"

[[bin]]
name = "helm"
path = "src/bin/helm.rs"

[features]
gpu = ["dep:concrete-core"]
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ cargo build --release
cargo test --release
```

### 1.B) Optionally run all CPU + GPU tests:
```shell
cargo test --features gpu --release
```

### 2) HELM Command Line Arguments
```shell
-v, --verilog <FILE> Verilog input file to evaluate
Expand Down
190 changes: 155 additions & 35 deletions src/bin/helm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "gpu")]
use concrete_core::prelude::*;
use debug_print::debug_println;
use helm::{ascii, circuit, circuit::EvalCircuit, verilog_parser};
use std::time::Instant;
Expand All @@ -6,6 +8,8 @@ use tfhe::{
boolean::gen_keys, generate_keys, shortint::parameters::PARAM_MESSAGE_1_CARRY_1_KS_PBS,
ConfigBuilder,
};
use rand::RngCore;
use rand::rngs::OsRng;

fn main() {
ascii::print_art();
Expand All @@ -15,6 +19,10 @@ fn main() {
.expect("Verilog input file is required");
let num_cycles = *matches.get_one::<usize>("cycles").expect("required");
let verbose = matches.get_flag("verbose");
#[cfg(feature = "gpu")]
let gpu_eval = matches.get_flag("gpu");
#[cfg(not(feature = "gpu"))]
let gpu_eval = false;
let inputs_filename = matches.get_one::<String>("input-wires-file").cloned();
let outputs_filename = matches.get_one::<String>("output-wires-file").cloned();
let arithmetic = matches.get_one::<String>("arithmetic");
Expand Down Expand Up @@ -44,6 +52,7 @@ fn main() {
color::Fg(color::Reset)
);
}

let mut circuit_ptxt =
circuit::Circuit::new(gates_set, &input_wires, &output_wires, &dff_outputs);

Expand Down Expand Up @@ -102,7 +111,7 @@ fn main() {
// Client decrypts the output of the circuit
start = Instant::now();
println!("Encrypted Evaluation:");
let decrypted_outputs = EvalCircuit::decrypt_outputs(&circuit, &enc_wire_map, verbose);
let decrypted_outputs = EvalCircuit::decrypt_outputs(&mut circuit, &enc_wire_map, verbose);
verilog_parser::write_output_wires(outputs_filename, &decrypted_outputs);
println!(
"Decryption done in {} seconds.",
Expand All @@ -122,55 +131,165 @@ fn main() {
color::Fg(color::Reset)
);

// Gate mode
let mut start = Instant::now();
let (client_key, server_key) = gen_keys();
println!("KeyGen done in {} seconds.", start.elapsed().as_secs_f64());
let mut circuit = circuit::GateCircuit::new(client_key, server_key, circuit_ptxt);
if gpu_eval {
#[cfg(feature = "gpu")]
{
// Gate mode (GPU)
let mut start = Instant::now();
let (lwe_dim, glwe_dim, poly_size) = (
LweDimension(630),
GlweDimension(1),
PolynomialSize(1024),
);
let stddev_glwe = 0.00000002980232238769531_f64;
let noise = Variance(stddev_glwe.powf(2.0));
let (dec_lc, dec_bl) = (DecompositionLevelCount(3), DecompositionBaseLog(7));
let (ks_lc, ks_bl) = (DecompositionLevelCount(8), DecompositionBaseLog(2));

// Client encrypts their inputs
start = Instant::now();
let mut enc_wire_map =
EvalCircuit::encrypt_inputs(&mut circuit, &wire_set, &input_wire_map);
println!(
"Encryption done in {} seconds.",
start.elapsed().as_secs_f64()
);
// Create random seed
let mut random_bytes = [0; 16];
OsRng.fill_bytes(&mut random_bytes);
let random_u128 = u128::from_be_bytes(random_bytes);

for cycle in 0..num_cycles {
// Create the necessary engines
let mut default_engine =
DefaultEngine::new(Box::new(UnixSeeder::new(random_u128))).unwrap();
let mut parallel_engine =
DefaultParallelEngine::new(Box::new(UnixSeeder::new(random_u128)))
.unwrap();
let mut cuda_engine = CudaEngine::new(()).unwrap();

// Generate the keys
let h_input_key =
default_engine.generate_new_lwe_secret_key(lwe_dim).unwrap();
let h_lut_key: GlweSecretKey32 = default_engine
.generate_new_glwe_secret_key(glwe_dim, poly_size)
.unwrap();
let h_interm_sk = default_engine
.transform_glwe_secret_key_to_lwe_secret_key(h_lut_key.clone())
.unwrap();
let h_keyswitch_key = default_engine
.generate_new_lwe_keyswitch_key(
&h_interm_sk,
&h_input_key,
ks_lc,
ks_bl,
noise,
)
.unwrap();
// create a BSK with multithreading
let h_bootstrap_key = parallel_engine
.generate_new_lwe_bootstrap_key(
&h_input_key,
&h_lut_key,
dec_bl,
dec_lc,
noise,
)
.unwrap();
let d_fourier_bsk = cuda_engine
.convert_lwe_bootstrap_key(&h_bootstrap_key)
.unwrap();
let d_fourier_ksk = cuda_engine
.convert_lwe_keyswitch_key(&h_keyswitch_key)
.unwrap();

let mut circuit = circuit::CircuitCuda::new(
circuit_ptxt,
default_engine,
cuda_engine,
h_input_key,
d_fourier_bsk,
d_fourier_ksk,
lwe_dim,
noise,
);

println!("KeyGen done in {} seconds.", start.elapsed().as_secs_f64());

// Client encrypts their inputs
start = Instant::now();
let mut enc_wire_map =
EvalCircuit::encrypt_inputs(&mut circuit, &wire_set, &input_wire_map);
println!(
"Encryption done in {} seconds.",
start.elapsed().as_secs_f64()
);
start = Instant::now();
enc_wire_map = EvalCircuit::evaluate_encrypted(
&mut circuit,
&enc_wire_map,
1,
arithmetic_type,
);
println!(
"GPU Evaluation done in {} seconds.\n",
start.elapsed().as_secs_f64()
);

// Client decrypts the output of the circuit
start = Instant::now();
println!("Encrypted Evaluation:");
let decrypted_outputs =
EvalCircuit::decrypt_outputs(&mut circuit, &enc_wire_map, verbose);
verilog_parser::write_output_wires(outputs_filename, &decrypted_outputs);
println!(
"Decryption done in {} seconds.",
start.elapsed().as_secs_f64()
);
}
} else {
// Gate mode
let mut start = Instant::now();
let (client_key, server_key) = gen_keys();
println!("KeyGen done in {} seconds.", start.elapsed().as_secs_f64());
let mut circuit = circuit::GateCircuit::new(client_key, server_key, circuit_ptxt);

// Client encrypts their inputs
start = Instant::now();
enc_wire_map = EvalCircuit::evaluate_encrypted(
&mut circuit,
&enc_wire_map,
1,
arithmetic_type,
let mut enc_wire_map =
EvalCircuit::encrypt_inputs(&mut circuit, &wire_set, &input_wire_map);
println!(
"Encryption done in {} seconds.",
start.elapsed().as_secs_f64()
);

for cycle in 0..num_cycles {
start = Instant::now();
enc_wire_map = EvalCircuit::evaluate_encrypted(
&mut circuit,
&enc_wire_map,
1,
arithmetic_type,
);
println!(
"Cycle {}) Evaluation done in {} seconds.\n",
cycle,
start.elapsed().as_secs_f64()
);
}

// Client decrypts the output of the circuit
start = Instant::now();
println!("Encrypted Evaluation:");
let decrypted_outputs =
EvalCircuit::decrypt_outputs(&mut circuit, &enc_wire_map, verbose);
verilog_parser::write_output_wires(outputs_filename, &decrypted_outputs);
println!(
"Cycle {}) Evaluation done in {} seconds.\n",
cycle,
"Decryption done in {} seconds.",
start.elapsed().as_secs_f64()
);
}

// Client decrypts the output of the circuit
start = Instant::now();
println!("Encrypted Evaluation:");
let decrypted_outputs = EvalCircuit::decrypt_outputs(&circuit, &enc_wire_map, verbose);
verilog_parser::write_output_wires(outputs_filename, &decrypted_outputs);
println!(
"Decryption done in {} seconds.",
start.elapsed().as_secs_f64()
);
} else {
println!(
"{} -- LUTs mode -- {}",
color::Fg(color::LightYellow),
color::Fg(color::Reset)
);

// LUT mode
let mut start = Instant::now();
let (client_key, server_key) = tfhe::shortint::gen_keys(PARAM_MESSAGE_1_CARRY_1_KS_PBS); // single bit ctxt
let (client_key, server_key) =
tfhe::shortint::gen_keys(PARAM_MESSAGE_1_CARRY_1_KS_PBS); // single bit ctxt
let mut circuit = circuit::LutCircuit::new(client_key, server_key, circuit_ptxt);
println!("KeyGen done in {} seconds.", start.elapsed().as_secs_f64());

Expand Down Expand Up @@ -201,7 +320,8 @@ fn main() {
// Client decrypts the output of the circuit
start = Instant::now();
println!("Encrypted Evaluation:");
let decrypted_outputs = EvalCircuit::decrypt_outputs(&circuit, &enc_wire_map, verbose);
let decrypted_outputs =
EvalCircuit::decrypt_outputs(&mut circuit, &enc_wire_map, verbose);
verilog_parser::write_output_wires(outputs_filename, &decrypted_outputs);
println!(
"Decryption done in {} seconds.",
Expand Down
Loading

0 comments on commit 19533a7

Please sign in to comment.