「学习笔记」秘密共享
秘密共享
门限密码学的思想基于秘密分享, 即使用秘密分享的办法, 将基本的公钥密码体系分布与若干参与者之间.
门限密码学包括门限加密和门限签名.
门限加密与解密
如果我们直接让分发者将密钥分享给参与者是一种方案, 但会引发一些问题, 如果分发者是不可信的, 则会有直接盗用密钥的风险, 同时, 参与者也会有可能直接盗用密钥.
为了避免此类问题, 给出了下面的门限加密方案:
由 \(P_1, P_2, \cdots, P_n\) 运行的生成公钥的 \(h\) 协议, 协议运行结束后每位参与者会得到私钥的碎片 \(x_i\), 对应该碎片的碎片验证公钥 \(h_i\) 以及与私钥 \(x\) 相对应的公钥 \(h\).
加密算法: 输入公钥 \(h\), 明文 \(m\), 则输出密文 \(c\).
门限解密: 由任意 \(t\) 个参与者, 输入密文 \(c\) , \(t\) 个私钥碎片 \(x_i\), 以及相应的碎片验证公钥 \(h_i\), 输出明文.
为什么需要碎片验证公钥? 防止分发者欺骗参与者, 因此留给参与者一个验证的机会.
Shamir 门限方案
这是最广为人知的方案, 它基于拉格朗日插值公式.
核心数学原理: 平面上的 \(t\) 个点, 能且只能确定一个 \(t - 1\) 次多项式.
证明:
我们从线性代数的角度来看, 一个 \(t - 1\) 次多项式有 \(t\) 个未知系数, \(f(x) = a_0 + a_1x + a_2 x^2 + a_3 x^3 + \cdots + a_{t - 1} x^{t - 1}\), 我们将 \(t\) 个已知点代入会得到一个含有 \(t\) 个未知数的线性方程组:
这些 \(x\) 我们都是已知的, 而系数 \(a_0, a_1, \cdots, a_{t-1}\) 都是未知的, 我们可以将 \(x\) 构成的矩阵看作是系数矩阵.
这是一个范德蒙德矩阵, 它的行列式是 \(\prod_{1 \le i < j \le t}(x_j - x_i)\), 如果 \(x_i\) 互不相等, 则行列式不等于零, 方程组有唯一的解, 在 Shamir 中我们认为保证了选择的 \(t\) 个 \(x\) 都是不相同的, 因此有唯一的解 \(\left(a_0, a_1, a_2 \cdots, a_{t - 1}\right)\), 由此证明平面上的 \(t\) 个点, 能且只能确定一个 \(t - 1\) 次多项式.
而我们唯一的解 \(\left(a_0, a_1, a_2 \cdots, a_{t - 1}\right)\), 其中的 \(a_0\) 则是我们的秘密.
秘密分发
假设秘密是一个大整数 \(S\).
- 构造多项式: 随机选取 \(t - 1\) 个系数 \(a_1, a_2, \cdots, a_{t - 1}\), 构造一个 \(t-1\) 次的多项式, \(f(x) = S + a_1x + a_2x^2 + \cdots + a_{t-1}x^{t-1}\).
- 生成碎片: 当 \(x = 1, 2, 3 \cdots, n\) 时, 多项式对应 \(n\) 个点: \((1, f(1)), (2, f(2)), (3, f(3)), \cdots, (n, f(n))\), 然后将这些坐标安全地分发给 \(n\) 个人.
解密
我们想找到一个 \(t - 1\) 次的多项式 \(f(x)\), 使得 \(f(x_1) = y_1, f(x_2) = y_2, \cdots\).
在这里, 拉格朗日想出来的办法是: 不直接找 \(f(x)\), 而是找到 \(t\) 个特定的基函数 \(l_i(x)\), 每一个基函数都是一个 \(t-1\) 次的多项式, 当 \(x = x_i\) 时, \(l_i(x_i) = 1\), 而当 \(x \neq x_i\) 时, \(l_i(x_i) = 0\), 有这 \(t\) 个基函数后, 最终的多项式可以构造为 \(f(x) = y_1 \cdot l_1(x) + y_2 \cdot l_2(x) + \cdots + y_t \cdot l_t(x)\).
而这个 \(l_i(x) = \prod_{1 \le j \le t, j \neq i}\dfrac{x - x_j}{x_i - x_j}\), 这里 Shamir 会保证 \(x_i\) 相互不同, 分母不为 \(0\), 当 \(x = x_i\) 时, \(l_i(x_i) = 1\), 因此我们可以利用拉格朗日插值来构造这个多项式 \(f(x)\), 即 \(f(x) = \sum_{i = 1}^{t} y_i \cdot \prod_{1 \le j \le t, j \neq i}\dfrac{x - x_i}{x_i - x_j}\).
利用拉格朗日插值来找常数即可.
例题
题目大意: 有 \(9\) 个持有密钥碎片的人, 恢复阈值为 \(5\), 现在有 \(2\) 个人的密钥被恶意篡改了, 现在要恢复密钥.
{
"prime": "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151",
"threshold": 5, # 恢复阈值为 5
"max_errors": 2, # 有两个被恶意篡改
"shares": [
[
4,
"1756507252888966302421944697206841956143152140868019425423436826040417874090358810282666628353861959194519032644153396178974087251656200520090451446037558616"
],
[
5,
"291079203062482778164854164602169614214941906034816769921809749669038694270141709535829730588575563957368793945410386647770027583595565500385787765396679943"
],
[
6,
"3353657858949220467189251132108794571872371959480001695994095692465794840483860565226874775451906223213941455607156170032589978963502693390308711679147462790"
],
[
3,
"3036190474984169590950378504231555599054858759783145166750792797321971974661532479326963124473761720145245595100028856413919438990575098181766312281016449474"
],
[
2,
"6194143121566534075891262449799030938599380831596361229544817695037620824633497487483944493077767373997778397971319267160293299864167417885508691584631990890"
],
[
1,
"3190833648678294242003969261324345442368829714246140188627248466512581507880823091610739631577934516878443539932340272490275059447848911907619478425588241928"
],
[
7,
"4068614300385897042736163548231103545434345847425657360978335306252159948463803163273112788447249335566556829589208573516328678189557514426677386978479001619"
],
[
8,
"2524499628636075408730372448736615895921954107928295154192144197934845731982899262196954960370286591718071680967232201013594469797728189493226395106754824275"
],
[
9,
"356348046654628493758686606367279817347683022998832017496460398267415288329999382120255439055531110457018951780523102517824504770874348953756247733306681596"
]
]
}
利用拉格让日插值来恢复密钥, 这里由于被篡改的密钥数量很少, 因此可以枚举被篡改的密钥的可能情况, 然后进行各自的拉格朗日求值, 最后求出常数项依次验证.
from Crypto.Util.number import *
import gmpy2
import libnum
p = 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
c = [1756507252888966302421944697206841956143152140868019425423436826040417874090358810282666628353861959194519032644153396178974087251656200520090451446037558616, 291079203062482778164854164602169614214941906034816769921809749669038694270141709535829730588575563957368793945410386647770027583595565500385787765396679943, 3353657858949220467189251132108794571872371959480001695994095692465794840483860565226874775451906223213941455607156170032589978963502693390308711679147462790, 3036190474984169590950378504231555599054858759783145166750792797321971974661532479326963124473761720145245595100028856413919438990575098181766312281016449474, 6194143121566534075891262449799030938599380831596361229544817695037620824633497487483944493077767373997778397971319267160293299864167417885508691584631990890, 3190833648678294242003969261324345442368829714246140188627248466512581507880823091610739631577934516878443539932340272490275059447848911907619478425588241928, 4068614300385897042736163548231103545434345847425657360978335306252159948463803163273112788447249335566556829589208573516328678189557514426677386978479001619, 2524499628636075408730372448736615895921954107928295154192144197934845731982899262196954960370286591718071680967232201013594469797728189493226395106754824275, 356348046654628493758686606367279817347683022998832017496460398267415288329999382120255439055531110457018951780523102517824504770874348953756247733306681596]
# 恢复阈值为 5, 选择其中的5个即可恢复, 一共 9 个, 其中有 2 个被修改过了, 只要能够找到一种情况, 选择的五个里面没有被修改过就 OK
_id = [4, 5, 6, 3, 2, 1, 7, 8, 9]
for i in range(8):
for j in range(i + 1, 9):
# 假设 i 与 j 这两个位置是被恶意修改的
cnt = 5
can = []
for k in range(9):
if k == i or k == j:
continue
# 跳过这两个, 再从头选五个
can.append(k)
cnt -= 1
if cnt == 0:
break
s = 0
for k in can:
paifz = 1
paifm = 1
for d in can:
if d == k: # 跳过这个点
continue
paifz *= (-_id[d])
paifm *= (_id[k] - _id[d])
paifm = gmpy2.invert(paifm, p)
s += c[k] * paifz * paifm % p
print(s % p, end=", ")
print("end")
from Crypto.Util.number import *
import libnum
import gmpy2
can = [2413043792228225722867547658151737091412109912996341756192551818193291240597896385314659605399324278070726614055370328530340482785373848218216139691997777490, 4732504155317934582329909772460019668582496216281253547589305423890566399952892766397805112457065632409202023138239626317906106256131619870721187199904540359, 854589733786575566913104637217829813415694121289115373995417199976902059405420769977951485783165, 2132293504812675132651991026621373548686939083862051861805159744474444356595897111934028963864015753956336866483989222553615835547703834783392796994182083122, 1664376359120090815626063307404100977478321035304902037826172954943032883259231656299644561305168213765687287198354045925741423484920479058687225831155925842, 1485834657431576828387382140479226354226032647096686677590941242827517811350993001369652159882984774810044235774945654711080131592589568327814772354755758729, 1485834657431576828387382140479226354226032647096686677590941242827517811350993001369652159882984774810044235774945654711080131592589568327814772354755758729, 1485834657431576828387382140479226354226032647096686677590941242827517811350993001369652159882984774810044235774945654711080131592589568327814772354755758729, 1337858318581015584993603897738356245191620647797037806226464821154670651926084434674894694592713197715718543162172034169579102989551373376443201826182023773, 3488229265875435860741491418565117937632599178195645706158638815231911829269708335954424516205935358425734684948568622891101862581196323059989077557813531207, 5638600213169856136489378939391879630073577708594253606090812809309153006613332237233954337819157519135750826734965211612624622172841272743534953289445038641, 5224915394922507248751140702790771490127077999646771896492871332355333355246547888949984161997369446288502940702674119740070912948059477981598552193224503792, 3972718609023502566307577451512273096529810272087224710262352875937440419475990756830344566074304841175986084931892889225270989333480656484182660274998261490, 3972718609023502566307577451512273096529810272087224710262352875937440419475990756830344566074304841175986084931892889225270989333480656484182660274998261490, 3972718609023502566307577451512273096529810272087224710262352875937440419475990756830344566074304841175986084931892889225270989333480656484182660274998261490, 3525449556415523196241852097914732156964520196944974373799576302598182796599917267146762834902865135254378178373538088527995790367382053548610467864993677518, 1111340358610700424065736748824157133728568158272416026220118060013415589893966268644678279794464140944730488844135012948175158589882920904389029195171951836, 733810425326841822519291500633825281290147342398046392876206791444657153173769325260984255130715712993083731647406644245835251257102166784298741476821831941, 3342375356707916486593740725840506518975850255366481595578472811615541097093437243096619623314700033760848547239364092889024231827502500650903242791454910947, 3342375356707916486593740725840506518975850255366481595578472811615541097093437243096619623314700033760848547239364092889024231827502500650903242791454910947, 3342375356707916486593740725840506518975850255366481595578472811615541097093437243096619623314700033760848547239364092889024231827502500650903242791454910947, 3153246651014649841238245304418589963645310009451687697390201428935473123297827955223379647933567366967943244123843432159056512505524748662396564793192214408, 2594942292913339808732835114174376673666494728211757682776139118441408613344693987338304867479620714538290842749301447605647595712738791333075710185490019743, 6494091618285846885162924354199339406745650338970197168997873133225037709006204811765244337112724070836536235702008074570258019357393279817300330209171663662, 6494091618285846885162924354199339406745650338970197168997873133225037709006204811765244337112724070836536235702008074570258019357393279817300330209171663662, 6494091618285846885162924354199339406745650338970197168997873133225037709006204811765244337112724070836536235702008074570258019357393279817300330209171663662, 4456074160499837794946378727714928066042842114025468972676071445438160073515618649415625479828525716083497953851196250965459940168375415881852678894158207545, 2781010219733167568750207183476779077246015122430607333022809995648991137521316328311309410249293552934927612773171198214369818887567415171123389335773359226, 2781010219733167568750207183476779077246015122430607333022809995648991137521316328311309410249293552934927612773171198214369818887567415171123389335773359226, 2781010219733167568750207183476779077246015122430607333022809995648991137521316328311309410249293552934927612773171198214369818887567415171123389335773359226, 5371361344336349049475857269471884523285980073098448643886547501291937789861962982194623910981911109184694366769622285220949193477523108857740623297808560220, 5371361344336349049475857269471884523285980073098448643886547501291937789861962982194623910981911109184694366769622285220949193477523108857740623297808560220, 5371361344336349049475857269471884523285980073098448643886547501291937789861962982194623910981911109184694366769622285220949193477523108857740623297808560220, 5371361344336349049475857269471884523285980073098448643886547501291937789861962982194623910981911109184694366769622285220949193477523108857740623297808560220, 5371361344336349049475857269471884523285980073098448643886547501291937789861962982194623910981911109184694366769622285220949193477523108857740623297808560220, 5371361344336349049475857269471884523285980073098448643886547501291937789861962982194623910981911109184694366769622285220949193477523108857740623297808560220]
for m in can:
l = (m.bit_length() + 7) // 8
s = m.to_bytes(l)
print(s)
try:
print(s.decode('utf-8'))
print("OK")
except:
continue
print("end")
# flag{two_liars_cannot_hide_a_polynomial}

浙公网安备 33010602011771号