Jestem jednym z autorów Gimli. Mamy już wersję z 2 tweetami (280 znaków) w C, ale chciałbym zobaczyć, jak mała może być.
Gimli ( papier , strona internetowa ) to projekt z dużą szybkością i permutacją kryptograficzną o wysokim poziomie bezpieczeństwa, który zostanie zaprezentowany podczas Konferencji na temat sprzętu kryptograficznego i systemów wbudowanych (CHES) 2017 (25-28 września).
Zadanie
Jak zwykle: aby niewielka użyteczna implementacja Gimli w wybranym przez Ciebie języku.
Powinien być w stanie pobrać 384 bity (lub 48 bajtów lub 12 znaków bez znaku ...) i zwrócić (może zmodyfikować w miejscu, jeśli używasz wskaźników) wynik Gimli zastosowany na tych 384 bitach.
Dozwolona jest konwersja wejściowa z dziesiętnej, szesnastkowej, ósemkowej lub binarnej.
Potencjalne narożne skrzynki
Zakłada się, że kodowanie liczb całkowitych ma charakter endianowy (np. To, co prawdopodobnie już masz).
Możesz zmienić nazwę Gimlina, Gale wciąż musi to być wywołanie funkcji.
Kto wygrywa?
To jest golf golfowy, więc wygrywa najkrótsza odpowiedź w bajtach! Oczywiście obowiązują standardowe zasady.
Implementacja referencyjna znajduje się poniżej.
Uwaga
Pojawiły się pewne obawy:
„hej, proszę, zaimplementuj mój program za darmo w innych językach, aby nie musiałem” (podziękowania dla @jstnthms)
Moja odpowiedź jest następująca:
Z łatwością mogę to zrobić w Javie, C #, JS, Ocaml ... To jest więcej dla zabawy. Obecnie My (zespół Gimli) wdrożyliśmy (i zoptymalizowaliśmy) w AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-Unrolled, AVX, AVX2, VHDL i Python3. :)
O Gimli
Stan
Gimli stosuje sekwencję rund do stanu 384-bitowego. Stan jest reprezentowany jako równoległościan o wymiarach 3 × 4 × 32 lub, równoważnie, jako macierz 3 × 4 32-bitowych słów.

Każda runda jest sekwencją trzech operacji:
- warstwa nieliniowa, w szczególności 96-bitowy moduł SP nałożony na każdą kolumnę;
- w każdej drugiej rundzie liniowa warstwa mieszająca;
- w co czwartej rundzie stały dodatek.
Warstwa nieliniowa.
SP-box składa się z trzech podoperacji: rotacji pierwszego i drugiego słowa; 3-wejściowa nieliniowa funkcja T; i zamiana pierwszego i trzeciego słowa.

Warstwa liniowa.
Warstwa liniowa składa się z dwóch operacji wymiany, mianowicie Small-Swap i Big-Swap. Small-Swap występuje co 4 rundy, zaczynając od 1. rundy. Big-Swap odbywa się co 4 rundy, począwszy od 3 rundy.

Stałe rundy.
Gimli ma 24 rundy o numerach 24,23, ..., 1. Gdy liczba rundy r wynosi 24,20,16,12,8,4 XOR, stała XOR (0x9e377900 XOR r) do pierwszego słowa stanu.
źródło odniesienia w 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);
}
}
}
Wersja tweetowana w C.
Być może nie jest to najmniejsza użyteczna implementacja, ale chcieliśmy mieć wersję standardową C (a zatem brak UB i „użyteczną” w bibliotece).
#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);}
Wektor testowy
Następujące dane wejściowe wygenerowane przez
for (i = 0;i < 12;++i) x[i] = i * i * i + i * 0x9e3779b9;
i „wydrukowane” wartości przez
for (i = 0;i < 12;++i) {
printf("%08x ",x[i])
if (i % 4 == 3) printf("\n");
}
a zatem:
00000000 9e3779ba 3c6ef37a daa66d46
78dde724 1715611a b54cdb2e 53845566
f1bbcfc8 8ff34a5a 2e2ac522 cc624026
powinien zwrócić:
ba11c85a 91bad119 380ce880 d24c2c68
3eceffea 277a921c 4f73a0bd da5a9cd8
84b673f0 34e52ff7 9e2bef49 f41bb8d6
-roundzamiast --roundoznacza, że nigdy nie wygasa. Konwersja --na myślnik nie jest prawdopodobnie sugerowana w kodzie :)
