Иерархическая деривация ключей по аналогии с BIP-32

Иерархическая деривация ключей в контексте криптографических библиотек на основе TweetNaCl.js опирается на идею построения дерева ключей из единого начального значения (seed), из которого детерминированно выводятся все последующие ключи. Такой подход позволяет воспроизводить целые наборы ключей без хранения каждого из них, обеспечивая при этом удобство резервного копирования и структурирование ключевого пространства.

В основе иерархической системы лежит детерминированное преобразование:

  • начальный секрет (seed)
  • функция расширения ключа
  • цепочка производных значений
  • индексы ветвления (path)

Ключевая идея заключается в том, что любой дочерний ключ вычисляется из родительского, но обратное вычисление невозможно.

В классическом BIP-32 используется следующая схема:

  • master key = HMAC-SHA512(seed)
  • child key = f(parent key, index)

В случае TweetNaCl.js прямой поддержки BIP-32 нет, поэтому реализуется либо адаптация через внешние криптографические функции, либо использование совместимых стандартов вроде SLIP-0010.

Особенности TweetNaCl.js и ограничения

TweetNaCl.js предоставляет минималистичный набор криптографических примитивов:

  • Ed25519 (подписи)
  • X25519 (обмен ключами)
  • XSalsa20-Poly1305 (шифрование)

Однако отсутствуют:

  • HMAC
  • SHA-256 / SHA-512
  • встроенная поддержка HD-деривации

Поэтому иерархическая схема строится поверх библиотеки, а не внутри неё.

SLIP-0010 как аналог BIP-32 для Ed25519

Для асимметрии Ed25519 стандарт BIP-32 не подходит напрямую, поскольку он рассчитан на secp256k1 и использует не совместимую схему вывода ключей.

Вместо этого применяется SLIP-0010, который определяет:

  • использование HMAC-SHA512
  • фиксированную схему деривации для Ed25519
  • отсутствие незащищённых (non-hardened) ключей

Иерархия ключей становится строго защищённой: каждый дочерний ключ зависит только от родительского и индекса.

Архитектура иерархического дерева ключей

Структура выглядит следующим образом:

seed
 └── master node
      ├── account 0
      │     ├── external chain
      │     └── internal chain
      └── account 1
            ├── external chain
            └── internal chain

Каждый узел содержит:

  • private key
  • public key
  • chain code (дополнительный энтропийный материал)

Chain code играет ключевую роль, так как предотвращает предсказуемость дочерних ключей даже при частичной компрометации родителя.

Формирование master key

В SLIP-0010 master key создаётся так:

  • вход: seed (обычно 16–64 байта)

  • вычисление: HMAC-SHA512(“ed25519 seed”, seed)

  • разделение результата:

    • первые 32 байта → private key
    • оставшиеся 32 байта → chain code

TweetNaCl.js не реализует HMAC-SHA512, поэтому используется внешняя реализация, например WebCrypto или отдельные библиотеки.

Пример:

import nacl from "tweetnacl";
import { hmac } from "some-hmac-sha512-lib";

function masterKey(seed) {
  const I = hmac("ed25519 seed", seed); // 64 bytes
  return {
    key: I.slice(0, 32),
    chainCode: I.slice(32)
  };
}

Деривация дочернего ключа

В SLIP-0010 для Ed25519 используется только hardened-деривация:

index >= 0x80000000

Процесс:

  • вход: parent key + chain code + index
  • вычисление HMAC-SHA512
  • разделение результата на новый private key и chain code

Формально:

I = HMAC-SHA512(chainCode, 0x00 || parentKey || index)
childKey = I_L
childChainCode = I_R

Реализация на JavaScript поверх TweetNaCl.js

TweetNaCl.js используется для работы с Ed25519 ключами после их генерации.

Пример структуры:

import nacl from "tweetnacl";
import { hmac } from "some-hmac-sha512-lib";

function deriveChild(parent, index) {
  const data = new Uint8Array(1 + 32 + 4);

  data[0] = 0x00;
  data.set(parent.key, 1);
  new DataView(data.buffer).setUint32(33, index, false);

  const I = hmac(parent.chainCode, data);

  return {
    key: I.slice(0, 32),
    chainCode: I.slice(32)
  };
}

После получения private key можно получить public key через TweetNaCl.js:

const keyPair = nacl.sign.keyPair.fromSeed(child.key);

Адресация ключей и путь деривации

Иерархический путь обычно записывается как:

m / purpose' / coin_type' / account' / change / address_index

Для Ed25519:

  • все уровни hardened
  • используется SLIP-0010

Пример:

m/44'/784'/0'/0'/0'

Каждый уровень добавляет детерминированное разветвление.

Безопасностные свойства модели

Иерархическая деривация даёт несколько критичных свойств:

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

Особенно важно, что при использовании Ed25519 non-hardened деривация исключена, что снижает риск атак на публичные ключи.

Ограничения при использовании TweetNaCl.js

При построении HD-дерева поверх TweetNaCl.js возникают ограничения:

  • необходимость внешнего HMAC-SHA512
  • отсутствие стандартизированного BIP32 API
  • необходимость ручного управления chain code
  • невозможность совместимости с Bitcoin-реализациями BIP32 без адаптации

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

Практическая модель хранения состояния узла

Каждый узел дерева должен хранить:

  • private key (32 bytes)
  • chain code (32 bytes)
  • depth
  • index
  • parent fingerprint (опционально)

Структура:

class HDNode {
  constructor(key, chainCode, depth, index) {
    this.key = key;
    this.chainCode = chainCode;
    this.depth = depth;
    this.index = index;
  }
}

Взаимодействие с подписью TweetNaCl.js

После деривации ключей используется стандартный API:

const message = new TextEncoder().encode("data");
const signature = nacl.sign.detached(message, keyPair.secretKey);

const isValid = nacl.sign.detached.verify(
  message,
  signature,
  keyPair.publicKey
);

Иерархия ключей при этом остаётся полностью прозрачной для слоя подписей.

Практическая архитектура системы

Комбинированная система обычно строится так:

  • seed хранится в защищённом виде
  • HD-деривация реализуется отдельно
  • TweetNaCl.js используется только для Ed25519 операций
  • HMAC-SHA512 реализуется через WebCrypto или внешние библиотеки

Такое разделение минимизирует зависимость от одной библиотеки и сохраняет криптографическую корректность модели HD-ключей