Skip to content

Commit 2ef1d8a

Browse files
committed
Add safe keygen
1 parent 4745546 commit 2ef1d8a

6 files changed

Lines changed: 208 additions & 2 deletions

File tree

mife/multiclient/damgard.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from mife.data.zmod import Zmod
88
from mife.misc.cprf import CPRF
99

10-
from mife.single.damgard import _FeDamgard_MK, FeDamgard, _FeDamgard_C, _FeDamgard_SK
10+
from mife.single.damgard import _FeDamgard_MK, FeDamgard, _FeDamgard_C, _FeDamgard_SK, _FeDamgard_SK_Safe
11+
1112

1213
# References:
1314
# https://eprint.iacr.org/2019/487.pdf
@@ -53,6 +54,15 @@ def __init__(self, k: _FeDamgard_SK):
5354
def export(self):
5455
pass
5556

57+
58+
class _FeDamgardMultiClient_SK_Safe:
59+
def __init__(self, k: List[_FeDamgard_SK_Safe]):
60+
self.k = k
61+
62+
def export(self):
63+
pass
64+
65+
5666
class _FeDamgardMultiClient_C:
5767
def __init__(self, tag: bytes, c: _FeDamgard_C):
5868
self.c = c
@@ -61,6 +71,7 @@ def __init__(self, tag: bytes, c: _FeDamgard_C):
6171
def export(self):
6272
pass
6373

74+
6475
class FeDamgardMultiClient:
6576

6677
@staticmethod
@@ -112,10 +123,36 @@ def decrypt(c: List[_FeDamgardMultiClient_C], pub: _FeDamgardMultiClient_MK,
112123

113124
return discrete_log_bound(actual_cul, pub.ipfe.g, bound)
114125

126+
@staticmethod
127+
def decrypt_safe(c: List[_FeDamgardMultiClient_C], pub: _FeDamgardMultiClient_MK,
128+
sk: _FeDamgardMultiClient_SK_Safe, bound: Tuple[int, int]) -> int:
129+
130+
for i in range(pub.n):
131+
if c[i].tag != c[0].tag:
132+
raise Exception("All cipher text must have the same tag")
133+
134+
actual_cul = pub.ipfe.F.identity()
135+
for k in range(pub.n):
136+
cul = pub.ipfe.F.identity()
137+
for i in range(pub.ipfe.n):
138+
cul = cul + sk.k[k].y[i] * c[k].c.c[i]
139+
cul = cul - sk.k[k].g_r_sx - sk.k[k].h_r_tx
140+
actual_cul = actual_cul + cul
141+
142+
return discrete_log_bound(actual_cul, pub.ipfe.g, bound)
143+
115144
@staticmethod
116145
def keygen(y: List[List[int]], key: _FeDamgardMultiClient_MK) -> _FeDamgardMultiClient_SK:
117146
actual_y = [y[i][j] for i in range(key.n) for j in range(key.m)]
118147
if len(y) != key.n or len(actual_y) != key.n * key.m:
119148
raise Exception(f"Function vector must be a {key.n} x {key.m} matrix")
120149
k = FeDamgard.keygen(actual_y, key.ipfe)
121150
return _FeDamgardMultiClient_SK(k)
151+
152+
@staticmethod
153+
def keygen_safe(y: List[List[int]], key: _FeDamgardMultiClient_MK, c: List[_FeDamgardMultiClient_C]):
154+
actual_y = [y[i][j] for i in range(key.n) for j in range(key.m)]
155+
if len(y) != key.n or len(actual_y) != key.n * key.m:
156+
raise Exception(f"Function vector must be a {key.n} x {key.m} matrix")
157+
k = [FeDamgard.keygen_safe(actual_y, key.ipfe, c[i].c) for i in range(key.n)]
158+
return _FeDamgardMultiClient_SK_Safe(k)

mife/multiclient/rom/ddh.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ def export(self):
8787
"m": self.m,
8888
"F": self.F.export(),
8989
"hash": self.hash.export(),
90-
"msk": [[[int(vec2[0]), int(vec2[1])] for vec2 in vec] for vec in self.msk] if self.msk is not None else None
90+
"msk": [[[int(vec2[0]), int(vec2[1])] for vec2 in vec] for vec in
91+
self.msk] if self.msk is not None else None
9192
}
9293

9394

@@ -132,6 +133,24 @@ def export(self):
132133
}
133134

134135

136+
class _FeDDHMultiClient_SK_Safe:
137+
def __init__(self, y: List[List[int]], td: Tuple[int, int]):
138+
"""
139+
Initialize FeDDHMultiClient decryption key
140+
141+
:param y: Function vector
142+
:param td: g1 * <msk, y>, g2 * <msk, y>
143+
"""
144+
self.y = y
145+
self.td = td
146+
147+
def export(self):
148+
return {
149+
"y": self.y,
150+
"d": self.d
151+
}
152+
153+
135154
class _FeDDHMultiClient_C:
136155
def __init__(self, tag: bytes, c: List[GroupElem]):
137156
"""
@@ -221,6 +240,26 @@ def decrypt(c: List[_FeDDHMultiClient_C], tag: bytes,
221240
cul = cul - (sk.d[0] * u1 + sk.d[1] * u2)
222241
return discrete_log_bound(cul, key.g, bound)
223242

243+
@staticmethod
244+
def decrypt_safe(c: List[_FeDDHMultiClient_C], key: _FeDDHMultiClient_MK, sk: _FeDDHMultiClient_SK_Safe,
245+
bound: Tuple[int, int]) -> int:
246+
"""
247+
Decrypt FeDDHMultiClient cipher text
248+
249+
:param c: FeDDHMultiClient cipher text
250+
:param key: FeDDHMultiClient public key
251+
:param sk: FeDDHMultiClient decryption key
252+
:param bound: Bound for the discrete log problem
253+
:return: Decrypted message
254+
"""
255+
cul = key.F.identity()
256+
257+
for i in range(key.n):
258+
cul = cul + inner_product(c[i].c, sk.y[i], key.F.identity())
259+
260+
cul = cul - (sk.td[0] + sk.td[1])
261+
return discrete_log_bound(cul, key.g, bound)
262+
224263
@staticmethod
225264
def keygen(y: List[List[int]], key: _FeDDHMultiClient_MK) -> _FeDDHMultiClient_SK:
226265
"""
@@ -244,3 +283,19 @@ def keygen(y: List[List[int]], key: _FeDDHMultiClient_MK) -> _FeDDHMultiClient_S
244283

245284
d = (cul_1, cul_2)
246285
return _FeDDHMultiClient_SK(y, d)
286+
287+
@staticmethod
288+
def keygen_safe(y: List[List[int]], key: _FeDDHMultiClient_MK, tag: bytes) -> _FeDDHMultiClient_SK_Safe:
289+
"""
290+
Generate a safe FeDDHMultiClient decryption key
291+
292+
:param y: Function vector
293+
:param key: FeDDHMultiClient master key
294+
:param tag: Tag for the decryption key
295+
:return: FeDDHMultiClient decryption key
296+
"""
297+
normal_key = FeDDHMultiClient.keygen(y, key)
298+
u1, u2 = key.hash(tag)
299+
u1, u2 = key.g * u1, key.g * u2
300+
td = (u1 * normal_key.d[0], u2 * normal_key.d[1])
301+
return _FeDDHMultiClient_SK_Safe(y, td)

mife/single/damgard.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ def export(self):
6565
"tx": self.tx
6666
}
6767

68+
class _FeDamgard_SK_Safe:
69+
def __init__(self, y: List[int], g_r_sx: GroupElem, h_r_tx: GroupElem):
70+
"""
71+
Initialize FeDamgard decryption key
72+
73+
:param y: Function vector
74+
:param g_r_sx: g * (r + <s, y>)
75+
:param h_r_tx: h * (r + <t, y>)
76+
"""
77+
self.y = y
78+
self.g_r_sx = g_r_sx
79+
self.h_r_tx = h_r_tx
80+
81+
def export(self):
82+
return {
83+
"y": self.y,
84+
"g_r_sx": self.g_r_sx,
85+
"h_r_tx": self.h_r_tx
86+
}
87+
88+
6889

6990
class _FeDamgard_C:
7091
def __init__(self, g_r: GroupElem, h_r: GroupElem, c: List[GroupElem]):
@@ -145,6 +166,24 @@ def decrypt(c: _FeDamgard_C, pub: _FeDamgard_MK, sk: _FeDamgard_SK, bound: Tuple
145166
cul = cul - sk.sx * c.g_r - sk.tx * c.h_r
146167
return discrete_log_bound(cul, pub.g, bound)
147168

169+
@staticmethod
170+
def decrypt_safe(c: _FeDamgard_C, pub: _FeDamgard_MK, sk: _FeDamgard_SK_Safe, bound: Tuple[int, int]):
171+
"""
172+
Decrypt FeDamgard cipher text within a bound using safe key
173+
174+
:param c: FeDamgard cipher text
175+
:param pub: FeDamgard public key
176+
:param sk: FeDamgard decryption key
177+
:param bound: Bound for discrete logarithm search, the decrypted text should be within the bound
178+
:return: Decrypted message
179+
"""
180+
cul = pub.F.identity()
181+
for i in range(pub.n):
182+
cul = cul + sk.y[i] * c.c[i]
183+
cul = cul - sk.g_r_sx - sk.h_r_tx
184+
return discrete_log_bound(cul, pub.g, bound)
185+
186+
148187
@staticmethod
149188
def keygen(y: List[int], key: _FeDamgard_MK) -> _FeDamgard_SK:
150189
"""
@@ -161,3 +200,20 @@ def keygen(y: List[int], key: _FeDamgard_MK) -> _FeDamgard_SK:
161200
sx = inner_product([key.msk[i][0] for i in range(key.n)], y)
162201
tx = inner_product([key.msk[i][1] for i in range(key.n)], y)
163202
return _FeDamgard_SK(y, sx, tx)
203+
204+
@staticmethod
205+
def keygen_safe(y: List[int], key: _FeDamgard_MK, c: _FeDamgard_C) -> _FeDamgard_SK_Safe:
206+
"""
207+
Generate FeDamgard safer decryption key
208+
209+
:param y: Function vector
210+
:param key: FeDamgard
211+
:param c: FeDamgard cipher text
212+
:return: FeDamgard decryption key
213+
"""
214+
normal_key = FeDamgard.keygen(y, key)
215+
g_r_sx = c.g_r * normal_key.sx
216+
h_r_tx = c.h_r * normal_key.tx
217+
return _FeDamgard_SK_Safe(y, g_r_sx, h_r_tx)
218+
219+

tests/multiclient/rom/test_ddh.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,27 @@ def test_scheme_5(self):
124124

125125
logging.info(f'FeDDHMultiClient test scheme 5 performance with P192 (n={n},m={m}): {end - start}s')
126126

127+
expected = 0
128+
for i in range(n):
129+
expected += sum([a * b for a, b in zip(x[i], y[i])])
130+
131+
self.assertEqual(expected, res)
132+
133+
def test_scheme_safe_1(self):
134+
start = time.time()
135+
n = 25
136+
m = 25
137+
x = [[i * 10 + j for j in range(m)] for i in range(n)]
138+
y = [[i - j - 5 for j in range(m)] for i in range(n)]
139+
tag = str(start).encode()
140+
key = FeDDHMultiClient.generate(n, m)
141+
cs = [FeDDHMultiClient.encrypt(x[i], tag, key.get_enc_key(i)) for i in range(n)]
142+
sk = FeDDHMultiClient.keygen_safe(y, key, tag)
143+
res = FeDDHMultiClient.decrypt_safe(cs, key.get_public_key(), sk, (-10000000, 10000000))
144+
end = time.time()
145+
146+
logging.info(f'FeDDHMultiClient test scheme 2 performance with Prime Group (n={n},m={m}): {end - start}s')
147+
127148
expected = 0
128149
for i in range(n):
129150
expected += sum([a * b for a, b in zip(x[i], y[i])])

tests/multiclient/test_damgard.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,24 @@ def test_scheme_3(self):
6969
expected += sum([a * b for a, b in zip(x[i], y[i])])
7070

7171
self.assertEqual(expected, res)
72+
73+
def test_scheme_safe_1(self):
74+
start = time.time()
75+
n = 10
76+
m = 10
77+
x = [[i * 10 + j for j in range(m)] for i in range(n)]
78+
y = [[i - j - 5 for j in range(m)] for i in range(n)]
79+
tag = str(start).encode()
80+
key = FeDamgardMultiClient.generate(n, m)
81+
cs = [FeDamgardMultiClient.encrypt(x[i], tag, key.get_enc_key(i), key.get_public_key()) for i in range(n)]
82+
sk = FeDamgardMultiClient.keygen_safe(y, key, cs)
83+
res = FeDamgardMultiClient.decrypt_safe(cs, key.get_public_key(), sk, (-10000000, 10000000))
84+
end = time.time()
85+
86+
logging.info(f'FeDamgardMultiClient test scheme 2 performance with Prime Group (n={n},m={m}): {end - start}s')
87+
88+
expected = 0
89+
for i in range(n):
90+
expected += sum([a * b for a, b in zip(x[i], y[i])])
91+
92+
self.assertEqual(expected, res)

tests/single/test_damgard.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,19 @@ def test_scheme_3(self):
6666
expected = sum([a * b for a, b in zip(x, y)])
6767
self.assertEqual(expected, m)
6868

69+
def test_scheme_safe_1(self):
70+
start = time.time()
71+
n = 20
72+
x = [i for i in range(n)]
73+
y = [-(i * 10 + 2) for i in range(n)]
74+
key = FeDamgard.generate(n)
75+
c = FeDamgard.encrypt(x, key)
76+
sk = FeDamgard.keygen_safe(y, key, c)
77+
m = FeDamgard.decrypt_safe(c, key.get_public_key(), sk, (-100000, 100000))
78+
end = time.time()
79+
80+
logging.info(f'FeDamgard test scheme 2 performance (n={n}): {end - start}s')
81+
82+
expected = sum([a * b for a, b in zip(x, y)])
83+
self.assertEqual(expected, m)
84+

0 commit comments

Comments
 (0)