Bootstrap with function

Hi community!

I am trying to play with the bootstrap function of ZAMA. I am not always getting the correct result while trying to implement the User defined function on x. Can you help me understand what is happening? Here is my code snippet.

let sk_rlwe = RLWESecretKey::new(&RLWE128_1024_1);
let sk_lwe = sk_rlwe.to_lwe_secret_key();

let base_log = 7;
let level = 3;
let bsk = LWEBSK::new(&sk_lwe, &sk_rlwe, base_log, level);

let (min, max) = (-3., 3.);
let precision = 4;
let padding = 2;

let compare = |x:f64|
if x == 0.{
1.
}
else{
0.
};

let encoder_input = Encoder::new(min, max, precision, padding).unwrap();
let encoder_output = Encoder::new(0., 1., precision, padding).unwrap();

let messages: Vec = vec![-3., -2., -1., 0., 1., 2., 3];

for i in 0…7{
let ct_b = LWE::encode_encrypt(&sk_lwe, messages[i], &encoder_input).unwrap();
let ct_o = ct_b.bootstrap_with_function(&bsk, compare, &encoder_output).unwrap();
let res = ct_o.decode_decrypt(&sk_lwe).unwrap();
}

I ran three different instances of code, the outputs I received were:

Instance1: 0.005 0 0.023 1 0.007 0.001 0
Instance2: 0.002 0 0.001 1 0 0.98 0.025
Instance3: 0.007 0 0.006 0.019 0 0.004 0.012

Ideally only the 4th value should be 1 and all other should be zero with some error. But here only instance 1 is giving results same as the expected results. What am I missing here?

Hello,

Could you share your Cargo.toml as well as the full source file you try to run (including imports)?

Thanks in advance

Cargo.toml file is:

[package]
name = “concretelibrary”
version = “0.1.0”
edition = “2021”

[lib]
name = “concretelibrary”
crate-type = [“cdylib”]

[dependencies]
pyo3 = {version = “0.16.5”, features = [“extension-module”]}
concrete = “^0.1.11”

I am trying to import the concrete library to use it inside python code that’s why extra dependencies

Full Source File is:

use pyo3::prelude::;
use concrete::
;

#[pyfunction]
fn initialize(){
let sk_rlwe = RLWESecretKey::new(&RLWE128_1024_1);
let sk_lwe = sk_rlwe.to_lwe_secret_key();

let base_log = 7;
let level = 3;
let bsk = LWEBSK::new(&sk_lwe, &sk_rlwe, base_log, level);

let (min, max) = (-3., 3.);
let precision = 4;
let padding = 2;

let compare = |x:f64|
if x == 0.{
1.
}
else{
0.
};

let encoder_input = Encoder::new(min, max, precision, padding).unwrap();
let encoder_output = Encoder::new(0., 1., precision, padding).unwrap();

let messages: Vec = vec![-3., -2., -1., 0., 1., 2., 3];

for i in 0…7{
let ct_b = LWE::encode_encrypt(&sk_lwe, messages[i], &encoder_input).unwrap();
let ct_o = ct_b.bootstrap_with_function(&bsk, compare, &encoder_output).unwrap();
let res = ct_o.decode_decrypt(&sk_lwe).unwrap();
}

}

#[pymodule]
fn concretelibrary(_py: Python, m: &PyModule) → PyResult<()>{
m.add_function(wrap_pyfunction!(initialize,m)?)?);
Ok(());
}

Hello @divyesh,

it seems you’re using a old version of concrete. Before entering the real topic let me just outline the changes already made to concrete and the upcoming ones:

  • v0.1 version you are using was cryptography oriented, meaning also error prone, an error in encodings or parameters and your result is false.
  • the next version of concrete (v0.2) introduced a brand new abstraction layer of the underlying crypto, allowing users to directly declare FheBool or FheUintX (up to 8 bits) and no longer care about encoding and parameters.
  • the upcoming version of concrete (coming end of march’23) will keep this abstraction layer but the underlying crypto will switch from the library to our fhe compiler (concrete-compiler) that will take care of optimal performances / security / correctness. TFHE library will be renamed TFHE-rs (already available on Github)

Coming back to your example, if you want to play with FHE from python you could already do it through our concrete-compiler by using concrete-numpy, something like:

import concrete.numpy as cnp

L=cnp.LookupTable([1,0,0,0,0,0,0])

@cnp.compiler({"x": "encrypted"})
def compare(x):
    return L[x]
    
inputset = [-3, -2, -1, 0, 1, 2, 3]
circuit = compare.compile(inputset)

for i in range(-3,3):
    clear_evaluation = compare(i)
    homomorphic_evaluation = circuit.encrypt_run_decrypt(i)
    print("clear eval:", clear_evaluation, "homomorphic eval:", homomorphic_evaluation)

or give tfhe-rs a try if you still want to play with a library.

(I will ask the team for your error but I wanted to bring other solutions too)

Hi @alex

I did give a try to the concrete-numpy library. But the usecase I am looking for where the look-up table will have the size of at least 1024, the time taken to run just one instance of the compare function was very much, which is evident from the technique that is being used. I read about that in the documentation that as we increase inputset the time will also increase.

Moreover, I am looking to perform operations on floating point operations, where say I have fixed inputs as integers, but outputs can be floating points like sin(x) or log(x). These outputs I have to use for performing ciphertext multiplications.

Although concrete version 0.1.11 is an old library and crypto specific, it actually takes care of all conditions I want in my project. Thats why I chose it.

Moreover I am also keen about the new developer specific releases that you are going to release and will be waiting to see if my above mentioned use cases can be fulfilled by the new library.

Also if it is possible, can you share some documentation on how should the encoding and boostrapping parameters be chosen? As I was also facing the loss of precision bits - consider increasing level or decreasing the log base error when I tried to compute the same thing with more precision and padding bits. (I guess the results are because of the error, since this library involves floating point operations the noise bits are overlapping with the message bits and giving the error)

Hi, @alex @IceTDrinker

I am trying version 0.2.1 of the zama library. Here is my code

use concrete::{ConfigBuilder, generate_keys, set_server_key, FheUint8};
use concrete::prelude::*;

fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_uint8()
.build();

let (client_key, server_key) = generate_keys(config);

set_server_key(server_key);

let clear_a = 27u8;
let clear_b = 128u8;

let a = FheUint8::encrypt(clear_a, &client_key);
let b = FheUint8::encrypt(clear_b, &client_key);

let result = a + b;

let decrypted_result: u8 = result.decrypt(&client_key);

let clear_result = clear_a + clear_b;

assert_eq!(decrypted_result, clear_result);

}

Here is the Cargo.toml file

[package]
name = “tfhe_new”
version = “0.1.0”
edition = “2021”

[dependencies]
concrete = “0.2.1”

I am getting these errors:

  1. use of undeclared type ‘FheUint8’
  2. enable_default_uint8() method not found in Concrete::ConfigBuilder

How do I resolve this?!

hello @divyesh

can you try in your cargo.toml to change concrete to:

concrete = { version = "0.2.1", features = ["integers"] }

Hello @IceTDrinker

After making change you suggested, I get the following error:

thread ‘main’ panicked at 'The AesniBlockCipher requires both aes and sse2 x86 CPU features.
aes feature available: false
sse2 feature available: true

Hello @divyesh

Could you share your CPU model and the OS you are using? I’ll try to see if we can remedy to this error in the mean time

Also if you are using Docker let us know as it can have some impact

Thanks

Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Model: AMD Ryzen 5 3500U with Radeon vega Mobile Gfx

OS: Ubuntu 20.04.4 LTS

Hello,

That’s weird your CPU is listed as having AES instructions. Do you have a special configuration like running in a VM for example?

Can you run lscpu in your Ubuntu and paste the result?

Yes, I am using a virtual box.
Here are my complete Specs

Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 48 bits physical, 48 bits virtual
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 1
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: AuthenticAMD
CPU family: 23
Model: 24
Model name: AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx
Stepping: 1
CPU MHz: 2096.051
BogoMIPS: 4192.10
L1d cache: 128 KiB
L1i cache: 256 KiB
L2 cache: 2 MiB
L3 cache: 4 MiB
NUMA node0 CPU(s): 0-3
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled
via prctl and seccomp
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __use
r pointer sanitization
Vulnerability Spectre v2: Mitigation; Full AMD retpoline, STIBP disabled
, RSB filling
Vulnerability Srbds: Not affected
Vulnerability Tsx async abort: Not affected
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mt
rr pge mca cmov pat pse36 clflush mmx fxsr sse
sse2 ht syscall nx fxsr_opt rdtscp lm constan
t_tsc rep_good nopl nonstop_tsc cpuid extd_api
cid pni ssse3 sse4_1 sse4_2 x2apic lahf_lm cmp
_legacy cr8_legacy 3dnowprefetch cpb ssbd vmmc
all fsgsbase arat

Can you try enabling “nested paging” in your VM configuration ?

I enabled nested paging, I am not getting the error but the code execution is taking a lot of time

Use --release in your cargo invocation

like

cargo run --release

It is running now, thank you

glad to hear it! :slight_smile:

the release flag is required to have optimized builds as some operations are very heavy

A quick question as well, how should we choose between tfhe-rs and concrete version 0.2.1 and concrete version 0.1.11

May I ask you to open a new topic for this particular question as I think it may interest other users?