//====================================================================== // // tb_sha3.v // ----------------------------- // Testbench for the SHA-3 core. // // Authors: Pavel Shatov, Joachim Strombergson, Pernd Paysan // Copyright (c) 2015, 2017 NORDUnet A/S // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // - Neither the name of the NORDUnet nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //====================================================================== module tb_sha3(); //---------------------------------------------------------------- // Hashes of empty messages //---------------------------------------------------------------- localparam [511:0] SHA3_224_EMPTY_MSG = { 224'h6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7, {512-224{1'bX}}}; localparam [511:0] SHA3_256_EMPTY_MSG = { 256'ha7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a, {512-256{1'bX}}}; localparam [511:0] SHA3_384_EMPTY_MSG = { 384'h0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004, {512-384{1'bX}}}; localparam [511:0] SHA3_512_EMPTY_MSG = { 512'ha69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26}; /* * The "short" message is the "abc" string (0x616263): * * https://www.di-mgt.com.au/sha_testvectors.html * */ localparam [511:0] SHA3_224_SHORT_MSG = { 224'he642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf, {512-224{1'bX}}}; localparam [511:0] SHA3_256_SHORT_MSG = { 256'h3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532, {512-256{1'bX}}}; localparam [511:0] SHA3_384_SHORT_MSG = { 384'hec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25, {512-384{1'bX}}}; localparam [511:0] SHA3_512_SHORT_MSG = { 512'hb751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0}; /* * The "long" message is the 1600-bit string 0xA3...A3 taken from: * https://csrc.nist.gov/Projects/Cryptographic-Standards-and-Guidelines/example-values * */ localparam [511:0] SHA3_224_LONG_MSG = { 224'h9376816ABA503F72F96CE7EB65AC095DEEE3BE4BF9BBC2A1CB7E11E0, {512-224{1'bX}}}; localparam [511:0] SHA3_256_LONG_MSG = { 256'h79F38ADEC5C20307A98EF76E8324AFBFD46CFD81B22E3973C65FA1BD9DE31787, {512-256{1'bX}}}; localparam [511:0] SHA3_384_LONG_MSG = { 384'h1881DE2CA7E41EF95DC4732B8F5F002B189CC1E42B74168ED1732649CE1DBCDD76197A31FD55EE989F2D7050DD473E8F, {512-384{1'bX}}}; localparam [511:0] SHA3_512_LONG_MSG = { 512'hE76DFAD22084A8B1467FCF2FFA58361BEC7628EDF5F3FDC0E4805DC48CAEECA81B7C13C30ADF52A3659584739A2DF46BE589C51CA1A4A8416DF6545A1CE8BA00}; /* * Sponge Parameters * */ `define SHA3_224_BLOCK_BITS 1152 `define SHA3_256_BLOCK_BITS 1088 `define SHA3_384_BLOCK_BITS 832 `define SHA3_512_BLOCK_BITS 576 `define SHA3_224_OUTPUT_BITS 224 `define SHA3_256_OUTPUT_BITS 256 `define SHA3_384_OUTPUT_BITS 384 `define SHA3_512_OUTPUT_BITS 512 //---------------------------------------------------------------- // Internal constant and parameter definitions. //---------------------------------------------------------------- parameter CLK_HALF_PERIOD = 2; parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD; //---------------------------------------------------------------- // Register and Wire declarations. //---------------------------------------------------------------- reg tb_clk; reg tb_rst_n; reg tb_we; reg [ 6:0] tb_addr; reg [31:0] tb_wr_data; reg tb_dut_init; reg tb_dut_next; wire [31:0] tb_rd_data; wire tb_rdy; integer i, j; integer num_err; integer total_bits; integer block_words, output_words; reg [511:0] hash_shreg; // output reg [31: 0] hash_word; // current output word reg mismatch; // error flag //---------------------------------------------------------------- // Device Under Test. //---------------------------------------------------------------- sha3 dut ( .clk (tb_clk), .nreset (tb_rst_n), .w (tb_we), .addr (tb_addr), .din (tb_wr_data), .dout (tb_rd_data), .init (tb_dut_init), .next (tb_dut_next), .ready (tb_rdy) ); //---------------------------------------------------------------- // clk_gen // // Clock generator process. //---------------------------------------------------------------- always begin : clk_gen #CLK_HALF_PERIOD tb_clk = ~tb_clk; end // clk_gen //---------------------------------------------------------------- // reset_dut() // // Toggles reset to force the DUT into a well defined state. //---------------------------------------------------------------- task reset_dut; begin $display("*** Toggling reset..."); tb_rst_n = 0; #(4 * CLK_HALF_PERIOD); tb_rst_n = 1; end endtask // reset_dut() //---------------------------------------------------------------- // init_sim() // // Initialize all counters and testbed functionality as well // as setting the DUT inputs to defined values. //---------------------------------------------------------------- task init_sim; begin tb_clk = 0; tb_rst_n = 0; tb_we = 0; tb_addr = 7'd0; tb_wr_data = 32'h0; tb_dut_init = 0; tb_dut_next = 0; end endtask // init_sim() //---------------------------------------------------------------- // test_empty_message() // // The first pritimive test that verifies what happens with an // empty input message. //---------------------------------------------------------------- task test_empty_message; input [511:0] correct_hash; // known-good hash input integer block_size; // block length (bits) input integer output_size; // output length (bits) begin $display("*** Testing %0d-bit hash (%0d-bit block)...", output_size, block_size); // number of words in block and output block_words = block_size >> 5; // block_words = block_length / 32 output_words = output_size >> 5; // output_words = output_length / 32 // wait for some time #(4*CLK_PERIOD); /* * Note, that we must wipe entire block buffer, because * it may contain leftovers from previous calculations! * We wipe the registers and apply padding at the same time. * */ for (i=0; i<50; i=i+1) begin case (i) 0: tb_wr_data = 32'h06000000; // ...0001 | 10 block_words-1: tb_wr_data = 32'h00000080; // 1000... default: tb_wr_data = 32'h00000000; endcase tb_addr = {1'b0, i[5:0]}; // increment address tb_we = 1; // enable writing #(CLK_PERIOD); end tb_addr = 'bX; tb_we = 0; /* run one absord-squeeze cycle */ sha3_sponge_pump_init(); // reset error counter mismatch = 0; // save the expected result hash_shreg = correct_hash; // now read and compare for (i=0; i> 5; // block_words = block_length / 32 output_words = output_size >> 5; // output_words = output_length / 32 // wait for some time #(4*CLK_PERIOD); /* * Note, that we must wipe entire internal state, because * it may contain leftovers from previous calculations! * We wipe the internal state, fill in the message (0x616263) * and apply padding all at once. * */ for (i=0; i<50; i=i+1) begin case (i) 0: tb_wr_data = 32'h61626306; // ...0001 | 10 | 'cba' block_words-1: tb_wr_data = 32'h00000080; // 1000... default: tb_wr_data = 32'h00000000; endcase tb_addr = {1'b0, i[5:0]}; // increment address tb_we = 1; // enable writing #(CLK_PERIOD); end tb_addr = 'bX; tb_we = 0; /* run one absord-squeeze cycle */ sha3_sponge_pump_init(); // reset error counter mismatch = 0; // save the expected result hash_shreg = correct_hash; // now read and compare for (i=0; i> 5; // block_words = block_length / 32 output_words = output_size >> 5; // output_words = output_length / 32 // wait for some time #(4*CLK_PERIOD); /* start filling the first block */ total_bits = 1600; /* * note, that we must wipe entire internal state, because * it may contain leftovers from previous calculations! */ for (i=0; i<50; i=i+1) begin tb_wr_data = (i < block_words) ? 32'hA3A3A3A3 : 32'h00000000; tb_addr = {1'b0, i[5:0]}; tb_we = 1; #(CLK_PERIOD); if (i < block_words) total_bits = total_bits - 32; end tb_addr = 'bX; tb_we = 0; /* run one absord-squeeze cycle */ sha3_sponge_pump_init(); // process remaining bits while (total_bits > -64) begin /* * note, that there's no need to fill entire bank now, * because x ^ 0 == x */ for (i=0; i 0) begin // message tb_wr_data = 32'hA3A3A3A3; tb_addr = {1'b0, i[5:0]}; tb_we = 1; #(CLK_PERIOD); total_bits = total_bits - 32; end else if (total_bits == 0) begin // padding tb_wr_data = 32'h06000000; tb_addr = {1'b0, i[5:0]}; tb_we = 1; #(CLK_PERIOD); total_bits = total_bits - 32; end else if (i == (block_words-1)) begin // more padding tb_wr_data = 32'h00000080; tb_addr = {1'b0, i[5:0]}; tb_we = 1; #(CLK_PERIOD); total_bits = total_bits - 32; end else begin // intermediate bytes tb_wr_data = 32'h00000000; tb_addr = {1'b0, i[5:0]}; tb_we = 1; #(CLK_PERIOD); end end tb_addr = 'bX; tb_we = 0; /* run one absord-squeeze cycle */ sha3_sponge_pump_next(); end // reset error counter mismatch = 0; // save the expected result hash_shreg = correct_hash; // now read and compare for (i=0; i