Модульная организация кода

Архитектура SJCL построена вокруг единого глобального пространства имён sjcl, в которое по мере загрузки файлов добавляются отдельные функциональные модули. Такой подход позволяет библиотеке оставаться совместимой с ранними версиями JavaScript и при этом обеспечивать логическое разделение криптографических компонентов без использования современных систем модулей ES Modules или CommonJS.

В основе организации лежит объект sjcl, создаваемый в глобальной области видимости. Каждый файл библиотеки расширяет этот объект, добавляя новые свойства или вложенные пространства имён:

  • sjcl.hash — хеш-функции
  • sjcl.cipher — блочные шифры
  • sjcl.mode — режимы работы блочных шифров
  • sjcl.codec — кодеки для преобразования данных
  • sjcl.misc — вспомогательные утилиты
  • sjcl.bn — большие числа
  • sjcl.ecc — эллиптическая криптография
  • sjcl.random — генератор случайных чисел

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

Отсутствие модульного загрузчика

В классической версии SJCL отсутствует механизм динамического разрешения зависимостей. Вместо этого используется статическая сборка:

  • исходные файлы объединяются в один итоговый скрипт;
  • порядок файлов фиксируется вручную в build-скриптах;
  • зависимости между компонентами учитываются только на уровне соглашений.

Такой подход делает библиотеку независимой от окружения (браузер, старые JS-движки), но накладывает ограничения на архитектурную гибкость.

Инициализация модулей через расширение объекта

Каждый модуль представляет собой самовызывающуюся функцию или набор выражений, которые дополняют sjcl:

sjcl.cipher.aes = function(key) {
    // реализация AES
};

или

sjcl.hash.sha256 = function(message) {
    // реализация SHA-256
};

Таким образом достигается эффект модульности без использования импортов. Каждый компонент становится частью общего пространства имён сразу после выполнения кода.

Разделение по функциональным доменам

Модульная структура организована не по техническим слоям, а по криптографическим примитивам.

Хеш-функции

Модули в sjcl.hash реализуют алгоритмы:

  • SHA-256
  • SHA-512
  • SHA-1 (в некоторых сборках)

Каждый алгоритм представлен отдельной реализацией, но унифицирован через общий интерфейс: функция принимает сообщение и возвращает битовый массив.

Блочные шифры

sjcl.cipher содержит реализации симметричных алгоритмов:

  • AES (основной шифр библиотеки)

Каждый шифр оформлен как конструктор, возвращающий объект с методами шифрования и дешифрования.

Режимы работы

sjcl.mode определяет способы применения блочных шифров:

  • CBC
  • CCM
  • GCM (в расширенных сборках)

Режимы отделены от самих алгоритмов шифрования и принимают шифр как параметр, реализуя композиционный подход.

Кодеки

sjcl.codec отвечает за преобразование данных между форматами:

  • bitArray — внутренний формат SJCL
  • hex — шестнадцатеричное представление
  • base64 — кодирование в Base64
  • utf8String — работа со строками

Кодеки не содержат криптографической логики и служат исключительно для представления данных.

Вспомогательные утилиты

sjcl.misc включает:

  • PBKDF2 (выработка ключей из пароля)
  • hmac
  • functions for key stretching and entropy management

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

Внутренние зависимости и соглашения

Несмотря на отсутствие формальной системы импортов, зависимости между модулями строго определены:

  • sjcl.mode зависит от sjcl.cipher
  • sjcl.cipher использует sjcl.bitArray
  • sjcl.hash использует только sjcl.bitArray
  • sjcl.misc может использовать и hash, и cipher, и codec

Эти зависимости не проверяются системой, а поддерживаются архитектурной дисциплиной разработки.

Единый формат данных: bitArray

Центральным элементом связности модульной структуры выступает формат bitArray. Почти все криптографические операции принимают и возвращают данные именно в этом виде.

bitArray обеспечивает:

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

Кодеки выступают мостом между bitArray и внешними представлениями данных.

Паттерн расширяемости

Добавление новых модулей осуществляется через простое присвоение в пространство имён:

sjcl.hash.myHash = function(data) {
    // пользовательская реализация
};

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

Особенности сборки библиотеки

Процесс сборки SJCL основан на объединении исходных файлов:

  • используется скриптовая сборка (обычно shell + cat или аналогичные инструменты)
  • порядок подключения файлов фиксирован
  • минимизация направлена на уменьшение размера, а не на разрешение зависимостей

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

Инкапсуляция внутри модулей

Каждый модуль изолирует внутренние переменные с помощью замыканий:

sjcl.cipher.aes = function(key) {
    var rounds = 10;
    var keySchedule = [];
    // внутренние функции и данные
};

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

Отсутствие runtime-композиции

Модули SJCL не могут подключаться или отключаться во время выполнения:

  • нет динамического require/import
  • нет ленивой загрузки
  • нет разрешения зависимостей в рантайме

Композиция полностью переносится на этап сборки, что упрощает выполнение в браузере, но ограничивает гибкость интеграции в современные модульные системы.

Связность архитектуры

Модульная структура SJCL характеризуется высокой связностью через общие структуры данных и слабой изоляцией на уровне системы загрузки. Связность достигается не инфраструктурой модулей, а:

  • единым глобальным объектом sjcl
  • единым форматом bitArray
  • строгими соглашениями о зависимостях
  • фиксированным порядком сборки

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