From 6edabf6f203b01bf1ca90ac49d7e56d5e81c0be7 Mon Sep 17 00:00:00 2001 From: huelse Date: Sun, 27 Mar 2022 19:54:13 +0800 Subject: [PATCH 01/18] Switch to SEAL 4.0.0 --- .gitattributes | 1 - SEAL | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f339c1e..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.cpp linguist-language=Python diff --git a/SEAL b/SEAL index 88bbc51..82b07db 160000 --- a/SEAL +++ b/SEAL @@ -1 +1 @@ -Subproject commit 88bbc51dd684b82a781312ff04abd235c060163e +Subproject commit 82b07db635132e297282649e2ab5908999089ad2 From 003a9130cc88adbf0b611c656fda0e6defdf32a4 Mon Sep 17 00:00:00 2001 From: huelse Date: Mon, 28 Mar 2022 22:31:59 +0800 Subject: [PATCH 02/18] Switch to SEAL 4.0 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index b137095..7987467 100644 --- a/setup.py +++ b/setup.py @@ -11,13 +11,13 @@ # include directories include_dirs = [py_include_dir, './pybind11/include', './SEAL/native/src', './SEAL/build/native/src'] # library path -extra_objects = ['./SEAL/build/lib/libseal-3.7.a'] +extra_objects = ['./SEAL/build/lib/libseal-4.0.a'] # available wrapper: src/wrapper.cpp, src/wrapper_with_pickle.cpp wrapper_file = 'src/wrapper.cpp' if platform.system() == "Windows": cpp_args[0] = '/std:c++latest' # /std:c++1z - extra_objects[0] = './SEAL/build/lib/seal-3.7.lib' + extra_objects[0] = './SEAL/build/lib/seal-4.0.lib' if not os.path.exists(extra_objects[0]): print('Can not find the seal lib,') From 8863a753a30b84ab399691094541b3bb6aa90079 Mon Sep 17 00:00:00 2001 From: huelse Date: Mon, 28 Mar 2022 22:32:29 +0800 Subject: [PATCH 03/18] Rewrite CoeffModulus.Create --- src/wrapper.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wrapper.cpp b/src/wrapper.cpp index 5c2f82c..cb08b6d 100644 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -16,7 +16,7 @@ PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MODULE(seal, m) { - m.doc() = "Microsoft SEAL (3.7) for Python, from https://github.com/Huelse/SEAL-Python"; + m.doc() = "Microsoft SEAL (4.0) for Python, from https://github.com/Huelse/SEAL-Python"; py::bind_vector>(m, "VectorDouble", py::buffer_protocol()); py::bind_vector>(m, "VectorInt", py::buffer_protocol()); @@ -142,7 +142,8 @@ PYBIND11_MODULE(seal, m) py::class_(m, "CoeffModulus") .def_static("MaxBitCount", &CoeffModulus::MaxBitCount, py::arg(), py::arg()=sec_level_type::tc128) .def_static("BFVDefault", &CoeffModulus::BFVDefault, py::arg(), py::arg()=sec_level_type::tc128) - .def_static("Create", &CoeffModulus::Create); + .def_static("Create", py::overload_cast>(&CoeffModulus::Create)); + .def_static("Create", py::overload_cast>(&CoeffModulus::Create)); // modulus.h py::class_(m, "PlainModulus") From 94d9ecd0f8f32c285d33f900fe5882828d63c648 Mon Sep 17 00:00:00 2001 From: huelse Date: Mon, 28 Mar 2022 22:38:38 +0800 Subject: [PATCH 04/18] Fix semicolon --- src/wrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wrapper.cpp b/src/wrapper.cpp index cb08b6d..3e695d1 100644 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -142,7 +142,7 @@ PYBIND11_MODULE(seal, m) py::class_(m, "CoeffModulus") .def_static("MaxBitCount", &CoeffModulus::MaxBitCount, py::arg(), py::arg()=sec_level_type::tc128) .def_static("BFVDefault", &CoeffModulus::BFVDefault, py::arg(), py::arg()=sec_level_type::tc128) - .def_static("Create", py::overload_cast>(&CoeffModulus::Create)); + .def_static("Create", py::overload_cast>(&CoeffModulus::Create)) .def_static("Create", py::overload_cast>(&CoeffModulus::Create)); // modulus.h From 2563d7abbd307617edc1cb68672b6cb8d7f4f9fd Mon Sep 17 00:00:00 2001 From: huelse Date: Fri, 1 Apr 2022 23:41:25 +0800 Subject: [PATCH 05/18] Add scheme_type bgv and remove base64 tentatively --- setup.py | 2 +- src/wrapper.cpp | 29 +++-------------------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/setup.py b/setup.py index 7987467..d09c4a3 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ ext_modules = [ Extension( name='seal', - sources=[wrapper_file, 'src/base64.cpp'], + sources=[wrapper_file], include_dirs=include_dirs, language='c++', extra_compile_args=cpp_args, diff --git a/src/wrapper.cpp b/src/wrapper.cpp index 3e695d1..89383f1 100644 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -3,12 +3,9 @@ #include #include #include "seal/seal.h" -#include "base64.h" -#include #include using namespace seal; - namespace py = pybind11; PYBIND11_MAKE_OPAQUE(std::vector); @@ -25,7 +22,8 @@ PYBIND11_MODULE(seal, m) py::enum_(m, "scheme_type") .value("none", scheme_type::none) .value("bfv", scheme_type::bfv) - .value("ckks", scheme_type::ckks); + .value("ckks", scheme_type::ckks) + .value("bgv", scheme_type::bgv); // encryptionparams.h py::class_(m, "EncryptionParameters") @@ -48,28 +46,7 @@ PYBIND11_MODULE(seal, m) std::ifstream in(path, std::ifstream::binary); parms.load(in); in.close(); - }) - .def(py::pickle( - [](const EncryptionParameters &parms){ - std::stringstream out_stream(std::ios::binary | std::ios::out); - parms.save(out_stream); - std::string str_buf = out_stream.str(); - std::string encoded_str = base64_encode(reinterpret_cast(str_buf.c_str()), (unsigned int)str_buf.length()); - return py::make_tuple(encoded_str); - }, - [](py::tuple t){ - if (t.size() != 1) - throw std::runtime_error("E002: Invalid state!"); - - std::string encoded_str = t[0].cast(); - std::string decoded_str = base64_decode(encoded_str); - std::stringstream in_stream(std::ios::binary | std::ios::in); - in_stream.str(decoded_str); - EncryptionParameters parms; - parms.load(in_stream); - return parms; - } - )); + }); // modulus.h py::enum_(m, "sec_level_type") From c7d1ebb8954ce459b4b13ab20550f13ceb606ba7 Mon Sep 17 00:00:00 2001 From: huelse Date: Sun, 3 Apr 2022 18:49:11 +0800 Subject: [PATCH 06/18] Add 4_bgv_basics.py --- examples/4_bgv_basics.py | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 examples/4_bgv_basics.py diff --git a/examples/4_bgv_basics.py b/examples/4_bgv_basics.py new file mode 100644 index 0000000..fbc7adb --- /dev/null +++ b/examples/4_bgv_basics.py @@ -0,0 +1,56 @@ +from seal import * +import numpy as np + +def example_bgv_basics(): + parms = EncryptionParameters (scheme_type.bgv) + poly_modulus_degree = 8192 + parms.set_poly_modulus_degree(poly_modulus_degree) + parms.set_coeff_modulus(CoeffModulus.BFVDefault(poly_modulus_degree)) + parms.set_plain_modulus(PlainModulus.Batching(poly_modulus_degree, 20)) + context = SEALContext(parms) + print(context) + + keygen = KeyGenerator(context) + secret_key = keygen.secret_key() + public_key = keygen.create_public_key() + relin_keys = keygen.create_relin_keys() + print(secret_key, public_key, relin_keys) + + encryptor = Encryptor(context, public_key) + evaluator = Evaluator(context) + decryptor = Decryptor(context, secret_key) + print(encryptor, evaluator, decryptor) + + batch_encoder = BatchEncoder(context) + slot_count = batch_encoder.slot_count() + row_size = slot_count / 2 + print(f'Plaintext matrix row size: {row_size}') + + pod_matrix = [0] * slot_count + pod_matrix[0] = 1 + pod_matrix[1] = 2 + pod_matrix[2] = 3 + pod_matrix[3] = 4 + + x_plain = batch_encoder.encode(pod_matrix) + + x_encrypted = encryptor.encrypt(x_plain) + print(f'noise budget in freshly encrypted x: {decryptor.invariant_noise_budget(x_encrypted)}') + + x_squared = evaluator.square(x_encrypted) + print(f'size of x_squared: {x_squared.size()}') + evaluator.relinearize_inplace(x_squared, relin_keys) + + print(f'size of x_squared (after relinearization): {x_squared.size()}') + print(f'noise budget in x_squared: {decryptor.invariant_noise_budget(x_squared)} bits') + + decrypted_result = decryptor.decrypt(x_squared) + pod_result = batch_encoder.decode(decrypted_result) + + for i in range(0, 8): + print(pod_result[i], end=', ') + print() + + +if __name__ == "__main__": + example_bgv_basics() From efb75d1d68ba1648183cca566feae8370ca16c65 Mon Sep 17 00:00:00 2001 From: huelse Date: Sun, 3 Apr 2022 23:01:25 +0800 Subject: [PATCH 07/18] Complete bgv basic example --- examples/4_bgv_basics.py | 71 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/examples/4_bgv_basics.py b/examples/4_bgv_basics.py index fbc7adb..ec81cf7 100644 --- a/examples/4_bgv_basics.py +++ b/examples/4_bgv_basics.py @@ -1,6 +1,13 @@ from seal import * import numpy as np +def print_vector(vector): + print('[ ', end='') + for i in range(0, 8): + print(vector[i], end=', ') + print('... ]') + + def example_bgv_basics(): parms = EncryptionParameters (scheme_type.bgv) poly_modulus_degree = 8192 @@ -8,18 +15,15 @@ def example_bgv_basics(): parms.set_coeff_modulus(CoeffModulus.BFVDefault(poly_modulus_degree)) parms.set_plain_modulus(PlainModulus.Batching(poly_modulus_degree, 20)) context = SEALContext(parms) - print(context) keygen = KeyGenerator(context) secret_key = keygen.secret_key() public_key = keygen.create_public_key() relin_keys = keygen.create_relin_keys() - print(secret_key, public_key, relin_keys) encryptor = Encryptor(context, public_key) evaluator = Evaluator(context) decryptor = Decryptor(context, secret_key) - print(encryptor, evaluator, decryptor) batch_encoder = BatchEncoder(context) slot_count = batch_encoder.slot_count() @@ -36,20 +40,73 @@ def example_bgv_basics(): x_encrypted = encryptor.encrypt(x_plain) print(f'noise budget in freshly encrypted x: {decryptor.invariant_noise_budget(x_encrypted)}') + print('-'*50) x_squared = evaluator.square(x_encrypted) print(f'size of x_squared: {x_squared.size()}') evaluator.relinearize_inplace(x_squared, relin_keys) - print(f'size of x_squared (after relinearization): {x_squared.size()}') print(f'noise budget in x_squared: {decryptor.invariant_noise_budget(x_squared)} bits') + decrypted_result = decryptor.decrypt(x_squared) + pod_result = batch_encoder.decode(decrypted_result) + print_vector(pod_result) + print('-'*50) + + x_4th = evaluator.square(x_squared) + print(f'size of x_4th: {x_4th.size()}') + evaluator.relinearize_inplace(x_4th, relin_keys) + print(f'size of x_4th (after relinearization): { x_4th.size()}') + print(f'noise budget in x_4th: {decryptor.invariant_noise_budget(x_4th)} bits') + decrypted_result = decryptor.decrypt(x_4th) + pod_result = batch_encoder.decode(decrypted_result) + print_vector(pod_result) + print('-'*50) + + x_8th = evaluator.square(x_4th) + print(f'size of x_8th: {x_8th.size()}') + evaluator.relinearize_inplace(x_8th, relin_keys) + print(f'size of x_8th (after relinearization): { x_8th.size()}') + print(f'noise budget in x_8th: {decryptor.invariant_noise_budget(x_8th)} bits') + decrypted_result = decryptor.decrypt(x_8th) + pod_result = batch_encoder.decode(decrypted_result) + print_vector(pod_result) + print('run out of noise budget') + print('-'*100) + x_encrypted = encryptor.encrypt(x_plain) + print(f'noise budget in freshly encrypted x: {decryptor.invariant_noise_budget(x_encrypted)}') + print('-'*50) + + x_squared = evaluator.square(x_encrypted) + print(f'size of x_squared: {x_squared.size()}') + evaluator.relinearize_inplace(x_squared, relin_keys) + evaluator.mod_switch_to_next_inplace(x_squared) + print(f'noise budget in x_squared (with modulus switching): {decryptor.invariant_noise_budget(x_squared)} bits') decrypted_result = decryptor.decrypt(x_squared) pod_result = batch_encoder.decode(decrypted_result) + print_vector(pod_result) + print('-'*50) - for i in range(0, 8): - print(pod_result[i], end=', ') - print() + x_4th = evaluator.square(x_squared) + print(f'size of x_4th: {x_4th.size()}') + evaluator.relinearize_inplace(x_4th, relin_keys) + evaluator.mod_switch_to_next_inplace(x_4th) + print(f'size of x_4th (after relinearization): { x_4th.size()}') + print(f'noise budget in x_4th (with modulus switching): {decryptor.invariant_noise_budget(x_4th)} bits') + decrypted_result = decryptor.decrypt(x_4th) + pod_result = batch_encoder.decode(decrypted_result) + print_vector(pod_result) + print('-'*50) + + x_8th = evaluator.square(x_4th) + print(f'size of x_8th: {x_8th.size()}') + evaluator.relinearize_inplace(x_8th, relin_keys) + evaluator.mod_switch_to_next_inplace(x_8th) + print(f'size of x_8th (after relinearization): { x_8th.size()}') + print(f'noise budget in x_8th (with modulus switching): {decryptor.invariant_noise_budget(x_8th)} bits') + decrypted_result = decryptor.decrypt(x_8th) + pod_result = batch_encoder.decode(decrypted_result) + print_vector(pod_result) if __name__ == "__main__": From 9a6f0357ba0e21c023f3218ead9c722d7bbfe5fa Mon Sep 17 00:00:00 2001 From: huelse Date: Tue, 5 Apr 2022 00:02:44 +0800 Subject: [PATCH 08/18] Improve setup.py --- setup.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index d09c4a3..be1a9e1 100644 --- a/setup.py +++ b/setup.py @@ -20,9 +20,8 @@ extra_objects[0] = './SEAL/build/lib/seal-4.0.lib' if not os.path.exists(extra_objects[0]): - print('Can not find the seal lib,') - print('Compile the seal lib first or check the path.') - exit(1) + print('Not found the seal lib file') + exit(0) ext_modules = [ Extension( @@ -37,7 +36,7 @@ setup( name='seal', - version='3.7', + version='4.0', author='Huelse', author_email='huelse@oini.top', description='Python wrapper for the Microsoft SEAL', From 35a38455332e7915ada2e499ed3f8a085ecc09ed Mon Sep 17 00:00:00 2001 From: huelse Date: Tue, 5 Apr 2022 16:11:32 +0800 Subject: [PATCH 09/18] Remove unsupported files --- helper.py | 51 --- src/base64.cpp | 112 ------ src/base64.h | 14 - src/wrapper_with_pickle.cpp | 703 ------------------------------------ 4 files changed, 880 deletions(-) delete mode 100644 helper.py delete mode 100644 src/base64.cpp delete mode 100644 src/base64.h delete mode 100644 src/wrapper_with_pickle.cpp diff --git a/helper.py b/helper.py deleted file mode 100644 index 530960d..0000000 --- a/helper.py +++ /dev/null @@ -1,51 +0,0 @@ -import os - -root_path = './SEAL/native/src/seal/' -files = ['plaintext.h', 'ciphertext.h', 'kswitchkeys.h', 'secretkey.h', 'publickey.h'] -keyword = 'private:' -new_line = 'EncryptionParameters parms;' - - -def add_parms_to_header(): - for file_name in files: - file_path = root_path + file_name - if os.path.exists(file_path): - new_line_exists = True - with open(file_path, 'r', encoding='utf-8') as f: - lines = f.readlines() - for line in lines: - if new_line in line: - new_line_exists = False - - if new_line_exists: - with open(file_path, 'w', encoding='utf-8') as fs: - for line in lines: - if keyword in line: - line = line.replace(line, ' {}\n\n {}\n'.format(new_line, keyword)) - fs.write(line) - print('Add parms to {} success.'.format(file_path)) - else: - print('Can not find the {}, please check the file integrity.'.format(file_path)) - - -def switch_wrapper(): - ifswitch = False - with open('./setup.py', 'r', encoding='utf-8') as f: - lines = f.readlines() - for line in lines: - if "wrapper_file = 'src/wrapper.cpp'" in line: - ifswitch = True - if ifswitch: - with open('./setup.py', 'w', encoding='utf-8') as fs: - for line in lines: - if "wrapper_file = 'src/wrapper.cpp'" in line: - line = line.replace(line, "wrapper_file = 'src/wrapper_with_pickle.cpp'\n") - fs.write(line) - print("Switch wrapper success.") - else: - print('Already switch to wrapper with pickle.') - - -if __name__ == '__main__': - add_parms_to_header() - switch_wrapper() diff --git a/src/base64.cpp b/src/base64.cpp deleted file mode 100644 index 252224b..0000000 --- a/src/base64.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - base64.cpp and base64.h - base64 encoding and decoding with C++. - Version: 1.01.00 - Copyright (C) 2004-2017 René Nyffenegger - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - 3. This notice may not be removed or altered from any source distribution. - René Nyffenegger rene.nyffenegger@adp-gmbh.ch -*/ - -#include "base64.h" -#include - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - -static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - - } - - return ret; - -} - -std::string base64_decode(std::string const& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = ( char_array_4[0] << 2 ) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = 0; j < i; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; - } - - return ret; -} diff --git a/src/base64.h b/src/base64.h deleted file mode 100644 index dd1134c..0000000 --- a/src/base64.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// base64 encoding and decoding with C++. -// Version: 1.01.00 -// - -#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A -#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A - -#include - -std::string base64_encode(unsigned char const* , unsigned int len); -std::string base64_decode(std::string const& s); - -#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ diff --git a/src/wrapper_with_pickle.cpp b/src/wrapper_with_pickle.cpp deleted file mode 100644 index 61590c7..0000000 --- a/src/wrapper_with_pickle.cpp +++ /dev/null @@ -1,703 +0,0 @@ -#include -#include -#include -#include -#include "seal/seal.h" -#include "base64.h" -#include -#include -#include - -using namespace seal; - -namespace py = pybind11; - -PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(std::vector); - -template -struct HasParms : std::false_type { }; - -template -struct HasParms : std::true_type { }; - -template -py::tuple serialize(T &c) -{ - if (!HasParms::value) - throw std::runtime_error("E001: Invalid state! set parms first."); - - // EncryptionParameters - std::stringstream out_stream1(std::ios::binary | std::ios::out); - // if parms exists - c.parms.save(out_stream1); - std::string str_buf1 = out_stream1.str(); - std::string encoded_str1 = base64_encode(reinterpret_cast(str_buf1.c_str()), (unsigned int)str_buf1.length()); - - // T - std::stringstream out_stream2(std::ios::binary | std::ios::out); - c.save(out_stream2); - std::string str_buf2 = out_stream2.str(); - std::string encoded_str2 = base64_encode(reinterpret_cast(str_buf2.c_str()), (unsigned int)str_buf2.length()); - - return py::make_tuple(encoded_str1, encoded_str2); -} - -template -T deserialize(py::tuple t) -{ - if (t.size() != 2) - throw std::runtime_error("E002: Invalid state!"); - - // EncryptionParameters - std::string encoded_str1 = t[0].cast(); - std::string decoded_str1 = base64_decode(encoded_str1); - std::stringstream in_stream1(std::ios::binary | std::ios::in); - in_stream1.str(decoded_str1); - EncryptionParameters parms; - parms.load(in_stream1); - SEALContext context(parms); - - // T - std::string encoded_str2 = t[1].cast(); - std::string decoded_str2 = base64_decode(encoded_str2); - std::stringstream in_stream2(std::ios::binary | std::ios::in); - in_stream2.str(decoded_str2); - T c; - c.load(context, in_stream2); - - return c; -} - -PYBIND11_MODULE(seal, m) -{ - m.doc() = "Microsoft SEAL (3.7) for Python, from https://github.com/Huelse/SEAL-Python"; - - py::bind_vector>(m, "VectorDouble", py::buffer_protocol()); - py::bind_vector>(m, "VectorInt", py::buffer_protocol()); - - // encryptionparams.h - py::enum_(m, "scheme_type") - .value("none", scheme_type::none) - .value("bfv", scheme_type::bfv) - .value("ckks", scheme_type::ckks); - - // encryptionparams.h - py::class_(m, "EncryptionParameters") - .def(py::init()) - .def(py::init()) - .def("set_poly_modulus_degree", &EncryptionParameters::set_poly_modulus_degree) - .def("set_coeff_modulus", &EncryptionParameters::set_coeff_modulus) - .def("set_plain_modulus", py::overload_cast(&EncryptionParameters::set_plain_modulus)) - .def("set_plain_modulus", py::overload_cast(&EncryptionParameters::set_plain_modulus)) - .def("scheme", &EncryptionParameters::scheme) - .def("poly_modulus_degree", &EncryptionParameters::poly_modulus_degree) - .def("coeff_modulus", &EncryptionParameters::coeff_modulus) - .def("plain_modulus", &EncryptionParameters::plain_modulus) - .def("save", [](const EncryptionParameters &parms, std::string &path){ - std::ofstream out(path, std::ofstream::binary); - parms.save(out); - out.close(); - }) - .def("load", [](EncryptionParameters &parms, std::string &path){ - std::ifstream in(path, std::ifstream::binary); - parms.load(in); - in.close(); - }) - .def(py::pickle( - [](const EncryptionParameters &parms){ - std::stringstream out_stream(std::ios::binary | std::ios::out); - parms.save(out_stream); - std::string str_buf = out_stream.str(); - std::string encoded_str = base64_encode(reinterpret_cast(str_buf.c_str()), (unsigned int)str_buf.length()); - return py::make_tuple(encoded_str); - }, - [](py::tuple t){ - if (t.size() != 1) - throw std::runtime_error("E002: Invalid state!"); - - std::string encoded_str = t[0].cast(); - std::string decoded_str = base64_decode(encoded_str); - std::stringstream in_stream(std::ios::binary | std::ios::in); - in_stream.str(decoded_str); - EncryptionParameters parms; - parms.load(in_stream); - return parms; - } - )); - - // modulus.h - py::enum_(m, "sec_level_type") - .value("none", sec_level_type::none) - .value("tc128", sec_level_type::tc128) - .value("tc192", sec_level_type::tc192) - .value("tc256", sec_level_type::tc256); - - // context.h - py::enum_(m, "error_type") - .value("none", EncryptionParameterQualifiers::error_type::none) - .value("success", EncryptionParameterQualifiers::error_type::success) - .value("invalid_scheme", EncryptionParameterQualifiers::error_type::invalid_scheme) - .value("invalid_coeff_modulus_size", EncryptionParameterQualifiers::error_type::invalid_coeff_modulus_size) - .value("invalid_coeff_modulus_bit_count", EncryptionParameterQualifiers::error_type::invalid_coeff_modulus_bit_count) - .value("invalid_coeff_modulus_no_ntt", EncryptionParameterQualifiers::error_type::invalid_coeff_modulus_no_ntt) - .value("invalid_poly_modulus_degree", EncryptionParameterQualifiers::error_type::invalid_poly_modulus_degree) - .value("invalid_poly_modulus_degree_non_power_of_two", EncryptionParameterQualifiers::error_type::invalid_poly_modulus_degree_non_power_of_two) - .value("invalid_parameters_too_large", EncryptionParameterQualifiers::error_type::invalid_parameters_too_large) - .value("invalid_parameters_insecure", EncryptionParameterQualifiers::error_type::invalid_parameters_insecure) - .value("failed_creating_rns_base", EncryptionParameterQualifiers::error_type::failed_creating_rns_base) - .value("invalid_plain_modulus_bit_count", EncryptionParameterQualifiers::error_type::invalid_plain_modulus_bit_count) - .value("invalid_plain_modulus_coprimality", EncryptionParameterQualifiers::error_type::invalid_plain_modulus_coprimality) - .value("invalid_plain_modulus_too_large", EncryptionParameterQualifiers::error_type::invalid_plain_modulus_too_large) - .value("invalid_plain_modulus_nonzero", EncryptionParameterQualifiers::error_type::invalid_plain_modulus_nonzero) - .value("failed_creating_rns_tool", EncryptionParameterQualifiers::error_type::failed_creating_rns_tool); - - // context.h - py::class_>(m, "EncryptionParameterQualifiers") - .def("parameters_set", &EncryptionParameterQualifiers::parameters_set) - .def_readwrite("using_fft", &EncryptionParameterQualifiers::using_fft) - .def_readwrite("using_ntt", &EncryptionParameterQualifiers::using_ntt) - .def_readwrite("using_batching", &EncryptionParameterQualifiers::using_batching) - .def_readwrite("using_fast_plain_lift", &EncryptionParameterQualifiers::using_fast_plain_lift) - .def_readwrite("using_descending_modulus_chain", &EncryptionParameterQualifiers::using_descending_modulus_chain) - .def_readwrite("sec_level", &EncryptionParameterQualifiers::sec_level); - - // context.h - py::class_>(m, "ContextData") - .def("parms", &SEALContext::ContextData::parms) - .def("parms_id", &SEALContext::ContextData::parms_id) - .def("qualifiers", &SEALContext::ContextData::qualifiers) - .def("total_coeff_modulus", &SEALContext::ContextData::total_coeff_modulus) - .def("total_coeff_modulus_bit_count", &SEALContext::ContextData::total_coeff_modulus_bit_count) - .def("next_context_data", &SEALContext::ContextData::next_context_data) - .def("chain_index", &SEALContext::ContextData::chain_index); - - // context.h - py::class_>(m, "SEALContext") - .def(py::init(), py::arg(), py::arg()=true, py::arg()=sec_level_type::tc128) - .def("get_context_data", &SEALContext::get_context_data) - .def("key_context_data", &SEALContext::key_context_data) - .def("first_context_data", &SEALContext::first_context_data) - .def("last_context_data", &SEALContext::last_context_data) - .def("parameters_set", &SEALContext::parameters_set) - .def("first_parms_id", &SEALContext::first_parms_id) - .def("last_parms_id", &SEALContext::last_parms_id) - .def("using_keyswitching", &SEALContext::using_keyswitching); - - // modulus.h - py::class_(m, "Modulus") - .def(py::init()) - .def("bit_count", &Modulus::bit_count) - .def("value", &Modulus::value) - .def("is_zero", &Modulus::is_zero) - .def("is_prime", &Modulus::is_prime); - //save & load - - // modulus.h - py::class_(m, "CoeffModulus") - .def_static("MaxBitCount", &CoeffModulus::MaxBitCount, py::arg(), py::arg()=sec_level_type::tc128) - .def_static("BFVDefault", &CoeffModulus::BFVDefault, py::arg(), py::arg()=sec_level_type::tc128) - .def_static("Create", &CoeffModulus::Create); - - // modulus.h - py::class_(m, "PlainModulus") - .def_static("Batching", py::overload_cast(&PlainModulus::Batching)) - .def_static("Batching", py::overload_cast>(&PlainModulus::Batching)); - - // plaintext.h - py::class_(m, "Plaintext") - .def(py::init<>()) - .def(py::init<std::size_t>()) - .def(py::init<std::size_t, std::size_t>()) - .def(py::init<const std::string &>()) - .def(py::init<const Plaintext &>()) - .def("set_zero", py::overload_cast<std::size_t, std::size_t>(&Plaintext::set_zero)) - .def("set_zero", py::overload_cast<std::size_t>(&Plaintext::set_zero)) - .def("set_zero", py::overload_cast<>(&Plaintext::set_zero)) - .def("is_zero", &Plaintext::is_zero) - .def("capacity", &Plaintext::capacity) - .def("coeff_count", &Plaintext::coeff_count) - .def("significant_coeff_count", &Plaintext::significant_coeff_count) - .def("nonzero_coeff_count", &Plaintext::nonzero_coeff_count) - .def("to_string", &Plaintext::to_string) - .def("is_ntt_form", &Plaintext::is_ntt_form) - .def("parms_id", py::overload_cast<>(&Plaintext::parms_id, py::const_), py::return_value_policy::reference) - .def("scale", py::overload_cast<>(&Plaintext::scale, py::const_), py::return_value_policy::reference) - .def("scale", [](Plaintext &plain, double scale){ - plain.scale() = scale; - }) - .def("save", [](const Plaintext &plain, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - plain.save(out); - out.close(); - }) - .def("load", [](Plaintext &plain, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - plain.load(context, in); - in.close(); - }) - .def("set_parms", [](Plaintext &plain, const EncryptionParameters &parms){ - plain.parms = parms; - }) - .def("save_size", [](const Plaintext &plain){ - return plain.save_size(); - }) - .def(py::pickle(&serialize<Plaintext>, &deserialize<Plaintext>)); - - // ciphertext.h - py::class_<Ciphertext>(m, "Ciphertext") - .def(py::init<>()) - .def(py::init<const SEALContext &>()) - .def(py::init<const SEALContext &, parms_id_type>()) - .def(py::init<const SEALContext &, parms_id_type, std::size_t>()) - .def(py::init<const Ciphertext &>()) - .def("coeff_modulus_size", &Ciphertext::coeff_modulus_size) - .def("poly_modulus_degree", &Ciphertext::poly_modulus_degree) - .def("size", &Ciphertext::size) - .def("size_capacity", &Ciphertext::size_capacity) - .def("is_transparent", &Ciphertext::is_transparent) - .def("is_ntt_form", py::overload_cast<>(&Ciphertext::is_ntt_form, py::const_)) - .def("parms_id", py::overload_cast<>(&Ciphertext::parms_id, py::const_), py::return_value_policy::reference) - .def("scale", py::overload_cast<>(&Ciphertext::scale, py::const_), py::return_value_policy::reference) - .def("scale", [](Ciphertext &cipher, double scale){ - cipher.scale() = scale; - }) - .def("save", [](const Ciphertext &cipher, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - cipher.save(out); - out.close(); - }) - .def("load", [](Ciphertext &cipher, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - cipher.load(context, in); - in.close(); - }) - .def("set_parms", [](Ciphertext &cipher, const EncryptionParameters &parms){ - cipher.parms = parms; - }) - .def("save_size", [](const Ciphertext &cipher){ - return cipher.save_size(); - }) - .def(py::pickle(&serialize<Ciphertext>, &deserialize<Ciphertext>)); - - // secretkey.h - py::class_<SecretKey>(m, "SecretKey") - .def(py::init<>()) - .def(py::init<const SecretKey &>()) - .def("parms_id", py::overload_cast<>(&SecretKey::parms_id, py::const_), py::return_value_policy::reference) - .def("save", [](const SecretKey &sk, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - sk.save(out); - out.close(); - }) - .def("load", [](SecretKey &sk, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - sk.load(context, in); - in.close(); - }) - .def("set_parms", [](SecretKey &sk, const EncryptionParameters &parms){ - sk.parms = parms; - }) - .def(py::pickle(&serialize<SecretKey>, &deserialize<SecretKey>)); - - // publickey.h - py::class_<PublicKey>(m, "PublicKey") - .def(py::init<>()) - .def(py::init<const PublicKey &>()) - .def("parms_id", py::overload_cast<>(&PublicKey::parms_id, py::const_), py::return_value_policy::reference) - .def("save", [](const PublicKey &pk, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - pk.save(out); - out.close(); - }) - .def("load", [](PublicKey &pk, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - pk.load(context, in); - in.close(); - }) - .def("set_parms", [](PublicKey &pk, const EncryptionParameters &parms){ - pk.parms = parms; - }) - .def(py::pickle(&serialize<PublicKey>, &deserialize<PublicKey>)); - - // kswitchkeys.h - py::class_<KSwitchKeys>(m, "KSwitchKeys") - .def(py::init<>()) - .def(py::init<const KSwitchKeys &>()) - .def("size", &KSwitchKeys::size) - .def("parms_id", py::overload_cast<>(&KSwitchKeys::parms_id, py::const_), py::return_value_policy::reference) - .def("save", [](const KSwitchKeys &ksk, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - ksk.save(out); - out.close(); - }) - .def("load", [](KSwitchKeys &ksk, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - ksk.load(context, in); - in.close(); - }) - .def("set_parms", [](KSwitchKeys &ksk, const EncryptionParameters &parms){ - ksk.parms = parms; - }) - .def(py::pickle(&serialize<KSwitchKeys>, &deserialize<KSwitchKeys>)); - - // relinKeys.h - py::class_<RelinKeys, KSwitchKeys>(m, "RelinKeys") - .def(py::init<>()) - .def(py::init<const RelinKeys::KSwitchKeys &>()) - .def("size", &RelinKeys::KSwitchKeys::size) - .def("parms_id", py::overload_cast<>(&RelinKeys::KSwitchKeys::parms_id, py::const_), py::return_value_policy::reference) - .def("save", [](const RelinKeys &rk, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - rk.save(out); - out.close(); - }) - .def("load", [](RelinKeys &rk, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - rk.load(context, in); - in.close(); - }) - .def_static("get_index", &RelinKeys::get_index) - .def("has_key", &RelinKeys::has_key) - .def("set_parms", [](RelinKeys &rk, const EncryptionParameters &parms){ - rk.parms = parms; - }) - .def(py::pickle(&serialize<RelinKeys>, &deserialize<RelinKeys>)); - - // galoisKeys.h - py::class_<GaloisKeys, KSwitchKeys>(m, "GaloisKeys") - .def(py::init<>()) - .def(py::init<const GaloisKeys::KSwitchKeys &>()) - .def("size", &GaloisKeys::KSwitchKeys::size) - .def("parms_id", py::overload_cast<>(&GaloisKeys::KSwitchKeys::parms_id, py::const_), py::return_value_policy::reference) - .def("save", [](const GaloisKeys &gk, const std::string &path){ - std::ofstream out(path, std::ofstream::binary); - gk.save(out); - out.close(); - }) - .def("load", [](GaloisKeys &gk, const SEALContext &context, const std::string &path){ - std::ifstream in(path, std::ifstream::binary); - gk.load(context, in); - in.close(); - }) - .def_static("get_index", &GaloisKeys::get_index) - .def("has_key", &GaloisKeys::has_key) - .def("set_parms", [](GaloisKeys &gk, const EncryptionParameters &parms){ - gk.parms = parms; - }) - .def(py::pickle(&serialize<GaloisKeys>, &deserialize<GaloisKeys>)); - - // keygenerator.h - py::class_<KeyGenerator>(m, "KeyGenerator") - .def(py::init<const SEALContext &>()) - .def(py::init<const SEALContext &, const SecretKey &>()) - .def("secret_key", &KeyGenerator::secret_key, py::return_value_policy::reference) - .def("create_public_key", py::overload_cast<PublicKey &>(&KeyGenerator::create_public_key, py::const_)) - .def("create_relin_keys", py::overload_cast<RelinKeys &>(&KeyGenerator::create_relin_keys)) - .def("create_galois_keys", py::overload_cast<const std::vector<int> &, GaloisKeys &>(&KeyGenerator::create_galois_keys)) - .def("create_galois_keys", py::overload_cast<GaloisKeys &>(&KeyGenerator::create_galois_keys)) - .def("create_public_key", [](KeyGenerator &keygen){ - PublicKey pk; - keygen.create_public_key(pk); - return pk; - }) - .def("create_relin_keys", [](KeyGenerator &keygen){ - RelinKeys rk; - keygen.create_relin_keys(rk); - return rk; - }) - .def("create_galois_keys", [](KeyGenerator &keygen){ - GaloisKeys gk; - keygen.create_galois_keys(gk); - return gk; - }); - - // encryptor.h - py::class_<Encryptor>(m, "Encryptor") - .def(py::init<const SEALContext &, const PublicKey &>()) - .def(py::init<const SEALContext &, const SecretKey &>()) - .def(py::init<const SEALContext &, const PublicKey &, const SecretKey &>()) - .def("set_public_key", &Encryptor::set_public_key) - .def("set_secret_key", &Encryptor::set_secret_key) - .def("encrypt_zero", [](const Encryptor &encryptor){ - Ciphertext encrypted; - encryptor.encrypt_zero(encrypted); - return encrypted; - }) - .def("encrypt", [](const Encryptor &encryptor, const Plaintext &plain){ - Ciphertext encrypted; - encryptor.encrypt(plain, encrypted); - return encrypted; - }); - // symmetric - - // evaluator.h - py::class_<Evaluator>(m, "Evaluator") - .def(py::init<const SEALContext &>()) - .def("negate_inplace", &Evaluator::negate_inplace) - .def("negate", [](Evaluator &evaluator, const Ciphertext &encrypted1){ - Ciphertext destination; - evaluator.negate(encrypted1, destination); - return destination; - }) - .def("add_inplace", &Evaluator::add_inplace) - .def("add", [](Evaluator &evaluator, const Ciphertext &encrypted1, const Ciphertext &encrypted2){ - Ciphertext destination; - evaluator.add(encrypted1, encrypted2, destination); - return destination; - }) - .def("add_many", [](Evaluator &evaluator, const std::vector<Ciphertext> &encrypteds){ - Ciphertext destination; - evaluator.add_many(encrypteds, destination); - return destination; - }) - .def("sub_inplace", &Evaluator::sub_inplace) - .def("sub", [](Evaluator &evaluator, const Ciphertext &encrypted1, const Ciphertext &encrypted2){ - Ciphertext destination; - evaluator.sub(encrypted1, encrypted2, destination); - return destination; - }) - .def("multiply_inplace", [](Evaluator &evaluator, Ciphertext &encrypted1, const Ciphertext &encrypted2){ - evaluator.multiply_inplace(encrypted1, encrypted2); - }) - .def("multiply", [](Evaluator &evaluator, const Ciphertext &encrypted1, const Ciphertext &encrypted2){ - Ciphertext destination; - evaluator.multiply(encrypted1, encrypted2, destination); - return destination; - }) - .def("square_inplace", [](Evaluator &evaluator, Ciphertext &encrypted1){ - evaluator.square_inplace(encrypted1); - }) - .def("square", [](Evaluator &evaluator, const Ciphertext &encrypted1){ - Ciphertext destination; - evaluator.square(encrypted1, destination); - return destination; - }) - .def("relinearize_inplace", [](Evaluator &evaluator, Ciphertext &encrypted1, const RelinKeys &relin_keys){ - evaluator.relinearize_inplace(encrypted1, relin_keys); - }) - .def("relinearize", [](Evaluator &evaluator, const Ciphertext &encrypted1, const RelinKeys &relin_keys){ - Ciphertext destination; - evaluator.relinearize(encrypted1, relin_keys, destination); - return destination; - }) - .def("mod_switch_to_next", [](Evaluator &evaluator, const Ciphertext &encrypted){ - Ciphertext destination; - evaluator.mod_switch_to_next(encrypted, destination); - return destination; - }) - .def("mod_switch_to_next_inplace", [](Evaluator &evaluator, Ciphertext &encrypted){ - evaluator.mod_switch_to_next_inplace(encrypted); - }) - .def("mod_switch_to_next_inplace", py::overload_cast<Plaintext &>(&Evaluator::mod_switch_to_next_inplace, py::const_)) - .def("mod_switch_to_next", [](Evaluator &evaluator, const Plaintext &plain){ - Plaintext destination; - evaluator.mod_switch_to_next(plain, destination); - return destination; - }) - .def("mod_switch_to_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, parms_id_type parms_id){ - evaluator.mod_switch_to_inplace(encrypted, parms_id); - }) - .def("mod_switch_to", [](Evaluator &evaluator, const Ciphertext &encrypted, parms_id_type parms_id){ - Ciphertext destination; - evaluator.mod_switch_to(encrypted, parms_id, destination); - return destination; - }) - .def("mod_switch_to_inplace", py::overload_cast<Plaintext &, parms_id_type>(&Evaluator::mod_switch_to_inplace, py::const_)) - .def("mod_switch_to", [](Evaluator &evaluator, const Plaintext &plain, parms_id_type parms_id){ - Plaintext destination; - evaluator.mod_switch_to(plain, parms_id, destination); - return destination; - }) - .def("rescale_to_next", [](Evaluator &evaluator, const Ciphertext &encrypted){ - Ciphertext destination; - evaluator.rescale_to_next(encrypted, destination); - return destination; - }) - .def("rescale_to_next_inplace", [](Evaluator &evaluator, Ciphertext &encrypted){ - evaluator.rescale_to_next_inplace(encrypted); - }) - .def("rescale_to_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, parms_id_type parms_id){ - evaluator.rescale_to_inplace(encrypted, parms_id); - }) - .def("rescale_to", [](Evaluator &evaluator, const Ciphertext &encrypted, parms_id_type parms_id){ - Ciphertext destination; - evaluator.rescale_to(encrypted, parms_id, destination); - return destination; - }) - .def("multiply_many", [](Evaluator &evaluator, const std::vector<Ciphertext> &encrypteds, const RelinKeys &relin_keys){ - Ciphertext destination; - evaluator.multiply_many(encrypteds, relin_keys, destination); - return destination; - }) - .def("exponentiate_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, std::uint64_t exponent, const RelinKeys &relin_keys){ - evaluator.exponentiate_inplace(encrypted, exponent, relin_keys); - }) - .def("exponentiate", [](Evaluator &evaluator, const Ciphertext &encrypted, std::uint64_t exponent, const RelinKeys &relin_keys){ - Ciphertext destination; - evaluator.exponentiate(encrypted, exponent, relin_keys, destination); - return destination; - }) - .def("add_plain_inplace", &Evaluator::add_plain_inplace) - .def("add_plain", [](Evaluator &evaluator, const Ciphertext &encrypted, const Plaintext &plain){ - Ciphertext destination; - evaluator.add_plain(encrypted, plain, destination); - return destination; - }) - .def("sub_plain_inplace", &Evaluator::sub_plain_inplace) - .def("sub_plain", [](Evaluator &evaluator, const Ciphertext &encrypted, const Plaintext &plain){ - Ciphertext destination; - evaluator.sub_plain(encrypted, plain, destination); - return destination; - }) - .def("multiply_plain_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, const Plaintext &plain){ - evaluator.multiply_plain_inplace(encrypted, plain); - }) - .def("multiply_plain", [](Evaluator &evaluator, const Ciphertext &encrypted, const Plaintext &plain){ - Ciphertext destination; - evaluator.multiply_plain(encrypted, plain, destination); - return destination; - }) - .def("transform_to_ntt_inplace", [](Evaluator &evaluator, Plaintext &plain, parms_id_type parms_id){ - evaluator.transform_to_ntt_inplace(plain,parms_id); - }) - .def("transform_to_ntt", [](Evaluator &evaluator, const Plaintext &plain, parms_id_type parms_id){ - Plaintext destination_ntt; - evaluator.transform_to_ntt(plain, parms_id, destination_ntt); - return destination_ntt; - }) - .def("transform_to_ntt_inplace", py::overload_cast<Ciphertext &>(&Evaluator::transform_to_ntt_inplace, py::const_)) - .def("transform_to_ntt", [](Evaluator &evaluator, const Ciphertext &encrypted){ - Ciphertext destination_ntt; - evaluator.transform_to_ntt(encrypted, destination_ntt); - return destination_ntt; - }) - .def("transform_from_ntt_inplace", &Evaluator::transform_from_ntt_inplace) - .def("transform_from_ntt", [](Evaluator &evaluator, const Ciphertext &encrypted_ntt){ - Ciphertext destination; - evaluator.transform_from_ntt(encrypted_ntt, destination); - return destination; - }) - .def("apply_galois_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, std::uint32_t galois_elt, const GaloisKeys &galois_keys){ - evaluator.apply_galois_inplace(encrypted, galois_elt, galois_keys); - }) - .def("apply_galois", [](Evaluator &evaluator, const Ciphertext &encrypted, std::uint32_t galois_elt, const GaloisKeys &galois_keys){ - Ciphertext destination; - evaluator.apply_galois(encrypted, galois_elt, galois_keys, destination); - return destination; - }) - .def("rotate_rows_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys){ - evaluator.rotate_rows_inplace(encrypted, steps, galois_keys); - }) - .def("rotate_rows", [](Evaluator &evaluator, const Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys){ - Ciphertext destination; - evaluator.rotate_rows(encrypted, steps, galois_keys, destination); - return destination; - }) - .def("rotate_columns_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, const GaloisKeys &galois_keys){ - evaluator.rotate_columns_inplace(encrypted, galois_keys); - }) - .def("rotate_columns", [](Evaluator &evaluator, const Ciphertext &encrypted, const GaloisKeys &galois_keys){ - Ciphertext destination; - evaluator.rotate_columns(encrypted, galois_keys, destination); - return destination; - }) - .def("rotate_vector_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys){ - evaluator.rotate_vector_inplace(encrypted, steps, galois_keys); - }) - .def("rotate_vector", [](Evaluator &evaluator, const Ciphertext &encrypted, int steps, const GaloisKeys &galois_keys){ - Ciphertext destination; - evaluator.rotate_vector(encrypted, steps, galois_keys, destination); - return destination; - }) - .def("complex_conjugate_inplace", [](Evaluator &evaluator, Ciphertext &encrypted, const GaloisKeys &galois_keys){ - evaluator.complex_conjugate_inplace(encrypted, galois_keys); - }) - .def("complex_conjugate", [](Evaluator &evaluator, const Ciphertext &encrypted, const GaloisKeys &galois_keys){ - Ciphertext destination; - evaluator.complex_conjugate(encrypted, galois_keys, destination); - return destination; - }); - - // ckks.h - py::class_<CKKSEncoder>(m, "CKKSEncoder") - .def(py::init<const SEALContext &>()) - .def("slot_count", &CKKSEncoder::slot_count) - .def("encode", [](CKKSEncoder &encoder, py::array_t<double> values, double scale){ - py::buffer_info buf = values.request(); - if (buf.ndim != 1) - throw std::runtime_error("E101: Number of dimensions must be one"); - - double *ptr = (double *)buf.ptr; - std::vector<double> vec(buf.shape[0]); - - for (auto i = 0; i < buf.shape[0]; i++) - vec[i] = ptr[i]; - - Plaintext pt; - encoder.encode(vec, scale, pt); - return pt; - }) - .def("encode", [](CKKSEncoder &encoder, double value, double scale){ - Plaintext pt; - encoder.encode(value, scale, pt); - return pt; - }) - .def("decode", [](CKKSEncoder &encoder, const Plaintext &plain){ - std::vector<double> destination; - encoder.decode(plain, destination); - - py::array_t<double> values(destination.size()); - py::buffer_info buf = values.request(); - double *ptr = (double *)buf.ptr; - - for (auto i = 0; i < buf.shape[0]; i++) - ptr[i] = destination[i]; - - return values; - }); - - // decryptor.h - py::class_<Decryptor>(m, "Decryptor") - .def(py::init<const SEALContext &, const SecretKey &>()) - .def("decrypt", &Decryptor::decrypt) - .def("invariant_noise_budget", &Decryptor::invariant_noise_budget) - .def("decrypt", [](Decryptor &decryptor, const Ciphertext &encrypted){ - Plaintext pt; - decryptor.decrypt(encrypted, pt); - return pt; - }); - - // batchencoder.h - py::class_<BatchEncoder>(m, "BatchEncoder") - .def(py::init<const SEALContext &>()) - .def("slot_count", &BatchEncoder::slot_count) - .def("encode", [](BatchEncoder &encoder, py::array_t<std::int64_t> values){ - py::buffer_info buf = values.request(); - if (buf.ndim != 1) - throw std::runtime_error("E101: Number of dimensions must be one"); - - std::int64_t *ptr = (std::int64_t *)buf.ptr; - std::vector<std::int64_t> vec(buf.shape[0]); - - for (auto i = 0; i < buf.shape[0]; i++) - vec[i] = ptr[i]; - - Plaintext pt; - encoder.encode(vec, pt); - return pt; - }) - .def("decode", [](BatchEncoder &encoder, const Plaintext &plain){ - std::vector<std::int64_t> destination; - encoder.decode(plain, destination); - - py::array_t<std::int64_t> values(destination.size()); - py::buffer_info buf = values.request(); - std::int64_t *ptr = (std::int64_t *)buf.ptr; - - for (auto i = 0; i < buf.shape[0]; i++) - ptr[i] = destination[i]; - - return values; - }); -} From e370593313ece352b6a9dfafe21d510458167f27 Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 16:11:54 +0800 Subject: [PATCH 10/18] Improve words and details --- README.md | 48 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index f7e0820..4358544 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,9 @@ This is a python binding for the Microsoft SEAL library. ## Build -* #### Linux + + +* ### Linux Clang++ (>= 5.0) or GNU G++ (>= 6.0), CMake (>= 3.12) ```shell @@ -47,10 +49,11 @@ This is a python binding for the Microsoft SEAL library. # Run the setup.py python3 setup.py build_ext -i ``` - - CMake Options: `-DSEAL_BUILD_EXAMPLES=ON` and [more](https://github.com/microsoft/SEAL#basic-cmake-options) -* #### Windows + Build examples (add after `cmake -S . -B`): `-DSEAL_BUILD_EXAMPLES=ON` and [more cmake options](https://github.com/microsoft/SEAL#basic-cmake-options) + + +* ### Windows Visual Studio 2019 or newer is required. And use the **x64 Native Tools Command Prompt for Visual Studio 2019** command prompt to configure and build the Microsoft SEAL library. It's usually can be found in your Start Menu. @@ -64,10 +67,10 @@ This is a python binding for the Microsoft SEAL library. python setup.py build_ext -i ``` - In general, the Ninja generator is better than the "Visual Studio 16 2019" generator, and there is more information in the Microsoft SEAL official [illustrate](https://github.com/microsoft/SEAL#building-microsoft-seal-manually). + In general, the Ninja generator is better than the "Visual Studio 16 2019" generator, and there is more information in the Microsoft SEAL official [docs](https://github.com/microsoft/SEAL#building-microsoft-seal-manually). -* #### Docker +* ### Docker requires: [Docker](https://www.docker.com/) To build source code into a docker image (from this directory): @@ -80,9 +83,12 @@ This is a python binding for the Microsoft SEAL library. docker run -it huelse/seal ``` + + ## Note -* #### Serialize + +* ## Serialize In most situations, you can use the SEAL's native serialize API to save the data, here is an example: @@ -93,34 +99,12 @@ This is a python binding for the Microsoft SEAL library. load_cipher.load(context, 'cipher') # work if the context is valid. ``` - Support type: `Encryptionparams, Ciphertext, Plaintext, SecretKey, Publickey, Relinkeys, Galoiskeys` - - If you want to use the pickle to serialize your data, you need to do these things below: - - ```shell - # 1. Modify the serializable object's header file in SEAL and switch the wrapper. - python helper.py + Supported classes: `Encryptionparams, Ciphertext, Plaintext, SecretKey, Publickey, Relinkeys, Galoiskeys` - # 2. Rebuild the SEAL lib like above - cmake --build build - - # 3. Run the setup.py - python setup.py build_ext -i - ``` - - And serialize the data object like this: - - ```python - import pickle - - cipher.set_parms(parms) # necessary - cipher_dump = pickle.dumps(cipher) - cipher_load = pickle.loads(cipher_dump) - ``` -* #### Other +* ### Other - There are a lot of changes in the latest SEAL lib, we try to make the API in python can be used easier, it may remain some problems we unknown, if any problems(bugs), [Issue](https://github.com/Huelse/SEAL-Python/issues) please. + There are a lot of changes in the latest SEAL lib, we try to make the API in python can be used easier, but it may remain some problems unknown, if any problems or bugs, report [issues](https://github.com/Huelse/SEAL-Python/issues). Email: [topmaxz@protonmail.com](mailto:topmaxz@protonmail.com?subject=Github-SEAL-Python-Issues) From fc48ea5dc9479a12c92f1d7f5615bb96b94f73f6 Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 16:24:00 +0800 Subject: [PATCH 11/18] Format and add recommend versions --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4358544..100c225 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ This is a python binding for the Microsoft SEAL library. ## Build - * ### Linux - Clang++ (>= 5.0) or GNU G++ (>= 6.0), CMake (>= 3.12) + + Recommend: Clang++ (>= 10.0) or GNU G++ (>= 9.4), CMake (>= 3.16) ```shell # Optional @@ -71,6 +71,7 @@ This is a python binding for the Microsoft SEAL library. * ### Docker + requires: [Docker](https://www.docker.com/) To build source code into a docker image (from this directory): @@ -87,8 +88,7 @@ This is a python binding for the Microsoft SEAL library. ## Note - -* ## Serialize +* ### Serialize In most situations, you can use the SEAL's native serialize API to save the data, here is an example: @@ -132,9 +132,14 @@ This is a python binding for the Microsoft SEAL library. The `.so` or `.pyd` file must be in the current directory, or you have `install` it already. +5. Windows Error LNK2001, RuntimeLibrary and MT_StaticRelease mismatch + + Only `x64` is supported, Choose `x64 Native Tools Command Prompt for VS`. + ## Contributing + * Professor: [Dr. Chen](https://zhigang-chen.github.io/) * [Contributors](https://github.com/Huelse/SEAL-Python/graphs/contributors) From 4aa020b48d8ce1a305d7e74e45f49b01c7059a41 Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 17:50:09 +0800 Subject: [PATCH 12/18] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 100c225..5d61a28 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ This is a python binding for the Microsoft SEAL library. load_cipher.load(context, 'cipher') # work if the context is valid. ``` - Supported classes: `Encryptionparams, Ciphertext, Plaintext, SecretKey, Publickey, Relinkeys, Galoiskeys` + Supported classes: `EncryptionParameters, Ciphertext, Plaintext, SecretKey, PublicKey, RelinKeys, GaloisKeys` * ### Other From 98b4db5ea92973cfa3416b3b581828fc8650ed94 Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 18:45:46 +0800 Subject: [PATCH 13/18] Remove return_value_policy --- src/wrapper.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/wrapper.cpp b/src/wrapper.cpp index 89383f1..45322d3 100644 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -144,8 +144,8 @@ PYBIND11_MODULE(seal, m) .def("nonzero_coeff_count", &Plaintext::nonzero_coeff_count) .def("to_string", &Plaintext::to_string) .def("is_ntt_form", &Plaintext::is_ntt_form) - .def("parms_id", py::overload_cast<>(&Plaintext::parms_id, py::const_), py::return_value_policy::reference) - .def("scale", py::overload_cast<>(&Plaintext::scale, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&Plaintext::parms_id, py::const_)) + .def("scale", py::overload_cast<>(&Plaintext::scale, py::const_)) .def("scale", [](Plaintext &plain, double scale){ plain.scale() = scale; }) @@ -176,8 +176,8 @@ PYBIND11_MODULE(seal, m) .def("size_capacity", &Ciphertext::size_capacity) .def("is_transparent", &Ciphertext::is_transparent) .def("is_ntt_form", py::overload_cast<>(&Ciphertext::is_ntt_form, py::const_)) - .def("parms_id", py::overload_cast<>(&Ciphertext::parms_id, py::const_), py::return_value_policy::reference) - .def("scale", py::overload_cast<>(&Ciphertext::scale, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&Ciphertext::parms_id, py::const_)) + .def("scale", py::overload_cast<>(&Ciphertext::scale, py::const_)) .def("scale", [](Ciphertext &cipher, double scale){ cipher.scale() = scale; }) @@ -199,7 +199,7 @@ PYBIND11_MODULE(seal, m) py::class_<SecretKey>(m, "SecretKey") .def(py::init<>()) .def(py::init<const SecretKey &>()) - .def("parms_id", py::overload_cast<>(&SecretKey::parms_id, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&SecretKey::parms_id, py::const_)) .def("save", [](const SecretKey &sk, const std::string &path){ std::ofstream out(path, std::ofstream::binary); sk.save(out); @@ -215,7 +215,7 @@ PYBIND11_MODULE(seal, m) py::class_<PublicKey>(m, "PublicKey") .def(py::init<>()) .def(py::init<const PublicKey &>()) - .def("parms_id", py::overload_cast<>(&PublicKey::parms_id, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&PublicKey::parms_id, py::const_)) .def("save", [](const PublicKey &pk, const std::string &path){ std::ofstream out(path, std::ofstream::binary); pk.save(out); @@ -232,7 +232,7 @@ PYBIND11_MODULE(seal, m) .def(py::init<>()) .def(py::init<const KSwitchKeys &>()) .def("size", &KSwitchKeys::size) - .def("parms_id", py::overload_cast<>(&KSwitchKeys::parms_id, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&KSwitchKeys::parms_id, py::const_)) .def("save", [](const KSwitchKeys &ksk, const std::string &path){ std::ofstream out(path, std::ofstream::binary); ksk.save(out); @@ -249,7 +249,7 @@ PYBIND11_MODULE(seal, m) .def(py::init<>()) .def(py::init<const RelinKeys::KSwitchKeys &>()) .def("size", &RelinKeys::KSwitchKeys::size) - .def("parms_id", py::overload_cast<>(&RelinKeys::KSwitchKeys::parms_id, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&RelinKeys::KSwitchKeys::parms_id, py::const_)) .def_static("get_index", &RelinKeys::get_index) .def("has_key", &RelinKeys::has_key) .def("save", [](const RelinKeys &rk, const std::string &path){ @@ -268,7 +268,7 @@ PYBIND11_MODULE(seal, m) .def(py::init<>()) .def(py::init<const GaloisKeys::KSwitchKeys &>()) .def("size", &GaloisKeys::KSwitchKeys::size) - .def("parms_id", py::overload_cast<>(&GaloisKeys::KSwitchKeys::parms_id, py::const_), py::return_value_policy::reference) + .def("parms_id", py::overload_cast<>(&GaloisKeys::KSwitchKeys::parms_id, py::const_)) .def_static("get_index", &GaloisKeys::get_index) .def("has_key", &GaloisKeys::has_key) .def("save", [](const GaloisKeys &gk, const std::string &path){ @@ -286,7 +286,7 @@ PYBIND11_MODULE(seal, m) py::class_<KeyGenerator>(m, "KeyGenerator") .def(py::init<const SEALContext &>()) .def(py::init<const SEALContext &, const SecretKey &>()) - .def("secret_key", &KeyGenerator::secret_key, py::return_value_policy::reference) + .def("secret_key", &KeyGenerator::secret_key) .def("create_public_key", py::overload_cast<PublicKey &>(&KeyGenerator::create_public_key, py::const_)) .def("create_relin_keys", py::overload_cast<RelinKeys &>(&KeyGenerator::create_relin_keys)) .def("create_galois_keys", py::overload_cast<const std::vector<int> &, GaloisKeys &>(&KeyGenerator::create_galois_keys)) From 6338e4398207d711e333e633ac752f1ce88928da Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 19:18:16 +0800 Subject: [PATCH 14/18] New setup --- pyproject.toml | 9 +++++++++ setup.py | 54 ++++++++++++++++++++++++------------------------- src/wrapper.cpp | 3 ++- 3 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1508fa9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ + +[build-system] +requires = [ + "setuptools>=42", + "wheel", + "pybind11>=2.9.1", +] + +build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index be1a9e1..c8e5313 100644 --- a/setup.py +++ b/setup.py @@ -1,46 +1,46 @@ import os import platform -from setuptools import setup, Extension +from glob import glob +from setuptools import setup from distutils.sysconfig import get_python_inc +from pybind11.setup_helpers import Pybind11Extension, build_ext +__version__ = "4.0.0" -# python include dir -py_include_dir = os.path.join(get_python_inc()) -# cpp flags -cpp_args = ['-std=c++17'] -# include directories -include_dirs = [py_include_dir, './pybind11/include', './SEAL/native/src', './SEAL/build/native/src'] -# library path -extra_objects = ['./SEAL/build/lib/libseal-4.0.a'] -# available wrapper: src/wrapper.cpp, src/wrapper_with_pickle.cpp -wrapper_file = 'src/wrapper.cpp' +include_dirs = [get_python_inc(), 'pybind11/include', 'SEAL/native/src', 'SEAL/build/native/src'] -if platform.system() == "Windows": - cpp_args[0] = '/std:c++latest' # /std:c++1z - extra_objects[0] = './SEAL/build/lib/seal-4.0.lib' +extra_objects = sorted(glob('SEAL/build/lib/*.lib') if platform.system() == "Windows" else glob('SEAL/build/lib/*.a')) -if not os.path.exists(extra_objects[0]): - print('Not found the seal lib file') +cpp_args = ['/std:c++latest'] if platform.system() == "Windows" else ['-std=c++17'] + +if len(extra_objects) < 1 or not os.path.exists(extra_objects[0]): + print('Not found the seal lib file, check the `SEAL/build/lib`') exit(0) +elif len(extra_objects) > 1: + print('Exists unknown extra objects, may cause exception') ext_modules = [ - Extension( - name='seal', - sources=[wrapper_file], + Pybind11Extension( + "seal", + sorted(glob('src/*.cpp')), include_dirs=include_dirs, - language='c++', extra_compile_args=cpp_args, extra_objects=extra_objects, + define_macros = [('VERSION_INFO', __version__)], ), ] setup( - name='seal', - version='4.0', - author='Huelse', - author_email='huelse@oini.top', - description='Python wrapper for the Microsoft SEAL', - url='https://github.com/Huelse/SEAL-Python', - license='MIT', + name="seal", + version=__version__, + author="Huelse", + author_email="topmaxz@protonmail.com", + url="https://github.com/Huelse/SEAL-Python", + description="Python wrapper for the Microsoft SEAL", + long_description="", ext_modules=ext_modules, + cmdclass={"build_ext": build_ext}, + zip_safe=False, + license='MIT', + python_requires=">=3.6", ) diff --git a/src/wrapper.cpp b/src/wrapper.cpp index 45322d3..c3671a1 100644 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -13,7 +13,8 @@ PYBIND11_MAKE_OPAQUE(std::vector<std::int64_t>); PYBIND11_MODULE(seal, m) { - m.doc() = "Microsoft SEAL (4.0) for Python, from https://github.com/Huelse/SEAL-Python"; + m.doc() = "Microsoft SEAL for Python, from https://github.com/Huelse/SEAL-Python"; + m.attr("__version__") = "4.0.0"; py::bind_vector<std::vector<double>>(m, "VectorDouble", py::buffer_protocol()); py::bind_vector<std::vector<std::int64_t>>(m, "VectorInt", py::buffer_protocol()); From 72834af934789581d69f8ca62239e0a6b6691f2c Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 19:33:56 +0800 Subject: [PATCH 15/18] Improve README --- README.md | 25 +++++++++++++++++-------- setup.py | 2 -- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5d61a28..1d12779 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ This is a python binding for the Microsoft SEAL library. git clone https://github.com/Huelse/SEAL-Python.git cd SEAL-Python - # Numpy is essential - pip3 install -r requirements.txt + # Install dependencies + pip3 install -r numpy pybind11 # Init the SEAL and pybind11 git submodule update --init --recursive @@ -42,28 +42,37 @@ This is a python binding for the Microsoft SEAL library. # Build the SEAL lib cd SEAL - cmake -S . -B build -DSEAL_USE_MSGSL=OFF -DSEAL_USE_ZLIB=OFF -DSEAL_USE_ZSTD=OFF + cmake -S . -B build -DSEAL_USE_MSGSL=OFF -DSEAL_USE_ZLIB=OFF cmake --build build cd .. # Run the setup.py python3 setup.py build_ext -i + + # Test + cp seal.*.so examples + python3 4_bgv_basics.py ``` - Build examples (add after `cmake -S . -B`): `-DSEAL_BUILD_EXAMPLES=ON` and [more cmake options](https://github.com/microsoft/SEAL#basic-cmake-options) + Build examples (after `cmake -S . -B`): `-DSEAL_BUILD_EXAMPLES=ON` + + Zstandard compression off: `-DSEAL_USE_ZSTD=OFF` + + [More cmake options](https://github.com/microsoft/SEAL#basic-cmake-options) * ### Windows - Visual Studio 2019 or newer is required. And use the **x64 Native Tools Command Prompt for Visual Studio 2019** command prompt to configure and build the Microsoft SEAL library. It's usually can be found in your Start Menu. + Visual Studio 2019 or newer is required. And use the **x64 Native Tools Command Prompt for VS** command prompt to configure and build the Microsoft SEAL library. It's usually can be found in your Start Menu. ```shell # Same as above - # Build the SEAL library - cmake -S . -B build -G Ninja -DSEAL_USE_MSGSL=OFF -DSEAL_USE_ZLIB=OFF -DSEAL_USE_ZSTD=OFF + # Run in "x64 Native Tools Command Prompt for VS" command prompt + cmake -S . -B build -G Ninja -DSEAL_USE_MSGSL=OFF -DSEAL_USE_ZLIB=OFF cmake --build build - # Run the setup.py + pip install numpy pybind11 + python setup.py build_ext -i ``` diff --git a/setup.py b/setup.py index c8e5313..0147f31 100644 --- a/setup.py +++ b/setup.py @@ -16,8 +16,6 @@ if len(extra_objects) < 1 or not os.path.exists(extra_objects[0]): print('Not found the seal lib file, check the `SEAL/build/lib`') exit(0) -elif len(extra_objects) > 1: - print('Exists unknown extra objects, may cause exception') ext_modules = [ Pybind11Extension( From 7b80e0da340d98028c9b4dc0d46d3848245aee68 Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 19:39:38 +0800 Subject: [PATCH 16/18] Simplify the doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d12779..b8cc5c8 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ This is a python binding for the Microsoft SEAL library. python setup.py build_ext -i ``` - In general, the Ninja generator is better than the "Visual Studio 16 2019" generator, and there is more information in the Microsoft SEAL official [docs](https://github.com/microsoft/SEAL#building-microsoft-seal-manually). + Microsoft SEAL official [docs](https://github.com/microsoft/SEAL#building-microsoft-seal-manually). * ### Docker From 55af9a2b40bf7549b38fc44cf07b9893aaa07f4f Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 20:12:33 +0800 Subject: [PATCH 17/18] Remove spaces --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b8cc5c8..95b5a6e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ This is a python binding for the Microsoft SEAL library. cd SEAL-Python # Install dependencies - pip3 install -r numpy pybind11 + pip3 install numpy pybind11 # Init the SEAL and pybind11 git submodule update --init --recursive @@ -42,7 +42,7 @@ This is a python binding for the Microsoft SEAL library. # Build the SEAL lib cd SEAL - cmake -S . -B build -DSEAL_USE_MSGSL=OFF -DSEAL_USE_ZLIB=OFF + cmake -S . -B build -DSEAL_USE_MSGSL=OFF -DSEAL_USE_ZLIB=OFF cmake --build build cd .. @@ -50,7 +50,7 @@ This is a python binding for the Microsoft SEAL library. python3 setup.py build_ext -i # Test - cp seal.*.so examples + cp seal.*.so examples python3 4_bgv_basics.py ``` From ddba3ed1603ffa1c6f8e820061803bf2549fbc11 Mon Sep 17 00:00:00 2001 From: huelse <huelse@qq.com> Date: Tue, 5 Apr 2022 20:12:41 +0800 Subject: [PATCH 18/18] Delete requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 296d654..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -numpy \ No newline at end of file