김리, 더 짧게 만드세요?


25

저는 Gimli의 저자 중 한 사람입니다. 우리는 이미 C에 2 개의 트윗 (280 문자) 버전을 가지고 있지만 얼마나 작은 지 알고 싶습니다.

Gimli ( paper , website )는 CES ( Cryptographic Hardware and Embedded Systems) 2017 (9 월 25-28 일) 에서 발표 될 보안 수준이 높은 암호화 순열 설계가 적용된 고속입니다 .

작업

평소와 같이 : 선택한 언어로 작게 사용할 수있는 Gimli 구현.

입력 384 비트 (또는 48 바이트 또는 부호없는 int ... 12 )로 가져 와서이 384 비트에 적용된 Gimli의 결과를 리턴 (포인터를 사용하는 경우 제자리에서 수정 될 수 있음) 할 수 있어야합니다 .

10 진수, 16 진수, 8 진수 또는 2 진수로의 입력 변환이 허용됩니다.

잠재적 코너 케이스

정수 인코딩은 리틀 엔디안 인 것으로 가정합니다 (예 : 이미 가지고있는 것).

로 이름 Gimli을 바꿀 수 G있지만 여전히 함수 호출이어야합니다.

누가 이겼어?

이것은 코드 골프이므로 바이트 단위의 최단 답변이 이깁니다! 물론 표준 규칙이 적용됩니다.

참조 구현은 다음과 같습니다.

노트

몇 가지 우려가 제기되었습니다.

"헤이 갱, 다른 언어로 무료로 내 프로그램을 구현하십시오."

내 대답은 다음과 같습니다.

Java, C #, JS, Ocaml에서 쉽게 할 수 있습니다 ... 재미 있습니다. 현재 우리 (Gimli 팀)는 AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-unrolled, AVX, AVX2, VHDL 및 Python3에서 구현하고 최적화했습니다. :)


김리 소개

상태

Gimli는 일련의 라운드를 384 비트 상태로 적용합니다. 이 상태는 3 × 4 × 32 차원의 평행 육면체 또는 32 비트 워드의 3 × 4 행렬로 표시됩니다.

상태

각 라운드는 세 가지 작업의 순서입니다.

  • 비선형 층, 구체적으로 각 열에 적용되는 96 비트 SP- 박스;
  • 매 두번째 라운드에서, 선형 혼합 층;
  • 4 번째 라운드마다 지속적으로 추가됩니다.

비선형 레이어

SP-box는 세 가지 하위 작업으로 구성됩니다. 첫 번째 단어와 두 번째 단어의 회전; 3- 입력 비선형 T- 기능; 그리고 첫 번째 단어와 세 번째 단어의 교체.

SP

선형 레이어.

선형 계층은 스왑 작업 (Small-Swap 및 Big-Swap)으로 구성됩니다. 스몰 스왑은 1 라운드부터 4 라운드마다 발생합니다. 빅 스왑은 3 라운드부터 4 라운드마다 발생합니다.

선의

둥근 상수.

김리에는 24,23, ..., 1의 24 라운드가 있습니다. 라운드 수 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 

3
트윗 담아 가기 140 개 문자, 280
개가

1
나는 그것이 2;) twitter.com/TweetGimli에 맞는 이유를 알고 있습니다.
Biv

10
"헤이 갱, 다른 언어로 무료로 프로그램을 구현하십시오."
jstnthms

hahaha Nah 이미 Python으로 가지고 있으며 Java, C #, JS에서 쉽게 할 수 있습니다. 재미를 더합니다. :)
Biv

5
웹 사이트 의 참조 코드 는 종료되지 않는다는 의미가 -round아니라 중대한 오류 --round가 있습니다. --en 대시로 변환 하는 것은 아마도 코드에서 제안되지 않을 것입니다 :)
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
}

잠시 동안 출력이 16 진수 (온라인 테스트에서)가 아니라는 사실에 의해 던져졌습니다. :)
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 획득, 패배자 만들기 :)
orlp

Ah ok : P 의미가 있습니다 : P : P
HyperNeutrino

이것은 여전히 ​​향상된 개선 사항이지만 암호의 아이디어는 이식성이 뛰어 나기 때문에 unsigned대신 사용하는 것이 다소 부정적 입니다 uint32_t(그리고 OP의 코드는 다소 부정적이었습니다 long). (실제로 이것은 단지 8 바이트를 절약합니다).
피터 테일러

1
@PeterTaylor 내 코드가 비슷하지만 실제로 OP의 코드와 경쟁하지는 않습니다. PPCG의 규칙에 따라 작업 중이며 최소한 플랫폼에서 구현해야 gcc하며 32 비트 또는 64 비트 Intel CPU (및 더 많은 것)에서 작동합니다.
orlp

4

uint32_t를 사용하는 C, 268 자 (268 바이트)

NB 원래 코드는로 사용 <stdint.h>및 유형 Suint32_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

자바 (오픈 JDK 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를 사용하지 않아도 됩니다.
Olivier Grégoire

@ 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

자바 스크립트 (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

트윗 가능한 버전 (z85 형식 Base85 인코딩) :

v7vb1h> C} HbQuA91y51A : oWYw48G)? I = H /] rGf9Na> sA.DWu06 {6f # TEC ^ CM : # IeA-cstx7 :>! VfVf # u * YB & mP (tuCl * + 7eENBP) $ :) Lh! k } t $ ^ wM51j % LDf $ HMAg2bB ^ MQP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.