diff --git a/Cargo.lock b/Cargo.lock index a78cba7..1d2630c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,7 +518,7 @@ dependencies = [ [[package]] name = "poulpy-core" version = "0.5.0" -source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=b598566cef299a20ac9b159eef61aeadbf66f968#b598566cef299a20ac9b159eef61aeadbf66f968" +source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=067fd785a1d9087f7d9fa437a8503a2d74ac737f#067fd785a1d9087f7d9fa437a8503a2d74ac737f" dependencies = [ "anyhow", "bytemuck", @@ -535,7 +535,7 @@ dependencies = [ [[package]] name = "poulpy-cpu-avx" version = "0.5.0" -source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=b598566cef299a20ac9b159eef61aeadbf66f968#b598566cef299a20ac9b159eef61aeadbf66f968" +source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=067fd785a1d9087f7d9fa437a8503a2d74ac737f#067fd785a1d9087f7d9fa437a8503a2d74ac737f" dependencies = [ "bytemuck", "byteorder", @@ -554,7 +554,7 @@ dependencies = [ [[package]] name = "poulpy-cpu-ref" version = "0.5.0" -source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=b598566cef299a20ac9b159eef61aeadbf66f968#b598566cef299a20ac9b159eef61aeadbf66f968" +source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=067fd785a1d9087f7d9fa437a8503a2d74ac737f#067fd785a1d9087f7d9fa437a8503a2d74ac737f" dependencies = [ "bytemuck", "byteorder", @@ -573,7 +573,7 @@ dependencies = [ [[package]] name = "poulpy-hal" version = "0.5.0" -source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=b598566cef299a20ac9b159eef61aeadbf66f968#b598566cef299a20ac9b159eef61aeadbf66f968" +source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=067fd785a1d9087f7d9fa437a8503a2d74ac737f#067fd785a1d9087f7d9fa437a8503a2d74ac737f" dependencies = [ "anyhow", "bytemuck", @@ -593,7 +593,7 @@ dependencies = [ [[package]] name = "poulpy-schemes" version = "0.5.0" -source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=b598566cef299a20ac9b159eef61aeadbf66f968#b598566cef299a20ac9b159eef61aeadbf66f968" +source = "git+https://github.com/poulpy-fhe/poulpy.git?rev=067fd785a1d9087f7d9fa437a8503a2d74ac737f#067fd785a1d9087f7d9fa437a8503a2d74ac737f" dependencies = [ "anyhow", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index 67f3164..c57cab1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,12 @@ license = "MIT" backend-avx = ["dep:poulpy-cpu-avx"] [dependencies] -poulpy-core = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "b598566cef299a20ac9b159eef61aeadbf66f968" } -poulpy-schemes = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "b598566cef299a20ac9b159eef61aeadbf66f968" } -poulpy-hal = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "b598566cef299a20ac9b159eef61aeadbf66f968" } -poulpy-cpu-ref = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "b598566cef299a20ac9b159eef61aeadbf66f968" } -poulpy-cpu-avx = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "b598566cef299a20ac9b159eef61aeadbf66f968", optional = true } +poulpy-core = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "067fd785a1d9087f7d9fa437a8503a2d74ac737f" } +poulpy-schemes = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "067fd785a1d9087f7d9fa437a8503a2d74ac737f" } +poulpy-hal = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "067fd785a1d9087f7d9fa437a8503a2d74ac737f" } +poulpy-cpu-ref = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "067fd785a1d9087f7d9fa437a8503a2d74ac737f" } +poulpy-cpu-avx = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "067fd785a1d9087f7d9fa437a8503a2d74ac737f", optional = true } getrandom = "0.3" [target.'cfg(target_arch = "x86_64")'.dependencies] -poulpy-cpu-avx = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "b598566cef299a20ac9b159eef61aeadbf66f968", optional = true, features = ["enable-avx"] } +poulpy-cpu-avx = { git = "https://github.com/poulpy-fhe/poulpy.git", rev = "067fd785a1d9087f7d9fa437a8503a2d74ac737f", optional = true, features = ["enable-avx"] } diff --git a/README.md b/README.md index 2bc120b..3e8983e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # 🦑 Squid - + **An ergonomic Rust wrapper for [Poulpy](https://github.com/phantomzone-org/poulpy), making Fully Homomorphic Encryption accessible without sacrificing control.** - + [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![CI](https://github.com/cedoor/squid/actions/workflows/ci.yml/badge.svg)](https://github.com/cedoor/squid/actions) ![Status](https://img.shields.io/badge/status-early%20development-orange) Poulpy is a low-level, modular toolkit exposing the full machinery of lattice-based homomorphic encryption. That power comes with sharp edges: manual scratch arenas, explicit lifecycle transitions, trait-heavy APIs. `squid` wraps Poulpy with a smaller, opinionated surface so you can write FHE programs without managing every byte of workspace memory or tracking which representation a ciphertext currently lives in. @@ -21,8 +21,8 @@ fn main() { let (sk, ek) = ctx.keygen(); // Encrypt two 32-bit integers - let a = ctx.encrypt::(255, &sk, &ek); - let b = ctx.encrypt::(30, &sk, &ek); + let a = ctx.encrypt::(255, &sk); + let b = ctx.encrypt::(30, &sk); // Homomorphic addition: computes (a + b) under encryption let c = ctx.add(&a, &b, &ek); @@ -38,24 +38,24 @@ fn main() { All operations currently require `T = u32` (the only width with compiled BDD circuits in Poulpy). Encrypt and decrypt work for `u8`, `u16`, and `u32`. -| Method | Description | -|---|---| -| `ctx.add(a, b, ek)` | Wrapping addition | -| `ctx.sub(a, b, ek)` | Wrapping subtraction | -| `ctx.and(a, b, ek)` | Bitwise AND | -| `ctx.or(a, b, ek)` | Bitwise OR | -| `ctx.xor(a, b, ek)` | Bitwise XOR | -| `ctx.sll(a, b, ek)` | Logical left shift | -| `ctx.srl(a, b, ek)` | Logical right shift | -| `ctx.sra(a, b, ek)` | Arithmetic right shift | -| `ctx.slt(a, b, ek)` | Signed less-than | -| `ctx.sltu(a, b, ek)` | Unsigned less-than | +| Method | Description | +| -------------------- | ---------------------- | +| `ctx.add(a, b, ek)` | Wrapping addition | +| `ctx.sub(a, b, ek)` | Wrapping subtraction | +| `ctx.and(a, b, ek)` | Bitwise AND | +| `ctx.or(a, b, ek)` | Bitwise OR | +| `ctx.xor(a, b, ek)` | Bitwise XOR | +| `ctx.sll(a, b, ek)` | Logical left shift | +| `ctx.srl(a, b, ek)` | Logical right shift | +| `ctx.sra(a, b, ek)` | Arithmetic right shift | +| `ctx.slt(a, b, ek)` | Signed less-than | +| `ctx.sltu(a, b, ek)` | Unsigned less-than | ## Backends -| Feature | Backend | Notes | -|---------------|------------|--------------------------------| -| *(default)* | `FFT64Ref` | Portable | +| Feature | Backend | Notes | +| ------------- | ---------- | ------------------------------- | +| _(default)_ | `FFT64Ref` | Portable | | `backend-avx` | `FFT64Avx` | x86-64, AVX2+FMA (~3–5× vs ref) | ```sh @@ -84,7 +84,7 @@ The public API is identical regardless of which backend is selected. - [ ] Identity / noise refresh: [#11](https://github.com/cedoor/squid/issues/11) - [ ] NTT backend: [#12](https://github.com/cedoor/squid/issues/12) - [x] Key serialization: [#13](https://github.com/cedoor/squid/issues/13) -- [ ] Revert `encrypt` workaround once upstream poulpy bug is fixed: [#24](https://github.com/cedoor/squid/issues/24) +- [x] Revert `encrypt` workaround once upstream poulpy bug is fixed: [#24](https://github.com/cedoor/squid/issues/24) ### Milestone 3 — Developer Experience & Optimization: [#3](https://github.com/cedoor/squid/milestone/3) diff --git a/examples/add_u32.rs b/examples/add_u32.rs index 3f0607c..6a987b6 100644 --- a/examples/add_u32.rs +++ b/examples/add_u32.rs @@ -20,8 +20,8 @@ fn main() { let b: u32 = 30; println!("Encrypting {a} and {b}..."); - let ct_a = ctx.encrypt::(a, &sk, &ek); - let ct_b = ctx.encrypt::(b, &sk, &ek); + let ct_a = ctx.encrypt::(a, &sk); + let ct_b = ctx.encrypt::(b, &sk); println!("Computing homomorphic addition..."); let ct_c = ctx.add(&ct_a, &ct_b, &ek); diff --git a/src/ciphertext.rs b/src/ciphertext.rs index 03300f9..cb932de 100644 --- a/src/ciphertext.rs +++ b/src/ciphertext.rs @@ -1,19 +1,9 @@ //! The user-facing ciphertext type. //! -//! [`Ciphertext`] wraps Poulpy's packed `FheUint, T>` (the wire -//! format) and additionally caches the prepared (DFT-domain) `FheUintPrepared` -//! produced at encryption time. Homomorphic ops consume the prepared cache; -//! [`Context::decrypt`](crate::context::Context::decrypt) and -//! [`Ciphertext::serialize`] use the packed form only. -//! -//! ## Chaining limitation -//! -//! In the currently pinned Poulpy revision, the `FheUint -> FheUintPrepared` -//! re-prepare path produces incorrect results, so a ciphertext that has lost -//! its prepared cache (an op result, or a freshly deserialized blob) cannot be -//! used as input to another homomorphic op. Doing so panics with a descriptive -//! message. This restriction will lift as upstream Poulpy stabilizes that -//! pipeline. +//! [`Ciphertext`] is a thin wrapper over Poulpy's packed +//! `FheUint, T>`. Homomorphic ops re-prepare each input on demand +//! inside [`crate::context::Context`]; the DFT-domain form is never cached on +//! the user-visible type and never surfaces in the public API. //! //! Standard-form wire encoding is [`Ciphertext::serialize`] / //! [`Ciphertext::deserialize`] / [`crate::context::Context::serialize_ciphertext`] / @@ -24,8 +14,8 @@ use std::io; use poulpy_core::layouts::{GLWEInfos, GLWEToRef}; -use poulpy_hal::layouts::{DeviceBuf, WriterTo}; -use poulpy_schemes::bin_fhe::bdd_arithmetic::{FheUint, FheUintPrepared, UnsignedInteger}; +use poulpy_hal::layouts::WriterTo; +use poulpy_schemes::bin_fhe::bdd_arithmetic::{FheUint, UnsignedInteger}; use crate::context::Context; @@ -42,22 +32,17 @@ pub(crate) const CIPHERTEXT_BLOB_VERSION: u8 = 1; /// /// ## Lifecycle /// -/// 1. Create with [`crate::Context::encrypt`] (caches the prepared form for ops). +/// 1. Create with [`crate::Context::encrypt`]. /// 2. Pass to homomorphic operations (`ctx.add`, `ctx.xor`, …). /// 3. Recover the plaintext with [`crate::Context::decrypt`]. pub struct Ciphertext { pub(crate) inner: FheUint, T>, - pub(crate) prepared: - Option, T, crate::backend::BE>>, } impl Ciphertext { /// Serializes the packed GLWE ciphertext (little-endian, versioned). The plaintext type `T` /// is recorded in the blob; use the same `T` with [`Ciphertext::deserialize`]. /// - /// The prepared cache is **not** serialized; deserialized ciphertexts can only be - /// decrypted (see module-level note about chaining). - /// /// Same as [`crate::context::Context::serialize_ciphertext`] with this value. pub fn serialize(&self) -> io::Result> { let mut out = Vec::new(); diff --git a/src/context.rs b/src/context.rs index e0ed6ec..afd87a9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -11,8 +11,8 @@ //! let mut ctx = Context::new(Params::unsecure()).with_options(ContextOptions::default()); //! let (sk, ek) = ctx.keygen(); //! -//! let a = ctx.encrypt::(42, &sk, &ek); -//! let b = ctx.encrypt::(7, &sk, &ek); +//! let a = ctx.encrypt::(42, &sk); +//! let b = ctx.encrypt::(7, &sk); //! let c = ctx.add(&a, &b, &ek); //! let result: u32 = ctx.decrypt(&c, &sk); //! ``` @@ -35,8 +35,8 @@ use poulpy_hal::{ use poulpy_schemes::bin_fhe::{ bdd_arithmetic::{ Add, And, BDDEncryptionInfos, BDDKey, BDDKeyEncryptSk, BDDKeyLayout, BDDKeyPrepared, - BDDKeyPreparedFactory, FheUint, FheUintPrepared, FromBits, Or, Sll, Slt, Sltu, Sra, Srl, - Sub, ToBits, UnsignedInteger, Xor, + BDDKeyPreparedFactory, FheUint, FheUintPrepare, FheUintPrepared, FromBits, Or, Sll, Slt, + Sltu, Sra, Srl, Sub, ToBits, UnsignedInteger, Xor, }, blind_rotation::{BlindRotationKeyLayout, CGGI}, circuit_bootstrapping::CircuitBootstrappingKeyLayout, @@ -626,79 +626,44 @@ impl Context { "trailing bytes in ciphertext blob", )); } - Ok(Ciphertext { - inner: fhe_uint, - prepared: None, - }) + Ok(Ciphertext { inner: fhe_uint }) } // ── Encrypt / Decrypt ──────────────────────────────────────────────────── /// Encrypt a plaintext value under the given secret key. /// - /// Internally encrypts directly to the prepared (DFT-domain) form via - /// `FheUintPrepared::encrypt_sk`, then packs to a standard `FheUint` via - /// `from_fhe_uint_prepared` (which is why an [`EvaluationKey`] is required). - /// This matches the path validated by Poulpy's `test_bdd_add` and avoids the - /// `FheUint::encrypt_sk -> FheUintPrepared::prepare` pipeline, which is - /// currently broken upstream (`b598566`). - /// - /// The cached prepared form is consumed by homomorphic ops; the packed - /// inner form is used for [`Context::decrypt`] and serialization. + /// Packs the bits of `value` into a single standard-form GLWE ciphertext + /// via `FheUint::encrypt_sk`. The DFT-domain prepared form is rebuilt + /// on demand inside [`Context::eval_binary`] when the value is used as an + /// operand. /// /// `T` must be one of `u8`, `u16`, `u32`, `u64`, `u128`. Note that /// homomorphic arithmetic operations are currently only implemented for /// `u32` (the only type with compiled BDD circuits in `poulpy-schemes`). - pub fn encrypt(&mut self, value: T, sk: &SecretKey, ek: &EvaluationKey) -> Ciphertext + pub fn encrypt(&mut self, value: T, sk: &SecretKey) -> Ciphertext where - T: UnsignedInteger + ToBits + FromBits, + T: UnsignedInteger + ToBits, { let mut source_xa = random_source(); let mut source_xe = random_source(); - let ggsw_enc_infos = EncryptionLayout::new_from_default_sigma(self.params.ggsw_layout) - .expect("default GGSW encryption sigma"); - - // TODO(poulpy-bug): switch to dynamic sizing once poulpy fixes the - // upstream `FheUint::encrypt_sk -> FheUintPrepared::prepare` bug - // (see `crate::ciphertext` module docs). Once fixed, encrypt should - // route through that path and use `FheUint::encrypt_sk_tmp_bytes` + - // `Module::fhe_uint_prepare_tmp_bytes` for exact scratch sizing. - // - // Until then we work around the bug via `FheUintPrepared::encrypt_sk` - // followed by `FheUint::from_fhe_uint_prepared`. Poulpy exposes no - // wrapper-level `*_tmp_bytes` helpers for either, and hand-composing - // from primitives is fragile (both wrappers call into deeper helpers - // like `glwe_pack -> glwe_trace` whose runtime scratch checks don't - // match a naive sum of public `_tmp_bytes`). Poulpy's own - // `bdd_arithmetic` example/tests use a single 4 MiB arena for the - // whole pipeline; we do the same here for these two sequential ops. - const ENCRYPT_SCRATCH_BYTES: usize = 1 << 22; - let mut scratch_arena = scratch::new_arena(ENCRYPT_SCRATCH_BYTES); - - let mut prepared: FheUintPrepared, T, crate::backend::BE> = - FheUintPrepared::alloc_from_infos(&self.module, &self.params.ggsw_layout); - prepared.encrypt_sk( + let glwe_enc_infos = EncryptionLayout::new_from_default_sigma(self.params.glwe_layout) + .expect("default GLWE encryption sigma"); + + let mut fhe_uint: FheUint, T> = FheUint::alloc_from_infos(&self.params.glwe_layout); + let enc_bytes = fhe_uint.encrypt_sk_tmp_bytes(&self.module); + let mut scratch_e = scratch::new_arena(enc_bytes); + fhe_uint.encrypt_sk( &self.module, value, &sk.sk_glwe_prepared, - &ggsw_enc_infos, + &glwe_enc_infos, &mut source_xe, &mut source_xa, - scratch::borrow(&mut scratch_arena), + scratch::borrow(&mut scratch_e), ); - let mut packed: FheUint, T> = FheUint::alloc_from_infos(&self.params.glwe_layout); - packed.from_fhe_uint_prepared( - &self.module, - &prepared, - &ek.bdd_key_prepared, - scratch::borrow(&mut scratch_arena), - ); - - Ciphertext { - inner: packed, - prepared: Some(prepared), - } + Ciphertext { inner: fhe_uint } } /// Decrypt a ciphertext and return the plaintext value. @@ -717,12 +682,10 @@ impl Context { // ── Internal helper ─────────────────────────────────────────────────────── - /// Run a binary op on the prepared form of `a` and `b`. + /// Prepare `a` and `b`, run `op`, and return the result. /// - /// Both inputs must carry their prepared cache (i.e. come straight from - /// [`Context::encrypt`]). Op outputs and deserialized ciphertexts have - /// no cache and panic with a clear message — see the [`crate::ciphertext`] - /// module docs for the upstream limitation. + /// Builds a fresh `FheUintPrepared` for each input on every call, then invokes `op` with both prepared operands and a + /// scratch region sized to whichever of prepare / op is larger. fn eval_binary( &mut self, a: &Ciphertext, @@ -743,27 +706,44 @@ impl Context { &mut poulpy_hal::layouts::Scratch, ), { - const NO_PREPARED_CACHE: &str = - "ciphertext lacks prepared cache; only freshly encrypted ciphertexts can be operated \ - on in this Poulpy revision (see ciphertext module docs)"; - let a_prep = a.prepared.as_ref().expect(NO_PREPARED_CACHE); - let b_prep = b.prepared.as_ref().expect(NO_PREPARED_CACHE); + let mut a_prep: FheUintPrepared, T, crate::backend::BE> = + FheUintPrepared::alloc_from_infos(&self.module, &self.params.ggsw_layout); + let mut b_prep: FheUintPrepared, T, crate::backend::BE> = + FheUintPrepared::alloc_from_infos(&self.module, &self.params.ggsw_layout); + + let prepare_bytes = self.module.fhe_uint_prepare_tmp_bytes( + self.params.binary_block_size as usize, + 1, + &self.params.ggsw_layout, + &self.params.glwe_layout, + &ek.bdd_key_prepared, + ); + let mut scratch_arena = scratch::new_arena(prepare_bytes.max(eval_scratch_bytes)); + + a_prep.prepare::( + &self.module, + &a.inner, + &ek.bdd_key_prepared, + scratch::borrow(&mut scratch_arena), + ); + b_prep.prepare::( + &self.module, + &b.inner, + &ek.bdd_key_prepared, + scratch::borrow(&mut scratch_arena), + ); let mut out: FheUint, T> = FheUint::alloc_from_infos(&self.params.glwe_layout); - let mut scratch_eval = scratch::new_arena(eval_scratch_bytes); op( &self.module, self.options.eval_threads, &mut out, - a_prep, - b_prep, + &a_prep, + &b_prep, &ek.bdd_key_prepared, - scratch::borrow(&mut scratch_eval), + scratch::borrow(&mut scratch_arena), ); - Ciphertext { - inner: out, - prepared: None, - } + Ciphertext { inner: out } } // ── Arithmetic and logical operations ──────────────────────────────────── diff --git a/tests/bdd_parallel.rs b/tests/bdd_parallel.rs index c64ce02..bf44f3e 100644 --- a/tests/bdd_parallel.rs +++ b/tests/bdd_parallel.rs @@ -10,12 +10,12 @@ fn eval_threads_two_matches_one() { let (sk1, ek1) = ctx1.keygen(); let (sk2, ek2) = ctx2.keygen(); - let ct_a1 = ctx1.encrypt(7u32, &sk1, &ek1); - let ct_b1 = ctx1.encrypt(5u32, &sk1, &ek1); + let ct_a1 = ctx1.encrypt(7u32, &sk1); + let ct_b1 = ctx1.encrypt(5u32, &sk1); let c1 = ctx1.add(&ct_a1, &ct_b1, &ek1); - let ct_a2 = ctx2.encrypt(7u32, &sk2, &ek2); - let ct_b2 = ctx2.encrypt(5u32, &sk2, &ek2); + let ct_a2 = ctx2.encrypt(7u32, &sk2); + let ct_b2 = ctx2.encrypt(5u32, &sk2); let c2 = ctx2.add(&ct_a2, &ct_b2, &ek2); let r1 = ctx1.decrypt(&c1, &sk1); diff --git a/tests/ciphertext_serialization.rs b/tests/ciphertext_serialization.rs index 526c205..fb1853f 100644 --- a/tests/ciphertext_serialization.rs +++ b/tests/ciphertext_serialization.rs @@ -3,9 +3,9 @@ use squid::{Ciphertext, Context, Params}; #[test] fn ciphertext_serialize_roundtrip_decrypts() { let mut ctx = Context::new(Params::test()); - let (sk, ek) = ctx.keygen(); + let (sk, _ek) = ctx.keygen(); - let ct = ctx.encrypt::(0xdead_beef, &sk, &ek); + let ct = ctx.encrypt::(0xdead_beef, &sk); let blob = ct.serialize().expect("serialize ciphertext"); let ct2 = Ciphertext::::deserialize(&mut ctx, &blob).expect("deserialize ciphertext"); @@ -15,9 +15,9 @@ fn ciphertext_serialize_roundtrip_decrypts() { #[test] fn ciphertext_wrong_type_parameter_is_rejected() { let mut ctx = Context::new(Params::test()); - let (sk, ek) = ctx.keygen(); + let (sk, _ek) = ctx.keygen(); - let ct = ctx.encrypt::(1, &sk, &ek); + let ct = ctx.encrypt::(1, &sk); let blob = ct.serialize().expect("serialize"); match Ciphertext::::deserialize(&mut ctx, &blob) { @@ -30,9 +30,9 @@ fn ciphertext_wrong_type_parameter_is_rejected() { fn ciphertext_rejects_mismatched_params_glwe_layout() { let mut ctx_encrypt = Context::new(Params::test()); let mut ctx_other = Context::new(Params::unsecure()); - let (sk, ek) = ctx_encrypt.keygen(); + let (sk, _ek) = ctx_encrypt.keygen(); - let ct = ctx_encrypt.encrypt::(1, &sk, &ek); + let ct = ctx_encrypt.encrypt::(1, &sk); let blob = ct.serialize().expect("serialize"); match Ciphertext::::deserialize(&mut ctx_other, &blob) { diff --git a/tests/evaluation_key_serialization.rs b/tests/evaluation_key_serialization.rs index 408438d..e791f04 100644 --- a/tests/evaluation_key_serialization.rs +++ b/tests/evaluation_key_serialization.rs @@ -9,8 +9,8 @@ fn evaluation_key_serialize_roundtrip_from_os_random() { let ek_blob = ek.serialize().expect("serialize ek"); let ek2 = EvaluationKey::deserialize(&mut ctx, &ek_blob).expect("deserialize ek"); - let a = ctx.encrypt::(11, &sk, &ek); - let b = ctx.encrypt::(22, &sk, &ek); + let a = ctx.encrypt::(11, &sk); + let b = ctx.encrypt::(22, &sk); let c = ctx.add(&a, &b, &ek2); assert_eq!(ctx.decrypt(&c, &sk), 33); } diff --git a/tests/keygen_seeds.rs b/tests/keygen_seeds.rs index c2eb155..aaeeb5c 100644 --- a/tests/keygen_seeds.rs +++ b/tests/keygen_seeds.rs @@ -45,8 +45,8 @@ fn secret_key_from_lattice_seed_matches_full_keygen_lattice_part() { fn keygen_from_seeds_homomorphic_smoke() { let mut ctx = Context::new(Params::test()); let (sk, ek) = ctx.keygen_from_seeds(SEEDS); - let x = ctx.encrypt::(10, &sk, &ek); - let y = ctx.encrypt::(20, &sk, &ek); + let x = ctx.encrypt::(10, &sk); + let y = ctx.encrypt::(20, &sk); let z = ctx.add(&x, &y, &ek); assert_eq!(ctx.decrypt(&z, &sk), 30); }