------------------------------------------------------------ -- Copyright: 2011 Integrated Sytems Laboratory, ETH Zurich -- http://www.iis.ee.ethz.ch/~sha3 ------------------------------------------------------------ ------------------------------------------------------------------------------- -- Title : Input Block -- Project : Shabziger ------------------------------------------------------------------------------- -- File : inputblock.vhd -- Author : Frank K. Guerkaynak -- Company : Integrated Systems Laboratory, ETH Zurich -- Created : 2011-08-16 -- Last update: 2011-09-15 -- Platform : ModelSim (simulation), Synopsys (synthesis) -- Standard : VHDL'87 ------------------------------------------------------------------------------- -- Description: This generates up to 1088 bits for the input ------------------------------------------------------------------------------- -- Copyright (c) 2011 Integrated Systems Laboratory, ETH Zurich ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2011-08-16 1.0 kgf Created -- 2011-08-31 1.1 kgf Added some modifications for the GMU_GROESTL -- Made a hack for JH, it will delay the FinBlock -- by one cycle -- 2011-09-01 1.2 kgf Added the FuncScanEnxTI input. This is 1 when -- the Shabziger is in configuration mode -- 2011-09-15 2.0 kgf Added three more registers to make the backend -- a little bit easier ------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use work.shabzigerpkg.all; -- includes constants entity inputblock is port ( AlgSelxSI : in std_logic_vector(3 downto 0); ClkxCI : in std_logic; RstxRBI : in std_logic; FinBlockxSI : in std_logic; BlockPenUltCyclexSI : in std_logic; -- the block has one more cycle, -- time to act ! BlockInWrEnxSO : out std_logic; -- Handover the current block to out BlockFinBlockxSO : out std_logic; -- Last block in the message FuncScanEnxTI : in std_logic; -- Shabziger is loading configuration FuncScanInxTI : in std_logic; -- input of the functional scan FuncScanOutxTO : out std_logic; -- output of the functional scan MsgLenxDO : out std_logic_vector(63 downto 0); DataOutxDO : out std_logic_vector(1087 downto 0); Data2OutxDO : out std_logic_vector(511 downto 0); Data3OutxDO : out std_logic_vector(511 downto 0); Data4OutxDO : out std_logic_vector(63 downto 0)); end inputblock; architecture rtl of inputblock is ------------------------------------------------------------------------------- -- Components ------------------------------------------------------------------------------- component lfsr73 port ( ScanInxTI : in std_logic; ScanEnxTI : in std_logic; ScanOutxTO : out std_logic; DataOutxDO : out std_logic_vector (63 downto 0); ClkxCI : in std_logic; RstxRBI : in std_logic); end component; component padunit port ( DataInxDI : in std_logic_vector(1087 downto 0); DataOutxDO : out std_logic_vector(1087 downto 0); AlgSelxSI : in std_logic_vector(3 downto 0); DataCntxDI : in std_logic_vector(63 downto 0)); end component; ------------------------------------------------------------------------------- -- Signals ------------------------------------------------------------------------------- -- State machine type in_reg_states is (init,first,genvec,send, sleep, g_groestl1, g_groestl2); signal StatexDP, StatexDN : in_reg_states; -- LFSR connections signal LFSRxD : std_logic_vector(63 downto 0); signal LFSRScanOutxT : std_logic; -- Stitching the scan out chain -- Signals for determining the Round Cnt, how many LFSR rounds -- fills the input register signal IntAlgSelxS : integer range 0 to 15; -- Integer of AlgSelxSI signal FinalRndxD : integer range 0 to 16; -- Alg dependent signal RndCntxDP, RndCntxDN : integer range 0 to 31; -- Round Count for -- LFSR number kept -- high deliberately -- normally only up to -- 16 will be used. signal InitRndxS, RegFullxS : std_logic; -- control signals signal FinBlockxSN, FinBlockxSP : std_logic; -- we will keep them in a register -- Padding signal PaddedxD : std_logic_vector(1087 downto 0); -- This is the padded version of the data signal SelDataxD : std_logic_vector(1087 downto 0); -- Either PaddedxD or StoreDataxD will be selected -- DataCounter -- Count how many bits we have sent. signal MsgLenxDP, MsgLenxDN : unsigned(63 downto 0); -- Main signals -- We now have four registers each driving four algorithms -- DataxDP is still the main one driving keccak and sha2 -- Data2xDP is 512 bit drives Groestl and Blake -- Data3xDP is 512 bit drives JH and Skein -- Data4xDP is 64 bit drives RAM and Dummy signal DataxDP, DataxDN, StoreDataxD : std_logic_vector(1087 downto 0); signal Data2xDP, Data3xDP : std_logic_vector(511 downto 0); signal Data4xDP : std_logic_vector(63 downto 0); signal EnxS : std_logic_vector(16 downto 0); -- Hack for JH -- JH needs one additional cycle for padding. We will use message sizes of -- multiples of 512, meaning that there will be a full 512-bit block of padding -- always. -- In the current inputblock, this does not work, so we add this signal, -- which will switch to '1' when the FinalxSI is '1'. But the internal -- FinalxS signal will only activate the second time around signal JHFinalxSP, JHFinalxSN : std_logic; begin -- rtl ------------------------------------------------------------------------------- -- Store the value of FinBlockxSI ------------------------------------------------------------------------------- -- FinBlockxS also selects normal data or data from the padunit, so it is -- important that it stays constant throughout block processing -- We will change it (generally) at the send cycle (exception JH and GMU GROESTL) p_finblock : process (StatexDP, AlgSelxSI, FinBlockxSP, FinBlockxSI, JHFinalxSP) begin -- process p_finblock FinBlockxSN <= FinBlockxSP; -- by default keep the value JHFinalxSN <= JHFinalxSP; --------------------------------------------------------------------------- if (AlgSelxSI = GMUGROESTL) and (StatexDP = g_groestl2) then FinBlockxSN <= FinBlockxSI; -- GMU Groestl waits two cycles --------------------------------------------------------------------------- elsif (AlgSelxSI = ETHZJH) or (AlgSelxSI = GMUJH) then if StatexDP = send then -- time to decide if JHFinalxSP = '1' then -- do we a pending req FinBlockxSN <= '1'; -- activate the final block JHFinalxSN <= '0'; -- clear pending request elsif FinBlockxSI = '1' then -- is there a fin block FinBlockxSN <= '0'; -- not this cycle JHFinalxSN <= '1'; -- make sure it will come next cycle else FinBlockxSN <= '0'; -- this returns to zero JHFinalxSN <= '0'; -- this stays zero end if; end if; --------------------------------------------------------------------------- elsif (StatexDP = send) then -- other algorithms FinBlockxSN <= FinBlockxSI; -- copy FinBlockxSI end if; --------------------------------------------------------------------------- end process p_finblock; -- This was the simpler version GMU GROESTL and SHA 2 will need more cases -- FinBlockxSN FinBlockxSI when StatexDP = send else FinBlockxSP; ------------------------------------------------------------------------------- -- Calculating the RndCnt depending on the Algorithm ------------------------------------------------------------------------------- IntAlgSelxS <= to_integer(unsigned(AlgSelxSI)); -- makes life easier FinalRndxD <= NUMROUND(IntAlgSelxS); -- declared in shabzigerpkg -- This process calculates the round counter -- The last round is algorithm dependent p_rnd : process (InitRndxS, RndCntxDP, FinalRndxD) begin -- process p_rnd -- defaults RndCntxDN <= RndCntxDP + 1; -- count rounds up RegFullxS <= '0'; if RndCntxDP = FinalRndxD then -- we have reached last count RegFullxS <= '1'; -- we are done, the reg is full RndCntxDN <= RndCntxDP; -- keep the count end if; if InitRndxS = '1' then -- use this signal to initialize RndCntxDN <= 0; -- set back the round counter end if; end process p_rnd; -- This is a simple way of calculating the enable signals -- based on the round counter p_en : process (RndCntxDP, StatexDP) begin -- process p_en EnxS <= (others => '0'); -- per default enable nothing if StatexDP = genvec then -- if we are not done with the rounds EnxS(RndCntxDP) <= '1'; -- enable only one 64bit block end if; end process p_en; ------------------------------------------------------------------------------- -- Generating the control signals ------------------------------------------------------------------------------- -- this will not work for some of the blocks we have but it should do well -- for the majority of the blocks we have so far.. p_cont: process (FinBlockxSP, StatexDP, RegFullxS, BlockPenUltCyclexSI, AlgSelxSI, FuncScanEnxTI) begin -- process p_cont -- defaults StatexDN <= StatexDP; -- Keep the state BlockInWrEnxSO <= '0'; -- Enable the block BlockFinBlockxSO <= '0'; -- Signal that this is the last block InitRndxS <= '0'; -- Initialize the round counter case StatexDP is ----------------------------------------------------------------------- when init => StatexDN <= first; -- we need one cycle breather at the -- beginning.. GMU state machines -- depend on this ----------------------------------------------------------------------- when first => StatexDN <= genvec; InitRndxS <= '1'; BlockFinBlockxSO <= '1'; BlockInWrEnxSO <= '1'; ----------------------------------------------------------------------- when genvec => if RegFullxS='1' then -- We have the data, let us send it StatexDN <= sleep; end if; ----------------------------------------------------------------------- when sleep => -- assumes we will always be faster if BlockPenUltCyclexSI = '1' then -- wait till block is ready StatexDN <= send; end if; ----------------------------------------------------------------------- when send => BlockInWrEnxSO <= '1'; -- Send the data block if FinBlockxSP='1' then BlockFinBlockxSO <= '1'; -- This is the final block end if; if AlgSelxSI = GMUGROESTL then StatexDN <= g_groestl1; -- GMU implementation uses two -- additional cycle constant input else StatexDN <= genvec; -- directly generate a new block InitRndxS <= '1'; -- clear round counter end if; ----------------------------------------------------------------------- when g_groestl1 => -- first GROESTL GMU sleeper state StatexDN <= g_groestl2; ----------------------------------------------------------------------- when g_groestl2 => -- second gmu groestl sleeper state StatexDN <= genvec; -- directly generate a new block InitRndxS <= '1'; -- clear round counter ----------------------------------------------------------------------- when others => null; -- dummy not needed end case; -- we stay in init as long as Shabziger is in config mode -- This should only follow a reset if FuncScanEnxTI = '1' then StatexDN <= init; BlockInWrEnxSO <= '0'; BlockFinBlockxSO <= '0'; InitRndxS <= '0'; end if; end process p_cont; ------------------------------------------------------------------------------- -- The LFSR instantiation ------------------------------------------------------------------------------- i_lfsr: lfsr73 port map ( ScanInxTI => FuncScanInxTI, ScanEnxTI => FuncScanEnxTI, ScanOutxTO => LFSRScanOutxT, DataOutxDO => LFSRxD, ClkxCI => ClkxCI, RstxRBI => RstxRBI); ------------------------------------------------------------------------------- -- The Data counter (needed for blake, ) ------------------------------------------------------------------------------- p_data_cnt: process (StatexDP, IntAlgSelxS, MsgLenxDP, RegFullxS, FinBlockxSP, AlgSelxSI) begin -- process p_data_cnt MsgLenxDN <= MsgLenxDP; if StatexDP = genvec then -- when we do genvec if RegFullxS = '1' then -- just when we finish the input if FinBlockxSP = '1' then -- Last round or normal round MsgLenxDN <= MsgLenxDP + to_unsigned (BITSLASTROUND(IntAlgSelxS),16); else MsgLenxDN <= MsgLenxDP + to_unsigned (BITSPERROUND(IntAlgSelxS),16); end if; end if; elsif AlgSelxSI = GMUGROESTL then if StatexDP = g_groestl2 and FinBlockxSP = '1' then MsgLenxDN <= (others => '0'); end if; elsif StatexDP = send then if FinBlockxSP = '1' then MsgLenxDN <= (others => '0'); end if; end if; end process p_data_cnt; MsgLenxDO <= std_logic_vector(MsgLenxDP); -- final assignment ------------------------------------------------------------------------------- -- The register holding Input Data ------------------------------------------------------------------------------- -- handle the LFSR to data transfer p_nextdata: process (DataxDP, EnxS, LFSRxD) begin -- process p_nextdata StoreDataxD <= DataxDP; -- by default don't change for i in 0 to 16 loop -- go through all 17 if EnxS(i)='1' then -- if Enable bit is set 1 downto i*64) <= LFSRxD; -- copy the value end if; end loop; -- i end process p_nextdata; ------------------------------------------------------------------------------- -- Here comes the part that will generate the padding ------------------------------------------------------------------------------- i_padunit: padunit port map ( DataInxDI => StoreDataxD, DataOutxDO => PaddedxD, AlgSelxSI => AlgSelxSI, DataCntxDI => std_logic_vector(MsgLenxDP)); SelDataxD <= PaddedxD when FinBlockxSP = '1' else StoreDataxD; -- Add the scan functionality DataxDN <= SelDataxD when FuncScanEnxTI = '0' else DataxDP(1086 downto 0) & LFSRScanOutxT; FuncScanOutxTO <= DataxDP(1087); -- purpose: memorizing process for the registers p_clk : process (ClkxCI, RstxRBI) begin -- process p_clk if RstxRBI = '0' then -- asynchronous reset (active low) DataxDP <= (others => '0'); Data2xDP <= (others => '0'); Data3xDP <= (others => '0'); Data4xDP <= (others => '0'); RndCntxDP <= 0; MsgLenxDP <= (others => '0'); StatexDP <= init; FinBlockxSP <= '1'; --init to '1' JHFinalxSP <= '0'; elsif ClkxCI'event and ClkxCI = '1' then -- rising clock edge DataxDP <= DataxDN; Data2xDP <= DataxDN(511 downto 0); Data3xDP <= DataxDN(511 downto 0); Data4xDP <= DataxDN(63 downto 0); RndCntxDP <= RndCntxDN; MsgLenxDP <= MsgLenxDN; StatexDP <= StatexDN; FinBlockxSP <= FinBlockxSN; JHFinalxSP <= JHFinalxSN; end if; end process p_clk; -- the output DataOutxDO <= DataxDP; -- 1088 main output Data2OutxDO <= Data2xDP; -- 512 bit replica Data3OutxDO <= Data3xDP; -- 512 bit replica Data4OutxDO <= Data4xDP; -- 64 bit replica end rtl;