Merge pull request #42 from Sunscreen-tech/rweber/plaintext

Remove Unsigned type; it doesn't support subtraction
This commit is contained in:
rickwebiii
2022-01-24 17:15:16 -08:00
committed by GitHub
9 changed files with 45 additions and 510 deletions

View File

@@ -1,6 +1,6 @@
use sunscreen_compiler::{
circuit,
types::{bfv::Unsigned, Cipher},
types::{bfv::Signed, Cipher},
Compiler, PlainModulusConstraint,
};
use sunscreen_runtime::Runtime;
@@ -11,17 +11,17 @@ use sunscreen_runtime::Runtime;
* the result. Circuits may take any number of parameters and return either a single result
* or a tuple of results.
*
* The [`Unsigned`] type refers to an unsigned integer modulo the plaintext
* The [`Signed`] type refers to an unsigned integer modulo the plaintext
* modulus (p). p is passed to the compiler via plain_modulus_constraint.
*
* A `Cipher` type indicates the type is encrypted. Thus, a `Cipher<Unsigned>`
* refers to an encrypted [`Unsigned`] value.
* A `Cipher` type indicates the type is encrypted. Thus, a `Cipher<Signed>`
* refers to an encrypted [`Signed`] value.
*
* One takes a circuit and passes them to the compiler, which transforms it into a form
* suitable for execution.
*/
#[circuit(scheme = "bfv")]
fn simple_multiply(a: Cipher<Unsigned>, b: Cipher<Unsigned>) -> Cipher<Unsigned> {
fn simple_multiply(a: Cipher<Signed>, b: Cipher<Signed>) -> Cipher<Signed> {
a * b
}
@@ -66,8 +66,8 @@ fn main() {
*/
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let b = runtime.encrypt(Unsigned::from(5), &public).unwrap();
let a = runtime.encrypt(Signed::from(15), &public).unwrap();
let b = runtime.encrypt(Signed::from(5), &public).unwrap();
/*
* Run the circuit with our arguments. This produces a results
@@ -76,9 +76,9 @@ fn main() {
let results = runtime.run(&circuit, vec![a, b], &public).unwrap();
/*
* Our circuit outputs a Unsigned single value as the result. Decrypt it.
* Our circuit outputs a Signed single value as the result. Decrypt it.
*/
let c: Unsigned = runtime.decrypt(&results[0], &secret).unwrap();
let c: Signed = runtime.decrypt(&results[0], &secret).unwrap();
/*
* Yay, 5 * 15 indeed equals 75.

View File

@@ -7,10 +7,10 @@
//! # Examples
//! This example is further annotated in `examples/simple_multiply`.
//! ```
//! # use sunscreen_compiler::{circuit, Compiler, types::{bfv::Unsigned, Cipher}, PlainModulusConstraint, Params, Runtime, Context};
//! # use sunscreen_compiler::{circuit, Compiler, types::{bfv::Signed, Cipher}, PlainModulusConstraint, Params, Runtime, Context};
//!
//! #[circuit(scheme = "bfv")]
//! fn simple_multiply(a: Cipher<Unsigned>, b: Cipher<Unsigned>) -> Cipher<Unsigned> {
//! fn simple_multiply(a: Cipher<Signed>, b: Cipher<Signed>) -> Cipher<Signed> {
//! a * b
//! }
//!
@@ -25,12 +25,12 @@
//!
//! let (public, secret) = runtime.generate_keys().unwrap();
//!
//! let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
//! let b = runtime.encrypt(Unsigned::from(5), &public).unwrap();
//! let a = runtime.encrypt(Signed::from(15), &public).unwrap();
//! let b = runtime.encrypt(Signed::from(5), &public).unwrap();
//!
//! let results = runtime.run(&circuit, vec![a, b], &public).unwrap();
//!
//! let c: Unsigned = runtime.decrypt(&results[0], &secret).unwrap();
//! let c: Signed = runtime.decrypt(&results[0], &secret).unwrap();
//!
//! assert_eq!(c, 75.into());
//! }

View File

@@ -1,9 +1,7 @@
mod fractional;
mod rational;
mod signed;
mod unsigned;
pub use fractional::*;
pub use rational::*;
pub use signed::*;
pub use unsigned::*;

View File

@@ -1,223 +0,0 @@
use seal::Plaintext as SealPlaintext;
use crate::types::{ops::*, Cipher};
use crate::{
types::{intern::CircuitNode, BfvType, FheType, TypeNameInstance},
with_ctx, CircuitInputTrait, Params, TypeName as DeriveTypeName, WithContext,
};
use sunscreen_runtime::{
InnerPlaintext, NumCiphertexts, Plaintext, TryFromPlaintext, TryIntoPlaintext,
};
#[derive(Debug, Clone, Copy, DeriveTypeName, PartialEq, Eq)]
/**
* A single unsigned integer.
*/
pub struct Unsigned {
val: u64,
}
impl std::ops::Deref for Unsigned {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.val
}
}
impl CircuitInputTrait for Unsigned {}
impl FheType for Unsigned {}
impl BfvType for Unsigned {}
impl Unsigned {}
impl GraphCipherAdd for Unsigned {
type Left = Unsigned;
type Right = Unsigned;
fn graph_cipher_add(
a: CircuitNode<Cipher<Self::Left>>,
b: CircuitNode<Cipher<Self::Right>>,
) -> CircuitNode<Cipher<Self::Left>> {
with_ctx(|ctx| {
let n = ctx.add_addition(a.ids[0], b.ids[0]);
CircuitNode::new(&[n])
})
}
}
impl GraphCipherPlainAdd for Unsigned {
type Left = Unsigned;
type Right = Unsigned;
fn graph_cipher_plain_add(
a: CircuitNode<Cipher<Self::Left>>,
b: CircuitNode<Self::Right>,
) -> CircuitNode<Cipher<Self::Left>> {
with_ctx(|ctx| {
let n = ctx.add_addition_plaintext(a.ids[0], b.ids[0]);
CircuitNode::new(&[n])
})
}
}
impl GraphCipherConstAdd for Unsigned {
type Left = Self;
type Right = u64;
fn graph_cipher_const_add(
a: CircuitNode<Cipher<Self::Left>>,
b: u64,
) -> CircuitNode<Cipher<Self::Left>> {
with_ctx(|ctx| {
let b = Self::from(b).try_into_plaintext(&ctx.params).unwrap();
let lit = ctx.add_plaintext_literal(b.inner);
let add = ctx.add_addition_plaintext(a.ids[0], lit);
CircuitNode::new(&[add])
})
}
}
impl GraphCipherMul for Unsigned {
type Left = Unsigned;
type Right = Unsigned;
fn graph_cipher_mul(
a: CircuitNode<Cipher<Self::Left>>,
b: CircuitNode<Cipher<Self::Right>>,
) -> CircuitNode<Cipher<Self::Left>> {
with_ctx(|ctx| {
let n = ctx.add_multiplication(a.ids[0], b.ids[0]);
CircuitNode::new(&[n])
})
}
}
impl GraphCipherConstMul for Unsigned {
type Left = Self;
type Right = u64;
fn graph_cipher_const_mul(
a: CircuitNode<Cipher<Self::Left>>,
b: u64,
) -> CircuitNode<Cipher<Self::Left>> {
with_ctx(|ctx| {
let b = Self::from(b).try_into_plaintext(&ctx.params).unwrap();
let lit = ctx.add_plaintext_literal(b.inner);
let add = ctx.add_multiplication_plaintext(a.ids[0], lit);
CircuitNode::new(&[add])
})
}
}
impl GraphCipherPlainMul for Unsigned {
type Left = Unsigned;
type Right = Unsigned;
fn graph_cipher_plain_mul(
a: CircuitNode<Cipher<Self::Left>>,
b: CircuitNode<Self::Right>,
) -> CircuitNode<Cipher<Self::Left>> {
with_ctx(|ctx| {
let n = ctx.add_multiplication_plaintext(a.ids[0], b.ids[0]);
CircuitNode::new(&[n])
})
}
}
impl TryIntoPlaintext for Unsigned {
fn try_into_plaintext(
&self,
params: &Params,
) -> std::result::Result<Plaintext, sunscreen_runtime::Error> {
let mut seal_plaintext = SealPlaintext::new()?;
let bits = std::mem::size_of::<u64>() * 8;
seal_plaintext.resize(bits);
for i in 0..bits {
let bit_value = (self.val & 0x1 << i) >> i;
seal_plaintext.set_coefficient(i, bit_value);
}
Ok(Plaintext {
data_type: self.type_name_instance(),
inner: InnerPlaintext::Seal(vec![WithContext {
params: params.clone(),
data: seal_plaintext,
}]),
})
}
}
impl TryFromPlaintext for Unsigned {
fn try_from_plaintext(
plaintext: &Plaintext,
_params: &Params,
) -> std::result::Result<Self, sunscreen_runtime::Error> {
let val = match &plaintext.inner {
InnerPlaintext::Seal(p) => {
if p.len() != 1 {
return Err(sunscreen_runtime::Error::IncorrectCiphertextCount);
}
let mut val = 0u64;
let bits = usize::min(std::mem::size_of::<u64>() * 8, p[0].len());
for i in 0..bits {
val += p[0].get_coefficient(i) * (1 << i);
}
Self { val }
}
};
Ok(val)
}
}
impl NumCiphertexts for Unsigned {
const NUM_CIPHERTEXTS: usize = 1;
}
impl From<u64> for Unsigned {
fn from(val: u64) -> Self {
Self { val }
}
}
impl Into<u64> for Unsigned {
fn into(self) -> u64 {
self.val
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_convert_u64_to_unsigned() {
let foo: Unsigned = 64u64.into();
assert_eq!(foo.val, 64);
}
#[test]
fn can_convert_unsigned_to_u64() {
let foo = Unsigned { val: 64 };
let converted: u64 = foo.into();
assert_eq!(converted, 64u64);
}
}

View File

@@ -20,13 +20,9 @@
* allows for somewhat efficiently representing integers, but has unusual
* overflow semantics developers need to understand. This type supports
* addition, subtraction, multiplication, and negation.
* * The [`Unsigned`](crate::types::bfv::Unsigned) type represents and unsigned
* integer. This type has the same benefits and caveats as
* [`Signed`](crate::types::bfv::Signed) types, but is unsigned.
* * The [`Fractional`](crate::types::bfv::Fractional) type is a quasi fixed-point
* value. It allows you to homomorphically compute decimal values as
* efficiently as [`Signed`](crate::types::bfv::Signed) and
* [`Unsigned`](crate::types::bfv::Unsigned) types. This type has complex overflow
* efficiently as the [`Signed`](crate::types::bfv::Signed) type. This type has complex overflow
* conditions. This type intrinsically supports homomorphic addition
* multiplication, and negation. Dividing by an [`f64`] constant is supported.
* Dividing by ciphertext is not possible.
@@ -44,7 +40,6 @@
* | Type | # ciphertexts | overflow conditions | values | ops/add | ops/mul | ops/sub | ops/neg | ops/div |
* |------------|---------------|---------------------|-------------------|----------------|---------|----------------|---------|---------|
* | Signed | 1 | moderate | signed integral | 1 add | 1 mul | 1 sub | 1 neg | - |
* | Unsigned | 1 | moderate | unsigned integral | 1 add | 1 mul | 1 sub | 1 neg | - |
* | Fractional | 1 | complex | signed decimal | 1 add | 1 mul | 1 sub | 1 neg | 1 mul* |
* | Rational | 2 | moderate | signed decimal | 2 muls + 1 sub | 2 muls | 2 muls + 1 sub | 1 neg | 2 muls |
*

View File

@@ -1,231 +0,0 @@
use sunscreen_compiler::{
circuit,
types::{bfv::Unsigned, Cipher},
CircuitInput, Compiler, PlainModulusConstraint, Runtime,
};
#[test]
fn can_add_cipher_plain() {
#[circuit(scheme = "bfv")]
fn add(a: Cipher<Unsigned>, b: Unsigned) -> Cipher<Unsigned> {
a + b
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let b = Unsigned::from(5);
let args: Vec<CircuitInput> = vec![a.into(), b.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 20.into());
}
#[test]
fn can_add_plain_cipher() {
#[circuit(scheme = "bfv")]
fn add(a: Unsigned, b: Cipher<Unsigned>) -> Cipher<Unsigned> {
b + a
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = Unsigned::from(5);
let b = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let args: Vec<CircuitInput> = vec![a.into(), b.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 20.into());
}
#[test]
fn can_add_cipher_literal() {
#[circuit(scheme = "bfv")]
fn add(a: Cipher<Unsigned>) -> Cipher<Unsigned> {
a + 4
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let args: Vec<CircuitInput> = vec![a.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 19.into());
}
#[test]
fn can_add_literal_cipher() {
#[circuit(scheme = "bfv")]
fn add(a: Cipher<Unsigned>) -> Cipher<Unsigned> {
4 + a
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let args: Vec<CircuitInput> = vec![a.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 19.into());
}
#[test]
fn can_mul_cipher_plain() {
#[circuit(scheme = "bfv")]
fn add(a: Cipher<Unsigned>, b: Unsigned) -> Cipher<Unsigned> {
a * b
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let b = Unsigned::from(3);
let args: Vec<CircuitInput> = vec![a.into(), b.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 45.into());
}
#[test]
fn can_mul_plain_cipher() {
#[circuit(scheme = "bfv")]
fn add(a: Unsigned, b: Cipher<Unsigned>) -> Cipher<Unsigned> {
a * b
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = Unsigned::from(15);
let b = runtime.encrypt(Unsigned::from(3), &public).unwrap();
let args: Vec<CircuitInput> = vec![a.into(), b.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 45.into());
}
#[test]
fn can_mul_cipher_literal() {
#[circuit(scheme = "bfv")]
fn add(a: Cipher<Unsigned>) -> Cipher<Unsigned> {
a * 3
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let args: Vec<CircuitInput> = vec![a.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 45.into());
}
#[test]
fn can_mul_literal_cipher() {
#[circuit(scheme = "bfv")]
fn add(a: Cipher<Unsigned>) -> Cipher<Unsigned> {
3 * a
}
let circuit = Compiler::with_circuit(add)
.noise_margin_bits(5)
.plain_modulus_constraint(PlainModulusConstraint::Raw(500))
.compile()
.unwrap();
let runtime = Runtime::new(&circuit.metadata.params).unwrap();
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let args: Vec<CircuitInput> = vec![a.into()];
let result = runtime.run(&circuit, args, &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 45.into());
}

View File

@@ -33,27 +33,27 @@ pub fn derive_typename(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
*
* # Examples
* ```rust
* # use sunscreen_compiler::{circuit, types::{bfv::Unsigned, Cipher}, Params, Context};
* # use sunscreen_compiler::{circuit, types::{bfv::Signed, Cipher}, Params, Context};
*
* #[circuit(scheme = "bfv")]
* fn multiply_add(
* a: Cipher<Unsigned>,
* b: Cipher<Unsigned>,
* c: Cipher<Unsigned>
* ) -> Cipher<Unsigned> {
* a: Cipher<Signed>,
* b: Cipher<Signed>,
* c: Cipher<Signed>
* ) -> Cipher<Signed> {
* a * b + c
* }
* ```
*
* ```rust
* # use sunscreen_compiler::{circuit, types::{bfv::Unsigned, Cipher}, Params, Context};
* # use sunscreen_compiler::{circuit, types::{bfv::Signed, Cipher}, Params, Context};
*
* #[circuit(scheme = "bfv")]
* fn multi_out(
* a: Cipher<Unsigned>,
* b: Cipher<Unsigned>,
* c: Cipher<Unsigned>
* ) -> (Cipher<Unsigned>, Cipher<Unsigned>) {
* a: Cipher<Signed>,
* b: Cipher<Signed>,
* c: Cipher<Signed>
* ) -> (Cipher<Signed>, Cipher<Signed>) {
* (a + b, b + c)
* }
* ```

View File

@@ -1,5 +1,5 @@
use sunscreen_compiler::{
types::{bfv::Unsigned, Cipher, TypeName},
types::{bfv::Signed, Cipher, TypeName},
CallSignature, CircuitFn, FrontendCompilation, Params, SchemeType, SecurityLevel, CURRENT_CTX,
};
use sunscreen_compiler_macros::circuit;
@@ -16,8 +16,6 @@ fn get_params() -> Params {
}
}
type CipherUnsigned = Cipher<Unsigned>;
#[test]
fn circuit_gets_called() {
static mut FOO: u32 = 0;
@@ -89,11 +87,11 @@ fn compile_failures() {
#[test]
fn capture_circuit_input_args() {
#[circuit(scheme = "bfv")]
fn circuit_with_args(_a: Unsigned, _b: Unsigned, _c: Unsigned, _d: Unsigned) {}
fn circuit_with_args(_a: Signed, _b: Signed, _c: Signed, _d: Signed) {}
assert_eq!(circuit_with_args.scheme_type(), SchemeType::Bfv);
let type_name = Unsigned::type_name();
let type_name = Signed::type_name();
let expected_signature = CallSignature {
arguments: vec![
@@ -116,11 +114,11 @@ fn capture_circuit_input_args() {
#[test]
fn can_add() {
#[circuit(scheme = "bfv")]
fn circuit_with_args(a: CipherUnsigned, b: CipherUnsigned, c: CipherUnsigned) {
fn circuit_with_args(a: Cipher<Signed>, b: Cipher<Signed>, c: Cipher<Signed>) {
let _ = a + b + c;
}
let type_name = Cipher::<Unsigned>::type_name();
let type_name = Cipher::<Signed>::type_name();
let expected_signature = CallSignature {
arguments: vec![type_name.clone(), type_name.clone(), type_name.clone()],
@@ -178,12 +176,12 @@ fn can_add() {
#[test]
fn can_add_plaintext() {
#[circuit(scheme = "bfv")]
fn circuit_with_args(a: Cipher<Unsigned>, b: Unsigned) {
fn circuit_with_args(a: Cipher<Signed>, b: Signed) {
let _ = a + b;
}
let expected_signature = CallSignature {
arguments: vec![Cipher::<Unsigned>::type_name(), Unsigned::type_name()],
arguments: vec![Cipher::<Signed>::type_name(), Signed::type_name()],
returns: vec![],
num_ciphertexts: vec![],
};
@@ -226,11 +224,11 @@ fn can_add_plaintext() {
#[test]
fn can_mul() {
#[circuit(scheme = "bfv")]
fn circuit_with_args(a: CipherUnsigned, b: CipherUnsigned, c: CipherUnsigned) {
fn circuit_with_args(a: Cipher<Signed>, b: Cipher<Signed>, c: Cipher<Signed>) {
let _ = a * b * c;
}
let type_name = Cipher::<Unsigned>::type_name();
let type_name = Cipher::<Signed>::type_name();
let expected_signature = CallSignature {
arguments: vec![type_name.clone(), type_name.clone(), type_name.clone()],
@@ -287,11 +285,11 @@ fn can_mul() {
#[test]
fn can_collect_output() {
#[circuit(scheme = "bfv")]
fn circuit_with_args(a: Cipher<Unsigned>, b: CipherUnsigned) -> CipherUnsigned {
fn circuit_with_args(a: Cipher<Signed>, b: Cipher<Signed>) -> Cipher<Signed> {
a + b * a
}
let type_name = Cipher::<Unsigned>::type_name();
let type_name = Cipher::<Signed>::type_name();
let expected_signature = CallSignature {
arguments: vec![type_name.clone(), type_name.clone()],
@@ -354,13 +352,13 @@ fn can_collect_output() {
fn can_collect_multiple_outputs() {
#[circuit(scheme = "bfv")]
fn circuit_with_args(
a: Cipher<Unsigned>,
b: Cipher<Unsigned>,
) -> (Cipher<Unsigned>, Cipher<Unsigned>) {
a: Cipher<Signed>,
b: Cipher<Signed>,
) -> (Cipher<Signed>, Cipher<Signed>) {
(a + b * a, a)
}
let type_name = Cipher::<Unsigned>::type_name();
let type_name = Cipher::<Signed>::type_name();
let expected_signature = CallSignature {
arguments: vec![type_name.clone(), type_name.clone()],

View File

@@ -1,11 +1,9 @@
use sunscreen_compiler::{types::bfv::Unsigned, types::Cipher, *};
type CipherUnsigned = Cipher<Unsigned>;
use sunscreen_compiler::{types::bfv::Signed, types::Cipher, *};
#[test]
fn can_encrypt_decrypt() {
#[circuit(scheme = "bfv")]
fn foo(a: CipherUnsigned, b: CipherUnsigned) -> CipherUnsigned {
fn foo(a: Cipher<Signed>, b: Cipher<Signed>) -> Cipher<Signed> {
a + b
}
@@ -19,12 +17,12 @@ fn can_encrypt_decrypt() {
let (public, secret) = runtime.generate_keys().unwrap();
let a = runtime.encrypt(Unsigned::from(15), &public).unwrap();
let b = runtime.encrypt(Unsigned::from(5), &public).unwrap();
let a = runtime.encrypt(Signed::from(15), &public).unwrap();
let b = runtime.encrypt(Signed::from(5), &public).unwrap();
let result = runtime.run(&circuit, vec![a, b], &public).unwrap();
let c: Unsigned = runtime.decrypt(&result[0], &secret).unwrap();
let c: Signed = runtime.decrypt(&result[0], &secret).unwrap();
assert_eq!(c, 20.into());
}