CRYPTOHACK-Modular Arithmetic部分wp

CRYPTOHACK学习记录

二次剩余(Quadratic Residues)

定义:

令整数a,p满足gcd(a,p)=1,若存在整数x使得

x2 ≡ a (mod p)

则称a为模p的二次剩余,否则称a为模p的二次非剩余,称x为a的平方根

题目为:

image-20250224194523920

了解定义后可以编写代码解决此题:

p=29
a=[14,6,11]
for i in a:
    for k in range (1,p):#i不会到p
        if (k*k)%p==i:
            print(f"x={k}")
            print(f"a={i}")

为什么x只要遍历1到p-1?

经过验证发现x2%p的值呈现周期性变化,周期为p,证明如下:

设m属于(1,p-1)假如m2%p=m2,则(p+m)2%p=(((p+m)%p)*((p+m)%p) )%p=m2

勒让德符号(Legendre Symbol)

题目为:

image-20250225000603812

Euler判别法

对奇素数p和满足gcd(a,p)=1的整数a,

image-20250224224254262

证明:已知存在x使得 x2 ≡ a ( mod p),所以p|(x2-a)

由费马小定理,有 ap-1 ≡ 1 ( mod p),故

image-20250224225333658

即要么a(p-1)/2 ≡ 1(mod p),要么a(p-1)/2 ≡ -1(mod p)。另外由于p是奇素数,所以p-1为偶数,有:

image-20250224225355841

P(x) 其中P(x)是某个整系数多项式,进而:

image-20250224225601510

由费马小定理可知p|(xp-x),所以p|(a(p-1)/2-1)

Legendre 符号

对奇素数p和整数a,定义Legendre 符号如下:

image-20250224230356028

根据题目提示 p ≡ 3 (mod 4)[确保(p+1)/4是整数],

首先当a是模p条件下的二次剩余时,有:a(p-1)/2 ≡ 1( mod p),

且ap ≡ a (mod p),相乘可得a(p+1)/2 ≡ a (mod p),即x=±a(p+1)/4,

由此可得解题脚本为:

from gmpy2 import *
p = ***
ints = ***
b=[]
for i in ints:
    L=pow(i,(p-1)//2,p)
    if L==1:
        b.append(i)
print(len(b))
root=pow(b[0],(p+1)//4,p)
print(root)
"""for j in b:
    for k in range(1,p):
        if (k*k)%p==j:
            print(k)"""#这种遍历方法运行时间太长根本无法运行

Modular Square Root

上一题求了 p≡1mod4情况下的模平方根,这题讨论了更普遍的情况,可以使用,tonelli_shanks算法,脚本如下

def legendre_symbol(a, p):
    return pow(a, (p - 1) // 2, p)

def tonelli_shanks(a, p):
    if legendre_symbol(a, p) != 1:
        return None
    q = p - 1
    s = 0
    while q % 2 == 0:
        q //= 2
        s += 1
    if s == 1:
        return pow(a, (p + 1) // 4, p)
    for z in range(2, p):
        if p - 1 == legendre_symbol(z, p):
            break
    c = pow(z, q, p)
    r = pow(a, (q + 1) // 2, p)
    t = pow(a, q, p)
    m = s
    while t != 1:
        i = 1
        while pow(t, 2**i, p) != 1:
            i += 1
        b = pow(c, 2**(m - i - 1), p)
        r = (r * b) % p
        t = (t * b * b) % p
        c = (b * b) % p
        m = i
    return r

p =***

a =***
root = tonelli_shanks(a, p)

print(root)

也可以直接用python中sympy中的sqrt_mod()函数

from sympy import *
p = 30531851861994333252675935111487950694414332763909083514133769861350960895076504687261369815735742549428789138300843082086550059082835141454526618160634109969195486322015775943030060449557090064811940139431735209185996454739163555910726493597222646855506445602953689527405362207926990442391705014604777038685880527537489845359101552442292804398472642356609304810680731556542002301547846635101455995732584071355903010856718680732337369128498655255277003643669031694516851390505923416710601212618443109844041514942401969629158975457079026906304328749039997262960301209158175920051890620947063936347307238412281568760161
a = 8479994658316772151941616510097127087554541274812435112009425778595495359700244470400642403747058566807127814165396640215844192327900454116257979487432016769329970767046735091249898678088061634796559556704959846424131820416048436501387617211770124292793308079214153179977624440438616958575058361193975686620046439877308339989295604537867493683872778843921771307305602776398786978353866231661453376056771972069776398999013769588936194859344941268223184197231368887060609212875507518936172060702209557124430477137421847130682601666968691651447236917018634902407704797328509461854842432015009878011354022108661461024768
print(sqrt_mod(a, p))

中国剩余定理(Chinese Remainder Theorem)

题目为:

image-20250226230813491

介绍:

中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中 n_1, n_2, \cdots, n_k 两两互质):

image-20250226220254791

方程组在模n意义下的唯一解为:

n=n1·n2···nk,mi = n/ni,ci = mimi-1 ≡ 1 (mod ni)image-20250226220402519

证明:把ai乘在第i行等式两边,再将其相加可得上图第i个方程组成立

image-20250226222517888

为什么要模n?

将x表示成kb+r的形式发现模n后代入方程组也成立

解题脚本如下:

from gmpy2 import *
def CRT(k,a,r):#k为方程的数量,a为余数列表,r为模数列表
    n=1#模数的积
    ans=0#储存最终结果
    for i in range(0,k):
        n=n*r[i]
    for j in range(0,k):
        m=n//r[j]
        m_ni=invert(m,r[j])
        ans=(ans+m*m_ni*a[j])%n
    return ans
k=3
a=[2,3,5]
r=[5,11,17]
print(CRT(k,a,r))

使用sagemath中已封装好的函数则更简便:(只需传入两个参数,第一个是余数,第二个是模数)

a=[2,3,5];
n=[5,11,17];
crt(a,n)

Adrien's Signs

题目如下:

from random import randint

a = 288260533169915
p = 1007621497415251

FLAG = b'crypto{????????????????????}'


def encrypt_flag(flag):
    ciphertext = []
    plaintext = ''.join([bin(i)[2:].zfill(8) for i in flag])#bin()用于将数据转换为二进制,前两位为0b,[2:]代表删去0b,zfill(width) 是字符串方法,用于将字符串填充到指定长度 width。如果字符串的长度小于 width,则在字符串的左侧填充零(0),直到字符串的长度等于 width。
    for b in plaintext:
        e = randint(1, p)#从1到p中随机选取的数
        n = pow(a, e, p)
        if b == '1':
            ciphertext.append(n)
        else:
            n = -n % p
            ciphertext.append(n)
    return ciphertext


print(encrypt_flag(FLAG))

经判断a为模p的二次剩余,即存在x,使得x2 ≡ a ( mod p),因为x2e ≡ ae ≡ n % p,所以n也应该是模p的二次剩余,但如果b≠1,n = -n % p,则n不是模p的二次剩余,由此可以逆推出二进制数据。

解题脚本如下:

a = 288260533169915
p = 1007621497415251
n=[67594220461269, 501237540280788, 718316769824518, 296304224247167***]
LS=pow(a,(p-1)//2,p)
print(LS)
b=""
flag=""
for i in n:
    LS_n=pow(i,(p-1)//2,p)
    if LS_n==1:
        b+="1"
    else:
        b+="0"
for j in range(0,len(b),8):#(起始值,结束值,步长【表示每次增加数】)
    b_split=b[j:j+8]
    flag+=chr(int(b_split,2))#其中2表示二进制
print(flag)

python学习:

append列表(list) 的方法,用于在列表的末尾添加一个元素。

语法:

list.append(element)

注意事项:

  • append 只能一次添加一个元素。
  • 如果添加的是一个列表,整个列表会被当作一个元素添加到原列表中。
my_list = [1, 2, 3]
my_list.append([4, 5])
print(my_list)  # 输出: [1, 2, 3, [4, 5]]

join字符串(str) 的方法,用于将一个可迭代对象(如列表、元组等)中的元素连接成一个字符串。

语法:

str.join(iterable)

注意事项:

  • join 只能用于字符串类型的可迭代对象。如果列表中包含非字符串元素,需要先将其转换为字符串。
my_list = [1, 2, 3]
result = '-'.join(map(str, my_list))  # 先将元素转换为字符串
print(result)  # 输出: '1-2-3'

Modular Binomials

这题为模二项式题,有两种解法,一种是直接网站分解N,另一种是进行变换

image-20250308100648384

在网上找到这篇写的过程很详细

from math import gcd
"""
    c1 = (2p + 3q) ^ e1 % N
    c2 = (5p + 7q) ^ e2 % N
    --------------------------------------------------------------------------------------
    N = pq => Binomial: mid elements % N == 0 
=>  c1 = (2p) ^ e1  +  (3q) ^ e1 % N#先用二项式定理拆开,同时含有p,q项的在模N的条件下被约掉
    c2 = (5p) ^ e2  +  (7q) ^ e2 % N
    --------------------------------------------------------------------------------------
    raise c1 to e2 and c2 to e1: to create similar exponent
    c1 ^ e2 = (2p) ^ (e1e2) + (3q) ^ (e1e2) % N  (1)
    c2 ^ e1 = (5p) ^ (e1e2) + (7q) ^ (e1e2) % N  (2)
    -------------------------------------------------------
    Let (1) * 5 ^ (e1e2) - (2) * 2 ^ (e1e2) to get rid of p:
=>  t = 5 ^ (e1e2) * c1 ^ e2  - 2 ^ (e1e1) * c2 ^ e1 = ( 15 ^ (e1e2) - 14 ^ (e1e2)) * q 
    --------------------------------------------------------------------------------------
=>  t % q == 0 and we haved N % q == 0:
=>  q = gcd(t, N)
    p = N / q
"""

N = 14905562257842714057932724129575002825405393502650869767115942606408600343380327866258982402447992564988466588305174271674657844352454543958847568190372446723549627752274442789184236490768272313187410077124234699854724907039770193680822495470532218905083459730998003622926152590597710213127952141056029516116785229504645179830037937222022291571738973603920664929150436463632305664687903244972880062028301085749434688159905768052041207513149370212313943117665914802379158613359049957688563885391972151218676545972118494969247440489763431359679770422939441710783575668679693678435669541781490217731619224470152467768073
e1 = 12886657667389660800780796462970504910193928992888518978200029826975978624718627799215564700096007849924866627154987365059524315097631111242449314835868137
e2 = 12110586673991788415780355139635579057920926864887110308343229256046868242179445444897790171351302575188607117081580121488253540215781625598048021161675697
c1 = 14010729418703228234352465883041270611113735889838753433295478495763409056136734155612156934673988344882629541204985909650433819205298939877837314145082403528055884752079219150739849992921393509593620449489882380176216648401057401569934043087087362272303101549800941212057354903559653373299153430753882035233354304783275982332995766778499425529570008008029401325668301144188970480975565215953953985078281395545902102245755862663621187438677596628109967066418993851632543137353041712721919291521767262678140115188735994447949166616101182806820741928292882642234238450207472914232596747755261325098225968268926580993051
c2 = 14386997138637978860748278986945098648507142864584111124202580365103793165811666987664851210230009375267398957979494066880296418013345006977654742303441030008490816239306394492168516278328851513359596253775965916326353050138738183351643338294802012193721879700283088378587949921991198231956871429805847767716137817313612304833733918657887480468724409753522369325138502059408241232155633806496752350562284794715321835226991147547651155287812485862794935695241612676255374480132722940682140395725089329445356434489384831036205387293760789976615210310436732813848937666608611803196199865435145094486231635966885932646519

x1 = pow(5, e1 * e2, N) * pow(c1, e2, N)
x2 = pow(2, e1 * e2, N) * pow(c2, e1, N)

# t = x1 - x2
q = gcd(x1 - x2, N)

p = N // q

print(p)
print(q)
posted @ 2025-03-08 10:39  C0E1  阅读(115)  评论(0)    收藏  举报