Created
July 13, 2023 09:43
-
-
Save daniestevez/79a31ab9804a91ab43c7a48942218285 to your computer and use it in GitHub Desktop.
Verilog implementation of the Tiny Encryption Algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright (c) 2021 - Daniel Estevez <[email protected]> | |
// | |
// 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