diff --git a/README.md b/README.md index 6ac388e..f53c92a 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,9 @@ The components in this repository are not intended for productional code. They serve as proof of concept, for example how to implement a pipeline using only (local) variables instead of (global) signals. Furthermore they were used how to do a VHDL-to-Verilog conversion for learning purposes. + +*HINT:* + +The tests of some algorithms use the OSVVM library, which is redistributed as +submodule. To get & initialize the submodule, please use the `--recursive` option +when cloning this repository. diff --git a/aes/sim/vhdl/Makefile b/aes/sim/vhdl/Makefile index 8773e1b..acd0f51 100644 --- a/aes/sim/vhdl/Makefile +++ b/aes/sim/vhdl/Makefile @@ -24,8 +24,10 @@ RTL_SRC := \ ../../rtl/vhdl/aes_enc.vhd \ ../../rtl/vhdl/aes_dec.vhd -SIM_SRC := \ - tb_aes.vhd +SIM_SRC := tb_aes.vhd +C_SRC := tb_aes.c +OSVVM_SRC := ../../../lib/OSVVM +VHD_STD := 08 .PHONY: sim @@ -36,13 +38,34 @@ sim: tb_aes.ghw compile: tb_aes -work: - mkdir work +osvvm work: + mkdir $@ -tb_aes: ${RTL_SRC} ${SIM_SRC} | work - ghdl -a --std=08 -fpsl --workdir=work ${RTL_SRC} ${SIM_SRC} - ghdl -e --std=08 -fpsl --workdir=work $@ +osvvm/OsvvmContext.o: $(OSVVM_SRC)/*.vhd | osvvm + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/NamePkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/OsvvmGlobalPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/VendorCovApiPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/TranscriptPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/TextUtilPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/AlertLogPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/MessagePkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/SortListPkg_int.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/RandomBasePkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/RandomPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/CoveragePkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/MemoryPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/ScoreboardGenericPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/ScoreboardPkg_slv.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/ScoreboardPkg_int.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/ResolutionPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/TbUtilPkg.vhd + ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC)/OsvvmContext.vhd + + +tb_aes: ${RTL_SRC} ${SIM_SRC} ${C_SRC} osvvm/OsvvmContext.o | work + ghdl -a --std=$(VHD_STD) -fpsl --workdir=work -P=osvvm ${RTL_SRC} ${SIM_SRC} + ghdl -e --std=$(VHD_STD) -fpsl --workdir=work -P=osvvm -Wl,-lcrypto -Wl,-lssl -Wl,tb_aes.c $@ tb_aes.ghw: tb_aes @@ -63,4 +86,5 @@ clean: rm -f *.o rm -f *.json rm -rf work/ + rm -rf osvvm/ diff --git a/aes/sim/vhdl/tb_aes.c b/aes/sim/vhdl/tb_aes.c new file mode 100644 index 0000000..4a4f458 --- /dev/null +++ b/aes/sim/vhdl/tb_aes.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include + +static const char HDL_LOGIC_CHAR[] = { 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'}; + +enum HDL_LOGIC_STATES { +HDL_U = 0, +HDL_X = 1, +HDL_0 = 2, +HDL_1 = 3, +HDL_Z = 4, +HDL_W = 5, +HDL_L = 6, +HDL_H = 7, +HDL_D = 8, +}; + + + +void slv_to_uchar(char* datain, unsigned char* dataout, int bytelen) { + + for (int i = 0; i < bytelen; i++) { + for (int y = 0; y < 8; y++) { + if (*datain == HDL_1) { + *dataout |= 1 << y; + } else if (*datain == HDL_0) { + *dataout &= ~(1 << y); + } + datain++; + } + dataout++; + } + + return; + +} + + +void slv_to_string(char* datain, char* dataout, int bytelen) { + + for (int i = 0; i < bytelen; i++) { + *dataout = HDL_LOGIC_CHAR[*datain]; + datain++; + dataout++; + } + + return; + +} + + +void uchar_to_slv(unsigned char* datain, char* dataout, int bytelen) { + + for (int i = 0; i < bytelen; i++) { + for (int y = 0; y < 8; y++) { + if ((*datain >> y) & 1 == 1) { + *dataout = HDL_1 ; + } else { + *dataout = HDL_0; + } + dataout++; + } + datain++; + } + + return; + +} + + +void handleErrors(void) +{ + ERR_print_errors_fp(stderr); + abort(); +} + + +int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, + unsigned char *ciphertext) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + int ciphertext_len; + + /* Create and initialise the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); + + /* + * Initialise the encryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL)) + handleErrors(); + + if(1 != EVP_CIPHER_CTX_set_padding(ctx, 0)) + handleErrors(); + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) + handleErrors(); + ciphertext_len = len; + + /* + * Finalise the encryption. Further ciphertext bytes may be written at + * this stage. + */ + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + handleErrors(); + ciphertext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return ciphertext_len; +} + + +void cryptData(char* datain, char* key, char mode, char* dataout, int len) { + + unsigned char c_data[len+1]; + unsigned char c_key[len+1]; + unsigned char c_data_e[len+1]; + int ciphertext_len; + + c_data[len] = 0; + c_key[len] = 0; + c_data_e[len] = 0; + + slv_to_uchar(datain, c_data, 16); + slv_to_uchar(key, c_key, 16); + + ciphertext_len = encrypt(c_data, 128/8, c_key, c_data_e); + + uchar_to_slv(c_data_e, dataout, 16); + + return; + +} diff --git a/aes/sim/vhdl/tb_aes.vhd b/aes/sim/vhdl/tb_aes.vhd index f740d2f..dafcaf6 100644 --- a/aes/sim/vhdl/tb_aes.vhd +++ b/aes/sim/vhdl/tb_aes.vhd @@ -22,6 +22,9 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +library osvvm; + use osvvm.RandomPkg.all; + use std.env.all; use work.aes_pkg.all; @@ -52,6 +55,27 @@ architecture rtl of tb_aes is signal s_validout_dec : std_logic; signal s_acceptin_dec : std_logic := '0'; + procedure cryptData(datain : in std_logic_vector(0 to 127); + key : in std_logic_vector(0 to 127); + mode : in boolean; + dataout : out std_logic_vector(0 to 127); + len : in integer) is + begin + report "VHPIDIRECT cryptData" severity failure; + end procedure; + + attribute foreign of cryptData: procedure is "VHPIDIRECT cryptData"; + + function swap (datain : std_logic_vector(0 to 127)) return std_logic_vector is + variable v_data : std_logic_vector(0 to 127); + begin + for i in 0 to 15 loop + for y in 0 to 7 loop + v_data((i*8)+y) := datain((i*8)+7-y); + end loop; + end loop; + return v_data; + end function; begin @@ -89,37 +113,52 @@ begin process is + variable v_key : std_logic_vector(0 to 127); + variable v_datain : std_logic_vector(0 to 127); + variable v_dataout : std_logic_vector(0 to 127); + variable v_random : RandomPType; begin + v_random.InitSeed(v_random'instance_name); wait until s_reset = '1'; - -- ENCRYPTION TEST + -- ENCRYPTION TESTs report "Test encryption"; - wait until rising_edge(s_clk); - s_validin_enc <= '1'; - s_key <= x"2b7e151628aed2a6abf7158809cf4f3c"; - s_datain <= x"3243f6a8885a308d313198a2e0370734"; - wait until s_acceptout_enc = '1' and rising_edge(s_clk); - s_validin_enc <= '0'; - wait until s_validout_enc = '1' and rising_edge(s_clk); - s_acceptin_enc <= '1'; - assert s_dataout_enc = x"3925841D02DC09FBDC118597196A0B32" - report "Encryption error" - severity failure; - s_datain <= s_dataout_enc; - wait until rising_edge(s_clk); - s_acceptin_enc <= '0'; - -- DECRYPTION TEST + for i in 0 to 63 loop + wait until rising_edge(s_clk); + s_validin_enc <= '1'; + v_key := v_random.RandSlv(128); + v_datain := v_random.RandSlv(128); + s_key <= v_key; + s_datain <= v_datain; + cryptData(swap(v_datain), swap(v_key), true, v_dataout, 128); + wait until s_acceptout_enc = '1' and rising_edge(s_clk); + s_validin_enc <= '0'; + wait until s_validout_enc = '1' and rising_edge(s_clk); + s_acceptin_enc <= '1'; + assert s_dataout_enc = swap(v_dataout) + report "Encryption error" + severity failure; + wait until rising_edge(s_clk); + s_acceptin_enc <= '0'; + end loop; + -- DECRYPTION TESTs report "Test decryption"; - wait until rising_edge(s_clk); - s_validin_dec <= '1'; - wait until s_acceptout_dec = '1' and rising_edge(s_clk); - s_validin_dec <= '0'; - wait until s_validout_dec = '1' and rising_edge(s_clk); - s_acceptin_dec <= '1'; - assert s_dataout_dec = x"3243f6a8885a308d313198a2e0370734" - report "Decryption error" - severity failure; - wait until rising_edge(s_clk); - s_acceptin_dec <= '0'; + for i in 0 to 63 loop + wait until rising_edge(s_clk); + s_validin_dec <= '1'; + v_key := x"2b7e151628aed2a6abf7158809cf4f3c"; + v_datain := x"3925841D02DC09FBDC118597196A0B32"; + s_key <= v_key; + s_datain <= v_datain; + wait until s_acceptout_dec = '1' and rising_edge(s_clk); + s_validin_dec <= '0'; + wait until s_validout_dec = '1' and rising_edge(s_clk); + s_acceptin_dec <= '1'; + assert s_dataout_dec = x"3243f6a8885a308d313198a2e0370734" + report "Decryption error" + severity failure; + wait until rising_edge(s_clk); + s_acceptin_dec <= '0'; + end loop; wait for 100 ns; report "Tests successful"; finish(0);