//======================================================================
//
// modexp.v
// --------
// Modular exponentiation core for implementing public key algorithms
// such as RSA, DH, ElGamal etc.
//
// The core calculates the following function:
//
// C = M ** e mod N
//
// M is a message with a length of n bits
// e is the exponent with a length of m bits
// N is the modulus with a length of n bits
//
// n can be 32 and up to and including 8192 bits in steps
// of 32 bits.
// m can be one and up to and including 8192 bits in steps
// of 32 bits.
//
// The core has a 32-bit memory like interface, but provides
// status signals to inform the system that a given operation
// has is done. Additionally, any errors will also be asserted.
//
//
// Author: Joachim Strombergson, Peter Magnusson
// Copyright (c) 2015, Assured AB
// 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 modexp(
input wire clk,
input wire reset_n,
input wire cs,
input wire we,
input wire [11 : 0] address,
input wire [31 : 0] write_data,
output wire [31 : 0] read_data
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam GENERAL_PREFIX = 4'h0;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_INIT_BIT = 0;
localparam CTRL_NEXT_BIT = 1;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_MODULUS_LENGTH = 8'h20;
localparam ADDR_EXPONENT_LENGTH = 8'h21;
localparam ADDR_LENGTH = 8'h22; // Should be deprecated.
localparam ADDR_MODULUS_PTR_RST = 8'h30;
localparam ADDR_MODULUS_DATA = 8'h31;
localparam ADDR_EXPONENT_PTR_RST = 8'h40;
localparam ADDR_EXPONENT_DATA = 8'h41;
localparam ADDR_MESSAGE_PTR_RST = 8'h50;
localparam ADDR_MESSAGE_DATA = 8'h51;
localparam ADDR_RESULT_PTR_RST = 8'h60;
localparam ADDR_RESULT_DATA = 8'h61;
localparam DEFAULT_MODLENGTH = 8'h80; // 2048 bits.
localparam DEFAULT_EXPLENGTH = 8'h80;
localparam MONTPROD_SELECT_ONE_NR = 3'h0;
localparam MONTPROD_SELECT_X_NR = 3'h1;
localparam MONTPROD_SELECT_Z_P = 3'h2;
localparam MONTPROD_SELECT_P_P = 3'h3;
localparam MONTPROD_SELECT_Z_ONE = 3'h4;
localparam MONTPROD_DEST_Z = 2'b00;
localparam MONTPROD_DEST_P = 2'b01;
localparam MONTPROD_DEST_NOWHERE = 2'b10;
localparam CTRL_IDLE = 4'h0;
localparam CTRL_RESIDUE = 4'h1;
localparam CTRL_CALCULATE_Z0 = 4'h2;
localparam CTRL_CALCULATE_P0 = 4'h3;
localparam CTRL_ITERATE = 4'h4;
localparam CTRL_ITERATE_Z_P = 4'h5;
localparam CTRL_ITERATE_P_P = 4'h6;
localparam CTRL_ITERATE_END = 4'h7;
localparam CTRL_CALCULATE_ZN = 4'h8;
localparam CTRL_DONE = 4'h9;
localparam EXPONATION_MODE_SECRET_SECURE = 1'b0;
localparam EXPONATION_MODE_PUBLIC_FAST = 1'b1; //for rsa, c=M^65537 etc, there is no need to slow down to hide the exponent
localparam CORE_NAME0 = 32'h6d6f6465; // "mode"
localparam CORE_NAME1 = 32'h78702020; // "xp "
localparam CORE_VERSION = 32'h302e3531; // "0.51"
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg [07 : 0] exponent_length_reg;
reg [07 : 0] exponent_length_new;
reg exponent_length_we;
reg [07 : 0] modulus_length_reg;
reg [07 : 0] modulus_length_new;
reg modulus_length_we;
reg [07 : 0] length_m1_reg;
reg [07 : 0] length_m1_new;
reg start_reg;
reg start_new;
reg start_we;
reg clear_start;
reg ready_reg;
reg ready_new;
reg ready_we;
reg [2 : 0] montprod_select_reg;
reg [2 : 0] montprod_select_new;
reg montprod_select_we;
reg [1 : 0] montprod_dest_reg;
reg [1 : 0] montprod_dest_new;
reg montprod_dest_we;
reg [3 : 0] modexp_ctrl_reg;
reg [3 : 0] modexp_ctrl_new;
reg modexp_ctrl_we;
reg [31 : 0] one_reg;
reg [31 : 0] one_new;
reg [31 : 0] b_one_reg;
reg [31 : 0] b_one_new;
reg [12 : 0] loop_counter_reg;
reg [12 : 0] loop_counter_new;
reg loop_counter_we;
reg [07 : 0] E_word_index;
reg [04 : 0] E_bit_index;
reg last_iteration;
reg ei_reg;
reg ei_new;
reg ei_we;
reg exponation_mode_reg;
reg exponation_mode_new;
reg exponation_mode_we;
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg [07 : 0] modulus_mem_int_rd_addr;
wire [31 : 0] modulus_mem_int_rd_data;
wire [31 : 0] modulus_mem_api_rd_data;
reg [07 : 0] message_mem_int_rd_addr;
wire [31 : 0] message_mem_int_rd_data;
wire [31 : 0] message_mem_api_rd_data;
reg [07 : 0] exponent_mem_int_rd_addr;
wire [31 : 0] exponent_mem_int_rd_data;
wire [31 : 0] exponent_mem_api_rd_data;
wire [31 : 0] result_mem_api_rd_data;
reg [07 : 0] result_mem_int_rd_addr;
wire [31 : 0] result_mem_int_rd_data;
reg [07 : 0] result_mem_int_wr_addr;
reg [31 : 0] result_mem_int_wr_data;
reg result_mem_int_we;
reg [07 : 0] p_mem_rd0_addr;
wire [31 : 0] p_mem_rd0_data;
reg [07 : 0] p_mem_rd1_addr;
wire [31 : 0] p_mem_rd1_data;
reg [07 : 0] p_mem_wr_addr;
reg [31 : 0] p_mem_wr_data;
reg p_mem_we;
reg [31 : 0] tmp_read_data;
//reg tmp_error;
reg montprod_calc;
wire montprod_ready;
reg [07 : 0] montprod_length;
wire [07 : 0] montprod_opa_addr;
reg [31 : 0] montprod_opa_data;
wire [07 : 0] montprod_opb_addr;
reg [31 : 0] montprod_opb_data;
wire [07 : 0] montprod_opm_addr;
reg [31 : 0] montprod_opm_data;
wire [07 : 0] montprod_result_addr;
wire [31 : 0] montprod_result_data;
wire montprod_result_we;
reg residue_calculate;
wire residue_ready;
reg [14 : 0] residue_nn;
reg [07 : 0] residue_length;
wire [07 : 0] residue_opa_rd_addr;
wire [31 : 0] residue_opa_rd_data;
wire [07 : 0] residue_opa_wr_addr;
wire [31 : 0] residue_opa_wr_data;
wire residue_opa_wr_we;
wire [07 : 0] residue_opm_addr;
reg [31 : 0] residue_opm_data;
reg [07 : 0] residue_mem_montprod_read_addr;
wire [31 : 0] residue_mem_montprod_read_data;
reg residue_valid_reg;
reg residue_valid_new;
reg invalidate_residue;
reg residue_valid_int_validated;
reg modulus_mem_api_rst;
reg modulus_mem_api_cs;
reg modulus_mem_api_wr;
reg exponent_mem_api_rst;
reg exponent_mem_api_cs;
reg exponent_mem_api_wr;
reg message_mem_api_rst;
reg message_mem_api_cs;
reg message_mem_api_wr;
reg result_mem_api_rst;
reg result_mem_api_cs;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign read_data = tmp_read_data;
//----------------------------------------------------------------
// core instantiations.
//----------------------------------------------------------------
montprod montprod_inst(
.clk(clk),
.reset_n(reset_n),
.calculate(montprod_calc),
.ready(montprod_ready),
.length(montprod_length),
.opa_addr(montprod_opa_addr),
.opa_data(montprod_opa_data),
.opb_addr(montprod_opb_addr),
.opb_data(montprod_opb_data),
.opm_addr(montprod_opm_addr),
.opm_data(montprod_opm_data),
.result_addr(montprod_result_addr),
.result_data(montprod_result_data),
.result_we(montprod_result_we)
);
residue residue_inst(
.clk(clk),
.reset_n(reset_n),
.calculate(residue_calculate),
.ready(residue_ready),
.nn(residue_nn),
.length(residue_length),
.opa_rd_addr(residue_opa_rd_addr),
.opa_rd_data(residue_opa_rd_data),
.opa_wr_addr(residue_opa_wr_addr),
.opa_wr_data(residue_opa_wr_data),
.opa_wr_we(residue_opa_wr_we),
.opm_addr(residue_opm_addr),
.opm_data(residue_opm_data)
);
blockmem2r1w residue_mem(
.clk(clk),
.read_addr0(residue_opa_rd_addr),
.read_data0(residue_opa_rd_data),
.read_addr1(residue_mem_montprod_read_addr),
.read_data1(residue_mem_montprod_read_data),
.wr(residue_opa_wr_we),
.write_addr(residue_opa_wr_addr),
.write_data(residue_opa_wr_data)
);
blockmem2r1wptr modulus_mem(
.clk(clk),
.reset_n(reset_n),
.read_addr0(modulus_mem_int_rd_addr),
.read_data0(modulus_mem_int_rd_data),
.read_data1(modulus_mem_api_rd_data),
.rst(modulus_mem_api_rst),
.cs(modulus_mem_api_cs),
.wr(modulus_mem_api_wr),
.write_data(write_data)
);
blockmem2r1wptr message_mem(
.clk(clk),
.reset_n(reset_n),
.read_addr0(message_mem_int_rd_addr),
.read_data0(message_mem_int_rd_data),
.read_data1(message_mem_api_rd_data),
.rst(message_mem_api_rst),
.cs(message_mem_api_cs),
.wr(message_mem_api_wr),
.write_data(write_data)
);
blockmem2r1wptr exponent_mem(
.clk(clk),
.reset_n(reset_n),
.read_addr0(exponent_mem_int_rd_addr),
.read_data0(exponent_mem_int_rd_data),
.read_data1(exponent_mem_api_rd_data),
.rst(exponent_mem_api_rst),
.cs(exponent_mem_api_cs),
.wr(exponent_mem_api_wr),
.write_data(write_data)
);
blockmem2rptr1w result_mem(
.clk(clk),
.reset_n(reset_n),
.read_addr0(result_mem_int_rd_addr[7 : 0]),
.read_data0(result_mem_int_rd_data),
.read_data1(result_mem_api_rd_data),
.rst(result_mem_api_rst),
.cs(result_mem_api_cs),
.wr(result_mem_int_we),
.write_addr(result_mem_int_wr_addr),
.write_data(result_mem_int_wr_data)
);
blockmem2r1w p_mem(
.clk(clk),
.read_addr0(p_mem_rd0_addr),
.read_data0(p_mem_rd0_data),
.read_addr1(p_mem_rd1_addr),
.read_data1(p_mem_rd1_data),
.wr(p_mem_we),
.write_addr(p_mem_wr_addr),
.write_data(p_mem_wr_data)
);
//----------------------------------------------------------------
// reg_update
//
// Update functionality for all registers in the core.
// All registers are positive edge triggered with asynchronous
// active low reset. All registers have write enable.
//----------------------------------------------------------------
always @ (posedge clk or negedge reset_n)
begin
if (!reset_n)
begin
exponent_length_reg <= DEFAULT_EXPLENGTH;
modulus_length_reg <= DEFAULT_MODLENGTH;
start_reg <= 1'b0;
ready_reg <= 1'b1;
montprod_select_reg <= MONTPROD_SELECT_ONE_NR;
montprod_dest_reg <= MONTPROD_DEST_NOWHERE;
modexp_ctrl_reg <= CTRL_IDLE;
one_reg <= 32'h0;
b_one_reg <= 32'h0;
length_m1_reg <= 8'h0;
loop_counter_reg <= 13'b0;
ei_reg <= 1'b0;
residue_valid_reg <= 1'b0;
exponation_mode_reg <= EXPONATION_MODE_SECRET_SECURE;
end
else
begin
one_reg <= one_new;
b_one_reg <= b_one_new;
residue_valid_reg <= residue_valid_new;
if (exponent_length_we)
exponent_length_reg <= exponent_length_new;
if (modulus_length_we)
begin
modulus_length_reg <= modulus_length_new;
length_m1_reg <= length_m1_new;
end
if (start_we)
start_reg <= start_new;
if (ready_we)
ready_reg <= ready_new;
if (montprod_select_we)
montprod_select_reg <= montprod_select_new;
if (montprod_dest_we)
montprod_dest_reg <= montprod_dest_new;
if (modexp_ctrl_we)
modexp_ctrl_reg <= modexp_ctrl_new;
if (loop_counter_we)
loop_counter_reg <= loop_counter_new;
if (ei_we)
ei_reg <= ei_new;
if (exponation_mode_we)
exponation_mode_reg <= exponation_mode_new;
end
end // reg_update
//----------------------------------------------------------------
// api
//
// The interface command decoding logic.
//----------------------------------------------------------------
always @*
begin : api
modulus_length_we = 1'b0;
exponent_length_we = 1'b0;
start_new = 1'b0;
start_we = 1'b0;
invalidate_residue = 1'b0;
modulus_mem_api_rst = 1'b0;
modulus_mem_api_cs = 1'b0;
modulus_mem_api_wr = 1'b0;
exponent_mem_api_rst = 1'b0;
exponent_mem_api_cs = 1'b0;
exponent_mem_api_wr = 1'b0;
message_mem_api_rst = 1'b0;
message_mem_api_cs = 1'b0;
message_mem_api_wr = 1'b0;
result_mem_api_rst = 1'b0;
result_mem_api_cs = 1'b0;
//TODO: Add API code to enable fast exponation for working with public exponents.
exponation_mode_we = 1'b0;
exponation_mode_new = EXPONATION_MODE_SECRET_SECURE;
modulus_length_new = write_data[7 : 0];
exponent_length_new = write_data[7 : 0];
length_m1_new = write_data[7 : 0] - 8'h1;
tmp_read_data = 32'h00000000;
// We need to be able to clear start bit after we have
// started a modexp operation.
if (clear_start)
begin
start_new = 1'b0;
start_we = 1'b1;
end
if (cs)
begin
case (address[11 : 8])
GENERAL_PREFIX:
begin
if (we)
begin
case (address[7 : 0])
ADDR_CTRL:
begin
start_new = write_data[0];
start_we = 1'b1;
end
ADDR_MODULUS_LENGTH:
begin
modulus_length_we = 1'b1;
end
ADDR_EXPONENT_LENGTH:
begin
exponent_length_we = 1'b1;
end
ADDR_MODULUS_PTR_RST:
begin
modulus_mem_api_rst = 1'b1;
end
ADDR_MODULUS_DATA:
begin
modulus_mem_api_cs = 1'b1;
modulus_mem_api_wr = 1'b1;
invalidate_residue = 1'b1;
end
ADDR_EXPONENT_PTR_RST:
begin
exponent_mem_api_rst = 1'b1;
end
ADDR_EXPONENT_DATA:
begin
exponent_mem_api_cs = 1'b1;
exponent_mem_api_wr = 1'b1;
end
ADDR_MESSAGE_PTR_RST:
begin
message_mem_api_rst = 1'b1;
end
ADDR_MESSAGE_DATA:
begin
message_mem_api_cs = 1'b1;
message_mem_api_wr = 1'b1;
end
ADDR_RESULT_PTR_RST:
begin
result_mem_api_rst = 1'b1;
end
default:
begin
end
endcase // case (address[7 : 0])
end
else
begin
case (address[7 : 0])
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 = {31'h00000000, start_reg};
ADDR_STATUS:
tmp_read_data = {31'h00000000, ready_reg};
ADDR_MODULUS_LENGTH:
tmp_read_data = {24'h000000, modulus_length_reg};
ADDR_EXPONENT_LENGTH:
tmp_read_data = {24'h000000, exponent_length_reg};
ADDR_MODULUS_DATA:
begin
modulus_mem_api_cs = 1'b1;
tmp_read_data = modulus_mem_api_rd_data;
end
ADDR_EXPONENT_DATA:
begin
exponent_mem_api_cs = 1'b1;
tmp_read_data = exponent_mem_api_rd_data;
end
ADDR_MESSAGE_DATA:
begin
message_mem_api_cs = 1'b1;
tmp_read_data = message_mem_api_rd_data;
end
ADDR_RESULT_DATA:
begin
result_mem_api_cs = 1'b1;
tmp_read_data = result_mem_api_rd_data;
end
default:
begin
end
endcase // case (address[7 : 0])
end
end
default:
begin
end
endcase // case (address[11 : 8])
end // if (cs)
end // api
//----------------------------------------------------------------
// one
//
// generates the big integer one ( 00... 01 )
//----------------------------------------------------------------
always @*
begin : one_process
one_new = 32'h00000000;
b_one_new = 32'h00000000;
if (montprod_opa_addr == length_m1_reg)
one_new = 32'h00000001;
if (montprod_opb_addr == length_m1_reg)
b_one_new = 32'h00000001;
end
//----------------------------------------------------------------
// Read mux for modulus. Needed since it is being
// addressed by two sources.
//----------------------------------------------------------------
always @*
begin : modulus_mem_reader_process
if (modexp_ctrl_reg == CTRL_RESIDUE)
modulus_mem_int_rd_addr = residue_opm_addr;
else
modulus_mem_int_rd_addr = montprod_opm_addr;
end
//----------------------------------------------------------------
// Feeds residue calculator.
//----------------------------------------------------------------
always @*
begin : residue_process
//N*2, N=length*32, *32 = shl5, *64 = shl6
residue_nn = { 1'b0, modulus_length_reg, 6'h0 };
residue_length = modulus_length_reg;
residue_opm_data = modulus_mem_int_rd_data;
end
//----------------------------------------------------------------
// Sets the register that decides if residue is valid or not.
//----------------------------------------------------------------
always @*
begin : residue_valid_process
if (invalidate_residue)
residue_valid_new = 1'b0;
else if ( residue_valid_int_validated == 1'b1)
residue_valid_new = 1'b1;
else
residue_valid_new = residue_valid_reg;
end
//----------------------------------------------------------------
// montprod_op_select
//
// Select operands used during montprod calculations depending
// on what operation we want to do.
//----------------------------------------------------------------
always @*
begin : montprod_op_select
montprod_length = modulus_length_reg;
result_mem_int_rd_addr = montprod_opa_addr;
message_mem_int_rd_addr = montprod_opa_addr;
p_mem_rd0_addr = montprod_opa_addr;
residue_mem_montprod_read_addr = montprod_opb_addr;
p_mem_rd1_addr = montprod_opb_addr;
montprod_opm_data = modulus_mem_int_rd_data;
case (montprod_select_reg)
MONTPROD_SELECT_ONE_NR:
begin
montprod_opa_data = one_reg;
montprod_opb_data = residue_mem_montprod_read_data;
end
MONTPROD_SELECT_X_NR:
begin
montprod_opa_data = message_mem_int_rd_data;
montprod_opb_data = residue_mem_montprod_read_data;
end
MONTPROD_SELECT_Z_P:
begin
montprod_opa_data = result_mem_int_rd_data;
montprod_opb_data = p_mem_rd1_data;
end
MONTPROD_SELECT_P_P:
begin
montprod_opa_data = p_mem_rd0_data;
montprod_opb_data = p_mem_rd1_data;
end
MONTPROD_SELECT_Z_ONE:
begin
montprod_opa_data = result_mem_int_rd_data;
montprod_opb_data = b_one_reg;
end
default:
begin
montprod_opa_data = 32'h00000000;
montprod_opb_data = 32'h00000000;
end
endcase // case (montprod_selcect_reg)
end
//----------------------------------------------------------------
// memory write mux
//
// Direct memory write signals to correct memory.
//----------------------------------------------------------------
always @*
begin : memory_write_process
result_mem_int_wr_addr = montprod_result_addr;
result_mem_int_wr_data = montprod_result_data;
result_mem_int_we = 1'b0;
p_mem_wr_addr = montprod_result_addr;
p_mem_wr_data = montprod_result_data;
p_mem_we = 1'b0;
case (montprod_dest_reg)
MONTPROD_DEST_Z:
result_mem_int_we = montprod_result_we;
MONTPROD_DEST_P:
p_mem_we = montprod_result_we;
default:
begin
end
endcase
// inhibit Z=Z*P when ei = 0
if (modexp_ctrl_reg == CTRL_ITERATE_Z_P)
result_mem_int_we = result_mem_int_we & ei_reg;
end
//----------------------------------------------------------------
// loop_counter
//
// Calculate the loop counter and related variables.
//----------------------------------------------------------------
always @*
begin : loop_counters_process
loop_counter_new = 13'b0;
loop_counter_we = 1'b0;
if (loop_counter_reg == { length_m1_reg, 5'b11111 })
last_iteration = 1'b1;
else
last_iteration = 1'b0;
case (modexp_ctrl_reg)
CTRL_CALCULATE_P0:
begin
loop_counter_new = 13'b0;
loop_counter_we = 1'b1;
end
CTRL_ITERATE_END:
begin
loop_counter_new = loop_counter_reg + 1'b1;
loop_counter_we = 1'b1;
end
default:
begin
end
endcase
end
//----------------------------------------------------------------
// exponent
//
// Reads the exponent.
//----------------------------------------------------------------
always @*
begin : exponent_process
// Accessing new instead of reg - pick up update at
// CTRL_ITERATE_NEW to remove a pipeline stall.
E_word_index = length_m1_reg - loop_counter_new[ 12 : 5 ];
E_bit_index = loop_counter_reg[ 04 : 0 ];
exponent_mem_int_rd_addr = E_word_index;
ei_new = exponent_mem_int_rd_data[ E_bit_index ];
if (modexp_ctrl_reg == CTRL_ITERATE)
ei_we = 1'b1;
else
ei_we = 1'b0;
end
//----------------------------------------------------------------
// modexp_ctrl
//
// Control FSM logic needed to perform the modexp operation.
//----------------------------------------------------------------
always @*
begin
ready_new = 1'b0;
ready_we = 1'b0;
montprod_select_new = MONTPROD_SELECT_ONE_NR;
montprod_select_we = 0;
montprod_dest_new = MONTPROD_DEST_NOWHERE;
montprod_dest_we = 0;
montprod_calc = 0;
modexp_ctrl_new = CTRL_IDLE;
modexp_ctrl_we = 1'b0;
clear_start = 1'b0;
residue_calculate = 1'b0;
residue_valid_int_validated = 1'b0;
case (modexp_ctrl_reg)
CTRL_IDLE:
begin
if (start_reg)
begin
ready_new = 1'b0;
ready_we = 1'b1;
modexp_ctrl_new = CTRL_DONE;
modexp_ctrl_we = 1'b1;
if (residue_valid_reg)
begin
//residue has alrady been calculated, start with MONTPROD( 1, Nr, MODULUS )
montprod_select_new = MONTPROD_SELECT_ONE_NR;
montprod_select_we = 1;
montprod_dest_new = MONTPROD_DEST_Z;
montprod_dest_we = 1;
montprod_calc = 1;
modexp_ctrl_new = CTRL_CALCULATE_Z0;
modexp_ctrl_we = 1;
end
else
begin
//modulus has been written and residue (Nr) must be calculated
modexp_ctrl_new = CTRL_RESIDUE;
modexp_ctrl_we = 1;
residue_calculate = 1'b1;
end
end
end
CTRL_RESIDUE:
begin
if (residue_ready)
begin
montprod_select_new = MONTPROD_SELECT_ONE_NR;
montprod_select_we = 1;
montprod_dest_new = MONTPROD_DEST_Z;
montprod_dest_we = 1;
montprod_calc = 1;
modexp_ctrl_new = CTRL_CALCULATE_Z0;
modexp_ctrl_we = 1;
residue_valid_int_validated = 1'b1; //update registers telling residue is valid
end
end
CTRL_CALCULATE_Z0:
begin
if (montprod_ready)
begin
montprod_select_new = MONTPROD_SELECT_X_NR;
montprod_select_we = 1;
montprod_dest_new = MONTPROD_DEST_P;
montprod_dest_we = 1;
montprod_calc = 1;
modexp_ctrl_new = CTRL_CALCULATE_P0;
modexp_ctrl_we = 1;
end
end
CTRL_CALCULATE_P0:
begin
if (montprod_ready == 1'b1)
begin
modexp_ctrl_new = CTRL_ITERATE;
modexp_ctrl_we = 1;
end
end
CTRL_ITERATE:
begin
montprod_select_new = MONTPROD_SELECT_Z_P;
montprod_select_we = 1;
montprod_dest_new = MONTPROD_DEST_Z;
montprod_dest_we = 1;
montprod_calc = 1;
modexp_ctrl_new = CTRL_ITERATE_Z_P;
modexp_ctrl_we = 1;
if (ei_new == 1'b0 && exponation_mode_reg == EXPONATION_MODE_PUBLIC_FAST)
begin
//Skip the fake montgomery calculation, exponation_mode_reg optimizing for speed not blinding.
montprod_select_new = MONTPROD_SELECT_P_P;
montprod_dest_new = MONTPROD_DEST_P;
modexp_ctrl_new = CTRL_ITERATE_P_P;
end
end
CTRL_ITERATE_Z_P:
if (montprod_ready)
begin
montprod_select_new = MONTPROD_SELECT_P_P;
montprod_select_we = 1;
montprod_dest_new = MONTPROD_DEST_P;
montprod_dest_we = 1;
montprod_calc = 1;
modexp_ctrl_new = CTRL_ITERATE_P_P;
modexp_ctrl_we = 1;
end
CTRL_ITERATE_P_P:
if (montprod_ready == 1'b1)
begin
modexp_ctrl_new = CTRL_ITERATE_END;
modexp_ctrl_we = 1;
end
CTRL_ITERATE_END:
begin
if (!last_iteration)
begin
modexp_ctrl_new = CTRL_ITERATE;
modexp_ctrl_we = 1;
end
else
begin
montprod_select_new = MONTPROD_SELECT_Z_ONE;
montprod_select_we = 1;
montprod_dest_new = MONTPROD_DEST_Z;
montprod_dest_we = 1;
montprod_calc = 1;
modexp_ctrl_new = CTRL_CALCULATE_ZN;
modexp_ctrl_we = 1;
end
end
CTRL_CALCULATE_ZN:
begin
if (montprod_ready)
begin
modexp_ctrl_new = CTRL_DONE;
modexp_ctrl_we = 1;
end
end
CTRL_DONE:
begin
clear_start = 1'b1;
ready_new = 1'b1;
ready_we = 1'b1;
modexp_ctrl_new = CTRL_IDLE;
modexp_ctrl_we = 1;
end
default:
begin
end
endcase // case (modexp_ctrl_reg)
end
endmodule // modexp
//======================================================================
// EOF modexp.v
//======================================================================