Newer
Older
dam1n19
committed
//-----------------------------------------------------------------------------
// SoC Labs Basic SHA-2 Hash Processing Module
// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
//
// Contributors
//
// David Mapstone (d.a.mapstone@soton.ac.uk)
//
// Copyright 2022, SoC Labs (www.soclabs.org)
//-----------------------------------------------------------------------------
dam1n19
committed
input logic clk,
input logic nrst,
input logic en,
// Synchronous, localised reset
input logic sync_rst,
// Data In data and Handshaking
input logic [511:0] data_in,
input logic data_in_last,
input logic data_in_valid,
output logic data_in_ready,
// Data Out data and Handshaking
dam1n19
committed
output logic data_out_last,
output logic data_out_valid,
input logic data_out_ready
);
dam1n19
committed
// Message Chunks
logic [31:0] M [15:0];
// Assign M Variables to 32 bit chunks of the input data
genvar i;
generate
for (i = 0; i < 16; i++) begin
assign M[i] = data_in[(32*((15-i)+1))-1:32*(15-i)];
end
endgenerate
// Hash Value Registers
logic [31:0] H [7:0];
logic [31:0] next_H [7:0];
// Message Schedule Registers
logic [31:0] W [63:0];
logic [31:0] next_W [63:0];
// Working Registers
logic [31:0] a,b,c,d,e,f,g,h;
logic [31:0] next_a,next_b,next_c,next_d,next_e,next_f,next_g,next_h;
logic [31:0] T1, T2;
// State Machine Registers
logic [2:0] state, next_state;
logic next_data_in_ready, next_data_out_valid, next_data_out_last;
logic [5:0] hash_iter, next_hash_iter;
logic last_block, next_last_block;
// // SHA-2 Constants
logic [31:0] K [63:0];
dam1n19
committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
assign K[0] = 32'h428a2f98;
assign K[1] = 32'h71374491;
assign K[2] = 32'hb5c0fbcf;
assign K[3] = 32'he9b5dba5;
assign K[4] = 32'h3956c25b;
assign K[5] = 32'h59f111f1;
assign K[6] = 32'h923f82a4;
assign K[7] = 32'hab1c5ed5;
assign K[8] = 32'hd807aa98;
assign K[9] = 32'h12835b01;
assign K[10] = 32'h243185be;
assign K[11] = 32'h550c7dc3;
assign K[12] = 32'h72be5d74;
assign K[13] = 32'h80deb1fe;
assign K[14] = 32'h9bdc06a7;
assign K[15] = 32'hc19bf174;
assign K[16] = 32'he49b69c1;
assign K[17] = 32'hefbe4786;
assign K[18] = 32'h0fc19dc6;
assign K[19] = 32'h240ca1cc;
assign K[20] = 32'h2de92c6f;
assign K[21] = 32'h4a7484aa;
assign K[22] = 32'h5cb0a9dc;
assign K[23] = 32'h76f988da;
assign K[24] = 32'h983e5152;
assign K[25] = 32'ha831c66d;
assign K[26] = 32'hb00327c8;
assign K[27] = 32'hbf597fc7;
assign K[28] = 32'hc6e00bf3;
assign K[29] = 32'hd5a79147;
assign K[30] = 32'h06ca6351;
assign K[31] = 32'h14292967;
assign K[32] = 32'h27b70a85;
assign K[33] = 32'h2e1b2138;
assign K[34] = 32'h4d2c6dfc;
assign K[35] = 32'h53380d13;
assign K[36] = 32'h650a7354;
assign K[37] = 32'h766a0abb;
assign K[38] = 32'h81c2c92e;
assign K[39] = 32'h92722c85;
assign K[40] = 32'ha2bfe8a1;
assign K[41] = 32'ha81a664b;
assign K[42] = 32'hc24b8b70;
assign K[43] = 32'hc76c51a3;
assign K[44] = 32'hd192e819;
assign K[45] = 32'hd6990624;
assign K[46] = 32'hf40e3585;
assign K[47] = 32'h106aa070;
assign K[48] = 32'h19a4c116;
assign K[49] = 32'h1e376c08;
assign K[50] = 32'h2748774c;
assign K[51] = 32'h34b0bcb5;
assign K[52] = 32'h391c0cb3;
assign K[53] = 32'h4ed8aa4a;
assign K[54] = 32'h5b9cca4f;
assign K[55] = 32'h682e6ff3;
assign K[56] = 32'h748f82ee;
assign K[57] = 32'h78a5636f;
assign K[58] = 32'h84c87814;
assign K[59] = 32'h8cc70208;
assign K[60] = 32'h90befffa;
assign K[61] = 32'ha4506ceb;
assign K[62] = 32'hbef9a3f7;
assign K[63] = 32'hc67178f2;
// ssig1 next_W assignments - issues using functions with arrayed objects in ivlog
logic [31:0] ssig1_next_W [63:0];
generate
for (i=0; i < 64; i++) begin
assign ssig0_next_W[i] = ((next_W[i] << 25) | (next_W[i] >> 7)) ^ ((next_W[i] << 14) | (next_W[i] >> 18)) ^ (next_W[i] >> 3);
assign ssig1_next_W[i] = ((next_W[i] << 15) | (next_W[i] >> 17)) ^ ((next_W[i] << 13) | (next_W[i] >> 19)) ^ (next_W[i] >> 10);
end
endgenerate
// State Machine Sequential Logic
always_ff @(posedge clk, negedge nrst) begin
if ((!nrst) | sync_rst) begin
state <= 3'd0;
hash_iter <= 6'd0;
last_block <= 1'b0;
data_in_ready <= 1'b0;
data_out_valid <= 1'b0;
data_out_last <= 1'b0;
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// Reset Working Registers
a <= 32'd0;
b <= 32'd0;
c <= 32'd0;
d <= 32'd0;
e <= 32'd0;
f <= 32'd0;
g <= 32'd0;
h <= 32'd0;
// Reset H Registers
for (int i=0; i < 8; i++) begin
H[i] <= 32'd0;
end
// Reset W Registers
for (int i=0; i < 64; i++) begin
W[i] <= 32'd0;
end
end else begin
state <= next_state;
hash_iter <= next_hash_iter;
last_block <= next_last_block;
data_in_ready <= next_data_in_ready;
data_out_valid <= next_data_out_valid;
data_out_last <= next_data_out_last;
data_out <= next_data_out;
// Set Working Registers
a <= next_a;
b <= next_b;
c <= next_c;
d <= next_d;
e <= next_e;
f <= next_f;
g <= next_g;
h <= next_h;
// Set H Registers
for (int i=0; i < 8; i++) begin
H[i] <= next_H[i];
end
// Set W Registers
for (int i=0; i < 64; i++) begin
W[i] <= next_W[i];
end
end
end
// State Machine Combinatorial Logic
always_comb begin
// Default
next_state = state;
next_hash_iter = hash_iter;
next_last_block = last_block;
next_data_in_ready = data_in_ready;
next_data_out_valid = data_out_valid;
next_data_out_last = data_out_last;
next_data_out = data_out;
// Set next Working Registers
next_a = a;
next_b = b;
next_c = c;
next_d = d;
next_e = e;
next_f = f;
next_g = g;
next_h = h;
// Set next H Registers
for (int i=0; i < 8; i++) begin
next_H[i] = H[i];
end
// Set next W Registers
for (int i=0; i < 64; i++) begin
next_W[i] = W[i];
end
// Logic for Temporary Words
T1 = h + bsig1(e) + ch(e,f,g) + K[hash_iter] + W[hash_iter];
T2 = bsig0(a) + maj(a,b,c);
if (!(data_out_valid && !data_out_ready)) begin
// If data out handshake has been seen, drop valid
next_data_out_valid = 1'b0;
end
// Initialise Hash Value Registers
next_H[0] = 32'h6a09e667;
next_H[1] = 32'hbb67ae85;
next_H[2] = 32'h3c6ef372;
next_H[3] = 32'ha54ff53a;
next_H[4] = 32'h510e527f;
next_H[5] = 32'h9b05688c;
next_H[6] = 32'h1f83d9ab;
next_H[7] = 32'h5be0cd19;
next_data_in_ready = 1'b1;
next_state = 3'd1;
end
3'd1: begin // Perform Hash Initialisation
if (!(data_out_valid && !data_out_ready)) begin
// If data out handshake has been seen, drop valid
next_data_out_valid = 1'b0;
end
if (data_in_valid && data_in_ready) begin
// Valid Handshake and data can be processed
// Use the Message chunks to populate the message schedule
for (logic [31:0] t = 0; t < 64; t++) begin
if (t < 16) begin
next_W[t] = M[t];
end else begin
next_W[t] = ssig1_next_W[t-2] + next_W[t-32'd7] + ssig0_next_W[t-15] + next_W[t-32'd16];
end
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
end
// Set Working Variables
next_a = H[0];
next_b = H[1];
next_c = H[2];
next_d = H[3];
next_e = H[4];
next_f = H[5];
next_g = H[6];
next_h = H[7];
// Move to next state
next_state = 3'd2;
next_hash_iter = 6'd0;
next_last_block = data_in_last;
// Drop Ready Signal to confirm handshake
next_data_in_ready = 1'b0;
end
end
3'd2: begin // Perform the main hash computation
if (!(data_out_valid && !data_out_ready)) begin
// If data out handshake has been seen, drop valid
next_data_out_valid = 1'b0;
end
// Perform Hash Function
next_a = T1 + T2;
next_b = a;
next_c = b;
next_d = c;
next_e = d + T1;
next_f = e;
next_g = f;
next_h = g;
// Decrement Iteration Register
next_hash_iter = hash_iter + 6'd1;
if (hash_iter == 63) begin
next_state = 3'd3;
end
end
3'd3: begin // Compute intermediate hash value
if (!(data_out_valid && !data_out_ready)) begin
// If data out handshake has been seen, drop valid
next_data_out_valid = 1'b0;
end
if (last_block) begin
if (!data_out_valid) begin // No Data waiting at output
// Output updated H values
next_data_out = {a + H[0], b + H[1], c + H[2], d + H[3], e + H[4], f + H[5], g + H[6], h + H[7]};
next_data_out_last = 1'b1;
next_data_out_valid = 1'b1;
// Next State Logic
next_state = 3'd1;
next_data_in_ready = 1'b1;
// Initialise Hash Value Registers
next_H[0] = 32'h6a09e667;
next_H[1] = 32'hbb67ae85;
next_H[2] = 32'h3c6ef372;
next_H[3] = 32'ha54ff53a;
next_H[4] = 32'h510e527f;
next_H[5] = 32'h9b05688c;
next_H[6] = 32'h1f83d9ab;
next_H[7] = 32'h5be0cd19;
end
end else begin
// Update H values for next message block
next_H[0] = a + H[0];
next_H[1] = b + H[1];
next_H[2] = c + H[2];
next_H[3] = d + H[3];
next_H[4] = e + H[4];
next_H[5] = f + H[5];
next_H[6] = g + H[6];
next_H[7] = h + H[7];
// Next State Logic
next_data_in_ready = 1'b1;
next_state = 3'd1;
end
end