use sunscreen::{ fhe_program, types::{bfv::Batched, Cipher, SwapRows}, Compiler, FheProgramInput, PlainModulusConstraint, Runtime, }; use std::ops::*; #[test] fn can_swap_rows_cipher() { fn swap_impl(a: T) -> T where T: SwapRows, { a.swap_rows() } #[fhe_program(scheme = "bfv")] fn swap_rows(a: Cipher>) -> Cipher> { swap_impl(a) } let app = Compiler::new() .fhe_program(swap_rows) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let args: Vec = vec![a_c.into()]; let result = runtime .run(app.get_fhe_program(swap_rows).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); let expected = [vec![5, 6, 7, 8], vec![1, 2, 3, 4]]; assert_eq!(c, swap_impl(a)); assert_eq!(c, expected.try_into().unwrap()); } #[test] fn can_rotate_left_cipher() { fn shl_impl(x: T, y: u64) -> T where T: Shl, { x << y } #[fhe_program(scheme = "bfv")] fn add(a: Cipher>) -> Cipher> { shl_impl(a, 1) } let app = Compiler::new() .fhe_program(add) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let args: Vec = vec![a_c.into()]; let result = runtime .run(app.get_fhe_program(add).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); assert_eq!(c, shl_impl(a, 1)); } #[test] fn can_rotate_right_cipher() { fn shr_impl(x: T, y: u64) -> T where T: Shr, { x >> y } #[fhe_program(scheme = "bfv")] fn add(a: Cipher>) -> Cipher> { shr_impl(a, 1) } let app = Compiler::new() .fhe_program(add) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let args: Vec = vec![a_c.into()]; let result = runtime .run(app.get_fhe_program(add).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); assert_eq!(c, shr_impl(a, 1)); } #[test] fn can_add_cipher_cipher() { fn add_impl(a: T, b: T) -> T where T: Add, { a + b } #[fhe_program(scheme = "bfv")] fn add(a: Cipher>, b: Cipher>) -> Cipher> { add_impl(a, b) } let app = Compiler::new() .fhe_program(add) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data.clone()).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let b = Batched::<4>::try_from(data).unwrap(); let b_c = runtime.encrypt(b, &public_key).unwrap(); let args: Vec = vec![a_c.into(), b_c.into()]; let result = runtime .run(app.get_fhe_program(add).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); assert_eq!(c, add_impl(a, b)); } #[test] fn can_sub_cipher_cipher() { fn sub_impl(a: T, b: T) -> T where T: Sub, { a - b } #[fhe_program(scheme = "bfv")] fn sub(a: Cipher>, b: Cipher>) -> Cipher> { sub_impl(a, b) } let app = Compiler::new() .fhe_program(sub) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data.clone()).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let b = Batched::<4>::try_from(data).unwrap(); let b_c = runtime.encrypt(b, &public_key).unwrap(); let args: Vec = vec![a_c.into(), b_c.into()]; let result = runtime .run(app.get_fhe_program(sub).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); assert_eq!(c, sub_impl(a, b)); } #[test] fn can_mul_cipher_cipher() { fn mul_impl(a: T, b: T) -> T where T: Mul, { a * b } #[fhe_program(scheme = "bfv")] fn mul(a: Cipher>, b: Cipher>) -> Cipher> { mul_impl(a, b) } let app = Compiler::new() .fhe_program(mul) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data.clone()).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let b = Batched::<4>::try_from(data).unwrap(); let b_c = runtime.encrypt(b, &public_key).unwrap(); let args: Vec = vec![a_c.into(), b_c.into()]; let result = runtime .run(app.get_fhe_program(mul).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); assert_eq!(c, mul_impl(a, b)); } #[test] fn can_neg_cipher_cipher() { fn neg_impl(a: T) -> T where T: Neg, { -a } #[fhe_program(scheme = "bfv")] fn mul(a: Cipher>) -> Cipher> { neg_impl(a) } let app = Compiler::new() .fhe_program(mul) .additional_noise_budget(5) .plain_modulus_constraint(PlainModulusConstraint::BatchingMinimum(0)) .compile() .unwrap(); let runtime = Runtime::new_fhe(app.params()).unwrap(); let (public_key, private_key) = runtime.generate_keys().unwrap(); let data = [vec![1, 2, 3, 4], vec![5, 6, 7, 8]]; let a = Batched::<4>::try_from(data).unwrap(); let a_c = runtime.encrypt(a, &public_key).unwrap(); let args: Vec = vec![a_c.into()]; let result = runtime .run(app.get_fhe_program(mul).unwrap(), args, &public_key) .unwrap(); let c: Batched<4> = runtime.decrypt(&result[0], &private_key).unwrap(); assert_eq!(c, neg_impl(a)); }