Я один из авторов Гимли. У нас уже есть версия с 2 твитами (280 символов) в C, но я бы хотел посмотреть, насколько она может быть маленькой.
Gimli ( статья , веб-сайт ) - это высокоскоростной дизайн криптографической перестановки с высоким уровнем безопасности, который будет представлен на Конференции по криптографическому оборудованию и встраиваемым системам (CHES) 2017 (25-28 сентября).
Задание
Как обычно: сделать небольшую полезную реализацию Gimli на выбранном вами языке.
Он должен иметь возможность принимать в качестве входных данных 384 бита (или 48 байт, или 12 беззнаковых целых ...) и возвращать (может изменить на месте, если вы используете указатели) результат Gimli, примененный к этим 384 битам.
Допускается преобразование входных данных из десятичного, шестнадцатеричного, восьмеричного или двоичного.
Потенциальные угловые случаи
Предполагается, что целочисленное кодирование является прямым порядком байтов (например, то, что вы, вероятно, уже имеете).
Вы можете переименовать Gimli
в, G
но это все равно должен быть вызов функции.
Кто выигрывает?
Это код-гольф, поэтому выигрывает самый короткий ответ в байтах! Стандартные правила применяются конечно.
Ссылочная реализация приведена ниже.
Заметка
Некоторая обеспокоенность была поднята:
«Эй, банда, пожалуйста, реализуй мою программу бесплатно на других языках, чтобы мне не пришлось» (спасибо @jstnthms)
Мой ответ следующий:
Я легко могу сделать это на Java, C #, JS, Ocaml ... Это больше для удовольствия. В настоящее время мы (команда Gimli) внедрили (и оптимизировали) это для AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, развернутых SSE, AVX, AVX2, VHDL и Python3. :)
О Гимли
Штат
Гимли применяет последовательность раундов к 384-битному состоянию. Состояние представлено в виде параллелепипеда с размерами 3 × 4 × 32 или, что эквивалентно, в виде матрицы 3 × 4 из 32-разрядных слов.
Каждый раунд представляет собой последовательность из трех операций:
- нелинейный уровень, в частности 96-битный SP-блок, применяемый к каждому столбцу;
- в каждом втором раунде слой линейного смешивания;
- в каждом четвертом раунде постоянное прибавление.
Нелинейный слой.
SP-бокс состоит из трех подопераций: повороты первого и второго слов; нелинейная Т-функция с 3 входами; и обмен первым и третьим словами.
Линейный слой.
Линейный слой состоит из двух операций подкачки, а именно, Small-Swap и Big-Swap. Мелкий обмен происходит каждые 4 раунда, начиная с 1-го раунда. Большой своп происходит каждые 4 раунда, начиная с 3-го раунда.
Круглые константы.
В Гимли 24 раунда, пронумерованных 24,23, ..., 1. Когда число раунда r равно 24,20,16,12,8,4, мы XOR округляем константу (0x9e377900 XOR r) до первого слова состояния.
справочный источник в C
#include <stdint.h>
uint32_t rotate(uint32_t x, int bits)
{
if (bits == 0) return x;
return (x << bits) | (x >> (32 - bits));
}
extern void gimli(uint32_t *state)
{
int round;
int column;
uint32_t x;
uint32_t y;
uint32_t z;
for (round = 24; round > 0; --round)
{
for (column = 0; column < 4; ++column)
{
x = rotate(state[ column], 24);
y = rotate(state[4 + column], 9);
z = state[8 + column];
state[8 + column] = x ^ (z << 1) ^ ((y&z) << 2);
state[4 + column] = y ^ x ^ ((x|z) << 1);
state[column] = z ^ y ^ ((x&y) << 3);
}
if ((round & 3) == 0) { // small swap: pattern s...s...s... etc.
x = state[0];
state[0] = state[1];
state[1] = x;
x = state[2];
state[2] = state[3];
state[3] = x;
}
if ((round & 3) == 2) { // big swap: pattern ..S...S...S. etc.
x = state[0];
state[0] = state[2];
state[2] = x;
x = state[1];
state[1] = state[3];
state[3] = x;
}
if ((round & 3) == 0) { // add constant: pattern c...c...c... etc.
state[0] ^= (0x9e377900 | round);
}
}
}
Tweetable версия в C
Это может быть не наименьшая используемая реализация, но мы хотели иметь стандартную версию C (таким образом, нет UB и «можно использовать» в библиотеке).
#include<stdint.h>
#define P(V,W)x=V,V=W,W=x
void gimli(uint32_t*S){for(long r=24,c,x,y,z;r;--r%2?P(*S,S[1+y/2]),P(S[3],S[2-y/2]):0,*S^=y?0:0x9e377901+r)for(c=4;c--;y=r%4)x=S[c]<<24|S[c]>>8,y=S[c+4]<<9|S[c+4]>>23,z=S[c+8],S[c]=z^y^8*(x&y),S[c+4]=y^x^2*(x|z),S[c+8]=x^2*z^4*(y&z);}
Тестовый вектор
Следующий вход, сгенерированный
for (i = 0;i < 12;++i) x[i] = i * i * i + i * 0x9e3779b9;
и «напечатанные» значения по
for (i = 0;i < 12;++i) {
printf("%08x ",x[i])
if (i % 4 == 3) printf("\n");
}
таким образом:
00000000 9e3779ba 3c6ef37a daa66d46
78dde724 1715611a b54cdb2e 53845566
f1bbcfc8 8ff34a5a 2e2ac522 cc624026
должен вернуть:
ba11c85a 91bad119 380ce880 d24c2c68
3eceffea 277a921c 4f73a0bd da5a9cd8
84b673f0 34e52ff7 9e2bef49 f41bb8d6
-round
а не--round
означает, что он никогда не заканчивается. Преобразование--
в тире, вероятно, не рекомендуется в коде :)Ответы:
CJam (114 символов)
Это анонимный блок (функция): если вы хотите назвать его,
G
добавьте:G
. В CJam назначенные имена могут состоять только из заглавных букв. Есть место, чтобы добавить комментарийe# Gimli in CJam
и оставить символы в одном твите.Онлайн тест
рассечение
источник
C (gcc), 237 байтов
Я, вероятно, получил байты с моим методом обмена, но это слишком мило, чтобы не использовать.
источник
unsigned
вместоuint32_t
(и кода OP был несколько обмана для использованияlong
) , потому что идея шифра, что это очень портативные. (Фактически, в основном это экономит всего 8 байтов).gcc
32-битным или 64-битным процессором Intel (и, вероятно, со многими другими).C, 268 символов (268 байт), используя uint32_t
NB Так как оригинальный код использует
<stdint.h>
и печатаетS
какuint32_t *
, я думаю, что использование кодаlong
- это обман, позволяющий набрать 280 символов за счет переносимости, что и является причиной использованияuint32_t
в первую очередь. Если для справедливости сравнения нам требуется последовательное использованиеuint32_t
и явная подписьvoid gimli(uint32_t *)
, то исходный код на самом деле составляет 284 символа, а код orlp - 276 символов.Это может быть разделено на два твита с маркерами продолжения как
а также
источник
long
в моей версии безопасно (относительно переносимости), потому что минимальный размер long по стандарту составляет 32 бита (в отличие отint
). Вращенияx
иy
выполняются до приведения вlong
назначении, что делает их безопасными (так как смещение вправо на значение со знаком зависит от CC). Актерский состав при возвращении вuint32_t* S
) избавляется от верхних бит и переводит нас в правильное состояние :).Java (OpenJDK 8) ,
351343339320318247 + 56 байтВсего лишь 1: 1 порт для начала игры в гольф.
Попробуйте онлайн!
источник
Integer
вообще использовать ? o_O Так как вы не используете какой-либоInteger
метод, нет причин не использоватьint
s здесь ...s[0]^=(0x9e377900|r);
(в самом конце) - вы не можете удалить лишние скобки?s[4+c]>>>(23)
.void P(int[]S,int a,int b){int x=S[a];S[a]=S[b];S[b]=x;}void gimli(int[]S){for(int r=24,c,x,y,z;r>0;S[0]^=y<1?0x9e377901+r:0){for(c=4;c-->0;){x=S[c]<<24|S[c]>>>8;y=S[c+4]<<9|S[c+4]>>>23;z=S[c+8];S[c]=z^y^8*(x&y);S[c+4]=y^x^2*(x|z);S[c+8]=x^2*z^4*(y&z);}y=r%4;if(--r%2>0){P(S,0,1+y/2);P(S,3,2-y/2);}}}
. Я в основном внес минимальные изменения, необходимые для его компиляции. Правила приоритета Java не очень отличаются от Си.JavaScript (ES6), 231 байт
демонстрация
Показать фрагмент кода
источник
32-битный x86 ассемблер (112 байт)
(__cdecl соглашение о вызовах)
Tweetable версия (кодировка Base85 в формате z85):
источник