aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/trng_csprng.v
blob: ce5c89cf28fa473a06c704c39e2c61c7f61ff09d (plain) (tree)
1
2
3
4
5
6
7
8
9
10







                                                                        

                            
  


                                                                  
  

                                                                    
  



                                                                       
  











                                                                       







                                                                        




                                                   

                                              




                                                       
                                                  
                                                 

                                                 

                                                    





                                                                    



                                           


                                           
 

                                           
 


                                           
                                           
 


                                           
 
















                                           

                                                      
 









                                
 

                                                       
 



                                                    


























                                                                    


                                   









                              






















                                    
                              
 



                                                                    

                           




                                       
                              
 

                                


                          

                                        

                               



                                                                    
                                        


                                        
                                          
                            
                                                 




                                                                    


                                            
 

                                             
 




                                                    
 

                                                     
 


                                                                

 


                                               
 



                                                                        
 



                                                    












                                                                    




                                                    
                                                   


                                   
                                   




                                                             




                                         


                                    
                                     

                            
                                             

                           
                                           

                            
                                             

                              
                                                 

                           



                                                       

                       
                                   
 
                             
                                               
 
                            
                                             

                                
                                                     

                                 
                                                       




                                                                    

















                                                                    
                                         





















                                                             
                                    




                                                    
                                     
















                                                     
                           
                                               

                           
                                               

                             
                                                 
 
                          
                                                                         

                            
                                                                       





                                                                


                              
                                             
                                      


                                
                                                                  
 
                                    
                                                       
 
                                     
                                                        











                                                                    





                                                            




                                                              


                                                                    



                                             


                        

                                            



                        


                                                         

           

                                                                         
             
                               
























                                                                    









                                         
                                       













                                              
                                                     





                                              


                                             






                                             
                                                     






                                              






                                              
                                                     























                                                       
                                                     














                                              
                                                     












                                              
                                                     












                                              
                                                     



                                              
                                                           








                                                   
                                                     































                                                  



                                         



                







                                                                        
//======================================================================
//
// trng_csprng.v
// -------------
// CSPRNG for the TRNG.
//
//
// Author: Joachim Strombergson
// Copyright (c) 2014, SUNET
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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 OWNER 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.
//
//======================================================================

module trng_csprng(
                   // Clock and reset.
                   input wire           clk,
                   input wire           reset_n,

                   input wire           cs,
                   input wire           we,
                   input wire  [7 : 0]  address,
                   input wire  [31 : 0] write_data,
                   output wire [31 : 0] read_data,
                   output wire          error,

                   input wire           discard,
                   input                test_mode,
                   output wire          more_seed,
                   output wire          security_error,

                   input [511 : 0]      seed_data,
                   input wire           seed_syn,
                   output wire          seed_ack,

                   output wire [7 : 0]  debug,
                   input wire           debug_update
                  );


  //----------------------------------------------------------------
  // Internal constant and parameter definitions.
  //----------------------------------------------------------------
  localparam ADDR_NAME0            = 8'h00;
  localparam ADDR_NAME1            = 8'h01;
  localparam ADDR_VERSION          = 8'h02;

  localparam ADDR_CTRL             = 8'h10;
  localparam CTRL_ENABLE_BIT       = 0;
  localparam CTRL_SEED_BIT         = 1;

  localparam ADDR_STATUS           = 8'h11;
  localparam STATUS_RND_VALID_BIT  = 0;

  localparam ADDR_STAT_BLOCKS_LOW  = 8'h14;
  localparam ADDR_STAT_BLOCKS_HIGH = 8'h15;

  localparam ADDR_RND_DATA         = 8'h20;

  localparam ADDR_NUM_ROUNDS       = 8'h40;
  localparam ADDR_NUM_BLOCKS_LOW   = 8'h41;
  localparam ADDR_NUM_BLOCKS_HIGH  = 8'h42;

  localparam ADDR_TEST_SEED_W00    = 8'h80;
  localparam ADDR_TEST_SEED_W01    = 8'h81;
  localparam ADDR_TEST_SEED_W02    = 8'h82;
  localparam ADDR_TEST_SEED_W03    = 8'h83;
  localparam ADDR_TEST_SEED_W04    = 8'h84;
  localparam ADDR_TEST_SEED_W05    = 8'h85;
  localparam ADDR_TEST_SEED_W06    = 8'h86;
  localparam ADDR_TEST_SEED_W07    = 8'h87;
  localparam ADDR_TEST_SEED_W08    = 8'h88;
  localparam ADDR_TEST_SEED_W09    = 8'h89;
  localparam ADDR_TEST_SEED_W10    = 8'h8a;
  localparam ADDR_TEST_SEED_W11    = 8'h8b;
  localparam ADDR_TEST_SEED_W12    = 8'h8c;
  localparam ADDR_TEST_SEED_W13    = 8'h8d;
  localparam ADDR_TEST_SEED_W14    = 8'h8e;
  localparam ADDR_TEST_SEED_W15    = 8'h8f;

  localparam CIPHER_KEYLEN256  = 1'b1; // 256 bit key.
  localparam CIPHER_MAX_BLOCKS = 64'h1000000000000000;

  localparam CTRL_IDLE   = 4'h0;
  localparam CTRL_SEED0  = 4'h1;
  localparam CTRL_NSYN   = 4'h2;
  localparam CTRL_SEED1  = 4'h3;
  localparam CTRL_INIT0  = 4'h4;
  localparam CTRL_INIT1  = 4'h5;
  localparam CTRL_NEXT0  = 4'h6;
  localparam CTRL_NEXT1  = 4'h7;
  localparam CTRL_MORE   = 4'h8;
  localparam CTRL_CANCEL = 4'hf;

  localparam DEFAULT_NUM_ROUNDS = 5'h18;
  localparam DEFAULT_NUM_BLOCKS = 64'h1000000000000000;

  parameter CORE_NAME0     = 32'h63737072; // "cspr"
  parameter CORE_NAME1     = 32'h6e672020; // "ng  "
  parameter CORE_VERSION   = 32'h302e3530; // "0.50"


  //----------------------------------------------------------------
  // Registers including update variables and write enable.
  //----------------------------------------------------------------
  reg [255 : 0] cipher_key_reg;
  reg [255 : 0] cipher_key_new;
  reg           cipher_key_we;

  reg [63 : 0]  cipher_iv_reg;
  reg [63 : 0]  cipher_iv_new;
  reg           cipher_iv_we;

  reg [63 : 0]  cipher_ctr_reg;
  reg [63 : 0]  cipher_ctr_new;
  reg           cipher_ctr_we;

  reg [511 : 0] cipher_block_reg;
  reg [511 : 0] cipher_block_new;
  reg           cipher_block_we;

  reg [63 : 0]  block_ctr_reg;
  reg [63 : 0]  block_ctr_new;
  reg           block_ctr_inc;
  reg           block_ctr_rst;
  reg           block_ctr_we;
  reg           block_ctr_max;

  reg [63 : 0]  block_stat_ctr_reg;
  reg [63 : 0]  block_stat_ctr_new;

  reg           ready_reg;
  reg           ready_new;
  reg           ready_we;

  reg           more_seed_reg;
  reg           more_seed_new;

  reg           seed_ack_reg;
  reg           seed_ack_new;

  reg           enable_reg;
  reg           enable_new;
  reg           enable_we;

  reg           seed_reg;
  reg           seed_new;

  reg [4 : 0]   num_rounds_reg;
  reg [4 : 0]   num_rounds_new;
  reg           num_rounds_we;

  reg [31 : 0]  num_blocks_low_reg;
  reg [31 : 0]  num_blocks_low_new;
  reg           num_blocks_low_we;

  reg [31 : 0]  num_blocks_high_reg;
  reg [31 : 0]  num_blocks_high_new;
  reg           num_blocks_high_we;

  reg [3 : 0]   csprng_ctrl_reg;
  reg [3 : 0]   csprng_ctrl_new;
  reg           csprng_ctrl_we;

  reg [31 : 0]  tmp_read_data;


  //----------------------------------------------------------------
  // Wires.
  //----------------------------------------------------------------
  reg            tmp_error;

  reg            cipher_init;
  reg            cipher_next;

  wire [511 : 0] cipher_data_out;
  wire           cipher_data_out_valid;
  wire           cipher_ready;

  wire           fifo_more_data;
  reg            fifo_discard;
  wire           rnd_syn;
  wire [31 : 0]  rnd_data;
  reg            rnd_ack;
  reg            fifo_cipher_data_valid;

  wire           muxed_rnd_ack;


  //----------------------------------------------------------------
  // Concurrent connectivity for ports etc.
  //----------------------------------------------------------------
  assign read_data      = tmp_read_data;
  assign error          = tmp_error;
  assign seed_ack       = seed_ack_reg;
  assign more_seed      = more_seed_reg;
  assign debug          = rnd_data[7 : 0];
  assign security_error = 0;
  assign muxed_rnd_ack  = rnd_ack | debug_update;


  //----------------------------------------------------------------
  // core instantiation.
  //----------------------------------------------------------------
  chacha_core cipher_inst(
                          .clk(clk),
                          .reset_n(reset_n),

                          .init(cipher_init),
                          .next(cipher_next),

                          .key(cipher_key_reg),
                          .keylen(CIPHER_KEYLEN256),
                          .iv(cipher_iv_reg),
                          .ctr(cipher_ctr_reg),
                          .rounds(num_rounds_reg),

                          .data_in(cipher_block_reg),
                          .ready(cipher_ready),

                          .data_out(cipher_data_out),
                          .data_out_valid(cipher_data_out_valid)
                         );


  trng_csprng_fifo fifo_inst(
                             .clk(clk),
                             .reset_n(reset_n),

                             .csprng_data(cipher_data_out),
                             .csprng_data_valid(fifo_cipher_data_valid),
                             .discard(fifo_discard),
                             .more_data(fifo_more_data),

                             .rnd_syn(rnd_syn),
                             .rnd_data(rnd_data),
                             .rnd_ack(muxed_rnd_ack)
                            );


  //----------------------------------------------------------------
  // reg_update
  //
  // Update functionality for all registers in the core.
  // All registers are positive edge triggered with synchronous
  // active low reset. All registers have write enable.
  //----------------------------------------------------------------
  always @ (posedge clk or negedge reset_n)
    begin
      if (!reset_n)
        begin
          cipher_key_reg      <= {8{32'h00000000}};
          cipher_iv_reg       <= {2{32'h00000000}};
          cipher_ctr_reg      <= {2{32'h00000000}};
          cipher_block_reg    <= {16{32'h00000000}};
          block_ctr_reg       <= {2{32'h00000000}};
          block_stat_ctr_reg  <= {2{32'h00000000}};
          more_seed_reg       <= 0;
          seed_ack_reg        <= 0;
          ready_reg           <= 0;
          enable_reg          <= 1;
          seed_reg            <= 0;
          num_rounds_reg      <= DEFAULT_NUM_ROUNDS;
          num_blocks_low_reg  <= DEFAULT_NUM_BLOCKS[31 : 0];
          num_blocks_high_reg <= DEFAULT_NUM_BLOCKS[63 : 32];
          csprng_ctrl_reg     <= CTRL_IDLE;
        end
      else
        begin
          more_seed_reg <= more_seed_new;
          seed_ack_reg  <= seed_ack_new;
          seed_reg      <= seed_new;

          if (enable_we)
            enable_reg <= enable_new;

          if (cipher_key_we)
            cipher_key_reg <= cipher_key_new;

          if (cipher_iv_we)
            cipher_iv_reg <= cipher_iv_new;

          if (cipher_ctr_we)
            cipher_ctr_reg <= cipher_ctr_new;

          if (cipher_block_we)
            cipher_block_reg <= cipher_block_new;

          if (block_ctr_we)
            begin
              block_ctr_reg      <= block_ctr_new;
              block_stat_ctr_reg <= block_stat_ctr_new;
            end

          if (ready_we)
            ready_reg <= ready_new;

          if (csprng_ctrl_we)
            csprng_ctrl_reg <= csprng_ctrl_new;

          if (num_rounds_we)
            num_rounds_reg <= num_rounds_new;

          if (num_blocks_low_we)
            num_blocks_low_reg <= num_blocks_low_new;

          if (num_blocks_high_we)
            num_blocks_high_reg <= num_blocks_high_new;
        end
    end // reg_update


  //----------------------------------------------------------------
  // csprng_api_logic
  //----------------------------------------------------------------
  always @*
    begin : csprng_api_logic
      enable_new          = 0;
      enable_we           = 0;
      seed_new            = 0;

      num_rounds_new      = 5'h00;
      num_rounds_we       = 0;

      num_blocks_low_new  = 32'h00000000;
      num_blocks_low_we   = 0;
      num_blocks_high_new = 32'h00000000;
      num_blocks_high_we  = 0;

      rnd_ack             = 0;

      tmp_read_data       = 32'h00000000;
      tmp_error           = 0;

      if (cs)
        begin
          if (we)
            begin
              // Write operations.
              case (address)
                // Write operations.
                ADDR_CTRL:
                  begin
                    enable_new = write_data[CTRL_ENABLE_BIT];
                    enable_we  = 1;
                    seed_new   = write_data[CTRL_SEED_BIT];
                  end

                ADDR_NUM_ROUNDS:
                  begin
                    num_rounds_new = write_data[4 : 0];
                    num_rounds_we  = 1;
                  end

                ADDR_NUM_BLOCKS_LOW:
                  begin
                    num_blocks_low_new = write_data;
                    num_blocks_low_we  = 1;
                  end

                ADDR_NUM_BLOCKS_HIGH:
                  begin
                    num_blocks_high_new = write_data;
                    num_blocks_high_we  = 1;
                  end

                default:
                  begin
                    tmp_error = 1;
                  end
              endcase // case (address)
            end // if (we)

          else
            begin
              // Read operations.
              case (address)
                // Read operations.
                ADDR_NAME0:
                    tmp_read_data = CORE_NAME0;

                ADDR_NAME1:
                    tmp_read_data = CORE_NAME1;

                ADDR_VERSION:
                    tmp_read_data = CORE_VERSION;

                ADDR_CTRL:
                    tmp_read_data = {30'h00000000, seed_reg, enable_reg};

                ADDR_STATUS:
                    tmp_read_data = {30'h00000000, ready_reg, rnd_syn};

                ADDR_STAT_BLOCKS_LOW:
                  tmp_read_data = block_stat_ctr_reg[31 : 0];

                ADDR_STAT_BLOCKS_HIGH:
                    tmp_read_data = block_stat_ctr_reg[63 : 32];

                ADDR_RND_DATA:
                  begin
                    tmp_read_data = rnd_data;
                    rnd_ack       = 1;
                  end

                ADDR_NUM_ROUNDS:
                    tmp_read_data = {27'h0000000, num_rounds_reg};

                ADDR_NUM_BLOCKS_LOW:
                    tmp_read_data = num_blocks_low_reg;

                ADDR_NUM_BLOCKS_HIGH:
                    tmp_read_data = num_blocks_high_reg;

                default:
                  begin
                    tmp_error = 1;
                  end
              endcase // case (address)
            end
        end
    end // cspng_api_logic


  //----------------------------------------------------------------
  // block_ctr
  //
  // Logic to implement the block counter. This includes the
  // ability to detect that maximum allowed number of blocks
  // has been reached. Either as defined by the application
  // or the hard coded CIPHER_MAX_BLOCKS value.

  // The stat counter is a sepatate block counter updated in
  // sync with the block counter. It is only used to track the
  // number of blocks generated from the cipher as a metric
  // provided to the system. The stat counter is never reset.
  //----------------------------------------------------------------
  always @*
    begin : block_ctr
      block_ctr_new      = {2{32'h00000000}};
      block_ctr_we       = 1'b0;
      block_ctr_max      = 1'b0;
      block_stat_ctr_new = {2{32'h00000000}};

      if (block_ctr_rst)
        begin
          block_ctr_new = {2{32'h00000000}};
          block_ctr_we  = 1'b1;
        end

      if (block_ctr_inc)
        begin
          block_ctr_new      = block_ctr_reg + 1'b1;
          block_stat_ctr_new = block_stat_ctr_reg + 1'b1;
          block_ctr_we       = 1;
        end

      if ((block_ctr_reg == {num_blocks_high_reg, num_blocks_low_reg}) ||
          (block_ctr_reg == CIPHER_MAX_BLOCKS))
        begin
          block_ctr_max = 1'b1;
        end
    end // block_ctr


  //----------------------------------------------------------------
  // csprng_ctrl_fsm
  //
  // Control FSM for the CSPRNG.
  //----------------------------------------------------------------
  always @*
    begin : csprng_ctrl_fsm
      cipher_key_new         = {8{32'h00000000}};
      cipher_key_we          = 0;
      cipher_iv_new          = {2{32'h00000000}};
      cipher_iv_we           = 0;
      cipher_ctr_new         = {2{32'h00000000}};
      cipher_ctr_we          = 0;
      cipher_block_new       = {16{32'h00000000}};
      cipher_block_we        = 0;
      cipher_init            = 0;
      cipher_next            = 0;
      block_ctr_rst          = 0;
      block_ctr_inc          = 0;
      ready_new              = 0;
      ready_we               = 0;
      seed_ack_new           = 0;
      more_seed_new          = 0;
      fifo_discard           = 0;
      fifo_cipher_data_valid = 0;
      csprng_ctrl_new        = CTRL_IDLE;
      csprng_ctrl_we         = 0;

      case (csprng_ctrl_reg)
        CTRL_IDLE:
          begin
            if (!enable_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else if (fifo_more_data)
              begin
                more_seed_new   = 1;
                csprng_ctrl_new = CTRL_SEED0;
                csprng_ctrl_we  = 1;
              end
          end

        CTRL_SEED0:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else if (seed_syn)
              begin
                seed_ack_new     = 1;
                cipher_block_new = seed_data;
                cipher_block_we  = 1;
                csprng_ctrl_new  = CTRL_NSYN;
                csprng_ctrl_we   = 1;
              end
          end

        CTRL_NSYN:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else
              begin
                more_seed_new    = 1;
                csprng_ctrl_new  = CTRL_SEED1;
                csprng_ctrl_we   = 1;
              end
          end

        CTRL_SEED1:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else if (seed_syn)
              begin
                seed_ack_new    = 1;
                cipher_key_new  = seed_data[255 : 0];
                cipher_key_we   = 1;
                cipher_iv_new   = seed_data[319 : 256];
                cipher_iv_we    = 1;
                cipher_ctr_new  = seed_data[383 : 320];
                cipher_ctr_we   = 1;
                csprng_ctrl_new = CTRL_INIT0;
                csprng_ctrl_we  = 1;
              end
            else
              begin
                more_seed_new = 1;
              end
          end

        CTRL_INIT0:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else
              begin
                cipher_init     = 1;
                block_ctr_rst   = 1;
                csprng_ctrl_new = CTRL_INIT1;
                csprng_ctrl_we  = 1;
              end
          end

        CTRL_INIT1:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else if (cipher_ready)
              begin
                csprng_ctrl_new = CTRL_NEXT0;
                csprng_ctrl_we  = 1;
              end
          end

        CTRL_NEXT0:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else
              begin
                cipher_next     = 1;
                csprng_ctrl_new = CTRL_NEXT1;
                csprng_ctrl_we  = 1;
              end
          end

        CTRL_NEXT1:
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else if (cipher_ready && cipher_data_out_valid)
              begin
                block_ctr_inc          = 1;
                fifo_cipher_data_valid = 1;
                csprng_ctrl_new        = CTRL_MORE;
                csprng_ctrl_we         = 1;
              end

        CTRL_MORE:
          begin
            if ((!enable_reg) || seed_reg || discard)
              begin
                csprng_ctrl_new = CTRL_CANCEL;
                csprng_ctrl_we  = 1;
              end
            else if (fifo_more_data)
              begin
                if (block_ctr_max)
                  begin
                    more_seed_new   = 1;
                    csprng_ctrl_new = CTRL_SEED0;
                    csprng_ctrl_we  = 1;
                  end
                else
                  begin
                    csprng_ctrl_new = CTRL_NEXT0;
                    csprng_ctrl_we  = 1;
                  end
              end
          end

        CTRL_CANCEL:
          begin
            fifo_discard     = 1;
            cipher_key_new   = {8{32'h00000000}};
            cipher_key_we    = 1;
            cipher_iv_new    = {2{32'h00000000}};
            cipher_iv_we     = 1;
            cipher_ctr_new   = {2{32'h00000000}};
            cipher_ctr_we    = 1;
            cipher_block_new = {16{32'h00000000}};
            cipher_block_we  = 1;
            block_ctr_rst    = 1;
            csprng_ctrl_new  = CTRL_IDLE;
            csprng_ctrl_we   = 1;
          end

        default:
          begin
          end

      endcase // case (cspng_ctrl_reg)
    end // csprng_ctrl_fsm

endmodule // trng_csprng

//======================================================================
// EOF trng_csprng.v
//======================================================================