GolfScript, 60 caratteri
{[[0 1{.283{1$2*.255>@*^}:r~^}255*].@?~)={257r}4*99]{^}*}:S;
Questo codice definisce una funzione denominata S
che accetta un byte e ad esso applica la S-box Rijndael. (Utilizza anche una funzione di supporto interna denominata r
per salvare alcuni caratteri.)
Questa implementazione utilizza una tabella di logaritmi per calcolare le inversioni di GF (2 8 ), come suggerito da Thomas Pornin . Per salvare alcuni caratteri, l'intera tabella del logaritmo viene ricalcolata per ogni byte di input; anche così, e nonostante GolfScript sia un linguaggio molto lento in generale, questo codice impiega solo circa 10 ms per elaborare un byte sul mio vecchio laptop. Il pre-calcolo della tabella del logaritmo (as L
) lo accelera fino a circa 0,5 ms per byte, al costo modesto di altri tre caratteri:
[0 1{.283{1$2*.255>@*^}:r~^}255*]:L;{[L?~)L={257r}4*99]{^}*}:S;
Per comodità, ecco un semplice cablaggio di prova che chiama la funzione S
, come definita sopra, per calcolare e stampare l'intera S-box in esadecimale come su Wikipedia :
"0123456789abcdef"1/:h; 256, {S .16/h= \16%h= " "++ }% 16/ n*
Prova questo codice online.
(La demo online precalcola la tabella dei logaritmi per evitare di impiegare troppo tempo. Anche così, il sito GolfScript online a volte può andare in timeout in modo casuale; questo è un problema noto con il sito e una ricarica di solito lo risolve.)
Spiegazione:
Cominciamo con il calcolo della tabella dei logaritmi, e in particolare con la funzione helper r
:
{1$2*.255>@*^}:r
Questa funzione accetta due input nello stack: un byte e una maschera di bit di riduzione (una costante tra 256 e 511). Duplica il byte di input, moltiplica la copia per 2 e, se il risultato supera 255, XORs con la maschera di bit per riportarlo sotto 256.
All'interno del codice di generazione della tabella di registro, la funzione r
viene chiamata con la maschera di bit di riduzione 283 = 0x11b (che corrisponde al polinomio di riduzione Rijndael GF (2 8 ) x 8 + x 4 + x 3 + x + 1) e il risultato è XORed con il byte originale, moltiplicandolo efficacemente per 3 (= x + 1, come polinomio) nel campo finito di Rijndael. Questa moltiplicazione viene ripetuta 255 volte, a partire dal byte 1, e i risultati (più un byte zero iniziale) vengono raccolti in un array di 257 elementi L
che assomiglia a questo (parte centrale omessa):
[0 1 3 5 15 17 51 85 255 26 46 ... 180 199 82 246 1]
Il motivo per cui ci sono 257 elementi è che, con lo 0 anteposto e con 1 che si verificano due volte, possiamo trovare l'inverso modulare di un dato byte semplicemente osservando il suo indice (a base zero) in questo array, negandolo e osservando il byte nell'indice negato nello stesso array. (In GolfScript, come in molti altri linguaggi di programmazione, gli indici di array negativi contano all'indietro dalla fine dell'array.) In effetti, questo è esattamente ciò che fa il codice L?~)L=
all'inizio della funzione S
.
Il resto del codice chiama la funzione helper r
quattro volte con la maschera di bit di riduzione 257 = 2 8 + 1 per creare quattro copie a rotazione di bit del byte di input invertito. Questi sono tutti raccolti in un array, insieme alla costante 99 = 0x63 e XORed insieme per produrre l'output finale.