Saya salah satu penulis Gimli. Kami sudah memiliki versi 2-tweet (280 karakter) di C tapi saya ingin melihat seberapa kecil itu bisa didapat.
Gimli ( kertas , situs web ) adalah kecepatan tinggi dengan desain permutasi kriptografi tingkat keamanan tinggi yang akan dipresentasikan pada Konferensi Perangkat Keras Kriptografi dan Sistem Tertanam (CHES) 2017 (25-28 September).
Tugas
Seperti biasa: untuk membuat implementasi Gimli yang dapat digunakan menjadi lebih kecil dalam bahasa pilihan Anda.
Seharusnya dapat mengambil 384 bit input (atau 48 byte, atau 12 int unsigned ...) dan mengembalikan (dapat memodifikasi di tempat jika Anda menggunakan pointer) hasil Gimli diterapkan pada 384 bit ini.
Konversi input dari desimal, heksadesimal, oktal atau biner diperbolehkan.
Kasing sudut potensial
Encoding integer diasumsikan sebagai little-endian (mis. Apa yang mungkin sudah Anda miliki).
Anda dapat mengubah nama Gimli
menjadi G
tetapi masih harus berupa panggilan fungsi.
Yang menang?
Ini adalah kode-golf sehingga jawaban tersingkat dalam byte menang! Aturan standar berlaku tentu saja.
Implementasi referensi disediakan di bawah ini.
Catatan
Beberapa keprihatinan telah dikemukakan:
"hei geng, tolong implementasikan program saya secara gratis dalam bahasa lain jadi saya tidak perlu" (thx to @jstnthms)
Jawaban saya adalah sebagai berikut:
Saya dapat dengan mudah melakukannya di Java, C #, JS, Ocaml ... Ini lebih untuk bersenang-senang. Saat ini Kami (tim Gimli) menerapkannya (dan dioptimalkan) pada AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-unrolled, AVX, AVX2, VHDL dan Python3. :)
Tentang Gimli
Negara
Gimli menerapkan urutan putaran ke keadaan 384-bit. Negara direpresentasikan sebagai paralelepiped dengan dimensi 3 × 4 × 32 atau, setara, sebagai matriks 3 × 4 kata 32-bit.
Setiap putaran adalah urutan dari tiga operasi:
- lapisan non-linear, khususnya SP-box 96-bit yang diterapkan pada setiap kolom;
- di setiap putaran kedua, lapisan pencampuran linier;
- di setiap ronde keempat, tambahan konstan.
Lapisan non-linear.
Kotak-SP terdiri dari tiga sub-operasi: rotasi kata pertama dan kedua; fungsi-T non-linier 3-input; dan swap kata pertama dan ketiga.
Lapisan linier.
Lapisan linier terdiri dari dua operasi swap, yaitu Small-Swap dan Big-Swap. Small-Swap terjadi setiap 4 ronde mulai dari ronde 1. Big-Swap terjadi setiap 4 putaran mulai dari putaran ke-3.
Konstanta bulat.
Ada 24 putaran di Gimli, bernomor 24,23, ..., 1. Ketika bilangan bulat r adalah 24,20,16,12,8,4 kita XOR konstanta putaran (0x9e377900 XOR r) ke kata keadaan pertama.
sumber referensi dalam 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);
}
}
}
Versi Tweetable dalam C
Ini mungkin bukan implementasi terkecil yang dapat digunakan tetapi kami ingin memiliki versi standar C (sehingga tidak ada UB, dan "dapat digunakan" di perpustakaan).
#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);}
Tes vektor
Input berikut dihasilkan oleh
for (i = 0;i < 12;++i) x[i] = i * i * i + i * 0x9e3779b9;
dan nilai "dicetak" oleh
for (i = 0;i < 12;++i) {
printf("%08x ",x[i])
if (i % 4 == 3) printf("\n");
}
demikian:
00000000 9e3779ba 3c6ef37a daa66d46
78dde724 1715611a b54cdb2e 53845566
f1bbcfc8 8ff34a5a 2e2ac522 cc624026
harus kembali:
ba11c85a 91bad119 380ce880 d24c2c68
3eceffea 277a921c 4f73a0bd da5a9cd8
84b673f0 34e52ff7 9e2bef49 f41bb8d6
-round
bukan--round
berarti bahwa hal itu tidak pernah berakhir. Mengubah--
ke en dasbor mungkin tidak disarankan dalam kode :)Jawaban:
CJam (114 karakter)
Ini adalah blok anonim (fungsi): jika Anda ingin memberi nama
G
maka tambahkan:G
. Dalam CJam, nama yang diberikan hanya bisa berupa huruf besar tunggal. Ada ruang untuk menambahkan komentare# Gimli in CJam
dan membiarkan karakter tersisa dalam satu tweet.Tes online
Pembedahan
sumber
C (gcc), 237 byte
Saya mungkin mendapatkan byte dengan metode swapping saya, tetapi terlalu manis untuk tidak digunakan.
sumber
unsigned
alih-alihuint32_t
(dan kode OP agak curang untuk digunakanlong
) karena ide di balik cipher adalah sangat portabel. (Bahkan, pada dasarnya ini menghemat hanya 8 byte).gcc
pada CPU Intel 32-bit atau 64-bit (dan mungkin banyak lagi).C, 268 karakter (268 byte) menggunakan uint32_t
NB Karena kode penggunaan asli
<stdint.h>
dan jenisS
sepertiuint32_t *
, saya pikir penggunaanlong
adalah cheat untuk masuk ke 280 karakter pada biaya portabilitas yang merupakan alasan untuk menggunakanuint32_t
di tempat pertama. Jika untuk keadilan perbandingan kami membutuhkan penggunaan konsistenuint32_t
dan tanda tangan eksplisitvoid gimli(uint32_t *)
, kode asli benar-benar 284 karakter, dan kode orlp adalah 276 karakter.Ini dapat dibagi menjadi dua tweet dengan penanda kelanjutan sebagai
dan
sumber
long
dalam versi saya aman (sehubungan dengan portabilitas) karena ukuran minimum yang panjang adalah 32 bit menurut standar (sebagai lawan dariint
). Rotasix
dany
dilakukan sebelum dilemparkan kelong
dalam penugasan, membuatnya aman (karena pergeseran kanan pada nilai yang ditandatangani adalah ketergantungan CC). Para pemain ketika akan kembali keuint32_t* S
) menghilangkan bit atas dan menempatkan kita dalam keadaan yang tepat :).Java (OpenJDK 8) ,
351343339320318247 + 56 byteHanya dekat 1: 1 dari referensi untuk mulai bermain golf.
Cobalah online!
sumber
Integer
sama sekali? o_O Karena Anda tidak menggunakanInteger
metode apa pun , tidak ada alasan untuk tidak menggunakannyaint
di sini ...s[0]^=(0x9e377900|r);
(di akhir) - tidak bisakah Anda menjatuhkan kurung tambahan?s[4+c]>>>(23)
.void P(int[]S,int a,int b){int x=S[a];S[a]=S[b];S[b]=x;}void gimli(int[]S){for(int r=24,c,x,y,z;r>0;S[0]^=y<1?0x9e377901+r:0){for(c=4;c-->0;){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);}y=r%4;if(--r%2>0){P(S,0,1+y/2);P(S,3,2-y/2);}}}
. Saya pada dasarnya telah membuat perubahan minimal yang diperlukan untuk mengkompilasi. Aturan presedensi Java tidak jauh berbeda dengan C.JavaScript (ES6), 231 byte
Demo
Tampilkan cuplikan kode
sumber
Assembler x86 32-bit (112 byte)
(__cdlelepon konvensi)
Versi Tweetable (pengkodean base85 format-z85):
sumber