Shamir秘密分享的基本形式(同态加、同态乘) | 您所在的位置:网站首页 › 秘密icon › Shamir秘密分享的基本形式(同态加、同态乘) |
Shamir秘密分享简介
Shamir秘密分享,指的是Shamir在1979年的文章《How to share a secret》[1] 中提出的门限秘密分享方案。该方案利用多项式求值和多项式插值,在有限域 Z p \mathbb{Z}_p Zp中构造门限方案分享秘密值。该方案是信息论安全的,并且可以抵抗半诚实的合谋攻击。 假设 p p p是一个素数, Z p = { 0 , 1 , 2 , ⋯ , p − 1 } \mathbb{Z}_p=\{0, 1,2, \cdots ,p-1\} Zp={0,1,2,⋯,p−1}是一个由整数构成的有限域,即 Z p \mathbb{Z}_p Zp中的元素对于模 p p p加法构成一个交换群, Z p ∗ = { 1 , 2 , ⋯ , p − 1 } \mathbb{Z}_p^*=\{1,2,\cdots,p-1\} Zp∗={1,2,⋯,p−1}中的元素对于模 p p p乘法构成一个交换群,乘法对加法具有分配律。下面的运算都是有限域 Z p \mathbb{Z}_p Zp中的运算,也就是模 p p p运算。 定义一个系数模 p p p的 t − 1 t-1 t−1次多项式 f ( x ) = s + c 1 x + c 2 x 2 + ⋯ + c t − 1 x t − 1 f(x)=s+c_1x+c_2x^2+\cdots+c_{t-1}x^{t-1} f(x)=s+c1x+c2x2+⋯+ct−1xt−1是关于秘密 s s s的秘密多项式。其中 c 1 , ⋯ , c t − 1 c_1,\cdots,c_{t-1} c1,⋯,ct−1是 Z p \mathbb{Z}_p Zp中均匀随机选取的随机数。(有 1 p \frac{1}{p} p1的概率使得 c t − 1 c_{t-1} ct−1为0,也就是 f ( x ) f(x) f(x)的次数小于 t − 1 t-1 t−1,但是由于 c t − 1 c_{t-1} ct−1也是秘密的,所以,其他人并不知道秘密多项式的次数,并不影响安全性) 在 Z p \mathbb{Z}_p Zp中选取 n ( n ≥ t ) n(n\ge t) n(n≥t)个不同的数 { x 1 , x 2 , ⋯ , x n } \{x_1,x_2,\cdots,x_n\} {x1,x2,⋯,xn}( x i x_i xi不为0),并计算 y 1 = f ( x 1 ) , y 2 = f ( x 2 ) , ⋯ , y n = f ( x n ) y_1=f(x_1),y_2=f(x_2),\cdots,y_n=f(x_n) y1=f(x1),y2=f(x2),⋯,yn=f(xn).每个用户 P i P_i Pi获得 ( x i , y i ) (x_i,y_i) (xi,yi)。这样就构成了一个 ( t , n ) (t,n) (t,n)门限秘密分享方案。只有至少 t t t个用户才能恢复出秘密的多项式,从而知道秘密 s s s 。根据代数学基本定理, t t t个用户可以插值得到唯一的多项式。而 t − 1 t-1 t−1个多项式只能得到最多 t − 2 t-2 t−2次多项式。由系数的随机性, t − 1 t-1 t−1个用户得不到任何 s s s的信息。 有限域上的拉格朗日插值秘密的恢复或者重建是简单的,通过多项式的插值就可以完成。最常见的就是通过拉格朗日插值法,求秘密多项式 f ( x ) f(x) f(x)。 定义拉格朗日基函数 l i ( x ) = ( ∏ i ≠ j ( x − x j ) ) ÷ ( ∏ i ≠ j ( x i − x j ) ) l_i(x)=(\prod_{i \neq j}(x-x_j))\div (\prod_{i \neq j}(x_i-x_j)) li(x)=(∏i=j(x−xj))÷(∏i=j(xi−xj))。容易验证 l i ( x ) l_i(x) li(x)在 x i x_i xi处的值为1,而在 x j ( j ≠ i ) x_j(j\neq i) xj(j=i)处的值为0. 不妨设 P 1 , P 2 , ⋯ , P k ( t ≤ k ≤ n ) P_1,P_2,\cdots,P_k(t\le k\le n) P1,P2,⋯,Pk(t≤k≤n)想要重建秘密。多项式 f ( x ) = ∑ i = 1 k y i l i ( x ) f(x)=\sum_{i=1}^{k} y_il_i(x) f(x)=∑i=1kyili(x). 同态加法假设 s 1 s_1 s1的秘密多项式为 f 1 ( x ) f_1(x) f1(x),其分享值为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯ , ( x n , y n ) (x_1,y_1),(x_2,y_2),\cdots,(x_n,y_n) (x1,y1),(x2,y2),⋯,(xn,yn), s 2 s_2 s2的秘密多项式为 f 2 ( x ) f_2(x) f2(x),其分享值为 ( x 1 , z 1 ) , ( x 2 , z 2 ) , ⋯ , ( x n , z n ) (x_1,z_1),(x_2,z_2),\cdots,(x_n,z_n) (x1,z1),(x2,z2),⋯,(xn,zn). 则, P 1 , P 2 , ⋯ , P n P_1,P_2,\cdots,P_n P1,P2,⋯,Pn可以在不重建秘密的情况下,计算 s 1 + s 2 s_1+s_2 s1+s2的秘密分享值。 每个用户 P i P_i Pi在本地计算 y i + z i y_i+z_i yi+zi,则对于 P i P_i Pi来说, s 1 + s 2 s_1+s_2 s1+s2的秘密分享值是 ( x i , y i + z i ) (x_i,y_i+z_i) (xi,yi+zi). 同态乘法注意到多项式的乘法会导致多项式的次数增加,所以我们需要 n ≥ 2 t + 1 n\ge2t+1 n≥2t+1. 首先,和加法类似,每个用户 P i P_i Pi在本地计算 y i × z i y_i\times z_i yi×zi,则对于 P i P_i Pi来说, s 1 × s 2 s_1 \times s_2 s1×s2的秘密分享值是 ( x i , y i × z i ) (x_i,y_i\times z_i) (xi,yi×zi). 然后我们需要额外的步骤,使得新的秘密多项式的次数也是 t − 1 t-1 t−1. 实际上,根据拉格朗日插值,秘密多项式 f ( x ) = ∑ i = 1 n y i l i ( x ) f(x)=\sum_{i=1}^n y_il_i(x) f(x)=∑i=1nyili(x),那么秘密 s = f ( 0 ) = ∑ i = 1 n y i l i ( 0 ) s=f(0)=\sum_{i=1}^ny_il_i(0) s=f(0)=∑i=1nyili(0). 由于 l i ( x ) l_i(x) li(x)是可以公开的,所以用户 P i P_i Pi可以在本地计算 y i l i ( 0 ) y_il_i(0) yili(0). P i P_i Pi重新采样随机数,构造一个 t − 1 t-1 t−1次的多项式 q i ( x ) = y i l i ( 0 ) + c 1 , i x + c 2 , i x 2 + ⋯ + c t − 1 , i x t − 1 q_i(x)=y_il_i(0)+c_{1,i}x+c_{2,i}x^2+\cdots+c_{t-1,i}x^{t-1} qi(x)=yili(0)+c1,ix+c2,ix2+⋯+ct−1,ixt−1. 现在, s 1 × s 2 s_1 \times s_2 s1×s2的新的秘密多项式等于 ∑ i = 1 n q i ( x ) \sum_{i=1}^{n}q_i(x) ∑i=1nqi(x). P i P_i Pi计算 q i ( x 1 ) , q i ( x 2 ) , ⋯ , q i ( x n ) q_i(x_1),q_i(x_2),\cdots,q_i(x_n) qi(x1),qi(x2),⋯,qi(xn),然后将 q i ( x j ) q_i(x_j) qi(xj)发送给 P j P_j Pj. 在收到其他用户发送来的值后, P i P_i Pi计算 y i ′ = ∑ j = 1 n q j ( x i ) y_i^\prime=\sum_{j=1}^nq_j(x_i) yi′=∑j=1nqj(xi)作为 s 1 × s 2 s_1 \times s_2 s1×s2在 x i x_i xi处的分享值。 示例代码 ''' It is an example for showing how shamir secret share works ---by zyf ''' import gmpy2 import time # secret is the secret you want to share # t is the threshold, the secret polynomial degree is t-1 # xs are the ids for users # p define the finite field def create_share(secret,t,xs,p)-> list: shares=[secret for _ in xs] st=gmpy2.random_state(time.time_ns()) n=len(xs) for i in range(t): c=gmpy2.mpz_random(st,p) if i==0: xt=[i for i in xs] else: for j in range(n): xt[j]=xt[j]*xs[j]%p for j in range(n): shares[j]=(shares[j]+xt[j]*c%p)%p return shares #compute l_i(0) def compute_l0(xs,p): n=len(xs) l0=[1 for _ in range(n)] for i in range(n): for j in range(n): if i==j: continue l0[i]=(l0[i]*(p-xs[j])*gmpy2.invert(xs[i]-xs[j],p))%p return l0 #reconstruct secret def reconstruct(shares,xs,p): l0=compute_l0(xs,p) secret=0 for i in range(len(xs)): secret=(secret+shares[i]*l0[i])%p return secret #add def add(shares1,shares2,p): n=len(shares1) res=[(shares1[i]+shares2[i])%p for i in range(n)] return res #mul def mul(shares1,shares2,xs,t,p): l0=compute_l0(xs,p) n=len(xs) tshare=[(shares1[i]*shares2[i]*l0[i])%p for i in range(n)] qi={} for i in range(n): qi[i]=create_share(tshare[i],t,xs,p) res=[0 for _ in range(n)] for i in range(n): for j in range(n): res[i]=(res[i]+qi[j][i])%p return res if __name__=="__main__": n=12 t=5 import numpy as np for i in range(10): s1=np.random.randint(2,10023) s2=np.random.randint(2,10023) print("s is ",s1," s2 is ",s2) p=gmpy2.next_prime((s1*s1*s2*s2+1)*3) xs=[i+1 for i in range(n)] sh1=create_share(s1,t,xs,p) sh2=create_share(s2,t,xs,p) add12=add(sh1,sh2,p) print("s1+s2 is ",s1+s2) print("re ",reconstruct(add12,xs,p)) mul12=mul(sh1,sh2,xs,t,p) print("s1*s2 is ",s1*s2) print("re ",reconstruct(mul12,xs,p)) mul112=mul(mul12,sh1,xs,t,p) print("s1*s2 is ",s1*s1*s2) print("re ",reconstruct(mul112,xs,p)) rs1=reconstruct(sh1,xs,p) print("reconstructed ",rs1) print(s1==rs1) 参考文献[1] Shamir, Adi. “How to share a secret.” Communications of the ACM 22.11 (1979): 612-613. [2] Goldwasser, S., M. Ben-Or, and A. Wigderson. “Completeness theorems for non-cryptographic fault-tolerant distributed computing.” Proc. of the 20th STOC. 1988. |
CopyRight 2018-2019 实验室设备网 版权所有 |