思路比较新奇的一道题,马克一下。
本来是@V 问的题目,后来由@春哥 去问了全知全能的 @maple ,才有了点思路,于是在这马克一下。
附一下@maple 原话:
WriteUp·
题目:https://www.nssctf.cn/problem/4461
审题,Part1是一个带pad
的RSA加密c ≡ m e 1 ( m o d n ) c \equiv m^{e_1} \pmod n c ≡ m e 1 ( mod n ) ,Part2是一个承诺Commitment,在承诺中,
c 1 ≡ m d 2 + k e y 8 + k e y 4 + k e y 2 ( m o d n ) c 2 ≡ f ( k e y ) ( m o d n ) c_1 \equiv m^{d_2} + k_{ey}^8 + k_{ey}^4 + k_{ey}^2 \pmod n \\
c_2 \equiv f(k_{ey}) \pmod n
c 1 ≡ m d 2 + k ey 8 + k ey 4 + k ey 2 ( mod n ) c 2 ≡ f ( k ey ) ( mod n )
现知道n , e 1 , c , e 2 , f , c 1 , c 1 n, e_1, c, e_2, f, c_1, c_1 n , e 1 , c , e 2 , f , c 1 , c 1 ,求m m m 。
Resultant·
首先看看结式Resultant,根据中文数学wiki里的介绍 ,Resultant是Sylvester Matrix的行列式,比如对多项式f f f 和g g g ,他们的Resultant记作res ( f , g ) \text{res}(f, g) res ( f , g ) ,关于Resultant的知识这里先留坑,只需要知道它可以用作二元多项式方程组的消元,参考wiki
举个栗子:
1 2 3 4 5 6 7 R = PolynomialRing(ZZ, 'x, y' ) x, y = R.gens() f = R.random_element() g = R.random_element() print (f.resultant(g, x)) print (f.resultant(g, y))
代入题目中,现在知道
f 1 ≡ m d 2 + k 8 + k 4 + k 2 ( m o d n ) f 2 ≡ f ( k ) ( m o d n ) f_1 \equiv m^{d_2} + k^8 + k^4 + k^2 \pmod n \\
f_2 \equiv f(k) \pmod n
f 1 ≡ m d 2 + k 8 + k 4 + k 2 ( mod n ) f 2 ≡ f ( k ) ( mod n )
由于m m m 和d 2 d_2 d 2 未知,如果把m d 2 m^{d_2} m d 2 看成未知数,那么f 1 f_1 f 1 和f 2 f_2 f 2 就是关于m d 2 m^{d_2} m d 2 和k k k 的一个二元多项式方程组(模n n n ),计算他们的Resultant就可消去烦人的key
在这里如果直接使用像上面的f.resultant(g, x)
的话会报TypeError: Singular error:
,这里引用@maple 的解释:
但问题不大,因为我们知道“Resultant是Sylvester Matrix的行列式”,所以只用求出f 1 f_1 f 1 和f 2 f_2 f 2 的Sylvester Matrix然后求行列式即可
1 2 3 4 5 R = PolynomialRing(Zmod(n), 'md, k' ) md, k = R.gens() f1 = md + k^8 + k^4 + k^2 - c1 f2 = sum ([poly[i] * k^i for i in range (len (poly))]) - c2 res = f1.sylvester_matrix(f2, k).det()
到这里测一下res
的类型会发现是multi_polynomial
,但实际上它只有一个未知数,所以需要转成univariate_polynomial
,另外后面我还需要求它的伴随矩阵 ,所以还需要转成monic ,于是最后一句应该写成
1 res = f1.sylvester_matrix(f2, k).det().univariate_polynomial().monic()
到这里res
即res ( f 1 , f 2 ) \text{res}(f_1, f_2) res ( f 1 , f 2 ) 就是一个关于m d 2 m^{d_2} m d 2 的多项式,这个d 2 d_2 d 2 还有点麻烦,所以需要先消去
PS:实际上是因为后面需要和c
做GCD,而c
是关于m m m 的多项式,在GCD前需要统一c
和res
的未知数(估计把c
转成关于m d 2 m^{d_2} m d 2 的多项式也行,留坑
Companion Matrix·
先看看不是多项式的情况,如果知道m d 2 ( m o d n ) m^{d_2} \pmod n m d 2 ( mod n ) 和e 2 e_2 e 2 ,那么直接计算m ≡ ( m d 2 ) e 2 ( m o d n ) m \equiv (m^{d_2})^{e_2} \pmod n m ≡ ( m d 2 ) e 2 ( mod n ) 即可,即普通的RSA解密,但问题是不可以直接对多项式做这样的操作
于是就需要用到伴随矩阵 ,根据wiki,只要多项式p ( x ) p(x) p ( x ) 是monic的就可以转成以下的伴随矩阵C ( p ) C(p) C ( p ) ,且矩阵C ( p ) C(p) C ( p ) 的特征多项式 即是p ( x ) p(x) p ( x )
不妨先看看wiki中特征多项式的定义的第一句,C ( p ) C(p) C ( p ) 的特征多项式是p ( x ) p(x) p ( x ) 也即p ( x ) p(x) p ( x ) 的解就是C ( p ) C(p) C ( p ) 的特征值(代入题目的话,就是C ( r e s ) C(r_{es}) C ( r es ) 的特征值中的其中一个是m d 2 m^{d_2} m d 2 )
接下来对矩阵C ( p ) C(p) C ( p ) 进行特征分解 ,分解成C ( p ) = V − 1 D V C(p) = V^{-1}DV C ( p ) = V − 1 D V ,
其中的D D D 是对角线上放着C ( p ) C(p) C ( p ) 所有特征值的对角矩阵
如果熟悉特征分解的话,就会知道他的一个作用是用于求矩阵幂的加速,即
C ( p ) a = ( V − 1 D V ) a = V − 1 D a V C(p)^a = (V^{-1} D V)^a = V^{-1} D^a V
C ( p ) a = ( V − 1 D V ) a = V − 1 D a V
D a D^a D a 对角矩阵次方的结果即对角线上是λ i a \lambda_i^a λ i a ,把特征分解合回去,即得C ( p ) a C(p)^a C ( p ) a 是特征值是λ i a \lambda_i^a λ i a 的矩阵,其特征多项式是根为λ i a \lambda_i^a λ i a 的矩阵
把上面这些代进题目中,只需要求C ( r e s ) e 2 C(r_{es})^{e_2} C ( r es ) e 2 的特征多项式,即得到其中一个根为m m m 的多项式
原理说了这么多,其实代码只需要一行
1 fres = (companion_matrix(res) ^ e2).charpoly()
PS:虽然特征分解出的不一定是对角矩阵,如果p ( x ) p(x) p ( x ) 有重根的话就是Jordan Form ,但Jordan Form由于不影响特征值所以好像也能做,待确认,先留个坑,可以先给个简单的栗子说明特征值没受影响
1 2 3 4 5 6 7 R = PolynomialRing(ZZ, 'x' ) x = R.gen() f = R((x-131 )^2 * (x+45678 )) c = companion_matrix(f.monic()) j = c.jordan_form() print ((j^3 ).eigenvalues()) print (131 ^3 )
Greatest Common Divisor·
现在虽然有了根为m m m 的多项式,但其实不能直接用这个多项式求根,因为模n n n 多项式的求根是一个困难问题,所以需要找别的方法
先来看看多项式的一些性质,假设多项式f f f 有一个根是a a a 的话,它就可以被分解为
f ( x ) = ( x − a ) ∗ f ′ ( x ) f(x) = (x - a) * f'(x)
f ( x ) = ( x − a ) ∗ f ′ ( x )
当然在这里不能通过分解res
求m m m ,不然就解了模n n n 多项式的求根难题了
前面说了,c
也是一个关于m m m 的多项式,也就是res
和c
可以被分解为
f r e s ( x ) ≡ ( x − m ) ∗ f ′ ( x ) ( m o d n ) f c ( x ) ≡ ( x − m ) ∗ f ′ ′ ( x ) ( m o d n ) f_{res}(x) \equiv (x - m) * f'(x) \pmod n \\
f_{c}(x) \equiv (x - m) * f''(x) \pmod n
f res ( x ) ≡ ( x − m ) ∗ f ′ ( x ) ( mod n ) f c ( x ) ≡ ( x − m ) ∗ f ′′ ( x ) ( mod n )
所以只需计算
GCD ( f r e s ( x ) , f c ( x ) ) \text{GCD}(f_{res}(x), f_{c}(x))
GCD ( f res ( x ) , f c ( x ))
即可得到( x − m ) (x - m) ( x − m ) 然后即可恢复m m m
PS:在SageMath中直接对模n n n 多项式用gcd
的话会报NotImplementedError
,所以还需要自己实现一遍,另在计算GCD是要用monic的多项式,不然结果好像会错
1 2 3 4 def polygcd (a, b ): while b: a, b = b, a%b return a.monic()
Padding·
虽说c
是关于m m m 的多项式,但因为Part1中的加密加了pad
,所以这个多项式会有点复杂
先来分析一下pad
,其实就是在msg
后面不断重复len(msg) & 0xff
直到字符长度为2048 // 8 - 1
,而len(msg) & 0xff
的变化只有256中,可枚举
令m m m 为x x x (以构造根为m m m 的多项式),把上面的padding粘上去,然后求e 1 e_1 e 1 次幂做RSA加密,再减去c c c 即可得到一个根为m m m 的多项式,至于怎么粘,多调试一下就好了,假设ml
是我枚举的len(msg)
,那么f c f_c f c 就是:
1 2 mx = x * 2 ^(2048 - 8 *(ml+1 )) + sum ([(ml & 0xff ) * 2 ^(8 *i) for i in range (2048 //8 - ml - 1 )]) fc = mx^e1 - c
Exp·
最后就是枚举ml
,然后计算g = polygcd(fc, fres)
,如果g
的degree为1 1 1 的话把m m m 提取出来检查是否为flag即可,也可以像我这样检查g
是否为1 1 1 ,即f r e s f_{res} f res 和f c f_{c} f c 是否互素
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import libnume1 = 233 n = 11804593083540766953191768473584891632857464298610295673456410319093405751966708262984066641796004658380825990723088997287209884308749055923966759203552497405777188930982989535372734594928432767182748217929177897158889489317608554405915470112027996617864702664597137007278287666634774284031478676422259138168442639629844443754737406734109480041155382192976640499144347256893867447543190494469466088332396851821283556702874066317163371254358756837283841870127393406798300254660201670728912096447184875821681550977470988174485488514169553325962974156396460297399345856735492168813016282687198473612371220123462499438299 c = 4236463649246394372490570028773321531426122440354351428997745409269923078428264643984899276198044684405861411922920531424639487584475747440112668094733950281377813868988540407013967573584191516922420060508458881142111648007775541541206593622564564631875373635260315932740995440619035591722675173125322220642392862827996987221780888705796026865917969313975598350208578877195524822778355327253625950282635041414028859491576352297298051077024341409125083650148374909480761558443601847884116325029903499801566422663448734010004472905405209374692154735955178855634936508017264189084568424915164265136679303107745093554391 e2 = 99181398864848350371016820825262886005052515653150198897546275436659368873943 n = 11804593083540766953191768473584891632857464298610295673456410319093405751966708262984066641796004658380825990723088997287209884308749055923966759203552497405777188930982989535372734594928432767182748217929177897158889489317608554405915470112027996617864702664597137007278287666634774284031478676422259138168442639629844443754737406734109480041155382192976640499144347256893867447543190494469466088332396851821283556702874066317163371254358756837283841870127393406798300254660201670728912096447184875821681550977470988174485488514169553325962974156396460297399345856735492168813016282687198473612371220123462499438299 poly = [11693140800527031176333218506340138430240732192854115958431704393516665671354696442539228569575338743555295185742126489158430815263152939757778849261704565332700814864041988371030487621611557506812653488873444536543143499111306076278080422306914610758456202844384883419669780999835836102076447921204517046598938140064244383099665415296806730515287813702062130475281955202867695799707516205462251852912274330831232375362037653669046715539164625549785400699583991291522758317569231805551847554593188947041531361947659444681456741424693383958548943092649257246992511287359572983628972516677506780721131000304618999959240 , 8649833849514355009128561581797540267452805179286553003531347469534976088903045945255322948772127884435044654450320045837146400545547035413423698519877318250595578140049443137749594587635124784776640002144869420735353810166877391696732603701567388813523929688499591774843294322221335666734637085035509293762539158494372418206937167893545676403532672666734540153869114591107560124251452526082108870638702356111887843199439729119638581693415233654435010304861838471514755642714031294943492873471199466178392719343340089957082809543276507257853855309815913146064538017999492250838671852901021723088900839652630087246141 , 10438652195883831412435505413668253747222376993835057512571018586886172468948369796145782100970559858131410652399919261454018181151110711244715955202406007064700539815605400586293839962095578425689125884220411946405356203770630361655071021743875660757465221991116870667245627142015074048387044977823496726850652712591020608153928488470683315016742274925734216097962308837642472645606961264797331661105479206824511239562468503777960135923781994521205671697654968415294210654160582131094288074290198995839634141037654146239631046959485219534841518635072303135929794463631818179287771643492272214514760725403082404954077 , 6299797573437298253264628040275849948907328879976403409079992234253896659195171862234483958852183317706433020249500667696777456584466888790659866599735145200280792478137705987287433143791976037155630359309176772317673958151640355448435973240969550879845354695745860375206302178000370970096709147495071090575765018242388707621300316998885753178573503094652529005706228511805022756376570371219075764243214260191102332714962783026379460713478294288812651004299398765770489801066856526467071118037951998756053462219010773133084404686760087508480150118199064293552990969966284945601004840346771690026959557356854894243142 , 5983820380221904115440358005660480412823344425839483679019674090060688612423646544886814493835896810583739677554610487986153726859924027361158809156736196645803178995096319914672180274662462472664438431485027075620562484665653780178408855146763748596173882017604170478152671447791422988271913561725716787175269110153429606771827175728957339646431861352878283239969487426243742285835160804730331718691578524218241320715981666141098574100230167376734068738383108974392515927882240711793555447542821660698352614753928088082506778754171275154966436158307349089886252792151153113074617130452582559608047038630881997177039 , 8645965524213201512342533940160639034615963495013466945596780273953897799745861434427630308300521898525016597999525817531163934211570038600077012713829688089842641388807750705270930654414851381582193662566863633088157205775657627097344504719056435375579887356258011212827309329133255360061251120340523712584772477488197868145839887008419529501177350232970834479788126170916738231188284692568626261063508315725550701926154671018704631776622326225119240790109750932269682399309418540027656506064831086635915646225839228991353015865676434534451013307891476809505965003364463706502868834742525815830814492484165778659587 , 8166140295702705700395932322789090244824428366114951893911644134774959163562810185361333621863609139128772766004899397707351421904667080061768039818505350911041979508989714659275009135159974367690971928143915291585444591471643654394998052988522554930699706249604920467869677602144648519540475773077094544621879816388166112425971849485960827238183936548150306573608653859245355573339051077997289111414512279487536882904628267661230723738630443448632824642827281459881525198877210749057510831197018233179399730814958129875964180438394548470264377690208812256581197996134290095012248199229098363134875105995583143456168 , 7886150187486607733887128114395381216280632497989629748521639744973030901762862876238518693357844959238094796545062411041606956447558438012468158689781248611833577676585338278147089873855656470245899229225464314602079901728048645256171396517696354087510327916826422932730522688556064550363916637523771395744826680925934243060230500845916621676929436788265600433752247152028066595489876401981088262668869028915433063354318691392248675089923289405167438193023160255479805758334680481491101176946904940583407560870907209114968515837974428072735042388612237381596523708101955987248270337329833158967647159556534902013893 ] c1, c2 = (9026467857515594907139807322545643350722792398333959966810869076838279879742354562376888810480050803270079309674260152449220680190968011586239815898932783620194546687257066163982003360839627375768650529178687560019057911732404297565185448089372452182330617296119274984700102752558018626083227105916899465707167123429214371669495986051607781832508462509001195586237627932854012820647829936908023798167666909963391041754465967388417732502397794744032988693994711566201865393143230144593516438201799281519569197057042946810458619730130134659584342739598850633062984339223231306255977280483664354044871774659593149033209 , 5887596182170973664955287957462647377802905573127495764035296813527168813405478740764981971139443147816701320451276508908764320611456709375484716332728626903126128547418401252520849124559671921918551772662755206548324883488334170067283423978156495671895979491847768306791576421069205614999618915580196468910801165217204877300901375945537974466575619851388784172797986385425693707736028155214422059085724499916277733254676564775837649200298391496783417808690237433893136207762575843230800924871422368332950754364751040187058272878178869385694948947692002564148365094951441755961075673329949416511183562799400968841515 ) R = PolynomialRing(Zmod(n), 'md, k' ) md, k = R.gens() f1 = md + k^8 + k^4 + k^2 - c1 f2 = sum ([poly[i] * k^i for i in range (len (poly))]) - c2 res = f1.sylvester_matrix(f2, k).det().univariate_polynomial().monic() fres = (companion_matrix(res) ^ e2).charpoly() def polygcd (a, b ): while b: a, b = b, a%b return a.monic() R = fres.parent() x = R.gen() for ml in range (10 , 2048 //8 ): mx = x * 2 ^(2048 - 8 *(ml+1 )) + sum ([(ml & 0xff ) * 2 ^(8 *i) for i in range (2048 //8 - ml - 1 )]) fc = mx^e1 - c g = polygcd(fc, fres) if g == 1 : continue flag = -g[0 ] % n print (ml, flag) flag = libnum.n2s(int (flag)) print (flag)
菜(:
PS:exp中部分代码参考了@maple 的exp,其实很多地方好像都只有唯一的写法,不然会报各种奇怪的错误
PPS:这个Commitment好像有点不太“正宗”,正常的Commitment应该是承诺一个消息,以后打开时发送消息然后用承诺值判断这个是否之前承诺的消息,但这里好像体现不出来,而且Reveal还解密?等着大佬来指点