2025.2.3hgame

2025.2.3hgame

2025.2.3hgame 哒!

week1

crypto

suprimeRSA

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
from Crypto.Util.number import *
import random
from sympy import prime

FLAG=b'hgame{xxxxxxxxxxxxxxxxxx}'
e=0x10001

def primorial(num):
result = 1
for i in range(1, num + 1):
result *= prime(i)
return result
M=primorial(random.choice([39,71,126]))

def gen_key():
while True:
k = getPrime(random.randint(20,40))
a = getPrime(random.randint(20,60))
p = k * M + pow(e, a, M)
if isPrime(p):
return p

p,q=gen_key(),gen_key()
n=p*q
m=bytes_to_long(FLAG)
enc=pow(m,e,n)

print(f'{n=}')
print(f'{enc=}')

"""
n=787190064146025392337631797277972559696758830083248285626115725258876808514690830730702705056550628756290183000265129340257928314614351263713241
enc=365164788284364079752299551355267634718233656769290285760796137651769990253028664857272749598268110892426683253579840758552222893644373690398408
"""

直接上ROCA
我是照着这篇博客来的
GKCTF2020_Crypto_复现
这里也贴一下博客里的脚本
脚本里的M_prime不需要换成题目里的M

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

from sage.all import *
from tqdm import tqdm

def solve(M, n, a, m):
# I need to import it in the function otherwise multiprocessing doesn't find it in its context
from sage_functions import coppersmith_howgrave_univariate

base = int(65537)
# the known part of p: 65537^a * M^-1 (mod N)
known = int(pow(base, a, M) * inverse_mod(M, n))
# Create the polynom f(x)
F = PolynomialRing(Zmod(n), implementation='NTL', names=('x',))
(x,) = F._first_ngens(1)
pol = x + known
beta = 0.1
t = m+1
# Upper bound for the small root x0
XX = floor(2 * n**0.5 / M)
# Find a small root (x0 = k) using Coppersmith's algorithm
roots = coppersmith_howgrave_univariate(pol, n, beta, m, t, XX)
# There will be no roots for an incorrect guess of a.
for k in roots:
# reconstruct p from the recovered k
p = int(k*M + pow(base, a, M))
if n%p == 0:
return p, n//p

def roca(n):

keySize = n.bit_length()

if keySize <= 960:
M_prime = 0x1b3e6c9433a7735fa5fc479ffe4027e13bea
m = 5

elif 992 <= keySize <= 1952:
M_prime = 0x24683144f41188c2b1d6a217f81f12888e4e6513c43f3f60e72af8bd9728807483425d1e
m = 4
print("Have you several days/months to spend on this ?")

elif 1984 <= keySize <= 3936:
M_prime = 0x16928dc3e47b44daf289a60e80e1fc6bd7648d7ef60d1890f3e0a9455efe0abdb7a748131413cebd2e36a76a355c1b664be462e115ac330f9c13344f8f3d1034a02c23396e6
m = 7
print("You'll change computer before this scripts ends...")

elif 3968 <= keySize <= 4096:
print("Just no.")
return None

else:
print("Invalid key size: {}".format(keySize))
return None

a3 = Zmod(M_prime)(n).log(65537)
order = Zmod(M_prime)(65537).multiplicative_order()
inf = a3 // 2
sup = (a3 + order) // 2

# Search 10 000 values at a time, using multiprocess
# too big chunks is slower, too small chunks also
chunk_size = 10000
for inf_a in tqdm(range(inf, sup, chunk_size)):
# create an array with the parameter for the solve function
inputs = [((M_prime, n, a, m), {}) for a in range(inf_a, inf_a+chunk_size)]
# the sage builtin multiprocessing stuff
from sage.parallel.multiprocessing_sage import parallel_iter
from multiprocessing import cpu_count

for k, val in parallel_iter(cpu_count(), solve, inputs):
if val:
p = val[0]
q = val[1]
print("found factorization:\np={}\nq={}".format(p, q))
return val

if __name__ == "__main__":
# Normal values
#p = 88311034938730298582578660387891056695070863074513276159180199367175300923113
#q = 122706669547814628745942441166902931145718723658826773278715872626636030375109
#a = 551658, interval = [475706, 1076306]
# won't find if beta=0.5
# p = 80688738291820833650844741016523373313635060001251156496219948915457811770063
# q = 69288134094572876629045028069371975574660226148748274586674507084213286357069
# #a = 176170, interval = [171312, 771912]
# n = p*q
n = 15518961041625074876182404585394098781487141059285455927024321276783831122168745076359780343078011216480587575072479784829258678691739
# For the test values chosen, a is quite close to the minimal value so the search is not too long
roca(n)
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

from sage.all_cmdline import *

def coppersmith_howgrave_univariate(pol, modulus, beta, mm, tt, XX):
"""
Taken from https://github.com/mimoo/RSA-and-LLL-attacks/blob/master/coppersmith.sage
Coppersmith revisited by Howgrave-Graham

finds a solution if:
* b|modulus, b >= modulus^beta , 0 < beta <= 1
* |x| < XX
More tunable than sage's builtin coppersmith method, pol.small_roots()
"""
#
# init
#
dd = pol.degree()
nn = dd * mm + tt

#
# checks
#
if not 0 < beta <= 1:
raise ValueError("beta should belongs in [0, 1]")

if not pol.is_monic():
raise ArithmeticError("Polynomial must be monic.")

#
# calculate bounds and display them
#
"""
* we want to find g(x) such that ||g(xX)|| <= b^m / sqrt(n)

* we know LLL will give us a short vector v such that:
||v|| <= 2^((n - 1)/4) * det(L)^(1/n)

* we will use that vector as a coefficient vector for our g(x)

* so we want to satisfy:
2^((n - 1)/4) * det(L)^(1/n) < N^(beta*m) / sqrt(n)

so we can obtain ||v|| < N^(beta*m) / sqrt(n) <= b^m / sqrt(n)
(it's important to use N because we might not know b)
"""
#
# Coppersmith revisited algo for univariate
#

# change ring of pol and x
polZ = pol.change_ring(ZZ)
x = polZ.parent().gen()

# compute polynomials
gg = []
for ii in range(mm):
for jj in range(dd):
gg.append((x * XX) ** jj * modulus ** (mm - ii) * polZ(x * XX) ** ii)
for ii in range(tt):
gg.append((x * XX) ** ii * polZ(x * XX) ** mm)

# construct lattice B
BB = Matrix(ZZ, nn)

for ii in range(nn):
for jj in range(ii + 1):
BB[ii, jj] = gg[ii][jj]

BB = BB.LLL()

# transform shortest vector in polynomial
new_pol = 0
for ii in range(nn):
new_pol += x ** ii * BB[0, ii] / XX ** ii

# factor polynomial
potential_roots = new_pol.roots()

# test roots
roots = []
for root in potential_roots:
if root[0].is_integer():
result = polZ(ZZ(root[0]))
if gcd(modulus, result) >= modulus ** beta:
roots.append(ZZ(root[0]))
return roots

分解出p,q后直接正常RSA解密即可

1
hgame{ROCA_ROCK_and_ROll!}

ezBag

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
from Crypto.Util.number import *
import random
from Crypto.Cipher import AES
import hashlib
from Crypto.Util.Padding import pad
from secrets import flag

list = []
bag = []
p=random.getrandbits(64)
assert len(bin(p)[2:])==64
for i in range(4):
t = p
a=[getPrime(32) for _ in range(64)]
b=0
for i in a:
temp=t%2
b+=temp*i
t=t>>1
list.append(a)
bag.append(b)
print(f'list={list}')
print(f'bag={bag}')

key = hashlib.sha256(str(p).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
flag = pad(flag,16)
ciphertext = cipher.encrypt(flag)
print(f"ciphertext={ciphertext}")


"""
list=[[2826962231, 3385780583, 3492076631, 3387360133, 2955228863, 2289302839, 2243420737, 4129435549, 4249730059, 3553886213, 3506411549, 3658342997, 3701237861, 4279828309, 2791229339, 4234587439, 3870221273, 2989000187, 2638446521, 3589355327, 3480013811, 3581260537, 2347978027, 3160283047, 2416622491, 2349924443, 3505689469, 2641360481, 3832581799, 2977968451, 4014818999, 3989322037, 4129732829, 2339590901, 2342044303, 3001936603, 2280479471, 3957883273, 3883572877, 3337404269, 2665725899, 3705443933, 2588458577, 4003429009, 2251498177, 2781146657, 2654566039, 2426941147, 2266273523, 3210546259, 4225393481, 2304357101, 2707182253, 2552285221, 2337482071, 3096745679, 2391352387, 2437693507, 3004289807, 3857153537, 3278380013, 3953239151, 3486836107, 4053147071], [2241199309, 3658417261, 3032816659, 3069112363, 4279647403, 3244237531, 2683855087, 2980525657, 3519354793, 3290544091, 2939387147, 3669562427, 2985644621, 2961261073, 2403815549, 3737348917, 2672190887, 2363609431, 3342906361, 3298900981, 3874372373, 4287595129, 2154181787, 3475235893, 2223142793, 2871366073, 3443274743, 3162062369, 2260958543, 3814269959, 2429223151, 3363270901, 2623150861, 2424081661, 2533866931, 4087230569, 2937330469, 3846105271, 3805499729, 4188683131, 2804029297, 2707569353, 4099160981, 3491097719, 3917272979, 2888646377, 3277908071, 2892072971, 2817846821, 2453222423, 3023690689, 3533440091, 3737441353, 3941979749, 2903000761, 3845768239, 2986446259, 3630291517, 3494430073, 2199813137, 2199875113, 3794307871, 2249222681, 2797072793], [4263404657, 3176466407, 3364259291, 4201329877, 3092993861, 2771210963, 3662055773, 3124386037, 2719229677, 3049601453, 2441740487, 3404893109, 3327463897, 3742132553, 2833749769, 2661740833, 3676735241, 2612560213, 3863890813, 3792138377, 3317100499, 2967600989, 2256580343, 2471417173, 2855972923, 2335151887, 3942865523, 2521523309, 3183574087, 2956241693, 2969535607, 2867142053, 2792698229, 3058509043, 3359416111, 3375802039, 2859136043, 3453019013, 3817650721, 2357302273, 3522135839, 2997389687, 3344465713, 2223415097, 2327459153, 3383532121, 3960285331, 3287780827, 4227379109, 3679756219, 2501304959, 4184540251, 3918238627, 3253307467, 3543627671, 3975361669, 3910013423, 3283337633, 2796578957, 2724872291, 2876476727, 4095420767, 3011805113, 2620098961], [2844773681, 3852689429, 4187117513, 3608448149, 2782221329, 4100198897, 3705084667, 2753126641, 3477472717, 3202664393, 3422548799, 3078632299, 3685474021, 3707208223, 2626532549, 3444664807, 4207188437, 3422586733, 2573008943, 2992551343, 3465105079, 4260210347, 3108329821, 3488033819, 4092543859, 4184505881, 3742701763, 3957436129, 4275123371, 3307261673, 2871806527, 3307283633, 2813167853, 2319911773, 3454612333, 4199830417, 3309047869, 2506520867, 3260706133, 2969837513, 4056392609, 3819612583, 3520501211, 2949984967, 4234928149, 2690359687, 3052841873, 4196264491, 3493099081, 3774594497, 4283835373, 2753384371, 2215041107, 4054564757, 4074850229, 2936529709, 2399732833, 3078232933, 2922467927, 3832061581, 3871240591, 3526620683, 2304071411, 3679560821]]
bag=[123342809734, 118191282440, 119799979406, 128273451872]
ciphertext=b'\x1d6\xcc}\x07\xfa7G\xbd\x01\xf0P4^Q"\x85\x9f\xac\x98\x8f#\xb2\x12\xf4+\x05`\x80\x1a\xfa !\x9b\xa5\xc7g\xa8b\x89\x93\x1e\xedz\xd2M;\xa2'
"""

很明显的背包问题的多子集和变式,照着A Gentle Tutorial for Lattice-Based Cryptanalysis这篇论文来即可,主要就是在矩阵的右边再增加n列的 子集以及背包容量
官方题解中给每个 子集以及背包容量 乘以了2^10这么个系数,然后LLL即可求解
或者不乘系数直接用BKZ也是可以的
exp:

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
B=[[0 for i in range(len(list[0])+5)] for i in range(len(list[0])+1)]
de=2
for i in range(len(list[0])):
B[i][i]=de
B[i][len(list[0])+ 1]=list[0][i]
B[i][len(list[0])+ 2]=list[1][i]
B[i][len(list[0])+ 3]=list[2][i]
B[i][len(list[0])+ 4]=list[3][i]
B[len(list[0])][i]=de/2
B[-1][-1]=bag[-1]
B[-1][-2]=bag[-2]
B[-1][-3]=bag[-3]
B[-1][-4]=bag[-4]
B[-1][len(list[0])]=de/2
B=matrix(ZZ,B)
B_=B.BKZ()
for i in range(len(list[0]) + 1):
M = B_.row(i).list()
flag = True
for m in M[:-5]:
if m != de/2 and m != -de/2:
flag = False
break
if flag:
print(M)
a=[1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1][::-1]
c=''
for i in a:
if i==-1:
c+='0'
else:
c+='1'


p=int(c,2)
#17739748707559623655
p=17739748707559623655
key = hashlib.sha256(str(p).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
print(cipher.decrypt(ciphertext))

flag:

1
hgame{A_S1mple_Modul@r_Subset_Sum_Problem}

sieve

两种不同孔径的筛子,才能筛干净

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Util.number import bytes_to_long
from sympy import nextprime

FLAG = b'hgame{xxxxxxxxxxxxxxxxxxxxxx}'
m = bytes_to_long(FLAG)

def trick(k):
if k > 1:
mul = prod(range(1,k))
if k - mul % k - 1 == 0:
return euler_phi(k) + trick(k-1) + 1
else:
return euler_phi(k) + trick(k-1)
else:
return 1

e = 65537
p = q = nextprime(trick(e^2//6)<<128)
n = p * q
enc = pow(m,e,n)
print(f'{enc=}')
#enc=2449294097474714136530140099784592732766444481665278038069484466665506153967851063209402336025065476172617376546

题目是要我们求n之前的数的欧拉函数和,如果是素数再额外+1
官方wp是用了两种筛,但单一个线性筛其实就可以完成题目的要求
在线性筛筛到素数时多加个1即可
官方exp:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#筛1(也可以⽤sage内置的prime_pi())

def count_primes_optimized_sieve(n):
if n < 2:
return 0
is_prime = [True] * (n + 1)
is_prime[0], is_prime[1] = False, False
for i in range(2, int(n**0.5) + 1):
if is_prime[i]:
for j in range(i*i, n + 1, i):
is_prime[j] = False
return sum(is_prime)
count_primes_optimized_sieve(65537^2//6)
#37030583
#筛2
def linear_sieve_phi(m):
phi = [0] * (m + 1)
is_prime = [True] * (m + 1)
primes = []
phi[1] = 1
for i in range(2, m + 1):
if is_prime[i]:
primes.append(i)
phi[i] = i - 1
for p in primes:
if i * p > m:
break
is_prime[i * p] = False
if i % p == 0:
phi[i * p] = phi[i] * p
break
else:
phi[i * p] = phi[i] * (p - 1)
pre_s = [0] * (m + 1)
for i in range(1, m + 1):
pre_s[i] = pre_s[i - 1] + phi[i]
return phi, pre_s
class EulerSumSolver:
def __init__(self, m=10**6):
self.m = m
self.phi, self.pre_s = linear_sieve_phi(m)
self.cache = {}
def S(self, n):
if n <= self.m:
return self.pre_s[n]
if n in self.cache:
return self.cache[n]
res = n * (n + 1) // 2
v = int(n ** 0.5)
sum1 = 0
for i in range(2, v + 1):
sum1 += self.S(n // i)
u = n // (v + 1)
sum2 = 0
for k in range(1, u + 1):
sum2 += self.S(k) * (n // k - n // (k + 1))
res -= (sum1 + sum2)
self.cache[n] = res
return res
solver = EulerSumSolver(m=10**6)
print(slover.S(65537^2//6))
#155763335194435672

单线性筛,大约需要17G以上的内存,内存不够可能会有点慢
exp:

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
41
42
43
44
from Crypto.Util.number import *
from sympy import nextprime
import time

def sieve_phi(n):
global phi,prime,__sum
__sum=1
phi = [0] * (n + 1)
prime = []
phi[1] = 1
print(1)
for i in range(2, n + 1):
if i%100000==0:
print(i,'/',n,'|',i/n)
if phi[i] == 0:
__sum+=1
phi[i] = i - 1
prime.append(i)
for p in prime:
if i * p > n:
break
if i%p==0:
phi[p*i]=phi[i]*p
break
phi[p*i]=phi[i]*(p-1)
__sum+=phi[i]
return __sum

e = 65537
n=e**2//6
c=2449294097474714136530140099784592732766444481665278038069484466665506153967851063209402336025065476172617376546

start=time.time()
result=sieve_phi(n)
ed=time.time()
print(result)
#155763335447735055
print('用时:',ed-start)
p=nextprime(result<<128)
n=p**2
phi=p**2-p
d=inverse(e,phi)
plain=pow(c,d,n)
print(long_to_bytes(plain))

flag:

1
#hgame{sieve_is_n0t_that_HArd}

misc

在CTF的征途上,我选择让思维稍作休憩。Misc领域的每一次奇技巧思,都值得被更深度地内化与沉淀。当解题的快感褪去后,我意识到过度聚焦于文档的堆砌,或许会稀释技术探索的纯粹性。此刻更愿将精力投入实战推演的复盘中,待未来的某个节点,以更精炼的方式呈现解题的密钥。知识的重组需要发酵的时间,正如隐写术的像素需要耐心校准,才能显现完整的图景。
省流:懒~

week2

crypto

Ancient Recall

命运之轮逆转了原本的厄运,请准确还原最初抽中的牌面组合,使既定命数回归其本应遵循的轨迹

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import random

Major_Arcana = ["The Fool", "The Magician", "The High Priestess","The Empress", "The Emperor", "The Hierophant","The Lovers", "The Chariot", "Strength","The Hermit", "Wheel of Fortune", "Justice","The Hanged Man", "Death", "Temperance","The Devil", "The Tower", "The Star","The Moon", "The Sun", "Judgement","The World"]
wands = ["Ace of Wands", "Two of Wands", "Three of Wands", "Four of Wands", "Five of Wands", "Six of Wands", "Seven of Wands", "Eight of Wands", "Nine of Wands", "Ten of Wands", "Page of Wands", "Knight of Wands", "Queen of Wands", "King of Wands"]
cups = ["Ace of Cups", "Two of Cups", "Three of Cups", "Four of Cups", "Five of Cups", "Six of Cups", "Seven of Cups", "Eight of Cups", "Nine of Cups", "Ten of Cups", "Page of Cups", "Knight of Cups", "Queen of Cups", "King of Cups"]
swords = ["Ace of Swords", "Two of Swords", "Three of Swords", "Four of Swords", "Five of Swords", "Six of Swords", "Seven of Swords", "Eight of Swords", "Nine of Swords", "Ten of Swords", "Page of Swords", "Knight of Swords", "Queen of Swords", "King of Swords"]
pentacles = ["Ace of Pentacles", "Two of Pentacles", "Three of Pentacles", "Four of Pentacles", "Five of Pentacles", "Six of Pentacles", "Seven of Pentacles", "Eight of Pentacles", "Nine of Pentacles", "Ten of Pentacles", "Page of Pentacles", "Knight of Pentacles", "Queen of Pentacles", "King of Pentacles"]
Minor_Arcana = wands + cups + swords + pentacles
tarot = Major_Arcana + Minor_Arcana
reversals = [0,-1]

Value = []
cards = []
YOUR_initial_FATE = []
while len(YOUR_initial_FATE)<5:
card = random.choice(tarot)
if card not in cards:
cards.append(card)
if card in Major_Arcana:
k = random.choice(reversals)
Value.append(tarot.index(card)^k)
if k == -1:
YOUR_initial_FATE.append("re-"+card)
else:
YOUR_initial_FATE.append(card)
else:
Value.append(tarot.index(card))
YOUR_initial_FATE.append(card)
else:
continue
print("Oops!lets reverse 1T!")

FLAG=("hgame{"+"&".join(YOUR_initial_FATE)+"}").replace(" ","_")

YOUR_final_Value = Value
def Fortune_wheel(FATE):
FATEd = [FATE[i]+FATE[(i+1)%5] for i in range(len(FATE))]
return FATEd

for i in range(250):
YOUR_final_Value = Fortune_wheel(YOUR_final_Value)
print(YOUR_final_Value)
YOUR_final_FATE = []
for i in YOUR_final_Value:
YOUR_final_FATE.append(tarot[i%78])
print("Your destiny changed!\n",",".join(YOUR_final_FATE))
print("oh,now you GET th3 GOOd lU>k,^^")
"""
Oops!lets reverse 1T!
[2532951952066291774890498369114195917240794704918210520571067085311474675019, 2532951952066291774890327666074100357898023013105443178881294700381509795270, 2532951952066291774890554459287276604903130315859258544173068376967072335730, 2532951952066291774890865328241532885391510162611534514014409174284299139015, 2532951952066291774890830662608134156017946376309989934175833913921142609334]
Your destiny changed!
Eight of Cups,Ace of Cups,Strength,The Chariot,Five of Swords
oh,now you GET th3 GOOd lU>k,^^
"""

题目要求还原出YOUR_initial_FATE,那么对YOUR_final_FATE进行250次Fortune_wheel的逆变换再取值即可
对于Fortune_wheel的逆变换
FATE=[a,b,c,d,e]
一次变换后FATE1=[a+b,b+c,c+d,d+e,e+a]
那么a=(FATE1[0]+FATE1[2]+FATE1[4]-FATE1[1]-FATE1[3])//2
官方wp中是设了5个未知数,对这5个未知数进行250次Fortune_wheel的变换,然后乘以系数矩阵的逆矩阵即可得到a,b,c,e,d
官方exp:

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
R.<a, b, c, d, e> = PolynomialRing(QQ, 5)
def Fortune_wheel(FATE):
FATEd = [FATE[i]+FATE[(i+1)%5] for i in range(5)]
return FATEd
#
获取系数矩阵

fate = [a,b,c,d,e]
for i in range(250):
fate = Fortune_wheel(fate)
v = vector(list(fate[0].dict().values()))#
得到系数向量

C = matrix(5, 5, lambda i, j: v[(j - i) % 5])#
系数循环

print(C.rank()==5)
#True

FATE=vector([2532951952066291774890498369114195917240794704918210520571067085311474675019, 2532951952066291774890327666074100357898023013105443178881294700381509795270, 2532951952066291774890554459287276604903130315859258544173068376967072335730, 2532951952066291774890865328241532885391510162611534514014409174284299139015, 2532951952066291774890830662608134156017946376309989934175833913921142609334])
E=[[0,0,0,0,0] for _ in range(5)]
for i in range(5):
E[i][i]=1
real_FATE = [vector(E[i])*C.inverse()*FATE for i in range(5)]
print(real_FATE)
#[-19, -20, 20, -15, 41]

value=[-19, -20, 20, -15, 41]
#这里省略其他赋值
YOUR_final_FATE=[]
for i in value:
if i<0:
YOUR_final_FATE.append('re-'+tarot[i^(-1)])
else:
YOUR_final_FATE.append(tarot[i])
FLAG=("hgame{"+"&".join(YOUR_final_FATE)+"}").replace(" ","_")
print(FLAG)
#hgame{re-The_Moon&re-The_Sun&Judgement&re-Temperance&Six_of_Cups}

exp:

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
YOUR_final_Value=[2532951952066291774890498369114195917240794704918210520571067085311474675019, 2532951952066291774890327666074100357898023013105443178881294700381509795270, 2532951952066291774890554459287276604903130315859258544173068376967072335730, 2532951952066291774890865328241532885391510162611534514014409174284299139015, 2532951952066291774890830662608134156017946376309989934175833913921142609334]

Major_Arcana = ["The Fool", "The Magician", "The High Priestess","The Empress", "The Emperor", "The Hierophant","The Lovers", "The Chariot", "Strength","The Hermit", "Wheel of Fortune", "Justice","The Hanged Man", "Death", "Temperance","The Devil", "The Tower", "The Star","The Moon", "The Sun", "Judgement","The World"]
wands = ["Ace of Wands", "Two of Wands", "Three of Wands", "Four of Wands", "Five of Wands", "Six of Wands", "Seven of Wands", "Eight of Wands", "Nine of Wands", "Ten of Wands", "Page of Wands", "Knight of Wands", "Queen of Wands", "King of Wands"]
cups = ["Ace of Cups", "Two of Cups", "Three of Cups", "Four of Cups", "Five of Cups", "Six of Cups", "Seven of Cups", "Eight of Cups", "Nine of Cups", "Ten of Cups", "Page of Cups", "Knight of Cups", "Queen of Cups", "King of Cups"]
swords = ["Ace of Swords", "Two of Swords", "Three of Swords", "Four of Swords", "Five of Swords", "Six of Swords", "Seven of Swords", "Eight of Swords", "Nine of Swords", "Ten of Swords", "Page of Swords", "Knight of Swords", "Queen of Swords", "King of Swords"]
pentacles = ["Ace of Pentacles", "Two of Pentacles", "Three of Pentacles", "Four of Pentacles", "Five of Pentacles", "Six of Pentacles", "Seven of Pentacles", "Eight of Pentacles", "Nine of Pentacles", "Ten of Pentacles", "Page of Pentacles", "Knight of Pentacles", "Queen of Pentacles", "King of Pentacles"]
Minor_Arcana = wands + cups + swords + pentacles
tarot = Major_Arcana + Minor_Arcana
reversals = [0,-1]

def de_Fortune_wheel(FATE):
ol=[0 for i in range(5)]
a_2=FATE[0]+FATE[2]+FATE[4]-FATE[1]-FATE[3]
a=a_2//2
ol[0]=a
for i in range(1,5):
ol[i]=FATE[i-1]-ol[i-1]
return ol
Value=YOUR_final_Value[:]
for i in range(250):
Value=de_Fortune_wheel(Value)

ini=[]
for i in Value:
if i<0:
i=i^-1
ini+=['re-'+tarot[i]]
else:
ini+=[tarot[i]]

flag:

1
hgame{re-The_Moon&re-The_Sun&Judgement&re-Temperance&Six_of_Cups}

2025.2.3hgame
https://bddye.github.io/2025/02/21/2025-2-3hgame/
作者
蹦跶的鱼儿
发布于
2025年2月21日
许可协议