Gimli ทำให้สั้นกว่านี้ใช่ไหม


25

ฉันเป็นหนึ่งในนักเขียนของกิมลี เรามี 2-tweet (280 chars) ใน C แต่ฉันอยากจะดูว่ามันเล็กแค่ไหน

Gimli ( paper , website ) เป็นความเร็วสูงด้วยการออกแบบการเปลี่ยนรูปแบบการเข้ารหัสลับระดับความปลอดภัยสูงที่จะนำเสนอในการประชุมเกี่ยวกับการเข้ารหัสฮาร์ดแวร์และระบบฝังตัว (CHES) 2017 (25-28 กันยายน)

งาน

ตามปกติ: เพื่อให้การนำ Gimli ไปปฏิบัติใช้ในภาษาที่คุณเลือกได้

มันควรจะสามารถใช้เป็นอินพุต 384 บิต (หรือ 48 ไบต์หรือ 12 int ไม่ได้ลงนาม ... ) และผลตอบแทน (อาจแก้ไขในสถานที่ถ้าคุณใช้ตัวชี้) ผลของ Gimliนำไปใช้กับ 384 บิตเหล่านี้

อนุญาตให้ทำการแปลงอินพุตจากทศนิยมฐานสิบหกฐานแปดหรือฐานสอง

กรณีมุมที่อาจเกิดขึ้น

การเข้ารหัสจำนวนเต็มจะถือว่าเป็น endian น้อย (เช่นสิ่งที่คุณอาจมีอยู่แล้ว)

คุณอาจเปลี่ยนชื่อGimliเป็นGแต่จะต้องยังคงเป็นการเรียกใช้ฟังก์ชัน

ใครชนะ?

นี่คือ code-golf ดังนั้นคำตอบที่สั้นที่สุดในหน่วยไบต์ชนะ! ใช้กฎมาตรฐานแน่นอน

การดำเนินการอ้างอิงมีให้ด้านล่าง

บันทึก

มีความกังวลเพิ่มขึ้น:

"เฮ้ก๊วนโปรดใช้โปรแกรมของฉันฟรีในภาษาอื่นดังนั้นฉันไม่จำเป็นต้อง" (ขอบคุณกับ @jstnthms)

คำตอบของฉันมีดังนี้:

ฉันสามารถทำได้ง่ายๆใน Java, C #, JS, Ocaml ... มันสนุกยิ่งกว่า ขณะนี้เรา (ทีม Gimli) ได้นำไปใช้ (และปรับให้เหมาะสม) กับ AVR, Cortex-M0, Cortex-M3 / M4, Neon, SSE, SSE-unrolled, AVX, AVX2, VHDL และ Python3 :)


เกี่ยวกับกิมลี

รัฐ

Gimli ใช้ลำดับของรอบกับสถานะ 384 บิต รัฐเป็นตัวแทนที่ขนานกับมิติ 3 × 4 × 32 หรือเทียบเท่าเป็นเมทริกซ์ 3 × 4 ของคำ 32- บิต

สถานะ

แต่ละรอบเป็นลำดับของการดำเนินการที่สาม:

  • เลเยอร์ที่ไม่ใช่เชิงเส้นโดยเฉพาะ 96 บิต SP- กล่องนำไปใช้กับแต่ละคอลัมน์;
  • ในทุก ๆ รอบที่สองชั้นผสมเชิงเส้น
  • ในทุก ๆ รอบที่สี่

ชั้นที่ไม่ใช่เชิงเส้น

กล่อง SP ประกอบด้วยการทำงานย่อยสามแบบ: การหมุนของคำแรกและคำที่สอง; 3-input non -earear T-function; และการสลับคำแรกและคำที่สาม

SP

ชั้นเชิงเส้น

เลเยอร์เชิงเส้นประกอบด้วยการดำเนินการสลับสองครั้งคือ 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) เป็นคำแรกของรัฐ

ป้อนคำอธิบายรูปภาพที่นี่

แหล่งอ้างอิงใน 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);
    }
  }
}

รุ่น Tweetable ใน 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
Stan Strum

1
ฉันรู้ว่าซึ่งเป็นเหตุผลที่มันเหมาะกับเป็น 2;) twitter.com/TweetGimli
Biv

10
"เฮ้แก๊งกรุณาใช้โปรแกรมของฉันฟรีในภาษาอื่น ๆ ดังนั้นฉันไม่ต้อง"
jstnthms

ฮ่าฮ่าฮ่าฉันมีมันใน Python อยู่แล้วและฉันสามารถทำได้ใน Java, C #, JS มันเป็นมากกว่าเพื่อความสนุกสนาน :)
Biv

5
รหัสอ้างอิงบนเว็บไซต์ที่มีข้อผิดพลาดที่สำคัญ-roundแทน--roundหมายความว่ามันไม่เคยสิ้นสุด --อาจไม่แนะนำให้แปลงเป็นเส้นประในรหัส :)
หรือ

คำตอบ:


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
}

สักครู่ฉันก็ถูกขว้างด้วยความจริงที่ว่า ouput ไม่ได้อยู่ในฐานสิบหก (ในการทดสอบออนไลน์) :)
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 ไบต์)
Peter Taylor

1
@PeterTaylor ถึงแม้ว่ารหัสของฉันจะคล้ายกัน แต่ฉันไม่ได้แข่งขันกับรหัสของ OP ฉันทำงานภายใต้กฎของ PPCG ที่ต้องทำงานอย่างน้อยต้องมีการติดตั้งบนแพลตฟอร์มและใช้กับgccซีพียู Intel แบบ 32 บิตหรือ 64 บิต (และอาจมากกว่านั้น)
orlp

4

C, 268 ตัวอักษร (268 ไบต์) โดยใช้ uint32_t

NB เนื่องจากรหัสดั้งเดิมใช้<stdint.h>และประเภทSตามที่uint32_t *ฉันคิดว่าการใช้longคือการโกงที่จะได้รับใน 280 chars ที่ค่าใช้จ่ายในการพกพาซึ่งเป็นเหตุผลสำหรับการใช้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ที่ได้รับมอบหมายทำให้พวกเขาปลอดภัย นักแสดงเมื่อกลับไปที่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ที่นี่ ...
Olivier Grégoire

@ OlivierGrégoireฉันคิดว่าเป็นเพียงส่วนที่เหลือจากฉันที่พยายาม Integer.divideUsigned แต่ฉันรู้ว่าฉันสามารถมี >>>
Roberto Graham

s[0]^=(0x9e377900|r);(ตอนท้ายสุด) - คุณไม่สามารถวางวงเล็บพิเศษได้หรือไม่?
Clashsoft

s[4+c]>>>(23)เช่นเดียวกันกับ
Clashsoft

1
คุณสามารถทำการเปลี่ยนแปลงน้อยลงและได้รับ 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);}}}300: ฉันได้ทำการเปลี่ยนแปลงเล็กน้อยที่จำเป็นเพื่อให้สามารถคอมไพล์ได้ กฎความสำคัญของ Java ไม่แตกต่างจาก C มากนัก
Peter Taylor

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

แอสเซมเบลอร์ x86 แบบ 32 บิต (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

เวอร์ชัน Tweetable (การเข้ารหัส Base85 รูปแบบ z85):

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.