hw/ip/hmac/rtl/sha2.sv Cov: 98.9%
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 algorithm
6: //
7:
8: module sha2 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: // FIFO read signal
16: input fifo_rvalid,
17: input sha_fifo_t fifo_rdata,
18: output logic fifo_rready,
19:
20: // Control signals
21: input sha_en, // If disabled, it clears internal content.
22: input hash_start,
23: input hash_process,
24: output logic hash_done,
25:
26: input [63:0] message_length, // bits but byte based
27: output sha_word_t [7:0] digest
28: );
29:
30: logic msg_feed_complete;
31:
32: logic shaf_rready;
33: sha_word_t shaf_rdata;
34: logic shaf_rvalid;
35:
36: logic [$clog2(NumRound)-1:0] round;
37:
38: logic [3:0] w_index;
39: sha_word_t [15:0] w;
40:
41: // w, hash, digest update logic control signals
42: logic update_w_from_fifo, calculate_next_w;
43: logic init_hash, run_hash, complete_one_chunk;
44: logic update_digest, clear_digest;
45:
46: logic hash_done_next; // to meet the phase with digest value.
47:
48: sha_word_t [7:0] hash; // a,b,c,d,e,f,g,h
49:
50: // Fill up w
51: always_ff @(posedge clk_i or negedge rst_ni) begin : fill_w
52: if (!rst_ni) begin
53: w <= '0;
54: end else if (wipe_secret) begin
55: w <= w ^ {16{wipe_v}};
56: end else if (!sha_en) begin
57: w <= '0;
58: end else if (!run_hash && update_w_from_fifo) begin
59: // this logic runs at the first stage of SHA.
60: w <= {shaf_rdata, w[15:1]};
61: end else if (calculate_next_w) begin
62: w <= {calc_w(w[0], w[1], w[9], w[14]), w[15:1]};
63: //end else if (run_hash && update_w_from_fifo) begin
64: // // This code runs when round is in [48, 63]. At this time, it reads from the fifo
65: // // to fill the register if available. If FIFO goes to empty, w_index doesn't increase
66: // // and it cannot reach 15. Then the sha engine doesn't start, which introduces latency.
67: // //
68: // // But in this case, still w should be shifted to feed SHA compress engine. Then
69: // // fifo_rdata should be inserted in the middle of w index.
70: // // w[64-round + w_index] <= fifo_rdata;
71: // for (int i = 0 ; i < 16 ; i++) begin
72: // if (i == (64 - round + w_index)) begin
73: // w[i] <= shaf_rdata;
74: // end else if (i == 15) begin
75: // w[i] <= '0;
76: // end else begin
77: // w[i] <= w[i+1];
78: // end
79: // end
80: end else if (run_hash) begin
81: // Just shift-out. There's no incoming data
82: w <= {sha_word_t'(0), w[15:1]};
83: end
84: end : fill_w
85:
86: // Update engine
87: always_ff @(posedge clk_i or negedge rst_ni) begin : compress_round
88: if (!rst_ni) begin
89: hash <= '{default:'0};
90: end else if (wipe_secret) begin
91: for (int i = 0 ; i < 8 ; i++) begin
92: hash[i] <= hash[i] ^ wipe_v;
93: end
94: end else if (init_hash) begin
95: hash <= digest;
96: end else if (run_hash) begin
97: hash <= compress( w[0], CubicRootPrime[round], hash);
98: end
99: end : compress_round
100:
101: // Digest
102: always_ff @(posedge clk_i or negedge rst_ni) begin
103: if (!rst_ni) begin
104: digest <= '{default: '0};
105: end else if (wipe_secret) begin
106: for (int i = 0 ; i < 8 ; i++) begin
107: digest[i] <= digest[i] ^ wipe_v;
108: end
109: end else if (hash_start) begin
110: for (int i = 0 ; i < 8 ; i++) begin
111: digest[i] <= InitHash[i];
112: end
113: end else if (!sha_en || clear_digest) begin
114: digest <= '0;
115: end else if (update_digest) begin
116: for (int i = 0 ; i < 8 ; i++) begin
117: digest[i] <= digest[i] + hash[i];
118: end
119: end
120: end
121:
122: // round
123: always_ff @(posedge clk_i or negedge rst_ni) begin
124: if (!rst_ni) begin
125: round <= '0;
126: end else if (!sha_en) begin
127: round <= '0;
128: end else if (run_hash) begin
129: if (round == (NumRound-1)) begin
130: round <= '0;
131: end else begin
132: round <= round + 1;
133: end
134: end
135: end
136:
137: // w_index
138: always_ff @(posedge clk_i or negedge rst_ni) begin
139: if (!rst_ni) begin
140: w_index <= '0;
141: end else if (!sha_en) begin
142: w_index <= '0;
143: end else if (update_w_from_fifo) begin
144: w_index <= w_index + 1;
145: end
146: end
147:
148: assign shaf_rready = update_w_from_fifo;
149:
150: always_ff @(posedge clk_i or negedge rst_ni) begin
151: if (!rst_ni) hash_done <= 1'b0;
152: else hash_done <= hash_done_next;
153: end
154:
155: typedef enum logic [1:0] {
156: FifoIdle,
157: FifoLoadFromFifo,
158: FifoWait
159: } fifoctl_state_e;
160:
161: fifoctl_state_e fifo_st_q, fifo_st_d;
162:
163: always_ff @(posedge clk_i or negedge rst_ni) begin
164: if (!rst_ni) begin
165: fifo_st_q <= FifoIdle;
166: end else begin
167: fifo_st_q <= fifo_st_d;
168: end
169: end
170:
171: always_comb begin
172: fifo_st_d = FifoIdle;
173: update_w_from_fifo = 1'b0;
174: hash_done_next = 1'b0;
175:
176: unique case (fifo_st_q)
177: FifoIdle: begin
178: if (hash_start) begin
179: fifo_st_d = FifoLoadFromFifo;
180: end else begin
181: fifo_st_d = FifoIdle;
182: end
183: end
184:
185: FifoLoadFromFifo: begin
186: if (!sha_en) begin
187: fifo_st_d = FifoIdle;
188: update_w_from_fifo = 1'b0;
189: end else if (!shaf_rvalid) begin
190: // Wait until it is filled
191: fifo_st_d = FifoLoadFromFifo;
192: update_w_from_fifo = 1'b0;
193: end else if (w_index == 4'd 15) begin
194: fifo_st_d = FifoWait;
195: update_w_from_fifo = 1'b1;
196: end else begin
197: fifo_st_d = FifoLoadFromFifo;
198: update_w_from_fifo = 1'b1;
199: end
200: end
201:
202: FifoWait: begin
203: // Wait until next fetch begins (begin at round == 48)a
204: if (msg_feed_complete && complete_one_chunk) begin
205: fifo_st_d = FifoIdle;
206:
207: hash_done_next = 1'b1;
208: end else if (complete_one_chunk) begin
209: fifo_st_d = FifoLoadFromFifo;
210: end else begin
211: fifo_st_d = FifoWait;
212: end
213: end
214:
215: default: begin
216: fifo_st_d = FifoIdle;
217: end
218: endcase
219: end
220:
221: // SHA control
222: typedef enum logic [1:0] {
223: ShaIdle,
224: ShaCompress,
225: ShaUpdateDigest
226: } sha_st_t;
227:
228: sha_st_t sha_st_q, sha_st_d;
229:
230: always_ff @(posedge clk_i or negedge rst_ni) begin
231: if (!rst_ni) begin
232: sha_st_q <= ShaIdle;
233: end else begin
234: sha_st_q <= sha_st_d;
235: end
236: end
237:
238: assign clear_digest = hash_start;
239:
240: always_comb begin
241: update_digest = 1'b0;
242: calculate_next_w = 1'b0;
243:
244: init_hash = 1'b0;
245: run_hash = 1'b0;
246:
247: unique case (sha_st_q)
248: ShaIdle: begin
249: if (fifo_st_q == FifoWait) begin
250: init_hash = 1'b1;
251: sha_st_d = ShaCompress;
252: end else begin
253: sha_st_d = ShaIdle;
254: end
255: end
256:
257: ShaCompress: begin
258: run_hash = 1'b1;
259:
260: if (round < 48) begin
261: calculate_next_w = 1'b1;
262: end
263:
264: if (complete_one_chunk) begin
265: sha_st_d = ShaUpdateDigest;
266: end else begin
267: sha_st_d = ShaCompress;
268: end
269: end
270:
271: ShaUpdateDigest: begin
272: update_digest = 1'b1;
273: if (fifo_st_q == FifoWait) begin
274: init_hash = 1'b1;
275: sha_st_d = ShaCompress;
276: end else begin
277: sha_st_d = ShaIdle;
278: end
279: end
280:
281: default: begin
282: sha_st_d = ShaIdle;
283: end
284: endcase
285: end
286:
287: // complete_one_chunk
288: assign complete_one_chunk = (round == 6'd63);
289:
290: sha2_pad u_pad (
291: .clk_i,
292: .rst_ni,
293:
294: .wipe_secret,
295: .wipe_v,
296:
297: .fifo_rvalid,
298: .fifo_rdata,
299: .fifo_rready,
300:
301: .shaf_rvalid,
302: .shaf_rdata,
303: .shaf_rready,
304:
305: .sha_en,
306: .hash_start,
307: .hash_process,
308: .hash_done,
309:
310: .message_length,
311: .msg_feed_complete
312: );
313:
314:
315: endmodule : sha2
316: