目录
Part 1 使用预先计算的三元组进行安全计算
Part 2 三元组的扩充
这是最开始的一篇SPDZ文章,与其他的安全计算有所不同,SPDZ支持双方私有值计算,它允许将部分计算转移到离线阶段。最早在SPDZ‘12和DKLPSS’13中提出,存在几种实现方式比如 cryptography group。我们的目标只是被动安全性,并假设一个加密提供者将诚实地生成所需的三元组。存在多个数据提供者和两台服务器,他们都是半诚实模型。乘法三元组。
简单的加法共享数据:
def share(secret):
share0 = random.randrange(Q)
share1 = (secret - share0) % Q
return [share0, share1]
恢复秘密:
def reconstruct(share0, share1):
return (share0 + share1) % Q
class PrivateValue:
def __init__(self, value, share0=None, share1=None):
if not value is None:
share0, share1 = share(value)
self.share0 = share0
self.share1 = share1
def reconstruct(self):
return PublicValue(reconstruct(self.share0, self.share1))
线性操作:加·减x+y,x-y
class PrivateValue:
...
def add(x, y):
if type(y) is PublicValue:
share0 = (x.share0 + y.value) % Q
share1 = x.share1
return PrivateValue(None, share0, share1)
if type(y) is PrivateValue:
share0 = (x.share0 + y.share0) % Q
share1 = (x.share1 + y.share1) % Q
return PrivateValue(None, share0, share1)
def sub(x, y):
if type(y) is PublicValue:
share0 = (x.share0 - y.value) % Q
share1 = x.share1
return PrivateValue(None, share0, share1)
if type(y) is PrivateValue:
share0 = (x.share0 - y.share0) % Q
share1 = (x.share1 - y.share1) % Q
return PrivateValue(None, share0, share1)
x = PrivateValue(5)
y = PrivateValue(3)
z = x + y
assert z.reconstruct() == 8
每个服务器执行共享实现常数乘:k·x
class PrivateValue:
...
def mul(x, y):
if type(y) is PublicValue:
share0 = (x.share0 * y.value) % Q
share1 = (x.share1 * y.value) % Q
return PrivateValue(None, share0, share1)
x = PrivateValue(5)
y = PublicValue(3)
z = x * y
assert z.reconstruct() == 15
变量乘 x*y
class PrivateValue:
def generate_mul_triple():
a = random.randrange(Q)
b = random.randrange(Q)
c = (a * b) % Q
return PrivateValue(a), PrivateValue(b), PrivateValue(c)
def mul(x, y):
if type(y) is PublicValue:
...
if type(y) is PrivateValue:
a, b, a_mul_b = generate_mul_triple()
# local masking followed by communication of the reconstructed values
alpha = (x - a).reconstruct()
beta = (y - b).reconstruct()
# local re-combination
return alpha.mul(beta) + \
alpha.mul(b) + \
a.mul(beta) + \
a_mul_b
对于原理可参考文章:乘法三元组
平方:
class PrivateValue:
def generate_square_triple():
a = random.randrange(Q)
aa = pow(a, 2, Q)
return PrivateValue(a), PrivateValue(aa)
def square(x):
a, aa = generate_square_triple()
alpha = (x - a).reconstruct()
return alpha.square() + \
(a * alpha) * 2 + \
aa
立方:
def generate_pows_triple(exponent, shape):
a = np.random.randint(Q, size=shape)
return [ share(np.power(a, e) % Q) for e in range(1, exponent+1) ]
def pows(x, triple):
# local masking a = triple[0]
v = sub(x, a)
# communication: the players simultanously send their share to the other
epsilon = reconstruct(v)
# local combination to compute all powers x_powers = []
for exponent in range(1, len(triple)+1):
# prepare all term values a_powers = [ONE] + triple[:exponent]
e_powers = [ pow(epsilon, e, Q) for e in range(exponent+1) ]
coeffs = [ binom(exponent, k) for k in range(exponent+1) ]
# compute and sum terms
terms = ( mul_public(a,e*c) for a,e,c in zip(a_powers,reversed(e_powers),coeffs) )
x_powers.append(reduce(lambda x,y: add(x, y), terms))
return x_powers
n次方:
def generate_statistical_mask():
return random.randrange(2*BOUND * 10**KAPPA)
def generate_zero_triple(field):
return share(0, field)
def convert(x, from_field, to_field, zero_triple):
# local mapping to positive representation x = add_public(x, BOUND, from_field)
# local masking and conversion by player 0 r = generate_statistical_mask()
y0 = (zero_triple[0] - r) % to_field
# exchange of masked share: one round of communication e = (x[0] + r) % from_field
# local conversion by player 1 xr = (e + x[1]) % from_field
y1 = (zero_triple[1] + xr) % to_field
# local mapping back from positive representation y = [y0, y1]
y = sub_public(y, BOUND, to_field)
return y
def upshare(x, large_zero_triple):
return convert(x, Q, P, large_zero_triple)
def downshare(x, small_zero_triple):
return convert(x, P, Q, small_zero_triple)