Summary: In this post we showcase a new tensor type that leverages the CKKS homomorphic encryption scheme implemented on the SEAL Microsoft library to evaluate tensor operations on encrypted data.

## Why Homomorphic Encryption in Machine Learning?

Before diving into how to use this tensor, I would like to highlight the main use-case where homomorphic encryption (HE) has shown to be practical enough.

Evaluating models on encrypted data: As companies continues to develop machine learning models for different tasks, these models can sometimes be a key asset and can't be shared publicly for different reasons, on the other end, the user wants to use these models without exposing his data. HE lets the user encrypts his data in a way that it can be computed on as if we were computing on plain data, thus he can send his encrypted data to the model owner who can evaluate his model on this encrypted data, and return an encrypted result to the user, who can later decrypts it.

OpenMined has started to work on TenSEAL which is a library for doing homomorphic encryption operations on tensors, so that implementing such use-case is possible. TenSEAL is a result of contributors efforts at extending the SEAL Microsoft library to tensor operations, and wrap this all together to add more HE capabilities to PySyft. From the side of PySyft, you will only see torch tensors that you are already familiar with, but which implements either the CKKS or BFV schemes.

Next we will look at the new tensor type, the CKKSTensor, and show how to use it in PySyft.

## CKKSTensor

The CKKS HE scheme is best suited for machine learning applications, it supports addition and multiplication on encrypted real numbers but yield approximate results, which should be fine for such use-case. Let's now go through a code example showing how to use the CKKSTensor which basically uses SEAL's implementation of the CKKS scheme to encrypt, evaluate and decrypt tensors.

#### Imports and Context Creation

import syft as sy
import torch as th
import syft.frameworks.tenseal as ts

# hook PyTorch to add extra functionalities like the ability to encrypt torch tensors
hook = sy.TorchHook(th)

# Generate CKKS public and secret keys
public_keys, secret_key = ts.generate_ckks_keys()


We are now all set to start encrypting and evaluating tensors.

Note: public_keys is actually a TenSEALContext object, a special object in TenSEAL that can hold multiple keys other than the public-key, namely the relinearization and galois keys which are public as well and serve other purposes than encrypting tensors, only the secret-key can be used to decrypt tensors.

#### Encrypting Tensors

Let's first create a random matrix.

matrix = th.tensor([[10.5, 73, 65.2], [13.33, 22, 81]])


Now we encrypt the matrix by specifying the encryption scheme as well as the public-key

matrix_encrypted = matrix.encrypt("ckks", public_key=public_keys)


#### Evaluation

We can add, sub and mul encrypted tensors with both encrypted and plain torch tensors, no need for extra tools to do this, just normal torch operations.

# to use for plain evaluations
t_eval = th.tensor([[1, 2.5, 4], [13, 7, 16]])
# to use for encrypted evaluations
t_encrypted = t_eval.encrypt("ckks", public_key=public_keys)

print("encrypted tensor + plain tensor")
result = matrix_encrypted + t_eval
# result is an encrypted tensor
print(result.decrypt(secret_key=secret_key))

print("encrypted tensor + encrypted tensor")
result = matrix_encrypted + t_encrypted
# result is an encrypted tensor
print(result.decrypt(secret_key=secret_key))

print("encrypted tensor - plain tensor")
result = matrix_encrypted - t_eval
# result is an encrypted tensor
print(result.decrypt(secret_key=secret_key))

print("encrypted tensor - encrypted tensor")
result = matrix_encrypted - t_encrypted
# result is an encrypted tensor
print(result.decrypt(secret_key=secret_key))

print("encrypted tensor * plain tensor")
result = matrix_encrypted * t_eval
# result is an encrypted tensor
print(result.decrypt(secret_key=secret_key))

print("encrypted tensor * encrypted tensor")
result = matrix_encrypted * t_encrypted
# result is an encrypted tensor
print(result.decrypt(secret_key=secret_key))


You can go further and try other tensor shapes.

## Conclusion and Future Work

This is the first step towards doing machine learning on HE encrypted data. Further steps in this project would aim at supporting more tensor operations including dot-product, matrix multiplication and convolution, thus providing the ability to evaluate neural networks on encrypted data.

If you enjoyed this and would like to join the movement toward privacy preserving, decentralized ownership of AI and the AI supply chain (data), you can do so in the following ways!

#### Star PySyft and TenSEAL on Github

The easiest way to help our community is just by starring the repositories! This helps raise awareness of the cool tools we're building.

#### Join the Crypto Team

If you're already a contributor to PySyft, and if you're interested to work on crypto related use cases, you should definitely join us!

#### Pick our tutorials on GitHub!

We made really nice tutorials to get a better understanding of what Federated and Privacy-Preserving Learning should look like and how we are building the bricks for this to happen.