巅峰极客2023 Crypto Rosita


巅峰极客2023 Crypto Rosita

偷偷更新应该没人发现吧

浅浅的记录一下。

跟强网杯2022 Lattice 这个有很大的相似之处。这个折磨我好久所以看着太熟悉了

可惜我太久没做ECC,忘记了smart attack 可恶

题目代码

from Crypto.Util.number import bytes_to_long
from hashlib import sha256
from os import urandom
# from secret import p, a, b, flag
p=getPrime(512)
flag=b'flag{??????????????}'
a=randint(1,p-1)
b=randint(1,p-1)
ECC = EllipticCurve(GF(p), [a, b])
R, E, C = [ECC.random_point() for _ in range(3)]
M=Matrix(ZZ,len(flag),3)
pad = lambda m: urandom(8) + m + b'\x00' * (ZZ(p).nbits() // 8 - len(m) - 8 - 1)
out = list()
for i in range(len(flag)):
    m = pad(chr(flag[i]).encode())
    nonce = urandom(16)
    sh = sha256(nonce + m).digest()
    Q = b2l(m)*R + b2l(nonce)*E + b2l(sh)*C
    out.append(Q)

with open('out.tuo', 'w') as f:
    f.write(str(out)

简短的题目

题目分析

很明显pad那部分后面全是0

所以$pad(m)R=m2^?R==mR^`$

转成矩阵表达咯

只给出了$Q_i$,还有就是M矩阵的第一列元素均为2^9*8^小bits

利用smart attack把离散对数问题变成可解

$d_i$是生成元G与$Q_i$的离散对数解

所以现在我们的问题换成了

求解正交格

找到矩阵R,构建矩阵,这里求正交格就这样造的

格基规约后,理想情况最后一列D均被规约成0

但是不一定能把所有行都能规约成正交矩阵R。这题73行,有70行被规约成与D正交

看强网杯2022 Lattice的wp这里这样满足n>m/2就能通过右核矩阵还原出M。其中n是规约后正交的行数,m为给出的数据行数

所以对于得到的70行足够还原出小向量。

还原M

所以M的每一列是矩阵R的右核解,我们要求的M的第一列是R的右核格上。

格基规约后的每行正交性是不变的。且M的第一列是短向量,期望对R求右核矩阵然后规约即可还原出M的第一列。

exp

from Crypto.Util.number import *
p=11093300438765357787693823122068501933326829181518693650897090781749379503427651954028543076247583697669597230934286751428880673539155279232304301123931419
a=(-10602337004611841904759335148883359090969653658510510358600275641050380448768874133472466281757169086931942865127222834826842856583448958195404187194601748)%p
b=(-3424757783971572799257324035329262490411658894172572005012994558801041224262349740588482997105623017991071214586261721870544696496442896621106306121614953)%p
def smart_attack(P, G, p):
    # https://crypto.stackexchange.com/a/70508
    E = G.curve()
    Eqp = EllipticCurve(Qp(p, 2), [ZZ(t) + randint(0, p) * p for t in E.a_invariants()])

    P_Qps = Eqp.lift_x(ZZ(G.xy()[0]), all=True)
    for P_Qp in P_Qps:
        if GF(p)(P_Qp.xy()[1]) == G.xy()[1]:
            break

    Q_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True)
    for Q_Qp in Q_Qps:
        if GF(p)(Q_Qp.xy()[1]) == P.xy()[1]:
            break

    p_times_P = p * P_Qp
    p_times_Q = p * Q_Qp

    x_P, y_P = p_times_P.xy()
    x_Q, y_Q = p_times_Q.xy()

    phi_P = -(x_P / y_P)
    phi_Q = -(x_Q / y_Q)
    k = phi_Q / phi_P
    return ZZ(k)
E = EllipticCurve(GF(p), [a, b])
D=[]
G=E.gens()[0]
for i in range(len(res)):
    temp_Q=E(res[i][0],res[i][1])
    D.append(smart_attack(temp_Q,G,p))
#有亿点点久

M=Matrix(ZZ,74,74)
for i in range(73):
    M[i,i]=1
    M[i,-1]=D[i]
M[-1,-1]=p
R=M.LLL()
LK=[]
for i in R:
    if i[-1]!=0:
        break
    else:
        LK.append(i[:-1])
print(len(LK))
LK=Matrix(ZZ,LK)
key=Matrix(ZZ,LK.right_kernel().basis()).LLL()[0]
for i in key:
    print(chr(long_to_bytes(ZZ(i))[-1]),end='')

  目录