Skip to content
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

Upstream 최신 버전 당겨오기 #8

Merged
merged 4 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ seal.egg-info
*.pyd
*.pyc
temp
env
.idea
*.bin
2 changes: 2 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[submodule "SEAL"]
path = SEAL
url = https://github.com/microsoft/SEAL.git
branch = main
[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