Grain Stream Cipher

From Gezel2

Jump to: navigation, search

This is the Grain Stream Cipher (grain v1 to be exact). See [http://www.it.lth.se/grain/].

I am curious why proposers of HARDWARE crypto algorithms tend to provide reference implementations in SOFTWARE. This applies not just to grain, but to virtually every hash, secret-key and public-key design proposed in the past few years (e.g. check [ESTREAM]). As you can see from the code below, an RTL reference implementation really takes no more than a single page of code.

[edit] grain.fdl

 dp grain(in init   : ns(1);
          in run    : ns(1);
          in key    : ns(80);
          in iv     : ns(64);
          out z     : ns(1);
          out valid : ns(1)) {
   reg n, l : ns(80); // n = NFSR state, l = LFSR state
   reg cnt  : ns(8);  // count init cycles (160 downto 0)
   reg val  : ns(1);
 
   sig nxt_n, nxt_l : ns(80);
   sig go : ns(1);
   sig g, f, h, l_bit, n_bit : ns(1);
   sig x0, x1, x2, x3, x4 : ns(1);
 
   always {
     n = init ? key : nxt_n;
     l = init ? ((ns(16)) 0xffff) # iv : nxt_l;
 
     val  = init ? 0 : (cnt == 1) ? 1 : val;
     valid = val;
 
     cnt  = init ? 160 : (cnt ? cnt - 1 : 0);
     go   = (cnt != 0) | run;
 
     f    =  l[0]  ^ l[13] ^ l[23]  ^ l[38]  ^   l[51] ^   l[62];
 
     g    =  l[ 0] ^ n[62] ^ n[60]  ^  n[52] ^   n[45] ^   
             n[37] ^ n[33] ^ n[28] ^  n[21] ^
             n[14] ^ n[ 9] ^ n[ 0]  ^ 
             (n[63] & n[60]) ^ 
             (n[37] & n[33]) ^ 
             (n[15] & n[9]) ^
             (n[60] & n[52] & n[45]) ^ 
             (n[33] & n[28] & n[21]) ^ 
             (n[63] & n[45] & n[28]  &  n[ 9]) ^
             (n[60] & n[52] & n[37]  &  n[33]) ^ 
             (n[63] & n[60] & n[21]  &  n[15]) ^
             (n[63] & n[60] & n[52]  &  n[45]  &   n[37]) ^ 
             (n[33] & n[28] & n[21]  &  n[15]  &   n[ 9]) ^
             (n[52] & n[45] & n[37]  &  n[33]  &   n[28] &   n[21]);
     x0   = l[ 3];
     x1   = l[25];
     x2   = l[46];
     x3   = l[64];
     x4   = n[63];
     h    =  x1 ^ x4 ^ (x0 & x3) ^ (x2 & x3) ^ 
            (x3 & x4) ^ (x0 & x1 & x2) ^ (x0 & x2 & x3) ^
            (x0 & x2 & x4) ^ (x1 & x2 & x4) ^ (x2 & x3 & x4);
 
     l_bit = (cnt != 0) ? (f ^ z) : f;
     n_bit = (cnt != 0) ? (g ^ z) : g;
 
     nxt_l = go ? l_bit # l[79:1] : l;
     nxt_n = go ? n_bit # n[79:1] : n;
 
     z = h ^ n[1] ^ n[2] ^ n[4] ^ n[10] ^ n[31] ^ n[43] ^ n[56];
   }
 
 }
 
 dp testgrain { 
   sig init : ns(1);
   sig run  : ns(1);
   sig key  : ns(80);
   sig iv   : ns(64);
   sig z    : ns(1);
   sig v    : ns(1);
   reg zw   : ns(8);
   reg c    : ns(3);
   reg zr   : ns(1);
   reg vr   : ns(1);
   sig zws  : ns(8);
   use grain(init, run, key, iv, z, v);
   sfg load {
     init = 1;
     run  = 0;
     key  = 0;
     iv   = 0;
   }
   sfg nokey {
     key  = 0;
     iv   = 0;
     init = 0;
     run  = 1;
   }
   sfg wait {
     zr = z;
     vr = v;
   }
   sfg collect {
     zw   = zr # zw[7:1];
     c    = c + 1;
     zr   = z;
     key  = 0;
     iv   = 0;
     init = 0;
     run  = 1;
     zws  = zw;
   }
   sfg show {
     $display("C ", $cycle, " -> ", zws);
   }
 }
 
 fsm ctl(testgrain) {
 
   initial s0;
   state s1, s2;
 
   @s0 (load, wait) -> s1;
   @s1 if (vr)   then (collect) -> s2;
                 else (wait, nokey)    -> s1;
   @s2 if (c==0) then (collect, show) -> s2;
                 else (collect) -> s2;  
 }
 
 system S {
   testgrain;
 }

[edit] Simulation Output

# fdlsim grain.fdl 300
C 170 -> de
C 178 -> e9
C 186 -> 31
C 194 -> cf
C 202 -> 16
C 210 -> 62
C 218 -> a7
C 226 -> 2f
C 234 -> 77
C 242 -> d0
C 250 -> 2b
C 258 -> 6b
C 266 -> 61
C 274 -> 88
C 282 -> a8
C 290 -> f6
C 298 -> a2