Я один із авторів Гімлі. У нас вже є 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