This document serves as a practical reference for implementing generic functions in Rust that use operators across mixed references and values. The following explanations help you to understand the trait bounds necessary to handle such operations.
The trait bound varies slightly depending on whether the left-hand side / right-hand side is an owned value or a reference. The following table shows the different scenarios:
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)
);
}
}