OpenCores
URL https://opencores.org/ocsvn/aes-128-ecb-encoder/aes-128-ecb-encoder/trunk

Subversion Repositories aes-128-ecb-encoder

[/] [aes-128-ecb-encoder/] [trunk/] [src/] [aes128_enc.sv] - Rev 2

Compare with Previous | Blame | View Log

/**
 * AES-128-ECB Encoder module
 *
 *  Copyright 2020 by Vyacheslav Gulyaev <v.gulyaev181@gmail.com>
 *
 *  Licensed under GNU General Public License 3.0 or later. 
 *  Some rights reserved. See COPYING, AUTHORS.
 *
 * @license GPL-3.0+ <http://spdx.org/licenses/GPL-3.0+>
 */

module aes128_enc(
                    input clk_i,
                    input rstn_i,
                    
                    input [127:0] data_i,
                    input [127:0] key_i,
                    input         valid_i,
                    

                    output logic [127:0] data_o,
                    output logic         valid_o
                    
               );

    //`define DEBUG_MODE 
    
    localparam logic [7:0] Sbox[0:15][0:15] = '{/*           0      1      2      3      4      5      6      7      8      9      A      B      C      D      E      F    */
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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},
                                                /*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}
                                                };
    
    localparam logic [7:0] Rcon[0:3][0:9] = '{
                                                 '{8'h01, 8'h02, 8'h04, 8'h08, 8'h10, 8'h20, 8'h40, 8'h80, 8'h1b, 8'h36},
                                                 '{8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00},
                                                 '{8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00},
                                                 '{8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00, 8'h00}
                                             };    
    
    typedef logic [7:0] state_t [0:3] [0:3];
    state_t state;
    state_t round_key;
    
    logic [127:0] data_int;
    logic [3:0]   round;
    logic         busy;

    ////////////////////////////////////////
    /*
     * Implementation of functions area start
     */
    
    /*Transform functions 128-bit(16byte) vector to byte state matrix 4x4 and back
     *[15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0] <==>  | 15  11   7  3 |
     *                                              | 14  10   6  2 |
     *                                              | 13   9   5  1 |
     *                                              | 12   8   4  0 |
     */ 
    function state_t vect_to_matrix(input logic [127:0] data);
        state_t state_o;
        state_o      ='{ '{data[127:120], data[95:88], data[63:56], data[31:24]},
                         '{data[119:112], data[87:80], data[55:48], data[23:16]},
                         '{data[111:104], data[79:72], data[47:40], data[15: 8]},
                         '{data[103: 96], data[71:64], data[39:32], data[ 7: 0]}
                        };
        return state_o;
    endfunction

    function logic [127:0] matrix_to_vector(input state_t st);
        logic [127:0] d_o;
        d_o = {    st[0][0], st[1][0], st[2][0], st[3][0],
                   st[0][1], st[1][1], st[2][1], st[3][1],
                   st[0][2], st[1][2], st[2][2], st[3][2],
                   st[0][3], st[1][3], st[2][3], st[3][3]
              };
        return d_o;
    endfunction
    
    /*
     * Replase data in state matrix with data from Sbox(2^8) table 
     */
    function state_t sub_bytes(input state_t st);
        logic [3:0] r_gf;
        logic [3:0] c_gf;
        state_t state_o;
        for (int r=0; r<4; r=r+1) begin
            for (int c=0; c<4; c=c+1) begin
                r_gf = st[r][c][7:4];
                c_gf = st[r][c][3:0];
                state_o[r][c] = Sbox[r_gf][c_gf];
            end
        end
        //void'(debug_output("After sub bytes", state_o));
        return state_o;
    endfunction
    
    /*
     * Cyclic shift bytes in state matrix rows
     */
    function state_t shift_rows(input state_t st);
        state_t state_o;
        state_o = '{'{st[0][0], st[0][1], st[0][2], st[0][3]},
                    '{st[1][1], st[1][2], st[1][3], st[1][0]},
                    '{st[2][2], st[2][3], st[2][0], st[2][1]},
                    '{st[3][3], st[3][0], st[3][1], st[3][2]}
                    }; 
        //void'(debug_output("After shift rows", state_o));
        return state_o;
    endfunction
    
    /*
     * Multiplication by 2: 1-bit shift left + xor 8'h1b (if val[7]==1)
     */
    function logic [7:0] mul2(input logic [7:0] val);
        return (({val[6:0], 1'b0}) ^ (val[7] ? 8'h1b : 8'h00));
    endfunction
    
    /*
     * Multiplication by 3: mul2 + val ('+' is xor operation)
     */
    function logic [7:0] mul3(input logic [7:0] val);
        return (mul2(val) ^ val);
    endfunction
    
    /* Mix column algorithm is multiplication matrix on column vector
     * | s'[0,c] | = | 02 03 01 01 | * | s[0,c] |
     * | s'[1.c] |   | 01 02 03 01 |   | s[1,c] |
     * | s'[2,c] |   | 01 01 02 03 |   | s[2,c] |
     * | s'[3,c] |   | 03 01 01 02 |   | s[3,c] |
     */
    function state_t mix_columns(input state_t st);
        state_t state_o;
        for (int c=0; c<4; c=c+1) begin
            state_o[0][c] = mul2(st[0][c]) ^ mul3(st[1][c]) ^ st[2][c]       ^ st[3][c];       //s'[0,c] = ({02}*s[0,c]) + ({03}*s[1,c]) + s[2,c]        + s[3,c]
            state_o[1][c] = st[0][c]       ^ mul2(st[1][c]) ^ mul3(st[2][c]) ^ st[3][c];       //s'[1,c] = s[0,c]        + ({02}*s[1,c]) + ({03}*s[2,c]) + s[3,c]
            state_o[2][c] = st[0][c]       ^ st[1][c]       ^ mul2(st[2][c]) ^ mul3(st[3][c]); //s'[2,c] = s[0,c]        + s[1,c]        + ({02}*s[2,c]) + ({03}*s[3,c])
            state_o[3][c] = mul3(st[0][c]) ^ st[1][c]       ^ st[2][c]       ^ mul2(st[3][c]); //s'[2,c] = ({02}*s[0,c]) + s[1,c]        + s[2,c]        + ({02}*s[3,c])
        end
        //void'(debug_output("After mix columns", state_o));
        return state_o;
    endfunction
    
    /*
     * Computing next round key for key schedule
     * */
    function state_t compute_next_round_key(input state_t key, input logic [3:0] cur_round);
        state_t     key_o;
        logic [3:0] r_gf;
        logic [3:0] c_gf;
        
        for (int r=0; r<4; r=r+1) begin
            //compute [0] column
            //sub bytes from Sbox
            if (r<3) begin
                r_gf = key[r+1][3][7:4];
                c_gf = key[r+1][3][3:0];
            end else begin
                r_gf = key[0][3][7:4];
                c_gf = key[0][3][3:0];
            end
            key_o[r][0] = key[r][0] ^ Sbox[r_gf][c_gf] ^ Rcon[r][cur_round];
            
            //compute [1:3] columns 
            for (int c=1; c<4; c=c+1) begin
                key_o[r][c] = key_o[r][c-1] ^ key[r][c];
            end
        end
        return key_o;
    endfunction
    
    /*
     * Adding round key
     * */
    function state_t add_round_key(input state_t st, input state_t key);
        state_t state_o;
        for (int r=0; r<4; r=r+1) begin
            for (int c=0; c<4; c=c+1) begin
                state_o[r][c] = st[r][c] ^ key[r][c];
            end
        end
        //void'(debug_output("After add round key", state_o));
        return state_o;
    endfunction
    
    /*
     * Debug output
     * */
/*     
    function debug_output(string info, state_t state);
        `ifdef DEBUG_MODE
            for (int r=0; r<4; r=r+1) begin
                $display("[%t]: %s: 0x%02H  0x%02H  0x%02H  0x%02H", $time, info, state[r][0], state[r][1], state[r][2], state[r][3]);
            end
            $display("");
        `endif
    endfunction
*/    
    /*
     * Implementation of functions area end
     */
    ////////////////////////////////////////


    //AES-128 encoder logic
    assign data_int = data_i ^ key_i; // Initialization, i.e. adding round key before 1st round
    
    always @(posedge clk_i or negedge rstn_i) begin
        if (~rstn_i) begin
            `ifdef DEBUG_MODE
                $display("=====Reseting=====");
            `endif
            state = vect_to_matrix(127'h0);
            round_key = vect_to_matrix(127'h0);
            round = 4'h0;
            busy = 1'b0;
            data_o = 128'h0;
            valid_o = 1'b0; 
        end else if (valid_i & ~busy) begin //1st round after valid data receiving
            `ifdef DEBUG_MODE
                $display("=====Received valid data, starting round 1=====");
            `endif
            round = 4'h0;
            busy = 1'b1;

            state = vect_to_matrix(data_int); //convert 128 bit data xored with key to byte matrix 4x4
            state = sub_bytes(state);  //change data bytes on bytes from Sbox field
            state = shift_rows(state); //shift columns in rows 
            state = mix_columns(state);//mix columns algorithm
            round_key = vect_to_matrix(key_i);//convert 128bit key to byte matrix 4x4
            round_key = compute_next_round_key(round_key, round);//get next schedule key
            state = add_round_key(state, round_key);

            round = round + 1;
            data_o = 128'h0;
            valid_o = 1'b0; 
        end else if (busy) begin //rounds 2-10
            `ifdef DEBUG_MODE
                $display("=====Round %02d=====", (round+1));
            `endif
            state = sub_bytes(state);  //change data bytes on bytes from Sbox field

            state = shift_rows(state); //shift columns in rows
            if (round!=4'h9) begin
                state = mix_columns(state);//mix columns algorithm
            end
            round_key = compute_next_round_key(round_key, round);//get next schedule key
            state = add_round_key(state, round_key);
            if (round==9'h9) begin
                round = 4'h0;
                busy = 1'b0;
                data_o = matrix_to_vector(state);
                valid_o = 1'b1;
            end else begin
                round = round + 1;
                busy = 1'b1;
                data_o = 128'h0;
                valid_o = 1'b0; 
            end
        end else begin
            `ifdef DEBUG_MODE
                $display("=====IDLE=====");
            `endif
            state = vect_to_matrix(127'h0);
            round_key = vect_to_matrix(127'h0);
            round = 4'h0;
            busy = 1'b0;
            data_o = 128'h0;
            valid_o = 1'b0; 
        end
    end
    
endmodule

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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