python求解二元二次方程组_【CTF WriteUp】2020祥云杯Crypto题解

【线下混战结束,终于有时间整理WP了】

Crypto

Exposure

本题为已知dp部分高位的情况,使用通过化简构造f(x)的Coppersmith解决

from sage.all import *

n = 140376049134934822153964243403031201922239588054133319056483413311963385321279682186354948441840374124640187894619689719746347334298621083485494086361152915457458004998419817456902929318697902819798254427945343361548635794308362823239150919240307072688623000747781103375481834571274423004856276841225675241863

e = 7621

c = 46735962204857190520476434898881001530665718155698898882603422023484998388668858692912250418134186095459060506275961050676051693220280588047233628259880712415593039977585805890920089318643002597837000049626154900908543384761210358835843974072960080857150727010985827690190496793207012355214605393036388807616

s = 1153696846823715458342658568392537778171840014923745253759529432977932183322553944430236879985

def coppersmith(bits, k):

F. = PolynomialRing(Zmod(n))

invE = inverse_mod(e, n)

f = (s << bits) + x + (k - 1) * invE # make monic

x0 = f.small_roots(X=2 ** bits, beta=0.44, epsilon=1/32)

return x0

for k in range(1, e):

bits = 200

x0 = coppersmith(bits,k)

if len(x0) != 0:

x = Integer(x0[0])

dp = x + (s << bits)

p = (e*dp - 1) // k+1

if p != -1:

q = n // p

assert n == p * q

phi = (p-1)*(q-1)

d = inverse_mod(e,phi)

print d

print pow(c,d,n)

more_calc

本题怎么说呢。。网上充满了非预期解,因为这题实在太容易非预期了,主代码又肯定不能跑,试一试就出来了。所以这里我们讲一讲正规套路。本题改编自2012年新加坡数学奥林匹克。

题目要求计算

的值。注意到当i = 1, 2, …, (p-1)/2时,

所以

其中最后一步根据费马小定理,对于素数p与小于p的数i,有i ** (p-1)=1 (mod p)。注意到

从意义上代表从p个元素中取出偶数个元素的方法。由于p是奇数,所以从p个元素中取出偶数个元素的方法数 = 从p个元素中取出奇数个元素的方法数(剩下),且二者之和为从p中取出元素的方法数2 ** p。由于没有计算取出0个元素的情况,所以此处有

以此方法求出q,进而求解本题。完整代码如下:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import gmpy2

from libnum import n2s

e = 65537

p = 27405107041753266489145388621858169511872996622765267064868542117269875531364939896671662734188734825462948115530667205007939029215517180761866791579330410449202307248373229224662232822180397215721163369151115019770596528704719472424551024516928606584975793350814943997731939996459959720826025110179216477709373849945411483731524831284895024319654509286305913312306154387754998813276562173335189450448233216133842189148761197948559529960144453513191372254902031168755165124218783504740834442379363311489108732216051566953498279198537794620521800773917228002402970358087033504897205021881295154046656335865303621793069

c = 350559186837488832821747843236518135605207376031858002274245004287622649330215113818719954185397072838014144973032329600905419861908678328971318153205085007743269253957395282420325663132161022100365481003745940818974280988045034204540385744572806102552420428326265541925346702843693366991753468220300070888651732502520797002707248604275755144713421649971492440442052470723153111156457558558362147002004646136522011344261017461901953583462467622428810167107079281190209731251995976003352201766861887320739990258601550606005388872967825179626176714503475557883810543445555390014562686801894528311600623156984829864743222963877167099892926717479789226681810584894066635076755996423203380493776130488170859798745677727810528672150350333480506424506676127108526488370011099147698875070043925524217837379654168009179798131378352623177947753192948012574831777413729910050668759007704596447625484384743880766558428224371417726480372362810572395522725083798926133468409600491925317437998458582723897120786458219630275616949619564099733542766297770682044561605344090394777570973725211713076201846942438883897078408067779325471589907041186423781580046903588316958615443196819133852367565049467076710376395085898875495653237178198379421129086523

s = p - (pow(2, p, p*p)-2)//p

q = gmpy2.next_prime(s)

n = p*q

e = 0x10001

phi = (p-1)*(q-1)

d = gmpy2.invert(e, phi)

print n2s(pow(c, d, n))

RSAssss

n是四个数的乘积,先yafu分解一下试试,得到两个值

a = 89615068527538836315602124154008300286636934599617334867509053076622715365809371740037316558871796433906844464070995869293654082577887578197182408045175035339285085728002838220314068474670975228778464240088084331807420720121364486765011169669747553393661650912114228227308579940164269877101973728452252879383

b = 89615068527538836315602124154008300286636934599617334867509053076622715365809371740037316558871796433906844464070995869293654082577887578197182408045172781798703173650574737644914515591522256758848089955578713458715234536664415216526830967831862301518636586702212189087959136509334102772855657664091570630079

再往下分解不下去了,所以这两个应该分别是p * next_prime(q)和q * next_prime( p)。注意到next_prime( p)有一个性质,就是当p较大时,并不会完整验算,所以next_prime( p) - p实际上很小。设

next_prime(q) - q = x

next_prime(p) - p = y

当x与y已知时,p*(q+x) = a和q*(p+y) = b构成二元二次方程组,可以通过爆破x与y尝试解方程,在正整数范围内求出解即为p和q之一。完整解题代码如下:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import gmpy2

from libnum import n2s

n = 8030860507195481656424331455231443135773524476536419534745106637165762909478292141556846892146553555609301914884176422322286739546193682236355823149096731058044933046552926707682168435727800175783373045726692093694148718521610590523718813096895883533245331244650675812406540694948121258394822022998773233400623162137949381772195351339548977422564546054188918542382088471666795842185019002025083543162991739309935972705871943787733784491735500905013651061284020447578230135075211268405413254368439549259917312445348808412659422810647972872286215701325216318641985498202349281374905892279894612835009186944143298761257

c = 3304124639719334349997663632110579306673932777705840648575774671427424134287680988314129312593361087606243819528298610131797078262351307396831985397555390640151391138633431951746748156610463582479645561779194981806129898009876517899450840875569675976765155608446799203699927448835004756707151281044859676695533373755798273892503194753948997947653100690841880925445059175494314198605475023939567750409907217654291430615102258523998394231436796902635077995829477347316754739938980814293304289318417443493019704073164585505217658570214989150175123757038125380996050761572021986573934155470641091678664451080065719261207

a = 89615068527538836315602124154008300286636934599617334867509053076622715365809371740037316558871796433906844464070995869293654082577887578197182408045175035339285085728002838220314068474670975228778464240088084331807420720121364486765011169669747553393661650912114228227308579940164269877101973728452252879383

b = 89615068527538836315602124154008300286636934599617334867509053076622715365809371740037316558871796433906844464070995869293654082577887578197182408045172781798703173650574737644914515591522256758848089955578713458715234536664415216526830967831862301518636586702212189087959136509334102772855657664091570630079

for x in range(1, 1000):

for y in range(1, 1000):

delta = (a-b-x*y)**2 + 4*a*x*y

tmp = gmpy2.iroot(delta, 2)

if(tmp[1]):

p = (a-b-x*y + int(tmp[0])) / (2*x)

if (a*b)%p == 0:

print p

pp = gmpy2.next_prime(p)

print pp

tn = n // (p*pp)

tq = int(gmpy2.iroot(tn,2)[0])

qq = gmpy2.next_prime(tq)

q = tn // qq

print q

print qq

print n - p * pp * q * qq

phi = (p-1) * (q-1) * (pp-1) * (qq-1)

d = gmpy2.invert

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值