Функция nacl.sign.keyPair.fromSeed в TweetNaCl.js /
nacl.js используется для построения пары ключей подписи Ed25519 на
основе заранее заданного 32-байтного значения — seed. В отличие от
генерации случайной пары ключей, этот механизм полностью детерминирован:
одинаковый seed всегда приводит к одинаковой паре ключей.
В основе лежит алгоритм Ed25519, который требует два ключевых компонента:
При использовании fromSeed секретный ключ не
генерируется случайно, а выводится из seed. Далее из него вычисляется
публичный ключ.
Seed выступает как единственный источник энтропии. Его длина фиксирована — 32 байта. Любое изменение хотя бы одного байта seed полностью меняет результирующую пару ключей.
Seed в TweetNaCl.js всегда представлен как:
Uint8Array(32)Он должен содержать криптографически стойкие данные, если цель — безопасность. Однако ключевая особенность метода заключается в том, что seed может быть:
Функция возвращает объект:
publicKey: Uint8Array(32)secretKey: Uint8Array(64)Важно, что secretKey в TweetNaCl.js не является просто seed. Он включает:
import nacl from 'tweetnacl';
// seed строго 32 байта
const seed = new Uint8Array([
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32
]);
const keyPair = nacl.sign.keyPair.fromSeed(seed);
console.log(keyPair.publicKey);
console.log(keyPair.secretKey);
Одно из ключевых свойств:
Это делает метод полезным в сценариях, где необходимо восстановление ключей без хранения приватного ключа.
Пример:
const seedA = new Uint8Array(32).fill(7);
const kp1 = nacl.sign.keyPair.fromSeed(seedA);
const kp2 = nacl.sign.keyPair.fromSeed(seedA);
kp1.publicKey === kp2.publicKey; // всегда true (по содержимому)
Сравнение происходит по байтам, а не по ссылке.
В библиотеке также существует:
nacl.sign.keyPair()
Различие принципиальное:
| Метод | Источник энтропии | Поведение |
|---|---|---|
| keyPair() | криптографически случайный генератор | каждый вызов новый ключ |
| keyPair.fromSeed() | фиксированный seed | воспроизводимый результат |
При вызове fromSeed выполняются этапы:
Секретная часть подвергается строгим битовым ограничениям:
Это необходимо для предотвращения слабых ключей и соблюдения свойств группы Ed25519.
Seed может храниться отдельно:
И затем восстанавливать ключевую пару при необходимости.
Один seed может стабильно представлять пользователя в системе:
Детерминированность позволяет:
import nacl from 'tweetnacl';
const seed = new Uint8Array(32).fill(42);
const keyPair = nacl.sign.keyPair.fromSeed(seed);
const message = new TextEncoder().encode("hello");
const signature = nacl.sign.detached(message, keyPair.secretKey);
const isValid = nacl.sign.detached.verify(
message,
signature,
keyPair.publicKey
);
Использование fromSeed накладывает важные
ограничения:
Критически важно избегать:
Math.random()Для создания seed обычно применяют:
const seed = nacl.randomBytes(32);
Это обеспечивает криптографически стойкую энтропию.
TweetNaCl.js работает с Uint8Array, но часто требуется
преобразование:
Пример преобразования в hex:
const toHex = (bytes) =>
Array.from(bytes)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
Результат стабилен:
Алгоритм Ed25519 полностью детерминирован, что исключает различия между платформами.
Несмотря на удобство, подход имеет особенности:
Типичные схемы:
nacl.sign.keyPair.fromSeed является прямым интерфейсом к
Ed25519:
secretKey в результате:
nacl.sign.* функцияхПрямое извлечение seed из secretKey невозможно без знания структуры и алгоритма.
seed (32 bytes)
↓
SHA-512 / derivation
↓
clamp + scalar derivation
↓
secret scalar
↓
public key generation
↓
keyPair
Все операции в fromSeed требуют строгого соблюдения
бинарного формата:
const encoder = new TextEncoder();
const seed = encoder.encode("example-seed-32-bytes-minimum!!");
Главная особенность метода: