If you wish to write generic functions which use operators with mixed reference and non-reference, it might get tricky at first to specify the trait bounds . This page should serve as a cookbook to help you.
Then, depending on if the left hand side / right hand side is an owned value or a reference, the trait bound is slightly different. The table below shows the possibilities.
Copy use std :: ops :: { Add , Mul };
use tfhe :: prelude ::* ;
use tfhe :: {generate_keys, set_server_key, ConfigBuilder , FheUint32 , FheUint64 };
pub fn ex1 <' a , FheType , ClearType >(ct : & ' a FheType , pt : ClearType ) -> FheType
where
& ' a FheType : Add < ClearType , Output = FheType >,
{
ct + pt
}
pub fn ex2 <' a , FheType , ClearType >(a : & ' a FheType , b : & ' a FheType , pt : ClearType ) -> FheType
where
& ' a FheType : Mul < & ' a FheType , Output = FheType >,
FheType : Add < ClearType , Output = FheType >,
{
(a * b) + pt
}
pub fn ex3 < FheType , ClearType >(a : FheType , b : FheType , pt : ClearType ) -> FheType
where
for <' a > & ' a FheType : Add < & ' a FheType , Output = FheType >,
FheType : Add < FheType , Output = FheType > + Add < ClearType , Output = FheType >,
{
let tmp = ( & a + & b) + ( & a + & b);
tmp + pt
}
pub fn ex4 < FheType , ClearType >(a : FheType , b : FheType , pt : ClearType ) -> FheType
where
FheType : Clone + Add < FheType , Output = FheType > + Add < ClearType , Output = FheType >,
{
let tmp = (a . clone () + b . clone ()) + (a . clone () + b . clone ());
tmp + pt
}
fn main () {
let config = ConfigBuilder :: default ()
. build ();
let (client_key, server_keys) = generate_keys (config);
set_server_key (server_keys);
// Use FheUint32
{
let clear_a = 46546 u32 ;
let clear_b = 6469 u32 ;
let clear_c = 64 u32 ;
let a = FheUint32 :: try_encrypt (clear_a, & client_key) . unwrap ();
let b = FheUint32 :: try_encrypt (clear_b, & client_key) . unwrap ();
assert_eq! (
ex1 ( & clear_a, clear_c),
ex1 ( & a, clear_c) . decrypt ( & client_key)
);
assert_eq! (
ex2 ( & clear_a, & clear_b, clear_c),
ex2 ( & a, & b, clear_c) . decrypt ( & client_key)
);
assert_eq! (
ex3 (clear_a, clear_b, clear_c),
ex3 (a . clone (), b . clone (), clear_c) . decrypt ( & client_key)
);
assert_eq! (
ex4 (clear_a, clear_b, clear_c),
ex4 (a, b, clear_c) . decrypt ( & client_key)
);
}
// Use FheUint64
{
let clear_a = 46544866 u64 ;
let clear_b = 6469446677 u64 ;
let clear_c = 647897 u64 ;
let a = FheUint64 :: try_encrypt (clear_a, & client_key) . unwrap ();
let b = FheUint64 :: try_encrypt (clear_b, & client_key) . unwrap ();
assert_eq! (
ex1 ( & clear_a, clear_c),
ex1 ( & a, clear_c) . decrypt ( & client_key)
);
assert_eq! (
ex2 ( & clear_a, & clear_b, clear_c),
ex2 ( & a, & b, clear_c) . decrypt ( & client_key)
);
assert_eq! (
ex3 (clear_a, clear_b, clear_c),
ex3 (a . clone (), b . clone (), clear_c) . decrypt ( & client_key)
);
assert_eq! (
ex4 (clear_a, clear_b, clear_c),
ex4 (a, b, clear_c) . decrypt ( & client_key)
);
}
}