私はギムリの著者の一人です。Cにはすでに2ツイート(280文字)のバージョンがありますが、どれだけ小さくできるかを確認したいと思います。
Gimli(論文、ウェブサイト)は、暗号化ハードウェアおよび組み込みシステムに関する会議(CHES)2017(9月25-28日)で発表される、高セキュリティレベルの暗号順列設計です。
タスク
いつものように:Gimliの小さく使用可能な実装を、選択した言語で作成します。
することができるはず、入力として384ビット取る(...または48バイト、または12 unsigned int型の)とリターン(あなたは、ポインタを使用する場合は所定の位置に変更することができる)ギムリの結果は、これらの384ビットに適用されます。
10進数、16進数、8進数、または2進数からの入力変換が許可されます。
潜在的なコーナーケース
整数エンコードは、リトルエンディアンであると想定されます(たとえば、既にあるもの)。
名前を変更するGimli
にG
それはまだ、関数呼び出しでなければなりません。
誰が勝ちますか?
これはコードゴルフなので、バイト単位の最短回答が勝ちです!もちろん、標準ルールが適用されます。
リファレンス実装を以下に示します。
注意
いくつかの懸念が提起されました。
「ギャングさん、私のプログラムを他の言語で無料で実装してください。そうする必要はありません」(thx to @jstnthms)
私の答えは次のとおりです。
Java、C#、JS、Ocamlで簡単に実行できます。現在、我々(Gimliチーム)は、AVR、Cortex-M0、Cortex-M3 / M4、Neon、SSE、SSE-unrolled、AVX、AVX2、VHDL、Python3に実装(および最適化)しています。:)
Gimliについて
状態
Gimliは、一連のラウンドを384ビット状態に適用します。状態は、次元3×4×32の平行六面体、または同等に、32ビットワードの3×4マトリックスとして表されます。
各ラウンドは、3つの操作のシーケンスです。
- 非線形層、具体的には各列に適用される96ビットSPボックス。
- 2ラウンドごとに、線形混合層。
- 4ラウンドごとに、一定の追加。
非線形レイヤー。
SPボックスは3つのサブ操作で構成されています。1番目と2番目の単語の回転。3入力の非線形T関数。そして、最初と3番目の単語の交換。
線形レイヤー。
リニアレイヤーは、Small-SwapとBig-Swapの2つのスワップ操作で構成されます。スモールスワップは、1ラウンド目から4ラウンドごとに発生します。ビッグスワップは、3ラウンド目から4ラウンドごとに発生します。
ラウンド定数。
ギムリには24ラウンド、24、23、...、1の番号が付けられています。ラウンド数rが24,20,16,12,8,4の場合、ラウンド定数(0x9e377900 XOR r)を最初の状態ワードとXORします。
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);
}
}
}
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