//------------------------------------------------------------------------------ // // 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 //------------------------------------------------------------------------------