Gimli, làm cho nó thậm chí còn ngắn hơn?


25

Tôi là một trong những tác giả của Gimli. Chúng tôi đã có phiên bản 2 tweet (280 ký tự) trong C nhưng tôi muốn xem nó có thể nhỏ đến mức nào.

Gimli ( giấy , trang web ) là một tốc độ cao với thiết kế hoán vị mật mã cấp độ bảo mật cao sẽ được trình bày tại Hội nghị về Phần cứng và Hệ thống nhúng mã hóa (CHES) 2017 (25-28 / 9).

Nhiệm vụ

Như thường lệ: để thực hiện Gimli nhỏ có thể sử dụng được bằng ngôn ngữ bạn chọn.

Nó có thể lấy 384 bit đầu vào (hoặc 48 byte hoặc 12 không dấu int ...) và trả về (có thể sửa đổi tại chỗ nếu bạn sử dụng con trỏ) kết quả của Gimli được áp dụng trên 384 bit này.

Chuyển đổi đầu vào từ thập phân, thập lục phân, bát phân hoặc nhị phân được cho phép.

Trường hợp góc tiềm năng

Mã hóa số nguyên được coi là ít endian (ví dụ như những gì bạn có thể đã có).

Bạn có thể đổi tên Gimlithành Gnhưng nó vẫn phải là một hàm gọi.

Ai thắng?

Đây là môn đánh gôn, vì vậy câu trả lời ngắn nhất bằng byte sẽ thắng! Quy tắc tiêu chuẩn áp dụng tất nhiên.

Một triển khai tham khảo được cung cấp dưới đây.

chú thích

Một số lo ngại đã được nêu ra:

"Này các bạn, vui lòng triển khai chương trình của tôi miễn phí bằng các ngôn ngữ khác để tôi không phải" (thx to @jstnthms)

Câu trả lời của tôi như sau:

Tôi có thể dễ dàng làm điều đó trong Java, C #, JS, Ocaml ... Đó là nhiều hơn cho vui. Hiện tại, chúng tôi (nhóm Gimli) đã triển khai (và tối ưu hóa) trên AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-unrolled, AVX, AVX2, VHDL và Python3. :)


Về Gimli

Nhà nước

Gimli áp dụng một chuỗi các vòng cho trạng thái 384 bit. Trạng thái được biểu diễn dưới dạng song song với kích thước 3 × 4 × 32 hoặc tương ứng là ma trận 3 × 4 của các từ 32 bit.

tiểu bang

Mỗi vòng là một chuỗi gồm ba thao tác:

  • một lớp phi tuyến tính, cụ thể là hộp SP 96 bit được áp dụng cho mỗi cột;
  • trong mỗi vòng thứ hai, một lớp trộn tuyến tính;
  • trong mỗi vòng thứ tư, một sự bổ sung liên tục.

Lớp phi tuyến tính.

Hộp SP bao gồm ba thao tác phụ: xoay các từ thứ nhất và thứ hai; một hàm T phi tuyến 3 đầu vào; và hoán đổi từ thứ nhất và từ thứ ba.

SP

Lớp tuyến tính.

Lớp tuyến tính bao gồm hai hoạt động hoán đổi, cụ thể là Hoán đổi nhỏ và Hoán đổi lớn. Hoán đổi nhỏ xảy ra cứ sau 4 vòng bắt đầu từ vòng 1. Big-Swap xảy ra cứ sau 4 vòng bắt đầu từ vòng 3.

Tuyến tính

Các hằng số tròn.

Có 24 vòng ở Gimli, được đánh số 24,23, ..., 1. Khi số vòng r là 24,20,16,12,8,4, chúng tôi XOR hằng số vòng (0x9e377900 XOR r) cho từ trạng thái đầu tiên.

nhập mô tả hình ảnh ở đây

nguồn tham khảo trong 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);
    }
  }
}

Phiên bản có thể Tweet trong C

Đây có thể không phải là triển khai có thể sử dụng nhỏ nhất nhưng chúng tôi muốn có phiên bản tiêu chuẩn C (do đó không có UB và "có thể sử dụng" trong thư viện).

#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);}

Vectơ kiểm tra

Các đầu vào sau được tạo bởi

for (i = 0;i < 12;++i) x[i] = i * i * i + i * 0x9e3779b9;

và "in" giá trị bởi

for (i = 0;i < 12;++i) {
  printf("%08x ",x[i])
  if (i % 4 == 3) printf("\n");
}

do đó:

00000000 9e3779ba 3c6ef37a daa66d46 
78dde724 1715611a b54cdb2e 53845566 
f1bbcfc8 8ff34a5a 2e2ac522 cc624026 

nên trả lại:

ba11c85a 91bad119 380ce880 d24c2c68 
3eceffea 277a921c 4f73a0bd da5a9cd8 
84b673f0 34e52ff7 9e2bef49 f41bb8d6 

3
Một tweet là 140 ký tự, không phải là 280
Stan Strum

1
Tôi biết, đó là lý do tại sao nó phù hợp với 2;) twitter.com/TweetGimli .
Biv

10
"hey băng đảng, xin vui lòng thực hiện chương trình của tôi cho miễn phí bằng các ngôn ngữ khác vì vậy tôi không phải"
jstnthms

hahaha Nah Tôi đã có nó trong Python và tôi có thể dễ dàng làm điều đó bằng Java, C #, JS. Đó là nhiều hơn cho niềm vui. :)
Biv

5
Các mã tham chiếu trên trang web có một lỗi rất quan trọng, -roundthay vì --roundphương tiện mà nó không bao giờ chấm dứt. Chuyển đổi --sang dấu gạch ngang có lẽ không được đề xuất trong mã :)
orlp

Câu trả lời:


3

CJam (114 ký tự)

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

Đây là một khối ẩn danh (chức năng): nếu bạn muốn đặt tên cho nó Gthì hãy nối thêm :G. Trong tên được gán của CJam chỉ có thể là các chữ cái viết hoa. Có không gian để viết bình luận e# Gimli in CJamvà để lại các ký tự trong một tweet.

Bài kiểm tra trực tuyến

Mổ xẻ

{                                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
}

Trong một khoảnh khắc tôi đã bị ném bởi thực tế là ouput không ở dạng hex (trong bài kiểm tra trực tuyến). :)
Biv

15

C (gcc), 237 byte

#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)}}

Tôi có thể đã đạt được byte bằng phương pháp hoán đổi của mình, nhưng nó quá dễ thương để không sử dụng.


mất hay thu được?
HyperNeutrino

@HyperNeutrino Đạt được, khiến tôi trở thành kẻ thua cuộc :)
orlp

À ok: P có ý nghĩa: P: P
HyperNeutrino

Đây vẫn chắc chắn là một cải tiến, nhưng nó hơi gian lận khi sử dụng unsignedthay vì uint32_t(và mã của OP có phần gian lận khi sử dụng long) bởi vì ý tưởng đằng sau mật mã là nó rất dễ mang theo. (Trên thực tế, về cơ bản, điều này chỉ tiết kiệm được 8 byte).
Peter Taylor

1
@PeterTaylor Mặc dù mã của tôi tương tự, tôi không thực sự cạnh tranh với mã của OP. Tôi đang làm việc theo các quy tắc của PPCG, nơi nó phải hoạt động với ít nhất là triển khai trên nền tảng và nó hoạt động với gccCPU Intel 32 bit hoặc 64 bit (và có thể nhiều hơn nữa).
orlp

4

C, 268 ký tự (268 byte) bằng uint32_t

NB Vì mã ban đầu sử dụng <stdint.h>và các loại Snhư uint32_t *, tôi nghĩ rằng việc sử dụng longlà một mánh gian lận để có được 280 ký tự với chi phí tính di động là lý do để sử dụng uint32_tở nơi đầu tiên. Nếu để công bằng so sánh, chúng tôi yêu cầu sử dụng nhất quán uint32_tvà chữ ký rõ ràng void gimli(uint32_t *), mã gốc thực sự là 284 ký tự và mã của orlp là 276 ký tự.

#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];}

Điều này có thể được chia thành hai tweet với các dấu tiếp tục là

#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

Việc sử dụng longtrong phiên bản của tôi là an toàn (liên quan đến tính di động) vì kích thước tối thiểu của một chiều dài là 32 bit theo tiêu chuẩn (trái ngược với int). Việc luân chuyển xyđược thực hiện trước khi thực hiện longtại nhiệm vụ, làm cho chúng an toàn (vì sự thay đổi đúng về giá trị đã ký là phụ thuộc CC). Các diễn viên khi quay trở lại uint32_t* S) sẽ loại bỏ các bit trên và đưa chúng ta vào trạng thái phù hợp :).
Biv

2

Java (OpenJDK 8) , 351 343 339 320 318 247 + 56 byte

Chỉ cần một cổng gần 1: 1 của tài liệu tham khảo để bắt đầu chơi gôn.

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;}}}

Hãy thử trực tuyến!


1
Tại sao lại sử dụng Integer? o_O Vì bạn không sử dụng bất kỳ Integerphương pháp nào , không có lý do gì để không sử dụng intở đây ...
Olivier Grégoire

@ OlivierGrégoire Tôi nghĩ chỉ là phần còn lại từ tôi khi thử Integer.divideUnsign, nhưng tôi nhận ra rằng tôi có thể có >>>
Roberto Graham

s[0]^=(0x9e377900|r);(cuối cùng) - bạn có thể bỏ dấu ngoặc đơn không?
Clashsoft

Tương tự với s[4+c]>>>(23).
Clashsoft

1
Bạn có thể thực hiện ít thay đổi hơn và nhận được 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);}}}. Về cơ bản tôi đã thực hiện các thay đổi tối thiểu cần thiết để biên dịch nó. Các quy tắc ưu tiên của Java không khác lắm so với C.
Peter Taylor

2

JavaScript (ES6), 231 byte

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}

Bản giới thiệu


0

Trình biên dịch x86 32 bit (112 byte)

(Quy ước gọi __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

Phiên bản có thể tweet (mã hóa Base85 định dạng z85):

v7vb1h> C} HbQuA91y51A: oWYw48G)? I = H /] rGf9Na> sA.DWu06 {6f # TEC ^ CM: # IeA-cstx7:>! VfVf # u * YB & m } t $ ^ wM51j% LDf $ HMAg2bB ^ MQP
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.