Sono uno degli autori di Gimli. Abbiamo già una versione a 2 tweet (280 caratteri) in C, ma vorrei vedere quanto può essere piccola.
Gimli ( carta , sito Web ) è un'alta velocità con un design di permutazione crittografica di alto livello di sicurezza che sarà presentato alla Conferenza su hardware crittografico e sistemi integrati (CHES) 2017 (25-28 settembre).
L'obiettivo
Come al solito: rendere l'implementazione ridotta di Gimli nella lingua che preferisci.
Dovrebbe essere in grado di prendere come input 384 bit (o 48 byte o 12 unsigned int ...) e restituire (può modificare sul posto se si utilizzano i puntatori) il risultato di Gimli applicato su questi 384 bit.
È consentita la conversione di input da decimale, esadecimale, ottale o binario.
Casi d'angolo potenziali
Si presume che la codifica intera sia little-endian (ad es. Quello che probabilmente hai già).
È possibile rinominare Gimli
in G
ma deve essere comunque una chiamata di funzione.
Chi vince?
Questo è code-golf quindi vince la risposta più breve in byte! Ovviamente si applicano le regole standard.
Di seguito viene fornita un'implementazione di riferimento.
Nota
Sono state sollevate alcune preoccupazioni:
"hey gang, per favore attua il mio programma gratuitamente in altre lingue, quindi non devo" (grazie a @jstnthms)
La mia risposta è la seguente:
Posso facilmente farlo in Java, C #, JS, Ocaml ... È più divertente. Attualmente (il team Gimli) l'abbiamo implementato (e ottimizzato) su AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-srolled, AVX, AVX2, VHDL e Python3. :)
Informazioni su Gimli
Lo stato
Gimli applica una sequenza di round a uno stato di 384 bit. Lo stato è rappresentato come un parallelepipedo con dimensioni 3 × 4 × 32 o, equivalentemente, come una matrice 3 × 4 di parole a 32 bit.
Ogni round è una sequenza di tre operazioni:
- uno strato non lineare, in particolare una SP-box a 96 bit applicata a ciascuna colonna;
- in ogni secondo giro, uno strato di miscelazione lineare;
- in ogni quarto round, un'aggiunta costante.
Lo strato non lineare.
La SP-box è composta da tre sotto-operazioni: rotazioni della prima e della seconda parola; una funzione T non lineare a 3 ingressi; e uno scambio di prima e terza parola.
Lo strato lineare
Lo strato lineare è costituito da due operazioni di swap, ovvero Small-Swap e Big-Swap. Lo Small Swap si verifica ogni 4 round a partire dal 1 ° round. Il Big-Swap si verifica ogni 4 round a partire dal 3 ° round.
Le costanti rotonde.
Ci sono 24 round in Gimli, numerati 24,23, ..., 1. Quando il numero tondo r è 24,20,16,12,8,4 XOR la costante tonda (0x9e377900 XOR r) alla prima parola di stato.
fonte di riferimento in 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);
}
}
}
Versione Tweet in C
Questa potrebbe non essere la più piccola implementazione utilizzabile ma volevamo avere una versione C standard (quindi nessun UB, e "utilizzabile" in una libreria).
#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);}
Test vettoriale
Il seguente input generato da
for (i = 0;i < 12;++i) x[i] = i * i * i + i * 0x9e3779b9;
e valori "stampati" di
for (i = 0;i < 12;++i) {
printf("%08x ",x[i])
if (i % 4 == 3) printf("\n");
}
in tal modo:
00000000 9e3779ba 3c6ef37a daa66d46
78dde724 1715611a b54cdb2e 53845566
f1bbcfc8 8ff34a5a 2e2ac522 cc624026
dovrebbe restituire:
ba11c85a 91bad119 380ce880 d24c2c68
3eceffea 277a921c 4f73a0bd da5a9cd8
84b673f0 34e52ff7 9e2bef49 f41bb8d6
-round
invece di --round
indicare che non termina mai. La conversione --
in un trattino non è probabilmente suggerita nel codice :)