OpenCores
URL https://opencores.org/ocsvn/avs_aes/avs_aes/trunk

Subversion Repositories avs_aes

[/] [avs_aes/] [trunk/] [rtl/] [VHDL/] [keyexpansionV2.vhd] - Blame information for rev 20

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ruschi
--------------------------------------------------------------------------------
2 10 ruschi
-- This file is part of the project      avs_aes
3
-- see: http://opencores.org/project,avs_aes
4 2 ruschi
--
5
-- description: hardware keyexpansion core.
6
-------------------------------------------------------------------------------
7
-- Generates all roundkeys for the AES algorithm. in each round on key is used
8
-- to XOR with the round data, e.g. the state. because this is for encryption
9
-- of multiple plaintext blocks always the same roundkey sequence the keys are
10
-- stored until a new key is provided.
11
-- Starting from an initial 128, 192 or 256 Bit key (table of 4,6 or eight
12
-- columns = i) the sucessive roundkeys are calculated in the following way:
13
-- 1.) The 1st round is done with the initial key with the dwords dw[0] to
14
-- dw[i-1]
15
-- 2.) dw[n*i] is build through rotating dw[i-1] 1 left, Substituting its
16
-- contents with the Sbox function, the result then is XORed with
17
-- roundconstant[n] and it is again XORed with dw[(n-1)i].
18
-------------------------------------------------------------------------------
19
-- TODO: Implement another copy of this as wrapper to RAM to enable software
20
-- keyexpanion  
21
--
22
--
23
-- Author(s):
24
--         Thomas Ruschival -- ruschi@opencores.org (www.ruschival.de)
25
--
26
--------------------------------------------------------------------------------
27
-- Copyright (c) 2009, Authors and opencores.org
28
-- All rights reserved.
29
--
30
-- Redistribution and use in source and binary forms, with or without modification,
31
-- are permitted provided that the following conditions are met:
32
--        * Redistributions of source code must retain the above copyright notice,
33
--        this list of conditions and the following disclaimer.
34
--        * Redistributions in binary form must reproduce the above copyright notice,
35
--        this list of conditions and the following disclaimer in the documentation
36
--        and/or other materials provided with the distribution.
37
--        * Neither the name of the organization nor the names of its contributors
38
--        may be used to endorse or promote products derived from this software without
39
--        specific prior written permission.
40
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
44
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
45
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
50
-- THE POSSIBILITY OF SUCH DAMAGE
51
-------------------------------------------------------------------------------
52
-- version management:
53 20 ruschi
-- $Author::                                         $
54
-- $Date::                                           $
55
-- $Revision::                                       $
56 2 ruschi
-------------------------------------------------------------------------------
57
 
58
library IEEE;
59
use IEEE.std_logic_1164.all;
60
use IEEE.numeric_std.all;
61
 
62 11 ruschi
library avs_aes_lib;
63
use avs_aes_lib.avs_aes_pkg.all;
64 2 ruschi
 
65
entity keyexpansionV2 is
66
        generic (
67
                KEYLENGTH : NATURAL := 128      -- Size of keyblock (128, 192, 256 Bits)   
68
                );
69
        port (
70
                clk                       : in  STD_LOGIC;      -- system clock
71
                keyword           : in  DWORD;          -- word of original userkey
72
                keywordaddr       : in  STD_LOGIC_VECTOR(2 downto 0);  -- keyword register address
73
                w_ena_keyword : in      STD_LOGIC;      -- write enable of keyword to wordaddr
74
                key_stable        : in  STD_LOGIC;      -- key is completa and valid, start expansion
75
                -- key_stable=0-> invalidate key
76
                roundkey_idx  : in      NIBBLE;         -- index for selecting roundkey
77
                roundkey          : out KEYBLOCK;       -- key for each round
78
                ready             : out STD_LOGIC       -- expansion done, roundkeys ready
79
                );
80
        -- number of rounds, needed for looping
81
        constant NO_ROUNDS      : NATURAL := lookupRounds(KEYLENGTH);
82
        -- Number of columns in user key: 4,6, or 8
83
        constant Nk                     : NATURAL := KEYLENGTH/DWORD_WIDTH;
84
        -- Number of interations
85
        constant LOOP_BOUND : NATURAL := 4*NO_ROUNDS;
86
end entity keyexpansionV2;
87
 
88
 
89
architecture ach1 of keyexpansionV2 is
90
 
91
        -- Round constants for XOR i/Nk is max 10 for Nk=4
92
        constant GF_ROUNDCONSTANTS_4_6 : BYTEARRAY(0 to 10) :=
93
                (X"01", X"02", X"04", X"08", X"10", X"20", X"40", X"80", X"1B", X"36", X"6C");
94
        -- keep quartus from complaining about "index not wide enough for all
95
        -- elements in the array" i/Nk is max 7 for Nk=8
96
        constant GF_ROUNDCONSTANTS_8 : BYTEARRAY(0 to 7) :=
97
                (X"01", X"02", X"04", X"08", X"10", X"20", X"40", X"80");
98
        signal roundconstant : BYTE;
99
 
100
        -- memory for roundkeys
101
        type   MEMORY_128 is array (0 to 15) of STD_LOGIC_VECTOR(127 downto 0);
102
        signal KEYMEM : MEMORY_128;
103
 
104
        -- key memory signals
105
        signal mem_in           : STD_LOGIC_VECTOR(127 downto 0);  -- in port for keymemory
106
        signal mem_out          : STD_LOGIC_VECTOR(127 downto 0);  -- out port of keymemory
107
        signal keymem_addr      : UNSIGNED(3 downto 0);   -- address of RAM
108
        signal w_ena_keymem : STD_LOGIC;        -- write enable to keymemory
109
        -- write address for keymemory
110
        signal w_addr           : UNSIGNED(3 downto 0);   -- register
111
        signal next_w_addr      : UNSIGNED(3 downto 0);   -- combinational next value
112
 
113
        -- Interconnect for shiftregister
114
        signal keyshiftreg_in  : DWORDARRAY(Nk-1 downto 0);       -- input from multiplexers
115
        signal keyshiftreg_out : DWORDARRAY(Nk-1 downto 0);       -- output
116
        signal keyshiftreg_ena : STD_LOGIC_VECTOR(7 downto 0);   -- enable of single registers
117
        -- Selector for Load multiplexer, only select keyword to be written to
118
        -- shiftreg if key_stable is deasserted loadmux_sel <= not key_stable
119
        signal loadmux_sel         : STD_LOGIC;
120
 
121
        ---------------------------------------------------------------------------
122
        -- datapath expansion algorithm
123
        ---------------------------------------------------------------------------
124
        signal exp_in                   : DWORD;        -- in for expansion logic (w[i-1])
125
        signal rot_out                  : DWORD;        -- rotated column (in to sbox)
126
        signal to_sbox                  : DWORD;  -- substituted key column (out from sbox)
127
        signal from_sbox                : DWORD;  -- substituted key column (out from sbox)
128
        signal delayed_col              : DWORD;  -- delayed unprocessed key column w[i-1] | imod4/=0
129
        signal XorRcon_out              : DWORD;  -- rotated,substituted,XORed with Rcon column w[i-1]|imod4=0
130
        signal mux_processed    : DWORD;  -- multiplexed delayed_col or XorRcon_out
131
        signal Xor_lastblock_in : DWORD;        -- input for w[i-1] XOR w[i-Nk]
132
        signal last_word                : DWORD;  -- result of expansion w[i] --> w[i-1] for next round
133
 
134
        ---------------------------------------------------------------------------
135
        -- Controller signals
136
        ---------------------------------------------------------------------------
137
        signal first_round       : STD_LOGIC;  -- selector Mux_input only '0' in first round
138
        signal shift_ena         : STD_LOGIC;  -- enable shift of register bank w[i-1] to w[i-Nk]
139
        signal imodNk0           : STD_LOGIC;  -- mux selector delayed_col or XorRcon_out if imodNk=0
140
        -- Special logic for Nk=8 256 Bit key
141
        signal imod84            : STD_LOGIC;  -- mux selector around Rotate to substitute if imod8=4
142
        -- Statemachine
143
        type   KEYEXPANSIONSTATES is (INIT, SUBSTITUTE, SHIFT, WRITELAST, DONE);
144
        signal expState          : KEYEXPANSIONSTATES;    -- register value
145
        signal next_expState : KEYEXPANSIONSTATES;        -- combinational next value
146
        -- counter for expanded keywords (max Nk*(Nr+1)=4*(14+1))
147
        signal i                         : UNSIGNED(5 downto 0);  -- register
148
        signal next_i            : UNSIGNED(5 downto 0);  -- combinational next value
149
 
150
begin  -- architecture ach1
151
 
152
-------------------------------------------------------------------------------
153
-- Key load and shift register datapath
154
-------------------------------------------------------------------------------
155
        loadmux_sel <= not key_stable;
156
 
157
        Shiftreg : for i in 0 to Nk-1 generate
158
                -- ordinary words are regular shift registers
159
                rest_of_shiftreg : if i /= Nk-1 generate
160
                        loadmux : Mux2
161
                                generic map (
162
                                        IOwidth => DWORD_WIDTH)
163
                                port map (
164
                                        inport_a => keyshiftreg_out(i+1),
165
                                        inport_b => keyword,
166
                                        selector => loadmux_sel,
167
                                        outport  => keyshiftreg_in(i));
168
                        keywordregister : memory_word
169
                                generic map (
170
                                        IOwidth => DWORD_WIDTH)
171
                                port map (
172
                                        data_in  => keyshiftreg_in(i),
173
                                        data_out => keyshiftreg_out(i),
174
                                        res_n    => '1',
175
                                        clk              => clk,
176
                                        ena              => keyshiftreg_ena(i));
177
                end generate;
178
                -- last word is different: here result from last expansion round is
179
                -- shifted in 
180
                lastDWORD : if i = Nk-1 generate
181
                        lastw_loadmux : Mux2
182
                                generic map (
183
                                        IOwidth => DWORD_WIDTH)
184
                                port map (
185
                                        inport_a => last_word,  -- loopback form expansion logic
186
                                        inport_b => keyword,
187
                                        selector => loadmux_sel,
188
                                        outport  => keyshiftreg_in(i));
189
 
190
                        last_keywordreg : memory_word
191
                                generic map (
192
                                        IOwidth => DWORD_WIDTH)
193
                                port map (
194
                                        data_in  => keyshiftreg_in(i),
195
                                        data_out => keyshiftreg_out(i),
196
                                        res_n    => '1',
197
                                        clk              => clk,
198
                                        ena              => keyshiftreg_ena(i));
199
                end generate lastDWORD;
200
        end generate Shiftreg;
201
 
202
        -- Lower 4 Keywords will be written to key ram
203
        mem_in <= keyshiftreg_out(0) &keyshiftreg_out(1) & keyshiftreg_out(2) & keyshiftreg_out(3);
204
        -- map memory port to a nice state
205
        roundkey <= (0 => mem_out(127 downto 96),
206
                                 1 => mem_out(95 downto 64),
207
                                 2 => mem_out(63 downto 32),
208
                                 3 => mem_out(31 downto 0));
209
 
210
        -- purpose: represent ram for storage of roundkeys (DP ram should be inferred)
211
        -- type   : sequential
212
        -- inputs : clk, res_n
213
        -- outputs: mem_out
214
        keymemory : process (clk) is
215
        begin  -- process keymemory
216
                if rising_edge(clk) then                -- rising clock edge
217
                        if w_ena_keymem = '1' then
218
                                KEYMEM(to_integer(w_addr)) <= mem_in;
219
                        end if;
220
                        mem_out <= KEYMEM(to_integer(UNSIGNED(roundkey_idx)));
221
                end if;
222
        end process keymemory;
223
 
224
 
225
        -- purpose: set the respective enable bits for each register if either registes must be shifted
226
        -- right. only enable external write if key_stable='0'
227
        -- or are loaded with userkey
228
        -- type   : combinational
229
        -- inputs : w_ena_keyword, shift_ena,keywordaddr
230
        -- outpukeyshiftreg_ena
231
        enableRegs : process (key_stable, keywordaddr, shift_ena, w_ena_keyword) is
232
        begin  -- process enableRegs
233
                -- default: freeze the registers
234
                keyshiftreg_ena <= (others => '0');
235
                -- if words are loaded externally only enable register for respective address
236
                -- words must only be written if key_stable is not asserted and
237
                -- therefore the FSM is in INIT state
238
                if w_ena_keyword = '1' and key_stable = '0' then
239
                        keyshiftreg_ena(to_integer(UNSIGNED(keywordaddr))) <= '1';
240
                        -- if register shall be shifted, enable all
241
                elsif shift_ena = '1' then
242
                        keyshiftreg_ena <= (others => '1');
243
                end if;
244
        end process enableRegs;
245
 
246
        -- purpose: write combinational next_write address to register
247
        -- type   : sequential
248
        -- inputs : clk, next_w_addr
249
        -- outputs: w_addr
250
        address_incr : process (clk) is
251
        begin  -- process address_incr
252
                if rising_edge(clk) then                -- rising clock edge
253
                        w_addr <= next_w_addr;
254
                end if;
255
        end process address_incr;
256
 
257
 
258
-------------------------------------------------------------------------------
259
-- Expansion Datapath
260
------------------------------------------------------------------------------- 
261
 
262
        ---------------------------------------------------------------------------
263
        -- Rotate left the key column a1,a2,a3,a4 --> a2,a3,4,a1
264
        ---------------------------------------------------------------------------
265
        rot_out <= keyshiftreg_out(Nk-1)(23 downto 0) & keyshiftreg_out(Nk-1)(31 downto 24);
266
 
267
        ---------------------------------------------------------------------------
268
        -- Special datapath for 256Bit key (Nk=8) if imodNk=4 to
269
        -- substitute w[i-1]
270
        ---------------------------------------------------------------------------
271
        NK8_sboxin : if KEYLENGTH = 256 generate
272
                Nk8_sboxmux : mux2
273
                        generic map (
274
                                IOwidth => 32)
275
                        port map (
276
                                inport_a => rot_out,
277
                                inport_b => keyshiftreg_out(Nk-1),
278
                                selector => imod84,
279
                                outport  => to_sbox);
280
 
281
                -- Logic to switch the multiplexer
282
                imod84 <= '1' when (i mod 8 = 4) else '0';
283
        end generate NK8_sboxin;
284
 
285
 
286
        regular_sboxin : if KEYLENGTH /= 256 generate
287
                to_sbox <= rot_out;
288
        end generate regular_sboxin;
289
 
290
        ---------------------------------------------------------------------------
291
        -- Keygenerate gets its own sboxes to substitute columns to define clear
292
        -- interface and increase f_max as this was on the critical path while
293
        -- shared with aes_core_encrypt
294
        ---------------------------------------------------------------------------
295
        HighWord : sbox
296
                generic map (
297
                        INVERSE => false)
298
                port map (
299
                        clk               => clk,
300
                        address_a => to_sbox(31 downto 24),
301
                        address_b => to_sbox(23 downto 16),
302
                        q_a               => from_sbox(31 downto 24),
303
                        q_b               => from_sbox(23 downto 16));
304
        LowWord : sbox
305
                generic map (
306
                        INVERSE => false)
307
                port map (
308
                        clk               => clk,
309
                        address_a => to_sbox(15 downto 8),
310
                        address_b => to_sbox(7 downto 0),
311
                        q_a               => from_sbox(15 downto 8),
312
                        q_b               => from_sbox(7 downto 0));
313
 
314
        ---------------------------------------------------------------------------
315
        -- Xor column with Roundconstant[i/Nk], make it 32 BIT
316
        ---------------------------------------------------------------------------
317
        XorRcon_out <= from_sbox xor (roundconstant & X"000000");
318
 
319
        ---------------------------------------------------------------------------
320
        -- select intermediate result of processed w[i-1] either direct or
321
        -- processed with Sub(Rot(W[i-1]) XOR roundconstant if i mod Nk = 0
322
        ---------------------------------------------------------------------------
323
        Mux_wi_1 : mux2
324
                generic map (
325
                        IOwidth => DWORD_WIDTH)
326
                port map (
327
                        inport_a => keyshiftreg_out(Nk-1),
328
                        inport_b => XorRcon_out,
329
                        selector => imodNk0,
330
                        outport  => mux_processed);
331
        -- Logic to switch the multiplexer
332
        imodNk0 <= '1' when (i mod Nk = 0) else '0';
333
 
334
        ---------------------------------------------------------------------------
335
        -- Special datapath for 256Bit key (Nk=8) if imodNk=4 to
336
        -- substitute w[i-1]
337
        ---------------------------------------------------------------------------
338
        NK8_wi_1 : if KEYLENGTH = 256 generate
339
                Nk8_mux_wi_1 : mux2
340
                        generic map (
341
                                IOwidth => 32)
342
                        port map (
343
                                inport_a => mux_processed,
344
                                inport_b => from_sbox,
345
                                selector => imod84,
346
                                outport  => Xor_lastblock_in);
347
        end generate NK8_wi_1;
348
 
349
 
350
        regular_wi_1 : if KEYLENGTH /= 256 generate
351
                Xor_lastblock_in <= mux_processed;
352
        end generate regular_wi_1;
353
 
354
        ---------------------------------------------------------------------------
355
        -- Xor currently processed column w[i-1] with w[i-Nk]
356
        ---------------------------------------------------------------------------
357
        last_word <= Xor_lastblock_in xor keyshiftreg_out(0);
358
 
359
 
360
-------------------------------------------------------------------------------
361
-- Controller for keyexpansion algorithm 
362
------------------------------------------------------------------------------- 
363
 
364
        -- purpose: Compute the next state of keyexpansion FSM
365
        -- type   : combinational
366
        -- inputs : expState, i, key_stable
367
        -- outputs: next_expState
368
        nextState : process (expState, i, key_stable) is
369
        begin
370
                -- Save defaults to avoid latches
371
                next_expState <= expState;
372
                -- FSM
373
                case expState is
374
                        when INIT =>
375
                                if key_stable = '1' then
376
                                        next_expState <= SUBSTITUTE;
377
                                end if;
378
                        when SUBSTITUTE =>
379
                                next_expState <= SHIFT;
380
                        when SHIFT =>
381
                                if i = LOOP_BOUND then
382
                                        next_expState <= DONE;
383
                                else
384
                                        next_expState <= SUBSTITUTE;
385
                                end if;
386
                        when WRITELAST =>
387
                                next_expState <= DONE;
388
                        when DONE =>
389
                                -- just stay
390
                                next_expState <= expState;
391
                end case;
392
                -- reset the process whenever key is invalid
393
                if key_stable = '0' then
394
                        next_expState <= INIT;
395
                end if;
396
        end process nextState;
397
 
398
        -- purpose: assign signals according to input and current state
399
        -- type   : combinational
400
        -- inputs : expState, i
401
        -- outputs: shift_ena, next_i, ready    
402
        stateToOutput : process (expState, i, w_addr) is
403
        begin
404
                -- Save defaults to avoid latches
405
                shift_ena        <= '0';
406
                next_i           <= i;
407
                ready            <= '0';
408
                w_ena_keymem <= '0';
409
                next_w_addr      <= w_addr;
410
                case expState is
411
                        when INIT =>
412
                                -- reset all variables to defined state
413
                                next_i          <= (others => '0');
414
                                next_w_addr <= (others => '0');
415
                        when SUBSTITUTE =>
416
                                -- Substitute is a mere wait state for 1 cycle until SBOX has done
417
                                -- the lookup
418
                                null;
419
                        when SHIFT =>
420
                                next_i    <= i+1;
421
                                shift_ena <= '1';
422
                                if (i mod 4 = 0) then
423
                                        w_ena_keymem <= '1';
424
                                        next_w_addr      <= w_addr+1;
425
                                end if;
426
                        when WRITELAST =>
427
                                w_ena_keymem <= '1';
428
                                next_w_addr      <= w_addr+1;
429
                        when DONE =>
430
                                ready <= '1';
431
                        when others => null;
432
                end case;
433
        end process stateToOutput;
434
 
435
        -- purpose: write state and variables to registers
436
        -- type   : sequential
437
        -- inputs : clk, res_n
438
        -- outputs: 
439
        registeredFSMsignals : process (clk) is
440
        begin  -- process registeredFSMsignals
441
                if rising_edge(clk) then                -- rising clock edge
442
                        i                <= next_i;
443
                        expState <= next_expState;
444
                        if Nk = 8 then
445
                                roundconstant <= GF_ROUNDCONSTANTS_8(to_integer(i)/Nk);
446
                        else
447
-- TODO : avoid divide operator, error when compiling with Nk=6 anx ISE 10.1
448
                                roundconstant <= GF_ROUNDCONSTANTS_4_6(to_integer(i)/Nk);
449
                        end if;
450
                end if;
451
        end process registeredFSMsignals;
452
 
453
end architecture ach1;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.