Skip to content

Instantly share code, notes, and snippets.

@daniestevez
Created July 13, 2023 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daniestevez/79a31ab9804a91ab43c7a48942218285 to your computer and use it in GitHub Desktop.
Save daniestevez/79a31ab9804a91ab43c7a48942218285 to your computer and use it in GitHub Desktop.
Verilog implementation of the Tiny Encryption Algorithm
//
// Copyright (c) 2021 - Daniel Estevez <daniel@destevez.net>
//
// TEA
//
// Verilog implementation of the Tiny Encryption Algorithm
//
`timescale 1ns / 1ps
`default_nettype none
// A pipelined Feistel network for TEA
//
// The latency from input to output is 7 clock cycles
module tea_feistel
#(
WORD_SIZE = 16
)
(
input wire clk,
input wire [WORD_SIZE-1:0] k0,
input wire [WORD_SIZE-1:0] k1,
input wire [WORD_SIZE-1:0] v0_in,
input wire [WORD_SIZE-1:0] v1_in,
input wire [WORD_SIZE-1:0] delta,
output wire [WORD_SIZE-1:0] v0_out,
output wire [WORD_SIZE-1:0] v1_out
);
reg [WORD_SIZE/2:0] sum0_lsbs = 1'b0;
reg [WORD_SIZE/2:0] sum1_lsbs = 1'b0;
reg [WORD_SIZE/2:0] sum_delta_lsbs = 1'b0;
reg [WORD_SIZE/2-1:0] k0_msbs_q = 1'b0;
reg [WORD_SIZE/2-1:0] k1_msbs_q = 1'b0;
reg [WORD_SIZE/2-1:0] delta_msbs_q = 1'b0;
reg [WORD_SIZE/2-1:0] v1_shift4_msbs_q = 1'b0;
reg [WORD_SIZE/2-1:0] v1_shift5_msbs_q = 1'b0;
reg [WORD_SIZE-1:0] sum0 = 1'b0;
reg [WORD_SIZE-1:0] sum1 = 1'b0;
reg [WORD_SIZE-1:0] sum_delta = 1'b0;
reg [WORD_SIZE-1:0] xor_out = 1'b0;
reg [WORD_SIZE/2:0] final_sum_lsbs = 1'b0;
reg [WORD_SIZE/2-1:0] xor_out_msbs_q = 1'b0;
reg [WORD_SIZE-1:0] final_sum = 1'b0;
reg [WORD_SIZE-1:0] v0_q = 1'b0;
reg [WORD_SIZE-1:0] v0_q2 = 1'b0;
reg [WORD_SIZE-1:0] v0_q3 = 1'b0;
reg [WORD_SIZE/2-1:0] v0_q4_msbs = 1'b0;
reg [WORD_SIZE-1:0] v1_q = 1'b0;
reg [WORD_SIZE-1:0] v1_q2 = 1'b0;
reg [WORD_SIZE-1:0] v1_q3 = 1'b0;
reg [WORD_SIZE-1:0] v1_q4 = 1'b0;
reg [WORD_SIZE-1:0] v1_q5 = 1'b0;
reg [WORD_SIZE-1:0] v1_q6 = 1'b0;
reg [WORD_SIZE-1:0] final_sum_q = 1'b0;
assign v1_out = final_sum_q;
assign v0_out = v1_q6;
wire [WORD_SIZE-1:0] v1_shift4;
wire [WORD_SIZE-1:0] v1_shift5;
assign v1_shift4 = {v1_in[WORD_SIZE-5:0], 4'b0000};
assign v1_shift5 = {5'b00000, v1_in[WORD_SIZE-1:5]};
wire [WORD_SIZE/2-1:0] sum0_lsbs_carry;
wire [WORD_SIZE/2-1:0] sum1_lsbs_carry;
wire [WORD_SIZE/2-1:0] sum_delta_lsbs_carry;
wire [WORD_SIZE/2-1:0] final_sum_carry;
assign sum0_lsbs_carry = {{WORD_SIZE/2-1{1'b0}}, sum0_lsbs[WORD_SIZE/2]};
assign sum1_lsbs_carry = {{WORD_SIZE/2-1{1'b0}}, sum1_lsbs[WORD_SIZE/2]};
assign sum_delta_lsbs_carry = {{WORD_SIZE/2-1{1'b0}}, sum_delta_lsbs[WORD_SIZE/2]};
assign final_sum_carry = {{WORD_SIZE/2-1{1'b0}}, final_sum_lsbs[WORD_SIZE/2]};
always @(posedge clk) begin
sum0_lsbs <= {1'b0, k0[WORD_SIZE/2-1:0]} + {1'b0, v1_shift4[WORD_SIZE/2-1:0]};
sum1_lsbs <= {1'b0, k1[WORD_SIZE/2-1:0]} + {1'b0, v1_shift5[WORD_SIZE/2-1:0]};
sum_delta_lsbs <= {1'b0, delta[WORD_SIZE/2-1:0]} + {1'b0, v1_in[WORD_SIZE/2-1:0]};
k0_msbs_q <= k0[WORD_SIZE-1:WORD_SIZE/2];
k1_msbs_q <= k1[WORD_SIZE-1:WORD_SIZE/2];
delta_msbs_q <= delta[WORD_SIZE-1:WORD_SIZE/2];
v1_shift4_msbs_q <= v1_shift4[WORD_SIZE-1:WORD_SIZE/2];
v1_shift5_msbs_q <= v1_shift5[WORD_SIZE-1:WORD_SIZE/2];
v0_q <= v0_in;
v1_q <= v1_in;
sum0 <= {k0_msbs_q + v1_shift4_msbs_q + sum0_lsbs_carry, sum0_lsbs[WORD_SIZE/2-1:0]};
sum1 <= {k1_msbs_q + v1_shift5_msbs_q + sum1_lsbs_carry, sum1_lsbs[WORD_SIZE/2-1:0]};
sum_delta <= {delta_msbs_q + v1_q[WORD_SIZE-1:WORD_SIZE/2] + sum_delta_lsbs_carry,
sum_delta_lsbs[WORD_SIZE/2-1:0]};
v0_q2 <= v0_q;
v1_q2 <= v1_q;
xor_out <= sum0 ^ sum1 ^ sum_delta;
v0_q3 <= v0_q2;
v1_q3 <= v1_q2;
final_sum_lsbs <= {1'b0, xor_out[WORD_SIZE/2-1:0]} + {1'b0, v0_q3[WORD_SIZE/2-1:0]};
xor_out_msbs_q <= xor_out[WORD_SIZE-1:WORD_SIZE/2];
v0_q4_msbs <= v0_q3[WORD_SIZE-1:WORD_SIZE/2];
v1_q4 <= v1_q3;
final_sum <= {xor_out_msbs_q + v0_q4_msbs + final_sum_carry, final_sum_lsbs[WORD_SIZE/2-1:0]};
v1_q5 <= v1_q4;
final_sum_q <= final_sum;
v1_q6 <= v1_q5;
end // always @ (posedge clk)
endmodule // tea_feistel
module tea_round_constants
#(
CYCLES_LOG2 = 5,
WORD_SIZE = 16,
DELTA = 16'h9E37
)
(
input wire [CYCLES_LOG2:0] round,
output wire [WORD_SIZE-1:0] constant
);
localparam CYCLES = 2**CYCLES_LOG2;
reg [WORD_SIZE-1:0] sums[0:2*CYCLES-1];
integer j;
integer sum;
initial begin
sum = (DELTA << 5) & ((1 << WORD_SIZE) - 1);
for (j = 0; j < 2*CYCLES; j = j + 1) begin
sums[j] = sum;
sum = (sum + (1 << WORD_SIZE) - DELTA) & ((1 << WORD_SIZE) - 1);
end
end
assign constant = sums[round];
endmodule // tea_round_constants
module tea_decrypt_pipeline
#(
CYCLES = 32,
WORD_SIZE = 16,
DELTA = 16'h9E37
)
(
input wire clk,
input wire [4*WORD_SIZE-1:0] key,
input wire [2*WORD_SIZE-1:0] block_in,
output wire [2*WORD_SIZE-1:0] block_out
);
wire [WORD_SIZE-1:0] v0 [0:2*CYCLES];
wire [WORD_SIZE-1:0] v1 [0:2*CYCLES];
assign v0[0] = block_in[WORD_SIZE-1:0];
assign v1[0] = block_in[2*WORD_SIZE-1:WORD_SIZE];
assign block_out = {v1[2*CYCLES], v0[2*CYCLES]};
wire [WORD_SIZE-1:0] k0[0:2*CYCLES-1];
wire [WORD_SIZE-1:0] k1[0:2*CYCLES-1];
reg [WORD_SIZE-1:0] sums[0:2*CYCLES-1];
integer j;
integer sum;
initial begin
sum = (DELTA << 5) & ((1 << WORD_SIZE) - 1);
for (j = 0; j < 2*CYCLES; j = j + 1) begin
sums[j] = sum;
sum = (sum + (1 << WORD_SIZE) - DELTA) & ((1 << WORD_SIZE) - 1);
end
end
localparam FEISTEL_LATENCY = 6;
reg [4*WORD_SIZE-1:0] keys_reg[0:FEISTEL_LATENCY*(2*CYCLES-1)-1];
initial begin
for (j = 0; j < FEISTEL_LATENCY*(2*CYCLES-1); j = j + 1) begin
keys_reg[j] = 1'b0;
end
end
always @(posedge clk) begin
keys_reg[0] <= key;
for (j = 1; j < FEISTEL_LATENCY*(2*CYCLES-1); j = j + 1) begin
keys_reg[j] <= keys_reg[j-1];
end
end
wire [4*WORD_SIZE-1:0] keys[0:2*CYCLES-1];
assign keys[0] = key;
genvar i;
generate
for (i = 1; i < 2*CYCLES; i = i + 1) begin
assign keys[i] = keys_reg[FEISTEL_LATENCY*i-1];
end
endgenerate
generate
for (i = 0; i < 2*CYCLES; i = i + 1) begin
tea_feistel
#(.WORD_SIZE(WORD_SIZE))
feistel
(.clk(clk), .k0(k0[i]), .k1(k1[i]), .v0_in(v0[i]), .v1_in(v1[i]),
.delta(sums[i]), .v0_out(v0[i+1]), .v1_out(v1[i+1]));
if (i % 2 == 0) begin
assign k0[i] = keys[i][2*WORD_SIZE-1:WORD_SIZE];
assign k1[i] = keys[i][WORD_SIZE-1:0];
end
else begin
assign k0[i] = keys[i][4*WORD_SIZE-1:3*WORD_SIZE];
assign k1[i] = keys[i][3*WORD_SIZE-1:2*WORD_SIZE];
end
end
endgenerate
endmodule // tea_decrypt_pipeline
module tea_decrypt_iterative
#(
CYCLES_LOG2 = 5,
WORD_SIZE = 16,
DELTA = 16'h9E37
)
(
input wire clk,
output wire strobe_in,
input wire [4*WORD_SIZE-1:0] key,
input wire [2*WORD_SIZE-1:0] block_in,
output wire [2*WORD_SIZE-1:0] block_out
);
reg [CYCLES_LOG2:0] feistel_count = 1'b0;
wire [CYCLES_LOG2+1:0] feistel_count_sum;
wire start;
wire next_feistel;
assign feistel_count_sum = feistel_count + 1'b1;
assign strobe_in = feistel_count_sum[CYCLES_LOG2+1];
always @(posedge clk) begin
if (next_feistel) begin
feistel_count <= feistel_count_sum[CYCLES_LOG2:0];
end
end
localparam FEISTEL_LATENCY = 3;
reg [FEISTEL_LATENCY-1:0] latency = 1'b1;
assign next_feistel = latency[FEISTEL_LATENCY-1];
always @(posedge clk) begin
latency <= {latency[FEISTEL_LATENCY-2:0], latency[FEISTEL_LATENCY-1]};
end
reg [4*WORD_SIZE-1:0] keys[0:FEISTEL_LATENCY-1];
integer j;
initial begin
for (j = 0; j < FEISTEL_LATENCY; j = j + 1) begin
keys[j] = 1'b0;
end
end
always @(posedge clk) begin
keys[0] <= strobe_in ? {key[2*WORD_SIZE-1:0], key[4*WORD_SIZE-1:2*WORD_SIZE]}
: {keys[FEISTEL_LATENCY-1][2*WORD_SIZE-1:0],
keys[FEISTEL_LATENCY-1][4*WORD_SIZE-1:2*WORD_SIZE]};
for (j = 1; j < FEISTEL_LATENCY; j = j + 1) begin
keys[j] <= keys[j-1];
end
end
wire [4*WORD_SIZE-1:0] active_key;
assign active_key = strobe_in ? key : keys[FEISTEL_LATENCY-1];
wire [WORD_SIZE-1:0] v0_out;
wire [WORD_SIZE-1:0] v1_out;
assign block_out = {v1_out, v0_out};
wire [WORD_SIZE-1:0] delta;
tea_feistel #(.WORD_SIZE(WORD_SIZE)) feistel
(
.clk(clk),
.k0(active_key[2*WORD_SIZE-1:WORD_SIZE]),
.k1(active_key[WORD_SIZE-1:0]),
.v0_in(strobe_in ? block_in[WORD_SIZE-1:0] : v0_out),
.v1_in(strobe_in ? block_in[2*WORD_SIZE-1:WORD_SIZE] : v1_out),
.delta(delta),
.v0_out(v0_out),
.v1_out(v1_out)
);
tea_round_constants
#(.CYCLES_LOG2(CYCLES_LOG2), .WORD_SIZE(WORD_SIZE), .DELTA(DELTA))
constants
(.round(feistel_count), .constant(delta));
endmodule // tea_decrypt_iterative
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment