aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/sha3.v
blob: c07ce0dae0c146c8813d39cd90b9a4864b14301b (plain) (tree)






























































































































































                                                                           
//======================================================================
// sha3
// ----
// keccak, SHA-3 winner
// derived from "readable keccak"
// 19-Nov-11  Markku-Juhani O. Saarinen <mjos@iki.fi>
// A baseline Keccak (3rd round) implementation.
// Verilog implementation (c) 2015 by Bernd Paysan
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// - Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// - Neither the name of the NORDUnet nor the names of its contributors may
//   be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//======================================================================

`define rotl64(x, r) ((({x, x}<<r)>>64)& 64'hffffffffffffffff)
`define rotci(i) ((rotc>>((23-i)*6)) & 6'h3f)
`define pilni(i) ((piln>>((23-i)*5)) & 5'h1f)
`define rndci(i) ((rndc>>((23-i)*64)) & 64'hffffffffffffffff)

module sha3(input wire clk, nreset, w,
	      input wire [8:bus] 	addr,
	      input wire [(8<<bus)-1:0] din,
	      output reg [(8<<bus)-1:0] dout,
	      output wire 		ready);
   parameter bus=2; // 2^bus bytes bus width
   reg [63:0] st[25], stn[25], bc[5], t;
   reg [4:0]  round, roundlimit;
   reg [(8<<bus)-1:0] dinxor;
   integer i, j;

   always @*
     begin
	case(bus)
	  3: dout = st[addr[7:3]];
	  2: dout = st[addr[7:3]] >> (32*addr[2]);
	  1: dout = st[addr[7:3]] >> (16*addr[2:1]);
	  0: dout = st[addr[7:3]] >> (8*addr[2:0]);
	endcase // case (bus)
	dinxor = addr[8] ? dout ^ din : din;
     end

   wire [24*6-1:0] rotc = { 6'h01, 6'h03, 6'h06, 6'h0A, 6'h0F, 6'h15,
			    6'h1C, 6'h24, 6'h2D, 6'h37, 6'h02, 6'h0E,
			    6'h1B, 6'h29, 6'h38, 6'h08, 6'h19, 6'h2B,
			    6'h3E, 6'h12, 6'h27, 6'h3D, 6'h14, 6'h2C };
   wire [24*5-1:0] piln = { 5'h0A, 5'h07, 5'h0B, 5'h11, 5'h12, 5'h03,
			    5'h05, 5'h10, 5'h08, 5'h15, 5'h18, 5'h04,
			    5'h0F, 5'h17, 5'h13, 5'h0D, 5'h0C, 5'h02,
			    5'h14, 5'h0E, 5'h16, 5'h09, 5'h06, 5'h01 };
   wire [24*64-1:0] rndc = { 64'h0000000000000001, 64'h0000000000008082,
			     64'h800000000000808a, 64'h8000000080008000,
			     64'h000000000000808b, 64'h0000000080000001,
			     64'h8000000080008081, 64'h8000000000008009,
			     64'h000000000000008a, 64'h0000000000000088,
			     64'h0000000080008009, 64'h000000008000000a,
			     64'h000000008000808b, 64'h800000000000008b,
			     64'h8000000000008089, 64'h8000000000008003,
			     64'h8000000000008002, 64'h8000000000000080,
			     64'h000000000000800a, 64'h800000008000000a,
			     64'h8000000080008081, 64'h8000000000008080,
			     64'h0000000080000001, 64'h8000000080008008 };

   always @*
     begin
	// theta1
	for(i=0; i<25; i=i+1) begin
	   stn[i] = st[i];
	end
	for(i=0; i<5; i=i+1) begin
	   bc[i] = stn[i] ^ stn[i+5] ^ stn[i+10] ^ stn[i+15] ^ stn[i+20];
	end
	// theta2
	for(i=0; i<5; i=i+1) begin
	   t = bc[(i+4)%5] ^ `rotl64(bc[(i+1)%5], 1);
	   for(j=i; j<25; j=j+5) begin
	      stn[j] = t ^ stn[j];
	   end
	end
	// rophi
	t = stn[1];
	for(i=0; i<24; i=i+1) begin
           j = `pilni(i);
           { stn[j], t } = { `rotl64(t, `rotci(i)), stn[j] };
	end
	// chi
        for (j = 0; j < 25; j = j+5) begin
	   for (i = 0; i < 5; i = i+1) begin
	      bc[i] = stn[j + i];
	   end
	   for (i = 0; i < 5; i = i + 1) begin
	      stn[j+i] = stn[j+i] ^ (~bc[(i+1)%5] & bc[(i+2)%5]);
	   end
	end
	// iota
        stn[0] = stn[0] ^ `rndci(round);
     end

   assign ready = round >= roundlimit;

   always @(posedge clk or negedge nreset)
     if(!nreset) begin
	for(i=0; i<25; i=i+1)
	  st[i] <= 64'h0;
	round <= 24;
	roundlimit <= 24;
     end else begin
	if(!w) begin
	  if(!ready) begin
	     for(i=0; i<25; i=i+1)
	       st[i] <= stn[i];
   	     round <= round + 5'b1;
	  end
	end else begin
	   if(&addr[8:bus]) begin // last element
	      round <= 0;
	      roundlimit <= din[4:0];
	   end else begin
	      case(bus)
		3: st[addr[7:3]] <= dinxor;
		2: case(addr[2])
		     1: st[addr[7:3]][63:32] <= dinxor;
		     0: st[addr[7:3]][31:0] <= dinxor;
		   endcase // case (addr[2])
		1: case(addr[2:1])
		     3: st[addr[7:3]][63:48] <= dinxor;
		     2: st[addr[7:3]][47:32] <= dinxor;
		     1: st[addr[7:3]][31:16] <= dinxor;
		     0: st[addr[7:3]][15:0] <= dinxor;
		   endcase // case (addr[2])
	      endcase // case (bus)
	   end
	end
     end

endmodule // sha3
//======================================================================