Browse Source

Updated to SEAL 2.3.1

Kim Laine 5 years ago
parent
commit
dead23d39d
7 changed files with 40 additions and 1874 deletions
  1. 20 0
      CMakeLists.txt
  2. 0 30
      Makefile
  3. 6 29
      README.md
  4. 0 1801
      SEAL_v2.3.0-4.patch
  5. 1 1
      pir.cpp
  6. 6 6
      pir_client.cpp
  7. 7 7
      pir_server.cpp

+ 20 - 0
CMakeLists.txt

@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(SealPIR VERSION 1.1 LANGUAGES CXX)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
+
+add_executable(sealpir 
+	main.cpp
+	pir.cpp
+	pir_client.cpp
+	pir_server.cpp
+)
+
+find_package(SEAL 2.3.1 EXACT REQUIRED)
+find_package(Threads REQUIRED)
+
+target_link_libraries(sealpir 
+	SEAL::seal
+	Threads::Threads
+)

+ 0 - 30
Makefile

@@ -1,30 +0,0 @@
-CXX=g++
-
-IDIR =../SEAL/SEAL/
-LDIR =../SEAL/bin/
-
-CFLAGS=-std=c++11 -I. -I$(IDIR) -O3
-ODIR=obj
-BDIR=bin
-LIBS=-L$(LDIR) -lseal
-
-DEPS = pir.hpp pir_server.hpp pir_client.hpp
-
-_OBJ = pir.o main.o pir_server.o pir_client.o 
-OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
-
-
-$(ODIR)/%.o: %.cpp $(DEPS)
-	@mkdir -p $(@D)
-	$(CXX) -c -o $@ $< $(CFLAGS)
-
-$(BDIR)/main: $(OBJ) $(DEPS) 
-	@mkdir -p $(@D)
-	$(CXX) -o $@ $(OBJ) $(CFLAGS) $(LIBS)
-
-all: main
-
-.PHONY: clean
-
-clean:
-	rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ $(BDIR)/* 

+ 6 - 29
README.md

@@ -5,39 +5,16 @@ SealPIR is a (research) library and should not be used in production systems. Se
 
 # Compiling SEAL
 
-SealPIR depends on SEAL v2.3.0-4 and a patch that exposes the substitution operator. You can get SEAL v2.3.0-4 from this [link](http://sealcrypto.org).
-
-Once you have downloaded SEAL, apply the patch SEAL_v2.3.0-4.patch (available in this repository) to it. Here are the exact steps. 
-
-We assume that you are in the SEAL directory, and that you have copied the patch to this directory.
-
-First, convert the SEAL directory into a git repo:
-
-```sh
-$ git init
-$ git add .
-$ git commit -m "SEAL v2.3.0-4"
-```
-Then, apply the patch:
-
-```sh
-$ git am SEAL_v2.3.0-4.patch
-```
-
-Finally, compile SEAL (NOTE: gcc-8 is not currently supported):
-
-```sh
-$ cd SEAL
-$ ./configure CXXFLAGS="-O3 -march=native -fPIC"
-$ make clean && make
-```
+SealPIR depends on SEAL 2.3.1 ([link](http://sealcrypto.org). Download SEAL, and follow the instructions in INSTALL.txt to install it system-wide.
 
 # Compiling SealPIR
 
-The current Makefile assumes that SEAL_v2.3.0-4 is located (relative to SealPIR) at: ../SEAL/. If this is not the case change the IDIR and LDIR variables in the Makefile accordingly.
-
-To compile SealPIR simply run ``make``. It should produce a binary file in ``bin/main``.
+Once SEAL 2.3.1 is installed, to build SealPIR simply run:
 
+	cmake .
+	make
+	
+This should produce a binary file ``bin/sealpir``.
 
 # Using SealPIR
 

+ 0 - 1801
SEAL_v2.3.0-4.patch

@@ -1,1801 +0,0 @@
-From e37bf6b79c81cbbeff19378ad425f987c036286b Mon Sep 17 00:00:00 2001
-From: Kim Laine <kim.laine@microsoft.com>
-Date: Mon, 4 Dec 2017 16:09:56 -0800
-Subject: [PATCH 1/3] Explosed generic Galois automorphisms in public API
-
----
- SEAL/seal/evaluator.cpp                 |   5 +
- SEAL/seal/evaluator.h                   | 181 ++++++++++++++++++++++++++------
- SEAL/seal/keygenerator.cpp              |   8 --
- SEAL/seal/keygenerator.h                |  40 ++++---
- SEALNET/sealnet/EvaluatorWrapper.cpp    | 146 ++++++++++++++++++++++++++
- SEALNET/sealnet/EvaluatorWrapper.h      | 157 ++++++++++++++++++++++++---
- SEALNET/sealnet/KeyGeneratorWrapper.cpp |  33 ++++++
- SEALNET/sealnet/KeyGeneratorWrapper.h   |  35 ++++++
- SEALNETTest/EvaluatorWrapper.cs         |  82 +++++++++++++++
- SEALNETTest/KeyGeneratorWrapper.cs      | 147 ++++++++++++++++++++++++++
- SEALTest/evaluator.cpp                  |  79 ++++++++++++++
- SEALTest/keygenerator.cpp               | 146 ++++++++++++++++++++++++++
- 12 files changed, 990 insertions(+), 69 deletions(-)
-
-diff --git a/SEAL/seal/evaluator.cpp b/SEAL/seal/evaluator.cpp
-index 0a5b99d..8945b5d 100644
---- a/SEAL/seal/evaluator.cpp
-+++ b/SEAL/seal/evaluator.cpp
-@@ -1791,6 +1791,11 @@ namespace seal
- 
-     void Evaluator::rotate_rows(Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys, const MemoryPoolHandle &pool)
-     {
-+        if (!qualifiers_.enable_batching)
-+        {
-+            throw logic_error("encryption parameters do not support batching");
-+        }
-+
-         // Is there anything to do?
-         if (steps == 0)
-         {
-diff --git a/SEAL/seal/evaluator.h b/SEAL/seal/evaluator.h
-index 5b67455..93cc1d2 100644
---- a/SEAL/seal/evaluator.h
-+++ b/SEAL/seal/evaluator.h
-@@ -894,13 +894,136 @@ namespace seal
-         @throws std::invalid_argument if plain_ntt is zero
-         @throws std::logic_error if destination_ntt is aliased and needs to be reallocated
-         */
--        inline void multiply_plain_ntt(const Ciphertext &encrypted_ntt, const Plaintext &plain_ntt, 
--            Ciphertext &destination_ntt)
-+        inline void multiply_plain_ntt(const Ciphertext &encrypted_ntt, 
-+            const Plaintext &plain_ntt, Ciphertext &destination_ntt)
-         {
-             destination_ntt = encrypted_ntt;
-             multiply_plain_ntt(destination_ntt, plain_ntt);
-         }
- 
-+        /**
-+        Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
-+        an appropriate set of Galois keys must also be provided. Dynamic memory allocations 
-+        in the process are allocated from the memory pool pointed to by the given 
-+        MemoryPoolHandle.
-+        
-+        The desired Galois automorphism is given as a Galois element, and must be an odd 
-+        integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
-+        with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps 
-+        to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
-+        i steps to the right. The Galois element M-1 corresponds to a column rotation (row
-+        swap). In the polynomial view (not batching), a Galois automorphism by a Galois
-+        element p changes Enc(plain(x)) to Enc(plain(x^p)).
-+
-+        @param[in] encrypted The ciphertext to apply the Galois automorphism to
-+        @param[in] galois_elt The Galois element
-+        @param[in] galois_keys The Galois keys
-+        @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
-+        @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-+        encryption parameters
-+        @throws std::invalid_argument if encrypted has size greater than two
-+        @throws std::invalid_argument if the Galois element is not valid
-+        @throws std::invalid_argument if necessary Galois keys are not present
-+        @throws std::invalid_argument if pool is uninitialized
-+        */
-+        void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt, 
-+            const GaloisKeys &galois_keys, const MemoryPoolHandle &pool);
-+
-+        /**
-+        Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
-+        an appropriate set of Galois keys must also be provided. Dynamic memory allocations
-+        in the process are allocated from the memory pool pointed to by the local
-+        MemoryPoolHandle.
-+
-+        The desired Galois automorphism is given as a Galois element, and must be an odd
-+        integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
-+        with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
-+        to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
-+        i steps to the right. The Galois element M-1 corresponds to a column rotation (row
-+        swap). In the polynomial view (not batching), a Galois automorphism by a Galois
-+        element p changes Enc(plain(x)) to Enc(plain(x^p)).
-+
-+        @param[in] encrypted The ciphertext to apply the Galois automorphism to
-+        @param[in] galois_elt The Galois element
-+        @param[in] galois_keys The Galois keys
-+        @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-+        encryption parameters
-+        @throws std::invalid_argument if encrypted has size greater than two
-+        @throws std::invalid_argument if the Galois element is not valid
-+        @throws std::invalid_argument if necessary Galois keys are not present
-+        */
-+        inline void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt, 
-+            const GaloisKeys &galois_keys)
-+        {
-+            apply_galois(encrypted, galois_elt, galois_keys, pool_);
-+        }
-+
-+        /**
-+        Applies a Galois automorphism to a ciphertext and writes the result to the
-+        destination parameter. To evaluate the Galois automorphism, an appropriate set of 
-+        Galois keys must also be provided. Dynamic memory allocations in the process are 
-+        allocated from the memory pool pointed to by the given MemoryPoolHandle.
-+
-+        The desired Galois automorphism is given as a Galois element, and must be an odd
-+        integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
-+        with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
-+        to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
-+        i steps to the right. The Galois element M-1 corresponds to a column rotation (row
-+        swap). In the polynomial view (not batching), a Galois automorphism by a Galois
-+        element p changes Enc(plain(x)) to Enc(plain(x^p)).
-+
-+        @param[in] encrypted The ciphertext to apply the Galois automorphism to
-+        @param[in] galois_elt The Galois element
-+        @param[in] galois_keys The Galois keys
-+        @param[out] destination The ciphertext to overwrite with the result
-+        @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
-+        @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-+        encryption parameters
-+        @throws std::invalid_argument if encrypted has size greater than two
-+        @throws std::invalid_argument if the Galois element is not valid
-+        @throws std::invalid_argument if necessary Galois keys are not present
-+        @throws std::logic_error if destination is aliased and needs to be reallocated
-+        @throws std::invalid_argument if pool is uninitialized
-+        */
-+        inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
-+            const GaloisKeys &galois_keys, Ciphertext &destination, 
-+            const MemoryPoolHandle &pool)
-+        {
-+            destination = encrypted;
-+            apply_galois(destination, galois_elt, galois_keys, pool);
-+        }
-+
-+        /**
-+        Applies a Galois automorphism to a ciphertext and writes the result to the
-+        destination parameter. To evaluate the Galois automorphism, an appropriate set of
-+        Galois keys must also be provided. Dynamic memory allocations in the process are
-+        allocated from the memory pool pointed to by the local MemoryPoolHandle.
-+
-+        The desired Galois automorphism is given as a Galois element, and must be an odd
-+        integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus). Used
-+        with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
-+        to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
-+        i steps to the right. The Galois element M-1 corresponds to a column rotation (row
-+        swap). In the polynomial view (not batching), a Galois automorphism by a Galois
-+        element p changes Enc(plain(x)) to Enc(plain(x^p)).
-+
-+        @param[in] encrypted The ciphertext to apply the Galois automorphism to
-+        @param[in] galois_elt The Galois element
-+        @param[in] galois_keys The Galois keys
-+        @param[out] destination The ciphertext to overwrite with the result
-+        @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-+        encryption parameters
-+        @throws std::invalid_argument if encrypted has size greater than two
-+        @throws std::invalid_argument if the Galois element is not valid
-+        @throws std::invalid_argument if necessary Galois keys are not present
-+        @throws std::logic_error if destination is aliased and needs to be reallocated
-+        */
-+        inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
-+            const GaloisKeys &galois_keys, Ciphertext &destination)
-+        {
-+            apply_galois(encrypted, galois_elt, galois_keys, destination, pool_);
-+        }
-+
-         /**
-         Rotates plaintext matrix rows cyclically. When batching is used, this function rotates
-         the encrypted plaintext matrix rows cyclically to the left (steps > 0) or to the right
-@@ -913,6 +1036,7 @@ namespace seal
-         @param[in] steps The number of steps to rotate (negative left, positive right)
-         @param[in] galois_keys The Galois keys
-         @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -934,13 +1058,15 @@ namespace seal
-         @param[in] encrypted The ciphertext to rotate
-         @param[in] steps The number of steps to rotate (negative left, positive right)
-         @param[in] galois_keys The Galois keys
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-         @throws std::invalid_argument if steps has too big absolute value
-         @throws std::invalid_argument if necessary Galois keys are not present
-         */
--        inline void rotate_rows(Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys)
-+        inline void rotate_rows(Ciphertext &encrypted, int steps, 
-+            const GaloisKeys &galois_keys)
-         {
-             rotate_rows(encrypted, steps, galois_keys, pool_);
-         }
-@@ -959,6 +1085,7 @@ namespace seal
-         @param[in] galois_keys The Galois keys
-         @param[out] destination The ciphertext to overwrite with the rotated result
-         @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -968,7 +1095,8 @@ namespace seal
-         @throws std::invalid_argument if pool is uninitialized
-         */
-         inline void rotate_rows(const Ciphertext &encrypted, int steps, 
--            const GaloisKeys &galois_keys, Ciphertext &destination, const MemoryPoolHandle &pool)
-+            const GaloisKeys &galois_keys, Ciphertext &destination, 
-+            const MemoryPoolHandle &pool)
-         {
-             destination = encrypted;
-             rotate_rows(destination, steps, galois_keys, pool);
-@@ -987,6 +1115,7 @@ namespace seal
-         @param[in] steps The number of steps to rotate (negative left, positive right)
-         @param[in] galois_keys The Galois keys
-         @param[out] destination The ciphertext to overwrite with the rotated result
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -1011,6 +1140,7 @@ namespace seal
-         @param[in] galois_keys The Galois keys
-         @param[out] destination The ciphertext to overwrite with the rotated result
-         @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -1021,6 +1151,10 @@ namespace seal
-         inline void rotate_columns(Ciphertext &encrypted, const GaloisKeys &galois_keys, 
-             const MemoryPoolHandle &pool)
-         {
-+            if (!qualifiers_.enable_batching)
-+            {
-+                throw std::logic_error("encryption parameters do not support batching");
-+            }
-             std::uint64_t m = (parms_.poly_modulus().coeff_count() - 1) << 1;
-             apply_galois(encrypted, m - 1, galois_keys, pool);
-         }
-@@ -1035,6 +1169,7 @@ namespace seal
-         @param[in] encrypted The ciphertext to rotate
-         @param[in] galois_keys The Galois keys
-         @param[out] destination The ciphertext to overwrite with the rotated result
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -1058,6 +1193,7 @@ namespace seal
-         @param[in] galois_keys The Galois keys
-         @param[out] destination The ciphertext to overwrite with the rotated result
-         @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -1084,6 +1220,7 @@ namespace seal
-         @param[in] encrypted The ciphertext to rotate
-         @param[in] galois_keys The Galois keys
-         @param[out] destination The ciphertext to overwrite with the rotated result
-+        @throws std::logic_error if the encryption parameters do not support batching
-         @throws std::invalid_argument if encrypted or galois_keys is not valid for the
-         encryption parameters
-         @throws std::invalid_argument if encrypted has size greater than two
-@@ -1101,10 +1238,11 @@ namespace seal
- 
-         Evaluator &operator =(Evaluator &&assign) = delete;
- 
--        void relinearize(Ciphertext &encrypted, const EvaluationKeys &evaluation_keys, int destination_size, 
--            const MemoryPoolHandle &pool);
-+        void relinearize(Ciphertext &encrypted, const EvaluationKeys &evaluation_keys, 
-+            int destination_size, const MemoryPoolHandle &pool);
- 
--        inline void decompose_single_coeff(const std::uint64_t *value, std::uint64_t *destination, const MemoryPoolHandle &pool)
-+        inline void decompose_single_coeff(const std::uint64_t *value, 
-+            std::uint64_t *destination, const MemoryPoolHandle &pool)
-         {
- #ifdef SEAL_DEBUG
-             if (value == nullptr)
-@@ -1150,7 +1288,8 @@ namespace seal
-             }
-         }
- 
--        inline void decompose(const std::uint64_t *value, std::uint64_t *destination, const MemoryPoolHandle &pool)
-+        inline void decompose(const std::uint64_t *value, std::uint64_t *destination, 
-+            const MemoryPoolHandle &pool)
-         {
- #ifdef SEAL_DEBUG
-             if (value == nullptr)
-@@ -1209,32 +1348,6 @@ namespace seal
- 
-         void populate_Zmstar_to_generator();
- 
--        // The apply_galois function applies a Galois automorphism to a ciphertext. 
--        // It is needed for slot permutations. 
--        // Input: encryption of M(x) and an integer p such that gcd(p, m) = 1.
--        // Output: encryption of M(x^p). 
--        // The function requires certain GaloisKeys and auxiliary data. 
--        void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt, const GaloisKeys &evaluation_keys,
--            const MemoryPoolHandle &pool);
--
--        inline void apply_galois(Ciphertext &encrypted, std::uint64_t galois_elt, const GaloisKeys &evaluation_keys)
--        {
--            apply_galois(encrypted, galois_elt, evaluation_keys, pool_);
--        }
--
--        inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
--            const GaloisKeys &evaluation_keys, Ciphertext &destination, const MemoryPoolHandle &pool)
--        {
--            destination = encrypted;
--            apply_galois(destination, galois_elt, evaluation_keys, pool);
--        }
--
--        inline void apply_galois(const Ciphertext &encrypted, std::uint64_t galois_elt,
--            const GaloisKeys &evaluation_keys, Ciphertext &destination)
--        {
--            apply_galois(encrypted, galois_elt, evaluation_keys, destination, pool_);
--        }
--
-         MemoryPoolHandle pool_;
- 
-         EncryptionParameters parms_;
-diff --git a/SEAL/seal/keygenerator.cpp b/SEAL/seal/keygenerator.cpp
-index fa7fd46..ee6338f 100644
---- a/SEAL/seal/keygenerator.cpp
-+++ b/SEAL/seal/keygenerator.cpp
-@@ -293,10 +293,6 @@ namespace seal
-         {
-             throw logic_error("cannot generate galois keys for unspecified secret key");
-         }
--        if (!qualifiers_.enable_batching)
--        {
--            throw logic_error("encryption parameters are not valid for batching");
--        }
- 
-         // Check that decomposition_bit_count is in correct interval
-         if (decomposition_bit_count < SEAL_DBC_MIN || decomposition_bit_count > SEAL_DBC_MAX)
-@@ -426,10 +422,6 @@ namespace seal
-         {
-             throw logic_error("cannot generate galois keys for unspecified secret key");
-         }
--        if (!qualifiers_.enable_batching)
--        {
--            throw logic_error("encryption parameters are not valid for batching");
--        }
- 
-         // Check that decomposition_bit_count is in correct interval
-         if (decomposition_bit_count < SEAL_DBC_MIN || decomposition_bit_count > SEAL_DBC_MAX)
-diff --git a/SEAL/seal/keygenerator.h b/SEAL/seal/keygenerator.h
-index a702a3e..393aa61 100644
---- a/SEAL/seal/keygenerator.h
-+++ b/SEAL/seal/keygenerator.h
-@@ -99,15 +99,38 @@ namespace seal
-         }
- 
-         /**
--        Generates Galois keys.
-+        Generates Galois keys. This function creates logarithmically many (in degree of the
-+        polynomial modulus) Galois keys that is sufficient to apply any Galois automorphism
-+        (e.g. rotations) on encrypted data. Most users will want to use this overload of
-+        the function.
- 
-         @param[in] decomposition_bit_count The decomposition bit count
-         @param[out] galois_keys The Galois keys instance to overwrite with the generated keys
-         @throws std::invalid_argument if decomposition_bit_count is not within [1, 60]
--        @throws std::logic_error if the encryption parameters do not support batching
--        */        
-+        */
-         void generate_galois_keys(int decomposition_bit_count, GaloisKeys &galois_keys);
- 
-+        /**
-+        Generates Galois keys. This function creates specific Galois keys that can be used to
-+        apply specific Galois automorphisms on encrypted data. The user needs to give as 
-+        input a vector of Galois elements corresponding to the keys that are to be created.
-+        
-+        The Galois elements are odd integers in the interval [1, M-1], where M = 2*N, and
-+        N = degree(poly_modulus). Used with batching, a Galois element 3^i % M corresponds
-+        to a cyclic row rotation i steps to the left, and a Galois element 3^(N/2-i) % M
-+        corresponds to a cyclic row rotation i steps to the right. The Galois element M-1
-+        corresponds to a column rotation (row swap). In the polynomial view (not batching),
-+        a Galois automorphism by a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
-+
-+        @param[in] decomposition_bit_count The decomposition bit count
-+        @param[in] galois_elts The Galois elements for which to generate keys
-+        @param[out] galois_keys The Galois keys instance to overwrite with the generated keys
-+        @throws std::invalid_argument if decomposition_bit_count is not within [1, 60]
-+        @throws std::invalid_argument if the Galois elements are not valid
-+        */
-+        void generate_galois_keys(int decomposition_bit_count,
-+            const std::vector<std::uint64_t> &galois_elts, GaloisKeys &galois_keys);
-+
-     private:
-         KeyGenerator(const KeyGenerator &copy) = delete;
- 
-@@ -141,17 +164,6 @@ namespace seal
-             return generated_;
-         }
- 
--        void generate_galois_keys(int decomposition_bit_count, 
--            const std::vector<std::uint64_t> &galois_elts, GaloisKeys &galois_keys);
--
--        inline GaloisKeys generate_galois_keys(int decomposition_bit_count, 
--            const std::vector<std::uint64_t> &galois_elts)
--        {
--            GaloisKeys keys;
--            generate_galois_keys(decomposition_bit_count, galois_elts, keys);
--            return keys;
--        }
--
-         MemoryPoolHandle pool_;
- 
-         EncryptionParameters parms_;
-diff --git a/SEALNET/sealnet/EvaluatorWrapper.cpp b/SEALNET/sealnet/EvaluatorWrapper.cpp
-index b4868ed..648fbfd 100644
---- a/SEALNET/sealnet/EvaluatorWrapper.cpp
-+++ b/SEALNET/sealnet/EvaluatorWrapper.cpp
-@@ -1513,6 +1513,152 @@ namespace Microsoft
-                 }
-             }
- 
-+            void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys)
-+            {
-+                if (evaluator_ == nullptr)
-+                {
-+                    throw gcnew ObjectDisposedException("Evaluator is disposed");
-+                }
-+                if (encrypted == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("encrypted cannot be null");
-+                }
-+                if (galoisKeys == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("galoisKeys cannot be null");
-+                }
-+                try
-+                {
-+                    evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt, galoisKeys->GetKeys());
-+                    GC::KeepAlive(encrypted);
-+                    GC::KeepAlive(galoisKeys);
-+                }
-+                catch (const exception &e)
-+                {
-+                    HandleException(&e);
-+                }
-+                catch (...)
-+                {
-+                    HandleException(nullptr);
-+                }
-+            }
-+
-+            void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys, 
-+                MemoryPoolHandle ^pool)
-+            {
-+                if (evaluator_ == nullptr)
-+                {
-+                    throw gcnew ObjectDisposedException("Evaluator is disposed");
-+                }
-+                if (encrypted == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("encrypted cannot be null");
-+                }
-+                if (galoisKeys == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("galoisKeys cannot be null");
-+                }
-+                if (pool == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("pool cannot be null");
-+                }
-+                try
-+                {
-+                    evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt, 
-+                        galoisKeys->GetKeys(), pool->GetHandle());
-+                    GC::KeepAlive(encrypted);
-+                    GC::KeepAlive(galoisKeys);
-+                    GC::KeepAlive(pool);
-+                }
-+                catch (const exception &e)
-+                {
-+                    HandleException(&e);
-+                }
-+                catch (...)
-+                {
-+                    HandleException(nullptr);
-+                }
-+            }
-+
-+            void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys, 
-+                Ciphertext ^destination)
-+            {
-+                if (evaluator_ == nullptr)
-+                {
-+                    throw gcnew ObjectDisposedException("Evaluator is disposed");
-+                }
-+                if (encrypted == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("encrypted cannot be null");
-+                }
-+                if (galoisKeys == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("galoisKeys cannot be null");
-+                }
-+                if (destination == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("destination cannot be null");
-+                }
-+                try
-+                {
-+                    evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt,
-+                        galoisKeys->GetKeys(), destination->GetCiphertext());
-+                    GC::KeepAlive(encrypted);
-+                    GC::KeepAlive(galoisKeys);
-+                    GC::KeepAlive(destination);
-+                }
-+                catch (const exception &e)
-+                {
-+                    HandleException(&e);
-+                }
-+                catch (...)
-+                {
-+                    HandleException(nullptr);
-+                }
-+            }
-+
-+            void Evaluator::ApplyGalois(Ciphertext ^encrypted, UInt64 galoisElt, GaloisKeys ^galoisKeys, 
-+                Ciphertext ^destination, MemoryPoolHandle ^pool)
-+            {
-+                if (evaluator_ == nullptr)
-+                {
-+                    throw gcnew ObjectDisposedException("Evaluator is disposed");
-+                }
-+                if (encrypted == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("encrypted cannot be null");
-+                }
-+                if (galoisKeys == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("galoisKeys cannot be null");
-+                }
-+                if (destination == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("destination cannot be null");
-+                }
-+                if (pool == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("pool cannot be null");
-+                }
-+                try
-+                {
-+                    evaluator_->apply_galois(encrypted->GetCiphertext(), galoisElt, 
-+                        galoisKeys->GetKeys(), destination->GetCiphertext(), pool->GetHandle());
-+                    GC::KeepAlive(encrypted);
-+                    GC::KeepAlive(galoisKeys);
-+                    GC::KeepAlive(destination);
-+                    GC::KeepAlive(pool);
-+                }
-+                catch (const exception &e)
-+                {
-+                    HandleException(&e);
-+                }
-+                catch (...)
-+                {
-+                    HandleException(nullptr);
-+                }
-+            }
-+
-             void Evaluator::RotateRows(Ciphertext ^encrypted, int steps, GaloisKeys ^galoisKeys)
-             {
-                 if (evaluator_ == nullptr)
-diff --git a/SEALNET/sealnet/EvaluatorWrapper.h b/SEALNET/sealnet/EvaluatorWrapper.h
-index 1f99af1..7a7ef05 100644
---- a/SEALNET/sealnet/EvaluatorWrapper.h
-+++ b/SEALNET/sealnet/EvaluatorWrapper.h
-@@ -113,7 +113,7 @@ namespace Microsoft
-                 by the given <see cref="MemoryPoolHandle" />.
-                 </remarks
-                 <param name="context">The SEALContext</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encryption parameters are not valid</exception>
-                 <exception cref="System::ArgumentException">if pool is uninitialized</exception>
-                 <exception cref="System::ArgumentNullException">if context or pool is null</exception>
-@@ -256,7 +256,7 @@ namespace Microsoft
-                 </remarks>
-                 <param name="encrypted1">The first ciphertext to multiply</param>
-                 <param name="encrypted2">The second ciphertext to multiply</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encrypted1 or encrypted2 is not valid 
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if pool is uninitialized</exception>
-@@ -296,7 +296,7 @@ namespace Microsoft
-                 <param name="encrypted1">The first ciphertext to multiply</param>
-                 <param name="encrypted2">The second ciphertext to multiply</param>
-                 <param name="destination">The ciphertext to overwrite with the multiplication result</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encrypted1 or encrypted2 is not valid 
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if pool is uninitialized</exception>
-@@ -330,7 +330,7 @@ namespace Microsoft
-                 the memory pool pointed to by the given <see cref="MemoryPoolHandle" />.
-                 </remarks>
-                 <param name="encrypted">The ciphertext to square</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encrypted is not valid for the
-                 encryption parameters</exception>
-                 <exception cref="System::ArgumentNullException">if encrypted or pool is 
-@@ -365,7 +365,7 @@ namespace Microsoft
-                 </remarks>
-                 <param name="encrypted">The ciphertext to square</param>
-                 <param name="destination">The ciphertext to overwrite with the square</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encrypted is not valid for the 
-                 encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if pool is uninitialized</exception>
-@@ -385,7 +385,7 @@ namespace Microsoft
-                 </remarks>
-                 <param name="encrypted">The ciphertext to relinearize</param>
-                 <param name="evaluationKeys">The evaluation keys</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encrypted or evaluationKeys is not 
-                 valid for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if the size of evaluationKeys is too 
-@@ -450,7 +450,7 @@ namespace Microsoft
-                 <param name="encrypted">The ciphertext to relinearize</param>
-                 <param name="evaluationKeys">The evaluation keys</param>
-                 <param name="destination">The ciphertext to overwrite with the relinearized result</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-                 <exception cref="System::ArgumentException">if encrypted or evaluationKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if the size of evaluationKeys is too
-@@ -1024,6 +1024,121 @@ namespace Microsoft
-                 */
-                 void MultiplyPlainNTT(Ciphertext ^encryptedNTT, Plaintext ^plainNTT);
- 
-+                /**
-+                <summary>Applies a Galois automorphism to a ciphertext.</summary>
-+
-+                <remarks>
-+                Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
-+                an appropriate set of Galois keys must also be provided. Dynamic memory allocations
-+                in the process are allocated from the memory pool pointed to by the local
-+                <see cref="MemoryPoolHandle" />.
-+                </remarks>
-+                <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
-+                <param name="galoisElt">The Galois element</param>
-+                <param name="galoisKeys">The Galois keys</param>
-+                <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-+                for the encryption parameters</exception>
-+                <exception cref="System::ArgumentException">if encrypted has size greater than
-+                two</exception>
-+                <exception cref="System::ArgumentException">if the Galois element is not
-+                valid</exception>
-+                <exception cref="System::ArgumentException">if necessary Galois keys are not
-+                present</exception>
-+                <exception cref="System::ArgumentNullException">if encrypted or galoisKeys is
-+                null</exception>
-+                */
-+                void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
-+                    GaloisKeys ^galoisKeys);
-+
-+                /**
-+                <summary>Applies a Galois automorphism to a ciphertext.</summary>
-+
-+                <remarks>
-+                Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
-+                an appropriate set of Galois keys must also be provided. Dynamic memory allocations
-+                in the process are allocated from the memory pool pointed to by the given
-+                <see cref="MemoryPoolHandle" />.
-+                </remarks>
-+                <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
-+                <param name="galoisElt">The Galois element</param>
-+                <param name="galoisKeys">The Galois keys</param>
-+                <param name="destination">The 
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-+                <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-+                for the encryption parameters</exception>
-+                <exception cref="System::ArgumentException">if encrypted has size greater than
-+                two</exception>
-+                <exception cref="System::ArgumentException">if the Galois element is not 
-+                valid</exception>
-+                <exception cref="System::ArgumentException">if necessary Galois keys are not
-+                present</exception>
-+                <exception cref="System::ArgumentException">if pool is uninitialized</exception>
-+                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys or pool
-+                is null</exception>
-+                */
-+                void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
-+                    GaloisKeys ^galoisKeys, MemoryPoolHandle ^pool);
-+
-+                /**
-+                <summary>Applies a Galois automorphism to a ciphertext and writes the result
-+                to the destination parameter.</summary>
-+
-+                <remarks>
-+                Applies a Galois automorphism to a ciphertext and writes the result to the
-+                destination parameter. To evaluate the Galois automorphism, an appropriate
-+                set of Galois keys must also be provided. Dynamic memory allocations in the
-+                process are allocated from the memory pool pointed to by the local
-+                <see cref="MemoryPoolHandle" />.
-+                </remarks>
-+                <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
-+                <param name="galoisElt">The Galois element</param>
-+                <param name="galoisKeys">The Galois keys</param>
-+                <param name="destination">The ciphertext to overwrite with the result</param>
-+                <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-+                for the encryption parameters</exception>
-+                <exception cref="System::ArgumentException">if encrypted has size greater than
-+                two</exception>
-+                <exception cref="System::ArgumentException">if the Galois element is not
-+                valid</exception>
-+                <exception cref="System::ArgumentException">if necessary Galois keys are not
-+                present</exception>
-+                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, or
-+                destination is null</exception>
-+                */
-+                void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
-+                    GaloisKeys ^galoisKeys, Ciphertext ^destination);
-+
-+                /**
-+                <summary>Applies a Galois automorphism to a ciphertext and writes the result
-+                to the destination parameter.</summary>
-+
-+                <remarks>
-+                Applies a Galois automorphism to a ciphertext and writes the result to the
-+                destination parameter. To evaluate the Galois automorphism, an appropriate 
-+                set of Galois keys must also be provided. Dynamic memory allocations in the 
-+                process are allocated from the memory pool pointed to by the given
-+                <see cref="MemoryPoolHandle" />.
-+                </remarks>
-+                <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
-+                <param name="galoisElt">The Galois element</param>
-+                <param name="galoisKeys">The Galois keys</param>
-+                <param name="destination">The ciphertext to overwrite with the result</param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-+                <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-+                for the encryption parameters</exception>
-+                <exception cref="System::ArgumentException">if encrypted has size greater than
-+                two</exception>
-+                <exception cref="System::ArgumentException">if the Galois element is not
-+                valid</exception>
-+                <exception cref="System::ArgumentException">if necessary Galois keys are not
-+                present</exception>
-+                <exception cref="System::ArgumentException">if pool is uninitialized</exception>
-+                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, 
-+                destination, or pool is null</exception>
-+                */
-+                void ApplyGalois(Ciphertext ^encrypted, System::UInt64 galoisElt,
-+                    GaloisKeys ^galoisKeys, Ciphertext ^destination, MemoryPoolHandle ^pool);
-+
-                 /**
-                 <summary>Rotates plaintext matrix rows cyclically.</summary>
- 
-@@ -1038,6 +1153,8 @@ namespace Microsoft
-                 <param name="encrypted">The ciphertext to rotate</param>
-                 <param name="steps">The number of steps to rotate (negative left, positive right)</param>
-                 <param name="galoisKeys">The Galois keys</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1046,7 +1163,7 @@ namespace Microsoft
-                 value</exception>
-                 <exception cref="System::ArgumentException">if necessary Galois keys are not
-                 present</exception>
--                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys or pool
-+                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, or pool
-                 is null</exception>
-                 */
-                 void RotateRows(Ciphertext ^encrypted, int steps, GaloisKeys ^galoisKeys);
-@@ -1065,7 +1182,9 @@ namespace Microsoft
-                 <param name="encrypted">The ciphertext to rotate</param>
-                 <param name="steps">The number of steps to rotate (negative left, positive right)</param>
-                 <param name="galoisKeys">The Galois keys</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1075,7 +1194,7 @@ namespace Microsoft
-                 <exception cref="System::ArgumentException">if necessary Galois keys are not
-                 present</exception>
-                 <exception cref="System::ArgumentException">if pool is uninitialized</exception>
--                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys or pool
-+                <exception cref="System::ArgumentNullException">if encrypted, galoisKeys, or pool
-                 is null</exception>
-                 */
-                 void RotateRows(Ciphertext ^encrypted, int steps, GaloisKeys ^galoisKeys, 
-@@ -1097,6 +1216,8 @@ namespace Microsoft
-                 <param name="steps">The number of steps to rotate (negative left, positive right)</param>
-                 <param name="galoisKeys">The Galois keys</param>
-                 <param name="destination">The ciphertext to overwrite with the rotated result</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1127,7 +1248,9 @@ namespace Microsoft
-                 <param name="steps">The number of steps to rotate (negative left, positive right)</param>
-                 <param name="galoisKeys">The Galois keys</param>
-                 <param name="destination">The ciphertext to overwrite with the rotated result</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1156,6 +1279,8 @@ namespace Microsoft
-                 </remarks>
-                 <param name="encrypted">The ciphertext to rotate</param>
-                 <param name="galoisKeys">The Galois keys</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1180,7 +1305,9 @@ namespace Microsoft
-                 </remarks>
-                 <param name="encrypted">The ciphertext to rotate</param>
-                 <param name="galoisKeys">The Galois keys</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1208,6 +1335,8 @@ namespace Microsoft
-                 <param name="encrypted">The ciphertext to rotate</param>
-                 <param name="galoisKeys">The Galois keys</param>
-                 <param name="destination">The ciphertext to overwrite with the rotated result</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if encrypted has size greater than 
-@@ -1234,7 +1363,9 @@ namespace Microsoft
-                 <param name="encrypted">The ciphertext to rotate</param>
-                 <param name="galoisKeys">The Galois keys</param>
-                 <param name="destination">The ciphertext to overwrite with the rotated result</param>
--                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool/param>
-+                <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
-+                <exception cref="System::InvalidOperationException">if the encryption parameters do
-+                not support batching</exception>
-                 <exception cref="System::ArgumentException">if encrypted or galoisKeys is not valid
-                 for the encryption parameters</exception>
-                 <exception cref="System::ArgumentException">if necessary Galois keys are not
-diff --git a/SEALNET/sealnet/KeyGeneratorWrapper.cpp b/SEALNET/sealnet/KeyGeneratorWrapper.cpp
-index c9d52de..e1547f1 100644
---- a/SEALNET/sealnet/KeyGeneratorWrapper.cpp
-+++ b/SEALNET/sealnet/KeyGeneratorWrapper.cpp
-@@ -1,10 +1,12 @@
- #include <cstddef>
-+#include <vector>
- #include "sealnet/KeyGeneratorWrapper.h"
- #include "sealnet/BigPolyWrapper.h"
- #include "sealnet/BigUIntWrapper.h"
- #include "sealnet/Common.h"
- 
- using namespace System;
-+using namespace System::Collections::Generic;
- using namespace std;
- 
- namespace Microsoft
-@@ -205,6 +207,37 @@ namespace Microsoft
-                 }
-             }
- 
-+            void KeyGenerator::GenerateGaloisKeys(int decompositionBitCount, List<UInt64> ^galoisElts,
-+                GaloisKeys ^galoisKeys)
-+            {
-+                if (generator_ == nullptr)
-+                {
-+                    throw gcnew ObjectDisposedException("KeyGenerator is disposed");
-+                }
-+                if (galoisKeys == nullptr)
-+                {
-+                    throw gcnew ArgumentNullException("galoisKeys cannot be null");
-+                }
-+                try
-+                {
-+                    std::vector<std::uint64_t> v_galois_elts;
-+                    for (int i = 0; i < galoisElts->Count; i++)
-+                    {
-+                        v_galois_elts.push_back(galoisElts[i]);
-+                    }
-+                    generator_->generate_galois_keys(decompositionBitCount, v_galois_elts, galoisKeys->GetKeys());
-+                    GC::KeepAlive(galoisElts);
-+                }
-+                catch (const exception &e)
-+                {
-+                    HandleException(&e);
-+                }
-+                catch (...)
-+                {
-+                    HandleException(nullptr);
-+                }
-+            }
-+
-             Microsoft::Research::SEAL::PublicKey ^KeyGenerator::PublicKey::get()
-             {
-                 if (generator_ == nullptr)
-diff --git a/SEALNET/sealnet/KeyGeneratorWrapper.h b/SEALNET/sealnet/KeyGeneratorWrapper.h
-index 7fd722c..cf7f1fc 100644
---- a/SEALNET/sealnet/KeyGeneratorWrapper.h
-+++ b/SEALNET/sealnet/KeyGeneratorWrapper.h
-@@ -158,6 +158,12 @@ namespace Microsoft
-                 /**
-                 <summary>Generates Galois keys.</summary>
- 
-+                <remarks>
-+                Generates Galois keys. This function creates logarithmically many (in degree of the
-+                polynomial modulus) Galois keys that is sufficient to apply any Galois automorphism
-+                (e.g. rotations) on encrypted data. Most users will want to use this overload of
-+                the function.
-+                </remarks>
-                 <param name="decompositionBitCount">The decomposition bit count</param>
-                 <param name="galoisKeys">The Galois keys instance to overwrite with the generated
-                 keys</param>
-@@ -167,6 +173,35 @@ namespace Microsoft
-                 */
-                 void GenerateGaloisKeys(int decompositionBitCount, GaloisKeys ^galoisKeys);
- 
-+                /**
-+                <summary>Generates Galois keys.</summary>
-+
-+                <remarks>
-+                Generates Galois keys. This function creates specific Galois keys that can be used to
-+                apply specific Galois automorphisms on encrypted data. The user needs to give as
-+                input a vector of Galois elements corresponding to the keys that are to be created.
-+
-+                The Galois elements are odd integers in the interval [1, M-1], where M = 2*N, and
-+                N = degree(PolyModulus). Used with batching, a Galois element 3^i % M corresponds 
-+                to a cyclic row rotation i steps to the left, and a Galois element 3^(N/2-i) % M 
-+                corresponds to a cyclic row rotation i steps to the right. The Galois element M-1 
-+                corresponds to a column rotation (row swap). In the polynomial view (not batching), 
-+                a Galois automorphism by a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
-+                </remarks>
-+                <param name="decompositionBitCount">The decomposition bit count</param>
-+                <param name="galoisElts">The Galois elements for which to generate keys</param>
-+                <param name="galoisKeys">The Galois keys instance to overwrite with the generated
-+                keys</param>
-+                <exception cref="System::ArgumentException">if decompositionBitCount is not
-+                within [0, 60]</exception>
-+                <exception cref="System::ArgumentException">if the Galois elements are not 
-+                valid</exception>
-+                <exception cref="System::ArgumentNullException">if galoisKeys is null</exception>
-+                */
-+                void GenerateGaloisKeys(int decompositionBitCount, 
-+                    System::Collections::Generic::List<System::UInt64> ^galoisElts,
-+                    GaloisKeys ^galoisKeys);
-+
-                 /**
-                 <summary>Destroys the KeyGenerator.</summary>
-                 */
-diff --git a/SEALNETTest/EvaluatorWrapper.cs b/SEALNETTest/EvaluatorWrapper.cs
-index 541786c..4321ecd 100644
---- a/SEALNETTest/EvaluatorWrapper.cs
-+++ b/SEALNETTest/EvaluatorWrapper.cs
-@@ -982,6 +982,88 @@ namespace SEALNETTest
-             Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);
-         }
- 
-+        [TestMethod]
-+        public void FVEncryptApplyGaloisDecryptNET()
-+        {
-+            var parms = new EncryptionParameters();
-+            var plain_modulus = new SmallModulus(257);
-+            parms.NoiseStandardDeviation = 3.19;
-+            parms.PlainModulus = plain_modulus;
-+            parms.PolyModulus = "1x^8 + 1";
-+            parms.CoeffModulus = new List<SmallModulus> {
-+                    DefaultParams.SmallMods40Bit(0), DefaultParams.SmallMods40Bit(1)
-+                };
-+            var context = new SEALContext(parms);
-+            var keygen = new KeyGenerator(context);
-+            var glk = new GaloisKeys();
-+            keygen.GenerateGaloisKeys(24, new List<UInt64> { 1, 3, 5, 15 }, glk);
-+
-+            var encryptor = new Encryptor(context, keygen.PublicKey);
-+            var evaluator = new Evaluator(context);
-+            var decryptor = new Decryptor(context, keygen.SecretKey);
-+
-+            var plain = new Plaintext("1");
-+            var encrypted = new Ciphertext();
-+            encryptor.Encrypt(plain, encrypted);
-+            evaluator.ApplyGalois(encrypted, 1, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 3, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 5, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 15, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1", plain.ToString());
-+
-+            plain.Set("1x^1");
-+            encryptor.Encrypt(plain, encrypted);
-+            evaluator.ApplyGalois(encrypted, 1, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 3, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^3", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 5, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("100x^7", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 15, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^1", plain.ToString());
-+
-+            plain.Set("1x^2");
-+            encryptor.Encrypt(plain, encrypted);
-+            evaluator.ApplyGalois(encrypted, 1, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^2", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 3, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^6", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 5, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("100x^6", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 15, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^2", plain.ToString());
-+
-+            plain.Set("1x^3 + 2x^2 + 1x^1 + 1");
-+            encryptor.Encrypt(plain, encrypted);
-+            evaluator.ApplyGalois(encrypted, 1, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^3 + 2x^2 + 1x^1 + 1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 3, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("2x^6 + 1x^3 + 100x^1 + 1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 5, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("100x^7 + FFx^6 + 100x^5 + 1", plain.ToString());
-+            evaluator.ApplyGalois(encrypted, 15, glk);
-+            decryptor.Decrypt(encrypted, plain);
-+            Assert.AreEqual("1x^3 + 2x^2 + 1x^1 + 1", plain.ToString());
-+        }
-+
-         [TestMethod]
-         public void FVEncryptRotateMatrixDecryptNET()
-         {
-diff --git a/SEALNETTest/KeyGeneratorWrapper.cs b/SEALNETTest/KeyGeneratorWrapper.cs
-index 04f9738..2a74a89 100644
---- a/SEALNETTest/KeyGeneratorWrapper.cs
-+++ b/SEALNETTest/KeyGeneratorWrapper.cs
-@@ -1,6 +1,7 @@
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using Microsoft.Research.SEAL;
- using System.Collections.Generic;
-+using System;
- 
- namespace SEALNETTest
- {
-@@ -35,6 +36,79 @@ namespace SEALNETTest
-                 keygen.GenerateEvaluationKeys(2, 2, evk);
-                 Assert.AreEqual(evk.HashBlock, parms.HashBlock);
-                 Assert.AreEqual(60, evk.Key(2)[0].Size);
-+
-+                var galks = new GaloisKeys();
-+                keygen.GenerateGaloisKeys(60, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.AreEqual(2, galks.Key(3)[0].Size);
-+                Assert.AreEqual(10, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.AreEqual(4, galks.Key(3)[0].Size);
-+                Assert.AreEqual(10, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(2, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.AreEqual(60, galks.Key(3)[0].Size);
-+                Assert.AreEqual(10, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(60, new List<UInt64> { 1, 3, 5, 7 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(3));
-+                Assert.IsTrue(galks.HasKey(5));
-+                Assert.IsTrue(galks.HasKey(7));
-+                Assert.IsFalse(galks.HasKey(9));
-+                Assert.IsFalse(galks.HasKey(127));
-+                Assert.AreEqual(2, galks.Key(1)[0].Size);
-+                Assert.AreEqual(2, galks.Key(3)[0].Size);
-+                Assert.AreEqual(2, galks.Key(5)[0].Size);
-+                Assert.AreEqual(2, galks.Key(7)[0].Size);
-+                Assert.AreEqual(4, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, new List<UInt64> { 1, 3, 5, 7 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(3));
-+                Assert.IsTrue(galks.HasKey(5));
-+                Assert.IsTrue(galks.HasKey(7));
-+                Assert.IsFalse(galks.HasKey(9));
-+                Assert.IsFalse(galks.HasKey(127));
-+                Assert.AreEqual(4, galks.Key(1)[0].Size);
-+                Assert.AreEqual(4, galks.Key(3)[0].Size);
-+                Assert.AreEqual(4, galks.Key(5)[0].Size);
-+                Assert.AreEqual(4, galks.Key(7)[0].Size);
-+                Assert.AreEqual(4, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(2, new List<UInt64> { 1, 3, 5, 7 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(3));
-+                Assert.IsTrue(galks.HasKey(5));
-+                Assert.IsTrue(galks.HasKey(7));
-+                Assert.IsFalse(galks.HasKey(9));
-+                Assert.IsFalse(galks.HasKey(127));
-+                Assert.AreEqual(60, galks.Key(1)[0].Size);
-+                Assert.AreEqual(60, galks.Key(3)[0].Size);
-+                Assert.AreEqual(60, galks.Key(5)[0].Size);
-+                Assert.AreEqual(60, galks.Key(7)[0].Size);
-+                Assert.AreEqual(4, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, new List<UInt64> { 1 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsFalse(galks.HasKey(3));
-+                Assert.IsFalse(galks.HasKey(127));
-+                Assert.AreEqual(4, galks.Key(1)[0].Size);
-+                Assert.AreEqual(1, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, new List<UInt64> { 127 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsFalse(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(127));
-+                Assert.AreEqual(4, galks.Key(127)[0].Size);
-+                Assert.AreEqual(1, galks.Size);
-             }
-             {
-                 parms.NoiseStandardDeviation = 3.19;
-@@ -61,6 +135,79 @@ namespace SEALNETTest
-                 keygen.GenerateEvaluationKeys(4, 1, evk);
-                 Assert.AreEqual(evk.HashBlock, parms.HashBlock);
-                 Assert.AreEqual(30, evk.Key(2)[0].Size);
-+
-+                var galks = new GaloisKeys();
-+                keygen.GenerateGaloisKeys(60, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.AreEqual(2, galks.Key(3)[0].Size);
-+                Assert.AreEqual(14, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.AreEqual(4, galks.Key(3)[0].Size);
-+                Assert.AreEqual(14, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(2, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.AreEqual(60, galks.Key(3)[0].Size);
-+                Assert.AreEqual(14, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(60, new List<UInt64> { 1, 3, 5, 7 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(3));
-+                Assert.IsTrue(galks.HasKey(5));
-+                Assert.IsTrue(galks.HasKey(7));
-+                Assert.IsFalse(galks.HasKey(9));
-+                Assert.IsFalse(galks.HasKey(511));
-+                Assert.AreEqual(2, galks.Key(1)[0].Size);
-+                Assert.AreEqual(2, galks.Key(3)[0].Size);
-+                Assert.AreEqual(2, galks.Key(5)[0].Size);
-+                Assert.AreEqual(2, galks.Key(7)[0].Size);
-+                Assert.AreEqual(4, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, new List<UInt64> { 1, 3, 5, 7 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(3));
-+                Assert.IsTrue(galks.HasKey(5));
-+                Assert.IsTrue(galks.HasKey(7));
-+                Assert.IsFalse(galks.HasKey(9));
-+                Assert.IsFalse(galks.HasKey(511));
-+                Assert.AreEqual(4, galks.Key(1)[0].Size);
-+                Assert.AreEqual(4, galks.Key(3)[0].Size);
-+                Assert.AreEqual(4, galks.Key(5)[0].Size);
-+                Assert.AreEqual(4, galks.Key(7)[0].Size);
-+                Assert.AreEqual(4, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(2, new List<UInt64> { 1, 3, 5, 7 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(3));
-+                Assert.IsTrue(galks.HasKey(5));
-+                Assert.IsTrue(galks.HasKey(7));
-+                Assert.IsFalse(galks.HasKey(9));
-+                Assert.IsFalse(galks.HasKey(511));
-+                Assert.AreEqual(60, galks.Key(1)[0].Size);
-+                Assert.AreEqual(60, galks.Key(3)[0].Size);
-+                Assert.AreEqual(60, galks.Key(5)[0].Size);
-+                Assert.AreEqual(60, galks.Key(7)[0].Size);
-+                Assert.AreEqual(4, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, new List<UInt64> { 1 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsTrue(galks.HasKey(1));
-+                Assert.IsFalse(galks.HasKey(3));
-+                Assert.IsFalse(galks.HasKey(511));
-+                Assert.AreEqual(4, galks.Key(1)[0].Size);
-+                Assert.AreEqual(1, galks.Size);
-+
-+                keygen.GenerateGaloisKeys(30, new List<UInt64> { 511 }, galks);
-+                Assert.AreEqual(galks.HashBlock, parms.HashBlock);
-+                Assert.IsFalse(galks.HasKey(1));
-+                Assert.IsTrue(galks.HasKey(511));
-+                Assert.AreEqual(4, galks.Key(511)[0].Size);
-+                Assert.AreEqual(1, galks.Size);
-             }
-         }
-     }
-diff --git a/SEALTest/evaluator.cpp b/SEALTest/evaluator.cpp
-index 51e083a..edde078 100644
---- a/SEALTest/evaluator.cpp
-+++ b/SEALTest/evaluator.cpp
-@@ -964,6 +964,85 @@ namespace SEALTest
-             Assert::IsTrue(encrypted.hash_block() == parms.hash_block());
-         }
- 
-+        TEST_METHOD(FVEncryptApplyGaloisDecrypt)
-+        {
-+            EncryptionParameters parms;
-+            SmallModulus plain_modulus(257);
-+            BigPoly poly_modulus("1x^8 + 1");
-+            parms.set_poly_modulus(poly_modulus);
-+            parms.set_plain_modulus(plain_modulus);
-+            parms.set_coeff_modulus({ small_mods_40bit(0), small_mods_40bit(1) });
-+            SEALContext context(parms);
-+            KeyGenerator keygen(context);
-+            GaloisKeys glk;
-+            keygen.generate_galois_keys(24, { 1, 3, 5, 15 }, glk);
-+
-+            Encryptor encryptor(context, keygen.public_key());
-+            Evaluator evaluator(context);
-+            Decryptor decryptor(context, keygen.secret_key());
-+
-+            Plaintext plain("1");
-+            Ciphertext encrypted;
-+            encryptor.encrypt(plain, encrypted);
-+            evaluator.apply_galois(encrypted, 1, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 3, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 5, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 15, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1" == plain.to_string());
-+
-+            plain = "1x^1";
-+            encryptor.encrypt(plain, encrypted);
-+            evaluator.apply_galois(encrypted, 1, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 3, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^3" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 5, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("100x^7" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 15, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^1" == plain.to_string());
-+
-+            plain = "1x^2";
-+            encryptor.encrypt(plain, encrypted);
-+            evaluator.apply_galois(encrypted, 1, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^2" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 3, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^6" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 5, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("100x^6" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 15, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^2" == plain.to_string());
-+
-+            plain = "1x^3 + 2x^2 + 1x^1 + 1";
-+            encryptor.encrypt(plain, encrypted);
-+            evaluator.apply_galois(encrypted, 1, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^3 + 2x^2 + 1x^1 + 1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 3, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("2x^6 + 1x^3 + 100x^1 + 1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 5, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("100x^7 + FFx^6 + 100x^5 + 1" == plain.to_string());
-+            evaluator.apply_galois(encrypted, 15, glk);
-+            decryptor.decrypt(encrypted, plain);
-+            Assert::IsTrue("1x^3 + 2x^2 + 1x^1 + 1" == plain.to_string());
-+        }
-+
-         TEST_METHOD(FVEncryptRotateMatrixDecrypt)
-         {
-             EncryptionParameters parms;
-diff --git a/SEALTest/keygenerator.cpp b/SEALTest/keygenerator.cpp
-index b4e15b3..a64b1af 100644
---- a/SEALTest/keygenerator.cpp
-+++ b/SEALTest/keygenerator.cpp
-@@ -68,6 +68,79 @@ namespace SEALTest
-                         }
-                     }
-                 }
-+
-+                GaloisKeys galks;
-+                keygen.generate_galois_keys(60, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::AreEqual(2, galks.key(3)[0].size());
-+                Assert::AreEqual(10, galks.size());
-+
-+                keygen.generate_galois_keys(30, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::AreEqual(4, galks.key(3)[0].size());
-+                Assert::AreEqual(10, galks.size());
-+
-+                keygen.generate_galois_keys(2, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::AreEqual(60, galks.key(3)[0].size());
-+                Assert::AreEqual(10, galks.size());
-+
-+                keygen.generate_galois_keys(60, { 1, 3, 5, 7 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(3));
-+                Assert::IsTrue(galks.has_key(5));
-+                Assert::IsTrue(galks.has_key(7));
-+                Assert::IsFalse(galks.has_key(9));
-+                Assert::IsFalse(galks.has_key(127));
-+                Assert::AreEqual(2, galks.key(1)[0].size());
-+                Assert::AreEqual(2, galks.key(3)[0].size());
-+                Assert::AreEqual(2, galks.key(5)[0].size());
-+                Assert::AreEqual(2, galks.key(7)[0].size());
-+                Assert::AreEqual(4, galks.size());
-+
-+                keygen.generate_galois_keys(30, { 1, 3, 5, 7 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(3));
-+                Assert::IsTrue(galks.has_key(5));
-+                Assert::IsTrue(galks.has_key(7));
-+                Assert::IsFalse(galks.has_key(9));
-+                Assert::IsFalse(galks.has_key(127));
-+                Assert::AreEqual(4, galks.key(1)[0].size());
-+                Assert::AreEqual(4, galks.key(3)[0].size());
-+                Assert::AreEqual(4, galks.key(5)[0].size());
-+                Assert::AreEqual(4, galks.key(7)[0].size());
-+                Assert::AreEqual(4, galks.size());
-+
-+                keygen.generate_galois_keys(2, { 1, 3, 5, 7 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(3));
-+                Assert::IsTrue(galks.has_key(5));
-+                Assert::IsTrue(galks.has_key(7));
-+                Assert::IsFalse(galks.has_key(9));
-+                Assert::IsFalse(galks.has_key(127));
-+                Assert::AreEqual(60, galks.key(1)[0].size());
-+                Assert::AreEqual(60, galks.key(3)[0].size());
-+                Assert::AreEqual(60, galks.key(5)[0].size());
-+                Assert::AreEqual(60, galks.key(7)[0].size());
-+                Assert::AreEqual(4, galks.size());
-+
-+                keygen.generate_galois_keys(30, { 1 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsFalse(galks.has_key(3));
-+                Assert::IsFalse(galks.has_key(127));
-+                Assert::AreEqual(4, galks.key(1)[0].size());
-+                Assert::AreEqual(1, galks.size());
-+
-+                keygen.generate_galois_keys(30, { 127 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsFalse(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(127));
-+                Assert::AreEqual(4, galks.key(127)[0].size());
-+                Assert::AreEqual(1, galks.size());
-             }
-             {
-                 parms.set_noise_standard_deviation(3.19);
-@@ -121,6 +194,79 @@ namespace SEALTest
-                         }
-                     }
-                 }
-+
-+                GaloisKeys galks;
-+                keygen.generate_galois_keys(60, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::AreEqual(2, galks.key(3)[0].size());
-+                Assert::AreEqual(14, galks.size());
-+
-+                keygen.generate_galois_keys(30, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::AreEqual(4, galks.key(3)[0].size());
-+                Assert::AreEqual(14, galks.size());
-+
-+                keygen.generate_galois_keys(2, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::AreEqual(60, galks.key(3)[0].size());
-+                Assert::AreEqual(14, galks.size());
-+
-+                keygen.generate_galois_keys(60, { 1, 3, 5, 7 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(3));
-+                Assert::IsTrue(galks.has_key(5));
-+                Assert::IsTrue(galks.has_key(7));
-+                Assert::IsFalse(galks.has_key(9));
-+                Assert::IsFalse(galks.has_key(511));
-+                Assert::AreEqual(2, galks.key(1)[0].size());
-+                Assert::AreEqual(2, galks.key(3)[0].size());
-+                Assert::AreEqual(2, galks.key(5)[0].size());
-+                Assert::AreEqual(2, galks.key(7)[0].size());
-+                Assert::AreEqual(4, galks.size());
-+
-+                keygen.generate_galois_keys(30, { 1, 3, 5, 7 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(3));
-+                Assert::IsTrue(galks.has_key(5));
-+                Assert::IsTrue(galks.has_key(7));
-+                Assert::IsFalse(galks.has_key(9));
-+                Assert::IsFalse(galks.has_key(511));
-+                Assert::AreEqual(4, galks.key(1)[0].size());
-+                Assert::AreEqual(4, galks.key(3)[0].size());
-+                Assert::AreEqual(4, galks.key(5)[0].size());
-+                Assert::AreEqual(4, galks.key(7)[0].size());
-+                Assert::AreEqual(4, galks.size());
-+
-+                keygen.generate_galois_keys(2, { 1, 3, 5, 7 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(3));
-+                Assert::IsTrue(galks.has_key(5));
-+                Assert::IsTrue(galks.has_key(7));
-+                Assert::IsFalse(galks.has_key(9));
-+                Assert::IsFalse(galks.has_key(511));
-+                Assert::AreEqual(60, galks.key(1)[0].size());
-+                Assert::AreEqual(60, galks.key(3)[0].size());
-+                Assert::AreEqual(60, galks.key(5)[0].size());
-+                Assert::AreEqual(60, galks.key(7)[0].size());
-+                Assert::AreEqual(4, galks.size());
-+
-+                keygen.generate_galois_keys(30, { 1 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsTrue(galks.has_key(1));
-+                Assert::IsFalse(galks.has_key(3));
-+                Assert::IsFalse(galks.has_key(511));
-+                Assert::AreEqual(4, galks.key(1)[0].size());
-+                Assert::AreEqual(1, galks.size());
-+
-+                keygen.generate_galois_keys(30, { 511 }, galks);
-+                Assert::IsTrue(galks.hash_block() == parms.hash_block());
-+                Assert::IsFalse(galks.has_key(1));
-+                Assert::IsTrue(galks.has_key(511));
-+                Assert::AreEqual(4, galks.key(511)[0].size());
-+                Assert::AreEqual(1, galks.size());
-             }
-         }
-     };
--- 
-2.14.1
-
-
-From 1fdfa03edbb50835beedefe26d74f17918c4f1e1 Mon Sep 17 00:00:00 2001
-From: Kim Laine <kim.laine@microsoft.com>
-Date: Mon, 4 Dec 2017 17:31:18 -0800
-Subject: [PATCH 2/3] Added negacyclic_shift_poly_coeffmod
-
----
- SEAL/seal/util/polyarithsmallmod.cpp |  28 ++++++---
- SEAL/seal/util/polyarithsmallmod.h   |  54 +++++++++++++++++-
- SEALTest/util/polyarithsmallmod.cpp  | 108 +++++++++++++++++++++++++++++++++++
- 3 files changed, 181 insertions(+), 9 deletions(-)
-
-diff --git a/SEAL/seal/util/polyarithsmallmod.cpp b/SEAL/seal/util/polyarithsmallmod.cpp
-index 5bfeede..4719348 100644
---- a/SEAL/seal/util/polyarithsmallmod.cpp
-+++ b/SEAL/seal/util/polyarithsmallmod.cpp
-@@ -407,16 +407,30 @@ namespace seal
-             }
-         }
- 
--        uint64_t poly_infty_norm_coeffmod(const std::uint64_t *poly, int poly_coeff_count, const SmallModulus &modulus)
-+        uint64_t poly_infty_norm_coeffmod(const std::uint64_t *operand, int coeff_count, const SmallModulus &modulus)
-         {
-+#ifdef SEAL_DEBUG
-+            if (operand == nullptr && coeff_count > 0)
-+            {
-+                throw invalid_argument("operand");
-+            }
-+            if (coeff_count < 0)
-+            {
-+                throw invalid_argument("coeff_count");
-+            }
-+            if (modulus.is_zero())
-+            {
-+                throw invalid_argument("modulus");
-+            }
-+#endif
-             // Construct negative threshold (first negative modulus value) to compute absolute values of coeffs.
-             uint64_t modulus_neg_threshold = (modulus.value() + 1) >> 1;
- 
-             // Mod out the poly coefficients and choose a symmetric representative from [-modulus,modulus). Keep track of the max.
-             uint64_t result = 0;
--            for (int coeff_index = 0; coeff_index < poly_coeff_count; coeff_index++)
-+            for (int coeff_index = 0; coeff_index < coeff_count; coeff_index++)
-             {
--                uint64_t poly_coeff = poly[coeff_index] % modulus.value();
-+                uint64_t poly_coeff = operand[coeff_index] % modulus.value();
-                 if (poly_coeff >= modulus_neg_threshold)
-                 {
-                     poly_coeff = modulus.value() - poly_coeff;
-@@ -594,14 +608,14 @@ namespace seal
-             return true;
-         }
- 
--        void exponentiate_poly_polymod_coeffmod(const uint64_t *poly, const uint64_t *exponent, int exponent_uint64_count, const PolyModulus &poly_modulus, const SmallModulus &modulus, uint64_t *result, MemoryPool &pool)
-+        void exponentiate_poly_polymod_coeffmod(const uint64_t *operand, const uint64_t *exponent, int exponent_uint64_count, const PolyModulus &poly_modulus, const SmallModulus &modulus, uint64_t *result, MemoryPool &pool)
-         {
-             int poly_modulus_coeff_count = poly_modulus.coeff_count();
- #ifdef SEAL_DEBUG
-             int poly_modulus_coeff_uint64_count = poly_modulus.coeff_uint64_count();
--            if (poly == nullptr)
-+            if (operand == nullptr)
-             {
--                throw invalid_argument("poly");
-+                throw invalid_argument("operand");
-             }
-             if (exponent == nullptr)
-             {
-@@ -631,7 +645,7 @@ namespace seal
-                 return;
-             }
- 
--            modulo_poly(poly, poly_modulus_coeff_count, poly_modulus, modulus, result, pool);
-+            modulo_poly(operand, poly_modulus_coeff_count, poly_modulus, modulus, result, pool);
- 
-             if (is_equal_uint(exponent, exponent_uint64_count, 1))
-             {
-diff --git a/SEAL/seal/util/polyarithsmallmod.h b/SEAL/seal/util/polyarithsmallmod.h
-index d660439..f081184 100644
---- a/SEAL/seal/util/polyarithsmallmod.h
-+++ b/SEAL/seal/util/polyarithsmallmod.h
-@@ -556,14 +556,64 @@ namespace seal
-             modulo_poly_inplace(result, result_coeff_count, poly_modulus, modulus);
-         }
- 
--        std::uint64_t poly_infty_norm_coeffmod(const std::uint64_t *poly, int poly_coeff_count,
-+        std::uint64_t poly_infty_norm_coeffmod(const std::uint64_t *operand, int coeff_count, 
-             const SmallModulus &modulus);
- 
-         bool try_invert_poly_coeffmod(const std::uint64_t *operand, const std::uint64_t *poly_modulus, 
-             int coeff_count, const SmallModulus &modulus, std::uint64_t *result, MemoryPool &pool);
- 
--        void exponentiate_poly_polymod_coeffmod(const std::uint64_t *poly, const std::uint64_t *exponent,
-+        void exponentiate_poly_polymod_coeffmod(const std::uint64_t *operand, const std::uint64_t *exponent,
-             int exponent_uint64_count, const PolyModulus &poly_modulus, const SmallModulus &modulus, 
-             std::uint64_t *result, MemoryPool &pool);
-+
-+        inline void negacyclic_shift_poly_coeffmod(const std::uint64_t *operand, int coeff_count, int shift,
-+            const SmallModulus &modulus, std::uint64_t *result)
-+        {
-+#ifdef SEAL_DEBUG
-+            if (operand == nullptr && coeff_count > 0)
-+            {
-+                throw std::invalid_argument("operand");
-+            }
-+            if (result == nullptr && coeff_count > 0)
-+            {
-+                throw std::invalid_argument("result");
-+            }
-+            if (operand == result && coeff_count > 0)
-+            {
-+                throw std::invalid_argument("operand cannot point to the same location as result");
-+            }
-+            if (coeff_count < 0)
-+            {
-+                throw std::invalid_argument("coeff_count");
-+            }
-+            if (modulus.is_zero())
-+            {
-+                throw std::invalid_argument("modulus");
-+            }
-+            if (shift < 0)
-+            {
-+                throw std::invalid_argument("shift");
-+            }
-+            if (util::get_power_of_two(static_cast<std::uint64_t>(coeff_count)) < 0)
-+            {
-+                throw std::invalid_argument("coeff_count");
-+            }
-+#endif
-+            std::uint64_t index_raw = shift;
-+            std::uint64_t coeff_count_mod_mask = static_cast<std::uint64_t>(coeff_count) - 1;
-+            std::uint64_t index;
-+            for (int i = 0; i < coeff_count; i++, operand++, index_raw++)
-+            {
-+                index = index_raw & coeff_count_mod_mask;
-+                if (!(index_raw & static_cast<std::uint64_t>(coeff_count)) || (*operand == 0))
-+                {
-+                    result[index] = *operand;
-+                }
-+                else
-+                {
-+                    result[index] = modulus.value() - *operand;
-+                }
-+            }
-+        }
-     }
- }
-diff --git a/SEALTest/util/polyarithsmallmod.cpp b/SEALTest/util/polyarithsmallmod.cpp
-index e917034..93df00b 100644
---- a/SEALTest/util/polyarithsmallmod.cpp
-+++ b/SEALTest/util/polyarithsmallmod.cpp
-@@ -470,6 +470,114 @@ namespace SEALTest
-                 Assert::AreEqual(9ULL, result[1]);
-                 Assert::AreEqual(0ULL, result[2]);
-             }
-+
-+            TEST_METHOD(NegacyclicShiftPolyCoeffSmallMod)
-+            {
-+                MemoryPool &pool = *global_variables::global_memory_pool;
-+                Pointer poly(allocate_zero_poly(4, 1, pool));
-+                Pointer result(allocate_zero_poly(4, 1, pool));
-+
-+                SmallModulus mod(10);
-+                int coeff_count = 4;
-+
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 0, mod, result.get());
-+                Assert::AreEqual(0ULL, result[0]);
-+                Assert::AreEqual(0ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
-+                Assert::AreEqual(0ULL, result[0]);
-+                Assert::AreEqual(0ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 4, mod, result.get());
-+                Assert::AreEqual(0ULL, result[0]);
-+                Assert::AreEqual(0ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 5, mod, result.get());
-+                Assert::AreEqual(0ULL, result[0]);
-+                Assert::AreEqual(0ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 8, mod, result.get());
-+                Assert::AreEqual(0ULL, result[0]);
-+                Assert::AreEqual(0ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+
-+                poly[0] = 1;
-+                poly[1] = 2;
-+                poly[2] = 3;
-+                poly[3] = 4;
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 0, mod, result.get());
-+                Assert::AreEqual(1ULL, result[0]);
-+                Assert::AreEqual(2ULL, result[1]);
-+                Assert::AreEqual(3ULL, result[2]);
-+                Assert::AreEqual(4ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
-+                Assert::AreEqual(6ULL, result[0]);
-+                Assert::AreEqual(1ULL, result[1]);
-+                Assert::AreEqual(2ULL, result[2]);
-+                Assert::AreEqual(3ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 4, mod, result.get());
-+                Assert::AreEqual(9ULL, result[0]);
-+                Assert::AreEqual(8ULL, result[1]);
-+                Assert::AreEqual(7ULL, result[2]);
-+                Assert::AreEqual(6ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 5, mod, result.get());
-+                Assert::AreEqual(4ULL, result[0]);
-+                Assert::AreEqual(9ULL, result[1]);
-+                Assert::AreEqual(8ULL, result[2]);
-+                Assert::AreEqual(7ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 8, mod, result.get());
-+                Assert::AreEqual(1ULL, result[0]);
-+                Assert::AreEqual(2ULL, result[1]);
-+                Assert::AreEqual(3ULL, result[2]);
-+                Assert::AreEqual(4ULL, result[3]);
-+
-+                poly[0] = 1;
-+                poly[1] = 2;
-+                poly[2] = 0;
-+                poly[3] = 4;
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 0, mod, result.get());
-+                Assert::AreEqual(1ULL, result[0]);
-+                Assert::AreEqual(2ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(4ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
-+                Assert::AreEqual(6ULL, result[0]);
-+                Assert::AreEqual(1ULL, result[1]);
-+                Assert::AreEqual(2ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 4, mod, result.get());
-+                Assert::AreEqual(9ULL, result[0]);
-+                Assert::AreEqual(8ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(6ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 5, mod, result.get());
-+                Assert::AreEqual(4ULL, result[0]);
-+                Assert::AreEqual(9ULL, result[1]);
-+                Assert::AreEqual(8ULL, result[2]);
-+                Assert::AreEqual(0ULL, result[3]);
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 8, mod, result.get());
-+                Assert::AreEqual(1ULL, result[0]);
-+                Assert::AreEqual(2ULL, result[1]);
-+                Assert::AreEqual(0ULL, result[2]);
-+                Assert::AreEqual(4ULL, result[3]);
-+
-+                poly[0] = 1;
-+                poly[1] = 2;
-+                poly[2] = 3;
-+                poly[3] = 4;
-+                coeff_count = 2;
-+                negacyclic_shift_poly_coeffmod(poly.get(), coeff_count, 1, mod, result.get());
-+                negacyclic_shift_poly_coeffmod(poly.get() + 2, coeff_count, 1, mod, result.get() + 2);
-+                Assert::AreEqual(8ULL, result[0]);
-+                Assert::AreEqual(1ULL, result[1]);
-+                Assert::AreEqual(6ULL, result[2]);
-+                Assert::AreEqual(3ULL, result[3]);
-+            }
-         };
-     }
- }
-\ No newline at end of file
--- 
-2.14.1
-
-
-From 9c5a16fb3e8ffc5bae69ba175867d89b774091c5 Mon Sep 17 00:00:00 2001
-From: Sebastian Angel <sebs@cs.utexas.edu>
-Date: Tue, 15 May 2018 00:11:24 +0000
-Subject: [PATCH 3/3] enable mutable
-
----
- SEAL/seal/util/defines.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/SEAL/seal/util/defines.h b/SEAL/seal/util/defines.h
-index 20c0bf2..4e1b2fb 100644
---- a/SEAL/seal/util/defines.h
-+++ b/SEAL/seal/util/defines.h
-@@ -19,7 +19,7 @@
- // parameter compatibility checks pass in cases where they normally 
- // should not pass. Please note that it is extremely easy to break 
- // things by doing this, and the consequences can be unexpected.
--//#define SEAL_EXPOSE_MUTABLE_HASH_BLOCK
-+#define SEAL_EXPOSE_MUTABLE_HASH_BLOCK
- 
- // Allow ciphertext data to be directly modified by exposing the
- // functions seal::Ciphertext::mutable_pointer(int) and 
-@@ -28,7 +28,7 @@
- // way of mutating ciphertext data is by allocating memory manually, 
- // and using aliased ciphertexts pointing to the allocated memory, 
- // which can then be mutated freely.
--//#define SEAL_EXPOSE_MUTABLE_CIPHERTEXT
-+#define SEAL_EXPOSE_MUTABLE_CIPHERTEXT
- 
- // For security reasons one should never throw when decoding fails due
- // to overflow, but in some cases this might help in diagnosing problems.
--- 
-2.14.1
-

+ 1 - 1
pir.cpp

@@ -222,7 +222,7 @@ void coeffs_to_bytes(uint32_t limit, const Plaintext &coeffs, uint8_t *output, u
 void vector_to_plaintext(const vector<uint64_t> &coeffs, Plaintext &plain) {
     uint32_t coeff_count = coeffs.size();
     plain.resize(coeff_count);
-    util::set_uint_uint(coeffs.data(), coeff_count, plain.pointer());
+    util::set_uint_uint(coeffs.data(), coeff_count, plain.data());
 }
 
 vector<uint64_t> compute_indices(uint64_t desiredIndex, vector<uint64_t> Nvec) {

+ 6 - 6
pir_client.cpp

@@ -19,7 +19,7 @@ PIRClient::PIRClient(const EncryptionParameters &params,
     encryptor_.reset(new Encryptor(context, keygen_->public_key()));
 
     SecretKey secret_key = keygen_->secret_key();
-    secret_key.mutable_hash_block() = expanded_params.hash_block();
+    secret_key.hash_block() = expanded_params.hash_block();
 
     decryptor_.reset(new Decryptor(newcontext, secret_key));
     evaluator_.reset(new Evaluator(newcontext));
@@ -37,7 +37,7 @@ void PIRClient::update_parameters(const EncryptionParameters &expanded_params,
     SEALContext newcontext(expanded_params);
 
     SecretKey secret_key = keygen_->secret_key();
-    secret_key.mutable_hash_block() = expanded_params.hash_block();
+    secret_key.hash_block() = expanded_params.hash_block();
 
     decryptor_.reset(new Decryptor(newcontext, secret_key));
     evaluator_.reset(new Evaluator(newcontext));
@@ -51,7 +51,7 @@ PirQuery PIRClient::generate_query(uint64_t desiredIndex) {
     for (uint32_t i = 0; i < indices.size(); i++) {
         Ciphertext dest;
         encryptor_->encrypt(Plaintext("1x^" + std::to_string(indices[i])), dest);
-        dest.mutable_hash_block() = expanded_params_.hash_block();
+        dest.hash_block() = expanded_params_.hash_block();
         result.push_back(dest);
     }
 
@@ -146,7 +146,7 @@ Ciphertext PIRClient::compose_to_ciphertext(vector<Plaintext> plains) {
 
     // A triple for loop. Going over polys, moduli, and decomposed index.
     for (int i = 0; i < encrypted_count; i++) {
-        uint64_t *encrypted_pointer = result.mutable_pointer(i);
+        uint64_t *encrypted_pointer = result.data(i);
 
         for (int j = 0; j < coeff_mod_count; j++) {
             // populate one poly at a time.
@@ -164,7 +164,7 @@ Ciphertext PIRClient::compose_to_ciphertext(vector<Plaintext> plains) {
                 // Compose here
                 const uint64_t *plain_coeff =
                     plains[k + j * (expansion_ratio) + i * (coeff_mod_count * expansion_ratio)]
-                        .pointer();
+                        .data();
 
                 for (int m = 0; m < coeff_count - 1; m++) {
                     if (k == 0) {
@@ -188,6 +188,6 @@ Ciphertext PIRClient::compose_to_ciphertext(vector<Plaintext> plains) {
         }
     }
 
-    result.mutable_hash_block() = expanded_params_.hash_block();
+    result.hash_block() = expanded_params_.hash_block();
     return result;
 }

+ 7 - 7
pir_server.cpp

@@ -31,7 +31,7 @@ void PIRServer::update_parameters(const EncryptionParameters &expanded_params,
 
     // Update all the galois keys
     for (std::pair<const int, GaloisKeys> &key : galoisKeys_) {
-        key.second.mutable_hash_block() = expanded_params_.hash_block();
+        key.second.hash_block() = expanded_params_.hash_block();
     }
 }
 
@@ -138,7 +138,7 @@ void PIRServer::set_database(const uint8_t *bytes, uint64_t ele_num, uint64_t el
 }
 
 void PIRServer::set_galois_key(std::uint32_t client_id, seal::GaloisKeys galkey) {
-    galkey.mutable_hash_block() = expanded_params_.hash_block();
+    galkey.hash_block() = expanded_params_.hash_block();
     galoisKeys_[client_id] = galkey;
 }
 
@@ -308,10 +308,10 @@ inline void PIRServer::multiply_power_of_X(const Ciphertext &encrypted, Cipherte
     // Multiply X^index for each ciphertext polynomial
     for (int i = 0; i < encrypted_count; i++) {
         for (int j = 0; j < coeff_mod_count; j++) {
-            negacyclic_shift_poly_coeffmod(encrypted.pointer(i) + (j * coeff_count),
+            negacyclic_shift_poly_coeffmod(encrypted.data(i) + (j * coeff_count),
                                            coeff_count - 1, index,
                                            expanded_params_.coeff_modulus()[j],
-                                           destination.mutable_pointer(i) + (j * coeff_count));
+                                           destination.data(i) + (j * coeff_count));
         }
     }
 }
@@ -330,7 +330,7 @@ inline void PIRServer::decompose_to_plaintexts_ptr(const Ciphertext &encrypted,
     // A triple for loop. Going over polys, moduli, and decomposed index.
 
     for (int i = 0; i < encrypted_count; i++) {
-        const uint64_t *encrypted_pointer = encrypted.pointer(i);
+        const uint64_t *encrypted_pointer = encrypted.data(i);
         for (int j = 0; j < coeff_mod_count; j++) {
             // populate one poly at a time.
             // create a polynomial to store the current decomposition value
@@ -366,7 +366,7 @@ vector<Plaintext> PIRServer::decompose_to_plaintexts(const Ciphertext &encrypted
 
     // A triple for loop. Going over polys, moduli, and decomposed index.
     for (int i = 0; i < encrypted_count; i++) {
-        const uint64_t *encrypted_pointer = encrypted.pointer(i);
+        const uint64_t *encrypted_pointer = encrypted.data(i);
         for (int j = 0; j < coeff_mod_count; j++) {
             // populate one poly at a time.
             // create a polynomial to store the current decomposition value
@@ -382,7 +382,7 @@ vector<Plaintext> PIRServer::decompose_to_plaintexts(const Ciphertext &encrypted
                 BigPoly temp;
                 temp.resize(coeff_count, plain_bit_count);
                 temp.set_zero();
-                uint64_t *plain_coeff = temp.pointer();
+                uint64_t *plain_coeff = temp.data();
                 for (int m = 0; m < coeff_count; m++) {
                     *(plain_coeff + m) =
                         (*(encrypted_pointer + m + (j * coeff_count)) / cur) % plainMod;