❗ This library has been deprecated due to changes in strategy and roadmap. To actively contribute based on our current roadmap, checkout OpenMined, PySyft, or join our slack
A Python implementation of the homomorphic encryption scheme by Yoshinori Aono et al.
This scheme was first introduced in the paper - "Fast and Secure Linear Regression and Biometric Authentication with Security Update" by Yoshinori Aono et al. A really unique feature supported by this proposal is the support for key switching. All the code is written in PARI library in C++.
This code also has an independent header containing a PARI implementation of the Knuth-Yao's Algorithm for sampling from a discrete Gaussian distribution. The paper followed for understanding and implementing the algorithm - High Precision Discrete Gaussian Sampling on FPGAs.
NOTE : Running the homomorphic multiplication gives a matrix as opposed to the message being . This is because after homomorphic multiplication, we don't get message but we get .
-
Install Docker
- If you're on macOS and use Homebrew, run
brew cask install docker; open -a docker
- If you're on macOS and use Homebrew, run
-
Run these commands:
make build
make run
-
Install Docker
- If you're on macOS and use Homebrew, run
brew cask install docker; open -a docker
- If you're on macOS and use Homebrew, run
-
Run
make build
-
Edit source code as you wish
-
Run
make dev
We just rolled out the support for key switching/rotation. Check it out by running init_key_switching.py
. You can also run init.py
to check out homomorphic operations working.
This scheme has an advantage
over other schemes that the key switching can both, increase as well as decrease the security level of the ciphertext!
New here? Check out our sample tutorial on YouTube recorded by Mayank. The tutorial covers a basic overview of how to use the API. More in-depth tutorials coming soon. Keep checking out YouTube channel and our GitHub repositories.
Welcome! If you are intrigued by our work and want to contribute, then please go through the tutorial as mentioned in the News
section and contact any of the contributors. You should also go through this introductory video by Andrew Trask, of the OpenMined platform.
Key Rotation
means that we change ciphertext associated with the key-pair (pk1, sk1)
, where pk1
is used to encrypt the message and sk1
is used to decrypt to message to another ciphertext associated with keypair (pk2, sk2)
, without decrypting the first ciphertext.
We specifically call it Key Rotation
when the parameters have this relation n1 = n2
.
We call it Security Update
if the paramters have this relation n1 < n2
, meaning that the security of new ciphertext has been updated and increased.
The following cases of operations have been implemented. Support for other cases might require some more literature reading and will follow shortly. Please take a look at he following options which are presently supported:
The scheme only supports ONE
homomorphic multiplication at the moment.
normal-ciphertext
means a ciphertext which has never been refreshed via either key rotation or security update and has only been operated additively or has never undergone any operation is just fresh.mult-ciphertext
means a ciphertext which has undergoneONE
multiplication no matter if it has undergone key rotation or security update before or not. Note that amult-ciphertext
CANNOT
be rotated or refreshed by key rotation or security update because of it's peculiar structure. It has to be decrypted.rotated-ciphertext
means a ciphertext which has undergone refreshment via either key rotation or security update.
If +
is supported it implies -
is permitted as well.
normal-ciphertext + normal-ciphertext = normal-ciphertext
andnormal-ciphertext * normal-ciphertext = mult-ciphertext
mult-ciphertext + mult-ciphertext = mult-ciphertext
rotated-ciphertext + rotated-ciphertext = rotated-ciphertext
androtated-ciphertext * rotated-ciphertext = mult-ciphertext
rotated-ciphertext + normal-ciphertext = rotated-ciphertext
androtated-ciphertext * normal-ciphertext = mult-ciphertext
normal-ciphertext + rotated-ciphertext = rotated-ciphertext
andnormal-ciphertext * rotated-ciphertext = mult-ciphertext
mult-ciphertext + normal-ciphertext = mult-ciphertext
andnormal-ciphertext + mult-ciphertext = mult-ciphertext
[?]mult-ciphertext + rotated-ciphertext = mult-ciphertext
androtated-ciphertext + mult-ciphertext = mult-ciphertext
[?]
The above bullets marked with [?] means that these operations don't exist conventionally in the actual paper. I have implemented them as my own decision given they might come in handy during the course of our project. I implemented them in this way (illustrating just one example, rest are similar to this one):
mult-ciphertext + (normal-ciphertext-of-1s * normal-ciphertext) = mult-ciphertext
normal-ciphertext-of-1s
mean that it is a ciphertext which is deliberately made my encrypting a vector of just all 1s, so that if it is multiplied with anything (say x
), this x
remains same, but since x
is of type - normal-ciphertext
and also this normal-ciphertext-of-1s
is also of the type - normal-ciphertext
, this means their homomorphic multiplication *
will yield a ciphertext encrypting x
of the type - mult-ciphertext
. This makes the whole above homomorphic addition as mult-ciphertext + mult-ciphertext = mult-ciphertext
.
The API can be imported using the command import Aono
. It currently supports the following functions and classes:
pari_init()
is the function that needs to be called before dealing with this API. pari_size
defines the size of stack we'll be using, and max_prime
defines the pre computed prime table.
pari_close()
function has to be called at the end of each program to clear the memory used.
This class abstracts the GEN variable in C++, making it available through python interface. The class is compatible with +, *, /, -, __getitem__ , %, and print.
-
Class Data:
value
(GEN
)
-
__init__(self, x)
The constructor converts x to a GEN variable. Arguments:x
(int
)
- Class Data:
n
,s
,sigma
,l
,lambda
(ints
)q
,p
(pari_GEN
)
-
Class Data:
sk
(pari_GEN
)params
(parameters*
)
-
__init__(self, sk = None, parmas = None)
The constructor initiates class data. Arguments:sk
(pari_GEN
),params
(parameters*
) -
decrypt(self, ct)
decrypt()
method returns the plaintext (pari_GEN
) encrypted in ciphertextct
. Arguments:ct
(pari_GEN
) -
serialize(self)
TO BE IMPLEMENTED
-
Class Data:
pk
(public_key_pack*
)params
(parameters*
)g
(globalvars*
)
-
__init__(self, pk = None, params = None, g = None)
The constructor initiates the class data. Arguments:pk
(public_key_pack*
),params
(parameters*
),g
(globalvars*
) -
encrypt(self, pt)
encrypt()
method returns the ciphertext (GEN
) which encrypts plaintextpt
. Arguments:pt
(pari_GEN
) -
serialize(self)
TO BE IMPLEMENTED
- Class Data:
sk
(secret_key
)pk
(public_key
)
-
generate_key(self, lambda, l, n, s, sigma, degree_p)
generate_key()
method returns the keys, which is of typekey_pair
. Heres
defines the tailprune anddegree_p
defines thebit_size
ofp
to be generated. Arguments:lambda
(int
),l
(int
),n
(int
),s
(int
),sigma
(int
),degree_p
(int
). -
deserialize(self)
TO BE IMPLEMENTED
The class is compatible with `’+’, '*', and '-' operators`
-
Class Data:
value
(pari_GEN
)pk
(public_key*
)params
(parameters*
)
-
__init__(self, plaintext = None, pk, params)
The constuctor method takes two arguments:plaintext
(pari_GEN
variable),pk
(public_key*
),params
(parameters*
)
TODO - Remove params
, it can be taken from pk
.
decrypt(self, sk)
decrypt()
method returns the decryptedciphertext
which ispari_GEN
variable. Arguments:sk
(secret_key*
)
-
Class Data:
pk
(public_key_pack*
)params
(parameters*
)old_params
(parameters*
)g
(globalvars*
)XComponent
(pari_GEN
)YComponent
(pari_GEN
)
-
__init__(self, X, Y, params, params_old, g, pk)
The constructor initiates the class data. Arguments:pk
(public_key_pack*
),params
(parameters*
),g
(globalvars*
) -
cipher_switch(self, ciphertext)
cipher_switch()
method returns the ciphertext (ciphertext
) which is obtained by switching the ciphertext passed to function with the updatation key. Arguments:ct
(ciphertext
)
generate_key(self, key_pair*, key_pair*)
generate_key()
method returns the updation key (updation_key
) which is the key that can be used to switch any ciphertext which is associated with the first (in order of arguments)key_pair
to the ciphertext which is associated with the secondkey_pair
. Arguments:key1
(key_pair
),key2
(key_pair
)
- Tweaks to homomorphic functions to support rotated or updated ciphertexts.
- Support for plaintext-ciphertext multiplication.
- Basic testing suite.
- Taking care of negative errors by mapping ciphertext to a symmteric group before decryption.
- Add a matrix reading support to testing suite.
- Add key switching tests to testing suite.
- Update README with pari_GEN.
- Add bootstrapping support.
- Serialization and Deserialization support.