Shamir 秘密共享
前言
秘密共享:
将秘密 S 派生 n 个碎片,并设置阈值 m,集齐不少于 m 个碎片,即可恢复出秘密 S,少于 m 个碎片则无法获得关于 S 的任何信息
常见的秘密共享方法有
Shamir 秘密共享
Blakley 秘密共享
CRT 秘密共享
准备工作
秘密:S
参与方个数:n
阈值:m
有限域:
秘密分发
生成随机数:
构造多项式
任取 n 个在 中的数
在 中计算
将 发送给 n 个参与方
秘密恢复
基于拉格朗日插值公式, 的另一个表示方法如下:
取 的值,即为秘密 S
一个 (3,5) 的算例
取 、,、,即 。
五个份额()依次是 、、、、。
取 、、,对应 、、:
换 、、,对应 、、:
两组都还原出 。
Python 实现
只依赖标准库:
import secrets
P = 2**127 - 1 # 梅森素数,须为素数
def split(secret, m, n, p=P):
"""把 secret 拆成 n 份,任意 m 份可还原。"""
if not 1 <= m <= n < p:
raise ValueError("需要 1 <= m <= n < p")
if not 0 <= secret < p:
raise ValueError("secret 必须落在 [0, p) 内")
poly = [secret] + [secrets.randbelow(p - 1) + 1 for _ in range(m - 1)]
shares = []
for x in range(1, n + 1):
y = 0
for c in reversed(poly): # Horner 求值
y = (y * x + c) % p
shares.append((x, y))
return shares
def combine(shares, p=P):
"""拉格朗日插值求 f(0)。"""
secret = 0
for i, (xi, yi) in enumerate(shares):
num = den = 1
for j, (xj, _) in enumerate(shares):
if i == j:
continue
num = num * (-xj) % p
den = den * (xi - xj) % p
secret = (secret + yi * num * pow(den, -1, p)) % p # pow(a, -1, p) 需 Python 3.8+
return secret参考资料:
密码学系列-Shamir秘密共享 https://zhuanlan.zhihu.com/p/577211618