Гімлі, зроби його ще коротшим?


25

Я один із авторів Гімлі. У нас вже є 2-твітна (280 символів) версія на С, але я хотів би побачити, наскільки вона може бути маленькою.

Gimli ( папір , веб-сайт ) - це висока швидкість із криптографічним перестановкою високого рівня безпеки, яка буде представлена ​​на конференції з криптографічного обладнання та вбудованих систем (CHES) 2017 (25-28 вересня).

Завдання

Як завжди: зробити неприємну корисну реалізацію Gimli мовою на ваш вибір.

Він повинен мати можливість приймати як вхідні 384 біта (або 48 байт, або 12 неподписаних int ...) і повертати (може змінюватися на місці, якщо ви використовуєте покажчики) результат Gimli, застосований до цих 384 біт.

Дозволено перетворення вводу з десяткових, шістнадцяткових, восьмеричних чи двійкових.

Потенційні кутові справи

Кодування цілочисниками вважається малоінтенсивним (наприклад, тим, що ви, мабуть, вже є).

Ви можете перейменувати Gimliв Gале вона все одно повинна бути викликом функції.

Хто виграє?

Це код-гольф, тому найкоротша відповідь у байтах виграє! Звичайно, застосовуються стандартні правила.

Нижче наведено посилання на реалізацію.

Примітка

Висловлено певну стурбованість:

"Ей банда, будь ласка, реалізовуйте мою програму безкоштовно іншими мовами, тому мені не доведеться" (thx to @jstnthms)

Моя відповідь така:

Я легко можу це зробити на Java, C #, JS, Ocaml ... Це більше для задоволення. В даний час ми (команда Gimli) реалізували (та оптимізували) на AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-unroll, AVX, AVX2, VHDL та Python3. :)


Про Гімлі

Стан

Gimli застосовує послідовність раундів до 384-бітного стану. Стан представлений у вигляді паралелепіпеда з розмірами 3 × 4 × 32 або, що еквівалентно, як матриця 3 × 4 із 32-розрядних слів.

держава

Кожен раунд - це послідовність трьох операцій:

  • нелінійний шар, зокрема 96-бітний SP-вікно, застосований до кожного стовпця;
  • у кожному другому раунді лінійний шар змішування;
  • у кожному четвертому раунді постійне доповнення.

Нелінійний шар.

SP-вікно складається з трьох під-операцій: обертання першого та другого слів; 3-вхідна нелінійна Т-функція; і підміна першого та третього слів.

СП

Лінійний шар.

Лінійний шар складається з двох операцій своп, а саме Small-Swap та Big-Swap. Small-Swap відбувається кожні 4 раунди, починаючи з 1-го раунду. Big-Swap відбувається кожні 4 раунди, починаючи з 3-го раунду.

Лінійний

Круглі константи.

У Гімлі 24 раунди, пронумеровані 24,23, ..., 1. Коли кругле число r дорівнює 24,20,16,12,8,4, ми XOR константа кругла (0x9e377900 XOR r) до першого слова стану.

введіть тут опис зображення

довідкове джерело в С

#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 

3
Твіт - 140 годин, а не 280
Стен Струм

1
Я знаю, саме тому воно вписується у 2;) twitter.com/TweetGimli .
Biv

10
"Ей банда, будь ласка,
реалізуйте

hahaha Nah У мене вже є в Python, і я легко можу це зробити в Java, C #, JS. Це більше для розваги. :)
Biv

5
Код посилання на веб-сайті має вирішальну помилку, -roundа не --roundозначає, що він ніколи не припиняється. Перетворення --на en dash, ймовірно, не пропонується в коді :)
orlp

Відповіді:


3

CJam (114 годин)

{24{[4/z{[8ZT].{8\#*G8#:Mmd+}__)2*\+.^W%\[_~;&8*\~@1$|2*@@&4*].^Mf%}%z([7TGT]R=4e!=\f=(2654435608R-_4%!*^\@]e_}fR}

Це анонімний блок (функція): якщо ви хочете назвати його, Gтоді додайте :G. У CJam призначені імена можуть бути лише окремими великими літерами. У коментарі є місце для додавання коментарів e# Gimli in CJamі символів, які залишилися.

Інтернет-тест

Розсічення

{                                e# Define a block
  24{                            e# For R=0 to 23...
    [                            e#   Collect values in an array
      4/z                        e#     Transpose to columns
      {                          e#     Map over each column
        [8ZT].{8\#*G8#:Mmd+}     e#       Rotations, giving [x y z]
        __)2*\+.^W%\             e#       => [y^z x^y x^z*2] [x y z]
        [_~;&8*\~@1$|2*@@&4*].^  e#       => [x' y' z']
        Mf%                      e#       Map out any bits which overflowed
      }%
      z                          e#    Transpose to rows
      ([7TGT]R=4e!=\f=           e#    Permute first row
      (2654435608R-_4%!*^        e#    Apply round constant to first element
      \@                         e#    Put the parts in the right order
    ]e_                          e#  Finish collecting in array and flatten
  }fR
}

На якусь мить мене кинуло те, що вихід не був у шістнадцятковій (в онлайн-тесті). :)
Biv

15

C (gcc), 237 байт

#define P(a,l)x=a;a=S[c=l>>r%4*2&3];S[c]=x;
r,c,x,y,z;G(unsigned*S){
for(r=24;r;*S^=r--%4?0:0x9e377901+r){
for(c=4;c--;*S++=z^y^8*(x&y))
x=*S<<24|*S>>8,y=S[4]<<9|S[4]>>23,z=S[8],S[8]=x^2*z^4*(y&z),S[4]=y^x^2*(x|z);
S-=4;P(*S,33)P(S[3],222)}}

Я, мабуть, набрав байти своїм методом заміни, але це занадто мило, щоб не використовувати.


загублений чи здобутий?
HyperNeutrino

@HyperNeutrino Здобув, зробивши мене
невдалою

Ну добре: P має сенс: P: P
HyperNeutrino

Це, безумовно, є поліпшенням, але використовувати його unsignedзамість uint32_t(а код ОП дещо обманює використання long), оскільки ідея за шифром полягає в тому, що він дуже портативний. (Насправді це принципово економить лише 8 байт).
Пітер Тейлор

1
@PeterTaylor Незважаючи на те, що мій код схожий, я не дуже змагаюся з кодом ОП. Я працюю за правилами PPCG, де він повинен працювати принаймні з реалізацією на платформі, і це робиться з gcc32-бітним або 64-бітним процесором Intel (і, мабуть, ще багатьма).
orlp

4

C, 268 символів (268 байт), використовуючи uint32_t

NB Зважаючи на те, що оригінальний код використовує такі <stdint.h>типи, Sяк uint32_t *, я вважаю, це використання long- це обман, щоб потрапити на 280 символів ціною переносимості, що є причиною використання uint32_tв першу чергу. Якщо для справедливості порівняння нам потрібне послідовне використання uint32_tта явна підпис void gimli(uint32_t *), оригінальний код дійсно становить 284 символів, а код orlp - 276 символів.

#include<stdint.h>
#define R(V)x=S[V],S[V]=S[V^y],S[V^y]=x,
void gimli(uint32_t*S){for(uint32_t r=24,x,y,z,*T;r--;y=72>>r%4*2&3,R(0)R(3)*S^=y&1?0x9e377901+r:0)for(T=S+4;T-->S;*T=z^y^8*(x&y),T[4]=y^x^2*(x|z),T[8]=x^2*z^4*(y&z))x=*T<<24|*T>>8,y=T[4]<<9|T[4]>>23,z=T[8];}

Це можна розділити на два твіти з маркерами продовження як

#include<stdint.h>
#define R(V)x=S[V],S[V]=S[V^y],S[V^y]=x,
void gimli(uint32_t*S){for(uint32_t r=24,x,y,z,*T;r--;y=72>>r%4*2&3,R(0)R(3)// 1

і

*S^=y&1?0x9e377901+r:0)for(T=S+4;T-->S;*T=z^y^8*(x&y),T[4]=y^x^2*(x|z),T[8]=x^2*z^4*(y&z))x=*T<<24|*T>>8,y=T[4]<<9|T[4]>>23,z=T[8];}// 2/2

Використання longв моїй версії є безпечним (щодо портативності), оскільки мінімальний розмір довгого стандарту становить 32 біти (на відміну від int). Обертання xта yвиконуються перед тим, як приступити до longвиконання завдання, роблячи їх безпечними (оскільки правильний зсув на підписане значення залежить від CC). Акторський склад при поверненні до uint32_t* S) позбавляється від верхніх бітів і приводить нас у правильний стан :).
Biv

2

Java (OpenJDK 8) , 351 343 339 320 318 247 + 56 байт

Всього близько 1: 1 посилання для початку гольфу.

void f(int[]x,int y,int z){int q=x[y];x[y]=x[z];x[z]=q;}

s->{for(int r=24,c,x,y,z;r>0;--r){for(c=0;c<4;x=s[c]<<24|s[c]>>>8,y=s[4+c]<<9|s[4+c]>>>23,z=s[8+c],s[8+c]=x^z<<1^(y&z)<<2,s[4+c]=y^x^(x|z)<<1,s[c++]=z^y^(x&y)<<3);if((r&3)==2){f(s,0,2);f(s,1,3);}if((r&3)<1){f(s,0,1);f(s,2,3);s[0]^=0x9e377900|r;}}}

Спробуйте в Інтернеті!


1
Навіщо використовувати Integerвзагалі? o_O Оскільки ви не використовуєте жодного Integerметоду, немає причин не використовувати intтут s ...
Олів'є Грегоар

@ OlivierGrégoire Я думаю, що це просто залишок від мене, що намагається Integer.divideUnsigned, але я зрозумів, що можу мати >>>
Роберто Грем

s[0]^=(0x9e377900|r);(в самому кінці) - ви не можете скинути зайві дужки?
Clashsoft

Те саме з s[4+c]>>>(23).
Clashsoft

1
Ви можете внести набагато менше змін і отримати 300 : 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);}}}. Я в основному вніс мінімальні зміни, необхідні для збору. Правила пріоритету Java не сильно відрізняються від C.
Пітер Тейлор

2

JavaScript (ES6), 231 байт

s=>{for(r=25;--r;[a,b,c,d,...e]=s,s=r&1?s:r&2?[c,d,a,b,...e]:[b,a,d,c,...e],s[0]^=r&3?0:0x9e377900|r)for(c=4;c--;x=s[c]<<24|s[c]>>>8,y=s[j=c+4]<<9|s[j]>>>23,z=s[c+8],s[c+8]=x^z*2^(y&z)*4,s[j]=y^x^(x|z)*2,s[c]=z^y^(x&y)*8);return s}

Демо


0

32-розрядний асемблер x86 (112 байт)

(__cdecl виклик конвенції)

            pusha
            mov     ecx, 9E377918h
    loc_6:  mov     esi, [esp+24h]
            push    esi
            push    4
            pop     ebx
    loc_E:  lodsd
            ror     eax, 8
            mov     ebp, [esi+0Ch]
            rol     ebp, 9
            mov     edx, [esi+1Ch]
            push    eax
            push    ebp
            lea     edi, [edx+edx]
            and     ebp, edx
            shl     ebp, 2
            xor     edi, ebp
            xor     eax, edi
            mov     [esi+1Ch], eax
            pop     ebp
            pop     eax
            push    eax
            push    ebp
            xor     ebp, eax
            or      eax, edx
            shl     eax, 1
            xor     ebp, eax
            mov     [esi+0Ch], ebp
            pop     ebp
            pop     eax
            xor     edx, ebp
            and     eax, ebp
            shl     eax, 3
            xor     edx, eax
            push    edx
            dec     ebx
            jnz     short loc_E
            pop     esi
            pop     ebp
            pop     ebx
            pop     eax
            pop     edi
            mov     dl, cl
            and     dl, 3
            jnz     short loc_5B
            xchg    eax, ebx
            xchg    esi, ebp
            xor     eax, ecx
    loc_5B: cmp     dl, 2
            jnz     short loc_63
            xchg    eax, ebp
            xchg    esi, ebx
    loc_63: stosd
            xchg    eax, ebx
            stosd
            xchg    eax, ebp
            stosd
            xchg    eax, esi
            stosd
            dec     cl
            jnz     short loc_6
            popa
            retn

Версія твітера (кодування Base85 у форматі z85):

v7vb1h> C} HbQuA91y51A: oWYw48G)? I = H /] rGf9Na> sA.DWu06 {6f # TEC ^ CM: # IeA-cstx7:>! VfVf # u * YB & mP (tuCl * + 7eENBP) $ :) Lh! kh! } t $ ^ wM51j% LDf $ HMAg2bB ^ MQP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.