summaryrefslogblamecommitdiff
path: root/rtl/ed25519_base_point_multiplier.v
blob: ddde3c4b330e46c9df138233160ae03fbfd492a2 (plain) (tree)
1
2
3

                                                                                
                                  


































                                                                                
                                    












                       
                         




















                                                         
























                                                            




























                                                                                






                                                                


















                                                                            

                                                                   
































                                                                                                                                      







                                                                                                                                    



































                                                                                                                                       

















                                                                                                                                         






                                                                            
 


             




                                                                        
                                 


                            










                                              























                                                                                
//------------------------------------------------------------------------------
//
// ed25519_base_point_multiplier.v
// -----------------------------------------------------------------------------
// Ed25519 base point scalar multiplier.
//
// Authors: Pavel Shatov
//
// Copyright (c) 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 ed25519_base_point_multiplier
(
    clk, rst_n,
    ena, rdy,
    k_addr, qy_addr,
    qy_wren,
    k_din,
    qy_dout
);


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

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

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

    output  [ 2:0]  k_addr;     //
    output  [ 2:0]  qy_addr;    //
    output          qy_wren;    //
    input   [31:0]  k_din;      //
    output  [31:0]  qy_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_BEFORE_ROUND_TRIG    = 5'd03;
    localparam [4:0] FSM_STATE_BEFORE_ROUND_WAIT    = 5'd04;
    localparam [4:0] FSM_STATE_DURING_ROUND_TRIG    = 5'd05;
    localparam [4:0] FSM_STATE_DURING_ROUND_WAIT    = 5'd06;
    localparam [4:0] FSM_STATE_AFTER_ROUND_TRIG     = 5'd07;
    localparam [4:0] FSM_STATE_AFTER_ROUND_WAIT     = 5'd08;
    localparam [4:0] FSM_STATE_BEFORE_INVERT_TRIG   = 5'd09;
    localparam [4:0] FSM_STATE_BEFORE_INVERT_WAIT   = 5'd10;
    localparam [4:0] FSM_STATE_DURING_INVERT_TRIG   = 5'd11;
    localparam [4:0] FSM_STATE_DURING_INVERT_WAIT   = 5'd12;
    localparam [4:0] FSM_STATE_AFTER_INVERT_TRIG    = 5'd13;
    localparam [4:0] FSM_STATE_AFTER_INVERT_WAIT    = 5'd14;
    localparam [4:0] FSM_STATE_FINAL_REDUCE_TRIG    = 5'd15;
    localparam [4:0] FSM_STATE_FINAL_REDUCE_WAIT    = 5'd16;
    localparam [4:0] FSM_STATE_HANDLE_SIGN_TRIG     = 5'd17;
    localparam [4:0] FSM_STATE_HANDLE_SIGN_WAIT     = 5'd18;
    localparam [4:0] FSM_STATE_OUTPUT_TRIG          = 5'd19;
    localparam [4:0] FSM_STATE_OUTPUT_WAIT          = 5'd20;
    localparam [4:0] FSM_STATE_DONE                 = 5'd31;

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


    //
    // Round Counter
    //
    reg  [7:0] bit_counter;
    wire [7:0] bit_counter_max  = 8'hFF;    // 255
    wire [7:0] bit_counter_zero = 8'h00;    // 0
    wire [7:0] bit_counter_next =
        (bit_counter < bit_counter_max) ? bit_counter + 1'b1 : bit_counter_zero;

    assign k_addr = bit_counter[7: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_BEFORE_ROUND_TRIG,
            FSM_STATE_DURING_ROUND_TRIG,
            FSM_STATE_AFTER_ROUND_TRIG,
            FSM_STATE_BEFORE_INVERT_TRIG,
            FSM_STATE_DURING_INVERT_TRIG,
            FSM_STATE_AFTER_INVERT_TRIG,
            FSM_STATE_FINAL_REDUCE_TRIG,
            FSM_STATE_HANDLE_SIGN_TRIG,
            FSM_STATE_OUTPUT_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_zero;
            FSM_STATE_AFTER_ROUND_TRIG:     bit_counter <= bit_counter_next;
        endcase


    //
    // Final Round Detection Logic
    //
    wire [ 3: 0] fsm_state_after_round = (bit_counter != bit_counter_zero) ?
        FSM_STATE_BEFORE_ROUND_TRIG : FSM_STATE_BEFORE_INVERT_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_BEFORE_ROUND_TRIG)
            //
            if (k_bit_index == 5'd0)
                //
                case (k_addr)
                    3'd0:       k_din_shreg <= {k_din[31:3], 3'b000};
                    3'd7:       k_din_shreg <= {2'b01, k_din[29:0]};
                    default:    k_din_shreg <= k_din;
                endcase
                //
            else                k_din_shreg <= {k_din_shreg[0], k_din_shreg[31:1]};
    

    //
    // 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_BEFORE_ROUND_TRIG:    worker_offset <= k_din_shreg[0] ? UOP_OFFSET_BEFORE_ROUND_K1 : UOP_OFFSET_BEFORE_ROUND_K0;
            FSM_STATE_DURING_ROUND_TRIG:    worker_offset <= UOP_OFFSET_DURING_ROUND;
            FSM_STATE_AFTER_ROUND_TRIG:     worker_offset <= k_din_shreg[0] ? UOP_OFFSET_AFTER_ROUND_K1 : UOP_OFFSET_AFTER_ROUND_K0;
            FSM_STATE_BEFORE_INVERT_TRIG:   worker_offset <= UOP_OFFSET_BEFORE_INVERSION;
            FSM_STATE_DURING_INVERT_TRIG:   worker_offset <= UOP_OFFSET_DURING_INVERSION;
            FSM_STATE_AFTER_INVERT_TRIG:    worker_offset <= UOP_OFFSET_AFTER_INVERSION;
            FSM_STATE_FINAL_REDUCE_TRIG:    worker_offset <= UOP_OFFSET_FINAL_REDUCTION;
            FSM_STATE_HANDLE_SIGN_TRIG:     worker_offset <= UOP_OFFSET_HANDLE_SIGN;
            FSM_STATE_OUTPUT_TRIG:          worker_offset <= UOP_OFFSET_OUTPUT;
            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_BEFORE_ROUND_TRIG : FSM_STATE_PREPARE_WAIT;

            FSM_STATE_BEFORE_ROUND_TRIG:    fsm_state_next = FSM_STATE_BEFORE_ROUND_WAIT;
            FSM_STATE_BEFORE_ROUND_WAIT:    fsm_state_next = fsm_wait_done ? FSM_STATE_DURING_ROUND_TRIG : FSM_STATE_BEFORE_ROUND_WAIT;

            FSM_STATE_DURING_ROUND_TRIG:    fsm_state_next = FSM_STATE_DURING_ROUND_WAIT;
            FSM_STATE_DURING_ROUND_WAIT:    fsm_state_next = fsm_wait_done ? FSM_STATE_AFTER_ROUND_TRIG : FSM_STATE_DURING_ROUND_WAIT;

            FSM_STATE_AFTER_ROUND_TRIG:     fsm_state_next = FSM_STATE_AFTER_ROUND_WAIT;
            FSM_STATE_AFTER_ROUND_WAIT:     fsm_state_next = fsm_wait_done ? fsm_state_after_round : FSM_STATE_AFTER_ROUND_WAIT;

            FSM_STATE_BEFORE_INVERT_TRIG:   fsm_state_next = FSM_STATE_BEFORE_INVERT_WAIT;
            FSM_STATE_BEFORE_INVERT_WAIT:   fsm_state_next = fsm_wait_done ? FSM_STATE_DURING_INVERT_TRIG : FSM_STATE_BEFORE_INVERT_WAIT;
            
            FSM_STATE_DURING_INVERT_TRIG:   fsm_state_next = FSM_STATE_DURING_INVERT_WAIT;
            FSM_STATE_DURING_INVERT_WAIT:   fsm_state_next = fsm_wait_done ? FSM_STATE_AFTER_INVERT_TRIG : FSM_STATE_DURING_INVERT_WAIT;
            
            FSM_STATE_AFTER_INVERT_TRIG:    fsm_state_next = FSM_STATE_AFTER_INVERT_WAIT;
            FSM_STATE_AFTER_INVERT_WAIT:    fsm_state_next = fsm_wait_done ? FSM_STATE_FINAL_REDUCE_TRIG : FSM_STATE_AFTER_INVERT_WAIT;
            
            FSM_STATE_FINAL_REDUCE_TRIG:    fsm_state_next = FSM_STATE_FINAL_REDUCE_WAIT;
            FSM_STATE_FINAL_REDUCE_WAIT:    fsm_state_next = fsm_wait_done ? FSM_STATE_HANDLE_SIGN_TRIG : FSM_STATE_FINAL_REDUCE_WAIT;
            
            FSM_STATE_HANDLE_SIGN_TRIG:     fsm_state_next = FSM_STATE_HANDLE_SIGN_WAIT;
            FSM_STATE_HANDLE_SIGN_WAIT:     fsm_state_next = fsm_wait_done ? FSM_STATE_OUTPUT_TRIG : FSM_STATE_HANDLE_SIGN_WAIT;

            FSM_STATE_OUTPUT_TRIG:          fsm_state_next = FSM_STATE_OUTPUT_WAIT;
            FSM_STATE_OUTPUT_WAIT:          fsm_state_next = fsm_wait_done ? FSM_STATE_DONE : FSM_STATE_OUTPUT_WAIT;

            FSM_STATE_DONE:                 fsm_state_next = FSM_STATE_IDLE;

        endcase
        //
    end



    //
    // Worker
    //
    
    wire worker_final_reduce = fsm_state == FSM_STATE_FINAL_REDUCE_WAIT;
    wire worker_handle_sign  = fsm_state == FSM_STATE_HANDLE_SIGN_WAIT;
    wire worker_output_now   = fsm_state == FSM_STATE_OUTPUT_WAIT;
    
    ed25519_uop_worker uop_worker
    (
        .clk        (clk),
        .rst_n      (rst_n),
		  
        .ena            (worker_trig),
        .rdy            (worker_done),
        .uop_offset     (worker_offset),
        .final_reduce   (worker_final_reduce),
        .handle_sign    (worker_handle_sign),
        .output_now     (worker_output_now),
        
        .y_addr         (qy_addr),
        .y_dout         (qy_dout),
        .y_wren         (qy_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
//------------------------------------------------------------------------------