Skip to content

Commit

Permalink
Add GPU circuit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cgouert committed Nov 7, 2023
1 parent d43897e commit b952165
Show file tree
Hide file tree
Showing 8 changed files with 938 additions and 451 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +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 = "28eb1ca", version = "=1.0.1", features=["backend_default", "backend_default_parallel", "backend_cuda"]}
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
403 changes: 242 additions & 161 deletions src/bin/helm.rs

Large diffs are not rendered by default.

725 changes: 454 additions & 271 deletions src/circuit.rs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/gates.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::{FheType, PtxtType};
use std::time::Instant;
use std::{
cmp::Ordering,
fmt,
Expand All @@ -17,8 +19,6 @@ use tfhe::{
ServerKey as ServerKeyShortInt,
},
};
use std::time::Instant;
use crate::{FheType, PtxtType};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum GateType {
Expand Down Expand Up @@ -69,7 +69,7 @@ impl PartialEq for Gate {

impl PartialOrd for Gate {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.gate_name.partial_cmp(&other.gate_name)
Some(self.cmp(other))
}
}

Expand Down Expand Up @@ -299,7 +299,7 @@ impl Gate {
);
self.encrypted_lut_output = Some(ret.clone());
let elapsed_time = Instant::now() - start_time;
println!("PBS time: {} us", elapsed_time.as_micros());
println!("PBS time: {} us", elapsed_time.as_micros());
ret
}

Expand Down
31 changes: 18 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,9 @@ pub fn hex_to_bitstring(hex_string: &str) -> String {
}

pub fn parse_args() -> ArgMatches {
Command::new("HELM")
.about("HELM: Navigating Homomorphic Evaluation through Gates and Lookups")
let mut arg_matches = Command::new("HELM")
.about("HELM: Navigating Homomorphic Evaluation through Gates and Lookups");
arg_matches = arg_matches
.arg(
Arg::new("verilog")
.long("verilog")
Expand Down Expand Up @@ -249,15 +250,6 @@ pub fn parse_args() -> ArgMatches {
])
.required(false),
)
.arg(
Arg::new("gpu")
.long("gpu")
.short('g')
.help("Enable GPU gate evaluation")
.required(false)
.conflicts_with("arithmetic")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("cycles")
.long("cycles")
Expand All @@ -275,6 +267,19 @@ pub fn parse_args() -> ArgMatches {
.help("Turn verbose printing on")
.required(false)
.action(ArgAction::SetTrue),
)
.get_matches()
);
#[cfg(feature = "gpu")]
{
arg_matches = arg_matches.arg(
Arg::new("gpu")
.long("gpu")
.short('g')
.help("Enable GPU gate evaluation")
.required(false)
.conflicts_with("arithmetic")
.action(ArgAction::SetTrue),
);
}

arg_matches.get_matches()
}
210 changes: 210 additions & 0 deletions tests/circuit_test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#[cfg(feature = "gpu")]
use concrete_core::prelude::*;
use debug_print::debug_println;
#[cfg(feature = "gpu")]
use helm::circuit::CircuitCuda;
use helm::{
circuit::{
ArithCircuit, Circuit, EvalCircuit, GateCircuit, HighPrecisionLutCircuit, LutCircuit,
Expand Down Expand Up @@ -102,6 +106,212 @@ fn encrypted_two_bit_adder() {
}
}

#[cfg(feature = "gpu")]
#[test]
fn encrypted_16_bit_multiplier_gpu() {
let datatype = "bool";
let (gates_set, wire_set, input_wires, output_wires, _, _, _) =
verilog_parser::read_verilog_file(
"hdl-benchmarks/processed-netlists/16-bit-mult-gates.v",
false,
);

let empty = vec![];
let mut circuit = Circuit::new(gates_set, &input_wires, &output_wires, &empty);
circuit.sort_circuit();
circuit.compute_levels();

// Encrypted
let (lwe_dim, _, glwe_dim, poly_size) = (
LweDimension(512),
LweDimension(512),
GlweDimension(1),
PolynomialSize(1024),
);
let stddev_glwe: f64 = 0.00000002980232238769531;
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));

const UNSAFE_SECRET: u128 = 0;
let mut default_engine = DefaultEngine::new(Box::new(UnixSeeder::new(UNSAFE_SECRET))).unwrap();
let mut parallel_engine =
DefaultParallelEngine::new(Box::new(UnixSeeder::new(UNSAFE_SECRET))).unwrap();
let mut cuda_engine = CudaEngine::new(()).unwrap();

// Generate the keys
let h_input_key: LweSecretKey32 = 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: LweSecretKey32 = default_engine
.transform_glwe_secret_key_to_lwe_secret_key(h_lut_key.clone())
.unwrap();
let h_keyswitch_key: LweKeyswitchKey32 = 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: LweBootstrapKey32 = parallel_engine
.generate_new_lwe_bootstrap_key(&h_input_key, &h_lut_key, dec_bl, dec_lc, noise)
.unwrap();
let d_fourier_bsk: CudaFourierLweBootstrapKey32 = cuda_engine
.convert_lwe_bootstrap_key(&h_bootstrap_key)
.unwrap();
let d_fourier_ksk: CudaLweKeyswitchKey32 = cuda_engine
.convert_lwe_keyswitch_key(&h_keyswitch_key)
.unwrap();

let input_wire_file: Option<String> =
Some("./hdl-benchmarks/test-cases/16-bit-mult.inputs.csv".to_string());
// Plaintext
let input_wire_map = helm::get_input_wire_map(input_wire_file, vec![], "bool");

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

let mut enc_wire_map = EvalCircuit::encrypt_inputs(&mut circuit, &wire_set, &input_wire_map);

enc_wire_map = EvalCircuit::evaluate_encrypted(&mut circuit, &enc_wire_map, 1, datatype);

let decrypted_outputs = EvalCircuit::decrypt_outputs(&mut circuit, &enc_wire_map, true);
println!("decrypted_outputs: {:?}", &decrypted_outputs);
assert_eq!(decrypted_outputs["G14[15]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[14]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[13]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[12]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[11]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[10]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[9]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[8]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[7]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[6]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[5]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[4]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[3]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[2]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[1]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[0]"], helm::PtxtType::Bool(true));
}

#[cfg(feature = "gpu")]
#[test]
fn encrypted_32_bit_multiplier_gpu() {
let datatype = "bool";
let (gates_set, wire_set, input_wires, output_wires, _, _, _) =
verilog_parser::read_verilog_file(
"hdl-benchmarks/processed-netlists/32-bit-mult-gates.v",
false,
);

let empty = vec![];
let mut circuit = Circuit::new(gates_set, &input_wires, &output_wires, &empty);
circuit.sort_circuit();
circuit.compute_levels();

// Encrypted
let (lwe_dim, _, glwe_dim, poly_size) = (
LweDimension(512),
LweDimension(512),
GlweDimension(1),
PolynomialSize(1024),
);
let stddev_glwe: f64 = 0.00000002980232238769531;
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));

const UNSAFE_SECRET: u128 = 0;
let mut default_engine = DefaultEngine::new(Box::new(UnixSeeder::new(UNSAFE_SECRET))).unwrap();
let mut parallel_engine =
DefaultParallelEngine::new(Box::new(UnixSeeder::new(UNSAFE_SECRET))).unwrap();
let mut cuda_engine = CudaEngine::new(()).unwrap();

// Generate the keys
let h_input_key: LweSecretKey32 = 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: LweSecretKey32 = default_engine
.transform_glwe_secret_key_to_lwe_secret_key(h_lut_key.clone())
.unwrap();
let h_keyswitch_key: LweKeyswitchKey32 = 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: LweBootstrapKey32 = parallel_engine
.generate_new_lwe_bootstrap_key(&h_input_key, &h_lut_key, dec_bl, dec_lc, noise)
.unwrap();
let d_fourier_bsk: CudaFourierLweBootstrapKey32 = cuda_engine
.convert_lwe_bootstrap_key(&h_bootstrap_key)
.unwrap();
let d_fourier_ksk: CudaLweKeyswitchKey32 = cuda_engine
.convert_lwe_keyswitch_key(&h_keyswitch_key)
.unwrap();

let input_wire_file: Option<String> =
Some("./hdl-benchmarks/test-cases/32-bit-mult.inputs.csv".to_string());
// Plaintext
let input_wire_map = helm::get_input_wire_map(input_wire_file, vec![], "bool");

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

let mut enc_wire_map = EvalCircuit::encrypt_inputs(&mut circuit, &wire_set, &input_wire_map);

enc_wire_map = EvalCircuit::evaluate_encrypted(&mut circuit, &enc_wire_map, 1, datatype);

let decrypted_outputs = EvalCircuit::decrypt_outputs(&mut circuit, &enc_wire_map, true);
println!("decrypted_outputs: {:?}", &decrypted_outputs);
assert_eq!(decrypted_outputs["G14[31]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[30]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[29]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[28]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[27]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[26]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[25]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[24]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[23]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[22]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[21]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[20]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[19]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[18]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[17]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[16]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[15]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[14]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[13]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[12]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[11]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[10]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[9]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[8]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[7]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[6]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[5]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[4]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[3]"], helm::PtxtType::Bool(true));
assert_eq!(decrypted_outputs["G14[2]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[1]"], helm::PtxtType::Bool(false));
assert_eq!(decrypted_outputs["G14[0]"], helm::PtxtType::Bool(true));
}

#[test]
fn encrypted_eight_bit_adder_lut() {
let datatype = "bool";
Expand Down

0 comments on commit b952165

Please sign in to comment.