Типизированные массивы в JavaScript стали основой для эффективной
работы с бинарными данными, особенно в криптографических библиотеках,
где важна точность представления байтов и минимальные накладные расходы
на преобразования. В SJCL (Stanford Javascript Crypto Library)
взаимодействие с такими данными строится вокруг внутреннего формата
bitArray, а для интеграции с внешними источниками данных используется
модуль sjcl.codec.bytes.
Внутри SJCL любые бинарные данные представлены не как
Uint8Array, а как специализированная структура —
bitArray. Это массив 32-битных слов с дополнительным
элементом, описывающим количество значимых бит в последнем слове.
Такое представление удобно для криптографических операций:
Однако при взаимодействии с внешним миром — браузерными API, Node.js Buffer, сетевыми протоколами — требуется преобразование в байтовый формат.
Именно для этого используется sjcl.codec.bytes.
sjcl.codec.bytes выполняет двустороннее преобразование
между:
Array<number> с значениями
0–255);bitArray).Основные функции:
sjcl.codec.bytes.toBits(bytes) — преобразует байты в
bitArray;sjcl.codec.bytes.fromBits(bitArray) — преобразует
bitArray обратно в байты.Этот кодек является мостом между криптографическим ядром и внешними источниками данных.
Типизированные массивы Uint8Array являются стандартом
работы с бинарными данными в современном JavaScript. Однако SJCL не
работает с ними напрямую, поэтому требуется явное преобразование.
const bytes = new Uint8Array([104, 101, 108, 108, 111]);
const bitArray = sjcl.codec.bytes.toBits(Array.from(bytes));
Ключевой момент заключается в том, что toBits ожидает
обычный массив чисел, а не Uint8Array. Поэтому используется
Array.from.
Внутренне происходит упаковка байтов в 32-битные слова:
После криптографической операции (шифрование, хеширование, генерация HMAC) результат снова нужно привести к байтовому виду.
const bitArray = sjcl.hash.sha256.hash("data");
const bytes = sjcl.codec.bytes.fromBits(bitArray);
const uint8 = new Uint8Array(bytes);
Функция fromBits возвращает обычный массив чисел,
который легко оборачивается в Uint8Array без дополнительных
преобразований.
При вызове toBits происходит последовательная
упаковка:
Пример логики:
[0x61, 0x62, 0x63, 0x64]
→ 0x61626364
Если количество байтов не кратно четырём, последний элемент дополняется нулями, а длина сохраняется отдельно.
При fromBits происходит обратная операция:
Это критично для корректного восстановления данных после хеширования, где длина часто не кратна 8.
При интеграции SJCL с современными API возникают типовые сценарии:
crypto.subtle.digest("SHA-256", uint8)
Результат Web Crypto возвращается как ArrayBuffer,
который удобно преобразовать:
const hashArray = new Uint8Array(buffer);
const sjclBits = sjcl.codec.bytes.toBits(Array.from(hashArray));
В Node.js чаще используется Buffer, который является
подтипом Uint8Array:
const buffer = Buffer.from("data");
const bits = sjcl.codec.bytes.toBits(Array.from(buffer));
Обратное преобразование:
const bytes = sjcl.codec.bytes.fromBits(bits);
const buffer = Buffer.from(bytes);
Работа через bytes codec кажется простой, но имеет ряд
особенностей:
Каждое преобразование:
SJCL исторически ориентирован на собственный формат данных. Поэтому:
bitArray хранит длину в битах, что приводит к ситуациям:
const input = new TextEncoder().encode("cryptographic data");
// Uint8Array → SJCL bitArray
const bits = sjcl.codec.bytes.toBits(Array.from(input));
// криптографическая операция
const hashBits = sjcl.hash.sha256.hash(bits);
// bitArray → bytes
const outputBytes = sjcl.codec.bytes.fromBits(hashBits);
// обратно в Uint8Array
const output = new Uint8Array(outputBytes);
sjcl.codec.bytes выполняет роль адаптера между двумя
мирами:
Он используется во всех ключевых сценариях:
Без этого слоя SJCL не мог бы корректно взаимодействовать с современными API браузеров и Node.js, сохраняя при этом свой внутренний криптографический формат.
При интенсивной работе с бинарными данными стоит учитывать:
Array.from;В системах с высокой нагрузкой преобразования между Uint8Array и bitArray часто становятся заметной частью профиля производительности, несмотря на простоту самих операций.
SJCL допускает данные произвольной длины, что приводит к особенностям при кодировании:
Это позволяет корректно работать с потоковыми данными и сообщениями переменной длины, но требует аккуратного обращения при интеграции с внешними форматами сериализации.