SMC(secure multiparty computation)多方安全计算致力于在结合多方资源进行计算下最大化的保护各方的隐私信息,随着现今大数据时代的到来,SMC在数据安全领域有着越来越重要的地位。
大神Shamir提出的秘密共享(secret sharing)旨在将隐私数据拆分为不同的份额分配给不同的人,每一个拿到份额的一方可以利用其计算,但无法通过自己的那一份得到完整的信息。这就好比小明画了一幅画,他把这幅画做成拼图给他的朋友每人一块,任意一块都不足够他的朋友猜出画上的内容,而只有多人将拼图拼起来才能知道小明画在纸上的信息。
SMC有许多实现的协议和方法,secret sharing拥有很好同态性质并且计算时间控制在多项式级,容易做成算法电路,因此许多协议都是基于secret sharing。
Completeness Theorems for Non-Cryptographic Fault-Tolerant Distributed Computation发表于1988年,是基于secret sharing的一个比较经典的protocol,后来有许多协议都对这个protocol提出了一些改进,因此对这个protocol的学习可以加深对于secret sharing的理解。
下面是作者作为一个小白对这篇论文的理解和整理,浅显且会出现理解的偏差,希望仅作讨论使用。
原文:http://citeseerx.ist.psu.edu/viewdoc/downloaddoi=10.1.1.116.2968&rep=rep1&type=pdf
How to Share a Secret: https://cs.jhu.edu/~sdoshi/crypto/papers/shamirturing.pdf
首先提及两种性质,t-private和t-resilient,分别对应gossip和byzantine agreement的问题。一套分布式系统如果可以抵御最多t个人的共谋(collusion)而不泄漏隐私,那么这个分布式系统具有t-private的特点;而如果这套系统可以在出现t个byzantine agreement问题中的叛贼将军的情况下仍然计算出正确的结果,那么称这套系统具有t-resilient的性质。
总的来说,这篇文章说了两个事:
- 当 t < n 2 t< \frac{n}{2} t<2n时,对于所有计算都存在t-private的协议
- 当 t < n 3 t< \frac{n}{3} t<3n时,对于所有计算都存在t-resilient的协议
由于题目中提到了完备性,所以文章中也分别对t大于等于 n 2 、 n 3 \frac{n}{2}、\frac{n}{3} 2n、3n的情况进行了讨论。
论文首先讨论了分布式系统的两大实现原理,一个是基于密码学原理,也就是创造一个单向函数(one-way function),利用这个函数进行信息交换,另一个基于非密码学原理,也就是信息论,这类方法规避了密码学对算力的假设,也即敌人有无限算力的情况下也无法威胁系统的隐私及安全,这种方法对隐私具有更高的定义,这篇文章叙述的协议就是基于第二种方法的。
整个协议基于Shamir大神提出的secret sharing,可以做到t-out-of-n,也就是t个人可以对某个信息进行操作,这样规避了一些节点出现掉线甚至不忠诚的问题。协议的实现要基于一下假设:
- 协议实质上是n个完全同步的处理器中的程序
- 两两相互安全的信道
- 在一轮的信息交换中,每个处理器可以给其他的players各发送一条信息,阅读所有收到的信息,并且进行无数次的运算
- 无限的算力。这里要说明一下,因为这个方法不基于处理器的计算能力,并且协议中不存在大量耗费时间的计算,所以在协议中对算力进行假设是没有意义的。
协议分为三个阶段,分别是输入阶段(input stage)、计算阶段(compute stage)和结果阶段(final stage)。在输入阶段,每个数据的owner要对自己的数据进行一定的处理,不仅要保证自己的数据具有t-private的特性,还要具有t-resilient的特性,与此同时,还要让数据的接收方在无法获取实际数据的情况下信任它的数据;在计算阶段,由于使用的多项式具有一定的同态性,每个节点在验证信任他获取的share是真实有效的后,对其进行计算和处理,使数据的使用者除了结果以外得不到任何信息;而在结果阶段,希望得到数据运算结果的节点先根据数据的特点对数据进行验证和纠错,然后再根据得到的数据进行插值计算。
在输入阶段,数据的拥有者为了保证系统的t-private的特性,随机生成 a i ∈ E a_i\in E ai∈E, 得到 f ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a t x t f(x)=a_0+a_1x+a_2x^2+...+a_tx^t f(x)=a0+a1x+a2x2+...+atxt, 然后发送 s i = f ( w i ) s_i=f(w^i) si=f(wi), i=1,2,…,n给每一个节点。根据线性代数的知识可以得到,只有t+1个人进行了共谋(collusion)才能迫使秘密泄漏,这就保证了t-private的特性。这里E就是整个系统的域,E尽量要取大一些,能够提高系统的安全,虽然会引入更大的计算量,但至少|E|要大于n。这里的w满足 w n m o d E = 1 w^n\ mod\ E=1 wn mod E=1,并且当 j ̸ = n j\not=n j̸=n时 w j m o d E ̸ = 1 w^j\ mod\ E \not= 1 wj mod E̸=1。每个节点都有特定的i,相当于每个节点的identifier,这个i是互相知道的,为什么要用 w i w^i wi呢,我们假设在final stage中某节点收到了序列 ( s 0 , s 1 , s 2 , . . . , s n − 1 ) (s_0,s_1,s_2,...,s_{n-1}) (s0,s1,s2,...,sn−1),利用编码理论的方法可以列出 f ( x ) ^ = s 0 + s 1 x + . . . + s n − 1 x n − 1 \hat{f(x)}=s_0+s_1x+...+s_{n-1}x^{n-1} f(x)^=s0+s1x+...+sn−1xn−1,编码时,当x= w i w^i wi,则根据傅立叶逆变换可以得到 a i = 1 n f ^ ( w − 1 ) a_i=\frac{1}{n}\hat{f}(w^{-1}) ai=n1f^(w−1),利用这一性质可以证明s序列是由 g ( x ) = ∏ i = t + 1 n − 1 ( x − w − i ) g(x)=\prod_{i=t+1}^{n-1}(x-w^{-i}) g(x)=∏i=t+1n−1(x−w−i)生成的Generalized Reed-Muller Code,然后根据BCH码的生成方法就能对s序列进行t个纠错( 1 2 d e g g ( x ) \frac{1}{2}deg\ g(x) 21deg g(x)),从而保证了t-resilient的特性。在数据owner分享他秘密的同时,其实并不是发给每个节点一对值,而是发送一个多项式 f i ( x ) f_i(x) fi(x),这个多项式的常数项为对应的si,接收者通过计算 f i ( 0 ) f_i(0) fi(0)来获取他的share,与此同时,owner还会配套发送多项式 g i ( x ) g_i(x) gi(x),利用这个函数,接收者们通过合作的方式来决定这个数据是否可接受,这个过程就是我们所说的零知识证明。
细节一: BCH码
t-private的实现推荐去看Shamir的How to Share a Secret, 下面我来通过介绍BCH码的方式介绍一下t-resilient的实现。我的理解较浅显,如果想了解深入BCH码,建议去看Peterson和Weldon的Error-Correcting Codes。
BCH码是在编码理论中属于循环线性码的一种,名字来自于其发明者名字的首字母,它拥有对多个错误进行纠错的能力,BCH码与其他线性码不同的地方在于他可以根据码的纠错能力来生成码。
BCH码的编码涉及域论,假设
G
F
(
p
m
)
GF(p^m)
GF(pm)为
G
F
(
p
)
GF(p)
GF(p)的扩域,
G
F
(
p
m
)
GF(p^m)
GF(pm)上的本原元就是其域中的一个元素,由这个元素的乘方可以得到该域內的所有元素。对于参数取自
G
F
(
p
)
GF(p)
GF(p),以本原元为根的最小多项式就是该扩域上的本原多项式。注意到
x
p
m
−
1
−
1
=
(
x
−
b
1
)
(
x
−
b
2
)
.
.
.
(
x
−
b
p
m
−
1
)
x^{p^m-1}-1=(x-b_1)(x-b_2)...(x-b_{p^m-1})
xpm−1−1=(x−b1)(x−b2)...(x−bpm−1),其中b取自扩域上的全部非零元素,这样利用因式分解可以得到本原元的每个次幂对应的最小多项式,一般来说,如果p=2,对应结果可以通过查表获取。
说了这么多,我自己都有些云里雾里,生成上面的列表就是为了生成我们想要的BCH码,当我们想要编码拥有t个纠错的能力,我们就计算
g
(
x
)
=
L
C
M
(
f
1
(
x
)
,
f
2
(
x
)
,
.
.
.
,
f
2
t
(
x
)
)
g(x)=LCM(f_1(x),f_2(x),...,f_{2t}(x))
g(x)=LCM(f1(x),f2(x),...,f2t(x)),也就是获取本原元前2t次幂对应的最小多项式的最小公倍多项式,假设我们想传递的信息为m(x),其信息位为k,那么生成的编码就为
c
(
x
)
=
m
(
x
)
×
x
r
+
m
(
x
)
m
o
d
g
(
x
)
c(x)=m(x)\times x^r+m(x)\ mod\ g(x)
c(x)=m(x)×xr+m(x) mod g(x),其中r为g(x)的阶数,这样生成的码长为n=k+r,同时我们也注意到生成的码有一个可贵的品质,那就是所有g(x)的根都是c(x)的根。
下面来说BCH码的译码。所谓纠错能力,就是指找到码中出现的错误以及对应错误的幅值。我们假设收到的码为r(x)=c(x)+e(x),e(x)就是出现的错误,
e
(
x
)
=
∑
i
=
1
v
y
i
x
p
(
i
)
e(x)=\sum_{i=1}^vy_ix^{p(i)}
e(x)=∑i=1vyixp(i),也就是所有错误偏差的幅值乘以对应的位置,我们如果把g(x)的根代入r(x)可以得到
r
(
α
i
)
=
c
(
α
i
)
+
e
(
α
i
)
=
0
+
e
(
α
i
)
=
e
(
α
i
)
=
S
i
r(\alpha_i)=c(\alpha_i)+e(\alpha_i)=0+e(\alpha_i)=e(\alpha_i)=S_i
r(αi)=c(αi)+e(αi)=0+e(αi)=e(αi)=Si,另外,由于
(
S
i
)
q
=
(
∑
i
=
1
v
y
i
x
p
(
i
)
)
q
=
∑
i
=
1
v
y
i
x
p
(
i
)
+
q
=
S
i
q
(S_i)^q=(\sum_{i=1}^vy_ix^{p(i)})^q=\sum_{i=1}^vy_ix^{p(i)+q}=S_{iq}
(Si)q=(∑i=1vyixp(i))q=∑i=1vyixp(i)+q=Siq,使我们只计算
S
1
,
S
3
,
.
.
.
S_1,S_3,...
S1,S3,...就可以通过平方的形式得到偶数下标的S,这下我们开心了,因为我们可以得到2t个
(
α
i
,
S
i
)
(\alpha_i,S_i)
(αi,Si)个数对,又由于e(x)中有2v个未知数,这样只要
v
≤
t
v\leq t
v≤t我们就能解出所有错误出现的位置和对应幅值。然而,由于x与y均为未知数,e(x)的并非线性函数,我们需要将其转化为线性函数进行计算。
注意到
(
x
−
x
1
)
(
x
−
x
2
)
.
.
.
(
x
−
x
v
)
=
x
v
+
δ
1
x
v
−
1
+
.
.
.
+
δ
v
(x-x_1)(x-x_2)...(x-x_v)=x^v+\delta_1x^{v-1}+...+\delta_v
(x−x1)(x−x2)...(x−xv)=xv+δ1xv−1+...+δv,用
α
i
\alpha_i
αi取代其中的x1、x2…,则当
x
=
α
i
,
i
=
1
,
2
,
.
.
.
,
v
x=\alpha_i, i=1,2,...,v
x=αi,i=1,2,...,v时右面的方程式为0,进而有
y
i
x
i
j
δ
v
+
y
i
x
i
j
+
1
δ
v
−
1
+
.
.
.
+
y
i
x
i
j
+
v
=
0
y_ix_i^j\delta_v+y_ix_i^{j+1}\delta_{v-1}+...+y_ix_i^{j+v}=0
yixijδv+yixij+1δv−1+...+yixij+v=0。使用
α
i
,
i
=
m
0
,
m
0
+
1
,
.
.
.
,
m
0
+
v
\alpha_i, i=m_0,m_{0+1},...,m_{0+v}
αi,i=m0,m0+1,...,m0+v代入后对得到的方程进行相加就可以得到
S
m
0
δ
v
+
S
m
0
+
1
δ
v
−
1
+
.
.
.
+
S
m
0
+
v
=
0
S_{m_0}\delta_v+S_{m_0+1}\delta_{v-1}+...+S_{m_0+v}=0
Sm0δv+Sm0+1δv−1+...+Sm0+v=0,当
m
0
=
1
,
2
,
.
.
.
,
v
m_0=1,2,...,v
m0=1,2,...,v,我们就可以列出v个这样的方程,只要
v
≤
t
v\leq t
v≤t,这个方程就可以解出全部的
δ
\delta
δ,求出
δ
\delta
δ代回上面的公式,求出的根就是对应的出错位置
x
p
(
i
)
x^{p(i)}
xp(i)。这里要注意一个问题,我们可以将以上S转化为一个
v
×
v
v\times v
v×v的矩阵,如果生成的矩阵不是满秩的,说明发生错误小于t,这时候需要通过去掉未知数的方法将矩阵降阶。在得到错误位置后,通过把求出的X代回X*Y=S就能计算出对应的Y,如果是二值编码则可以省掉这个步骤。
在这个协议中,当接收节点接收到
(
s
0
,
s
1
,
.
.
.
,
s
n
−
1
)
(s_0,s_1,...,s_{n-1})
(s0,s1,...,sn−1)序列后,利用g(x)的根
(
w
−
(
t
+
1
)
,
w
−
(
t
+
2
)
,
.
.
.
,
w
−
(
n
−
1
)
)
(w^{-(t+1)},w^{-(t+2)},...,w^{-(n-1)})
(w−(t+1),w−(t+2),...,w−(n−1))进行校验和纠错,就可以保证拥有t-resilient的能力,所以这里要求
n
≥
3
t
+
1
n\geq 3t+1
n≥3t+1。
细节二:
整个协议的保密措施都是基于所有秘密被encode在各自的t阶多项式中的,包括涉及到的计算也针对t阶多项式进行了许多操作,因此数据owner需要在不透露自己数据的情况下证明自己发出的shares确实是依据协议由t阶多项式生成的,为了达成这个目的,协议使用了零知识证明(zero-knowledge proof)。
首先,owner生成一个f(x,y)的多项式,其中x和y均有t阶,并且满足f(0,0)=s,也就是他的原数据,这时owner就把
f
i
(
x
)
=
f
(
x
,
w
i
)
f_i(x)=f(x,w^i)
fi(x)=f(x,wi)和
g
i
(
x
)
=
f
(
w
i
,
y
)
g_i(x)=f(w^i,y)
gi(x)=f(wi,y)发给第i个节点,这样第i个节点就可以计算
f
(
w
j
,
w
i
)
=
f
i
(
w
j
)
f(w^j,w^i)=f_i(w^j)
f(wj,wi)=fi(wj)并发送给第j个节点,第j个节点比对收到的值和
g
j
(
w
i
)
g_j(w^i)
gj(wi),如果它有t+1个值都出现了不匹配的情况,那么它就会请求公布自己收到的信息,如果owner拒绝公布或公布后t+1个节点都对此报错,说明数据有问题,那么各个节点就会对这个owner节点的数据做一定的处理,例如取零。这个过程中,要么公布的数据是有问题的,要么owner的数据就是有问题的,所以在这里并没有任何的隐私泄漏问题。
细节三:
owner利用f(x)和g(x)对数据a、b进行加密,假如他现在想利用c(x)分配一个秘密
c
=
a
∗
b
c=a*b
c=a∗b,并且希望它用的c(x)的参数是随机分布的,但同时又能证明里面的秘密确实是
c
=
a
∗
b
c=a*b
c=a∗b。
D
(
x
)
=
A
(
x
)
×
B
(
x
)
=
c
+
c
1
x
+
.
.
.
+
c
2
t
x
2
t
D(x)=A(x)\times B(x)=c+c_1x+...+c_{2t}x^{2t}
D(x)=A(x)×B(x)=c+c1x+...+c2tx2t
D
t
(
x
)
=
r
t
,
0
+
r
t
,
1
x
+
.
.
.
+
r
t
,
t
−
1
x
t
−
1
+
c
2
t
x
t
D_t(x)=r_{t,0}+r_{t,1}x+...+r_{t,t-1}x^{t-1}+c_{2t}x^{t}
Dt(x)=rt,0+rt,1x+...+rt,t−1xt−1+c2txt
D
t
−
1
(
x
)
=
r
t
−
1
,
0
+
r
t
−
1
,
1
x
+
.
.
.
+
r
t
−
1
,
t
−
1
x
t
−
1
+
[
c
2
t
−
1
−
r
t
,
t
−
1
]
x
t
D_{t-1}(x)=r_{t-1,0}+r_{t-1,1}x+...+r_{t-1,t-1}x^{t-1}+[c_{2t-1}-r_{t,t-1}]x^{t}
Dt−1(x)=rt−1,0+rt−1,1x+...+rt−1,t−1xt−1+[c2t−1−rt,t−1]xt
…
D
1
(
x
)
=
r
1
,
0
+
r
1
,
1
x
+
.
.
.
+
r
1
,
t
−
1
x
t
−
1
+
[
c
t
+
1
−
r
t
,
1
−
r
t
−
1
,
r
−
.
.
.
−
r
2
,
t
−
1
]
x
t
D_1(x)=r_{1,0}+r_{1,1}x+...+r_{1,t-1}x^{t-1}+[c_{t+1}-r_{t,1}-r_{t-1,r}-...-r_{2,t-1}]x^t
D1(x)=r1,0+r1,1x+...+r1,t−1xt−1+[ct+1−rt,1−rt−1,r−...−r2,t−1]xt
在生成这些多项式后,得到
C
(
x
)
=
D
(
x
)
−
∑
i
=
1
t
x
i
∗
D
i
(
x
)
C(x)=D(x)-\sum_{i=1}^tx^i*D_i(x)
C(x)=D(x)−∑i=1txi∗Di(x),把
(
w
i
,
C
(
w
i
)
)
(w^i,C(w^i))
(wi,C(wi))和相应Di(x)的值都发出去,就可以做到对C(x)的校验了。
下面来介绍一下计算阶段,在计算阶段开始前,每个节点都已经检验确保了自己得到的shares是由数据owner遵守协议给出的。对于加法和常数乘法运算,多项式拥有很好的同态性质,例如f(x)和g(x)对a和b进行了加密,那么h(x)=f(x)+g(x)就包含了a+b的信息,常数乘以一个函数也可以用这种方法进行运算。然而对于乘法的运算,会产生阶数增加的问题,**两个t阶的多项式相乘会得到一个阶数为2t的多项式,对于n>2t的情况还勉强可以解决,**但每次的运算并不是只相乘一次的,并且这个2t多项式的参数相互之间不具有独立性,这就需要我们进行降阶(degree reduction)。
在进行插值前,假设某一节点收到了序列
(
s
0
,
s
1
,
.
.
.
,
s
n
−
1
)
(s_0,s_1,...,s_{n-1})
(s0,s1,...,sn−1),这一序列是由2t阶的多项式产生的,我们想将这一序列转化为由t阶多项式产生的序列
(
r
0
,
r
1
,
.
.
.
,
r
n
−
1
)
(r_0,r_1,...,r_{n-1})
(r0,r1,...,rn−1)。
设
H
=
(
h
1
,
h
2
,
.
.
.
,
h
2
t
,
0
,
0
,
0...
)
1
×
n
H=(h_1,h_2,...,h_{2t},0,0,0...)_{1\times n}
H=(h1,h2,...,h2t,0,0,0...)1×n,
K
=
(
h
0
,
.
.
.
,
h
t
,
0
,
0
,
0
,
.
.
.
)
1
×
n
K=(h_0,...,ht,0,0,0,...)_{1\times n}
K=(h0,...,ht,0,0,0,...)1×n,
P是一个截取变换(truncation),
P
(
x
0
,
x
1
,
.
.
.
,
x
n
−
1
)
=
(
x
0
,
x
1
,
.
.
.
,
x
t
,
0
,
0
,
.
.
.
)
1
×
n
P(x_0,x_1,...,x_{n-1})=(x_0,x_1,...,x_{t},0,0,...)_{1\times n}
P(x0,x1,...,xn−1)=(x0,x1,...,xt,0,0,...)1×n
B为范德蒙特矩阵,
有
H
⋅
B
=
S
H·B=S
H⋅B=S
H
⋅
P
=
K
H·P=K
H⋅P=K
K
⋅
P
=
R
K·P=R
K⋅P=R
所以得到
S
⋅
(
B
−
1
P
B
)
=
R
S·(B^{-1}PB)=R
S⋅(B−1PB)=R,由于
A
=
B
−
1
P
B
A=B^{-1}PB
A=B−1PB为常数,这就为degree reduction提供了很方便的计算方法。
为了进一步消除2t多项式参数之间的独立性,在各个节点将计算结果给到计算final stage的节点之前,这些节点会对给出的值做随机化,也就是随机生成一个没有常数项的t阶多项式,利用自己的
w
i
w^i
wi计算加到给出结果上,即
h
′
(
x
)
=
h
(
x
)
+
∑
j
=
0
n
−
1
q
j
(
x
)
h'(x)=h(x)+\sum_{j=0}^{n-1}q_j(x)
h′(x)=h(x)+∑j=0n−1qj(x),且
h
′
(
0
)
=
h
(
0
)
h'(0)=h(0)
h′(0)=h(0)。
最后的结果阶段,某个节点收到其他节点发来他们经过处理后的shares之后,利用编码理论的方法对收到的值进行校验和校正,利用得到的结果进行正确的插值计算。