Perform Multiple operations on Integer

Dear Community,
How do I perform multiple functions using tfhe integer. I am using the code as below:

use tfhe::integer::ciphertext::RadixCiphertext;
use tfhe::integer::client_key::RadixClientKey;
use tfhe::integer::server_key::ServerKey;

fn analysis<PBSOder: tfhe::shortint::PBSOrderMarker>(array: &Vec<RadixCiphertext<PBSOder>>, ck: &RadixClientKey, sk: &ServerKey){
    let enc = ck.encrypt(5 as u64);
   for itr in 0..100{
       let t = array[itr];
       let c1 = sk.le_parallelized(&t, &enc);
   }
}

I get the following error for c1, expected type parameter PBSOder, found KeySwitchBootstrap.

How to resolve this

The problem here, is that encrypt returns a RadixCiphertext<KeySwitchBootstrap> not a RadixCiphertext<PBSOder>.

You could fix this by using RadixCiphertextBig instead of RadixCiphertext<PBSOder>.

fn analysis(array: &Vec<RadixCiphertextBig>, ck: &RadixClientKey, sk: &ServerKey){
    let enc = ck.encrypt(5 as u64);
   for itr in 0..100{
       let t = array[itr];
       let c1 = sk.le_parallelized(&t, &enc);
   }
}

I see that your analysis function takes both the client key and the server key, this is not exactly how fhe code should be written, as the client key must stay private and not sent to the server.

What you may be looking for is a trivial encryption using the sks.

let trivial_5 = sks.create_trivial_radix(5, array[0].blocks().len());
use tfhe::integer::IntegerCiphertext;

fn analysis(array: &Vec<RadixCiphertextBig>, sk: &ServerKey){
   let trivial_5 = sks.create_trivial_radix(5u64, array[0].blocks().len());
   for ct in array.iter() {
       let c1 = sk.le_parallelized(ct, &trivial_5);
   }
}

(Normally, create_trivial_radix should also works if you really want to use RadixCiphertext<PBSOder>

use tfhe::integer::IntegerCiphertext;

fn analysis<PBSOder: tfhe::shortint::PBSOrderMarker>(array: &Vec<RadixCiphertext<PBSOder>>, sk: &ServerKey){
   let trivial_5 = sks.create_trivial_radix(5u64, array[0].blocks().len());
   for ct in array.iter() {
       let c1 = sk.le_parallelized(ct, &trivial_5);
   }
}

What is the difference between RadixCiphertext and RadixCiphertextBig?

Also when I sometimes do c1 = arrray[itr], I get an error cannot move out of index because it doesn’t implement Copy trait, so how do we such steps?

What is the difference between RadixCiphertext and RadixCiphertextBig?

RadixCiphertext is a generic type of ciphertext that uses radix representation.

RadixCiphertextBig is a concrete implementation of radix ciphertext type that uses the ‘big’ lwe for encryption. There also exists RadixCiphertextSmall.

You should not worry about them, in the next release it is going to be simplified

Also when I sometimes do c1 = arrray[itr], I get an error cannot move out of index because it doesn’t implement Copy trait, so how do we such steps?

You can either take a reference or clone

 let c1 = &arrray[itr];
// or
 let c1 = arrray[itr].clone();

Is it possible to access individual blocks of the radix ciphertexts and perform operations on those based like programmable bootstrap

Dear team, any update on this?

You probably want to check this trait

Cheers

Lets say I create a ciphertext

zero = sk.create_trivial_radix(5u64,  num_blocks);

Now what I want to apply programmable bootstrapping on each bock of cipher

So I do something like this:

blocks = zero.blocks();
for i in 0..4{
    blocks[i] = some_operation(blocks[i]);
}

I get error private field not a method

If I do

blocks = zero.blocks;

I still get error private field

You need to import the trait with

use tfhe::integer::IntegerCiphertext;

To be able to use the method in your first code snippet, use the blocks_mut method if you need to modify the underlying blocks.

Cheers

1 Like

Thank you this is working. Now I have extracted all the blocks, next step I want to convert the blocks back to IntegerCiphertext(RadixCiphertext), will it happen automatically because of the reference or will I have to apply some function on it to convert it?

Normally the blocks function directly references the blocks in the original Integer Ciphertext so you should be able to continue with the ciphertext you called blocks_mut on

If ever you may want to use some specific blocks you can use from_blocks IntegerCiphertext in tfhe::integer::ciphertext - Rust

1 Like

okay thank you. Sorry for being persistent with the questions, but I have one more.

The extracted blocks are of Ciphertext format, and to perform programmable bootstrapping on it, we require ClientKey to generate the wopbs_key, but initially we had the RadixClientkey, so how do we perform these steps? To simplify, how can I apply programmable bootstrapping on the blocks extracted from the Radixciphertext using wopbs_key generated by RadixClientKey and ServerKey?

Also if I have to create a trivial Ciphertext(not RadixCiphertext) for doing sum of the result obtained from above bootstrap code of a block, how to create this?!

Why do you want to use wopbs on the blocks ? There are wopbs primitives at the integer level

One example is to find out which are the positions/blocks that are non zero in the integer ciphertext, and then using this result to perform some other complex function.

You don’t need wopbs for that you should be able to perform per block operation using the classic PBS. At the moment we don’t have an accessor but there should be a way to convert the integer key to shortint with something like:

let sk = …; //integer server key
let shortint_sk: tfhe::shortint::ServerKey = sk.clone().into();

Then use the shortint_sk methods on the blocks you extracted

1 Like