lightphe 0.0.18__tar.gz → 0.0.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {lightphe-0.0.18 → lightphe-0.0.20}/PKG-INFO +11 -6
  2. {lightphe-0.0.18 → lightphe-0.0.20}/README.md +10 -5
  3. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/__init__.py +23 -5
  4. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/Benaloh.py +5 -1
  5. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/GoldwasserMicali.py +10 -2
  6. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/NaccacheStern.py +5 -1
  7. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/RSA.py +41 -25
  8. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/PKG-INFO +11 -6
  9. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/requires.txt +0 -1
  10. lightphe-0.0.20/requirements.txt +3 -0
  11. {lightphe-0.0.18 → lightphe-0.0.20}/setup.py +1 -1
  12. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_large_keys.py +5 -4
  13. lightphe-0.0.18/requirements.txt +0 -4
  14. {lightphe-0.0.18 → lightphe-0.0.20}/LICENSE +0 -0
  15. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/commons/__init__.py +0 -0
  16. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/commons/logger.py +0 -0
  17. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/commons/phe_utils.py +0 -0
  18. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/DamgardJurik.py +0 -0
  19. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/ElGamal.py +0 -0
  20. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/EllipticCurveElGamal.py +0 -0
  21. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
  22. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/Paillier.py +0 -0
  23. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/__init__.py +0 -0
  24. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Algorithm.py +0 -0
  25. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Ciphertext.py +0 -0
  26. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Homomorphic.py +0 -0
  27. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Tensor.py +0 -0
  28. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/__init__.py +0 -0
  29. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/SOURCES.txt +0 -0
  30. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/dependency_links.txt +0 -0
  31. {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/top_level.txt +0 -0
  32. {lightphe-0.0.18 → lightphe-0.0.20}/setup.cfg +0 -0
  33. {lightphe-0.0.18 → lightphe-0.0.20}/tests/__init__.py +0 -0
  34. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_benaloh.py +0 -0
  35. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_ciphertexts.py +0 -0
  36. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_cloud.py +0 -0
  37. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_damgard.py +0 -0
  38. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_elgamal.py +0 -0
  39. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_ellipticcurveelgamal.py +0 -0
  40. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_exporting_keys.py +0 -0
  41. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_goldwasser.py +0 -0
  42. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_keys.py +0 -0
  43. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_naccache.py +0 -0
  44. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_okamoto.py +0 -0
  45. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_paillier.py +0 -0
  46. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_rsa.py +0 -0
  47. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_salary.py +0 -0
  48. {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_tensors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.18
3
+ Version: 0.0.20
4
4
  Summary: A Lightweight Partially Homomorphic Encryption Library for Python
5
5
  Home-page: https://github.com/serengil/LightPHE
6
6
  Author: Sefik Ilkin Serengil
@@ -129,7 +129,7 @@ assert cs.decrypt(c3) == m1 + m2
129
129
  assert cs.decrypt(c4) == k * m1
130
130
  ```
131
131
 
132
- On the other hand, if you adopt a multiplicatively homomorphic cryptosyste (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
132
+ On the other hand, if you adopt a multiplicatively homomorphic cryptosystem (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
133
133
 
134
134
  ```python
135
135
  # build a multiplicatively homomorphic cryptosystem
@@ -152,7 +152,7 @@ assert cs.decrypt(c3) == m1 * m2
152
152
 
153
153
  ### Ciphertext Regeneration
154
154
 
155
- Similar to the most of additively homomorphic algorithms, Paillier lets you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
155
+ The most of additively homomorphic algorithms allow you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
156
156
 
157
157
  ```python
158
158
  c1_prime = cs.regenerate_ciphertext(c1)
@@ -163,7 +163,7 @@ assert cs.decrypt(c1) == m1
163
163
 
164
164
  ### Elliptic Curve Cryptography
165
165
 
166
- ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
166
+ ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass (default), edwards and koblitz) and 100+ standard elliptic curve configurations.
167
167
 
168
168
  In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
169
169
 
@@ -171,7 +171,8 @@ In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic
171
171
  forms = ["weierstrass", "edwards", "koblitz"]
172
172
  phe = LightPHE(
173
173
  algorithm_name="EllipticCurve-ElGamal",
174
- form=forms[1],
174
+ form="edwards",
175
+ # curve="ed448", # optinally you can specify the curve for given form
175
176
  )
176
177
  ```
177
178
 
@@ -204,12 +205,16 @@ c4 = c1 + c2
204
205
  c5 = 3 * c1
205
206
 
206
207
  # perform element-wise multiplication between an encrypted embedding and plain embedding
207
- c6 = c1 * t3 # Encrypted-plaintext multiplication
208
+ c6 = c1 * t3
209
+
210
+ # encrypted dot product (likewise cosine similarity)
211
+ c7 = c1 @ t3
208
212
 
209
213
  # proof of work
210
214
  assert np.allclose(cs.decrypt(c4), [a + b for a, b in zip(t1, t2)], rtol=1e-2)
211
215
  assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
212
216
  assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
217
+ assert np.allclose(cs.decrypt(c7)[0], sum([a * b for a, b in zip(t1, t3)]), rtol=1e-2)
213
218
  ```
214
219
 
215
220
  # Contributing
@@ -113,7 +113,7 @@ assert cs.decrypt(c3) == m1 + m2
113
113
  assert cs.decrypt(c4) == k * m1
114
114
  ```
115
115
 
116
- On the other hand, if you adopt a multiplicatively homomorphic cryptosyste (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
116
+ On the other hand, if you adopt a multiplicatively homomorphic cryptosystem (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
117
117
 
118
118
  ```python
119
119
  # build a multiplicatively homomorphic cryptosystem
@@ -136,7 +136,7 @@ assert cs.decrypt(c3) == m1 * m2
136
136
 
137
137
  ### Ciphertext Regeneration
138
138
 
139
- Similar to the most of additively homomorphic algorithms, Paillier lets you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
139
+ The most of additively homomorphic algorithms allow you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
140
140
 
141
141
  ```python
142
142
  c1_prime = cs.regenerate_ciphertext(c1)
@@ -147,7 +147,7 @@ assert cs.decrypt(c1) == m1
147
147
 
148
148
  ### Elliptic Curve Cryptography
149
149
 
150
- ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
150
+ ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass (default), edwards and koblitz) and 100+ standard elliptic curve configurations.
151
151
 
152
152
  In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
153
153
 
@@ -155,7 +155,8 @@ In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic
155
155
  forms = ["weierstrass", "edwards", "koblitz"]
156
156
  phe = LightPHE(
157
157
  algorithm_name="EllipticCurve-ElGamal",
158
- form=forms[1],
158
+ form="edwards",
159
+ # curve="ed448", # optinally you can specify the curve for given form
159
160
  )
160
161
  ```
161
162
 
@@ -188,12 +189,16 @@ c4 = c1 + c2
188
189
  c5 = 3 * c1
189
190
 
190
191
  # perform element-wise multiplication between an encrypted embedding and plain embedding
191
- c6 = c1 * t3 # Encrypted-plaintext multiplication
192
+ c6 = c1 * t3
193
+
194
+ # encrypted dot product (likewise cosine similarity)
195
+ c7 = c1 @ t3
192
196
 
193
197
  # proof of work
194
198
  assert np.allclose(cs.decrypt(c4), [a + b for a, b in zip(t1, t2)], rtol=1e-2)
195
199
  assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
196
200
  assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
201
+ assert np.allclose(cs.decrypt(c7)[0], sum([a * b for a, b in zip(t1, t3)]), rtol=1e-2)
197
202
  ```
198
203
 
199
204
  # Contributing
@@ -34,7 +34,7 @@ from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
34
34
 
35
35
  logger = Logger(module="lightphe/__init__.py")
36
36
 
37
- VERSION = "0.0.18"
37
+ VERSION = "0.0.20"
38
38
 
39
39
 
40
40
  class LightPHE:
@@ -50,6 +50,7 @@ class LightPHE:
50
50
  form: Optional[str] = None,
51
51
  curve: Optional[str] = None,
52
52
  plaintext_limit: Optional[int] = None,
53
+ max_tries: int = 10000,
53
54
  ):
54
55
  """
55
56
  Build LightPHE class
@@ -74,6 +75,10 @@ class LightPHE:
74
75
  This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
75
76
  plaintext_limit (int, optional): Upper bound for plaintext values.
76
77
  This parameter is only used if `algorithm_name` is 'Benaloh'.
78
+ max_tries (int): maximum attempts to generate keys. Default is 10000.
79
+ RSA, Benaloh, Naccache-Stern and Goldwasser-Micali algorithms
80
+ need multiple attempts to generate valid keys. Will be discarded
81
+ for other algorithms.
77
82
  """
78
83
  self.algorithm_name = algorithm_name
79
84
  self.precision = precision
@@ -90,6 +95,7 @@ class LightPHE:
90
95
  form=form,
91
96
  curve=curve,
92
97
  plaintext_limit=plaintext_limit,
98
+ max_tries=max_tries,
93
99
  )
94
100
 
95
101
  def __build_cryptosystem(
@@ -100,6 +106,7 @@ class LightPHE:
100
106
  form: Optional[str] = None,
101
107
  curve: Optional[str] = None,
102
108
  plaintext_limit: Optional[int] = None,
109
+ max_tries: int = 10000,
103
110
  ) -> Union[
104
111
  RSA,
105
112
  ElGamal,
@@ -128,12 +135,18 @@ class LightPHE:
128
135
  - ed25519, ed448 for edwards form
129
136
  - secp256k1 for weierstrass form
130
137
  This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
138
+ plaintext_limit (int, optional): Upper bound for plaintext values.
139
+ This parameter is only used if `algorithm_name` is 'Benaloh'.
140
+ max_tries (int): maximum attempts to generate keys. Default is 10000.
141
+ RSA, Benaloh, Naccache-Stern and Goldwasser-Micali algorithms
142
+ need multiple attempts to generate valid keys. Will be discarded
143
+ for other algorithms.
131
144
  Returns
132
145
  cryptosystem
133
146
  """
134
147
  # build cryptosystem
135
148
  if algorithm_name == Algorithm.RSA:
136
- cs = RSA(keys=keys, key_size=key_size)
149
+ cs = RSA(keys=keys, key_size=key_size, max_tries=max_tries)
137
150
  elif algorithm_name == Algorithm.ElGamal:
138
151
  cs = ElGamal(keys=keys, key_size=key_size)
139
152
  elif algorithm_name == Algorithm.ExponentialElGamal:
@@ -149,11 +162,16 @@ class LightPHE:
149
162
  elif algorithm_name == Algorithm.OkamotoUchiyama:
150
163
  cs = OkamotoUchiyama(keys=keys, key_size=key_size)
151
164
  elif algorithm_name == Algorithm.Benaloh:
152
- cs = Benaloh(keys=keys, key_size=key_size, plaintext_limit=plaintext_limit)
165
+ cs = Benaloh(
166
+ keys=keys,
167
+ key_size=key_size,
168
+ plaintext_limit=plaintext_limit,
169
+ max_tries=max_tries,
170
+ )
153
171
  elif algorithm_name == Algorithm.NaccacheStern:
154
- cs = NaccacheStern(keys=keys, key_size=key_size)
172
+ cs = NaccacheStern(keys=keys, key_size=key_size, max_tries=max_tries)
155
173
  elif algorithm_name == Algorithm.GoldwasserMicali:
156
- cs = GoldwasserMicali(keys=keys, key_size=key_size)
174
+ cs = GoldwasserMicali(keys=keys, key_size=key_size, max_tries=max_tries)
157
175
  else:
158
176
  raise ValueError(f"unimplemented algorithm - {algorithm_name}")
159
177
  return cs
@@ -20,6 +20,7 @@ class Benaloh(Homomorphic):
20
20
  keys: Optional[dict] = None,
21
21
  key_size: Optional[int] = None,
22
22
  plaintext_limit: Optional[int] = None,
23
+ max_tries: int = 10000,
23
24
  ):
24
25
  """
25
26
  Args:
@@ -29,9 +30,12 @@ class Benaloh(Homomorphic):
29
30
  plaintext_limit (int, optional): Upper bound for plaintext values.
30
31
  If provided, r is set to the next prime greater than this value;
31
32
  otherwise, r is chosen randomly from a default range.
33
+ max_tries (int): maximum attempts to generate keys.
32
34
  """
33
35
  self.keys = keys or self.generate_keys(
34
- key_size=key_size or 1024, plaintext_limit=plaintext_limit
36
+ key_size=key_size or 1024,
37
+ plaintext_limit=plaintext_limit,
38
+ max_tries=max_tries,
35
39
  )
36
40
  self.plaintext_modulo = self.keys["public_key"]["r"]
37
41
  self.ciphertext_modulo = self.keys["public_key"]["n"]
@@ -23,15 +23,23 @@ class GoldwasserMicali(Homomorphic):
23
23
  Ref: sefiks.com/2023/10/27/a-step-by-step-partially-homomorphic-encryption-example-with-goldwasser-micali-in-python/
24
24
  """
25
25
 
26
- def __init__(self, keys: Optional[dict] = None, key_size: Optional[int] = None):
26
+ def __init__(
27
+ self,
28
+ keys: Optional[dict] = None,
29
+ key_size: Optional[int] = None,
30
+ max_tries: int = 10000,
31
+ ):
27
32
  """
28
33
  Args:
29
34
  keys (dict): private - public key pair.
30
35
  set this to None if you want to generate random keys.
31
36
  key_size (int): key size in bits
37
+ max_tries (int): maximum attempts to generate keys
32
38
  """
33
39
 
34
- self.keys = keys or self.generate_keys(key_size or 1024)
40
+ self.keys = keys or self.generate_keys(
41
+ key_size=key_size or 1024, max_tries=max_tries
42
+ )
35
43
  self.ciphertext_modulo = self.keys["public_key"]["n"]
36
44
 
37
45
  # Plaintext can be any integer (even larger than n) because it is internally
@@ -25,6 +25,7 @@ class NaccacheStern(Homomorphic):
25
25
  keys: Optional[dict] = None,
26
26
  key_size: Optional[int] = None,
27
27
  deterministic: bool = False,
28
+ max_tries: int = 10000,
28
29
  ):
29
30
  """
30
31
  Args:
@@ -34,9 +35,12 @@ class NaccacheStern(Homomorphic):
34
35
  decryption requires to solve DLP.
35
36
  deterministic (boolean): deterministic or probabilistic version of
36
37
  cryptosystem
38
+ max_tries (int): maximum attempts to generate keys
37
39
  """
38
40
  # Naccache-Stern requires to solve DLP in decryption, so small key is recommended
39
- self.keys = keys or self.generate_keys(key_size or 1024)
41
+ self.keys = keys or self.generate_keys(
42
+ key_size=key_size or 1024, max_tries=max_tries
43
+ )
40
44
  self.plaintext_modulo = self.keys["public_key"]["sigma"]
41
45
  self.ciphertext_modulo = self.keys["public_key"]["n"]
42
46
  self.deterministic = deterministic
@@ -14,7 +14,13 @@ class RSA(Homomorphic):
14
14
  Ref: https://sefiks.com/2023/03/06/a-step-by-step-partially-homomorphic-encryption-example-with-rsa-in-python/
15
15
  """
16
16
 
17
- def __init__(self, keys: Optional[dict] = None, key_size: Optional[int] = None, encrypt_with_public=True):
17
+ def __init__(
18
+ self,
19
+ keys: Optional[dict] = None,
20
+ key_size: Optional[int] = None,
21
+ encrypt_with_public=True,
22
+ max_tries: int = 10000,
23
+ ):
18
24
  """
19
25
  Args:
20
26
  keys (dict): private - public key pair.
@@ -26,17 +32,25 @@ class RSA(Homomorphic):
26
32
  one can decrypt it with your public (digital signatures).
27
33
  Set this arg to True if you want to do encryption with public key e,
28
34
  and do decryption with private key d.
35
+ max_tries (int): maximum attempts to generate keys.
29
36
  """
30
- self.keys = keys or self.generate_keys(key_size or 1024)
37
+ self.keys = keys or self.generate_keys(
38
+ key_size=key_size or 1024, max_tries=max_tries
39
+ )
31
40
  self.plaintext_modulo = self.keys["public_key"]["n"]
32
41
  self.ciphertext_modulo = self.keys["public_key"]["n"]
33
42
  self.encrypt_with_public = encrypt_with_public
34
43
 
35
- def generate_keys(self, key_size: int) -> dict:
44
+ def generate_keys(
45
+ self,
46
+ key_size: int,
47
+ max_tries: int = 10000,
48
+ ) -> dict:
36
49
  """
37
50
  Generate public and private keys of RSA cryptosystem
38
51
  Args:
39
52
  key_size (int): key size in bits
53
+ max_tries (int): maximum number of tries to generate keys
40
54
  Returns:
41
55
  keys (dict): having private_key and public_key keys
42
56
  """
@@ -44,33 +58,35 @@ class RSA(Homomorphic):
44
58
  keys["private_key"] = {}
45
59
  keys["public_key"] = {}
46
60
 
47
- while True:
48
- try:
49
- # picking a prime modulus p and q
50
- p = sympy.randprime(200, 2 ** int(key_size / 2) - 1)
51
- q = sympy.randprime(200, 2 ** int(key_size / 2) - 1)
61
+ for _ in range(max_tries):
62
+ # picking a prime modulus p and q
63
+ p = sympy.randprime(2 ** (key_size // 2 - 300), 2 ** (key_size // 2) - 1)
64
+ q = sympy.randprime(2 ** (key_size // 2 - 300), 2 ** (key_size // 2) - 1)
52
65
 
53
- n = p * q
54
- phi = (p - 1) * (q - 1)
66
+ if p == q:
67
+ continue
55
68
 
56
- # select public exponent e
57
- while True:
58
- e = random.randint(1, phi - 1)
59
- if math.gcd(e, n) == 1:
60
- break
69
+ n = p * q
70
+ phi = (p - 1) * (q - 1)
61
71
 
62
- d = pow(e, -1, phi)
63
- break
64
- except:
65
- pass
66
-
67
- keys["public_key"]["n"] = n
68
- keys["public_key"]["e"] = e
69
- keys["private_key"]["d"] = d
70
- return keys
72
+ # select public exponent e
73
+ for _ in range(1000): # try max 1000 random e
74
+ e = random.randint(2, phi - 1)
75
+ if math.gcd(e, phi) == 1:
76
+ d = pow(e, -1, phi)
77
+ return {
78
+ "public_key": {"n": n, "e": e},
79
+ "private_key": {"d": d},
80
+ }
81
+ raise ValueError(f"Failed to generate RSA keys after {max_tries} tries")
71
82
 
72
83
  def generate_random_key(self) -> int:
73
- pass
84
+ """
85
+ RSA does not require random key for encryption, still return one
86
+ Returns:
87
+ random key (int): one time random key for encryption
88
+ """
89
+ return random.randint(1, self.keys["public_key"]["n"] - 1)
74
90
 
75
91
  def encrypt(self, plaintext: int) -> int:
76
92
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.18
3
+ Version: 0.0.20
4
4
  Summary: A Lightweight Partially Homomorphic Encryption Library for Python
5
5
  Home-page: https://github.com/serengil/LightPHE
6
6
  Author: Sefik Ilkin Serengil
@@ -129,7 +129,7 @@ assert cs.decrypt(c3) == m1 + m2
129
129
  assert cs.decrypt(c4) == k * m1
130
130
  ```
131
131
 
132
- On the other hand, if you adopt a multiplicatively homomorphic cryptosyste (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
132
+ On the other hand, if you adopt a multiplicatively homomorphic cryptosystem (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
133
133
 
134
134
  ```python
135
135
  # build a multiplicatively homomorphic cryptosystem
@@ -152,7 +152,7 @@ assert cs.decrypt(c3) == m1 * m2
152
152
 
153
153
  ### Ciphertext Regeneration
154
154
 
155
- Similar to the most of additively homomorphic algorithms, Paillier lets you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
155
+ The most of additively homomorphic algorithms allow you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
156
156
 
157
157
  ```python
158
158
  c1_prime = cs.regenerate_ciphertext(c1)
@@ -163,7 +163,7 @@ assert cs.decrypt(c1) == m1
163
163
 
164
164
  ### Elliptic Curve Cryptography
165
165
 
166
- ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
166
+ ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass (default), edwards and koblitz) and 100+ standard elliptic curve configurations.
167
167
 
168
168
  In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
169
169
 
@@ -171,7 +171,8 @@ In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic
171
171
  forms = ["weierstrass", "edwards", "koblitz"]
172
172
  phe = LightPHE(
173
173
  algorithm_name="EllipticCurve-ElGamal",
174
- form=forms[1],
174
+ form="edwards",
175
+ # curve="ed448", # optinally you can specify the curve for given form
175
176
  )
176
177
  ```
177
178
 
@@ -204,12 +205,16 @@ c4 = c1 + c2
204
205
  c5 = 3 * c1
205
206
 
206
207
  # perform element-wise multiplication between an encrypted embedding and plain embedding
207
- c6 = c1 * t3 # Encrypted-plaintext multiplication
208
+ c6 = c1 * t3
209
+
210
+ # encrypted dot product (likewise cosine similarity)
211
+ c7 = c1 @ t3
208
212
 
209
213
  # proof of work
210
214
  assert np.allclose(cs.decrypt(c4), [a + b for a, b in zip(t1, t2)], rtol=1e-2)
211
215
  assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
212
216
  assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
217
+ assert np.allclose(cs.decrypt(c7)[0], sum([a * b for a, b in zip(t1, t3)]), rtol=1e-2)
213
218
  ```
214
219
 
215
220
  # Contributing
@@ -1,4 +1,3 @@
1
1
  sympy>=1.12
2
- pytest>=7.1.2
3
2
  tqdm
4
3
  lightecc
@@ -0,0 +1,3 @@
1
+ sympy>=1.12
2
+ tqdm
3
+ lightecc
@@ -8,7 +8,7 @@ with open("requirements.txt", "r", encoding="utf-8") as f:
8
8
 
9
9
  setuptools.setup(
10
10
  name="lightphe",
11
- version="0.0.18",
11
+ version="0.0.20",
12
12
  author="Sefik Ilkin Serengil",
13
13
  author_email="serengil@gmail.com",
14
14
  description="A Lightweight Partially Homomorphic Encryption Library for Python",
@@ -22,14 +22,15 @@ def test_large_keys():
22
22
  Benaloh | 1024 | 4.91 | 0.00 | 0.00 |0.01
23
23
  Benaloh | 2048 | 140.54 | 0.00 | 0.00 |0.03
24
24
  Benaloh | 3072 | 439.46 | 0.00 | 0.00 |0.08
25
+
26
+ Naccache-Stern | 1024 | 19.97 | 0.00 | 0.00 |0.06
25
27
  """
26
28
  algorithms = [
27
- # "Naccache-Stern",
28
- # "Goldwasser-Micali",
29
+ "Naccache-Stern",
30
+ "Goldwasser-Micali",
29
31
  "Benaloh",
30
32
  ]
31
- # key_sizes = [1024, 2048, 3072, 7680]
32
- key_sizes = [3072, 7680]
33
+ key_sizes = [1024, 2048, 3072, 7680]
33
34
 
34
35
  for key_size in key_sizes:
35
36
  for algorithm_name in algorithms:
@@ -1,4 +0,0 @@
1
- sympy>=1.12
2
- pytest>=7.1.2
3
- tqdm
4
- lightecc
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes