# Trendy windy trigonity **Source** ```python= from Crypto.Util.number import bytes_to_long flag = b'CSCTF{fake_flag}' print(len(flag)) R = RealField(1000) a,b = bytes_to_long(flag[:len(flag)//2]),bytes_to_long(flag[len(flag)//2:]) x = R(0.75872961153339387563860550178464795474547887323678173252494265684893323654606628651427151866818730100357590296863274236719073684620030717141521941211167282170567424114270941542016135979438271439047194028943997508126389603529160316379547558098144713802870753946485296790294770557302303874143106908193100) enc = a*cos(x)+b*sin(x) print(enc) #38 #enc = 2.78332652222000091147933689155414792020338527644698903976732528036823470890155538913578083110732846416012108159157421703264608723649277363079905992717518852564589901390988865009495918051490722972227485851595410047572144567706501150041757189923387228097603575500648300998275877439215112961273516978501e45 ``` ## Phân tích Ta có phương trình : $flag_1*a + flag_2*b = enc$ , trong đó : $a = cos(x) , b = sin(x)$ Thì đây đơn giản là knapsnack problem đơn giản , nhưng do $a,b,enc$ không phải số thực nên ta chưa áp dụng LLL được . Ta đơn giản chỉ cần nhân bội số đủ để nó thành số nguyên thôi . Chuỗi thập phân đằng sau có độ dài là 300 nên ta nhân `10^300` vào ## Code ```python! from Crypto.Util.number import * def Low_density_Subset_Sum_Problems(multi,result) : n = len(multi) N = int(sqrt((n+1)//4)) + 1 M = Matrix(QQ , n + 1 , n + 1) for i in range(n) : M[i,i] = 1 M[i,-1] = N*multi[i] M[-1,i] = 1/2 M[-1,-1] = -N*result M = M.LLL()[0] M = [int(i-1/2) for i in M] return M[:-1] R = RealField(1000) x = R(0.75872961153339387563860550178464795474547887323678173252494265684893323654606628651427151866818730100357590296863274236719073684620030717141521941211167282170567424114270941542016135979438271439047194028943997508126389603529160316379547558098144713802870753946485296790294770557302303874143106908193100) enc = 2.78332652222000091147933689155414792020338527644698903976732528036823470890155538913578083110732846416012108159157421703264608723649277363079905992717518852564589901390988865009495918051490722972227485851595410047572144567706501150041757189923387228097603575500648300998275877439215112961273516978501e45 a = cos(x) b = sin(x) s = Low_density_Subset_Sum_Problems([int(a*10^300),int(b*10^300)],int(enc*10^300)) print(long_to_bytes(s[0]) + long_to_bytes(s[1])) ``` Flag : ```CSCTF{Trigo_453_Tr3ndy_FuN_Th35e_D4Y5}``` # Super-fnv **Source** ```python= from pwn import xor from random import randint from hashlib import sha256 from FLAG import flag cc = [randint(-2**67, 2**67) for _ in range(9)] key = sha256("".join(str(i) for i in cc).encode()).digest() enc = xor(key, flag) def superfnv(): x = 2093485720398457109348571098457098347250982735 k = 1023847102938470123847102938470198347092184702 for c in cc: x = k * (x + c) return x % 2**600 print(f"{enc.hex() = }") print(f"{superfnv() = }") # enc.hex() = '4ba8d3d47b0d72c05004ffd937e85408149e13d13629cd00d5bf6f4cb62cf4ca399ea9e20e4227935c08f3d567bc00091f9b15d53e7bca549a' # superfnv() = 2957389613700331996448340985096297715468636843830320883588385773066604991028024933733915453111620652760300119808279193798449958850518105887385562556980710950886428083819728334367280 ``` ## Phân tích Ta có hàm `super-fnv` sẽ thực hiện phép tính : $x = k*(x+c) \ mod \ 2^{600}$ lặp 9 lần , sau 9 lần lặp thì `x` sẽ có dạng : $x \equiv k^9*x_0 + k^9*c_1 + k^8*c_2 + ... + k^0*c9 \mod \ 2^{600}$ Với $x_0$ là $x$ ban đầu của mình `2093485720398457109348571098457098347250982735` Thì giờ ta sẽ viết lại : $x - k^9*x_0 \equiv k^9*c_1 + k^8*c_2 + ... + k^0*c9 \mod \ 2^{600}$ Giờ nó nhìn giống `Modular Subset Sum Problem` nhỉ , ừ thì nó đúng là thế nhưng vấn đề của ta ở đây là nó quá nhiều nghiệm nên không tìm chính xác được nghiệm mà ta cần . Mình cũng dùng 1 số tool khác để có thể tìm nhiều nghiệm solve linear như `https://github.com/protozeit/toolbase/blob/master/crypto/solvelinmod.py` mà không được :<< Rồi sau khi anh @Kindoo solve thì mình mới dùng tool `Wolfram` , lúc trước đọc 7749 cái hướng dẫn mà không hiểu cách code của nó =(( Cách giải thì vẫn tương tự solve linear mod như link ở trên thôi , nhập phương trình và bounds của của ẩn , và nó sẽ tìm hết tất cả các nghiệm cho mình :smiley_cat: ## Code ```wolfram! xx = {k^(n - i) for i = 0 to (n - 1)}; target = 2957389613700331996448340985096297715468636843830320883588385773066604991028024933733915453111620652760300119808279193798449958850518105887385562556980710950886428083819728334367280; LB = -2^67; UB = 2^67; M = 2^600; x = 2093485720398457109348571098457098347250982735; k = 1023847102938470123847102938470198347092184702; eq = xx.x + k*M == target; sol = FindInstance[ eq && And @@ (Thread[x[ Append[x, k], Integers, 1000 ]; cc = x /. sol[[1]]; key = Hash[cc, "SHA256"]; ct = FromHex["4ba8d3d47b0d72c05004ffd937e85408149e13d13629cd00d5bf6f4cb62cf4ca399ea9e20e4227935c08f3d567bc00091f9b15d53e7bca549a"]; flag = BitXor[key, ct]; If[StringContainsQ[flag, "CSCTF"], Print[flag]] ``` Flag : ```CSCTF{478845edc037270f072a5e829b1e9b34ad448950718243847c}``` # Connorsmith **Source** ```python= m = int.from_bytes(b'CSCTF{redacted}') p = random_prime(2**1024) q = random_prime(2**1024) N = p*q d = randint(0, int(N**0.35)) e = pow(d, -1, (p-1)*(q-1)) print(f'{N = }') print(f'{e = }') print(f'c = {pow(m, e, N)}') print(f'hint = {(p+q) >> 795}') """ N = 7552253013225223212686972759229408890943243937848116869511428282592494711559240135372705736006054353083281103140787662239958191241833157109597880624454796412006762881501916845155158694626704629051045217266597685547634722763704638532067409306181328833329683262904207364205190648604464680961179156366009048508124744257064547090561236984730817200175311749708243086463240602718911105727107075971987228340827791295829216059926076767577606528647738447725195880791137450082195604212374273765390335921438605358227547423468794396280894150559661664635540689602987474623120205743645087417873312711804245504568677508120251077973 e = 3972273176912267799970180147678020025192175195982968793722693097132970664724388722714705209022371322943558028173459714967997171817396680330435643595109433373306392229639747130134793710239081601404067602930871254806754684103349829634489509031907387929080189489106215966862642406152181674399593026117258657690036458955106821789654735855538375273851668820461621159458690509295524433242439365251850800232909323376356116251835554606066609685882803255427299046970093232995420925951786433206910901590576814359503385919307570360242528454529766855342865079257244016304989185569117193284115242278439808082079787893597831292429 c = 6722063431743120124281037577917473736384734002344400102535470664988199976365033546621632487383386053044468700113542626459908567596300577088705896140930724832695917664482501591801075560437336915520962349830960551339852803481367045861684404716913927870231244602348980596739084252620702852351036834534769613031735817640709051052713694452907186969900542466747407949270228341375666775282809021111998328175103742416108902755346724742467339317044645243210574003890806923017769148711785248795287760426567277473640239499920974270994457112678786022613046685998793486144172215215581287541508145268729387185453679039441575292812 hint = 891237814844096809623936988168241703768093224718029580247856301709140 """ ``` ## Phân tích Đập vào mắt ta trong bài này thì là nó xác định $d$ trước với `d = randint(0, int(N**0.35))` , với mấy số d được xác định bởi n kiểu này thì ta thường nghĩ đến các cách tấn công như : `Wiener Attack` hay `Boneh-durfee`. Nhưng cả 2 cách này đều không khả quan lắm do để thực hiện nó thì giới hạn của d để thực hiện 2 cách trên là $d < N^{0.292}$ , ở đây là `0.35`. Lúc này thì ta sẽ phải khai thác đến dữ kiện hint kia . Thì ta có : $e*d = 1 + k*phi = 1 + k*(N+1- (p+q))$ $1 + k*(N+1 - (p+q)) \equiv 0 \ mod \ e$ $1 + k*(N+1 - (hint << 795 + x)) \equiv 0 \mod \ e$ Thì giờ đây ta chỉ cần giải phương trình này bằng coppersmith với 2 ẩn là $k$ và $x$ trong modulo $e$. ```python= import sys from coppersmith_multivariate_heuristic import coppersmith_multivariate_heuristic from Crypto.Util.number import long_to_bytes from sage.all import * N = 7552253013225223212686972759229408890943243937848116869511428282592494711559240135372705736006054353083281103140787662239958191241833157109597880624454796412006762881501916845155158694626704629051045217266597685547634722763704638532067409306181328833329683262904207364205190648604464680961179156366009048508124744257064547090561236984730817200175311749708243086463240602718911105727107075971987228340827791295829216059926076767577606528647738447725195880791137450082195604212374273765390335921438605358227547423468794396280894150559661664635540689602987474623120205743645087417873312711804245504568677508120251077973 e = 3972273176912267799970180147678020025192175195982968793722693097132970664724388722714705209022371322943558028173459714967997171817396680330435643595109433373306392229639747130134793710239081601404067602930871254806754684103349829634489509031907387929080189489106215966862642406152181674399593026117258657690036458955106821789654735855538375273851668820461621159458690509295524433242439365251850800232909323376356116251835554606066609685882803255427299046970093232995420925951786433206910901590576814359503385919307570360242528454529766855342865079257244016304989185569117193284115242278439808082079787893597831292429 c = 6722063431743120124281037577917473736384734002344400102535470664988199976365033546621632487383386053044468700113542626459908567596300577088705896140930724832695917664482501591801075560437336915520962349830960551339852803481367045861684404716913927870231244602348980596739084252620702852351036834534769613031735817640709051052713694452907186969900542466747407949270228341375666775282809021111998328175103742416108902755346724742467339317044645243210574003890806923017769148711785248795287760426567277473640239499920974270994457112678786022613046685998793486144172215215581287541508145268729387185453679039441575292812 hint = 891237814844096809623936988168241703768093224718029580247856301709140 hint = hint << 795 PR.<x,y> = PolynomialRing(Zmod(e)) f = y*((N+1) - (x + hint)) + 1 tmp = coppersmith_multivariate_heuristic(f, [2**795, 2**711], beta = 1)[0] print(tmp) ``` ![image](https://hackmd.io/_uploads/r1VJb3E2A.png) Chaỵ 3p là ra , nhưng nhanh hơn rất nhiều so với hàm mình dùng trước r , treo máy có khi phải cả đêm :sleeping: . Kiona vô địch :yum: ```python= [177751836399556739219298619379109781012477889949806793333033426536103775450599682453136337130332392835049844717992739559363652650443931602863383863338842680216961343326620972648633880853391604562066337471832137216804201275790942633787153974, 896422735159838833493902020285108669832628148233746995493909503761254449745112601249854782322065199197766396901471392300202416434320465826293530430588281205658179368020642743951305235075064393760621843207154080912] ``` Sau khi có `tmp` thì ta thấy $tmp[0] + (hint << 795) = p + q$ -> $phi = N + 1 - (p+q)$ . Còn lại thì decrypt rsa thôi . ```python= a = tmp[0] phi = N + 1 - (hint+a) d = pow(e,-1,phi) print(long_to_bytes(pow(c,d,N))) ``` Flag : ```CSCTF{37c37f30fc67f98f376a1c30b25b3969}``` # Two Many Hints Bài này chắc là bài mình tiếc nhất vì không giải được trong giải vì 1 lỗi rất ngớ ngẩn :disappointed: **Source** ```python= from hashlib import sha256 from Crypto.Cipher import AES from Crypto.Util.Padding import pad,unpad from secret import flag # PARAMETERS q = 3329 k = 2 sigma = 2.5 n = 256 K = CyclotomicField(n,'z') OK = K.OK() OKq= OK.quotient(q,'y') A = matrix(K, k,k, [K(random_vector(ZZ,n//2,x=-q//2,y=q//2).list()) for _ in k*k*"_"]).lift_centered() s = matrix(K, [K(random_vector(ZZ,n//2,sigma,distribution="gaussian").list()) for __ in k*"_"] ) e = matrix(K, [K(random_vector(ZZ,n//2,sigma,distribution="gaussian").list()) for __ in k*"_"] ) b = (s*A +e ).change_ring(OKq) H = matrix(k,k,[ OK(list(random_vector(ZZ,n))) for _ in k*k*"_"] ) l = s*H # I won't give you this 3:) h = floor(.25*n/2) l2 = matrix([l[0,0] , OK(l[0,1].list()[:-h]) ]) key = sha256(str(s).encode()).digest()[:16] iv = sha256(str(e).encode()).digest()[:16] cipher= AES.new(key,AES.MODE_CBC,iv=iv) enc = cipher.encrypt(pad(flag,16)) #Printing print(f"A = {A.coefficients()}") print(f"b = {b.coefficients()}") print(f"H = {H.coefficients()}") print(f"l2 = {l2.coefficients()}") print("enc = ", enc.hex()) ``` **Output** ```python= A = [-1052*z^127 + 566*z^126 + 1032*z^125 + 1260*z^124 + 1379*z^123 + 395*z^122 - 929*z^121 - 1350*z^120 + 1535*z^119 + 72*z^118 + 262*z^117 - 669*z^116 + 1141*z^115 + 1076*z^114 - 200*z^113 + 1453*z^112 - 1492*z^111 - 1165*z^110 - 599*z^109 + 990*z^108 - 207*z^107 + 1014*z^106 + 1230*z^105 + 125*z^104 + 369*z^103 - 1073*z^102 - 741*z^101 + 1349*z^100 + 459*z^99 + 51*z^98 - 616*z^97 - 1491*z^96 - 310*z^95 - 975*z^94 + 580*z^93 - 1371*z^92 + 291*z^91 - 904*z^90 - 989*z^89 - 1007*z^88 - 1525*z^87 + 1548*z^86 + 885*z^85 - 671*z^84 - 406*z^83 - 1164*z^82 + 1600*z^81 + 438*z^80 + 1079*z^79 - 15*z^78 + 1027*z^77 + 1263*z^76 + 1307*z^75 + 1250*z^74 - 1347*z^73 - 1003*z^72 - 1444*z^71 - 1174*z^70 + 1117*z^69 + 159*z^68 - 1555*z^67 + 1035*z^66 - 1167*z^65 + 326*z^64 - 362*z^63 - 1377*z^62 + 152*z^61 + 934*z^60 + 1120*z^59 - 155*z^58 - 797*z^57 - 379*z^56 + 501*z^55 - 958*z^54 - 577*z^53 - 836*z^52 + 663*z^51 - 550*z^50 - 442*z^49 + 1271*z^48 + 1200*z^47 - 454*z^46 + 1164*z^45 - 505*z^44 - 1571*z^43 + 1480*z^42 + 113*z^41 - 36*z^40 + 821*z^39 - 1456*z^38 + 1475*z^37 + 325*z^36 + 525*z^35 - 481*z^34 + 1586*z^33 - 139*z^32 - 950*z^31 - 277*z^30 - 389*z^29 + 653*z^28 - 1526*z^27 - 645*z^26 + 438*z^25 - 904*z^24 - 1272*z^23 - 28*z^22 + 848*z^21 - 206*z^20 - 918*z^19 + 1311*z^18 - 1544*z^17 - 760*z^16 - 755*z^15 + 837*z^14 + 1258*z^13 + 659*z^12 + 405*z^11 + 1208*z^10 - 1168*z^9 - 422*z^8 + 356*z^7 - 1398*z^6 - 1632*z^5 + 862*z^4 - 166*z^3 + 391*z^2 + 1229*z - 369, -374*z^127 - 587*z^126 - 509*z^125 + 570*z^124 - 728*z^123 + 999*z^122 + 1375*z^121 - 103*z^120 + 1335*z^119 - 600*z^118 - 91*z^117 + 292*z^116 - 51*z^115 + 140*z^114 - 30*z^113 - 1085*z^112 + 1125*z^111 - 780*z^110 - 1305*z^109 - 715*z^108 - 1403*z^107 - 518*z^106 + 11*z^105 - 936*z^104 + 544*z^103 - 1190*z^102 + 1407*z^101 + 1079*z^100 + 325*z^99 + 278*z^98 + 788*z^97 - 236*z^96 - 1304*z^95 - 1385*z^94 + 1484*z^93 - 771*z^92 - 15*z^91 - 195*z^90 - 799*z^89 - 772*z^88 - 1269*z^87 - 716*z^86 + 1201*z^85 - 199*z^84 + 900*z^83 - 593*z^82 - 1512*z^81 - 1019*z^80 + 1379*z^79 - 753*z^78 + 892*z^77 + 1000*z^76 - 848*z^75 + 41*z^74 + 611*z^73 + 456*z^72 + 1624*z^71 + 262*z^70 + 1112*z^69 - 1527*z^68 - 438*z^67 + 902*z^66 - 1338*z^65 - 1350*z^64 - 1014*z^63 + 1085*z^62 + 511*z^61 - 1236*z^60 + 887*z^59 + 784*z^58 - 966*z^57 - 1174*z^56 - 1236*z^55 + 1206*z^54 - 597*z^53 - 1004*z^52 - 941*z^51 - 1251*z^50 - 543*z^49 - 529*z^48 - 443*z^47 + 796*z^46 - 814*z^45 - 1347*z^44 + 1469*z^43 + 406*z^42 - 551*z^41 + 1408*z^40 + 1605*z^39 + 1481*z^38 + 829*z^37 - 917*z^36 - 1527*z^35 - 1469*z^34 - 1533*z^33 + 143*z^32 - 1221*z^31 - 887*z^30 - 1653*z^29 + 315*z^28 - 125*z^27 - 1373*z^26 + 1026*z^25 - 234*z^24 + 1380*z^23 - 1019*z^22 + 817*z^21 + 716*z^20 - 53*z^19 - 215*z^18 + 1355*z^17 - 184*z^16 - 1364*z^15 + 1269*z^14 - 1402*z^13 - 771*z^12 + 672*z^11 + 66*z^10 - 846*z^9 - 1208*z^8 + 563*z^7 - 1457*z^6 + 259*z^5 + 1486*z^4 - 556*z^3 + 622*z^2 - 164*z + 550, 59*z^127 - 782*z^126 - 80*z^125 - 426*z^124 - 1524*z^123 + 138*z^122 - 646*z^121 + 192*z^120 + 1125*z^119 + 845*z^118 + 948*z^117 - 503*z^116 + 721*z^115 + 158*z^114 + 1543*z^113 - 1638*z^112 - 197*z^111 + 1577*z^110 + 1585*z^109 + 1389*z^108 - 106*z^107 + 1612*z^106 - 289*z^105 - 365*z^104 + 101*z^103 + 354*z^102 - 1037*z^101 + 1388*z^100 - 592*z^99 + 181*z^98 + 454*z^97 - 702*z^96 + 501*z^95 + 904*z^94 - 133*z^93 - 1644*z^92 + 1446*z^91 + 917*z^90 + 1520*z^89 + 1620*z^88 + 971*z^87 + 1398*z^86 - 1386*z^85 + 1130*z^84 + 862*z^83 + 88*z^82 - 1083*z^81 + 782*z^80 - 1138*z^79 + 845*z^78 - 1318*z^77 - 769*z^76 - 226*z^75 + 311*z^74 - 536*z^73 + 287*z^72 + 47*z^71 + 547*z^70 + 249*z^69 - 1470*z^68 + 683*z^67 - 152*z^66 - 1430*z^65 - 147*z^64 + 388*z^63 + 1145*z^62 + 99*z^61 - 646*z^60 - 942*z^59 + 1472*z^58 + 225*z^57 - 412*z^56 - 243*z^55 + 1642*z^54 - 51*z^53 + 1028*z^52 - 1476*z^51 + 1375*z^50 + 938*z^49 - 1304*z^48 - 120*z^47 - 123*z^46 - 1479*z^45 - 1338*z^44 + 257*z^43 + 1562*z^42 - 1413*z^41 - 730*z^40 - 1024*z^39 - 1134*z^38 + 963*z^37 + 142*z^36 - 147*z^35 - 1292*z^34 - 1295*z^33 - 387*z^32 + 1447*z^31 + 1182*z^30 + 10*z^29 - 1656*z^28 - 110*z^27 - 592*z^26 - 1454*z^25 - 328*z^24 - 1001*z^23 - 751*z^22 - 127*z^21 - 467*z^20 - 583*z^19 - 909*z^18 - 122*z^17 - 177*z^16 - 1503*z^15 + 1409*z^14 - 1343*z^13 - 715*z^12 + 1261*z^11 + 1100*z^10 - 929*z^9 - 1314*z^8 + 1207*z^7 + 1474*z^6 + 590*z^5 - 1302*z^4 - 1233*z^3 + 862*z^2 + 354*z - 1358, 511*z^127 + 892*z^126 + 786*z^125 + 1358*z^124 + 301*z^123 + 620*z^122 - 481*z^121 + 1353*z^120 + 408*z^119 - 732*z^118 + 879*z^117 - 779*z^116 + 974*z^115 - 1417*z^114 - 255*z^113 - 1183*z^112 - 593*z^111 - 271*z^110 - 1592*z^109 + 1552*z^108 + 1482*z^107 - 1574*z^106 + 77*z^105 + 219*z^104 + 1193*z^103 + 1598*z^102 + 40*z^101 - 677*z^100 + 978*z^99 - 900*z^98 + 1323*z^97 - 176*z^96 - 1091*z^95 - 299*z^94 + 616*z^93 - 1060*z^92 + 671*z^91 + 786*z^90 + 1123*z^89 + 1547*z^88 + 1214*z^87 - 1076*z^86 - 1463*z^85 - 1201*z^84 - 488*z^83 - 584*z^82 - 530*z^81 + 145*z^80 + 327*z^79 - 964*z^78 + 868*z^77 - 1112*z^76 - 939*z^75 - 955*z^74 + 851*z^73 - 1030*z^72 - 992*z^71 - 1560*z^70 + 488*z^69 - 372*z^68 - 157*z^67 + 382*z^66 - 364*z^65 + 1348*z^64 - 417*z^63 + 262*z^62 + 991*z^61 - 1471*z^60 + 803*z^59 - 1000*z^58 + 1616*z^57 + 1485*z^56 - 963*z^55 - 1020*z^54 + 1381*z^53 - 1048*z^52 + 130*z^51 + 1528*z^50 + 986*z^49 + 1239*z^48 - 1454*z^47 + 1095*z^46 - 639*z^45 - 190*z^44 - 689*z^43 - 1351*z^42 - 1242*z^41 - 550*z^40 - 1180*z^39 - 761*z^38 - 1067*z^37 - 1565*z^36 + 404*z^35 - 821*z^34 + 1449*z^33 - 1377*z^32 + 507*z^31 - 691*z^30 + 604*z^29 - 1649*z^28 + 350*z^27 - 1568*z^26 - 872*z^25 - 944*z^24 - 242*z^23 + 84*z^22 + 240*z^21 + 646*z^20 - 1513*z^19 + 40*z^18 + 266*z^17 - 1232*z^16 - 56*z^15 + 800*z^14 + 1335*z^13 + 1472*z^12 - 1042*z^11 + 636*z^10 - 1620*z^9 + 780*z^8 - 158*z^7 + 818*z^6 - 911*z^5 - 498*z^4 - 1380*z^3 - 1287*z^2 + 820*z - 335] b = [-395*z^127 - 347*z^126 + 654*z^125 - 1469*z^124 + 318*z^123 + 325*z^122 - 20*z^121 - 516*z^120 + 159*z^119 + 102*z^118 + 825*z^117 - 943*z^116 - 767*z^115 - 1662*z^114 - 1556*z^113 + 1638*z^112 - 103*z^111 + 1408*z^110 + 1047*z^109 + 169*z^108 - 1205*z^107 - 1025*z^106 - 128*z^105 - 391*z^104 + 1653*z^103 + 441*z^102 - 1430*z^101 + 187*z^100 - 417*z^99 + 468*z^98 + 635*z^97 + 816*z^96 - 1590*z^95 - 822*z^94 - 626*z^93 + 73*z^92 - 206*z^91 + 573*z^90 + 81*z^89 - 620*z^88 - 764*z^87 - 831*z^86 + 1356*z^85 - 106*z^84 - 950*z^83 + 664*z^82 + 453*z^81 - 1663*z^80 - 1410*z^79 + 1243*z^78 + 213*z^77 - 55*z^76 + 814*z^75 - 81*z^74 - 1272*z^73 + 1513*z^72 + 687*z^71 + 519*z^70 + 55*z^69 + 1540*z^68 - 1234*z^67 - 1046*z^66 - 1049*z^65 - 1479*z^64 - 302*z^63 - 496*z^62 + 1586*z^61 - 825*z^60 - 123*z^59 - 1020*z^58 - 1416*z^57 + 623*z^56 - 615*z^55 + 760*z^54 + 1155*z^53 - 1143*z^52 + 1037*z^51 - 478*z^50 - 531*z^49 + 1380*z^48 + 1111*z^47 - 258*z^46 + 884*z^45 - 1491*z^44 + 1132*z^43 - 1184*z^42 - 1397*z^41 + 238*z^40 - 128*z^39 + 642*z^38 + 763*z^37 + 927*z^36 + 1121*z^35 - 441*z^34 + 22*z^33 + 1167*z^32 + 1512*z^31 - 402*z^30 + 1261*z^29 + 750*z^28 - 1469*z^27 - 931*z^26 + 616*z^25 + 229*z^24 + 517*z^23 + 145*z^22 - 112*z^21 + 493*z^20 - 981*z^19 + 796*z^18 - 1196*z^17 + 702*z^16 + 1423*z^15 + 978*z^14 + 1312*z^13 - 183*z^12 - 386*z^11 + 585*z^10 + 1473*z^9 - 1137*z^8 + 918*z^7 + 1539*z^6 - 193*z^5 + 861*z^4 - 315*z^3 - 529*z^2 + 866*z + 1234, -1263*z^127 + 785*z^126 - 515*z^125 - 1149*z^124 - 1165*z^123 - 1111*z^122 - 628*z^121 + 962*z^120 - 1277*z^119 + 1546*z^118 - 13*z^117 + 1237*z^116 + 1397*z^115 - 1056*z^114 - 172*z^113 - 1048*z^112 - 782*z^111 + 430*z^110 - 881*z^109 + 566*z^108 + 67*z^107 - 29*z^106 - 889*z^105 + 1233*z^104 - 1208*z^103 + 497*z^102 - 416*z^101 + 653*z^100 + 1639*z^99 + 516*z^98 - 65*z^97 - 1068*z^96 - 799*z^95 + 324*z^94 + 302*z^93 + 382*z^92 - 123*z^91 - 158*z^90 + 279*z^89 - 896*z^88 + 329*z^87 - 696*z^86 + 1240*z^85 + 315*z^84 + 1113*z^83 - 741*z^82 + 178*z^81 + 186*z^80 - 1171*z^79 + 1126*z^78 - 908*z^77 - 1643*z^76 + 193*z^75 + 1372*z^74 - 793*z^73 + 1544*z^72 - 1330*z^71 + 295*z^70 + 1172*z^69 - 1159*z^68 + 696*z^67 - 718*z^66 - 1587*z^65 + 1007*z^64 - 323*z^63 - 258*z^62 - 125*z^61 - 704*z^60 - 375*z^59 + 1362*z^58 + 97*z^57 - 512*z^56 + 785*z^55 + 1398*z^54 + 1048*z^53 - 926*z^52 + 121*z^51 + 1559*z^50 + 308*z^49 - 72*z^48 - 1050*z^47 + 190*z^46 + 868*z^45 - 1248*z^44 - 1498*z^43 - 658*z^42 + 228*z^41 + 661*z^40 - 670*z^39 - 500*z^38 - 594*z^37 + 1495*z^36 - 194*z^35 - 1119*z^34 + 1139*z^33 + 1268*z^32 - 1589*z^31 + 1133*z^30 - 123*z^29 + 93*z^28 - 859*z^27 - 1547*z^26 + 1274*z^25 - 695*z^24 - 1250*z^23 + 1406*z^22 - 1548*z^21 - 949*z^20 - 566*z^19 + 1542*z^18 + 96*z^17 + 195*z^16 + 149*z^15 - 1152*z^14 + 204*z^13 + 1202*z^12 + 505*z^11 - 1213*z^10 - 575*z^9 - 942*z^8 - 923*z^7 - 503*z^6 + 801*z^5 + 637*z^4 - 1143*z^3 - 506*z^2 + 138*z + 900] H = [z^127 - z^126 - z^125 + z^124 + 9*z^123 - z^122 - z^121 + 2*z^120 - 98*z^118 + 8*z^117 + 5*z^115 + 11*z^114 - 2*z^113 - z^111 + 10*z^110 - z^108 + z^106 - z^105 - 4*z^104 - z^103 - z^102 - 3*z^101 + 7*z^100 + z^99 + 50*z^98 + 17*z^97 - 3261*z^96 + z^94 + 2*z^93 + z^92 - z^91 + 14*z^90 + z^89 - z^88 + 4*z^87 - 51*z^86 + 7*z^85 - z^84 + z^83 - z^82 + 2*z^81 - 8*z^80 - z^79 + z^78 + 2*z^76 - 6*z^75 - z^74 - 2*z^73 - z^72 - 2*z^71 - z^69 - z^68 - 2*z^67 - 5*z^66 - 3*z^65 - 30*z^64 + 5*z^63 + z^62 - 4*z^61 - 2*z^60 - 9*z^59 + z^58 - 5*z^57 + 3*z^56 + 6*z^55 - 4*z^54 - z^53 - 3*z^52 - z^51 + 2*z^50 - 13*z^49 + 2*z^47 + z^46 - z^45 - 2*z^44 + 5*z^43 - z^42 + 5*z^41 - z^39 + z^37 - z^35 + z^34 - 3*z^33 + 6*z^32 - 2*z^31 - z^30 - 6*z^28 - z^26 + z^25 - z^24 + 3*z^23 - 8*z^21 - 10*z^20 - 17*z^19 + z^18 - z^16 - 2*z^15 + z^14 + z^13 + z^12 + z^11 + 10*z^10 - z^9 - z^8 - z^7 - 2*z^6 + z^5 - z^3 - z^2 + 12*z, z^126 + z^125 - 4*z^124 + z^123 + z^122 + z^121 - 4*z^119 + z^118 + z^117 - 19*z^116 - z^115 + 3*z^114 - 2*z^113 + z^112 + 5*z^111 + 3*z^110 + z^107 - z^106 - z^105 - 5*z^104 + 2*z^103 - z^102 - 3*z^100 - 8*z^99 + 4*z^98 + 2*z^95 + 13*z^94 - 2*z^93 + z^92 - z^90 - 3*z^88 + z^87 - z^86 + z^85 + z^84 - 2*z^83 - 6*z^81 - 5*z^78 - z^77 + z^76 + z^75 - z^74 - 2*z^73 + z^72 + 8*z^71 + z^70 + 3*z^69 - z^68 - 5*z^66 - z^64 - z^63 - 2*z^62 - 2*z^61 - 16*z^60 + z^59 + 8*z^58 - z^57 - z^56 - z^55 + z^54 + 3*z^53 + z^52 + 5*z^51 - z^50 - 3*z^49 - 4*z^47 + z^46 - z^45 + 5*z^43 + z^40 + z^39 + 2*z^38 - z^37 - z^36 + z^35 - z^34 - 2*z^33 + z^32 + z^31 - z^30 - z^29 + z^27 - 4*z^26 + 2*z^24 + z^23 + 2*z^22 + z^21 + 22*z^19 - z^18 + 2*z^16 + z^15 - z^14 + z^12 - 10*z^11 + z^10 - z^9 + z^8 - z^7 - z^6 - z^3 + z^2, -3*z^124 + 2*z^123 + 2*z^122 + z^121 - 67*z^120 + 2*z^119 + 2*z^118 + z^117 + 55*z^116 - 4*z^115 + z^114 - z^113 - 2*z^112 + 17*z^111 + 4*z^110 - z^109 + z^108 + z^107 + z^106 + z^104 + z^103 + 2*z^102 - z^101 - z^100 - z^99 + z^98 - 6*z^97 - z^96 - z^95 + z^92 - z^91 - z^90 + z^89 - 54*z^88 - z^86 - z^85 - z^84 - z^83 + z^82 + 3*z^81 + z^79 + z^77 - z^76 - 2*z^75 + 2*z^74 - z^73 - 2*z^72 + 2*z^71 - z^70 - z^69 - z^68 + z^67 - z^66 - 3*z^65 + z^64 - z^63 + z^62 + 48*z^60 - z^58 - 3*z^57 - 2*z^56 - z^54 - 4*z^53 + 8*z^52 - 3*z^51 - 56*z^50 + 3*z^49 - z^48 + z^45 + 24*z^44 - z^43 - 3*z^42 + z^40 + z^39 - z^38 + 2*z^37 - z^35 - z^34 - 3*z^33 + 2*z^31 - 42*z^29 - z^28 - 10*z^26 + z^25 + z^24 + 8*z^23 - z^22 + z^21 + 3*z^19 - 6*z^18 + 2*z^16 - z^15 - z^14 - z^13 + z^12 + 6*z^11 - 3*z^10 + z^8 + z^7 + 2*z^6 + 2*z^5 + z^4 + z^3 - 3*z^2 - 1, -z^127 + 2*z^126 - 16*z^125 - z^123 + z^122 + z^121 - 23*z^120 + z^119 + z^118 + 2*z^117 + z^116 + 5*z^115 + 8*z^114 - 5*z^113 + z^112 - z^111 + 5*z^110 + 2*z^108 + z^107 + 24*z^105 + 3*z^104 + z^103 - z^102 + 26*z^101 - 3*z^100 + 3*z^99 - z^98 + 3*z^97 + z^96 - z^94 - z^93 + z^92 - 4*z^90 - 3*z^88 - z^87 + 2*z^86 - 3*z^85 - 2*z^84 + z^83 - 2*z^82 + 6*z^80 + z^79 - z^78 + 8*z^77 - 2*z^76 - 3*z^75 - 2*z^74 - 2*z^73 + 3*z^71 + z^70 + z^69 - 2*z^67 - z^66 - 72*z^64 + 5*z^62 + 5*z^61 - 9*z^60 - z^59 + z^55 + z^54 - z^53 + z^52 + 3*z^51 + 15*z^50 + 3*z^49 - 3*z^48 - z^47 - z^45 - 7*z^44 - z^43 - 3*z^42 + 17*z^41 - z^37 - 3*z^36 + z^35 - 3*z^34 + z^32 - z^31 - z^30 + z^29 + 2*z^28 - z^26 + 2*z^25 + z^24 - 3*z^23 - 2*z^22 + 4*z^20 - 2*z^19 - z^18 + 2*z^17 + 6*z^15 - z^14 - z^13 - 2*z^12 - 2*z^11 + 2*z^9 + z^8 - 3*z^6 - 3*z^5 - z^4 - 4*z^3 + 2*z^2 - z] l2 = [-6125*z^127 - 2822*z^126 - 92*z^125 - 9474*z^124 - 2842*z^123 + 6910*z^122 - 4249*z^121 + 4443*z^120 - 6752*z^119 - 3199*z^118 - 6560*z^117 + 3735*z^116 + 10442*z^115 - 6547*z^114 - 3302*z^113 - 9315*z^112 + 6096*z^111 + 2825*z^110 + 8951*z^109 - 307*z^108 + 9340*z^107 - 2962*z^106 + 13486*z^105 + 3908*z^104 + 10228*z^103 - 6813*z^102 + 5772*z^101 + 12398*z^100 + 3491*z^99 + 13448*z^98 + 3687*z^97 - 748*z^96 - 361*z^95 + 7100*z^94 - 3617*z^93 + 6460*z^92 + 3983*z^91 + 7359*z^90 - 12602*z^89 - 3562*z^88 - 26786*z^87 - 280*z^86 - 3294*z^85 - 6302*z^84 - 6502*z^83 + 9983*z^82 + 6643*z^81 + 6723*z^80 - 10252*z^79 - 3047*z^78 - 665*z^77 + 10404*z^76 + 6441*z^75 - 6583*z^74 - 5947*z^73 + 9607*z^72 - 12514*z^71 + 131*z^70 - 3517*z^69 - 3115*z^68 + 13435*z^67 - 12509*z^66 - 6094*z^65 - 12622*z^64 + 2840*z^63 + 3166*z^62 + 2622*z^61 + 3362*z^60 - 3041*z^59 + 7126*z^58 - 3046*z^57 - 3350*z^56 - 432*z^55 + 6468*z^54 - 2885*z^53 + 470*z^52 - 3109*z^51 - 6331*z^50 - 3812*z^49 + 6021*z^48 - 3058*z^47 - 4180*z^46 + 3159*z^45 + 19359*z^44 - 6450*z^43 - 6568*z^42 - 13101*z^41 + 6179*z^40 - 13210*z^39 - 2478*z^38 - 3550*z^37 + 6556*z^36 + 3405*z^35 + 309*z^34 + 3076*z^33 + 9636*z^32 - 467*z^31 + 2596*z^30 + 13554*z^29 - 6653*z^28 - 16341*z^27 - 12422*z^26 + 10044*z^25 - 19304*z^24 - 6484*z^23 - 5988*z^22 - 3026*z^21 - 2853*z^20 - 3058*z^19 - 12863*z^18 - 537*z^17 + 2784*z^16 + 804*z^15 - 271*z^14 - 9575*z^13 + 13044*z^12 - 6387*z^11 - 464*z^10 - 10906*z^9 - 6056*z^8 + 137*z^7 - 12311*z^6 - 6797*z^5 + 111*z^4 + 9323*z^3 - 16100*z^2 - 3241*z + 216, 169*z^95 - 237*z^94 - 287*z^93 + 535*z^92 - 142*z^91 - 257*z^90 + 132*z^89 + 61*z^88 + 214*z^87 - 69*z^86 + 154*z^85 - 102*z^84 + 413*z^83 + 166*z^82 + 547*z^81 + 2*z^80 - 88*z^79 - 215*z^78 - 467*z^77 - 167*z^76 - 467*z^75 + 164*z^74 - 120*z^73 - 304*z^72 + 144*z^71 + 282*z^70 - 277*z^69 - 27*z^68 + 41*z^67 + 111*z^66 - 549*z^65 + 636*z^64 - 46*z^63 + 328*z^62 - 65*z^61 + 149*z^60 - 137*z^59 - 130*z^58 - 116*z^57 + 113*z^56 - 150*z^55 - 187*z^54 - 29*z^53 + 422*z^52 - 421*z^51 + 149*z^50 + 236*z^49 + 149*z^48 - 232*z^47 - 336*z^46 - 278*z^45 - 155*z^44 + 135*z^43 - 393*z^42 - 31*z^41 + 358*z^40 + 51*z^39 - 6*z^38 - 47*z^37 + 345*z^36 + 66*z^35 + 243*z^34 - 263*z^33 + 76*z^32 - 120*z^31 - 85*z^30 + 120*z^29 + 99*z^28 - 288*z^27 + 209*z^26 + 178*z^25 + 32*z^24 - 368*z^23 + 148*z^22 - 262*z^21 + 141*z^20 - 357*z^19 + 94*z^18 - 207*z^17 + 205*z^16 + 27*z^15 + 25*z^14 + 62*z^13 - 250*z^12 - 234*z^11 - 36*z^10 + 101*z^9 + 520*z^8 + 200*z^7 - 279*z^6 - 60*z^5 + 369*z^4 - 81*z^3 + 133*z^2 - 330*z + 227] enc = 0c8850f11526011aad008ba5fdb4335ea1985d2212bd017fd00dce2eae58b1fb46a65644768718d34bd67c921eb278e419c025b7f0ffbb6b24123946908dd4cb ``` ## Phân tích Đây cũng là lần đầu tiên mình gặp bài về ` CyclotomicField` , nó cũng khiến mình mất một thời gian ngồi research . Xong mình đơn giản hiểu nó là 1 trường số phức mà thôi , trong đó thì $z^n = 1$ và $z^{n/2} = -1$ . Các phép nhân còn lại thực hiện như bình thường . Ví dụ 1 phép nhân trong trường này nhé $(z^{30} + z^{125})*(z^{12}*z^{90}) = z^{42} + z^{120} + z^{137} + z^{215}$ $= z^{42} + z^{120} + z^{128}*z{9} + z^{128}*z{87}$ $= z^{42} + z^{120} - z^{9} - z^{27}$ Như ta thấy thì cứ thằng nào mà số mũ vượt qua 128 là tự động trừ đi rồi nhân thêm $-1$ vào hệ số của nó . ```python= q = 3329 k = 2 sigma = 2.5 n = 256 K = CyclotomicField(n,'z') OK = K.OK() OKq= OK.quotient(q,'y') a = K.gens()[0] print((a^30+a^125)*(a^12+a^90)) ``` Các bạn chạy thử để kiểm nghiệm nhé :smiley_cat: Vậy sau khi ta hiểu phép nhân rồi thì ta có thể làm gì với bài này . Bản thân mình lúc đầu nhìn vào thì thấy `A*s + e = b` thì nhìn thấy nó là `LWE` rồi nhưng để exploit từ dữ kiện `A,b` nhận được thì mình thấy no hope vl nên mình đá qua output còn lại là `H và l2` ```python= H = matrix(k,k,[ OK(list(random_vector(ZZ,n))) for _ in k*k*"_"] ) l = s*H # I won't give you this 3:) h = floor(.25*n/2) l2 = matrix([l[0,0] , OK(l[0,1].list()[:-h]) ]) ``` Thì như ta thấy nó sẽ thực hiện 1 phép nhân $l=s*H$ và cho ta biết phần tử đầu tiên của $l$ và 96 phần tử đầu tiên của $l$ . > Chú ý : Ở đây s là nhân bên trái , tức solve_left nhé , chứ không phải solve_right , chỉ vì cái này mà mình không giải được :crying_cat_face: Ta có : `s = matrix(K, [K(random_vector(ZZ,n//2,sigma,distribution="gaussian").list()) for __ in k*"_"] )` Tức `s` là 1 matrix $2x1$ và sẽ có dạng kiểu : $[x_1*z^{127} + x_2*z^{126} + ... + x_{128}*z^0]$ - $s1$ $[y_1*z^{127} + y_2*z^{126} + ... + y_{128}*z^0]$ - $s2$ Và nó sẽ nhân với`H` , thì mình sẽ đặt các $s$ như trên rồi nhân với $H$ luôn , và sẽ nhóm các phần tử chung $z^{127},z^{126} , ..,z^{0}$ với nhau rồi so sánh với giá trị trong $l$ , ứng với từng $z$ mình sẽ có 1 phương trình Ở đây $l2[0]$ cho ta $128$ giá trị và $l2[1]$ cho ta $96$ giá trị là 224 giá trị , tức 224 phương trình , tuy chưa để solve_left nhưng đủ để ta giải bằng LLL hoặc tools của Blupper rồi . Link : https://raw.githubusercontent.com/TheBlupper/linineq/main/linineq.py Cho bạn nào chưa rõ về phương trình tạo như nào mình sẽ có 1 ví dụ nhỏ ở dưới đây nhé : $s = (x_1*z^2 + x_2*z)*(3*z^2 + 2) = 3*x_1*z^4 + 2*x_1*z^2 + 3*x_2*z^2 + 2*x_2*z$ $s = 3*x_1*z^4 + (2*x_1+3*x_2)*z^2 + 2*x_2*z$ Thì giá sử mình biết nó có các phần tử của $z,z^2$ là $4,10$ thì mình có thể tìm được $x1,x2$ . Ở đây thì nó là : $H[0]*s_1 + H[1]*s_2 = l2[0]$ $H[2]*s_1 + H[1]*s_2 = l2[1]$ Mình cũng thực hiện phép nhân rồi lấy các hệ số tương ứng với $z^{127} , .. z^0$ và kết quả của hệ số đó thì ta sẽ lấy ở $l2$ Giờ thì mình sẽ nhờ thực hiện phép nhân để lấy hệ số của từng thằng $z^{127}, z^{126} , .. , z^0$ ra thôi. Cái này thực hiện như phép nhân bình thường chỉ khác chỗ $z^{128}$ mình nói ở trên , khi vượt quá thì số mũ tự động trừ đi $128$ và hệ số nhân thêm $-1$ ```python= import sympy as sp import re z = sp.symbols('z') x = sp.symbols('x_0:128') y = sp.symbols('y_0:128') poly1 = sum(x[i] * z**(127 - i) for i in range(128)) poly2 = (z**127 - z**126 - z**125 + z**124 + 9*z**123 - z**122 - z**121 + 2*z**120 - 98*z**118 + 8*z**117 + 5*z**115 + 11*z**114 - 2*z**113 - z**111 + 10*z**110 - z**108 + z**106 - z**105 - 4*z**104 - z**103 - z**102 - 3*z**101 + 7*z**100 + z**99 + 50*z**98 + 17*z**97 - 3261*z**96 + z**94 + 2*z**93 + z**92 - z**91 + 14*z**90 + z**89 - z**88 + 4*z**87 - 51*z**86 + 7*z**85 - z**84 + z**83 - z**82 + 2*z**81 - 8*z**80 - z**79 + z**78 + 2*z**76 - 6*z**75 - z**74 - 2*z**73 - z**72 - 2*z**71 - z**69 - z**68 - 2*z**67 - 5*z**66 - 3*z**65 - 30*z**64 + 5*z**63 + z**62 - 4*z**61 - 2*z**60 - 9*z**59 + z**58 - 5*z**57 + 3*z**56 + 6*z**55 - 4*z**54 - z**53 - 3*z**52 - z**51 + 2*z**50 - 13*z**49 + 2*z**47 + z**46 - z**45 - 2*z**44 + 5*z**43 - z**42 + 5*z**41 - z**39 + z**37 - z**35 + z**34 - 3*z**33 + 6*z**32 - 2*z**31 - z**30 - 6*z**28 - z**26 + z**25 - z**24 + 3*z**23 - 8*z**21 - 10*z**20 - 17*z**19 + z**18 - z**16 - 2*z**15 + z**14 + z**13 + z**12 + z**11 + 10*z**10 - z**9 - z**8 - z**7 - 2*z**6 + z**5 - z**3 - z**2 + 12*z) product_poly1 = poly1 * poly2 poly3 = sum(y[i] * z**(127 - i) for i in range(128)) poly4 = (z**126 + z**125 - 4*z**124 + z**123 + z**122 + z**121 - 4*z**119 + z**118 + z**117 - 19*z**116 - z**115 + 3*z**114 - 2*z**113 + z**112 + 5*z**111 + 3*z**110 + z**107 - z**106 - z**105 - 5*z**104 + 2*z**103 - z**102 - 3*z**100 - 8*z**99 + 4*z**98 + 2*z**95 + 13*z**94 - 2*z**93 + z**92 - z**90 - 3*z**88 + z**87 - z**86 + z**85 + z**84 - 2*z**83 - 6*z**81 - 5*z**78 - z**77 + z**76 + z**75 - z**74 - 2*z**73 + z**72 + 8*z**71 + z**70 + 3*z**69 - z**68 - 5*z**66 - z**64 - z**63 - 2*z**62 - 2*z**61 - 16*z**60 + z**59 + 8*z**58 - z**57 - z**56 - z**55 + z**54 + 3*z**53 + z**52 + 5*z**51 - z**50 - 3*z**49 - 4*z**47 + z**46 - z**45 + 5*z**43 + z**40 + z**39 + 2*z**38 - z**37 - z**36 + z**35 - z**34 - 2*z**33 + z**32 + z**31 - z**30 - z**29 + z**27 - 4*z**26 + 2*z**24 + z**23 + 2*z**22 + z**21 + 22*z**19 - z**18 + 2*z**16 + z**15 - z**14 + z**12 - 10*z**11 + z**10 - z**9 + z**8 - z**7 - z**6 - z**3 + z**2) result_poly = poly1*poly2 + poly3*poly4 result_poly_simplified = sp.expand(result_poly) adjusted_terms = {} for term in result_poly_simplified.as_ordered_terms(): coeff, z_exp = term.as_coeff_exponent(z) if z_exp > 127: new_exp = z_exp - 128 coeff *= -1 else: new_exp = z_exp if new_exp in adjusted_terms: adjusted_terms[new_exp] += coeff else: adjusted_terms[new_exp] = coeff adjusted_poly = sum(coeff * z**exp for exp, coeff in adjusted_terms.items()) coefficients = [adjusted_terms.get(i, 0) for i in range(128)] poly5 = (-3*z**124 + 2*z**123 + 2*z**122 + z**121 - 67*z**120 + 2*z**119 + 2*z**118 + z**117 + 55*z**116 - 4*z**115 + z**114 - z**113 - 2*z**112 + 17*z**111 + 4*z**110 - z**109 + z**108 + z**107 + z**106 + z**104 + z**103 + 2*z**102 - z**101 - z**100 - z**99 + z**98 - 6*z**97 - z**96 - z**95 + z**92 - z**91 - z**90 + z**89 - 54*z**88 - z**86 - z**85 - z**84 - z**83 + z**82 + 3*z**81 + z**79 + z**77 - z**76 - 2*z**75 + 2*z**74 - z**73 - 2*z**72 + 2*z**71 - z**70 - z**69 - z**68 + z**67 - z**66 - 3*z**65 + z**64 - z**63 + z**62 + 48*z**60 - z**58 - 3*z**57 - 2*z**56 - z**54 - 4*z**53 + 8*z**52 - 3*z**51 - 56*z**50 + 3*z**49 - z**48 + z**45 + 24*z**44 - z**43 - 3*z**42 + z**40 + z**39 - z**38 + 2*z**37 - z**35 - z**34 - 3*z**33 + 2*z**31 - 42*z**29 - z**28 - 10*z**26 + z**25 + z**24 + 8*z**23 - z**22 + z**21 + 3*z**19 - 6*z**18 + 2*z**16 - z**15 - z**14 - z**13 + z**12 + 6*z**11 - 3*z**10 + z**8 + z**7 + 2*z**6 + 2*z**5 + z**4 + z**3 - 3*z**2 - 1) poly6 = (-z**127 + 2*z**126 - 16*z**125 - z**123 + z**122 + z**121 - 23*z**120 + z**119 + z**118 + 2*z**117 + z**116 + 5*z**115 + 8*z**114 - 5*z**113 + z**112 - z**111 + 5*z**110 + 2*z**108 + z**107 + 24*z**105 + 3*z**104 + z**103 - z**102 + 26*z**101 - 3*z**100 + 3*z**99 - z**98 + 3*z**97 + z**96 - z**94 - z**93 + z**92 - 4*z**90 - 3*z**88 - z**87 + 2*z**86 - 3*z**85 - 2*z**84 + z**83 - 2*z**82 + 6*z**80 + z**79 - z**78 + 8*z**77 - 2*z**76 - 3*z**75 - 2*z**74 - 2*z**73 + 3*z**71 + z**70 + z**69 - 2*z**67 - z**66 - 72*z**64 + 5*z**62 + 5*z**61 - 9*z**60 - z**59 + z**55 + z**54 - z**53 + z**52 + 3*z**51 + 15*z**50 + 3*z**49 - 3*z**48 - z**47 - z**45 - 7*z**44 - z**43 - 3*z**42 + 17*z**41 - z**37 - 3*z**36 + z**35 - 3*z**34 + z**32 - z**31 - z**30 + z**29 + 2*z**28 - z**26 + 2*z**25 + z**24 - 3*z**23 - 2*z**22 + 4*z**20 - 2*z**19 - z**18 + 2*z**17 + 6*z**15 - z**14 - z**13 - 2*z**12 - 2*z**11 + 2*z**9 + z**8 - 3*z**6 - 3*z**5 - z**4 - 4*z**3 + 2*z**2 - z) result_poly = poly1*poly5 + poly3*poly6 result_poly_simplified = sp.expand(result_poly) adjusted_terms = {} for term in result_poly_simplified.as_ordered_terms(): coeff, z_exp = term.as_coeff_exponent(z) if z_exp > 127: new_exp = z_exp - 128 coeff *= -1 else: new_exp = z_exp if new_exp in adjusted_terms: adjusted_terms[new_exp] += coeff else: adjusted_terms[new_exp] = coeff adjusted_poly = sum(coeff * z**exp for exp, coeff in adjusted_terms.items()) coefficients_2 = [adjusted_terms.get(i, 0) for i in range(128)] multi = [] coeffis = coefficients + coefficients_2 with open('test.txt' , 'w') as f : for i in coeffis : f.write(str(i) + '\n') ``` Nó chạy khá lâu đấy nên mình sẽ để luôn file test.txt ở đây , ờ ừm nope bị giới hạn từ r , các bạn tự chạy hen =)) Mình không nhân trực tiếp được bằng sage , do khi nó nhân thì nó không giữ nguyên $z$ nữa mà bị biến về dạng số phức rồi. Sau khi có hệ số thì ta chú ý 1 chút về phép nhân ma trận ta thực hiện , ở đây là $s*H$ nên $s$ sẽ nhân các phần tử theo hàng dọc chứ không phải hàng ngang :crying_cat_face: Nên sau khi ta lấy hệ số nhân ta phải chuyển vị nó lại và lấy 224 hàng đầu tiên là sẽ có được hệ số nhân đúng cho việc solve_right :crying_cat_face: ```python= import re import sympy as sp multi = [] f = open('test.txt' , 'r') for _ in range(256) : expression = str(f.readline()) x_coeffs = [0] * 128 y_coeffs = [0] * 128 expression = expression.replace(' ', '') matches = re.findall(r'([+-]?\d*)\*?(x|y)_(\d+)', expression) for match in matches: coeff_str, var, index_str = match index = int(index_str) if coeff_str == '' or coeff_str == '+': coeff = 1 elif coeff_str == '-': coeff = -1 else: coeff = int(coeff_str) if var == 'x': if 0 <= index < 128: x_coeffs[index] = coeff elif var == 'y': if 0 <= index < 128: y_coeffs[index] = coeff coefficients = x_coeffs + y_coeffs multi.append(coefficients) from linineq import * coefficients = [ 216, -3241, -16100, 9323, 111, -6797, -12311, 137, -6056, -10906, -464, -6387, 13044, -9575, -271, 804, 2784, -537, -12863, -3058, -2853, -3026, -5988, -6484, -19304, 10044, -12422, -16341, -6653, 13554, 2596, -467, 9636, 3076, 309, 3405, 6556, -3550, -2478, -13210, 6179, -13101, -6568, -6450, 19359, 3159, -4180, -3058, 6021, -3812, -6331, -3109, 470, -2885, 6468, -432, -3350, -3046, 7126, -3041, 3362, 2622, 3166, 2840, -12622, -6094, -12509, 13435, -3115, -3517, 131, -12514, 9607, -5947, -6583, 6441, 10404, -665, -3047, -10252, 6723, 6643, 9983, -6502, -6302, -3294, -280, -26786, -3562, -12602, 7359, 3983, 6460, -3617, 7100, -361, -748, 3687, 13448, 3491, 12398, 5772, -6813, 10228, 3908, 13486, -2962, 9340, -307, 8951, 2825, 6096, -9315, -3302, -6547, 10442, 3735, -6560, -3199, -6752, 4443, -4249, 6910, -2842, -9474, -92, -2822, -6125 ] coefficients2 = [ 227, -330, 133, -81, 369, -60, -279, 200, 520, 101, -36, -234, -250, 62, 25, 27, 205, -207, 94, -357, 141, -262, 148, -368, 32, 178, 209, -288, 99, 120, -85, -120, 76, -263, 243, 66, 345, -47, -6, 51, 358, -31, -393, 135, -155, -278, -336, -232, 149, 236, 149, -421, 422, -29, -187, -150, 113, -116, -130, -137, 149, -65, 328, -46, 636, -549, 111, 41, -27, -277, 282, 144, -304, -120, 164, -467, -167, -467, -215, -88, 2, 547, 166, 413, -102, 154, -69, 214, 61, 132, -257, -142, 535, -287, -237, 169 ] print(len(coefficients) , len(coefficients2)) coe = coefficients + coefficients2 M = Matrix(multi).T M2 = [] for i in range(224) : M2.append(M[i]) M2 = Matrix(M2) b = vector(coe) s = solve_bounded(M2,b,[-10]*256,[10]*256) q = 3329 k = 2 sigma = 2.5 n = 256 K = CyclotomicField(n,'z') OK = K.OK() OKq= OK.quotient(q,'y') a = K.gens()[0] s1 , s2 = s[:128] , s[128:] poly1 = sum(s1[i] * a**(127 - i) for i in range(128)) print(poly1) poly2 = sum(s2[i] * a**(127 - i) for i in range(128)) print(poly2) ``` Sau khi có $s$ thì mọi chuyển trở nên đơn giản rồi , ta chỉ cần lấy $b - A*s$ là ra e , rồi decrypt flag thôi . ```python= s = vector([poly1,poly2]) e = (b-s*A).change_ring(OKq) key = sha256(str(matrix(s)).encode()).digest()[:16] iv = sha256(str(matrix(e)).encode()).digest()[:16] cipher= AES.new(key,AES.MODE_CBC,iv=iv) print(cipher.decrypt(enc)) ``` Flag : ```CSCTF{wh4t_1f_my_h1nt_i5_4lgbr4!c????0x54763498142}```