PCS-2/comp/jenkins_hash.vhd
2023-12-03 19:31:49 +01:00

149 lines
5.8 KiB
VHDL

-- jenkins_hash.vhd: Jenkins hashing function VHDL implementation based on https://burtleburtle.net/bob/c/lookup3.c
-- Copyright (C) 2019 FIT BUT
-- Author(s): Lukas Kekely <ikekely@fit.vutbr.cz>
--
-- SPDX-License-Identifier: BSD-3-Clause
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
entity jenkins_hash is
generic(
-- Width of hashed key in 32-bit words.
LENGTH : natural := 1;
-- Initialization seed value.
INITVAL : std_logic_vector(32-1 downto 0) := X"DEADBABE"
);
port (
-- Main clock signal and its synchronous reset.
CLK : in std_logic;
RESET : in std_logic;
-- Input interface ---------------------------------------------------------
INPUT_KEY : in std_logic_vector(LENGTH*32-1 downto 0); -- value to be hashed
INPUT_VALID : in std_logic; -- key valid
-- Output interface --------------------------------------------------------
OUTPUT_HASH : out std_logic_vector(32-1 downto 0); -- computed hash value
OUTPUT_KEY : out std_logic_vector(LENGTH*32-1 downto 0); -- delayed input key
OUTPUT_VALID : out std_logic -- delayed input valid
);
end entity;
architecture behavioral of jenkins_hash is
constant MIX_STAGES : integer := (LENGTH-1) / 3;
constant FINAL_LENGTH : integer := LENGTH - MIX_STAGES*3;
constant INITIAL_VALUE : std_logic_vector(32-1 downto 0) := X"deadbeef" + conv_std_logic_vector(LENGTH*4, 32) + INITVAL;
type computation_stage is record
a : std_logic_vector(32-1 downto 0);
b : std_logic_vector(32-1 downto 0);
c : std_logic_vector(32-1 downto 0);
key : std_logic_vector(LENGTH*32-1 downto 0);
valid : std_logic;
end record;
type computation_stage_array is array(natural range <>) of computation_stage;
signal mix_stage : computation_stage_array(0 to MIX_STAGES);
signal mix_to_final : computation_stage;
signal final_adders : computation_stage;
signal final_key_part : std_logic_vector(FINAL_LENGTH*32-1 downto 0);
begin
-- Unsupported configurations checks -----------------------------------------
assert LENGTH > 0 report "FAILURE: Jenkins Hash key must be at least one word wide!" severity failure;
-- Set up the internal state -------------------------------------------------
mix_stage(0).a <= INITIAL_VALUE;
mix_stage(0).b <= INITIAL_VALUE;
mix_stage(0).c <= INITIAL_VALUE;
mix_stage(0).key <= INPUT_KEY;
mix_stage(0).valid <= INPUT_VALID;
-- Handle most of the key ----------------------------------------------------
mix_pipeline: for s in 0 to MIX_STAGES-1 generate
signal local_key_part : std_logic_vector(3*32-1 downto 0);
signal adders : computation_stage;
begin
-- initial adding with key words
local_key_part <= mix_stage(s).key(3*32*(s+1)-1 downto 3*32*s);
adders.a <= mix_stage(s).a + local_key_part(32-1 downto 0);
adders.b <= mix_stage(s).b + local_key_part(64-1 downto 32);
adders.c <= mix_stage(s).c + local_key_part(96-1 downto 64);
adders.key <= mix_stage(s).key;
adders.valid <= mix_stage(s).valid;
-- mixing operation itself
mix: entity work.jenkins_mix
generic map (
LENGTH => LENGTH
) port map (
CLK => CLK,
RESET => RESET,
INPUT_A => adders.a,
INPUT_B => adders.b,
INPUT_C => adders.c,
INPUT_KEY => adders.key,
INPUT_VALID => adders.valid,
OUTPUT_A => mix_stage(s+1).a, -- output dirrectly to the next stage
OUTPUT_B => mix_stage(s+1).b,
OUTPUT_C => mix_stage(s+1).c,
OUTPUT_KEY => mix_stage(s+1).key,
OUTPUT_VALID => mix_stage(s+1).valid
);
end generate;
mix_to_final <= mix_stage(MIX_STAGES); -- output from the last mix stage is input for final
-- Handle the last 3 words ---------------------------------------------------
-- initial adding with key words for given length
final_key_part <= mix_to_final.key(LENGTH*32-1 downto LENGTH*32-FINAL_LENGTH*32);
final_length3: if FINAL_LENGTH = 3 generate
final_adders.c <= mix_to_final.c + final_key_part(96-1 downto 64);
final_adders.b <= mix_to_final.b + final_key_part(64-1 downto 32);
final_adders.a <= mix_to_final.a + final_key_part(32-1 downto 0);
end generate;
final_length2: if FINAL_LENGTH = 2 generate
final_adders.c <= mix_to_final.c;
final_adders.b <= mix_to_final.b + final_key_part(64-1 downto 32);
final_adders.a <= mix_to_final.a + final_key_part(32-1 downto 0);
end generate;
final_length1: if FINAL_LENGTH = 1 generate
final_adders.c <= mix_to_final.c;
final_adders.b <= mix_to_final.b;
final_adders.a <= mix_to_final.a + final_key_part(32-1 downto 0);
end generate;
final_length0: if FINAL_LENGTH = 0 generate
assert false report "FAILURE: Jenkins Hash impossible generate state reached in final stage!" severity failure;
end generate;
final_adders.key <= mix_to_final.key;
final_adders.valid <= mix_to_final.valid;
-- final operation itself
final: entity work.jenkins_final
generic map (
LENGTH => LENGTH
) port map (
CLK => CLK,
RESET => RESET,
INPUT_A => final_adders.a,
INPUT_B => final_adders.b,
INPUT_C => final_adders.c,
INPUT_KEY => final_adders.key,
INPUT_VALID => final_adders.valid,
OUTPUT_A => open, -- output dirrectly into hash output
OUTPUT_B => open,
OUTPUT_C => OUTPUT_HASH, -- C is returned as hash
OUTPUT_KEY => OUTPUT_KEY,
OUTPUT_VALID => OUTPUT_VALID
);
end architecture;