../src/lowrisc_prim_all_0.1/rtl/prim_keccak.sv Cov: 98.5%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // prim_keccak is single round permutation module
   6: 
   7: module prim_keccak #(
   8:   parameter int Width = 1600, // b= {25, 50, 100, 200, 400, 800, 1600}
   9: 
  10:   // Derived
  11:   localparam int W        = Width/25,
  12:   localparam int L        = $clog2(W),
  13:   localparam int MaxRound = 12 + 2*L, // Keccak-f only
  14:   localparam int RndW     = $clog2(MaxRound) // Representing up to MaxRound-1
  15: ) (
  16:   input        [RndW-1:0]  rnd_i,   // Current Round
  17:   input        [Width-1:0] s_i,
  18:   output logic [Width-1:0] s_o
  19: );
  20:   ///////////
  21:   // Types //
  22:   ///////////
  23:   //             x    y    z
  24:   typedef logic [4:0][4:0][W-1:0] box_t;   // (x,y,z) state
  25:   typedef logic           [W-1:0] lane_t;  // (z)
  26:   typedef logic [4:0]     [W-1:0] plane_t; // (x,z)
  27:   typedef logic [4:0][4:0]        slice_t; // (x,y)
  28:   typedef logic      [4:0][W-1:0] sheet_t; // (y,z) identical to plane_t
  29:   typedef logic [4:0]             row_t;   // (x)
  30:   typedef logic      [4:0]        col_t;   // (y) identical to row_t
  31: 
  32:   //////////////
  33:   // Keccak_f //
  34:   //////////////
  35:   box_t state_in, keccak_f;
  36:   box_t theta_data, rho_data, pi_data, chi_data, iota_data;
  37:   assign state_in = bitarray_to_box(s_i);
  38:   assign theta_data = theta(state_in);
  39:   // Commented out rho function as vcs complains z-Offset%W isn't constant
  40:   //assign rho_data   = rho(theta_data);
  41:   assign pi_data    = pi(rho_data);
  42:   assign chi_data   = chi(pi_data);
  43:   assign iota_data  = iota(chi_data, rnd_i);
  44:   assign keccak_f   = iota_data;
  45:   assign s_o        = box_to_bitarray(keccak_f);
  46: 
  47:   // Rho ======================================================================
  48:   // As RhoOffset[x][y] is considered as variable int in VCS,
  49:   // it is replaced with generate statement.
  50:   localparam int RhoOffset [5][5]  = '{
  51:     //y  0    1    2    3    4     x
  52:     '{   0,  36,   3, 105, 210},// 0
  53:     '{   1, 300,  10,  45,  66},// 1
  54:     '{ 190,   6, 171,  15, 253},// 2
  55:     '{  28,  55, 153,  21, 120},// 3
  56:     '{  91, 276, 231, 136,  78} // 4
  57:   };
  58:   for (genvar x = 0 ; x < 5 ; x++) begin : gen_rho_x
  59:     for (genvar y = 0 ; y < 5 ; y++) begin : gen_rho_y
  60:       localparam int Offset = RhoOffset[x][y]%W;
  61:       localparam int ShiftAmt = W- Offset;
  62:       if (Offset == 0) begin : gen_offset0
  63:         assign rho_data[x][y][W-1:0] = theta_data[x][y][W-1:0];
  64:       end else begin : gen_others
  65:         assign rho_data[x][y][W-1:0] = {theta_data[x][y][0+:ShiftAmt],
  66:                                         theta_data[x][y][ShiftAmt+:Offset]};
  67:       end
  68:     end
  69:   end
  70: 
  71:   ////////////////
  72:   // Assertions //
  73:   ////////////////
  74: 
  75:   `ASSERT_INIT(ValidWidth_A, Width inside {25, 50, 100, 200, 400, 800, 1600})
  76:   `ASSERT_INIT(ValidW_A, W inside {1, 2, 4, 8, 16, 32, 64})
  77:   `ASSERT_INIT(ValidL_A, L inside {0, 1, 2, 3, 4, 5, 6})
  78:   `ASSERT_INIT(ValidRound_A, MaxRound <= 24) // Keccak-f only
  79: 
  80:   ///////////////
  81:   // Functions //
  82:   ///////////////
  83: 
  84:   // Convert bitarray to 3D box
  85:   // Please take a look at FIPS PUB 202
  86:   // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
  87:   // > For all triples (x,y,z) such that 0<=x<5, 0<=y<5, and 0<=z
  88:   // >    A[x,y,z]=S[w(5y+x)+z]
  89:   function automatic box_t bitarray_to_box(logic [Width-1:0] s_in);
  90:     automatic box_t box;
  91:     for (int y = 0 ; y < 5 ; y++) begin
  92:       for (int x = 0 ; x < 5 ; x++) begin
  93:         for (int z = 0 ; z < W ; z++) begin
  94:           box[x][y][z] = s_in[W*(5*y+x) + z];
  95:         end
  96:       end
  97:     end
  98:     return box;
  99:   endfunction : bitarray_to_box
 100: 
 101:   // Convert 3D cube to bitarray
 102:   function automatic logic [Width-1:0] box_to_bitarray(box_t state);
 103:     automatic logic [Width-1:0] bitarray;
 104:     for (int y = 0 ; y < 5 ; y++) begin
 105:       for (int x = 0 ; x < 5 ; x++) begin
 106:         for (int z = 0 ; z < W ; z++) begin
 107:           bitarray[W*(5*y+x)+z] = state[x][y][z];
 108:         end
 109:       end
 110:     end
 111:     return bitarray;
 112:   endfunction : box_to_bitarray
 113: 
 114:   // Step Mapping =============================================================
 115:   // theta(θ)
 116:   // XOR each bit in the state with the parity of two columns
 117:   // C[x,z] = A[x,0,z] ^ A[x,1,z] ^ A[x,2,z] ^ A[x,3,z] ^ A[x,4,z]
 118:   // D[x,z] = C[x-1,z] ^ C[x+1,z-1]
 119:   // theta = A[x,y,z] ^ D[x,z]
 120:   function automatic box_t theta(box_t state);
 121:     plane_t c;
 122:     plane_t d;
 123:     box_t result;
 124:     for (int x = 0 ; x < 5 ; x++) begin
 125:       for (int z = 0 ; z < W ; z++) begin
 126:         c[x][z] = state[x][0][z] ^ state[x][1][z]
 127:                 ^ state[x][2][z] ^ state[x][3][z] ^ state[x][4][z];
 128:       end
 129:     end
 130:     for (int x = 0 ; x < 5 ; x++) begin
 131:       int index_x1, index_x2;
 132:       index_x1 = (x == 0) ? 4 : x-1; // (x-1)%5
 133:       index_x2 = (x == 4) ? 0 : x+1; // (x+1)%5
 134:       for (int z = 0 ; z < W ; z++) begin
 135:         int index_z;
 136:         index_z = (z == 0) ? W-1 : z-1; // (z+1)%W
 137:         d[x][z] = c[index_x1][z] ^ c[index_x2][index_z];
 138:       end
 139:     end
 140:     for (int x = 0 ; x < 5 ; x++) begin
 141:       for (int y = 0 ; y < 5 ; y++) begin
 142:         for (int z = 0 ; z < W ; z++) begin
 143:           result[x][y][z] = state[x][y][z] ^ d[x][z];
 144:         end
 145:       end
 146:     end
 147:     return result;
 148:   endfunction : theta
 149: 
 150:   // rho
 151: 
 152:   // Commented out entire rho function due to VCS elaboration error.
 153:   // (z-RhoOffset[x][y]%W) isn't considered as a constant in VCS.
 154:   // Even changing it to W-RhoOffset[x][y]%W and assign to ShiftAmt
 155:   // creates same error.
 156: 
 157:   // Offset : Look at Table 2 in FIPS PUB 202
 158:   //localparam int RhoOffset [5][5]  = '{
 159:   //  //y  0    1    2    3    4     x
 160:   //  '{   0,  36,   3, 105, 210},// 0
 161:   //  '{   1, 300,  10,  45,  66},// 1
 162:   //  '{ 190,   6, 171,  15, 253},// 2
 163:   //  '{  28,  55, 153,  21, 120},// 3
 164:   //  '{  91, 276, 231, 136,  78} // 4
 165:   //};
 166: 
 167:   // rotate bits of each lane by offset
 168:   // 1. rho[0,0,z] = A[0,0,z]
 169:   // 2. Offset swap
 170:   //    a. (x,y) := (1,0)
 171:   //    b. for t [0..23]
 172:   //       i. rho[x,y,z] = A[x,y,z-(t+1)(t+2)/2]
 173:   //       ii. (x,y) = (y, (2x+3y))
 174:   //function automatic box_t rho(box_t state);
 175:   //  box_t result;
 176:   //  for (int x = 0 ; x < 5 ; x++) begin
 177:   //    for (int y = 0 ; y < 5 ; y++) begin
 178:   //      for (int z = 0 ; z < W ; z++) begin
 179:   //        automatic int index_z;
 180:   //        index_z = (z-RhoOffset[x][y])%W;
 181:   //        result[x][y][z] = state[x][y][(z-RhoOffset[x][y])%W];
 182:   //      end
 183:   //    end
 184:   //  end
 185:   //  return result;
 186:   //endfunction : rho
 187: 
 188:   // pi
 189:   // rearrange the position of lanes
 190:   // pi[x,y,z] = state[(x+3y),x,z]
 191:   localparam int PiRotate [5][5] = '{
 192:     //y  0    1    2    3    4     x
 193:     '{   0,   3,   1,   4,   2},// 0
 194:     '{   1,   4,   2,   0,   3},// 1
 195:     '{   2,   0,   3,   1,   4},// 2
 196:     '{   3,   1,   4,   2,   0},// 3
 197:     '{   4,   2,   0,   3,   1} // 4
 198:   };
 199:   function automatic box_t pi(box_t state);
 200:     box_t result;
 201:     for (int x = 0 ; x < 5 ; x++) begin
 202:       for (int y = 0 ; y < 5 ; y++) begin
 203:         int index_x;
 204:         result[x][y][W-1:0] = state[PiRotate[x][y]][x][W-1:0];
 205:       end
 206:     end
 207:     return result;
 208:   endfunction : pi
 209: 
 210:   // chi
 211:   // chi[x,y,z] = state[x,y,z] ^ ((state[x+1,y,z] ^ 1) & state[x+2,y,z])
 212:   function automatic box_t chi(box_t state);
 213:     box_t result;
 214:     for (int x = 0 ; x < 5 ; x++) begin
 215:       int index_x1, index_x2;
 216:       index_x1 = (x == 4) ? 0 : x+1;
 217:       index_x2 = (x >= 3) ? x-3 : x+2;
 218:       for (int y = 0 ; y < 5 ; y++) begin
 219:         for (int z = 0 ; z < W ; z++) begin
 220:           result[x][y][z] = state[x][y][z] ^
 221:                                 ((~state[index_x1][y][z])
 222:                                  & state[index_x2][y][z]);
 223:         end
 224:       end
 225:     end
 226:     return result;
 227:   endfunction : chi
 228: 
 229:   // iota
 230:   // XOR (x,y) = (0,0) with round constant
 231: 
 232:   // RC parameter: Precomputed by util/keccak_rc.py. Only up-to 0..L-1 is used
 233:   // RC = '0
 234:   // RC[2**j-1] = rc(j+7*rnd)
 235:   // rc(t) =
 236:   //    1. t%255 == 0 -> 1
 237:   //    2. R[0:7] = 'b10000000
 238:   //    3. for i = [1..t%255]
 239:   //      a. R = 0 || R
 240:   //      b. R[0] = R[0] ^ R[8]
 241:   //      c. R[4] = R[4] ^ R[8]
 242:   //      d. R[5] = R[5] ^ R[8]
 243:   //      e. R[6] = R[6] ^ R[8]
 244:   //      f. R = R[0:7]
 245:   //    4. return R[0]
 246:   // RC has L = [0..6]
 247:   // for lower L case, only chopping lower part of 64bit RC is sufficient.
 248:   localparam logic [63:0] RC [24] = '{
 249:      64'h 0000_0000_0000_0001, // Round 0
 250:      64'h 0000_0000_0000_8082, // Round 1
 251:      64'h 8000_0000_0000_808A, // Round 2
 252:      64'h 8000_0000_8000_8000, // Round 3
 253:      64'h 0000_0000_0000_808B, // Round 4
 254:      64'h 0000_0000_8000_0001, // Round 5
 255:      64'h 8000_0000_8000_8081, // Round 6
 256:      64'h 8000_0000_0000_8009, // Round 7
 257:      64'h 0000_0000_0000_008A, // Round 8
 258:      64'h 0000_0000_0000_0088, // Round 9
 259:      64'h 0000_0000_8000_8009, // Round 10
 260:      64'h 0000_0000_8000_000A, // Round 11
 261:      64'h 0000_0000_8000_808B, // Round 12
 262:      64'h 8000_0000_0000_008B, // Round 13
 263:      64'h 8000_0000_0000_8089, // Round 14
 264:      64'h 8000_0000_0000_8003, // Round 15
 265:      64'h 8000_0000_0000_8002, // Round 16
 266:      64'h 8000_0000_0000_0080, // Round 17
 267:      64'h 0000_0000_0000_800A, // Round 18
 268:      64'h 8000_0000_8000_000A, // Round 19
 269:      64'h 8000_0000_8000_8081, // Round 20
 270:      64'h 8000_0000_0000_8080, // Round 21
 271:      64'h 0000_0000_8000_0001, // Round 22
 272:      64'h 8000_0000_8000_8008  // Round 23
 273:   };
 274: 
 275:   // iota: XOR with RC for (x,y) = (0,0)
 276:   function automatic box_t iota(box_t state, logic [RndW-1:0] rnd);
 277:     box_t result;
 278:     result = state;
 279:     result[0][0][W-1:0] = state[0][0][W-1:0] ^ RC[rnd][W-1:0];
 280: 
 281:     return result;
 282:   endfunction : iota
 283: 
 284:   // Round function : Rnd(A,i_r)
 285:   // Not used due to rho function issue described above.
 286: 
 287:   //function automatic box_t keccak_rnd(box_t state, logic [RndW-1:0] rnd);
 288:   //  box_t keccak_state;
 289:   //  keccak_state = iota(chi(pi(rho(theta(state)))), rnd);
 290:   //
 291:   //  return keccak_state;
 292:   //endfunction : keccak_rnd
 293: 
 294: endmodule
 295: 
 296: