Алгоритм Curve25519 и протокол Diffie-Hellman

Curve25519 — это эллиптическая кривая, специально спроектированная для выполнения операций криптографии с высокой скоростью и устойчивостью к множеству известных атак, возникающих в классических реализациях Diffie-Hellman на конечных полях и старых эллиптических кривых. В контексте JavaScript-библиотек TweetNaCl.js и nacl.js она используется через реализацию X25519 — стандартизированного алгоритма обмена ключами на основе скалярного умножения точек на кривой.

Основная идея заключается в том, что вместо работы с большими простыми числами, как в классическом Diffie-Hellman, используются точки на эллиптической кривой и операция скалярного умножения:

k × G = P

где:

  • k — приватный ключ (скаляр)
  • G — базовая точка кривой Curve25519
  • P — публичный ключ

Обратная операция (нахождение k по P) вычислительно неосуществима при корректных параметрах кривой, что обеспечивает криптографическую стойкость.


Curve25519 определена над конечным полем:

?p, где p = 2²⁵⁵ − 19

Её уравнение в классической форме Эдвардса или Монтгомери специально оптимизировано для быстрых вычислений и защиты от побочных каналов. В библиотечных реализациях, включая TweetNaCl.js, используется форма Монтгомери, позволяющая эффективно выполнять только одну операцию — скалярное умножение.

Ключевые свойства:

  • 128-битный уровень безопасности
  • высокая скорость вычислений
  • устойчивость к timing-атакам
  • отсутствие необходимости в проверке точек (в X25519)

Скалярное умножение как основа X25519

Вместо операций с координатами точек используется только координата u (Montgomery ladder). Это делает алгоритм проще и безопаснее.

Функция скалярного умножения в TweetNaCl.js:

nacl.scalarMult(n, p)

где:

  • n — 32-байтовый приватный ключ
  • p — публичный ключ другой стороны
  • результат — общий секрет (32 байта)

Для генерации публичного ключа из приватного используется:

nacl.scalarMult.base(n)

Протокол Diffie–Hellman на Curve25519 (X25519)

Диффи-Хеллман позволяет двум сторонам создать общий секрет через открытый канал без предварительного обмена ключами.

Алгоритм в упрощённом виде:

  1. Сторона A генерирует приватный ключ a

  2. Сторона B генерирует приватный ключ b

  3. Обе стороны вычисляют публичные ключи:

    • A → A_pub = a × G
    • B → B_pub = b × G
  4. Обмен публичными ключами

  5. Вычисление общего секрета:

    • A → S = a × B_pub
    • B → S = b × A_pub

В результате:

a × (b × G) = b × (a × G)

что гарантирует совпадение общего секрета.


Реализация в TweetNaCl.js

TweetNaCl.js предоставляет низкоуровневый API, где все ключи представлены как Uint8Array длиной 32 байта.

Генерация ключевой пары

import nacl from 'tweetnacl';
import { randomBytes } from 'crypto';

const alicePrivateKey = randomBytes(32);
const alicePublicKey = nacl.scalarMult.base(alicePrivateKey);

const bobPrivateKey = randomBytes(32);
const bobPublicKey = nacl.scalarMult.base(bobPrivateKey);

Вычисление общего секрета

const aliceSharedSecret = nacl.scalarMult(alicePrivateKey, bobPublicKey);
const bobSharedSecret = nacl.scalarMult(bobPrivateKey, alicePublicKey);

aliceSharedSecret и bobSharedSecret будут идентичны.


Использование общего секрета

Сам по себе результат X25519 не является ключом для симметричного шифрования в чистом виде. Обычно он проходит через KDF (Key Derivation Function), например HKDF.

Простейшее применение — использование как ключ для nacl.secretbox:

const nonce = randomBytes(24);
const message = Buffer.from("secret message");

const key = aliceSharedSecret;

const ciphertext = nacl.secretbox(message, nonce, key);
const decrypted = nacl.secretbox.open(ciphertext, nonce, key);

Особенности реализации X25519 в TweetNaCl.js

  1. Отсутствие работы с координатами точек

    • используется только scalar multiplication
    • упрощает API и снижает риск ошибок
  2. 32-байтовые ключи

    • фиксированный размер
    • отсутствие вариативности формата
  3. Монтгомери-лестница

    • защита от side-channel атак
    • постоянное время выполнения
  4. Полная детерминированность операций

    • одинаковый вход всегда даёт одинаковый результат

Безопасность и ограничения

Curve25519/X25519 устраняет целый класс проблем классических DH:

  • нет необходимости проверять принадлежность точки кривой
  • исключены малые подгруппы
  • исключены многие ошибки реализации ECC

Однако остаются требования:

  • приватные ключи должны быть случайными
  • нельзя повторно использовать nonce в симметричных операциях
  • общий секрет должен проходить через KDF при серьёзных сценариях

Формирование публичного ключа

Внутренне scalarMult.base реализует фиксированное умножение:

publicKey = scalarMult(basePoint, privateKey)

Base point в Curve25519 является фиксированной константой, заданной стандартом, и используется для генерации всей группы публичных ключей.


Отличие от классического Diffie–Hellman

Параметр DH (Finite Fields) X25519 (Curve25519)
Математика модульная арифметика эллиптические кривые
Размер ключа 2048+ бит 256 бит
Скорость ниже выше
Безопасность зависит от параметров стандартизирована
Реализация сложнее проще

Типичные ошибки при работе с TweetNaCl.js

  • использование строк вместо Uint8Array
  • попытка хранить ключи в UTF-8 формате
  • повторное использование nonce в secretbox
  • отсутствие KDF после X25519
  • логирование приватных ключей в процессе отладки

Взаимодействие X25519 с другими примитивами NaCl

Curve25519 в TweetNaCl.js часто используется как базовый слой для:

  • nacl.box — аутентифицированное шифрование (Curve25519 + Salsa20 + Poly1305)
  • nacl.sign — Ed25519 (связанный, но другой алгоритм)
  • генерации session keys

nacl.box фактически инкапсулирует X25519:

nacl.box(message, nonce, theirPublicKey, mySecretKey)

внутри происходит:

  • X25519 для обмена ключом
  • derivation симметричного ключа
  • шифрование сообщения

Формат данных и представление ключей

Все ключи и секреты в TweetNaCl.js имеют фиксированное представление:

  • 32 байта для ключей Curve25519
  • Uint8Array как единственный допустимый формат
  • отсутствие строковой сериализации на уровне API

Для хранения часто используют base64 или hex, но только вне криптографических операций.


Принцип построения безопасного обмена ключами

Curve25519 обеспечивает свойства:

  • Diffie-Hellman property — общий секрет вычисляется только участниками
  • Forward secrecy при использовании ephemeral keys
  • Non-interactive agreement — отсутствие необходимости в сервере доверия

В реальных системах каждый сеанс обычно использует новый ключевой набор, что делает компрометацию одного сеанса независимой от других.