毕业设计里用到了一些密码学的知识,在博客做个记录。
秘密共享
秘密共享(Secret Sharing),如其名,是一种用来共享秘密的技术。理解这个技术,首先需要把意义搞清楚,然后了解技术实现原理,最后用工具实现一个demo。
共享的意义
一个秘密信息,必然有其最初的持有者,也即发布者。发布者具有秘密的使用权和共享权,即他有权利将秘密分享给别人。但这里存在一个问题:如何保证这个共享过程是安全的?
传统的方法,是加密。如对称加密,双方用约定的密钥进行加密解密通信——但也有一个问题:如何安全传递密钥?总是需要有一个最初“绝对安全”的信道。非对称加密解决了这个矛盾,发布方自己生成公私钥对,通过公开公钥,用私钥加密、公钥解密,无需事先约定。
非对称加密解决了绝大部分加密的问题,目前广泛应用的RSA就是明证。但其实它依赖了一个潜在假设(虽然这个假设很接近现实):公开环境是一个诚实信道,它不会篡改发布的共享信息。否则,中间人攻击就会破获秘密。
假设这样一个场景:发布者A与接受者B之间存在N条独立信道,在不清楚各信道信任度和稳定度的情况下,A如何将信息发送给B?秘密共享应运而生。它通过某种方法将秘密拆分,从N个信道同时发送,即使有信道存在恶意者,也无法恢复秘密。
在实际应用中,秘密共享常用于密钥的分布式存储,将一个密钥拆分后多地存储,分散风险,等到需要用的时候再聚合到一起。
共享原理
形式化定义如下:
S
(
s
,
t
,
n
)
→
{
⟨
s
0
⟩
,
⟨
s
1
⟩
,
.
.
.
,
⟨
s
n
⟩
}
S(s,t,n)\rightarrow{\langle s_0\rangle,\langle s_1\rangle,...,\langle s_n\rangle}
S(s,t,n)→{⟨s0⟩,⟨s1⟩,...,⟨sn⟩}
其中s表示需要拆分的秘密,t表示恢复门限,n为拆分数目。
存在恢复函数
R
R
R,对于任意
m
≥
t
m\ge t
m≥t有
R
(
⟨
s
0
⟩
,
⟨
s
1
⟩
,
.
.
.
,
⟨
s
m
⟩
)
→
s
R(\langle s_0\rangle,\langle s_1\rangle,...,\langle s_m\rangle)\rightarrow s
R(⟨s0⟩,⟨s1⟩,...,⟨sm⟩)→s。
shamir算法
shamir是一种秘密共享的实现1,利用了拉格朗日插值公式2。详细原理见参考文献。
下面补充一个shamir算法的有用的性质:加同态。
已知已有两个用于秘密共享的多项式
f
(
x
)
=
a
0
+
a
1
x
+
.
.
+
a
n
x
n
f(x)=a_0+a_1x+..+a_nx^n
f(x)=a0+a1x+..+anxn、
g
(
x
)
=
b
0
+
b
1
x
+
.
.
+
b
n
x
n
g(x)=b_0+b_1x+..+b_nx^n
g(x)=b0+b1x+..+bnxn以及素数
p
p
p。通过秘密共享分享的分片形式是
(
x
,
f
(
x
)
m
o
d
p
)
(x, f(x)mod\ p)
(x,f(x)mod p),
(
x
,
g
(
x
)
m
o
d
p
)
(x, g(x)mod\ p)
(x,g(x)mod p)。
将分片中的多项式结果求和,得到
(
x
,
f
(
x
)
+
g
(
x
)
m
o
d
p
)
(x, f(x)+g(x)\mod\ p)
(x,f(x)+g(x)mod p)。
根据shamir算法中的定义,
a
0
a_0
a0
b
0
b_0
b0是原秘密。因此通过恢复算法对求和后的分片进行恢复,将会得到
a
0
+
b
0
a_0+b_0
a0+b0。这就实现了秘密求和。在双方求和的情况下,没有意义,但在参与者数目大于等于3时,就会有用。
下面的demo将会演示这个过程。
实现应用
github上有对shamir算法的实现3,这里直接借用实现一个拆分求和后恢复的过程。
from secretsharing import secret_int_to_points, points_to_secret_int
from secretsharing import primes
p = primes.get_large_enough_prime([100000])
n_frac = 3
n_rcvr = 2
// 拆分
def ss(n):
return secret_int_to_points(n, n_rcvr, n_frac, p)
// 恢复
def recover(s):
return points_to_secret_int(s, p)
// 对秘密求和
def secret_sum(s1, s2):
return [(i+1, (s1[i][1]+s2[i][1])%p) for i in range(3)]
>>> sh = seret_sum(ss(123),ss(234))
>>> recover(sh)
357
后记
本来写了一堆原理,结果没保存点了发布,发现已经掉线,全没了,心累。算了,参考文献里写的也很详细了。
https://github.com/blockstack/secret-sharing ↩︎