summaryrefslogtreecommitdiff
path: root/rtl
diff options
context:
space:
mode:
authorPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2018-09-25 01:18:36 +0300
committerPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2018-09-25 01:18:36 +0300
commit0770d120f20bab87df10df989790d9157afa91a2 (patch)
tree6fec790e14b732f7015a77c066f584d0f6a5a631 /rtl
parent59cd537cc2314f308a3817baa3eee0f8c4619c60 (diff)
Double-and-add point multiplication framework
Diffstat (limited to 'rtl')
-rw-r--r--rtl/ed25519_multiplier.v250
1 files changed, 250 insertions, 0 deletions
diff --git a/rtl/ed25519_multiplier.v b/rtl/ed25519_multiplier.v
new file mode 100644
index 0000000..d6960ec
--- /dev/null
+++ b/rtl/ed25519_multiplier.v
@@ -0,0 +1,250 @@
+//------------------------------------------------------------------------------
+//
+// ed25519_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_multiplier
+(
+ clk, rst_n,
+ ena, rdy,
+ k_addr, qy_addr,
+ qy_wren,
+ k_din,
+ qy_dout
+);
+
+
+ //
+ // Microcode Header
+ //
+`include "ed25519_uop.v"
+
+
+ //
+ // 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 [3:0] FSM_STATE_IDLE = 4'd00;
+ localparam [3:0] FSM_STATE_PREPARE_TRIG = 4'd01;
+ localparam [3:0] FSM_STATE_PREPARE_WAIT = 4'd02;
+ localparam [3:0] FSM_STATE_BEFORE_ROUND_TRIG = 4'd03;
+ localparam [3:0] FSM_STATE_BEFORE_ROUND_WAIT = 4'd04;
+ localparam [3:0] FSM_STATE_DURING_ROUND_TRIG = 4'd05;
+ localparam [3:0] FSM_STATE_DURING_ROUND_WAIT = 4'd06;
+ localparam [3:0] FSM_STATE_AFTER_ROUND_TRIG = 4'd07;
+ localparam [3:0] FSM_STATE_AFTER_ROUND_WAIT = 4'd08;
+ localparam [3:0] FSM_STATE_DONE = 4'd15;
+
+ reg [3:0] fsm_state = FSM_STATE_IDLE;
+ reg [3: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: 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_DONE;
+
+
+
+
+ //
+ // 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;
+ 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_DONE: fsm_state_next = FSM_STATE_IDLE;
+
+ endcase
+ //
+ end
+
+
+ //
+ // Worker
+ //
+ ed25519_worker uop_worker
+ (
+ .clk (clk),
+ .rst_n (rst_n),
+ .ena (worker_trig),
+ .rdy (worker_done),
+ .uop_offset (worker_offset)
+ );
+
+
+ //
+ // 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
+//------------------------------------------------------------------------------