秘密分享的基本概念
秘密的拥有者有一个秘密的数 s s s。拥有者需要将自己的秘密分享给 n n n个参与者,每个参与者得到一份分享值。通常要求单个的参与者不能得到秘密 s s s的任何信息,但是多个参与者可以通过公布自己的分享值,重建秘密 s s s.
秘密分享在隐私计算中有比较多的应用,比如百万富翁问题、隐私求和等等。根据多少个参与者可以重建秘密,可以将秘密分享分为门限秘密分享和门限秘密分享。门限秘密是指当至少有 t ( 1 < t < n ) t (1<t<n) t(1<t<n)个用户公布分享值的时候,秘密可以被重建,少于 t t t个用户不能得到任何信息。非门限的秘密分享是必须当所有的参与者都公布自己的分享值的时候,秘密才能被重建。下面主要讨论非门限秘密分享的常见两种形式:算术秘密分享和布尔秘密分享(也叫做二进制秘密分享)。
算术秘密分享
算术秘密分享通常是指在整数环 Z p \mathbb{Z}_p Zp上的分享,其中 p > 1 p>1 p>1. 这里的秘密 s ∈ [ 0 , p ) s \in [0,p) s∈[0,p)是一个整数。
分享
首先,在环 Z p \mathbb{Z}_p Zp上均匀随机采样,得到 n − 1 n-1 n−1个随机数 x 1 , x 2 , ⋯ , x n − 1 x_1,x_2,\cdots,x_{n-1} x1,x2,⋯,xn−1.然后计算 x n = s − x 1 − x 2 − ⋯ − x n − 1 m o d p x_n=s-x_1-x_2-\cdots -x_{n-1} \mod p xn=s−x1−x2−⋯−xn−1modp,将 x i x_i xi发送给 P i P_i Pi就完成了分享。
重建
每一个参与者 P i P_i Pi将自己的分享值 x i x_i xi公布,然后计算 s = ∑ i = 1 n x i m o d p s=\sum_{i=1}^n x_i \mod p s=∑i=1nximodp.
同态加法
加法是简单的,假设秘密
s
s
s给参与者
P
i
P_i
Pi的分享值为
x
i
s
x^s_i
xis,秘密
t
t
t给参与者
P
i
P_i
Pi的分享值为
x
i
t
x_i^t
xit,那么秘密分享的同态加法是指在不泄露和重建秘密
s
,
t
s,t
s,t的情况下,每个参与者得到秘密
s
+
t
s+t
s+t的分享。
同态加法的计算不需要交互,每个参与者
P
i
P_i
Pi在本地计算
x
i
s
+
t
=
x
i
s
+
x
i
t
m
o
d
p
x^{s+t}_i=x_i^s+x_i^t \mod p
xis+t=xis+xitmodp.
则
x
i
s
+
t
x^{s+t}_i
xis+t就是秘密
s
+
t
m
o
d
p
s+t \mod p
s+tmodp在参与者
P
i
P_i
Pi的分享值。
同态乘法
相对来说,乘法要比加法麻烦一点。需要用不经意传输OT,或者Beaver Triples.这里介绍乘法三元组(Beaver Triples)的方法,因为相对OT来说更容易理解一点。
乘法三元组是说,我们在进行乘法计算之前,预先得到
a
,
b
,
c
a,b,c
a,b,c的分享,并且满足
c
=
a
b
c=ab
c=ab. 这里的乘法三元组可以由秘密的拥有者计算。秘密拥有者采用两个随机的元素
a
,
b
∈
Z
p
a,b \in \mathbb{Z}_p
a,b∈Zp,并计算
c
=
a
b
m
o
d
p
c=ab \mod p
c=abmodp,然后将
a
,
b
,
c
a,b,c
a,b,c分享给参与者。
假设
a
a
a的分享值为
x
i
a
x^a_i
xia,
b
b
b的分享值为
x
i
b
x^b_i
xib,
c
c
c的分享值为
x
i
c
x^c_i
xic.
我们下面讨论如何使用乘法三元组去同态计算
s
t
m
o
d
p
st \mod p
stmodp的秘密分享。
首先
P
i
P_i
Pi计算
x
i
s
+
x
i
a
m
o
d
p
x^s_i+x^a_i \mod p
xis+xiamodp和
x
i
t
+
x
i
b
m
o
d
p
x^t_i+x^b_i \mod p
xit+xibmodp,然后将计算结果发送给其他参与者。
当每个参与者都计算完成后,这时,
P
i
P_i
Pi就有了
x
j
s
+
x
j
a
m
o
d
p
x^s_j+x^a_j \mod p
xjs+xjamodp和
x
j
t
+
x
j
b
m
o
d
p
x^t_j+x^b_j \mod p
xjt+xjbmodp,其中
j
=
1
,
2
,
⋯
,
n
j=1,2,\cdots,n
j=1,2,⋯,n.所以,
P
i
P_i
Pi可以得到
A
=
s
+
a
m
o
d
p
=
∑
j
=
1
n
(
x
j
s
+
x
j
a
)
m
o
d
p
A=s+a \mod p=\sum_{j=1}^n (x^s_j+x^a_j)\mod p
A=s+amodp=∑j=1n(xjs+xja)modp和
B
=
t
+
b
m
o
d
p
=
∑
j
=
1
n
(
x
j
t
+
x
j
b
)
m
o
d
p
B=t+b \mod p=\sum_{j=1}^n (x^t_j+x^b_j)\mod p
B=t+bmodp=∑j=1n(xjt+xjb)modp.
接下来, P i P_i Pi在本地计算 x i s t = A x i t − B x i a + c i m o d p x^{st}_i=Ax^t_i-Bx^a_i+c_i \mod p xist=Axit−Bxia+cimodp.
证明如下:
∑
i
=
1
n
x
i
s
t
m
o
d
p
=
∑
i
=
1
n
(
A
x
i
t
−
B
x
i
a
+
c
i
)
m
o
d
p
=
A
t
−
B
a
+
c
m
o
d
p
=
(
s
+
a
)
t
−
(
t
+
b
)
a
+
c
m
o
d
p
=
s
t
m
o
d
p
.
\begin{aligned} \sum_{i=1}^n x^{st}_i \mod p=&\sum_{i=1}^n (Ax^t_i-Bx^a_i+c_i ) \mod p\\ =&At-Ba+c \mod p\\ =&(s+a)t-(t+b)a+c\mod p \\ =&st \mod p. \end{aligned}
i=1∑nxistmodp====i=1∑n(Axit−Bxia+ci)modpAt−Ba+cmodp(s+a)t−(t+b)a+cmodpstmodp.
需要注意的是,一个乘法三元组应该只被使用一次,否则可能会泄露某些信息。
布尔秘密分享
布尔秘密分享是一种特殊的算术秘密分享,也就是当
p
=
2
p=2
p=2时的算术秘密分享。
当
p
=
2
p=2
p=2时,具有很多特殊的性质。我们可以将之与电路门对应起来。其中加法就是异或门,乘法就是与门。通过这种对应,我们可以利用电路门的特性,可以很方便的计算一些非线性函数。
示例代码
'''
It is a toy example for showing how arithmetic share works
---by zyf
'''
import numpy as np
# s is the secret share that you want to share
# n is the number of palyers
# p is the order of the integer finite ring
def share(s,n,p):
x=np.random.randint(0,p,size=n)
x[n-1]=(s-np.sum(x[:n-1]))%p
return x
# shares is the shared values
def reconstruct(shares,p):
return np.sum(shares)%p
# the addition of shares
def hadd(x1, x2,p):
res=(x1+x2)%p
return res
# the multiplication of shares
# sa is the shared values of a
# sb is the shared values of b
# sc is the shared values of c
# c=ab mod p
def hmul(x1,x2,xa,xb,xc,p):
xA=hadd(x1,xa,p)
xB=hadd(x2,xb,p)
A=reconstruct(xA,p)
B=reconstruct(xB,p)
res=(A*x2-B*xa+xc)%p
return res
if __name__=="__main__":
n_test=10
for i in range(n_test):
s1=np.random.randint(0,100)
s2=np.random.randint(0,100)
p=np.random.randint(s1*s2+max(s1,s2),2*s1*s2+2*max(s1,s2))
n=np.random.randint(3,10)
x1=share(s1,n,p)
x2=share(s2,n,p)
x_add=hadd(x1,x2,p)
print("The sum is ",s1+s2)
re_sum=reconstruct(x_add,p)
print("The re sum is ",re_sum)
a=np.random.randint(0,p)
b=np.random.randint(0,p)
c=a*b%p
xa=share(a,n,p)
xb=share(b,n,p)
xc=share(c,n,p)
x_mul=hmul(x1,x2,xa,xb,xc,p)
print("The mul is ",s1*s2)
re_mul=reconstruct(x_mul,p)
print("The re mul is ",re_mul)