blasthash
blasthash

Reputation: 98

How to designate port as byte array in VHDL

Alright guys, sorry if this is a question that's been asked already, as I'm new enough to VHDL logic design to not know exactly how to term a particular concept.

What I'm trying to do is implement the AES-256 algorithm in VHDL for FPGA use.

I have a port named:

entity rijndael is port
(
input : in std_logic_vector(255 downto 0)
subkey: in std_logic_vector(255 downto 0)
output: out std_logic_vector(255 downto 0)
);
end rijndael;

How in the architecture do I designate each byte worth of input as an array of individual byte-worth segments for the subBytes() process of the AES algorithm?

Upvotes: 1

Views: 3423

Answers (3)

rick
rick

Reputation: 1646

Here's how I defined it when I had to implement AES-128:

constant KEY_LENGTH: integer := 128;
constant BLOCK_LENGTH: integer := 128;

subtype key_type is std_logic_vector(KEY_LENGTH-1 downto 0);
type key_array_type is array (natural range<>) of key_type;
subtype word_type is std_logic_vector(31 downto 0);
subtype byte_type is std_logic_vector(7 downto 0);
type state_type is array (0 to 3, 0 to 3) of std_logic_vector(7 downto 0);
type state_array_type is array (natural range<>) of state_type;
type column_type is array (0 to 3) of std_logic_vector(7 downto 0);
type column_array_type is array (natural range<>) of column_type;

This was the public interface:

function encrypt(
    plain_text: std_logic_vector(BLOCK_LENGTH-1 downto 0);
    cypher_key: in key_type
) return std_logic_vector;

And here you can see some of the private methods. Note that the main processing methods take in an object 'state_type' and return another value, also of state_type:

function shift_rows(state_in: state_type) return state_type;
function mix_columns(state_in: state_type) return state_type;
function add_round_key(state: state_type; round_key: key_type) return state_type;
function mix_column(column_in: column_type) return column_type;
function expand_key(cypher_key: key_type) return column_array_type;
function round_key(expanded_key: column_array_type; round_number: integer) return key_type;

I found it useful to declare some functions to convert to and from the custom types and std_logic_vector:

function vector_from_state(state: state_type) return std_logic_vector;
function state_from_vector(vector: std_logic_vector(127 downto 0)) return state_type;
function vector_from_column(column: column_type) return std_logic_vector;
function state_from_columns(columns: column_array_type) return state_type;
function vector_from_columns(columns: column_array_type) return std_logic_vector;
function columns_from_state(state: state_type) return column_array_type;

If someone finds it useful I may upload the entire code to GitHub upon request.

Upvotes: 1

user1155120
user1155120

Reputation:

From looking in the standard the byte values in AES are organized into columns and rows, you basically need and indexing system to identity array subranges that specify which 8 bits of the input are associated with which row and column.

If you need to loop (as in a generate loop, come on this hardware) you could use multidimensional arrays and assign them from the the input array subranges, where you have row and column indexes. You could make the input array an array of 8 bit things to follow FIPS-197 closely:

Input, State and Output Byte relationship, 128 bit block

You'd find the notation system used in the FIPS is different from the Rijndael submission, you're better off using a common reference system with anyone who might offer help at some point. The FIPS appears to imply you should be using big endian arrays, while you've declared input as little endian.

I'll demonstrate with a design specification that analyzes, elaborates and simulates. (Can't guarantee it is correct, it's late and I'm a bit peckish).

library ieee;
use ieee.std_logic_1164.all;

entity State is
    port (
        input:      in      std_logic_vector (0 to 255);
        output:     out     std_logic_vector (0 to 255)
    );

end entity;

architecture foo of State is

    subtype in0  is natural range   0 to   7;
    subtype in1  is natural range   8 to  15;
    subtype in2  is natural range  16 to  23;
    subtype in3  is natural range  24 to  31;
    subtype in4  is natural range  32 to  39;
    subtype in5  is natural range  40 to  47;
    subtype in6  is natural range  48 to  55;
    subtype in7  is natural range  56 to  63;
    subtype in8  is natural range  64 to  71;
    subtype in9  is natural range  72 to  79;
    subtype in10 is natural range  80 to  87;
    subtype in11 is natural range  88 to  95;
    subtype in12 is natural range  96 to 103;
    subtype in13 is natural range 104 to 111;
    subtype in14 is natural range 112 to 119;
    subtype in15 is natural range 120 to 127;
    subtype in16 is natural range 128 to 135;
    subtype in17 is natural range 136 to 143;
    subtype in18 is natural range 144 to 151;
    subtype in19 is natural range 152 to 159;
    subtype in20 is natural range 160 to 167;
    subtype in21 is natural range 168 to 175;
    subtype in22 is natural range 176 to 183;
    subtype in23 is natural range 184 to 191;
    subtype in24 is natural range 192 to 199;
    subtype in25 is natural range 200 to 207;
    subtype in26 is natural range 208 to 215;
    subtype in27 is natural range 216 to 223;
    subtype in28 is natural range 224 to 231;
    subtype in29 is natural range 232 to 239;
    subtype in30 is natural range 240 to 247;
    subtype in31 is natural range 248 to 255;

    type state_array is array   -- (row, col) of 8 bits
         (natural range 0 to 3, natural range 0 to 7)
                         of std_logic_vector(0 to 7); 

    signal S:   state_array;

begin 

    S <= state_array'( 
              ( input(in0),  input(in4),  input(in8),  input(in12),
                input(in16), input(in20), input(in24), input(in28) ),
              ( input(in1),  input(in5),  input(in9),  input(in13),
                input(in17), input(in21), input(in25), input(in29) ),
              ( input(in2),  input(in6),  input(in10), input(in14), 
                input(in18), input(in22), input(in26), input(in30) ),
              ( input(in3),  input(in7),  input(in11), input(in15),
                input(in19), input(in23), input(in27), input(in31) )
         );

    output <= S(0,0) & S(1,0) & S(2,0) & S(3,0) &  -- columns on side
              S(0,1) & S(1,1) & S(2,1) & S(3,1) &
              S(0,2) & S(1,2) & S(2,2) & S(3,2) &
              S(0,3) & S(1,3) & S(2,3) & S(3,3) &
              S(0,4) & S(1,4) & S(2,4) & S(3,4) &
              S(0,5) & S(1,5) & S(2,5) & S(3,5) &
              S(0,6) & S(1,6) & S(2,6) & S(3,6) &
              S(0,7) & S(1,7) & S(2,7) & S(3,7) ;

end architecture;

This gives you indexes on bytes so you can use generate statements and do byte steering for transformations, in terms of State (S shown). You could of course dispense with the subtype declarations and ranges for the input slices directly.

Upvotes: 2

user3273575
user3273575

Reputation: 16

A byte is eight bits; so, std_logic_vector(7 downto 0) would be correct. std_logic_vector is an array of std_logic -- each std_logic can represent a single digital bit.

Upvotes: 0

Related Questions