Bootstrapping with function: absolute value


i’m trying to implement an edge detection filter using the sobel operator:
to do so i need to be able to evaluate the absolute value of a LWE sample.
My understanding is that it should be possible with PBS, but i can’t make it work.

Here’s the code:

let encoder_input = Encoder::new(-5., 5., 6, 1)?;
let encoder_output = Encoder::new(0., 5., 4, 1)?;

let sk_rlwe = RLWESecretKey::new(&RLWE80_512_1);
	let sk = LWESecretKey::new(&LWE80_256);
	let sk_out = sk_rlwe.to_lwe_secret_key();

bsk = LWEBSK::new(&sk, &sk_rlwe, 3, 8);

//edge detection function:
let (mut Gx, mut Gy) = convolutionXY(img, &i, &(*w as usize), &sobel_filter)?;
		Gx = Gx.bootstrap_with_function(bsk, |x| f64::abs(x), encoder_output)?;
		Gy = Gy.bootstrap_with_function(bsk, |x| f64::abs(x), encoder_output)?;
		let Gtot = Gx.add_with_padding_exact(&Gy)?;

I verified that the values Gx and Gy obtained from the convolutionXY function are correct, but if i try to decrypt the result of the PBS it is completly wrong.

My best guess is that it has to do with the parameters of the output decoder, i tried different combinations but nothing really worked.

Thank you,

Hi Edoardo,

Thanks for your interest in the concrete library.
You are right, it is possible to compute an absolute value using a PBS.
We tried to reproduce the bug from your example, but in our case,
everything seemed to work fine. Please find below the code we run:

let encoder_input = Encoder::new(-5., 5., 6, 1).unwrap();
let encoder_output = Encoder::new(0., 5., 4, 1).unwrap();

let sk_rlwe = RLWESecretKey::new(&RLWE80_512_1);
let sk_in = LWESecretKey::new(&LWE80_256);
let sk_out = sk_rlwe.to_lwe_secret_key();
let bsk = LWEBSK::new(&sk_in, &sk_rlwe, 3, 8);

let mut Gx = LWE::encode_encrypt(&sk_in, 3.0, &encoder_input).unwrap();
let mut Gy = LWE::encode_encrypt(&sk_in, 3.0, &encoder_input).unwrap();

Gx = Gx.bootstrap_with_function(&bsk, |x| f64::abs(x), &encoder_output).unwrap();
Gy = Gy.bootstrap_with_function(&bsk, |x| f64::abs(x), &encoder_output).unwrap();

let Gtot = Gx.add_with_padding_exact(&Gy).unwrap();
let dec  = Gtot.decrypt_decode(&sk_out).unwrap();
println!("Dec(Gtot) = {:?}", dec);

Could you try this piece of code to see if this is correctly working on your side?
Otherwise, could you please send us a complete minimal example which produces the bug?

Thank you, best regards,