GolfScript, 60 caractères
{[[0 1{.283{1$2*.255>@*^}:r~^}255*].@?~)={257r}4*99]{^}*}:S;
Ce code définit une fonction nommée S
qui prend un octet et lui applique la S-box Rijndael. (Il utilise également une fonction d'assistance interne nommée r
pour enregistrer quelques caractères.)
Cette implémentation utilise une table de logarithmes pour calculer les inverses GF (2 8 ), comme suggéré par Thomas Pornin . Pour enregistrer quelques caractères, la table de logarithme entière est recalculée pour chaque octet d'entrée; malgré cela, et bien que GolfScript soit un langage très lent en général, ce code ne prend que 10 ms environ pour traiter un octet sur mon ancien ordinateur portable. Le précalcul de la table de logarithme (as L
) l'accélère jusqu'à environ 0,5 ms par octet, au coût modeste de trois caractères supplémentaires:
[0 1{.283{1$2*.255>@*^}:r~^}255*]:L;{[L?~)L={257r}4*99]{^}*}:S;
Pour plus de commodité, voici un harnais de test simple qui appelle la fonction S
, telle que définie ci-dessus, pour calculer et imprimer l'ensemble de la S-box en hexadécimal comme sur Wikipedia :
"0123456789abcdef"1/:h; 256, {S .16/h= \16%h= " "++ }% 16/ n*
Essayez ce code en ligne.
(La démo en ligne précalcule la table de logarithme pour éviter de prendre trop de temps. Même ainsi, le site GolfScript en ligne peut parfois expirer de manière aléatoire; il s'agit d'un problème connu avec le site, et un rechargement le corrige généralement.)
Explication:
Commençons par le calcul de la table de logarithme, et plus précisément avec la fonction d'assistance r
:
{1$2*.255>@*^}:r
Cette fonction prend deux entrées sur la pile: un octet et un masque de bits de réduction (une constante entre 256 et 511). Il duplique l'octet d'entrée, multiplie la copie par 2 et, si le résultat dépasse 255, le XOR avec le masque de bits pour le ramener sous 256.
Dans le code de génération de la table de journal, la fonction r
est appelée avec le masque de réduction 283 = 0x11b (qui correspond au polynôme de réduction Rijndael GF (2 8 ) x 8 + x 4 + x 3 + x + 1), et le résultat est XORed avec l'octet d'origine, en le multipliant effectivement par 3 (= x + 1, comme un polynôme) dans le champ fini de Rijndael. Cette multiplication est répétée 255 fois, à partir de l'octet 1, et les résultats (plus un zéro octet initial) sont collectés dans un tableau de 257 éléments L
qui ressemble à ceci (partie centrale omise):
[0 1 3 5 15 17 51 85 255 26 46 ... 180 199 82 246 1]
La raison pour laquelle il y a 257 éléments est que, avec le 0 précédant et 1 se produisant deux fois, nous pouvons trouver l'inverse modulaire de tout octet donné simplement en recherchant son index (de base zéro) dans ce tableau, en le niant et en regardant jusqu'à l'octet à l'index négatif dans le même tableau. (Dans GolfScript, comme dans de nombreux autres langages de programmation, les index de tableau négatifs comptent à rebours à partir de la fin du tableau.) En effet, c'est exactement ce que fait le code L?~)L=
au début de la fonction S
.
Le reste du code appelle la fonction d'assistance r
quatre fois avec le masque binaire de réduction 257 = 2 8 + 1 pour créer quatre copies à rotation binaire de l'octet d'entrée inversé. Ceux-ci sont tous collectés dans un tableau, avec la constante 99 = 0x63, et XOR ensemble pour produire la sortie finale.