Я один із авторів Гімлі. У нас вже є 2-твітна (280 символів) версія на С, але я хотів би побачити, наскільки вона може бути маленькою.
Gimli ( папір , веб-сайт ) - це висока швидкість із криптографічним перестановкою високого рівня безпеки, яка буде представлена на конференції з криптографічного обладнання та вбудованих систем (CHES) 2017 (25-28 вересня).
Завдання
Як завжди: зробити неприємну корисну реалізацію Gimli мовою на ваш вибір.
Він повинен мати можливість приймати як вхідні 384 біта (або 48 байт, або 12 неподписаних int ...) і повертати (може змінюватися на місці, якщо ви використовуєте покажчики) результат Gimli, застосований до цих 384 біт.
Дозволено перетворення вводу з десяткових, шістнадцяткових, восьмеричних чи двійкових.
Потенційні кутові справи
Кодування цілочисниками вважається малоінтенсивним (наприклад, тим, що ви, мабуть, вже є).
Ви можете перейменувати Gimliв Gале вона все одно повинна бути викликом функції.
Хто виграє?
Це код-гольф, тому найкоротша відповідь у байтах виграє! Звичайно, застосовуються стандартні правила.
Нижче наведено посилання на реалізацію.
Примітка
Висловлено певну стурбованість:
"Ей банда, будь ласка, реалізовуйте мою програму безкоштовно іншими мовами, тому мені не доведеться" (thx to @jstnthms)
Моя відповідь така:
Я легко можу це зробити на Java, C #, JS, Ocaml ... Це більше для задоволення. В даний час ми (команда Gimli) реалізували (та оптимізували) на AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-unroll, AVX, AVX2, VHDL та Python3. :)
Про Гімлі
Стан
Gimli застосовує послідовність раундів до 384-бітного стану. Стан представлений у вигляді паралелепіпеда з розмірами 3 × 4 × 32 або, що еквівалентно, як матриця 3 × 4 із 32-розрядних слів.

Кожен раунд - це послідовність трьох операцій:
- нелінійний шар, зокрема 96-бітний SP-вікно, застосований до кожного стовпця;
- у кожному другому раунді лінійний шар змішування;
- у кожному четвертому раунді постійне доповнення.
Нелінійний шар.
SP-вікно складається з трьох під-операцій: обертання першого та другого слів; 3-вхідна нелінійна Т-функція; і підміна першого та третього слів.

Лінійний шар.
Лінійний шар складається з двох операцій своп, а саме Small-Swap та Big-Swap. Small-Swap відбувається кожні 4 раунди, починаючи з 1-го раунду. Big-Swap відбувається кожні 4 раунди, починаючи з 3-го раунду.

Круглі константи.
У Гімлі 24 раунди, пронумеровані 24,23, ..., 1. Коли кругле число r дорівнює 24,20,16,12,8,4, ми XOR константа кругла (0x9e377900 XOR r) до першого слова стану.
довідкове джерело в С
#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);
}
}
}
Версія твіттера на 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
