aboutsummaryrefslogblamecommitdiff
path: root/rtl/ecdsa384_base_point_multiplier.v
blob: dc8d97691866e9e65409a5b02909542464e86f10 (plain) (tree)





















































































































































































































































































































                                                                                                                                             
//------------------------------------------------------------------------------
//
// ecdsa384_base_point_multiplier.v
// -----------------------------------------------------------------------------
// ECDSA base point scalar multiplier.
//
// Authors: Pavel Shatov
//
// Copyright (c) 2016, 2018 NORDUnet A/S
//
// 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.
//
//------------------------------------------------------------------------------

module ecdsa384_base_point_multiplier
(
    clk, rst_n,
    ena, rdy,
    k_addr, rxy_addr,
    rx_wren, ry_wren,
    k_din,
    rxy_dout
);


    //
    // Microcode Header
    //
`include "ecdsa_uop.vh"
    

    //
    // Ports
    //
    input           clk;        // system clock
    input           rst_n;      // active-low async reset

    input           ena;        // enable input
    output          rdy;        // ready output

    output  [ 3:0]  k_addr;     //
    output  [ 3:0]  rxy_addr;   //
    output          rx_wren;    //
    output          ry_wren;    //
    input   [31:0]  k_din;      //
    output  [31:0]  rxy_dout;   //


    //
    // FSM
    //
    localparam [4:0] FSM_STATE_IDLE                 = 5'd00;
    localparam [4:0] FSM_STATE_PREPARE_TRIG         = 5'd01;
    localparam [4:0] FSM_STATE_PREPARE_WAIT         = 5'd02;
    localparam [4:0] FSM_STATE_CYCLE_DBL_TRIG       = 5'd03;
    localparam [4:0] FSM_STATE_CYCLE_DBL_WAIT       = 5'd04;
    localparam [4:0] FSM_STATE_CYCLE_ADD_TRIG       = 5'd05;
    localparam [4:0] FSM_STATE_CYCLE_ADD_WAIT       = 5'd06;
    localparam [4:0] FSM_STATE_CYCLE_ADD_EXTRA_TRIG = 5'd07;
    localparam [4:0] FSM_STATE_CYCLE_ADD_EXTRA_WAIT = 5'd08;
    localparam [4:0] FSM_STATE_AFTER_CYCLE_TRIG     = 5'd09;
    localparam [4:0] FSM_STATE_AFTER_CYCLE_WAIT     = 5'd10;
    localparam [4:0] FSM_STATE_INVERT_TRIG          = 5'd11;
    localparam [4:0] FSM_STATE_INVERT_WAIT          = 5'd12;
    localparam [4:0] FSM_STATE_CONVERT_TRIG         = 5'd13;
    localparam [4:0] FSM_STATE_CONVERT_WAIT         = 5'd14;
    localparam [4:0] FSM_STATE_CONVERT_EXTRA_TRIG   = 5'd15;
    localparam [4:0] FSM_STATE_CONVERT_EXTRA_WAIT   = 5'd16;
    localparam [4:0] FSM_STATE_DONE                 = 5'd17;

    reg [4:0] fsm_state = FSM_STATE_IDLE;
    reg [4:0] fsm_state_next;


    //
    // Round Counter
    //
    reg  [8:0] bit_counter;
    wire [8:0] bit_counter_last = 9'h17F;    // 384
    wire [8:0] bit_counter_zero = 9'h000;    // 0
    wire [8:0] bit_counter_prev =
        (bit_counter > bit_counter_zero) ? bit_counter - 1'b1 : bit_counter_last;

    assign k_addr = bit_counter[8:5];


    //
    // Worker Trigger Logic
    //
    reg  worker_trig = 1'b0;
    wire worker_done;

    wire fsm_wait_done = !worker_trig && worker_done;

    always @(posedge clk or negedge rst_n)
        //
        if (rst_n == 1'b0)                      worker_trig <= 1'b0;
        else case (fsm_state)
            FSM_STATE_PREPARE_TRIG,
            FSM_STATE_CYCLE_DBL_TRIG,
            FSM_STATE_CYCLE_ADD_TRIG,
            FSM_STATE_CYCLE_ADD_EXTRA_TRIG,
            FSM_STATE_AFTER_CYCLE_TRIG,
            FSM_STATE_INVERT_TRIG,
            FSM_STATE_CONVERT_TRIG,
            FSM_STATE_CONVERT_EXTRA_TRIG:       worker_trig <= 1'b1;
            default:                            worker_trig <= 1'b0;
        endcase
        
        
    //
    // Round Counter Increment Logic
    //
    always @(posedge clk)
        //
        case (fsm_state_next)
            FSM_STATE_PREPARE_TRIG:         bit_counter <= bit_counter_last;
            FSM_STATE_AFTER_CYCLE_TRIG:     bit_counter <= bit_counter_prev;
        endcase


    //
    // Final Cycle Detection Logic
    //
    wire [ 3: 0] fsm_state_after_cycle = (bit_counter == bit_counter_last) ?
        FSM_STATE_INVERT_TRIG : FSM_STATE_CYCLE_DBL_TRIG;
        

    //
    // K Latch
    //
    reg [31:0] k_din_shreg;
    
    wire [4:0] k_bit_index = bit_counter[4:0];
    
    always @(posedge clk)
        //
        if (fsm_state_next == FSM_STATE_CYCLE_DBL_TRIG)
            //
            if (k_bit_index == 5'd31) k_din_shreg <= k_din;
            else                      k_din_shreg <= {k_din_shreg[30:0], ~k_din_shreg[31]};
    

    //
    // Worker Flags
    //
    wire worker_flagz_sz;
    wire worker_flagz_rz;
    wire worker_flagz_e;
    wire worker_flagz_f;
    
    wire [2:0] worker_flagz_cycle_add =
        {worker_flagz_sz, worker_flagz_e,  worker_flagz_f};

    wire worker_flagz_convert_extra =
        worker_flagz_rz;

    
    //
    // Worker Offset Logic
    //
    reg [UOP_ADDR_WIDTH-1:0] worker_offset;
    
    always @(posedge clk)
        //
        case (fsm_state)
        
            FSM_STATE_PREPARE_TRIG:         worker_offset <= UOP_OFFSET_PREPARE;
            
            FSM_STATE_CYCLE_DBL_TRIG:       worker_offset <= UOP_OFFSET_CYCLE_DOUBLE;
            FSM_STATE_CYCLE_ADD_TRIG:       worker_offset <= UOP_OFFSET_CYCLE_ADD;
            
            FSM_STATE_CYCLE_ADD_EXTRA_TRIG:
                // {sz, e, f}
                casez(worker_flagz_cycle_add)
                    3'b1??:                 worker_offset <= UOP_OFFSET_CYCLE_ADD_AT_INFINITY;
                    3'b011:                 worker_offset <= UOP_OFFSET_CYCLE_ADD_SAME_X_SAME_Y;
                    3'b010:                 worker_offset <= UOP_OFFSET_CYCLE_ADD_SAME_X;
                    3'b00?:                 worker_offset <= UOP_OFFSET_CYCLE_ADD_REGULAR;
                endcase
                
            FSM_STATE_AFTER_CYCLE_TRIG:     worker_offset <= k_din_shreg[31] ?
                                            UOP_OFFSET_CYCLE_K1 : UOP_OFFSET_CYCLE_K0;
                                            
            FSM_STATE_INVERT_TRIG:          worker_offset <= UOP_OFFSET_INVERT;
            FSM_STATE_CONVERT_TRIG:         worker_offset <= UOP_OFFSET_CONVERT;
            
            FSM_STATE_CONVERT_EXTRA_TRIG:   worker_offset <= worker_flagz_convert_extra ?
                                            UOP_OFFSET_CONVERT_AT_INFINITY : UOP_OFFSET_CONVERT_REGULAR;
            
            default:                        worker_offset <= {UOP_ADDR_WIDTH{1'bX}};
            
        endcase
            

    //
    // FSM Process
    //
    always @(posedge clk or negedge rst_n)
        //
        if (rst_n == 1'b0)  fsm_state <= FSM_STATE_IDLE;
        else                fsm_state <= fsm_state_next;


    //
    // FSM Transition Logic
    //
    always @* begin
        //
        fsm_state_next = FSM_STATE_IDLE;
        //
        case (fsm_state)

            FSM_STATE_IDLE:                 fsm_state_next = ena           ? FSM_STATE_PREPARE_TRIG         : FSM_STATE_IDLE;
            
            FSM_STATE_PREPARE_TRIG:         fsm_state_next =                 FSM_STATE_PREPARE_WAIT         ;
            FSM_STATE_PREPARE_WAIT:         fsm_state_next = fsm_wait_done ? FSM_STATE_CYCLE_DBL_TRIG       : FSM_STATE_PREPARE_WAIT;
            FSM_STATE_CYCLE_DBL_TRIG:       fsm_state_next =                 FSM_STATE_CYCLE_DBL_WAIT       ;
            FSM_STATE_CYCLE_DBL_WAIT:       fsm_state_next = fsm_wait_done ? FSM_STATE_CYCLE_ADD_TRIG       : FSM_STATE_CYCLE_DBL_WAIT;
            FSM_STATE_CYCLE_ADD_TRIG:       fsm_state_next =                 FSM_STATE_CYCLE_ADD_WAIT       ;
            FSM_STATE_CYCLE_ADD_WAIT:       fsm_state_next = fsm_wait_done ? FSM_STATE_CYCLE_ADD_EXTRA_TRIG : FSM_STATE_CYCLE_ADD_WAIT;
            FSM_STATE_CYCLE_ADD_EXTRA_TRIG: fsm_state_next =                 FSM_STATE_CYCLE_ADD_EXTRA_WAIT ;
            FSM_STATE_CYCLE_ADD_EXTRA_WAIT: fsm_state_next = fsm_wait_done ? FSM_STATE_AFTER_CYCLE_TRIG     : FSM_STATE_CYCLE_ADD_EXTRA_WAIT;
            FSM_STATE_AFTER_CYCLE_TRIG:     fsm_state_next =                 FSM_STATE_AFTER_CYCLE_WAIT     ;
            FSM_STATE_AFTER_CYCLE_WAIT:     fsm_state_next = fsm_wait_done ? fsm_state_after_cycle          : FSM_STATE_AFTER_CYCLE_WAIT;
            FSM_STATE_INVERT_TRIG:          fsm_state_next =                 FSM_STATE_INVERT_WAIT          ;
            FSM_STATE_INVERT_WAIT:          fsm_state_next = fsm_wait_done ? FSM_STATE_CONVERT_TRIG         : FSM_STATE_INVERT_WAIT;
            FSM_STATE_CONVERT_TRIG:         fsm_state_next =                 FSM_STATE_CONVERT_WAIT         ;
            FSM_STATE_CONVERT_WAIT:         fsm_state_next = fsm_wait_done ? FSM_STATE_CONVERT_EXTRA_TRIG   : FSM_STATE_CONVERT_WAIT;
            FSM_STATE_CONVERT_EXTRA_TRIG:   fsm_state_next =                 FSM_STATE_CONVERT_EXTRA_WAIT   ;
            FSM_STATE_CONVERT_EXTRA_WAIT:   fsm_state_next = fsm_wait_done ? FSM_STATE_DONE                 : FSM_STATE_CONVERT_EXTRA_WAIT;
            FSM_STATE_DONE:                 fsm_state_next =                 FSM_STATE_IDLE                 ;

        endcase
        //
    end


    //
    // Worker
    //
    wire worker_output_now = (fsm_state == FSM_STATE_CONVERT_EXTRA_WAIT);
    
    ecdsa384_uop_worker uop_worker
    (
        .clk            (clk),
        .rst_n          (rst_n),
          
        .ena            (worker_trig),
        .rdy            (worker_done),
        .uop_offset     (worker_offset),
        .output_now     (worker_output_now),
          
        .flagz_sz       (worker_flagz_sz),
        .flagz_rz       (worker_flagz_rz),
        .flagz_e        (worker_flagz_e),
        .flagz_f        (worker_flagz_f),
        
        .xy_addr        (rxy_addr),
        .xy_dout        (rxy_dout),
        .x_wren         (rx_wren),
        .y_wren         (ry_wren)
    );


    //
    // Ready Flag Logic
    //
    reg rdy_reg = 1'b1;
    assign rdy = rdy_reg;

    always @(posedge clk or negedge rst_n)
        //
        if (rst_n == 1'b0)              rdy_reg <= 1'b1;
        else case (fsm_state)
            FSM_STATE_IDLE: if (ena)    rdy_reg <= 1'b0;
            FSM_STATE_DONE:             rdy_reg <= 1'b1;
        endcase
        

endmodule


//------------------------------------------------------------------------------
// End-of-File
//------------------------------------------------------------------------------