この課題の目的は、選択した言語で、次の関数の不可能なほど短い実装を見つけるp
ことです。これを実装するCコード(出力も印刷するこのTIOリンクを参照
)と、それを含むウィキペディアページがあります。
unsigned char pi[] = {
252,238,221,17,207,110,49,22,251,196,250,218,35,197,4,77,
233,119,240,219,147,46,153,186,23,54,241,187,20,205,95,193,
249,24,101,90,226,92,239,33,129,28,60,66,139,1,142,79,
5,132,2,174,227,106,143,160,6,11,237,152,127,212,211,31,
235,52,44,81,234,200,72,171,242,42,104,162,253,58,206,204,
181,112,14,86,8,12,118,18,191,114,19,71,156,183,93,135,
21,161,150,41,16,123,154,199,243,145,120,111,157,158,178,177,
50,117,25,61,255,53,138,126,109,84,198,128,195,189,13,87,
223,245,36,169,62,168,67,201,215,121,214,246,124,34,185,3,
224,15,236,222,122,148,176,188,220,232,40,80,78,51,10,74,
167,151,96,115,30,0,98,68,26,184,56,130,100,159,38,65,
173,69,70,146,39,94,85,47,140,163,165,125,105,213,149,59,
7,88,179,64,134,172,29,247,48,55,107,228,136,217,231,137,
225,27,131,73,76,63,248,254,141,83,170,144,202,216,133,97,
32,113,103,164,45,43,9,91,203,155,37,208,190,229,108,82,
89,166,116,210,230,244,180,192,209,102,175,194,57,75,99,182,
};
unsigned char p(unsigned char x) {
return pi[x];
}
とは p
p
は、2つのロシアの暗号化標準、つまりハッシュ関数Streebogとブロック暗号Kuznyechikのコンポーネントです。で、この記事(およびISO会議中)、これらのアルゴリズムの設計者は、彼らが、配列を生成したと主張しpi
たランダム8ビットの順列を選ぶことで。
「不可能」な実装
あります!≈ 2 1684年 8ビットに置換。したがって、与えられたランダムな順列に対して、それを実装するプログラムは、1683ビット未満しか必要としないことが予想されます。
しかし、たとえば次のCプログラムのように、複数の異常に小さい実装(ここにリストされています)が見つかりました。
p(x){unsigned char*k="@`rFTDVbpPBvdtfR@\xacp?\xe2>4\xa6\xe9{z\xe3q5\xa7\xe8",l=0,b=17;while(--l&&x^1)x=2*x^x/128*285;return l%b?k[l%b]^k[b+l/b]^b:k[l/b]^188;}
158文字しか含まれていないため、1264ビットに収まります。ここをクリックして、動作することを確認してください。
置換がランダムプロセスの出力である場合(設計者が主張するように)、この短いプログラムは存在しないため、「あり得ない」短い実装について説明します(詳細については、このページを参照してください)。
リファレンス実装
以前のCコードのより読みやすいバージョンは次のとおりです。
unsigned char p(unsigned char x){
unsigned char
s[]={1,221,146,79,147,153,11,68,214,215,78,220,152,10,69},
k[]={0,32,50,6,20,4,22,34,48,16,2,54,36,52,38,18,0};
if(x != 0) {
unsigned char l=1, a=2;
while(a!=x) {
a=(a<<1)^(a>>7)*29;
l++;
}
unsigned char i = l % 17, j = l / 17;
if (i != 0) return 252^k[i]^s[j];
else return 252^k[j];
}
else return 252;
}
この表k
はk[x] = L(16-x)
、がL
であるという意味で線形でL(x^y)==L(x)^L(y)
あり、はCのように^
XORを示すという意味です。ただし、このプロパティを活用して実装を短縮することはできませんでした。s
より単純な実装を可能にする構造は認識していません。出力は常にサブフィールドにあります。つまり、であり、指数関数は有限体で行われます。もちろん、もしあなたがそれを見つけたら、もっと簡単な表現を使うことは絶対に自由です!s
whileループは、256要素の有限体の離散対数の評価に対応します。単純なブルートフォース検索で機能します。ダミー変数a
は有限体のジェネレーターに設定され、結果がに等しくなるまでこのジェネレーターで乗算されx
ます。その場合、それl
はの離散対数ですx
。この関数は0で定義されていないため、if
ステートメントに対応する特別なケースです。
ジェネレータによる乗算は乗算として見ることができるで次に、低減された多項式モジュロ。の役割は、変数が8ビットのままであることを保証することです。または、を使用することもできます。この場合、(または他の整数型)を使用できます。一方、1が1に等しい場合に必要なため、最初から開始する必要があります。unsigned char
a
a=(a<<1)^(a>>7)*(256^29)
a
int
l=1,a=2
l=255
x
のプロパティの詳細については、以前の短い実装を取得するための最適化のほとんどをまとめて、論文に記載p
されています。
ルール
p
1683ビット未満で関数を実装するプログラムを提案します。プログラムが短くなればなるほど、特定の言語にとっては異常であるほど、短いほど良いです。言語にKuznyechik、Streebogが含まれているかp
、組み込み言語として使用されている場合、それらを使用することはできません。
最適な実装を決定するために使用するメトリックは、バイト単位のプログラムの長さです。学術論文ではビット長を使用していますが、ここでは簡単にするためにバイトにこだわっています。
言語に関数、引数、または出力の明確な概念がない場合は、エンコードを定義するのはユーザー次第ですが、明らかに禁止さpi[x]
れてx
いる値のエンコードなどのトリックがあります。
このトピックに関する調査結果を含む研究論文をすでに提出しています。こちらから入手できます。しかし、科学の場で公開された場合、私たちは最高の実装の著者を喜んで認めます。
ところで、この質問を起草する際に彼の助けをしてくれたxnorに感謝します!
1683 bits at most
厳しい制限でしょうか?それとも目標ですか?