From 66874e833ba377f3062cbfef1a52b092062f9390 Mon Sep 17 00:00:00 2001 From: Michael Boehmer Date: Tue, 19 Jul 2022 21:08:36 +0200 Subject: [PATCH] random forwarder test included --- gbe_trb/base/fwd_test.vhd | 174 ++++++++++++++++++++++ gbe_trb/base/fwd_test_random.vhd | 244 +++++++++++++++++++++++++++++++ gbe_trb/base/rng_trivium.vhd | 171 ++++++++++++++++++++++ 3 files changed, 589 insertions(+) create mode 100644 gbe_trb/base/fwd_test.vhd create mode 100644 gbe_trb/base/fwd_test_random.vhd create mode 100644 gbe_trb/base/rng_trivium.vhd diff --git a/gbe_trb/base/fwd_test.vhd b/gbe_trb/base/fwd_test.vhd new file mode 100644 index 0000000..baf6125 --- /dev/null +++ b/gbe_trb/base/fwd_test.vhd @@ -0,0 +1,174 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity fwd_test is + port( + CLK : in std_logic; + RESET : in std_logic; + -- + FWD_ENABLE_IN : in std_logic := '0'; + FWD_DELAY_IN : in std_logic_vector(15 downto 0) := x"0010"; + FWD_SIZE_IN : in std_logic_vector(15 downto 0) := x"0010"; + FWD_START_IN : in std_logic := '0'; + FWD_BUSY_OUT : out std_logic; + -- + FWD_READY_IN : in std_logic := '0'; + FWD_FULL_IN : in std_logic := '0'; + FWD_DATA_OUT : out std_logic_vector(7 downto 0); + FWD_DATA_VALID_OUT : out std_logic; + FWD_SOP_OUT : out std_logic; + FWD_EOP_OUT : out std_logic; + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity fwd_test; + +architecture fwd_test_arch of fwd_test is + +-- Components + +-- state machine signals + type state_t is (IDLE, START, DATA, CLEANUP, DELAY); + signal STATE, NEXT_STATE : state_t; + +-- Signals + signal sop_x : std_logic; + signal sop : std_logic; + signal eop_x : std_logic; + signal eop : std_logic; + signal rst_x : std_logic; + signal rst : std_logic; + + signal test_cnt : unsigned(15 downto 0); + signal test_data : unsigned(7 downto 0); + signal test_done_x : std_logic; + signal test_done : std_logic; + signal test_ce_x : std_logic; + signal delay_ce_x : std_logic; + +begin + + ----------------------------------------------------------- + -- Test data generator + ----------------------------------------------------------- + THE_TEST_DATA_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( (RESET = '1') or (sop = '1') ) then + test_data <= (others => '0'); + elsif( test_ce_x = '1' ) then + test_data <= test_data + 1; + end if; + end if; + end process THE_TEST_DATA_PROC; + + test_ce_x <= '1' when ((STATE = DATA) and (FWD_FULL_IN = '0')) + else '0'; + + FWD_DATA_OUT <= std_logic_vector(test_data); + + FWD_DATA_VALID_OUT <= test_ce_x; + + ----------------------------------------------------------- + -- Test counter + ----------------------------------------------------------- + THE_TEST_CNT_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + test_cnt <= (others => '1'); + elsif( sop = '1' ) then + test_cnt <= unsigned(FWD_SIZE_IN); + elsif( rst = '1' ) then + test_cnt <= unsigned(FWD_DELAY_IN); + elsif( (test_ce_x = '1') or (delay_ce_x = '1') ) then + test_cnt <= test_cnt - 1; + end if; + end if; + end process THE_TEST_CNT_PROC; + + delay_ce_x <= '1' when (STATE = DELAY) else '0'; + + test_done_x <= '1' when (test_cnt = x"0001") else '0'; + + test_done <= test_done_x when rising_edge(CLK); + + eop_x <= '1' when ((test_cnt = x"0001") and (STATE = DATA)) else '0'; + + eop <= eop_x when rising_edge(CLK); + + ----------------------------------------------------------- + -- statemachine: clocked process + ----------------------------------------------------------- + THE_FSM: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + STATE <= IDLE; + sop <= '0'; + rst <= '0'; + else + STATE <= NEXT_STATE; + sop <= sop_x; + rst <= rst_x; + end if; + end if; + end process THE_FSM; + + ----------------------------------------------------------- + -- + ----------------------------------------------------------- + THE_STATE_TRANSITIONS: process( STATE, FWD_ENABLE_IN, FWD_START_IN, test_done ) + begin + sop_x <= '0'; + rst_x <= '0'; + + case STATE is + + when IDLE => + if( (FWD_ENABLE_IN = '1') and (FWD_START_IN = '1') and (FWD_READY_IN = '1') and (FWD_FULL_IN = '0') ) then + NEXT_STATE <= START; + sop_x <= '1'; + else + NEXT_STATE <= IDLE; + end if; + + when START => + if( FWD_FULL_IN = '0' ) then + NEXT_STATE <= DATA; + else + NEXT_STATE <= START; + end if; + + when DATA => + if( test_done = '1' ) then + NEXT_STATE <= CLEANUP; + rst_x <= '1'; + else + NEXT_STATE <= DATA; + end if; + + when CLEANUP => + NEXT_STATE <= DELAY; + + when DELAY => + if( test_done = '1' ) then + NEXT_STATE <= IDLE; + else + NEXT_STATE <= DELAY; + end if; + + when others => + NEXT_STATE <= IDLE; + end case; + end process THE_STATE_TRANSITIONS; + + FWD_SOP_OUT <= sop; + FWD_EOP_OUT <= eop; + + FWD_BUSY_OUT <= '1' when (STATE /= IDLE) else '0'; + +end architecture; diff --git a/gbe_trb/base/fwd_test_random.vhd b/gbe_trb/base/fwd_test_random.vhd new file mode 100644 index 0000000..57f23d5 --- /dev/null +++ b/gbe_trb/base/fwd_test_random.vhd @@ -0,0 +1,244 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +entity fwd_test_random is + port( + CLK : in std_logic; + RESET : in std_logic; + -- + FWD_ENABLE_IN : in std_logic := '0'; + FWD_DELAY_IN : in std_logic_vector(15 downto 0) := x"0000"; + FWD_START_IN : in std_logic := '0'; + FWD_BUSY_OUT : out std_logic; + -- + FWD_READY_IN : in std_logic := '0'; + FWD_FULL_IN : in std_logic := '0'; + FWD_DATA_OUT : out std_logic_vector(7 downto 0); + FWD_DATA_VALID_OUT : out std_logic; + FWD_SOP_OUT : out std_logic; + FWD_EOP_OUT : out std_logic; + -- + DEBUG : out std_logic_vector(15 downto 0) + ); +end entity fwd_test_random; + +architecture fwd_test_random_arch of fwd_test_random is + +-- Components + component rng_trivium is + generic( + NUM_BITS: integer range 1 to 64 := 32; + -- Default key. + INIT_KEY: std_logic_vector(79 downto 0) := x"00000000000000000000"; + INIT_IV: std_logic_vector(79 downto 0) := x"00000000000000000000" + ); + port( + CLK : in std_logic; + RESET : in std_logic; + RESEED_IN : in std_logic; + NEWKEY_IN : in std_logic_vector(79 downto 0); + NEWIV_IN : in std_logic_vector(79 downto 0); + READY_IN : in std_logic; + VALID_OUT : out std_logic; + DATA_OUT : out std_logic_vector(NUM_BITS-1 downto 0) + ); + end component rng_trivium; + +-- state machine signals + type state_t is (IDLE, START, FLH, FLL, DATA, CLEANUP, DELAY); + signal STATE, NEXT_STATE : state_t; + +-- Signals + signal sop_x : std_logic; + signal sop : std_logic; + signal eop_x : std_logic; + signal eop : std_logic; + signal rst_x : std_logic; + signal rst : std_logic; + + signal frame_len : std_logic_vector(15 downto 0); + + signal test_cnt : unsigned(15 downto 0); + signal test_data : std_logic_vector(15 downto 0); + signal test_done_x : std_logic; + signal test_done : std_logic; + signal test_ce_x : std_logic; + signal delay_ce_x : std_logic; + + signal data_valid_x : std_logic; + +begin + + ----------------------------------------------------------- + -- Test data generator + ----------------------------------------------------------- + THE_PRNG: rng_trivium + generic map( + NUM_BITS => 16, + INIT_KEY => x"00000000000000000000", + INIT_IV => x"00000000000000000000" + ) + port map( + CLK => CLK, + RESET => RESET, + RESEED_IN => '0', + NEWKEY_IN => (others => '0'), + NEWIV_IN => (others => '0'), + READY_IN => test_ce_x, + VALID_OUT => open, + DATA_OUT => test_data + ); + + -- store the random frame length + THE_FL_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + frame_len <= (others => '0'); + elsif( sop = '1' ) then + frame_len <= b"00000" & test_data(8 downto 0) & b"11"; + end if; + end if; + end process THE_FL_PROC; + + -- TAKE CARE HERE: we write two bytes "length"... must be considered carefully. + + -- new PRNG data is produced when we are idle and in case we wrote a byte + test_ce_x <= '1' when ((STATE = IDLE) or (data_valid_x = '1')) + else '0'; + + -- test data is only written when we are ready + data_valid_x <= '1' when ((STATE = DATA) or (STATE = FLH) or (STATE = FLL)) and (FWD_FULL_IN = '0') + else '0'; + + -- multiplex output data + FWD_DATA_OUT <= frame_len(15 downto 8) when (STATE = FLH) else + frame_len(7 downto 0) when (STATE = FLL) else + test_data(7 downto 0) when (STATE = DATA); + + -- write signal for next stage + FWD_DATA_VALID_OUT <= data_valid_x; + +-------------------------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------------------------- + + + + ----------------------------------------------------------- + -- Test counter + ----------------------------------------------------------- + THE_TEST_CNT_PROC: process( CLK ) + begin + if( rising_edge(CLK) ) then + if ( RESET = '1' ) then + test_cnt <= (others => '1'); + elsif( sop = '1' ) then + test_cnt <= unsigned(b"00000" & test_data(8 downto 0) & b"11"); + elsif( rst = '1' ) then + test_cnt <= unsigned(FWD_DELAY_IN); + elsif( (data_valid_x = '1') or (delay_ce_x = '1') ) then + test_cnt <= test_cnt - 1; + end if; + end if; + end process THE_TEST_CNT_PROC; + + delay_ce_x <= '1' when (STATE = DELAY) else '0'; + + test_done_x <= '1' when (test_cnt = x"0000") else '0'; + + test_done <= test_done_x when rising_edge(CLK); + + eop_x <= '1' when ((test_cnt = x"0000") and (STATE = DATA)) else '0'; + + eop <= eop_x when rising_edge(CLK); + + ----------------------------------------------------------- + -- statemachine: clocked process + ----------------------------------------------------------- + THE_FSM: process( CLK ) + begin + if( rising_edge(CLK) ) then + if( RESET = '1' ) then + STATE <= IDLE; + sop <= '0'; + rst <= '0'; + else + STATE <= NEXT_STATE; + sop <= sop_x; + rst <= rst_x; + end if; + end if; + end process THE_FSM; + + ----------------------------------------------------------- + -- + ----------------------------------------------------------- + THE_STATE_TRANSITIONS: process( STATE, FWD_ENABLE_IN, FWD_START_IN, test_done ) + begin + sop_x <= '0'; + rst_x <= '0'; + + case STATE is + + when IDLE => + if( (FWD_ENABLE_IN = '1') and (FWD_START_IN = '1') and (FWD_READY_IN = '1') and (FWD_FULL_IN = '0') ) then + NEXT_STATE <= START; + sop_x <= '1'; + else + NEXT_STATE <= IDLE; + end if; + + when START => + if( FWD_FULL_IN = '0' ) then + NEXT_STATE <= FLH; + else + NEXT_STATE <= START; + end if; + + when FLH => + if( FWD_FULL_IN = '0' ) then + NEXT_STATE <= FLL; + else + NEXT_STATE <= FLH; + end if; + + when FLL => + if( FWD_FULL_IN = '0' ) then + NEXT_STATE <= DATA; + else + NEXT_STATE <= FLL; + end if; + + when DATA => + if( test_done = '1' ) then + NEXT_STATE <= CLEANUP; + rst_x <= '1'; + else + NEXT_STATE <= DATA; + end if; + + when CLEANUP => + NEXT_STATE <= DELAY; + + when DELAY => + if( test_done = '1' ) then + NEXT_STATE <= IDLE; + else + NEXT_STATE <= DELAY; + end if; + + when others => + NEXT_STATE <= IDLE; + end case; + end process THE_STATE_TRANSITIONS; + + FWD_SOP_OUT <= sop; + FWD_EOP_OUT <= eop; + + FWD_BUSY_OUT <= '1' when (STATE /= IDLE) else '0'; + +end architecture; diff --git a/gbe_trb/base/rng_trivium.vhd b/gbe_trb/base/rng_trivium.vhd new file mode 100644 index 0000000..f94165f --- /dev/null +++ b/gbe_trb/base/rng_trivium.vhd @@ -0,0 +1,171 @@ +-- +-- Pseudo Random Number Generator "Trivium". +-- +-- Author: Joris van Rantwijk +-- +-- This is a pseudo-random number generator in synthesizable VHDL. +-- The generator produces up to 64 new random bits on every clock cycle. +-- +-- The algorithm "Trivium" is by Christophe De Canniere and Bart Preneel. +-- See also: +-- C. De Canniere, B. Preneel, "Trivium Specifications", +-- http://www.ecrypt.eu.org/stream/p3ciphers/trivium/trivium_p3.pdf +-- +-- The eSTREAM portfolio page for Trivium: +-- http://www.ecrypt.eu.org/stream/e2-trivium.html +-- +-- The generator requires an 80-bit key and an 80-bit initialization +-- vector. Defaults for these values must be supplied at compile time +-- and will be used to initialize the generator at reset. The generator +-- also supports re-keying at run time. +-- +-- After reset and after re-seeding, at least (1152/num_bits) clock cycles +-- are needed before valid random data appears on the output. +-- +-- NOTE: This generator is designed to produce up to 2**64 bits +-- of secure random data. If more than 2**64 bits are generated +-- with the same key and IV, it becomes inceasingly likely that +-- the output contains patterns and correlations. +-- + +-- +-- Copyright (C) 2016 Joris van Rantwijk +-- +-- This code is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public +-- License as published by the Free Software Foundation; either +-- version 2.1 of the License, or (at your option) any later version. +-- +-- See +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity rng_trivium is + generic( + NUM_BITS: integer range 1 to 64 := 32; + -- Default key. + INIT_KEY: std_logic_vector(79 downto 0) := x"00000000000000000000"; + INIT_IV: std_logic_vector(79 downto 0) := x"00000000000000000000" + ); + port( + CLK : in std_logic; + RESET : in std_logic; + RESEED_IN : in std_logic; + NEWKEY_IN : in std_logic_vector(79 downto 0); + NEWIV_IN : in std_logic_vector(79 downto 0); + READY_IN : in std_logic; + VALID_OUT : out std_logic; + DATA_OUT : out std_logic_vector(NUM_BITS-1 downto 0) + ); +end entity; + +architecture trivium_arch of rng_trivium is + -- Prepare initial state vector for given key and IV. + -- + -- NOTE: Elements 0 .. 79 from the key vector are mapped to + -- to state elements s_80 .. s_1. + -- Elements 0 .. 79 from the IV vector are mapped + -- to state elements s_173 .. s_94. + -- + -- This deviates from the original Trivium specification + -- but is in line with the phase-3, API-compliant implementation + -- of Trivium as published on the ECRYPT website. + -- + function make_initial_state(nkey, niv: in std_logic_vector) + return std_logic_vector + is + variable s: std_logic_vector(287 downto 0); + begin + assert nkey'length = 80; + assert niv'length = 80; + + s := (others => '0'); + + for k in 0 to 79 loop + s(79-k) := nkey(k); + end loop; + + for k in 0 to 79 loop + s(93+79-k) := niv(k); + end loop; + + s(288-1 downto 288-3) := "111"; + + return s; + end function; + + signal reg_state : std_logic_vector(287 downto 0) := make_initial_state(INIT_KEY, INIT_IV); + signal reg_valid_wait : unsigned(10 downto 0) := (others => '0'); + signal reg_valid : std_logic := '0'; + signal reg_output : std_logic_vector(NUM_BITS-1 downto 0); + +begin + + -- Check that num_bits is a power of 2. + assert (64 / NUM_BITS) * NUM_BITS = 64; + + -- Drive output signal. + VALID_OUT <= reg_valid; + DATA_OUT <= reg_output; + + -- Synchronous process. + process( CLK ) is + variable t1, t2, t3: std_logic_vector(NUM_BITS-1 downto 0); + begin + if rising_edge(CLK) then + -- Determine valid output state. + -- Delay by 4*288/num_bits clock cycles after re-seeding. + if reg_valid_wait = 4*288/NUM_BITS then + reg_valid <= '1'; + end if; + + if reg_valid = '0' then + reg_valid_wait <= reg_valid_wait + 1; + end if; + + if READY_IN = '1' or reg_valid = '0' then + -- Prepare output word. + t1 := reg_state(66-1 downto 66-NUM_BITS) xor reg_state(93-1 downto 93-NUM_BITS); + t2 := reg_state(162-1 downto 162-NUM_BITS) xor reg_state(177-1 downto 177-NUM_BITS); + t3 := reg_state(243-1 downto 243-NUM_BITS) xor reg_state(288-1 downto 288-NUM_BITS); + + -- Create output word such that index 0 of the output + -- contains the earliest-generated bit and index (num_bits-1) + -- of the output contains the last-generated bit. + for k in 0 to NUM_BITS-1 loop + reg_output(NUM_BITS-1-k) <= t1(k) xor t2(k) xor t3(k); + end loop; + + -- Update internal state. + t1 := t1 xor (reg_state(91-1 downto 91-NUM_BITS) and reg_state(92-1 downto 92-NUM_BITS)) xor reg_state(171-1 downto 171-NUM_BITS); + t2 := t2 xor (reg_state(175-1 downto 175-NUM_BITS) and reg_state(176-1 downto 176-NUM_BITS)) xor reg_state(264-1 downto 264-NUM_BITS); + t3 := t3 xor (reg_state(286-1 downto 286-NUM_BITS) and reg_state(287-1 downto 287-NUM_BITS)) xor reg_state(69-1 downto 69-NUM_BITS); + + reg_state(93-1 downto 0) <= reg_state(93-1-NUM_BITS downto 0) & t3; + reg_state(177-1 downto 94-1) <= reg_state(177-1-NUM_BITS downto 94-1) & t1; + reg_state(288-1 downto 178-1) <= reg_state(288-1-NUM_BITS downto 178-1) & t2; + end if; + + -- Re-seed function. + if RESEED_IN = '1' then + reg_valid <= '0'; + reg_valid_wait <= (others => '0'); + reg_state <= make_initial_state(NEWKEY_IN, NEWIV_IN); + end if; + + -- Synchronous reset. + if RESET = '1' then + reg_valid <= '0'; + reg_valid_wait <= (others => '0'); + reg_state <= make_initial_state(INIT_KEY, INIT_IV); + reg_output <= (others => '0'); + end if; + + end if; + end process; + +end architecture; + -- 2.43.0