Skip to content

Updating SEAL-Python to v4.0.0 #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
405327e
Merge pull request #78 from Desilo/daesan/v3.7.1
Huelse Jan 25, 2022
f5dfd92
Fix seal lib path in windows
Huelse Mar 2, 2022
9da15c7
Remove useless sign
Huelse Mar 2, 2022
f288ba6
Improve README
Huelse Mar 2, 2022
9f6e1ca
Upgrade to SEAL-3.7.2 and the latest pybind11
Huelse Mar 2, 2022
5510656
Fix SEAL as submodules
Huelse Mar 2, 2022
1f6c9d9
Change version
Huelse Mar 2, 2022
48283bf
Tab to space
Huelse Mar 2, 2022
c8f0afb
Format tab to space
Huelse Mar 2, 2022
c6f5ead
Change version and format
Huelse Mar 5, 2022
453f62f
Fit in SEAL 3.7
Huelse Mar 5, 2022
6edabf6
Switch to SEAL 4.0.0
Huelse Mar 27, 2022
003a913
Switch to SEAL 4.0
Huelse Mar 28, 2022
8863a75
Rewrite CoeffModulus.Create
Huelse Mar 28, 2022
94d9ecd
Fix semicolon
Huelse Mar 28, 2022
2563d7a
Add scheme_type bgv and remove base64 tentatively
Huelse Apr 1, 2022
c7d1ebb
Add 4_bgv_basics.py
Huelse Apr 3, 2022
efb75d1
Complete bgv basic example
Huelse Apr 3, 2022
9a6f035
Improve setup.py
Huelse Apr 4, 2022
35a3845
Remove unsupported files
Huelse Apr 5, 2022
e370593
Improve words and details
Huelse Apr 5, 2022
fc48ea5
Format and add recommend versions
Huelse Apr 5, 2022
4aa020b
Fix typo
Huelse Apr 5, 2022
98b4db5
Remove return_value_policy
Huelse Apr 5, 2022
6338e43
New setup
Huelse Apr 5, 2022
72834af
Improve README
Huelse Apr 5, 2022
7b80e0d
Simplify the doc
Huelse Apr 5, 2022
55af9a2
Remove spaces
Huelse Apr 5, 2022
ddba3ed
Delete requirements.txt
Huelse Apr 5, 2022
2248348
Merge pull request #85 from Huelse/4.0.0
Huelse Apr 5, 2022
e9390a3
Merge pull request #88 from Huelse/main
Huelse May 3, 2022
2e7bab0
Add to_string in Ciphertext and from_string in context
Huelse May 3, 2022
d2953c2
Add more main data class from string methods
Huelse May 3, 2022
91e61dd
Add to string api to the main data class
Huelse May 4, 2022
629c467
Use `std::ios::binary` instead
Huelse May 4, 2022
7e5f990
Add some details
Huelse May 4, 2022
9308aab
Merge pull request #89 from Huelse/pickle_opt
Huelse May 4, 2022
ac10d29
Improve details
Huelse May 4, 2022
0d4f259
New serialization example
Huelse May 5, 2022
85787b9
Improve README.md
Huelse May 5, 2022
8aee24b
Merge pull request #90 from Huelse/pickle_opt
Huelse May 5, 2022
8841ef0
Merge pull request #91 from Huelse/main
Huelse May 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitattributes

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ build
*.pyd
*.pyc
temp
.idea
*.bin
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
[submodule "pybind11"]
path = pybind11
url = https://github.com/pybind/pybind11.git
branch = stable
92 changes: 47 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ This is a python binding for the Microsoft SEAL library.


## Build
* #### Linux
Clang++ (>= 5.0) or GNU G++ (>= 6.0), CMake (>= 3.12)

* ### Linux

Recommend: Clang++ (>= 10.0) or GNU G++ (>= 9.4), CMake (>= 3.16)

```shell
# Optional
Expand All @@ -30,42 +32,60 @@ 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 numpy pybind11

# Init the SEAL and pybind11
git submodule update --init --recursive
# Get the newest repositories (unnecessary)
# Get the newest repositories (dev only)
# git submodule update --remote

# 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
cd examples
python3 4_bgv_basics.py
```

* #### Windows
Build examples (after `cmake -S . -B`): `-DSEAL_BUILD_EXAMPLES=ON`

Zstandard compression off: `-DSEAL_USE_ZSTD=OFF`

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.
[More cmake options](https://github.com/microsoft/SEAL#basic-cmake-options)


* ### Windows

Visual Studio 2019 or newer is required. x64 support only! 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
# Build
pip install numpy pybind11
python setup.py build_ext -i

# Test
cp seal.*.pyd examples
cd examples
python 4_bgv_basics.py
```

Generally, 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).
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):
Expand All @@ -78,51 +98,28 @@ 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:
See more in `examples/7_serialization.py`, here is a simple example:

```python
cipher.save('cipher')

load_cipher = Ciphertext()
load_cipher.load(context, 'cipher') # work if the context is valid.
```

Support type: `Encryptionparams, Ciphertext, Plaintext, SecretKey, Publickey, Relinkeys, Galoiskeys`
Supported classes: `EncryptionParameters, Ciphertext, Plaintext, SecretKey, PublicKey, RelinKeys, GaloisKeys`

Particularly, if you want to use the pickle to serialize your data, you need to do these things like below:

```shell
# 1. Modify the serializable object's header file in SEAL and switch the wrapper.
python helper.py
* ### Other

# 2. Rebuild the SEAL lib like above
cmake --build build
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).

# 3. Run the setup.py
python setup.py build_ext -i
```

Then, you can pickle the data object like this:

```python
import pickle

cipher.set_parms(parms) # necessary
cipher_dump = pickle.dumps(cipher)
cipher_load = pickle.loads(cipher_dump)
```

Generally, we don't use compression library.

* #### 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.

Email: [[email protected]](mailto:[email protected]?subject=Github-SEAL-Python-Issues)
Email: [[email protected]](mailto:[email protected]?subject=Github-SEAL-Python-Issues)



Expand All @@ -148,9 +145,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)
2 changes: 1 addition & 1 deletion SEAL
Submodule SEAL updated 128 files
113 changes: 113 additions & 0 deletions examples/4_bgv_basics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
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
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)

keygen = KeyGenerator(context)
secret_key = keygen.secret_key()
public_key = keygen.create_public_key()
relin_keys = keygen.create_relin_keys()

encryptor = Encryptor(context, public_key)
evaluator = Evaluator(context)
decryptor = Decryptor(context, secret_key)

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)}')
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)

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__":
example_bgv_basics()
73 changes: 73 additions & 0 deletions examples/7_serialization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from seal import *
import pickle
import time


def get_seal():
parms = EncryptionParameters(scheme_type.ckks)
poly_modulus_degree = 8192
parms.set_poly_modulus_degree(poly_modulus_degree)
parms.set_coeff_modulus(CoeffModulus.Create(poly_modulus_degree, [60, 40, 40, 60]))
scale = 2.0 ** 40

context = SEALContext(parms)
ckks_encoder = CKKSEncoder(context)
slot_count = ckks_encoder.slot_count()

keygen = KeyGenerator(context)
public_key = keygen.create_public_key()
secret_key = keygen.secret_key()

encryptor = Encryptor(context, public_key)
# evaluator = Evaluator(context)
decryptor = Decryptor(context, secret_key)

data = [3.1415926] * slot_count
plain = ckks_encoder.encode(data, scale)
cipher = encryptor.encrypt(plain)

return cipher, context, ckks_encoder, decryptor


def serialization_example():
print('serialization example')
print('-' * 70)
cipher2, context2, ckks_encoder2, decryptor2 = get_seal()
cipher2.save('cipher2.bin')
print('save cipher2 data success')

time.sleep(.5)

cipher3 = Ciphertext()
cipher3.load(context2, 'cipher2.bin')
print('load cipher2 data success')
plain3 = decryptor2.decrypt(cipher3)
data3 = ckks_encoder2.decode(plain3)
print(data3)
print('-' * 70)


def pickle_example():
print('pickle example')
print('-' * 70)
cipher1, context1, ckks_encoder1, decryptor1 = get_seal()
with open('cipher1.bin', 'wb') as f:
pickle.dump(cipher1.to_string(), f)
print('write cipher1 data success')

time.sleep(.5)

with open('cipher1.bin', 'rb') as f:
temp = pickle.load(f)
cipher2 = context1.from_cipher_str(temp)
plain2 = decryptor1.decrypt(cipher2)
data = ckks_encoder1.decode(plain2)
print('read cipher1 data success')
print(data)

print('-' * 70)


if __name__ == "__main__":
serialization_example()
pickle_example()
Loading