GolfScript, 60 символов
{[[0 1{.283{1$2*.255>@*^}:r~^}255*].@?~)={257r}4*99]{^}*}:S;
Этот код определяет именованную функцию, S
которая принимает байт и применяет к ней S-блок Rijndael. (Он также использует внутреннюю вспомогательную функцию с именем, r
чтобы сохранить несколько символов.)
Эта реализация использует таблицу логарифма для вычисления GF (2 8 ) обратно, так как предложенный Томасом Pornin . Чтобы сохранить несколько символов, вся логарифмическая таблица пересчитывается для каждого входного байта; несмотря на это, несмотря на то, что GolfScript является очень медленным языком в целом, этот код занимает всего около 10 мс для обработки байта на моем старом ноутбуке. Предварительный расчет таблицы логарифмов (as L
) ускоряет ее примерно до 0,5 мс на байт при скромной стоимости еще трех символов:
[0 1{.283{1$2*.255>@*^}:r~^}255*]:L;{[L?~)L={257r}4*99]{^}*}:S;
Для удобства вот простой тестовый набор, который вызывает функцию S
, как определено выше, для вычисления и распечатки всего S-блока в шестнадцатеричном виде, как в Википедии :
"0123456789abcdef"1/:h; 256, {S .16/h= \16%h= " "++ }% 16/ n*
Попробуйте этот код онлайн.
(Демонстрация в режиме онлайн предварительно вычисляет таблицу логарифмов, чтобы не занимать слишком много времени. Несмотря на это, онлайн-сайт GolfScript иногда может случайно зависнуть; это известная проблема с сайтом, и перезагрузка обычно исправляет ее.)
Объяснение:
Начнем с вычисления логарифмической таблицы, а именно с вспомогательной функции r
:
{1$2*.255>@*^}:r
Эта функция принимает два входа в стек: битовую маску и битовую маску сокращения (константа между 256 и 511). Он дублирует входной байт, умножает копию на 2 и, если результат превышает 255, XOR с помощью битовой маски возвращает значение ниже 256.
В коде генерации таблицы журнала функция r
вызывается с битовой маской редукции 283 = 0x11b (что соответствует многочлену редукции Rijndael GF (2 8 ) x 8 + x 4 + x 3 + x + 1), и результатом является XORed с исходным байтом, эффективно умножая его на 3 (= x + 1, как многочлен) в конечном поле Рейндаля. Это умножение повторяется 255 раз, начиная с байта 1, и результаты (плюс начальный нулевой байт) собираются в массив из 257 элементов, L
который выглядит следующим образом (средняя часть опущена):
[0 1 3 5 15 17 51 85 255 26 46 ... 180 199 82 246 1]
Причина, по которой существует 257 элементов, состоит в том, что с добавленным 0 и 1, встречающимся дважды, мы можем найти модульную инверсию любого данного байта, просто посмотрев его (основанный на нуле) индекс в этом массиве, отрицая его и посмотрев до байта в отрицательном индексе в том же массиве. (В GolfScript, как и во многих других языках программирования, отрицательные индексы массива считаются в обратном направлении от конца массива.) Действительно, это именно то, что делает код L?~)L=
в начале функции S
.
Остальная часть коды вызывает вспомогательную функцию в r
четыре раза с уменьшением битовой маской 257 = 2 8 +-для создания четыре битовых-повернутой копии перевернутого входного байта. Все они собраны в массив вместе с константой 99 = 0x63, и XORed вместе для получения окончательного результата.