1 |
2 |
schengopen |
////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//// ////
|
3 |
|
|
//// This file is part of the AES SystemVerilog Behavioral ////
|
4 |
|
|
//// Model project ////
|
5 |
|
|
//// http://www.opencores.org/cores/aes_beh_model/ ////
|
6 |
|
|
//// ////
|
7 |
|
|
//// Description ////
|
8 |
|
|
//// Implementation of AES SystemVerilog Behavioral ////
|
9 |
|
|
//// Model according to AES Behavioral Model specification document.////
|
10 |
|
|
//// ////
|
11 |
|
|
//// To Do: ////
|
12 |
|
|
//// - ////
|
13 |
|
|
//// ////
|
14 |
|
|
//// Author(s): ////
|
15 |
|
|
//// - scheng, schengopencores@opencores.org ////
|
16 |
|
|
//// ////
|
17 |
|
|
////////////////////////////////////////////////////////////////////////
|
18 |
|
|
//// ////
|
19 |
|
|
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
|
20 |
|
|
//// ////
|
21 |
|
|
//// This source file may be used and distributed without ////
|
22 |
|
|
//// restriction provided that this copyright statement is not ////
|
23 |
|
|
//// removed from the file and that any derivative work contains ////
|
24 |
|
|
//// the original copyright notice and the associated disclaimer. ////
|
25 |
|
|
//// ////
|
26 |
|
|
//// This source file is free software; you can redistribute it ////
|
27 |
|
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
28 |
|
|
//// Public License as published by the Free Software Foundation; ////
|
29 |
|
|
//// either version 2.1 of the License, or (at your option) any ////
|
30 |
|
|
//// later version. ////
|
31 |
|
|
//// ////
|
32 |
|
|
//// This source is distributed in the hope that it will be ////
|
33 |
|
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
34 |
|
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
35 |
|
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
36 |
|
|
//// details. ////
|
37 |
|
|
//// ////
|
38 |
|
|
//// You should have received a copy of the GNU Lesser General ////
|
39 |
|
|
//// Public License along with this source; if not, download it ////
|
40 |
|
|
//// from http://www.opencores.org/lgpl.shtml ////
|
41 |
|
|
//// ////
|
42 |
|
|
////////////////////////////////////////////////////////////////////////
|
43 |
|
|
|
44 |
3 |
schengopen |
// This is a SystemVerilog implementation of the AES encryption/decryption
|
45 |
|
|
// algorithm described in FIPS-197. The model is implemented as a SystemVerilog
|
46 |
|
|
// class which can be instantiated in a testbench to generate known good
|
47 |
|
|
// results for verification of AES IPs.
|
48 |
2 |
schengopen |
//
|
49 |
3 |
schengopen |
// You are encouraged to use the typdefs at the end of this file instead of the
|
50 |
|
|
// class below while declaring variables for the aes model in your testbench.
|
51 |
2 |
schengopen |
//
|
52 |
|
|
// Refer to the specification document on how to use the model in your
|
53 |
|
|
// testbench.
|
54 |
|
|
|
55 |
3 |
schengopen |
typedef enum {encrypt, decrypt} aes_func;
|
56 |
|
|
|
57 |
|
|
class aes_beh_model #(int Nk=4, int Nr=10, aes_func func=decrypt);
|
58 |
2 |
schengopen |
// Refer to section 5 fig.4 of FIPS-197 spec for definitions of Nk and Nr
|
59 |
|
|
//
|
60 |
|
|
// Key length Nk Nr
|
61 |
|
|
// 128 4 10
|
62 |
|
|
// 192 6 12
|
63 |
|
|
// 256 8 14
|
64 |
|
|
|
65 |
|
|
byte unsigned state[0:3][0:3];
|
66 |
|
|
byte unsigned keysch[0:4*(Nr+1)-1][0:3];
|
67 |
|
|
protected int unsigned curr_round;
|
68 |
|
|
bit done; // done=1 -> decryption done, valid plaintext available for read.
|
69 |
|
|
bit loaded; // Ciphertext loaded, ready to start decryption.
|
70 |
|
|
|
71 |
|
|
function new(); // Constructor
|
72 |
|
|
done = 0;
|
73 |
|
|
loaded = 0;
|
74 |
|
|
endfunction
|
75 |
|
|
|
76 |
|
|
function int unsigned GetCurrRound;
|
77 |
|
|
// Returns which round we are at in the decryption process. For AES decryption
|
78 |
|
|
// round counts down from Nr to 0.
|
79 |
|
|
GetCurrRound = curr_round;
|
80 |
|
|
endfunction
|
81 |
|
|
|
82 |
|
|
task LoadCt(bit [0:127] ct);
|
83 |
|
|
// Populate state array with ciphertext and set loaded flag
|
84 |
3 |
schengopen |
if (func == decrypt)
|
85 |
|
|
begin
|
86 |
|
|
for (int j=0; j<=3; j++)
|
87 |
|
|
for (int k=0; k<=3; k++) state[k][j] = ct[(32*j+8*k)+:8];
|
88 |
|
|
loaded = 1;
|
89 |
|
|
done = 0;
|
90 |
|
|
curr_round = Nr; // Inverse cipher round counts down from Nr
|
91 |
|
|
end
|
92 |
|
|
else
|
93 |
|
|
$display("#Info : aes_beh_model::LoadCt() cannot load ciphertext to encryptor.");
|
94 |
2 |
schengopen |
endtask
|
95 |
|
|
|
96 |
3 |
schengopen |
task LoadPt(bit [0:127] pt);
|
97 |
|
|
// Populate state array with plaintext and set loaded flag
|
98 |
|
|
if (func == encrypt)
|
99 |
|
|
begin
|
100 |
|
|
for (int j=0; j<=3; j++)
|
101 |
|
|
for (int k=0; k<=3; k++) state[k][j] = pt[(32*j+8*k)+:8];
|
102 |
|
|
loaded = 1;
|
103 |
|
|
done = 0;
|
104 |
|
|
curr_round = 0; // Cipher round counts up from 0
|
105 |
|
|
end
|
106 |
|
|
else
|
107 |
|
|
$display("#Info : aes_beh_model::LoadPt() cannot load plaintext to decryptor.");
|
108 |
|
|
endtask
|
109 |
|
|
|
110 |
2 |
schengopen |
function bit [0:127] GetState;
|
111 |
|
|
// Returns current state as a 128-bit vector.
|
112 |
|
|
// Once all rounds are completed, state contains the decrypted plaintext.
|
113 |
|
|
for (int j=0; j<=3; j++)
|
114 |
|
|
for (int k=0; k<=3; k++) GetState[(32*j+8*k)+:8] = state[k][j];
|
115 |
|
|
endfunction
|
116 |
|
|
|
117 |
|
|
function bit [0:127] GetCurrKsch;
|
118 |
|
|
// Get key schedule of the current round.
|
119 |
|
|
// Note that for decryption, round counts down from Nr.
|
120 |
|
|
for (int j=0; j<=3; j++)
|
121 |
|
|
for (int k=0; k<=3; k++) GetCurrKsch[(32*j+8*k)+:8] = keysch[curr_round*4+j][k];
|
122 |
|
|
endfunction
|
123 |
|
|
|
124 |
|
|
function bit [0:127] LookupKsch(int unsigned r);
|
125 |
|
|
// Lookup key schedule for any round.
|
126 |
|
|
for (int j=0; j<=3; j++)
|
127 |
|
|
for (int k=0; k<=3; k++) LookupKsch[(32*j+8*k)+:8] = keysch[r*4+j][k];
|
128 |
|
|
endfunction
|
129 |
|
|
|
130 |
|
|
task KeyExpand(bit [0:4*8*Nk-1] key);
|
131 |
|
|
// Load key to model and compute key_schedule
|
132 |
|
|
|
133 |
|
|
int j=0;
|
134 |
|
|
byte unsigned temp[0:3];
|
135 |
|
|
byte unsigned Rcon[1:11] = {8'h01,8'h02,8'h04,8'h08,8'h10,8'h20,8'h40,8'h80,8'h1b,8'h36,8'h6c};
|
136 |
|
|
byte unsigned kt[0:4*Nk-1]; // Array holding the key
|
137 |
|
|
|
138 |
|
|
// Populate kt array
|
139 |
|
|
for (int i=0; i<=4*Nk-1; i++) kt[i] = key[i*8+:8];
|
140 |
|
|
|
141 |
|
|
while (j < Nk)
|
142 |
|
|
begin
|
143 |
|
|
keysch[j][0] = kt[4*j];
|
144 |
|
|
keysch[j][1] = kt[4*j+1];
|
145 |
|
|
keysch[j][2] = kt[4*j+2];
|
146 |
|
|
keysch[j][3] = kt[4*j+3];
|
147 |
|
|
j++;
|
148 |
|
|
end
|
149 |
|
|
|
150 |
|
|
// Now j = Nk
|
151 |
|
|
while (j < 4*(Nr+1))
|
152 |
|
|
begin
|
153 |
|
|
temp[0] = keysch[j-1][0];
|
154 |
|
|
temp[1] = keysch[j-1][1];
|
155 |
|
|
temp[2] = keysch[j-1][2];
|
156 |
|
|
temp[3] = keysch[j-1][3];
|
157 |
|
|
|
158 |
|
|
if ((j % Nk) == 0) // When j is a multiple of key length
|
159 |
|
|
begin
|
160 |
|
|
RotWord(temp);
|
161 |
|
|
SubWord(temp);
|
162 |
|
|
temp[0] ^= Rcon[j/Nk];
|
163 |
|
|
end
|
164 |
|
|
else if ((Nk > 6) && ((j % Nk) == 4)) // Only Nk=8 (AES256) will hit this case
|
165 |
|
|
SubWord(temp);
|
166 |
|
|
|
167 |
|
|
keysch[j][0] = keysch[j-Nk][0] ^ temp[0];
|
168 |
|
|
keysch[j][1] = keysch[j-Nk][1] ^ temp[1];
|
169 |
|
|
keysch[j][2] = keysch[j-Nk][2] ^ temp[2];
|
170 |
|
|
keysch[j][3] = keysch[j-Nk][3] ^ temp[3];
|
171 |
|
|
|
172 |
|
|
j++;
|
173 |
|
|
end
|
174 |
|
|
|
175 |
|
|
endtask
|
176 |
|
|
|
177 |
|
|
protected task RotWord(inout byte unsigned x[0:3]);
|
178 |
|
|
byte unsigned tmp;
|
179 |
|
|
|
180 |
|
|
tmp = x[0];
|
181 |
|
|
x[0] = x[1];
|
182 |
|
|
x[1] = x[2];
|
183 |
|
|
x[2] = x[3];
|
184 |
|
|
x[3] = tmp;
|
185 |
|
|
endtask
|
186 |
|
|
|
187 |
|
|
protected function byte unsigned inv_sbox_transform(byte unsigned x);
|
188 |
|
|
// Inverse Sbox transform matrix
|
189 |
|
|
const byte unsigned inv_sbox[0:255] = {
|
190 |
|
|
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
191 |
|
|
// ===============================================================================================
|
192 |
|
|
/*0*/ 8'h52,8'h09,8'h6a,8'hd5,8'h30,8'h36,8'ha5,8'h38,8'hbf,8'h40,8'ha3,8'h9e,8'h81,8'hf3,8'hd7,8'hfb,
|
193 |
|
|
/*1*/ 8'h7c,8'he3,8'h39,8'h82,8'h9b,8'h2f,8'hff,8'h87,8'h34,8'h8e,8'h43,8'h44,8'hc4,8'hde,8'he9,8'hcb,
|
194 |
|
|
/*2*/ 8'h54,8'h7b,8'h94,8'h32,8'ha6,8'hc2,8'h23,8'h3d,8'hee,8'h4c,8'h95,8'h0b,8'h42,8'hfa,8'hc3,8'h4e,
|
195 |
|
|
/*3*/ 8'h08,8'h2e,8'ha1,8'h66,8'h28,8'hd9,8'h24,8'hb2,8'h76,8'h5b,8'ha2,8'h49,8'h6d,8'h8b,8'hd1,8'h25,
|
196 |
|
|
/*4*/ 8'h72,8'hf8,8'hf6,8'h64,8'h86,8'h68,8'h98,8'h16,8'hd4,8'ha4,8'h5c,8'hcc,8'h5d,8'h65,8'hb6,8'h92,
|
197 |
|
|
/*5*/ 8'h6c,8'h70,8'h48,8'h50,8'hfd,8'hed,8'hb9,8'hda,8'h5e,8'h15,8'h46,8'h57,8'ha7,8'h8d,8'h9d,8'h84,
|
198 |
|
|
/*6*/ 8'h90,8'hd8,8'hab,8'h00,8'h8c,8'hbc,8'hd3,8'h0a,8'hf7,8'he4,8'h58,8'h05,8'hb8,8'hb3,8'h45,8'h06,
|
199 |
|
|
/*7*/ 8'hd0,8'h2c,8'h1e,8'h8f,8'hca,8'h3f,8'h0f,8'h02,8'hc1,8'haf,8'hbd,8'h03,8'h01,8'h13,8'h8a,8'h6b,
|
200 |
|
|
/*8*/ 8'h3a,8'h91,8'h11,8'h41,8'h4f,8'h67,8'hdc,8'hea,8'h97,8'hf2,8'hcf,8'hce,8'hf0,8'hb4,8'he6,8'h73,
|
201 |
|
|
/*9*/ 8'h96,8'hac,8'h74,8'h22,8'he7,8'had,8'h35,8'h85,8'he2,8'hf9,8'h37,8'he8,8'h1c,8'h75,8'hdf,8'h6e,
|
202 |
|
|
/*a*/ 8'h47,8'hf1,8'h1a,8'h71,8'h1d,8'h29,8'hc5,8'h89,8'h6f,8'hb7,8'h62,8'h0e,8'haa,8'h18,8'hbe,8'h1b,
|
203 |
|
|
/*b*/ 8'hfc,8'h56,8'h3e,8'h4b,8'hc6,8'hd2,8'h79,8'h20,8'h9a,8'hdb,8'hc0,8'hfe,8'h78,8'hcd,8'h5a,8'hf4,
|
204 |
|
|
/*c*/ 8'h1f,8'hdd,8'ha8,8'h33,8'h88,8'h07,8'hc7,8'h31,8'hb1,8'h12,8'h10,8'h59,8'h27,8'h80,8'hec,8'h5f,
|
205 |
|
|
/*d*/ 8'h60,8'h51,8'h7f,8'ha9,8'h19,8'hb5,8'h4a,8'h0d,8'h2d,8'he5,8'h7a,8'h9f,8'h93,8'hc9,8'h9c,8'hef,
|
206 |
|
|
/*e*/ 8'ha0,8'he0,8'h3b,8'h4d,8'hae,8'h2a,8'hf5,8'hb0,8'hc8,8'heb,8'hbb,8'h3c,8'h83,8'h53,8'h99,8'h61,
|
207 |
|
|
/*f*/ 8'h17,8'h2b,8'h04,8'h7e,8'hba,8'h77,8'hd6,8'h26,8'he1,8'h69,8'h14,8'h63,8'h55,8'h21,8'h0c,8'h7d
|
208 |
|
|
};
|
209 |
|
|
inv_sbox_transform = inv_sbox[x];
|
210 |
|
|
endfunction
|
211 |
|
|
|
212 |
|
|
protected function byte unsigned sbox_transform(byte unsigned x);
|
213 |
|
|
// Sbox transform matrix
|
214 |
|
|
const byte unsigned sbox[0:255] = {
|
215 |
|
|
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
216 |
|
|
// ===============================================================================================
|
217 |
|
|
/*0*/ 8'h63,8'h7c,8'h77,8'h7b,8'hf2,8'h6b,8'h6f,8'hc5,8'h30,8'h01,8'h67,8'h2b,8'hfe,8'hd7,8'hab,8'h76,
|
218 |
|
|
/*1*/ 8'hca,8'h82,8'hc9,8'h7d,8'hfa,8'h59,8'h47,8'hf0,8'had,8'hd4,8'ha2,8'haf,8'h9c,8'ha4,8'h72,8'hc0,
|
219 |
|
|
/*2*/ 8'hb7,8'hfd,8'h93,8'h26,8'h36,8'h3f,8'hf7,8'hcc,8'h34,8'ha5,8'he5,8'hf1,8'h71,8'hd8,8'h31,8'h15,
|
220 |
|
|
/*3*/ 8'h04,8'hc7,8'h23,8'hc3,8'h18,8'h96,8'h05,8'h9a,8'h07,8'h12,8'h80,8'he2,8'heb,8'h27,8'hb2,8'h75,
|
221 |
|
|
/*4*/ 8'h09,8'h83,8'h2c,8'h1a,8'h1b,8'h6e,8'h5a,8'ha0,8'h52,8'h3b,8'hd6,8'hb3,8'h29,8'he3,8'h2f,8'h84,
|
222 |
|
|
/*5*/ 8'h53,8'hd1,8'h00,8'hed,8'h20,8'hfc,8'hb1,8'h5b,8'h6a,8'hcb,8'hbe,8'h39,8'h4a,8'h4c,8'h58,8'hcf,
|
223 |
|
|
/*6*/ 8'hd0,8'hef,8'haa,8'hfb,8'h43,8'h4d,8'h33,8'h85,8'h45,8'hf9,8'h02,8'h7f,8'h50,8'h3c,8'h9f,8'ha8,
|
224 |
|
|
/*7*/ 8'h51,8'ha3,8'h40,8'h8f,8'h92,8'h9d,8'h38,8'hf5,8'hbc,8'hb6,8'hda,8'h21,8'h10,8'hff,8'hf3,8'hd2,
|
225 |
|
|
/*8*/ 8'hcd,8'h0c,8'h13,8'hec,8'h5f,8'h97,8'h44,8'h17,8'hc4,8'ha7,8'h7e,8'h3d,8'h64,8'h5d,8'h19,8'h73,
|
226 |
|
|
/*9*/ 8'h60,8'h81,8'h4f,8'hdc,8'h22,8'h2a,8'h90,8'h88,8'h46,8'hee,8'hb8,8'h14,8'hde,8'h5e,8'h0b,8'hdb,
|
227 |
|
|
/*a*/ 8'he0,8'h32,8'h3a,8'h0a,8'h49,8'h06,8'h24,8'h5c,8'hc2,8'hd3,8'hac,8'h62,8'h91,8'h95,8'he4,8'h79,
|
228 |
|
|
/*b*/ 8'he7,8'hc8,8'h37,8'h6d,8'h8d,8'hd5,8'h4e,8'ha9,8'h6c,8'h56,8'hf4,8'hea,8'h65,8'h7a,8'hae,8'h08,
|
229 |
|
|
/*c*/ 8'hba,8'h78,8'h25,8'h2e,8'h1c,8'ha6,8'hb4,8'hc6,8'he8,8'hdd,8'h74,8'h1f,8'h4b,8'hbd,8'h8b,8'h8a,
|
230 |
|
|
/*d*/ 8'h70,8'h3e,8'hb5,8'h66,8'h48,8'h03,8'hf6,8'h0e,8'h61,8'h35,8'h57,8'hb9,8'h86,8'hc1,8'h1d,8'h9e,
|
231 |
|
|
/*e*/ 8'he1,8'hf8,8'h98,8'h11,8'h69,8'hd9,8'h8e,8'h94,8'h9b,8'h1e,8'h87,8'he9,8'hce,8'h55,8'h28,8'hdf,
|
232 |
|
|
/*f*/ 8'h8c,8'ha1,8'h89,8'h0d,8'hbf,8'he6,8'h42,8'h68,8'h41,8'h99,8'h2d,8'h0f,8'hb0,8'h54,8'hbb,8'h16
|
233 |
|
|
};
|
234 |
|
|
sbox_transform = sbox[x];
|
235 |
|
|
endfunction
|
236 |
|
|
|
237 |
|
|
protected task SubBytes;
|
238 |
|
|
for (int j=0; j<=3; j++)
|
239 |
|
|
for (int k=0; k<=3; k++) state[j][k] = sbox_transform(state[j][k]);
|
240 |
|
|
endtask
|
241 |
|
|
|
242 |
|
|
protected task InvSubBytes;
|
243 |
|
|
for (int j=0; j<=3; j++)
|
244 |
|
|
for (int k=0; k<=3; k++) state[j][k] = inv_sbox_transform(state[j][k]);
|
245 |
|
|
endtask
|
246 |
|
|
|
247 |
|
|
protected task SubWord(inout byte unsigned x[0:3]);
|
248 |
|
|
x[0] = sbox_transform(x[0]);
|
249 |
|
|
x[1] = sbox_transform(x[1]);
|
250 |
|
|
x[2] = sbox_transform(x[2]);
|
251 |
|
|
x[3] = sbox_transform(x[3]);
|
252 |
|
|
endtask
|
253 |
|
|
|
254 |
|
|
protected task InvShiftRows;
|
255 |
|
|
byte unsigned tmp_state[1:3][0:3]; // Row 0 of state is not shifted
|
256 |
|
|
|
257 |
|
|
for (int j=1; j<=3; j++)
|
258 |
|
|
for (int k=0; k<=3; k++) tmp_state[j][k] = state[j][(k+4-j)%4];
|
259 |
|
|
|
260 |
|
|
for (int j=1; j<=3; j++)
|
261 |
|
|
for (int k=0; k<=3; k++) state[j][k] = tmp_state[j][k];
|
262 |
|
|
endtask
|
263 |
|
|
|
264 |
3 |
schengopen |
protected task ShiftRows;
|
265 |
|
|
byte unsigned tmp_state[1:3][0:3]; // Row 0 of state is not shifted
|
266 |
|
|
|
267 |
|
|
for (int j=1; j<=3; j++)
|
268 |
|
|
for (int k=0; k<=3; k++) tmp_state[j][k] = state[j][(k+j)%4];
|
269 |
|
|
|
270 |
|
|
for (int j=1; j<=3; j++)
|
271 |
|
|
for (int k=0; k<=3; k++) state[j][k] = tmp_state[j][k];
|
272 |
|
|
endtask
|
273 |
|
|
|
274 |
2 |
schengopen |
protected function byte unsigned xtime(byte unsigned x);
|
275 |
|
|
// Multiplication by 2 over GF(256)
|
276 |
|
|
// Refer to FIPS-197 spec section 4.2.1 on definition of GF(256) multiplication
|
277 |
|
|
xtime = (x[7])? (x<<1) ^ 8'h1b : x<<1;
|
278 |
|
|
endfunction
|
279 |
|
|
|
280 |
3 |
schengopen |
protected function byte unsigned GFmul2(byte unsigned x);
|
281 |
|
|
// Same as xtime(). For improved readibility only.
|
282 |
|
|
GFmul2 = xtime(x);
|
283 |
|
|
endfunction
|
284 |
|
|
|
285 |
|
|
protected function byte unsigned GFmul3(byte unsigned x);
|
286 |
|
|
// Multiply by 3 over GF(256)
|
287 |
|
|
// 3*x = 2*x + x
|
288 |
|
|
// Addition over GF(256) is xor
|
289 |
|
|
GFmul3 = xtime(x) ^ x;
|
290 |
|
|
endfunction
|
291 |
|
|
|
292 |
2 |
schengopen |
protected function byte unsigned GFmul4(byte unsigned x);
|
293 |
|
|
// Multiply by 4 over GF(256)
|
294 |
|
|
// 4*x = 2*(2*x)
|
295 |
|
|
GFmul4 = xtime(xtime(x));
|
296 |
|
|
endfunction
|
297 |
|
|
|
298 |
|
|
protected function byte unsigned GFmul8(byte unsigned x);
|
299 |
|
|
// Multiply by 8 over GF(256)
|
300 |
|
|
// 8*x = 2*(4*x)
|
301 |
|
|
GFmul8 = xtime(GFmul4(x));
|
302 |
|
|
endfunction
|
303 |
|
|
|
304 |
|
|
protected function byte unsigned GFmul9(byte unsigned x);
|
305 |
|
|
// Multiply by 9 over GF(256)
|
306 |
|
|
// 9*x = 8*x + x
|
307 |
|
|
// Addition over GF(256) is xor
|
308 |
|
|
GFmul9 = GFmul8(x) ^ x;
|
309 |
|
|
endfunction
|
310 |
|
|
|
311 |
|
|
protected function byte unsigned GFmulb(byte unsigned x);
|
312 |
|
|
// Multiply by 0xb over GF(256)
|
313 |
|
|
// b*x = 8*x + 2*x +x
|
314 |
|
|
GFmulb = GFmul8(x) ^ xtime(x) ^ x;
|
315 |
|
|
endfunction
|
316 |
|
|
|
317 |
|
|
protected function byte unsigned GFmuld(byte unsigned x);
|
318 |
|
|
// Multiply by 0xd over GF(256)
|
319 |
|
|
// d*x = 8*x + 4*x + x
|
320 |
|
|
GFmuld = GFmul8(x) ^ GFmul4(x) ^ x;
|
321 |
|
|
endfunction
|
322 |
|
|
|
323 |
|
|
protected function byte unsigned GFmule(byte unsigned x);
|
324 |
|
|
// Multiply by 0xe over GF(256)
|
325 |
|
|
// e*x = 8*x + 4*x +2*x
|
326 |
|
|
GFmule = GFmul8(x) ^ GFmul4(x) ^ xtime(x);
|
327 |
|
|
endfunction
|
328 |
|
|
|
329 |
3 |
schengopen |
protected task MixColumns;
|
330 |
|
|
byte unsigned tmp_col[0:3];
|
331 |
|
|
|
332 |
|
|
for (int j=0; j<=3; j++)
|
333 |
|
|
begin
|
334 |
|
|
tmp_col[0] = GFmul2(state[0][j]) ^ GFmul3(state[1][j]) ^ state[2][j] ^ state[3][j];
|
335 |
|
|
tmp_col[1] = state[0][j] ^ GFmul2(state[1][j]) ^ GFmul3(state[2][j]) ^ state[3][j];
|
336 |
|
|
tmp_col[2] = state[0][j] ^ state[1][j] ^ GFmul2(state[2][j]) ^ GFmul3(state[3][j]);
|
337 |
|
|
tmp_col[3] = GFmul3(state[0][j]) ^ state[1][j] ^ state[2][j] ^ GFmul2(state[3][j]);
|
338 |
|
|
|
339 |
|
|
state[0][j] = tmp_col[0];
|
340 |
|
|
state[1][j] = tmp_col[1];
|
341 |
|
|
state[2][j] = tmp_col[2];
|
342 |
|
|
state[3][j] = tmp_col[3];
|
343 |
|
|
end
|
344 |
|
|
endtask
|
345 |
|
|
|
346 |
2 |
schengopen |
protected task InvMixColumns;
|
347 |
|
|
byte unsigned tmp_col[0:3];
|
348 |
|
|
|
349 |
|
|
for (int j=0; j<=3; j++)
|
350 |
|
|
begin
|
351 |
|
|
tmp_col[0] = GFmule(state[0][j]) ^ GFmulb(state[1][j]) ^ GFmuld(state[2][j]) ^ GFmul9(state[3][j]);
|
352 |
|
|
tmp_col[1] = GFmul9(state[0][j]) ^ GFmule(state[1][j]) ^ GFmulb(state[2][j]) ^ GFmuld(state[3][j]);
|
353 |
|
|
tmp_col[2] = GFmuld(state[0][j]) ^ GFmul9(state[1][j]) ^ GFmule(state[2][j]) ^ GFmulb(state[3][j]);
|
354 |
|
|
tmp_col[3] = GFmulb(state[0][j]) ^ GFmuld(state[1][j]) ^ GFmul9(state[2][j]) ^ GFmule(state[3][j]);
|
355 |
|
|
|
356 |
|
|
state[0][j] = tmp_col[0];
|
357 |
|
|
state[1][j] = tmp_col[1];
|
358 |
|
|
state[2][j] = tmp_col[2];
|
359 |
|
|
state[3][j] = tmp_col[3];
|
360 |
|
|
end
|
361 |
|
|
endtask
|
362 |
3 |
schengopen |
|
363 |
2 |
schengopen |
protected task AddRoundKey;
|
364 |
|
|
for (int j=0; j<=3; j++)
|
365 |
|
|
for (int k=0; k<=3; k++) state[k][j] ^= keysch[curr_round*4+j][k];
|
366 |
|
|
endtask
|
367 |
|
|
|
368 |
|
|
task run(int mode);
|
369 |
3 |
schengopen |
// Run cipher / inverse cipher rounds as defined in section 5.1 / 5.3 of FIPS-197 spec.
|
370 |
|
|
// Model functions as cipher / inverse cipher depending on the value of the parameter func.
|
371 |
|
|
//
|
372 |
|
|
// Two run modes are supported
|
373 |
2 |
schengopen |
// mode=0 -> Run from current round to completion
|
374 |
|
|
// mode=1 -> Run 1 round only
|
375 |
3 |
schengopen |
//
|
376 |
|
|
// For encryption both the LoadPt() and KeyExpand() must be called first before calling run().
|
377 |
|
|
// For dncryption both the LoadPt() and KeyExpand() must be called first before calling run().
|
378 |
|
|
// This is to ensure the cipher / inverse cipher doesn't work on garbage.
|
379 |
2 |
schengopen |
|
380 |
3 |
schengopen |
// Only continue if model is loaded and there are unfinished round(s)
|
381 |
2 |
schengopen |
if (loaded & ~done)
|
382 |
3 |
schengopen |
begin
|
383 |
|
|
if (func == decrypt) // Model configured as decryptor
|
384 |
2 |
schengopen |
do
|
385 |
|
|
begin
|
386 |
|
|
unique if (curr_round == Nr)
|
387 |
|
|
begin
|
388 |
|
|
`ifdef INTERNAL_DEBUG
|
389 |
|
|
$display("round[%2d].istart\t%h",Nr-curr_round,GetState);
|
390 |
|
|
$display("round[%2d].ik_sch\t%h",Nr-curr_round,GetCurrKsch);
|
391 |
|
|
`endif
|
392 |
|
|
|
393 |
|
|
done = 0;
|
394 |
|
|
AddRoundKey;
|
395 |
|
|
curr_round--;
|
396 |
|
|
end
|
397 |
|
|
else if ((curr_round <= Nr-1) && (curr_round >= 1))
|
398 |
|
|
begin
|
399 |
|
|
`ifdef INTERNAL_DEBUG
|
400 |
|
|
$display("round[%2d].istart\t%h",Nr-curr_round,GetState);
|
401 |
|
|
`endif
|
402 |
|
|
|
403 |
|
|
InvShiftRows;
|
404 |
|
|
`ifdef INTERNAL_DEBUG
|
405 |
|
|
$display("round[%2d].is_row\t%h",Nr-curr_round,GetState);
|
406 |
|
|
`endif
|
407 |
|
|
|
408 |
|
|
InvSubBytes;
|
409 |
|
|
`ifdef INTERNAL_DEBUG
|
410 |
|
|
$display("round[%2d].is_box\t%h",Nr-curr_round,GetState);
|
411 |
|
|
$display("round[%2d].ik_sch\t%h",Nr-curr_round,GetCurrKsch);
|
412 |
|
|
`endif
|
413 |
|
|
|
414 |
|
|
AddRoundKey;
|
415 |
|
|
`ifdef INTERNAL_DEBUG
|
416 |
|
|
$display("round[%2d].ik_add\t%h",Nr-curr_round,GetState);
|
417 |
|
|
`endif
|
418 |
|
|
|
419 |
|
|
InvMixColumns;
|
420 |
|
|
curr_round--;
|
421 |
|
|
end
|
422 |
|
|
else if (curr_round == 0)
|
423 |
|
|
begin
|
424 |
|
|
`ifdef INTERNAL_DEBUG
|
425 |
|
|
$display("round[%2d].istart\t%h",Nr-curr_round,GetState);
|
426 |
|
|
`endif
|
427 |
|
|
|
428 |
|
|
InvShiftRows;
|
429 |
|
|
`ifdef INTERNAL_DEBUG
|
430 |
|
|
$display("round[%2d].is_row\t%h",Nr-curr_round,GetState);
|
431 |
|
|
`endif
|
432 |
|
|
|
433 |
|
|
InvSubBytes;
|
434 |
|
|
`ifdef INTERNAL_DEBUG
|
435 |
|
|
$display("round[%2d].is_box\t%h",Nr-curr_round,GetState);
|
436 |
|
|
$display("round[%2d].ik_sch\t%h",Nr-curr_round,GetCurrKsch);
|
437 |
|
|
`endif
|
438 |
|
|
|
439 |
|
|
AddRoundKey;
|
440 |
|
|
`ifdef INTERNAL_DEBUG
|
441 |
|
|
$display("round[%2d].ioutput\t%h",Nr-curr_round,GetState);
|
442 |
|
|
`endif
|
443 |
|
|
|
444 |
|
|
done = 1; // Last round completed
|
445 |
|
|
loaded = 0;
|
446 |
|
|
end
|
447 |
|
|
|
448 |
|
|
if (mode == 1) break;
|
449 |
|
|
end
|
450 |
|
|
while (done == 0);
|
451 |
|
|
|
452 |
3 |
schengopen |
else
|
453 |
|
|
// Model configured as encryptor
|
454 |
|
|
do
|
455 |
|
|
begin
|
456 |
|
|
unique if (curr_round == 0)
|
457 |
|
|
begin
|
458 |
|
|
`ifdef INTERNAL_DEBUG
|
459 |
|
|
$display("round[%2d].input\t%h",curr_round,GetState);
|
460 |
|
|
$display("round[%2d].k_sch\t%h",curr_round,GetCurrKsch);
|
461 |
|
|
`endif
|
462 |
|
|
|
463 |
|
|
done = 0;
|
464 |
|
|
AddRoundKey;
|
465 |
|
|
curr_round++;
|
466 |
|
|
end
|
467 |
|
|
else if ((curr_round <= Nr-1) && (curr_round >= 1))
|
468 |
|
|
begin
|
469 |
|
|
`ifdef INTERNAL_DEBUG
|
470 |
|
|
$display("round[%2d].start\t%h",curr_round,GetState);
|
471 |
|
|
`endif
|
472 |
|
|
|
473 |
|
|
SubBytes;
|
474 |
|
|
`ifdef INTERNAL_DEBUG
|
475 |
|
|
$display("round[%2d].s_box\t%h",curr_round,GetState);
|
476 |
|
|
`endif
|
477 |
|
|
|
478 |
|
|
ShiftRows;
|
479 |
|
|
`ifdef INTERNAL_DEBUG
|
480 |
|
|
$display("round[%2d].s_row\t%h",curr_round,GetState);
|
481 |
|
|
`endif
|
482 |
|
|
|
483 |
|
|
MixColumns;
|
484 |
|
|
`ifdef INTERNAL_DEBUG
|
485 |
|
|
$display("round[%2d].m_col\t%h",curr_round,GetState);
|
486 |
|
|
`endif
|
487 |
|
|
|
488 |
|
|
AddRoundKey;
|
489 |
|
|
`ifdef INTERNAL_DEBUG
|
490 |
|
|
$display("round[%2d].k_sch\t%h",curr_round,GetCurrKsch);
|
491 |
|
|
`endif
|
492 |
|
|
|
493 |
|
|
curr_round++;
|
494 |
|
|
end
|
495 |
|
|
else if (curr_round == Nr)
|
496 |
|
|
begin
|
497 |
|
|
`ifdef INTERNAL_DEBUG
|
498 |
|
|
$display("round[%2d].start\t%h",curr_round,GetState);
|
499 |
|
|
`endif
|
500 |
|
|
|
501 |
|
|
SubBytes;
|
502 |
|
|
`ifdef INTERNAL_DEBUG
|
503 |
|
|
$display("round[%2d].s_box\t%h",curr_round,GetState);
|
504 |
|
|
`endif
|
505 |
|
|
|
506 |
|
|
ShiftRows;
|
507 |
|
|
`ifdef INTERNAL_DEBUG
|
508 |
|
|
$display("round[%2d].s_row\t%h",curr_round,GetState);
|
509 |
|
|
`endif
|
510 |
|
|
|
511 |
|
|
AddRoundKey;
|
512 |
|
|
`ifdef INTERNAL_DEBUG
|
513 |
|
|
$display("round[%2d].k_sch\t%h",curr_round,GetCurrKsch);
|
514 |
|
|
$display("round[%2d].output\t%h",curr_round,GetState);
|
515 |
|
|
`endif
|
516 |
|
|
|
517 |
|
|
done = 1; // Last round completed
|
518 |
|
|
loaded = 0;
|
519 |
|
|
end
|
520 |
|
|
|
521 |
|
|
if (mode == 1) break;
|
522 |
|
|
end
|
523 |
|
|
while (done == 0);
|
524 |
|
|
|
525 |
|
|
end
|
526 |
2 |
schengopen |
// Either ciphertext is not loaded or decryption has already completed
|
527 |
3 |
schengopen |
else $display("#Info : aes_beh_model::run() has nothing to do");
|
528 |
2 |
schengopen |
endtask
|
529 |
|
|
endclass // aes_decrypt_model
|
530 |
|
|
|
531 |
|
|
// The following types should be used for declaration of aes class objects in your source code.
|
532 |
|
|
// e.g. ....
|
533 |
|
|
// aes256_decrypt_t my_aes_decryptor;
|
534 |
|
|
// bit [0:127] pt;
|
535 |
|
|
// ....
|
536 |
|
|
// my_aes_decryptor = new;
|
537 |
|
|
// my_aes_decryptor.KeyExpand(256'h.......);
|
538 |
|
|
// my_aes_decryptor.LoadCt(128'h.........);
|
539 |
|
|
// my_aes_descryptor.run(0);
|
540 |
|
|
// pt = my_aes_descryptor.GetState();
|
541 |
|
|
|
542 |
3 |
schengopen |
typedef aes_beh_model #(.Nk(8),.Nr(14),.func(decrypt)) aes256_decrypt_t;
|
543 |
|
|
typedef aes_beh_model #(.Nk(6),.Nr(12),.func(decrypt)) aes192_decrypt_t;
|
544 |
|
|
typedef aes_beh_model #(.Nk(4),.Nr(10),.func(decrypt)) aes128_decrypt_t;
|
545 |
|
|
|
546 |
|
|
typedef aes_beh_model #(.Nk(8),.Nr(14),.func(encrypt)) aes256_encrypt_t;
|
547 |
|
|
typedef aes_beh_model #(.Nk(6),.Nr(12),.func(encrypt)) aes192_encrypt_t;
|
548 |
|
|
typedef aes_beh_model #(.Nk(4),.Nr(10),.func(encrypt)) aes128_encrypt_t;
|