SIMECK Block Cipher


The Simeck Family of Lightweight Block Ciphers written by Gangqiang Yang, Bo Zhu, Valentin Suder, Mark D. Aagaard, and Guang Gong was published in 2015. According to the authors, SIMECK combines the good design components of both SIMON and SPECK, in order to devise more compact and efficient block ciphers. There are three variants.

  • Simeck32/64
  • Simeck48/96
  • Simeck64/128

Only the 64/128 version of encryption is implemented here because it has the most potential to be used in applications. Reference implementations for all variants by Bo Zhu can be found here.

Compact code

The following combines key scheduling and encryption in one function. mk should point to a 128-bit master key while data should point to a 64-bit block of plaintext to encrypt. The value 0x938BCA3083F used for the key schedule is exactly 44 bits, and because there are 44 rounds of encryption, it’s also used as the loop counter.

#define R(v,n)(((v)<<(n))|((v)>>(32-(n))))
#define X(a,b)(t)=(a),(a)=(b),(b)=(t)

void simeck(void*mk,void*p){
  unsigned int t,k0,k1,k2,k3,l,r,*k=mk,*x=p;
  unsigned long long s=0x938BCA3083F;


  } while(s>>=1);
  x[0]=r; x[1]=l;

x86 assembly

; -----------------------------------------------
; SIMECK64/128 Block Cipher in x86 assembly
; size: 97 bytes
; global calls use cdecl convention
; -----------------------------------------------
    bits 32

    %ifndef BIN
      global _simeck

struc pushad_t
  _edi resd 1
  _esi resd 1
  _ebp resd 1
  _esp resd 1
  _ebx resd 1
  _edx resd 1
  _ecx resd 1
  _eax resd 1

%define x0 ebx
%define x1 eax

%define k0 ecx
%define k1 edx
%define k2 edi
%define k3 ebp

%define t0 esi
%define s0 dword[esp+_edi+4]
%define s1 dword[esp+_esi+4]

    mov    edi, 0xBCA3083F
    mov    esi, 0x938
    mov    esi, [esp+64+4] ; esi=mk
    xchg   eax, k0
    xchg   eax, k1
    xchg   eax, k2
    xchg   eax, k3
    mov    esi, [esp+64+8] ; esi=x
    push   esi
    xchg   eax, x0
    xor    x0, k0  ; x[0]^=k[0];
    mov    t0, x1  ; x[0]^=R(x[1],1);
    rol    t0, 1   ;
    xor    x0, t0  ;
    rol    t0, 4   ; x[0]^=(R(x[1],5)&x[1]);
    and    t0, x1  ;
    xor    x0, t0  ;

    xchg   x0, x1  ; X(x[0],x[1]);

    ; t0 = (s & 1) - 4;
    xor    t0, t0
    shr    s1, 1
    rcr    s0, 1
    adc    t0, -4

    xor    k0, t0  ; k[0]^=t0;
    mov    t0, k1  ; k[0]^=R(k[1],1);
    rol    t0, 1   ;
    xor    k0, t0  ;
    rol    t0, 4   ; k[0]^=(R(k[1],5)&k[1]);
    and    t0, k1  ;
    xor    k0, t0  ;

    xchg   k0, k1  ; X(k[0],k[1]);
    xchg   k1, k2  ; X(k[1],k[2]);
    xchg   k2, k3  ; X(x[0],k[0]);

    cmp    s0, 0
    jnz    sm_l0

    pop    edi
    xchg   eax, x0
    stosd          ; x[0]=x0;
    xchg   eax, x0
    stosd          ; x[1]=x1;


ARM assembly

  .arch armv6
  .align  2

  .global simeck
k  .req r0
p  .req r1

r  .req r2
l  .req r3

k0 .req r4
k1 .req r5
k2 .req r6
k3 .req r7

t0 .req r8
t1 .req r9

sx .req r10
sy .req r11

    // save registers
    push   {r0-r12, lr}
    // unsigned long long s=0x938BCA3083F;
    ldr    sx, =#0xBCA3083F
    ldr    sy, =#0x938
    // k0=k[0]; k1=k[1]; k2=k[2]; k3=k[3];
    ldm    k, {k0,k1,k2,k3}
    // r=x[0]; l=x[1];
    ldm    p, {r,l}
    // r ^= R(l,1) ^ (R(l,5) & l) ^ k0;
    eor    t0, k0, l,ror #31
    and    t1, l, l, ror #27
    eor    t0, t1        
    mov    t1, l         
    eor    l, r, t0       
    mov    r, t1     

    // t1 = (s & 1) - 4;
    and    t1, sx, #1
    sub    t1, #4
    // k0 ^= R(k1,1) ^ (R(k1,5) & k1) ^ t1;
    // X(k0,k1); X(k1,k2); X(k2,k3);
    eor    k0, k0, k1, ror #31
    and    t0, k1, k1, ror #27
    eor    t0, k0
    mov    k0, k1
    mov    k1, k2
    mov    k2, k3
    eor    k3, t0, t1
    // s >>= 1
    movs   sy, sy, lsr #1
    movs   sx, sx, rrx
    bne    sm_l0
    // x[0]=r; x[1]=l;
    stm    p, {r,l}    
    // restore registers, and return
    pop    {r0-r12, pc}

ARM64 / AArch64 assembly

// SIMECK in ARM64 assembly
// 100 bytes

    .arch armv8-a
    .global simeck
     // unsigned long long s = 0x938BCA3083F;
     movz    x2, 0x083F
     movk    x2, 0xBCA3, lsl 16
     movk    x2, 0x0938, lsl 32 
     // load 128-bit key 
     ldp     w3, w4, [x0]
     ldp     w5, w6, [x0, 8]
     // load 64-bit plaintext 
     ldp     w8, w7, [x1]
     // r ^= R(l,1) ^ (R(l,5) & l) ^ k0;
     eor     w9, w3, w7, ror 31
     and     w10, w7, w7, ror 27
     eor     w9, w9, w10        
     mov     w10, w7         
     eor     w7, w8, w9      
     mov     w8, w10     

     // t1 = (s & 1) - 4;
     // k0 ^= R(k1,1) ^ (R(k1,5) & k1) ^ t1;
     // X(k0,k1); X(k1,k2); X(k2,k3);
     eor     w3, w3, w4, ror 31
     and     w9, w4, w4, ror 27
     eor     w9, w9, w3 
     mov     w3, w4 
     mov     w4, w5 
     mov     w5, w6 
     and     x10, x2, 1
     sub     x10, x10, 4
     eor     w6, w9, w10 
     // s >>= 1
     lsr     x2, x2, 1 
     cbnz    x2, L0
     // save 64-bit ciphertext 
     stp     w8, w7, [x1]

Sources here.

This entry was posted in arm, assembly, cryptography, encryption, programming, x86 and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s