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

В библиотеке Stanford JavaScript Crypto Library криптографические ключи на эллиптических кривых строятся вокруг математической структуры, в которой безопасность основана на задаче дискретного логарифмирования в группе точек эллиптической кривой. Каждая ключевая пара состоит из закрытого скалярного значения и открытой точки на кривой.

В SJCL поддерживаются стандартные кривые, определённые через предустановленные параметры:

  • sjcl.ecc.curves.c256
  • sjcl.ecc.curves.c384
  • sjcl.ecc.curves.c521

Каждая из них соответствует определённому уровню криптографической стойкости и длине ключа. На практике чаще всего используется c256, соответствующая 256-битной кривой.


Структура ключевой пары

Ключевая пара в SJCL включает два компонента:

Закрытый ключ

  • Скалярное значение x
  • Случайное число из диапазона порядка группы кривой
  • Никогда не покидает область локального хранения

Открытый ключ

  • Точка на эллиптической кривой P = x * G
  • Состоит из координат (x, y)
  • Может свободно передаваться и использоваться для шифрования или проверки подписи

В терминах SJCL открытый ключ представлен объектом точки (sjcl.ecc.point), а закрытый — объектом секрета (sjcl.bn или внутренний тип библиотеки).


Генерация случайности как основа безопасности

Генерация ключей полностью зависит от качества источника энтропии. SJCL использует встроенный генератор:

sjcl.random

Он должен быть предварительно инициализирован внешней энтропией (движения мыши, события клавиатуры или системные источники). Без достаточной энтропии генерация ключей считается криптографически небезопасной.

Ключевой момент: если sjcl.random находится в состоянии READY, генерация ключей может выполняться корректно.


Генерация пары ключей ECDH / ECDSA

Основной механизм генерации ключевой пары в SJCL реализован через модуль elGamal или ecdsa, в зависимости от сценария использования.

Базовая генерация ключей

// выбор кривой
const curve = sjcl.ecc.curves.c256;

// генерация ключевой пары
const keypair = sjcl.ecc.elGamal.generateKeys(curve);

// извлечение закрытого ключа
const privateKey = keypair.sec;

// извлечение открытого ключа
const publicKey = keypair.pub;

Внутренний процесс генерации

При вызове generateKeys происходит следующая последовательность действий:

  1. Запрашивается криптографически стойкое случайное число x

  2. Проверяется, что x находится в диапазоне [1, n-1], где n — порядок группы

  3. Выполняется умножение точки генератора кривой:

    P = x * G
  4. Формируется объект публичного ключа как точка (Px, Py)

  5. Закрытый ключ сохраняется как скаляр x


Представление ключей в SJCL

Закрытый ключ

console.log(privateKey.get());

Результатом будет большое число, представленное в формате внутреннего big number.

Открытый ключ

console.log(publicKey.x.toString());
console.log(publicKey.y.toString());

Открытый ключ всегда состоит из двух координат точки на кривой. SJCL хранит их как элементы конечного поля.


Использование ECDH (обмен ключами)

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

const alice = sjcl.ecc.elGamal.generateKeys(sjcl.ecc.curves.c256);
const bob = sjcl.ecc.elGamal.generateKeys(sjcl.ecc.curves.c256);

const secretAlice = alice.sec.dh(bob.pub);
const secretBob = bob.sec.dh(alice.pub);

Оба значения secretAlice и secretBob совпадают, так как вычисляются как:

S = xA * xB * G

Особенности реализации в SJCL

1. Отсутствие прямого экспорта приватного ключа

Закрытый ключ не сериализуется автоматически. Для хранения требуется явное преобразование в строку:

const sk = privateKey.get().toString();

2. Объектная модель

SJCL использует объектно-ориентированную модель:

  • sjcl.ecc.elGamal.publicKey
  • sjcl.ecc.elGamal.secretKey

Они инкапсулируют математические операции над кривой.

3. Привязка к конкретной кривой

Ключ строго связан с параметрами кривой. Нельзя использовать публичный ключ, сгенерированный на c256, в контексте c384.


Безопасность генерации ключей

Ключевой фактор устойчивости системы — корректная инициализация генератора случайных чисел.

Типичная ошибка:

  • генерация ключей до накопления энтропии
  • использование фиксированного seed
  • отсутствие событий для sjcl.random

Корректная схема инициализации:

sjcl.random.startCollectors();
// ожидание состояния READY
sjcl.random.addEventListener("ready", function () {
    const keys = sjcl.ecc.elGamal.generateKeys(sjcl.ecc.curves.c256);
});

Кодирование и представление точек

Открытый ключ может быть преобразован в сериализованный формат:

  • uncompressed point (x, y)
  • hex encoding
  • base64 (через дополнительную обработку)

SJCL по умолчанию оперирует внутренним представлением, поэтому внешнее кодирование требует ручной реализации.


Типичные сценарии использования ключей

Шифрование (ElGamal ECC)

  • публичный ключ используется для шифрования сообщения
  • закрытый ключ используется для расшифрования

Подписи (ECDSA)

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

Внутренние ограничения

  • операции зависят от производительности JavaScript-движка
  • генерация ключей может быть затратной по времени
  • отсутствует встроенная аппаратная интеграция (HSM, WebCrypto используется отдельно)

Представление ключа как объекта SJCL

Упрощённая структура ключевой пары:

{
  pub: {
    x: BigInt,
    y: BigInt,
    curve: Object
  },
  sec: {
    x: BigInt (private scalar)
  }
}

Фактически структура более сложная, но логически соответствует этой модели.


Вычислительная модель умножения точки

В основе генерации лежит операция:

P = xG

где:

  • G — базовая точка кривой
  • x — закрытый ключ
  • P — публичный ключ

Операция выполняется через последовательные удвоения и сложения точек в конечном поле.


Практическая устойчивость схемы

Криптографическая стойкость зависит от:

  • длины кривой (256/384/521 бит)
  • качества генерации x
  • отсутствия утечек энтропии
  • корректной реализации point multiplication

SJCL реализует базовые алгоритмы без аппаратного ускорения, что делает её подходящей для учебных и прикладных сценариев, но не для высоконагруженных HSM-систем.