产业气象站 | Linux 中国,国王的秘密:如何保护你的主密码( 二 )


虽然有第三方模块可以计算多项式的值 , 但那并不是针对有限域内的运算的 , 所以 , 国王还得亲自操刀 , 写出计算多项式的代码:
defevaluate(coefficients,x):
acc=0
power=1
forcincoefficients:
acc+=c*power
power*=x
returnacc
再下一步 , 国王选择五个不同的点 , 计算多项式的值 , 并分别交给五个孩子 , 让他们各自保存一份:
shards={}
foriinrange(5):
x=Mod(int_from_bytes(urandom(16)),P)
y=evaluate(polynomial,x)
shards[i]=(x,y)
正如国王所虑 , 不是每个孩子都正直守信 。 其中有两个孩子 , 在他尸骨未寒的时候 , 就想从自己掌握的秘密片段中窥出些什么 , 但穷极所能 , 终无所获 。 另外三个孩子听说了这个事 , 合力将这两人永远驱逐:
delshards[2]
delshards[3]
二十年弹指一挥间 , 奉先王遗命 , 三个孩子将合力恢复出先王的大秘密 。 他们将各自的秘密片段拼合在一起:
retrieved=list(shards.values())
然后是40天没日没夜的苦干 。 这是个大工程 , 他们虽然都懂些Python , 但都不如前国王精通 。
最终 , 揭示秘密的时刻到了 。
用于反算秘密的代码基于 , 它利用多项式在n个非0位置的值 , 来计算其在0处的值 。 前面的n指的是多项式的阶数 。 这个过程的原理是 , 可以为一个多项式找到一个显示方程 , 使其满足:其在t[0]处的值是1 , 在i不为0的时候 , 其在t[i]处的值是0 。 因多项式值的计算属于线性运算 , 需要计算这些多项式各自的值 , 并使用多项式的值进行插值:
fromfunctoolsimportreduce
fromoperatorimportmul
defretrieve_original(secrets):
x_s=[s[0]forsinsecrets]
acc=Mod(0,P)
foriinrange(len(secrets)):
others=list(x_s)
【产业气象站 | Linux 中国,国王的秘密:如何保护你的主密码】cur=others.pop(i)
factor=Mod(1,P)
forelinothers:
factor*=el*(el-cur).inverse()
acc+=factor*secrets[i][1]
returnacc
这代码是在太复杂了 , 40天能算出结果已经够快了 。 雪上加霜的是 , 他们只能利用五个秘密片段中的三个来完成这个运算 , 这让他们万分紧张:
retrieved_secret=retrieve_original(retrieved)
后事如何?
retrieved_secret==secret
TRUE
数学这个魔术的优美之处就在于它每一次都是那么靠谱 , 无一例外 。 国王的孩子们 , 曾经的孩童 , 而今已是壮年 , 足以理解先王的初衷 , 并以先王的锦囊妙计保卫了国家 , 并继之以繁荣昌盛!
关于Shamir秘密共享算法的现代故事
现代 , 很多人都对类似的大秘密苦不堪言:密码管理器的主密码!几乎没有谁能有足够信任的人去完全托付自己最深的秘密 , 好消息是 , 找到至少有三个不会串通起来搞鬼的五人组不是个太困难的事 。
同样是在现代 , 比较幸运的是 , 我们不必再像国王那样自己动手分割要守护的秘密 。 拜现代开源技术所赐 , 这都可以使用现成的软件完成 。
假设你有五个不敢完全信任 , 但还可以有点信任的人:张三、李四、王五、赵六和钱大麻子 。
安装并运行ssss分割密钥:
$echo"longlegstravelfast"|ssss-split-t3-n5
Generatingsharesusinga(3,5)schemewithdynamicsecuritylevel.
Enterthesecret,atmost128ASCIIcharacters:Usinga168bitsecuritylevel.
1-797842b76d80771f04972feb31c66f3927e7183609
2-947925f2fbc23dc9bca950ef613da7a4e42dc1c296
3-14647bdfc4e6596e0dbb0aa6ab839b195c9d15906d
4-97c77a805cd3d3a30bff7841f3158ea841cd41a611
5-17da24ad63f7b704baed220839abb215f97d95f4f8