------------------------------------------------------------
-- Copyright: 2011 Integrated Sytems Laboratory, ETH Zurich
-- http://www.iis.ee.ethz.ch/~sha3
------------------------------------------------------------
-------------------------------------------------------------------------------
-- Title : The Q round of Groestl
-- Project :
-------------------------------------------------------------------------------
-- File : groestl_q.vhd
-- Author : Frank K. Guerkaynak
-- Company : Integrated Systems Laboratory, ETH Zurich
-- Created : 2011-08-21
-- Last update: 2011-09-05
-- Platform : ModelSim (simulation), Synopsys (synthesis)
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: 1/8 of the round
-------------------------------------------------------------------------------
-- Copyright (c) 2011 Integrated Systems Laboratory, ETH Zurich
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2011-08-21 1.0 kgf Created
-- 2011-09-04 1.1 kgf Major corrections
-- 2011-09-05 1.2 kgf Moved the register between Addroundcons and
-- SubBytes
-------------------------------------------------------------------------------
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
entity groestl_q is
port (
ClkxCI : in std_logic;
RstxRBI : in std_logic;
RndxSI : in std_logic_vector(7 downto 0);
SubRndxSI : in integer range 0 to 7;
InxDI : in std_logic_vector(511 downto 0);
OutxDO : out std_logic_vector(511 downto 0));
end groestl_q;
architecture rtl of groestl_q is
component g_mixbytes
port (
InxDI : in std_logic_vector(63 downto 0);
OutxDO : out std_logic_vector(7 downto 0));
end component;
component groestl_subbytes
port (
DxDI : in std_logic_vector(7 downto 0);
DxDO : out std_logic_vector(7 downto 0));
end component;
type statematrix is array (0 to 7, 0 to 7) of std_logic_vector (7 downto 0);
type statearray is array (0 to 7) of std_logic_vector (7 downto 0);
type incconsttype is array (0 to 7) of integer range 0 to 7;
type minputtype is array (0 to 7) of std_logic_vector(63 downto 0);
-- KGF states
signal QxDP, QxDN, Q1xD : statematrix;
signal RQxD : std_logic_vector(63 downto 0); -- selected column
signal SQxD : std_logic_vector(63 downto 0); -- after Subbytes
signal MQxD : statearray; -- after MixBytes
signal M1xD : minputtype;
signal QStartxD, QFinxD : std_logic_vector(511 downto 0);
constant INCQ : incconsttype := (1,3,5,7,0,2,4,6); -- shift amounts for Q
begin -- rtl
-------------------------------------------------------------------------------
-- New start either a fresh vector or a state round
-------------------------------------------------------------------------------
QStartxD <= InxDI when RndxSI = "00000000" else QFinxD;
p_new : process (QStartxD, SubRndxSI, RndxSI, Q1xD)
variable varq : statematrix;
begin -- process p_new
varq := Q1xD;
if SubRndxSI = 0 then -- Add round constant
varq(0,7) := QStartxD(455 downto 448) xor x"ff" xor RndxSI;
varq(1,7) := QStartxD(391 downto 384) xor x"ef" xor RndxSI;
varq(2,7) := QStartxD(327 downto 320) xor x"df" xor RndxSI;
varq(3,7) := QStartxD(263 downto 256) xor x"cf" xor RndxSI;
varq(4,7) := QStartxD(199 downto 192) xor x"bf" xor RndxSI;
varq(5,7) := QStartxD(135 downto 128) xor x"af" xor RndxSI;
varq(6,7) := QStartxD( 71 downto 64) xor x"9f" xor RndxSI;
varq(7,7) := QStartxD( 7 downto 0) xor x"8f" xor RndxSI;
for y in 0 to 6 loop
for x in 0 to 7 loop
varq(x,y) := QStartxD((((7-x) * 64) + ((7-y) *8) + 7) downto ((7-x) * 64) + ((7-y) *8)) xor x"ff";
end loop; -- x
end loop; -- y
end if;
QxDN <= varq;
end process p_new;
-------------------------------------------------------------------------------
-- Register is here now QxDP QxDN
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Select a vector to operate on. The shift is implicit in here
-------------------------------------------------------------------------------
p_selq: process (QxDP, SubRndxSI)
begin -- process p_selp
-- we have to change the numbering here, since it is after the register 0
-- became 1 etc.
case SubRndxSI is
when 1 => RQxD <= QxDP(1,0) & QxDP(3,1) & QxDP(5,2) & QxDP(7,3) & QxDP(0,4) & QxDP(2,5) & QxDP(4,6) & QxDP(6,7);
when 2 => RQxD <= QxDP(2,0) & QxDP(4,1) & QxDP(6,2) & QxDP(0,3) & QxDP(1,4) & QxDP(3,5) & QxDP(5,6) & QxDP(7,7);
when 3 => RQxD <= QxDP(3,0) & QxDP(5,1) & QxDP(7,2) & QxDP(1,3) & QxDP(2,4) & QxDP(4,5) & QxDP(6,6) & QxDP(0,7);
when 4 => RQxD <= QxDP(4,0) & QxDP(6,1) & QxDP(0,2) & QxDP(2,3) & QxDP(3,4) & QxDP(5,5) & QxDP(7,6) & QxDP(1,7);
when 5 => RQxD <= QxDP(5,0) & QxDP(7,1) & QxDP(1,2) & QxDP(3,3) & QxDP(4,4) & QxDP(6,5) & QxDP(0,6) & QxDP(2,7);
when 6 => RQxD <= QxDP(6,0) & QxDP(0,1) & QxDP(2,2) & QxDP(4,3) & QxDP(5,4) & QxDP(7,5) & QxDP(1,6) & QxDP(3,7);
when 7 => RQxD <= QxDP(7,0) & QxDP(1,1) & QxDP(3,2) & QxDP(5,3) & QxDP(6,4) & QxDP(0,5) & QxDP(2,6) & QxDP(4,7);
when others => RQxD <= QxDP(0,0) & QxDP(2,1) & QxDP(4,2) & QxDP(6,3) & QxDP(7,4) & QxDP(1,5) & QxDP(3,6) & QxDP(5,7);
end case;
end process p_selq;
-------------------------------------------------------------------------------
-- 8 x Sub bytes on this vector
-------------------------------------------------------------------------------
gen_q_sub: for i in 0 to 7 generate
i_subbytes: groestl_subbytes port map (DxDI => RQxD( (i*8) +7 downto i*8),
DxDO => SQxD( (i*8) +7 downto i*8));
end generate gen_q_sub;
-------------------------------------------------------------------------------
-- We have a fixed MixBytes function. Normally the function is shifted, we will
-- shift the input data instead
-------------------------------------------------------------------------------
-- M1xD(0) SQxD;
-- M1xD(1) SQxD( 7 downto 0) & SQxD(63 downto 8);
-- M1xD(2) SQxD(15 downto 0) & SQxD(63 downto 16);
-- M1xD(3) SQxD(23 downto 0) & SQxD(63 downto 24);
-- M1xD(4) SQxD(31 downto 0) & SQxD(63 downto 32);
-- M1xD(5) SQxD(39 downto 0) & SQxD(63 downto 40);
-- M1xD(6) SQxD(47 downto 0) & SQxD(63 downto 48);
-- M1xD(7) SQxD(55 downto 0) & SQxD(63 downto 56);
M1xD(0) <= SQxD;
M1xD(1) <= SQxD(55 downto 0) & SQxD(63 downto 56);
M1xD(2) <= SQxD(47 downto 0) & SQxD(63 downto 48);
M1xD(3) <= SQxD(39 downto 0) & SQxD(63 downto 40);
M1xD(4) <= SQxD(31 downto 0) & SQxD(63 downto 32);
M1xD(5) <= SQxD(23 downto 0) & SQxD(63 downto 24);
M1xD(6) <= SQxD(15 downto 0) & SQxD(63 downto 16);
M1xD(7) <= SQxD( 7 downto 0) & SQxD(63 downto 8);
gen_q_mix: for i in 0 to 7 generate
i_mixbytes: g_mixbytes port map ( InxDI => M1xD(i),
OutxDO => MQxD(i));
end generate gen_q_mix;
-------------------------------------------------------------------------------
-- Write back Q
-------------------------------------------------------------------------------
p_shiftq: process (QxDP, SubRndxSI, MQxD)
variable varq : statematrix;
begin -- process p_selp
-- default
varq := QxDP; -- do not shift for the first 7 cycles;
-- changed the numbering here. This is after the register, SubRndxSI is 1
-- ahead here
case SubRndxSI is
when 1 => varq(1,0) := MQxD(0); varq(3,1) := MQxD(1); varq(5,2) := MQxD(2); varq(7,3) := MQxD(3);
varq(0,4) := MQxD(4); varq(2,5) := MQxD(5); varq(4,6) := MQxD(6); varq(6,7) := MQxD(7);
when 2 => varq(2,0) := MQxD(0); varq(4,1) := MQxD(1); varq(6,2) := MQxD(2); varq(0,3) := MQxD(3);
varq(1,4) := MQxD(4); varq(3,5) := MQxD(5); varq(5,6) := MQxD(6); varq(7,7) := MQxD(7);
when 3 => varq(3,0) := MQxD(0); varq(5,1) := MQxD(1); varq(7,2) := MQxD(2); varq(1,3) := MQxD(3);
varq(2,4) := MQxD(4); varq(4,5) := MQxD(5); varq(6,6) := MQxD(6); varq(0,7) := MQxD(7);
when 4 => varq(4,0) := MQxD(0); varq(6,1) := MQxD(1); varq(0,2) := MQxD(2); varq(2,3) := MQxD(3);
varq(3,4) := MQxD(4); varq(5,5) := MQxD(5); varq(7,6) := MQxD(6); varq(1,7) := MQxD(7);
when 5 => varq(5,0) := MQxD(0); varq(7,1) := MQxD(1); varq(1,2) := MQxD(2); varq(3,3) := MQxD(3);
varq(4,4) := MQxD(4); varq(6,5) := MQxD(5); varq(0,6) := MQxD(6); varq(2,7) := MQxD(7);
when 6 => varq(6,0) := MQxD(0); varq(0,1) := MQxD(1); varq(2,2) := MQxD(2); varq(4,3) := MQxD(3);
varq(5,4) := MQxD(4); varq(7,5) := MQxD(5); varq(1,6) := MQxD(6); varq(3,7) := MQxD(7);
when 7 => varq(7,0) := MQxD(0); varq(1,1) := MQxD(1); varq(3,2) := MQxD(2); varq(5,3) := MQxD(3);
varq(6,4) := MQxD(4); varq(0,5) := MQxD(5); varq(2,6) := MQxD(6); varq(4,7) := MQxD(7);
when others => -- We wait for the shift until the last
-- cycle. Now it iis time to shift all
-- values
for y in 0 to 7 loop
for x in 0 to 6 loop
varq(x,y) := QxDP((x+INCQ(y)) mod 8 , y);
end loop; -- x
varq(7,y) := MQxD(y);
end loop; -- y
end case;
Q1xD <= varq;
end process p_shiftq;
-------------------------------------------------------------------------------
-- Output
-------------------------------------------------------------------------------
p_out: process (Q1xD)
variable vout : std_logic_vector(511 downto 0);
begin -- process p_out
for y in 0 to 7 loop
for x in 0 to 7 loop
vout( ((7-x)*64) + ((7-y) * 8) + 7 downto ((7-x)*64) + ((7-y)*8) ) := Q1xD(x,y);
end loop; -- x
end loop; -- y
QFinxD <= vout;
end process p_out;
OutxDO <= QFinxD;
-- Memory
-----------------------------------------------------------------------------
p_mem : process (ClkxCI, RstxRBI)
begin -- process p_mem
if RstxRBI = '0' then -- asynchronous reset (active low)
QxDP <= (others => (others => (others => '0')));
elsif ClkxCI'event and ClkxCI = '1' then -- rising clock edge
QxDP <= QxDN;
end if;
end process p_mem;
end rtl;