Files
Tajna-tretej-stolicy/crypto-elliptic-enigma/WRITEUP.md
2026-04-22 10:58:32 +03:00

2.6 KiB
Raw Blame History

Elliptic Enigma

Crypto 852 pts

В руках два файла:

Файл Что внутри
public/server.py Код сервера подписи
public/signatures.json Параметры кривой, публичный ключ, 30 подписей, шифротекст флага

ECDSA на кастомной эллиптической кривой — смотрим генерацию nonce k, обычно вся соль в нём.

Решение

В коде сервера:

k = random.getrandbits(120)

Порядок группы n — 128 бит. У каждого k старшие 8 бит тупо равны нулю. Даже небольшая утечка нескольких бит nonce, размазанная по десяткам подписей, приводит прямиком к Hidden Number Problem, а HNP классически решается решёточной редукцией (LLL).

Стандартная ECDSA-подпись: для сообщения с хешем z считается

s = k^{-1}(z + r \cdot d) \pmod{n}

Откуда чистой алгеброй:

k = s^{-1} z + s^{-1} r d \pmod{n}

Обозначим t_i = s_i^{-1} r_i \pmod{n} и u_i = s_i^{-1} z_i \pmod{n}, и для каждой подписи получаем уравнение вида

k_i = u_i + t_i \cdot d \pmod{n}, \qquad k_i < 2^{120}

Получили классическую постановку HNP: много сравнений по модулю n, а сами скрытые числа маленькие.

Дальше — стандартный пайплайн:

  1. Загружаем подписи из signatures.json.
  2. Для каждого сообщения считаем z_i так же, как сервер: SHA-256, первые 16 байт.
  3. Вычисляем t_i и u_i.
  4. Собираем из них решётку для LLL и запускаем редукцию.
  5. Из редуцированного базиса вытаскиваем кандидатов на приватный ключ d.
  6. С d на руках расшифровываем флаг: AES-256-CBC(SHA256(d), iv=0, ciphertext).

Флаг

caplag{b14s3d_n0nc3_l4tt1c3_r3duc710n}