Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 5

`default_nettype none

module tea_ctr(
input wire clk,
input wire reset_n,

input wire encdec,


input wire next,
output wire ready,

input wire [127 : 0] key,


input wire [63 : 0] nonce,

input wire [63 : 0] block,


output wire [63 : 0] result
);

//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam CTRL_IDLE = 2'h0;
localparam CTRL_INIT = 2'h1;
localparam CTRL_ROUNDS0 = 2'h2;
localparam CTRL_ROUNDS1 = 2'h3;

localparam DELTA = 32'h9e3779b9;


localparam NUM_ROUNDS = 32;

//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg [31 : 0] v0_reg;
reg [31 : 0] v0_new;
reg v0_we;

reg [31 : 0] v1_reg;


reg [31 : 0] v1_new;
reg v1_we;

reg [31 : 0] sum_reg;


reg [31 : 0] sum_new;
reg sum_we;

reg [63 : 0] ctr_reg;


reg [63 : 0] ctr_new;
reg ctr_we;

reg ready_reg;
reg ready_new;
reg ready_we;

reg [1 : 0] core_ctrl_reg;
reg [1 : 0] core_ctrl_new;
reg core_ctrl_we;

//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg init_state;
reg update_v0;
reg update_v1;
reg update_sum;

//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign ready = ready_reg;
assign result = {v0_reg, v1_reg} ^ block;

//----------------------------------------------------------------
// 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: reg_update
if (!reset_n)
begin
ready_reg <= 1'h1;
v0_reg <= 32'h0;
v1_reg <= 32'h0;
sum_reg <= 32'h0;
ctr_reg <= 64'h0;
core_ctrl_reg <= CTRL_IDLE;
end
else
begin
if (ready_we)
ready_reg <= ready_new;

if (v0_we)
v0_reg <= v0_new;

if (v1_we)
v1_reg <= v1_new;

if (sum_we)
sum_reg <= sum_new;

if (ctr_we)
ctr_reg <= ctr_new;

if (core_ctrl_we)
core_ctrl_reg <= core_ctrl_new;
end
end // reg_update

//----------------------------------------------------------------
// tea_ctr_dp
//
// Datapath with state update logic.
//----------------------------------------------------------------
always @*
begin : tea_ctr_dp
reg [31 : 0] keyw [0 : 3];

v0_new = 32'h0;
v0_we = 1'h0;
v1_new = 32'h0;
v1_we = 1'h0;
sum_new = 32'h0;
sum_we = 1'h0;

keyw[0] = key[127 : 096];


keyw[1] = key[095 : 064];
keyw[2] = key[063 : 032];
keyw[3] = key[031 : 000];

if (init_state)
begin
v0_new = nonce[63 : 32];
v1_new = nonce[31 : 0];
v0_we = 1'h1;
v1_we = 1'h1;
sum_new = 32'h0;
sum_we = 1'h1;
ctr_new = 64'h1; // Start counter from 1
ctr_we = 1'h1;
end

if (update_v0 || update_v1)
begin
if (encdec)
sum_new = sum_reg + DELTA;
else
sum_new = sum_reg - DELTA;
sum_we = 1'h1;
end

// TEA encryption step


if (update_v0)
begin
v0_we = 1'h1;
v1_we = 1'h1;

v0_new = v0_reg + (((v1_reg << 4) + keyw[0]) ^ (v1_reg + sum_reg) ^


((v1_reg >> 5) + keyw[1]));
v1_new = v1_reg + (((v0_new << 4) + keyw[2]) ^ (v0_new + sum_reg) ^
((v0_new >> 5) + keyw[3]));
end

if (update_v1)
begin
v1_we = 1'h1;
v0_we = 1'h1;

v1_new = v1_reg - (((v0_reg << 4) + keyw[2]) ^ (v0_reg + sum_reg) ^


((v0_reg >> 5) + keyw[3]));
v0_new = v0_reg - (((v1_new << 4) + keyw[0]) ^ (v1_new + sum_reg) ^
((v1_new >> 5) + keyw[1]));
end
end // tea_ctr_dp

//----------------------------------------------------------------
// xtea_core_ctrl
//
// Control FSM for TEA core in CTR mode.
//----------------------------------------------------------------
always @*
begin : tea_ctr_ctrl
init_state = 1'h0;
update_v0 = 1'h0;
update_v1 = 1'h0;
update_sum = 1'h0;
ready_new = 1'h0;
ready_we = 1'h0;
core_ctrl_new = CTRL_IDLE;
core_ctrl_we = 1'h0;

case (core_ctrl_reg)
CTRL_IDLE:
begin
if (next)
begin
ready_new = 1'h0;
ready_we = 1'h1;
core_ctrl_new = CTRL_INIT;
core_ctrl_we = 1'h1;
end
end

CTRL_INIT:
begin
init_state = 1'h1;
core_ctrl_new = CTRL_ROUNDS0;
core_ctrl_we = 1'h1;
end

CTRL_ROUNDS0:
begin
update_v0 = 1'h1;

core_ctrl_new = CTRL_ROUNDS1;
core_ctrl_we = 1'b1;
end

CTRL_ROUNDS1:
begin
update_v1 = 1'h1;

ready_new = 1'h1;
ready_we = 1'h1;
core_ctrl_new = CTRL_IDLE;
core_ctrl_we = 1'b1;

// Increment counter
ctr_new = ctr_reg + 1;
ctr_we = 1'h1;
end

default:
begin
end
endcase // case (core_ctrl_reg)
end // tea_ctr_ctrl

endmodule // tea_ctr

//======================================================================
// EOF tea_ctr.v
//======================================================================

You might also like