------------------------------------------------------------
-- Copyright: 2011 Integrated Sytems Laboratory, ETH Zurich
-- http://www.iis.ee.ethz.ch/~sha3
------------------------------------------------------------
-------------------------------------------------------------------------------
-- Title : The P round of Groestl
-- Project :
-------------------------------------------------------------------------------
-- File : greostl_p.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 Corrected many bugs
-- 2011-09-05 1.2 kgf Moved the register after the roundconstants to
-- reduce the input timing
-------------------------------------------------------------------------------
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
entity groestl_p 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_p;
architecture rtl of groestl_p 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 PxDP, PxDN, P1xD : statematrix;
signal RPxD : std_logic_vector(63 downto 0); -- selected column
signal SPxD : std_logic_vector(63 downto 0); -- after Subbytes
signal MPxD : statearray; -- after MixBytes
signal M1xD : minputtype;
signal PStartxD : std_logic_vector(511 downto 0); -- start of the Calculation
signal PFinxD : std_logic_vector(511 downto 0); -- end of the calculation
constant INCP : incconsttype := (0, 1, 2, 3, 4, 5, 6, 7); -- shift amounts for P
begin -- rtl
-------------------------------------------------------------------------------
-- New start either a fresh vector or a state round
-------------------------------------------------------------------------------
PStartxD <= InxDI when RndxSI = "00000000" else PFinxD;
p_new : process (SubRndxSI, RndxSI, P1xD, PStartxD)
variable varp : statematrix;
begin -- process p_new
varp := P1xD;
if SubRndxSI = 0 then -- Add round constant
varp(0, 0) := PStartxD(511 downto 504) xor x"00" xor RndxSI;
varp(1, 0) := PStartxD(447 downto 440) xor x"10" xor RndxSI;
varp(2, 0) := PStartxD(383 downto 376) xor x"20" xor RndxSI;
varp(3, 0) := PStartxD(319 downto 312) xor x"30" xor RndxSI;
varp(4, 0) := PStartxD(255 downto 248) xor x"40" xor RndxSI;
varp(5, 0) := PStartxD(191 downto 184) xor x"50" xor RndxSI;
varp(6, 0) := PStartxD(127 downto 120) xor x"60" xor RndxSI;
varp(7, 0) := PStartxD( 63 downto 56) xor x"70" xor RndxSI;
for y in 1 to 7 loop
for x in 0 to 7 loop
varp(x,y) := PStartxD((((7-x) * 64) + ((7-y) *8) + 7) downto ((7-x) * 64) + ((7-y) *8));
end loop; -- x
end loop; -- y
end if;
PxDN <= varp;
end process p_new;
-------------------------------------------------------------------------------
-- Register is here PxDP PxDN
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Select a vector to operate on. The shift is implicit in here
-------------------------------------------------------------------------------
-- note that the SubRndxSI is one cycle behind, the register is before this
p_selp: process (PxDP, SubRndxSI)
begin -- process p_selp
case SubRndxSI is
when 1 => RPxD <= PxDP(0,0) & PxDP(1,1) & PxDP(2,2) & PxDP(3,3) & PxDP(4,4) & PxDP(5,5) & PxDP(6,6) & PxDP(7,7);
when 2 => RPxD <= PxDP(1,0) & PxDP(2,1) & PxDP(3,2) & PxDP(4,3) & PxDP(5,4) & PxDP(6,5) & PxDP(7,6) & PxDP(0,7);
when 3 => RPxD <= PxDP(2,0) & PxDP(3,1) & PxDP(4,2) & PxDP(5,3) & PxDP(6,4) & PxDP(7,5) & PxDP(0,6) & PxDP(1,7);
when 4 => RPxD <= PxDP(3,0) & PxDP(4,1) & PxDP(5,2) & PxDP(6,3) & PxDP(7,4) & PxDP(0,5) & PxDP(1,6) & PxDP(2,7);
when 5 => RPxD <= PxDP(4,0) & PxDP(5,1) & PxDP(6,2) & PxDP(7,3) & PxDP(0,4) & PxDP(1,5) & PxDP(2,6) & PxDP(3,7);
when 6 => RPxD <= PxDP(5,0) & PxDP(6,1) & PxDP(7,2) & PxDP(0,3) & PxDP(1,4) & PxDP(2,5) & PxDP(3,6) & PxDP(4,7);
when 7 => RPxD <= PxDP(6,0) & PxDP(7,1) & PxDP(0,2) & PxDP(1,3) & PxDP(2,4) & PxDP(3,5) & PxDP(4,6) & PxDP(5,7);
when others => RPxD <= PxDP(7,0) & PxDP(0,1) & PxDP(1,2) & PxDP(2,3) & PxDP(3,4) & PxDP(4,5) & PxDP(5,6) & PxDP(6,7);
end case;
end process p_selp;
-------------------------------------------------------------------------------
-- 8 x Sub bytes on this vector
-------------------------------------------------------------------------------
gen_p_sub: for i in 0 to 7 generate
i_subbytes: groestl_subbytes port map (DxDI => RPxD( (i*8) +7 downto i*8),
DxDO => SPxD( (i*8) +7 downto i*8));
end generate gen_p_sub;
-------------------------------------------------------------------------------
-- We have a fixed MixBytes function. Normally the function is shifted, we will
-- shift the input data instead
-------------------------------------------------------------------------------
-- M1xD(0) SPxD;
-- M1xD(1) SPxD( 7 downto 0) & SPxD(63 downto 8);
-- M1xD(2) SPxD(15 downto 0) & SPxD(63 downto 16);
-- M1xD(3) SPxD(23 downto 0) & SPxD(63 downto 24);
-- M1xD(4) SPxD(31 downto 0) & SPxD(63 downto 32);
-- M1xD(5) SPxD(39 downto 0) & SPxD(63 downto 40);
-- M1xD(6) SPxD(47 downto 0) & SPxD(63 downto 48);
-- M1xD(7) SPxD(55 downto 0) & SPxD(63 downto 56);
M1xD(0) <= SPxD;
M1xD(1) <= SPxD(55 downto 0) & SPxD(63 downto 56);
M1xD(2) <= SPxD(47 downto 0) & SPxD(63 downto 48);
M1xD(3) <= SPxD(39 downto 0) & SPxD(63 downto 40);
M1xD(4) <= SPxD(31 downto 0) & SPxD(63 downto 32);
M1xD(5) <= SPxD(23 downto 0) & SPxD(63 downto 24);
M1xD(6) <= SPxD(15 downto 0) & SPxD(63 downto 16);
M1xD(7) <= SPxD( 7 downto 0) & SPxD(63 downto 8);
gen_p_mix: for i in 0 to 7 generate
i_mixbytes: g_mixbytes port map ( InxDI => M1xD(i),
OutxDO => MPxD(i));
end generate gen_p_mix;
-------------------------------------------------------------------------------
-- Write back P
-------------------------------------------------------------------------------
p_shiftp: process (PxDP, SubRndxSI, MPxD)
variable varb: statematrix;
begin -- process p_selp
-- default
varb := PxDP; -- do not shift for the first 7 cycles;
-- note that the SubRndxSI is one cycle behind, the register is before this
case SubRndxSI is
when 1 => varb(0,0) := MPxD(0); varb(1,1) := MPxD(1); varb(2,2) := MPxD(2); varb(3,3) := MPxD(3);
varb(4,4) := MPxD(4); varb(5,5) := MPxD(5); varb(6,6) := MPxD(6); varb(7,7) := MPxD(7);
when 2 => varb(1,0) := MPxD(0); varb(2,1) := MPxD(1); varb(3,2) := MPxD(2); varb(4,3) := MPxD(3);
varb(5,4) := MPxD(4); varb(6,5) := MPxD(5); varb(7,6) := MPxD(6); varb(0,7) := MPxD(7);
when 3 => varb(2,0) := MPxD(0); varb(3,1) := MPxD(1); varb(4,2) := MPxD(2); varb(5,3) := MPxD(3);
varb(6,4) := MPxD(4); varb(7,5) := MPxD(5); varb(0,6) := MPxD(6); varb(1,7) := MPxD(7);
when 4 => varb(3,0) := MPxD(0); varb(4,1) := MPxD(1); varb(5,2) := MPxD(2); varb(6,3) := MPxD(3);
varb(7,4) := MPxD(4); varb(0,5) := MPxD(5); varb(1,6) := MPxD(6); varb(2,7) := MPxD(7);
when 5 => varb(4,0) := MPxD(0); varb(5,1) := MPxD(1); varb(6,2) := MPxD(2); varb(7,3) := MPxD(3);
varb(0,4) := MPxD(4); varb(1,5) := MPxD(5); varb(2,6) := MPxD(6); varb(3,7) := MPxD(7);
when 6 => varb(5,0) := MPxD(0); varb(6,1) := MPxD(1); varb(7,2) := MPxD(2); varb(0,3) := MPxD(3);
varb(1,4) := MPxD(4); varb(2,5) := MPxD(5); varb(3,6) := MPxD(6); varb(4,7) := MPxD(7);
when 7 => varb(6,0) := MPxD(0); varb(7,1) := MPxD(1); varb(0,2) := MPxD(2); varb(1,3) := MPxD(3);
varb(2,4) := MPxD(4); varb(3,5) := MPxD(5); varb(4,6) := MPxD(6); varb(5,7) := MPxD(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
varb(x,y) := PxDP((x+INCP(y)) mod 8 , y);
end loop; -- x
varb(7,y) := MPxD(y);
end loop; -- y
end case;
P1xD <= varb;
end process p_shiftp;
-------------------------------------------------------------------------------
-- Output
-------------------------------------------------------------------------------
p_out: process (P1xD)
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) ) := P1xD(x,y);
end loop; -- x
end loop; -- y
PFinxD <= vout;
end process p_out;
OutxDO <= PFinxD;
-- Memory
-----------------------------------------------------------------------------
p_mem : process (ClkxCI, RstxRBI)
begin -- process p_mem
if RstxRBI = '0' then -- asynchronous reset (active low)
PxDP <= (others => (others => (others => '0')));
elsif ClkxCI'event and ClkxCI = '1' then -- rising clock edge
PxDP <= PxDN;
end if;
end process p_mem;
end rtl;