hw/ip/hmac/rtl/sha2_pad.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // SHA-256 Padding logic
6: //
7:
8: module sha2_pad import hmac_pkg::*; (
9: input clk_i,
10: input rst_ni,
11:
12: input wipe_secret,
13: input sha_word_t wipe_v,
14:
15: // To actual FIFO
16: input fifo_rvalid,
17: input sha_fifo_t fifo_rdata,
18: output logic fifo_rready,
19:
20: // from SHA2 compress engine
21: output logic shaf_rvalid,
22: output sha_word_t shaf_rdata,
23: input shaf_rready,
24:
25: input sha_en,
26: input hash_start,
27: input hash_process,
28: input hash_done,
29:
30: input [63:0] message_length, // # of bytes in bits (8 bits granularity)
31: output logic msg_feed_complete // Indicates, all message is feeded
32: );
33:
34: //logic [8:0] length_added;
35:
36: logic [63:0] tx_count; // fin received data count.
37:
38: logic inc_txcount;
39: logic fifo_partial;
40: logic txcnt_eq_1a0;
41: logic hash_process_flag; // Set by hash_process, clear by hash_done
42:
43: assign fifo_partial = ~&fifo_rdata.mask;
44:
45: // tx_count[8:0] == 'h1c0 --> should send LenHi
46: assign txcnt_eq_1a0 = (tx_count[8:0] == 9'h1a0);
47:
48: always_ff @(posedge clk_i or negedge rst_ni) begin
49: if (!rst_ni) begin
50: hash_process_flag <= 1'b0;
51: end else if (hash_process) begin
52: hash_process_flag <= 1'b1;
53: end else if (hash_done || hash_start) begin
54: hash_process_flag <= 1'b0;
55: end
56: end
57:
58: // Data path: fout_wdata
59: typedef enum logic [2:0] {
60: FifoIn, // fin_wdata, fin_wstrb
61: Pad80, // {8'h80, 8'h00} , strb (calc based on len[4:3])
62: Pad00, // 32'h0, full strb
63: LenHi, // len[63:32], full strb
64: LenLo // len[31:0], full strb
65: } sel_data_e;
66: sel_data_e sel_data;
67:
68: always_comb begin
69: unique case (sel_data)
70: FifoIn: begin
71: shaf_rdata = fifo_rdata.data;
72: end
73:
74: Pad80: begin
75: // {a[7:0], b[7:0], c[7:0], d[7:0]}
76: // msglen[4:3] == 00 |-> {'h80, 'h00, 'h00, 'h00}
77: // msglen[4:3] == 01 |-> {msg, 'h80, 'h00, 'h00}
78: // msglen[4:3] == 10 |-> {msg[15:0], 'h80, 'h00}
79: // msglen[4:3] == 11 |-> {msg[23:0], 'h80}
80: unique case (message_length[4:3])
81: 2'b 00: shaf_rdata = 32'h 8000_0000;
82: 2'b 01: shaf_rdata = {fifo_rdata.data[31:24], 24'h 8000_00};
83: 2'b 10: shaf_rdata = {fifo_rdata.data[31:16], 16'h 8000};
84: 2'b 11: shaf_rdata = {fifo_rdata.data[31: 8], 8'h 80};
85: default: shaf_rdata = 32'h0;
86: endcase
87: end
88:
89: Pad00: begin
90: shaf_rdata = '0;
91: end
92:
93: LenHi: begin
94: shaf_rdata = message_length[63:32];
95: end
96:
97: LenLo: begin
98: shaf_rdata = message_length[31:0];
99: end
100:
101: default: begin
102: shaf_rdata = '0;
103: end
104: endcase
105: end
106:
107: // Padded length
108: // $ceil(message_length + 8 + 64, 512) -> message_length [8:0] + 440 and ignore carry
109: //assign length_added = (message_length[8:0] + 9'h1b8) ;
110:
111: // fifo control
112: // add 8'h 80 , N 8'h00, 64'h message_length
113:
114: // Steps
115: // 1. `hash_start` from CPU (or DMA?)
116: // 2. calculate `padded_length` from `message_length`
117: // 3. Check if tx_count == message_length, then go to 5
118: // 4. Receiving FIFO input (hand over to fifo output)
119: // 5. Padding bit 1 (8'h80) followed by 8'h00 if needed
120: // 6. Padding with length (high -> low)
121:
122: // State Machine
123: typedef enum logic [2:0] {
124: StIdle, // fin_full to prevent unwanted FIFO write
125: StFifoReceive, // Check tx_count == message_length
126: StPad80, // 8'h 80 + 8'h 00 X N
127: StPad00,
128: StLenHi,
129: StLenLo
130: } pad_st_e;
131:
132: pad_st_e st_q, st_d;
133:
134: always_ff @(posedge clk_i or negedge rst_ni) begin
135: if (!rst_ni) begin
136: st_q <= StIdle;
137: end else begin
138: st_q <= st_d;
139: end
140: end
141:
142: // Next state
143: always_comb begin
144: shaf_rvalid = 1'b0;
145: inc_txcount = 1'b0;
146: sel_data = FifoIn;
147: fifo_rready = 1'b0;
148:
149: st_d = StIdle;
150:
151: unique case (st_q)
152: StIdle: begin
153: sel_data = FifoIn;
154: shaf_rvalid = 1'b0;
155:
156: if (sha_en && hash_start) begin
157: inc_txcount = 1'b0;
158:
159: st_d = StFifoReceive;
160: end else begin
161: st_d = StIdle;
162: end
163: end
164:
165: StFifoReceive: begin
166: sel_data = FifoIn;
167:
168: if (fifo_partial && fifo_rvalid) begin
169: // End of the message, assume hash_process_flag is set
170: shaf_rvalid = 1'b0; // Update entry at StPad80
171: inc_txcount = 1'b0;
172: fifo_rready = 1'b0;
173:
174: st_d = StPad80;
175: end else if (!hash_process_flag) begin
176: fifo_rready = shaf_rready;
177: shaf_rvalid = fifo_rvalid;
178: inc_txcount = shaf_rready;
179:
180: st_d = StFifoReceive;
181: end else if (tx_count == message_length) begin
182: // already received all msg and was waiting process flag
183: shaf_rvalid = 1'b0;
184: inc_txcount = 1'b0;
185: fifo_rready = 1'b0;
186:
187: st_d = StPad80;
188: end else begin
189: shaf_rvalid = fifo_rvalid;
190: fifo_rready = shaf_rready; // 0 always
191: inc_txcount = shaf_rready; // 0 always
192:
193: st_d = StFifoReceive;
194: end
195: end
196:
197: StPad80: begin
198: sel_data = Pad80;
199:
200: shaf_rvalid = 1'b1;
201: fifo_rready = shaf_rready && |message_length[4:3]; // Only when partial
202:
203: // exactly 96 bits left, do not need to pad00's
204: if (shaf_rready && txcnt_eq_1a0) begin
205: st_d = StLenHi;
206: inc_txcount = 1'b1;
207: // it does not matter if value is < or > than 416 bits. If it's the former, 00 pad until
208: // length field. If >, then the next chunk will contain the length field with appropriate
209: // 0 padding.
210: end else if (shaf_rready && !txcnt_eq_1a0) begin
211: st_d = StPad00;
212: inc_txcount = 1'b1;
213: end else begin
214: st_d = StPad80;
215: inc_txcount = 1'b0;
216: end
217:
218: // # Below part is temporal code to speed up the SHA by 16 clocks per chunk
219: // # (80 clk --> 64 clk)
220: // # leaving this as a reference but needs to verify it.
221: //if (shaf_rready && !txcnt_eq_1a0) begin
222: // st_d = StPad00;
223: //
224: // inc_txcount = 1'b1;
225: // shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid;
226: // fifo_rready = (msg_word_aligned) ? 1'b0 : 1'b1;
227: //end else if (!shaf_rready && !txcnt_eq_1a0) begin
228: // st_d = StPad80;
229: //
230: // inc_txcount = 1'b0;
231: // shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid;
232: //
233: //end else if (shaf_rready && txcnt_eq_1a0) begin
234: // st_d = StLenHi;
235: // inc_txcount = 1'b1;
236: //end else begin
237: // // !shaf_rready && txcnt_eq_1a0 , just wait until fifo_rready asserted
238: // st_d = StPad80;
239: // inc_txcount = 1'b0;
240: //end
241: end
242:
243: StPad00: begin
244: sel_data = Pad00;
245: shaf_rvalid = 1'b1;
246:
247: if (shaf_rready) begin
248: inc_txcount = 1'b1;
249:
250: if (txcnt_eq_1a0) begin
251: st_d = StLenHi;
252: end else begin
253: st_d = StPad00;
254: end
255: end else begin
256: st_d = StPad00;
257: end
258: end
259:
260: StLenHi: begin
261: sel_data = LenHi;
262: shaf_rvalid = 1'b1;
263:
264: if (shaf_rready) begin
265: st_d = StLenLo;
266:
267: inc_txcount = 1'b1;
268: end else begin
269: st_d = StLenHi;
270:
271: inc_txcount = 1'b0;
272: end
273: end
274:
275: StLenLo: begin
276: sel_data = LenLo;
277: shaf_rvalid = 1'b1;
278:
279: if (shaf_rready) begin
280: st_d = StIdle;
281:
282: inc_txcount = 1'b1;
283: end else begin
284: st_d = StLenLo;
285:
286: inc_txcount = 1'b0;
287: end
288: end
289:
290: default: begin
291: st_d = StIdle;
292: end
293: endcase
294: end
295:
296: // tx_count
297: always_ff @(posedge clk_i or negedge rst_ni) begin
298: if (!rst_ni) begin
299: tx_count <= '0;
300: end else if (hash_start) begin
301: tx_count <= '0;
302: end else if (inc_txcount) begin
303: tx_count[63:5] <= tx_count[63:5] + 1'b1;
304: end
305: end
306:
307: // State machine is in Idle only when it meets tx_count == message length
308: assign msg_feed_complete = hash_process_flag && (st_q == StIdle);
309:
310: // When fifo_partial, fifo shouldn't be empty and hash_process was set
311: `ASSERT(ValidPartialConditionAssert,
312: fifo_partial && fifo_rvalid |-> hash_process_flag,
313: clk_i, !rst_ni)
314:
315: endmodule
316: