Home Modular Arithmetic CryptoHack Writeup
Post
Cancel

Modular Arithmetic CryptoHack Writeup

These is the beginning of my writeups for the CryptoHack challenges. I will be starting with the Modular Math challenges.

Quadratic Residues

We need to do simple brute force on all the values in the field as prime p is very small. We can use the following code to solve the challenge.

1
2
3
4
5
6
7
8
9
p = 29
ints = [14, 6, 11]
flag = 100000 # max
for n in ints:
    for a in range(1,29):
        if pow(a,2,p) == n:
            flag = min(flag,a)
print(flag)
# Answer: 8

Legendre Symbol

We have to divide this problem into two part. First find the quadratic residue from the given ints list and then find the square root of the quadratic residue. Given that p = 3 (mod 4), we can show that the square root of a quadratic residue is given by pow(a, (p+1)//4, p). This is the link to the proof.

Basically we do the following thing Legendre Symbol

here a ^ (p-1)/2 is congruent to 1 (mod p) as p is prime a ^ (p+1)/4 is the square root of a.

1
2
3
4
5
6
7
8
9
10
11
p = 101524035174539890485408575671085261788758965189060164484385690801466167356667036677932998889725476582421738788500738738503134356158197247473850273565349249573867251280253564698939768700489401960767007716413932851838937641880157263936985954881657889497583485535527613578457628399173971810541670838543309159139

ints = [25081841204695904475894082974192007718642931811040324543182130088804239047149283334700530600468528298920930150221871666297194395061462592781551275161695411167049544771049769000895119729307495913024360169904315078028798025169985966732789207320203861858234048872508633514498384390497048416012928086480326832803, 45471765180330439060504647480621449634904192839383897212809808339619841633826534856109999027962620381874878086991125854247108359699799913776917227058286090426484548349388138935504299609200377899052716663351188664096302672712078508601311725863678223874157861163196340391008634419348573975841578359355931590555, 17364140182001694956465593533200623738590196990236340894554145562517924989208719245429557645254953527658049246737589538280332010533027062477684237933221198639948938784244510469138826808187365678322547992099715229218615475923754896960363138890331502811292427146595752813297603265829581292183917027983351121325, 14388109104985808487337749876058284426747816961971581447380608277949200244660381570568531129775053684256071819837294436069133592772543582735985855506250660938574234958754211349215293281645205354069970790155237033436065434572020652955666855773232074749487007626050323967496732359278657193580493324467258802863, 4379499308310772821004090447650785095356643590411706358119239166662089428685562719233435615196994728767593223519226235062647670077854687031681041462632566890129595506430188602238753450337691441293042716909901692570971955078924699306873191983953501093343423248482960643055943413031768521782634679536276233318, 85256449776780591202928235662805033201684571648990042997557084658000067050672130152734911919581661523957075992761662315262685030115255938352540032297113615687815976039390537716707854569980516690246592112936796917504034711418465442893323439490171095447109457355598873230115172636184525449905022174536414781771, 50576597458517451578431293746926099486388286246142012476814190030935689430726042810458344828563913001012415702876199708216875020997112089693759638454900092580746638631062117961876611545851157613835724635005253792316142379239047654392970415343694657580353333217547079551304961116837545648785312490665576832987, 96868738830341112368094632337476840272563704408573054404213766500407517251810212494515862176356916912627172280446141202661640191237336568731069327906100896178776245311689857997012187599140875912026589672629935267844696976980890380730867520071059572350667913710344648377601017758188404474812654737363275994871, 4881261656846638800623549662943393234361061827128610120046315649707078244180313661063004390750821317096754282796876479695558644108492317407662131441224257537276274962372021273583478509416358764706098471849536036184924640593888902859441388472856822541452041181244337124767666161645827145408781917658423571721, 18237936726367556664171427575475596460727369368246286138804284742124256700367133250078608537129877968287885457417957868580553371999414227484737603688992620953200143688061024092623556471053006464123205133894607923801371986027458274343737860395496260538663183193877539815179246700525865152165600985105257601565]

a = 0
for i in ints:
    if pow(i,(p-1)//2,p) == 1:
        a = i
        break

print(pow(a,(p+1)//4,p))

Modular Square Root

In the problem Legendre Symbol we have already found the square root of the quadratic residue for the prime where p satisfies the condition p = 3 (mod 4). We now need to similarly handle the case where p can also be p = 1 (mod 4).

  • Sage Math have a built in function to find the square root of a quadratic residue. We can use the following code to solve the challenge.

Chinese Remainder Theorem

The given question is a simple application of the Chinese Remainder Theorem. To solve this programatically we will be using Gauss algorithm to find the value of x.

  • Gauss Algorithm
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    def ChineseRemainderGauss(n,N,a):
      # n is the list of moduli
      # N is the product of all moduli
      # a is the list of remainders
      # x is the solution
      x = 0
      for i in range(len(n)):
          ai = a[i]
          ni = N//n[i]
          x += ai * ni * invmod(bi,n[i])
      return x%N
    
  • Function to find iverse modulo of a number (Extended Euclidean Algorithm).
    1
    2
    3
    4
    5
    6
    7
    
    def invmod(x, y):
      x0, x1, y0, y1 = 1, 0, 0, 1
      while y > 0:
          q, x, y = math.floor(x / y), y, x % y
          x0, x1 = x1, x0 - q * x1
          y0, y1 = y1, y0 - q * y1
      return x0 % y
    

Adrien’s Signs

This challenge does not introduce any new concept and can be solved using concpets learnt in previous chals. We have been given a script source.py which is used to encode the flag.

Interpreting source.py

We iterate through each char of the flag and convert the ASCII value to binary string of size 8 and append them in a string plaintext. Then for corresponding to each bit we generate a random n and append it in the list if bit is 1 or else we append -n % p. The resulting list is provided as output.txt. We have to find a way to get back the binary string plaintext then we can extract the flag from it.

compute p % 4 it will result into 3. Hence p is of type 3 (mod 4). So if the value of pow(x,(p-1)//2,p) == 1 then the corresponding bit will 1 else 0. Because when we do the above for -n%p it will give pow(x,(p-1)//2,p) == -1.

Here is the code for this chal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
encFlag = [67594220461269, 501237540280788, 718316769824518, 296304224247167, 48290626940198, 30829701196032, 521453693392074, 840985324383794, 770420008897119, 745131486581197, 729163531979577, 334563813238599, 289746215495432, 538664937794468, 894085795317163, 983410189487558, 863330928724430, 996272871140947, 352175210511707, 306237700811584, 631393408838583, 589243747914057, 538776819034934, 365364592128161, 454970171810424, 986711310037393, 657756453404881, 388329936724352, 90991447679370, 714742162831112, 62293519842555, 653941126489711, 448552658212336, 970169071154259, 339472870407614, 406225588145372, 205721593331090, 926225022409823, 904451547059845, 789074084078342, 886420071481685, 796827329208633, 433047156347276, 21271315846750, 719248860593631, 534059295222748, 879864647580512, 918055794962142, 635545050939893, 319549343320339, 93008646178282, 926080110625306, 385476640825005, 483740420173050, 866208659796189, 883359067574584, 913405110264883, 898864873510337, 208598541987988, 23412800024088, 911541450703474, 57446699305445, 513296484586451, 180356843554043, 756391301483653, 823695939808936, 452898981558365, 383286682802447, 381394258915860, 385482809649632, 357950424436020, 212891024562585, 906036654538589, 706766032862393, 500658491083279, 134746243085697, 240386541491998, 850341345692155, 826490944132718, 329513332018620, 41046816597282, 396581286424992, 488863267297267, 92023040998362, 529684488438507, 925328511390026, 524897846090435, 413156582909097, 840524616502482, 325719016994120, 402494835113608, 145033960690364, 43932113323388, 683561775499473, 434510534220939, 92584300328516, 763767269974656, 289837041593468, 11468527450938, 628247946152943, 8844724571683, 813851806959975, 72001988637120, 875394575395153, 70667866716476, 75304931994100, 226809172374264, 767059176444181, 45462007920789, 472607315695803, 325973946551448, 64200767729194, 534886246409921, 950408390792175, 492288777130394, 226746605380806, 944479111810431, 776057001143579, 658971626589122, 231918349590349, 699710172246548, 122457405264610, 643115611310737, 999072890586878, 203230862786955, 348112034218733, 240143417330886, 927148962961842, 661569511006072, 190334725550806, 763365444730995, 516228913786395, 846501182194443, 741210200995504, 511935604454925, 687689993302203, 631038090127480, 961606522916414, 138550017953034, 932105540686829, 215285284639233, 772628158955819, 496858298527292, 730971468815108, 896733219370353, 967083685727881, 607660822695530, 650953466617730, 133773994258132, 623283311953090, 436380836970128, 237114930094468, 115451711811481, 674593269112948, 140400921371770, 659335660634071, 536749311958781, 854645598266824, 303305169095255, 91430489108219, 573739385205188, 400604977158702, 728593782212529, 807432219147040, 893541884126828, 183964371201281, 422680633277230, 218817645778789, 313025293025224, 657253930848472, 747562211812373, 83456701182914, 470417289614736, 641146659305859, 468130225316006, 46960547227850, 875638267674897, 662661765336441, 186533085001285, 743250648436106, 451414956181714, 527954145201673, 922589993405001, 242119479617901, 865476357142231, 988987578447349, 430198555146088, 477890180119931, 844464003254807, 503374203275928, 775374254241792, 346653210679737, 789242808338116, 48503976498612, 604300186163323, 475930096252359, 860836853339514, 994513691290102, 591343659366796, 944852018048514, 82396968629164, 152776642436549, 916070996204621, 305574094667054, 981194179562189, 126174175810273, 55636640522694, 44670495393401, 74724541586529, 988608465654705, 870533906709633, 374564052429787, 486493568142979, 469485372072295, 221153171135022, 289713227465073, 952450431038075, 107298466441025, 938262809228861, 253919870663003, 835790485199226, 655456538877798, 595464842927075, 191621819564547]
flag = ""
a = 288260533169915
p = 1007621497415251
for ch in encFlag:
    if pow(ch,(p-1)//2,p)==1:
        flag += '1'
    else:
        flag += '0'
flag
ls = [chr(int(flag[i:i+8],2)) for i in range(0,len(flag),8)]
result = ""
for i in ls:
    result += i
print(result)
This post is licensed under CC BY 4.0 by the author.