diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rtl/sha3.v | 86 | ||||
-rw-r--r-- | src/rtl/sha3_wrapper.v | 19 | ||||
-rw-r--r-- | src/tb/tb_sha3.v | 1130 |
3 files changed, 659 insertions, 576 deletions
diff --git a/src/rtl/sha3.v b/src/rtl/sha3.v index a8b41bc..31b6465 100644 --- a/src/rtl/sha3.v +++ b/src/rtl/sha3.v @@ -44,20 +44,23 @@ `define SHA3_NUM_ROUNDS 5'd24
module sha3( input wire clk,
- input wire nreset,
- input wire w,
- input wire [ 8:2] addr,
- input wire [32-1:0] din,
+ input wire nreset,
+ input wire w,
+ input wire [ 8:2] addr,
+ input wire [32-1:0] din,
output wire [32-1:0] dout,
- input wire init,
- input wire next,
- output wire ready);
+ input wire init,
+ input wire next,
+ input wire [ 1:0] mode,
+ output wire ready);
- /* The SHA-3 algorithm really wants everything to be little-endian,
+ /*
+ * The SHA-3 algorithm really wants everything to be little-endian,
* which is at odds with everything else in our system (including the
* register interface to sha3_wrapper). Rather than trying to rewrite
- * Bernd's beautiful code, we'll just byte-swap all I/O.
+ * Bernd's beautiful code, I'll isolate it in its own little-endian
+ * universe by byte-swapping all reads and writes.
*/
reg [31:0] dout_swap;
@@ -193,10 +196,69 @@ module sha3( input wire clk, round <= round + 'd1;
- end else if (init || next) begin
+ end else if (init) begin
+
+ /*
+ * I'd like to have something concise like this,
+ * but the tools don't like it.
+
+ for (i = 0; i < blksize[mode]; i = i + 1)
+ st[i] <= st[i];
+
+ for (i < blksize[mode]; i < 25; i = i + 1)
+ st[i] <= 64'h0;
+
+ */
+
+ case (mode)
+ 0: begin
+ for (i = 0; i < 18; i = i + 1)
+ st[i] <= blk[i];
+ for (i = 18; i < 25; i = i + 1)
+ st[i] <= 64'h0;
+ end
+ 1: begin
+ for (i = 0; i < 17; i = i + 1)
+ st[i] <= blk[i];
+ for (i = 17; i < 25; i = i + 1)
+ st[i] <= 64'h0;
+ end
+ 2: begin
+ for (i = 0; i < 13; i = i + 1)
+ st[i] <= blk[i];
+ for (i = 13; i < 25; i = i + 1)
+ st[i] <= 64'h0;
+ end
+ 3: begin
+ for (i = 0; i < 9; i = i + 1)
+ st[i] <= blk[i];
+ for (i = 9; i < 25; i = i + 1)
+ st[i] <= 64'h0;
+ end
+ endcase
- for (i=0; i<25; i=i+1)
- st[i] <= init ? blk[i] : st[i] ^ blk[i]; // init has priority over next
+ round <= 'd0;
+
+ end else if (next) begin
+
+ case (mode)
+ 0: begin
+ for (i = 0; i < 18; i = i + 1)
+ st[i] <= st[i] ^ blk[i];
+ end
+ 1: begin
+ for (i = 0; i < 17; i = i + 1)
+ st[i] <= st[i] ^ blk[i];
+ end
+ 2: begin
+ for (i = 0; i < 13; i = i + 1)
+ st[i] <= st[i] ^ blk[i];
+ end
+ 3: begin
+ for (i = 0; i < 9; i = i + 1)
+ st[i] <= st[i] ^ blk[i];
+ end
+ endcase
round <= 'd0;
diff --git a/src/rtl/sha3_wrapper.v b/src/rtl/sha3_wrapper.v index f3dc554..91223f8 100644 --- a/src/rtl/sha3_wrapper.v +++ b/src/rtl/sha3_wrapper.v @@ -73,6 +73,8 @@ module sha3_wrapper localparam CONTROL_INIT_BIT = 0; localparam CONTROL_NEXT_BIT = 1; + localparam CONTROL_MODE_LOW_BIT = 2; + localparam CONTROL_MODE_HIGH_BIT = 3; // localparam STATUS_READY_BIT = 0; -- hardcoded to always read 1 localparam STATUS_VALID_BIT = 1; @@ -85,8 +87,8 @@ module sha3_wrapper // // Registers // - reg [ 1:0] reg_control; - reg [ 1:0] reg_control_prev; + reg [ 3:0] reg_control; + reg [ 3:0] reg_control_prev; // @@ -98,6 +100,10 @@ module sha3_wrapper wire reg_control_next_posedge = reg_control[CONTROL_NEXT_BIT] & ~reg_control_prev[CONTROL_NEXT_BIT]; + wire [1:0] reg_control_mode_posedge = + reg_control[CONTROL_MODE_HIGH_BIT:CONTROL_MODE_LOW_BIT] & + ~reg_control_prev[CONTROL_MODE_HIGH_BIT:CONTROL_MODE_LOW_BIT]; + // // Wires @@ -115,6 +121,7 @@ module sha3_wrapper .init (reg_control_init_posedge), .next (reg_control_next_posedge), + .mode (reg_control_mode_posedge), .ready (reg_status_valid), @@ -136,7 +143,7 @@ module sha3_wrapper // always @(posedge clk) // - if (!rst_n) reg_control_prev <= 2'b00; + if (!rst_n) reg_control_prev <= 4'b00; else reg_control_prev <= reg_control; @@ -147,7 +154,7 @@ module sha3_wrapper // if (!rst_n) begin // - reg_control <= 2'b00; + reg_control <= 4'b00; // end else if (cs && we && (addr_msb == ADDR_MSB_REGS)) begin // @@ -155,7 +162,7 @@ module sha3_wrapper // case (addr_lsb) // - ADDR_CONTROL: reg_control <= write_data[CONTROL_NEXT_BIT:CONTROL_INIT_BIT]; + ADDR_CONTROL: reg_control <= write_data[CONTROL_MODE_HIGH_BIT:CONTROL_INIT_BIT]; // endcase // @@ -171,7 +178,7 @@ module sha3_wrapper ADDR_NAME0: tmp_read_data = CORE_NAME0; ADDR_NAME1: tmp_read_data = CORE_NAME1; ADDR_VERSION: tmp_read_data = CORE_VERSION; - ADDR_CONTROL: tmp_read_data = {{30{1'b0}}, reg_control}; + ADDR_CONTROL: tmp_read_data = {{28{1'b0}}, reg_control}; ADDR_STATUS: tmp_read_data = {{30{1'b0}}, reg_status_valid, 1'b1}; // default: tmp_read_data = 32'h00000000; diff --git a/src/tb/tb_sha3.v b/src/tb/tb_sha3.v index 5dd93c4..cd40ec4 100644 --- a/src/tb/tb_sha3.v +++ b/src/tb/tb_sha3.v @@ -37,567 +37,581 @@ //====================================================================== 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;
+ + + //---------------------------------------------------------------- + // 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 + +`define SHA3_224_MODE 0 +`define SHA3_256_MODE 1 +`define SHA3_384_MODE 2 +`define SHA3_512_MODE 3 + + + //---------------------------------------------------------------- + // 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; + reg [1:0] tb_dut_mode; + 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), + .mode (tb_dut_mode), + .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; + tb_dut_mode = 2'b0; + 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) + input integer mode; + + 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 + tb_dut_mode = mode; + #(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<output_words; i=i+1) begin + + tb_addr = {1'b1, i[5:0]}; + #(CLK_PERIOD); + + hash_word = tb_rd_data; + + $display(" *** hash_word[%0d]: reference = %08x, calculated = %08x", + i, hash_shreg[511-:32], hash_word); + + // compare + if (hash_shreg[511-:32] !== hash_word) begin + mismatch = 1; + num_err = num_err + 1; + end + + hash_shreg = {hash_shreg[511-32:0], {32{1'bX}}}; + end + + if (mismatch) $display(" *** Test failed."); + else $display(" *** Test passed."); + + end + + endtask // test_empty_message + + + //---------------------------------------------------------------- + // test_short_message() + // + // The second simple test that verifies what happens with an + // input message, that fits into just one block. + //---------------------------------------------------------------- + task test_short_message; + + input [511:0] correct_hash; // known-good hash + input integer block_size; // block length (bits) + input integer output_size; // output length (bits) + input integer mode; + + 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 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 + tb_dut_mode = mode; + #(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<output_words; i=i+1) begin + + tb_addr = {1'b1, i[5:0]}; + #(CLK_PERIOD); + + hash_word = tb_rd_data; + + $display(" *** hash_word[%0d]: reference = %08x, calculated = %08x", + i, hash_shreg[511-:32], hash_word); + + // compare + if (hash_shreg[511-:32] !== hash_word) begin + mismatch = 1; + num_err = num_err + 1; + end + + hash_shreg = {hash_shreg[511-32:0], {32{1'bX}}}; + end + + if (mismatch) $display(" *** Test failed."); + else $display(" *** Test passed."); + + end + + endtask // test_short_message + + + //---------------------------------------------------------------- + // test_long_message() + // + // The second not so pritimive test, that verifies what happens + // when an input message spans more than one block. + //---------------------------------------------------------------- + task test_long_message; + + input [511:0] correct_hash; + input integer block_size; + input integer output_size; + input integer mode; + + 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); + + /* 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; + tb_dut_mode = mode; + + /* 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<block_words; i=i+1) begin + + + if (total_bits > 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<output_words; i=i+1) begin + + tb_addr = {1'b1, i[5:0]}; + #(CLK_PERIOD); + + hash_word = tb_rd_data; + + $display(" *** hash_word[%0d]: reference = %08x, calculated = %08x", + i, hash_shreg[511-:32], hash_word); + + // compare + if (hash_shreg[511-:32] !== hash_word) begin + mismatch = 1; + num_err = num_err + 1; + end + + hash_shreg = {hash_shreg[511-32:0], {32{1'bX}}}; + end + + if (mismatch) $display(" *** Test failed."); + else $display(" *** Test passed."); + + end + + endtask // test_long_message + + + //---------------------------------------------------------------- + // sha3_sponge_pump_init; + // + // Make the "sponge" absord input data and then wait for output + // data to be "squeezed out". + //---------------------------------------------------------------- + task sha3_sponge_pump_init; + + begin : sha3_sponge_pump_init_task + + reg poll_rdy; // flag to keep waiting while the DUT is busy + + // start operation + tb_dut_init = 1; + #(CLK_PERIOD); + tb_dut_init = 0; + + // poll ready output until the operation is finished + poll_rdy = 1; + while (poll_rdy) begin + #(CLK_PERIOD); + poll_rdy = !tb_rdy; + end + + end + + endtask // sha3_sponge_pump + + + //---------------------------------------------------------------- + // sha3_sponge_pump_next; + // + // Make the "sponge" absord input data and then wait for output + // data to be "squeezed out". + //---------------------------------------------------------------- + task sha3_sponge_pump_next; + + begin : sha3_sponge_pump_next_task + + reg poll_rdy; // flag to keep waiting while the DUT is busy + + // start operation + tb_dut_next = 1; + #(CLK_PERIOD); + tb_dut_next = 0; + + // poll ready output until the operation is finished + poll_rdy = 1; + while (poll_rdy) begin + #(CLK_PERIOD); + poll_rdy = !tb_rdy; + end + + end + + endtask // sha3_sponge_pump + + + //---------------------------------------------------------------- + // sha3_test + // The main test functionality. + //---------------------------------------------------------------- + initial + + begin : sha3_test + $display("*** Testbench for sha3.v started."); + + num_err = 0; + + init_sim(); + reset_dut(); + + test_empty_message(SHA3_224_EMPTY_MSG, `SHA3_224_BLOCK_BITS, `SHA3_224_OUTPUT_BITS, `SHA3_224_MODE); + test_empty_message(SHA3_256_EMPTY_MSG, `SHA3_256_BLOCK_BITS, `SHA3_256_OUTPUT_BITS, `SHA3_256_MODE); + test_empty_message(SHA3_384_EMPTY_MSG, `SHA3_384_BLOCK_BITS, `SHA3_384_OUTPUT_BITS, `SHA3_384_MODE); + test_empty_message(SHA3_512_EMPTY_MSG, `SHA3_512_BLOCK_BITS, `SHA3_512_OUTPUT_BITS, `SHA3_512_MODE); + + test_short_message(SHA3_224_SHORT_MSG, `SHA3_224_BLOCK_BITS, `SHA3_224_OUTPUT_BITS, `SHA3_224_MODE); + test_short_message(SHA3_256_SHORT_MSG, `SHA3_256_BLOCK_BITS, `SHA3_256_OUTPUT_BITS, `SHA3_256_MODE); + test_short_message(SHA3_384_SHORT_MSG, `SHA3_384_BLOCK_BITS, `SHA3_384_OUTPUT_BITS, `SHA3_384_MODE); + test_short_message(SHA3_512_SHORT_MSG, `SHA3_512_BLOCK_BITS, `SHA3_512_OUTPUT_BITS, `SHA3_512_MODE); + + test_long_message(SHA3_224_LONG_MSG, `SHA3_224_BLOCK_BITS, `SHA3_224_OUTPUT_BITS, `SHA3_224_MODE); + test_long_message(SHA3_256_LONG_MSG, `SHA3_256_BLOCK_BITS, `SHA3_256_OUTPUT_BITS, `SHA3_256_MODE); + test_long_message(SHA3_384_LONG_MSG, `SHA3_384_BLOCK_BITS, `SHA3_384_OUTPUT_BITS, `SHA3_384_MODE); + test_long_message(SHA3_512_LONG_MSG, `SHA3_512_BLOCK_BITS, `SHA3_512_OUTPUT_BITS, `SHA3_512_MODE); + + $display("*** Testbench for sha3.v done."); - 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<output_words; i=i+1) begin
-
- tb_addr = {1'b1, i[5:0]};
- #(CLK_PERIOD);
-
- hash_word = tb_rd_data;
- - $display(" *** hash_word[%0d]: reference = %08x, calculated = %08x",
- i, hash_shreg[511-:32], hash_word);
-
- // compare
- if (hash_shreg[511-:32] !== hash_word) begin
- mismatch = 1;
- num_err = num_err + 1;
- end
-
- hash_shreg = {hash_shreg[511-32:0], {32{1'bX}}};
- end
-
- if (mismatch) $display(" *** Test failed.");
- else $display(" *** Test passed.");
-
- end - - endtask // test_empty_message -
-
- //---------------------------------------------------------------- - // test_short_message() - // - // The second simple test that verifies what happens with an - // input message, that fits into just one block. - //---------------------------------------------------------------- - task test_short_message;
+ if (num_err == 0) + $display(" *** All tests passed."); + else + $display(" *** %0d tests not passed.", num_err); - 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 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<output_words; i=i+1) begin
-
- tb_addr = {1'b1, i[5:0]};
- #(CLK_PERIOD);
-
- hash_word = tb_rd_data;
- - $display(" *** hash_word[%0d]: reference = %08x, calculated = %08x",
- i, hash_shreg[511-:32], hash_word);
-
- // compare
- if (hash_shreg[511-:32] !== hash_word) begin
- mismatch = 1;
- num_err = num_err + 1;
- end
-
- hash_shreg = {hash_shreg[511-32:0], {32{1'bX}}};
- end
-
- if (mismatch) $display(" *** Test failed.");
- else $display(" *** Test passed.");
-
- end - - endtask // test_short_message -
-
- //---------------------------------------------------------------- - // test_long_message() - // - // The second not so pritimive test, that verifies what happens
- // when an input message spans more than one block. - //---------------------------------------------------------------- - task test_long_message;
+ $finish; - input [511:0] correct_hash;
- input integer block_size;
- input integer output_size;
- - 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);
-
- /* 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<block_words; i=i+1) begin
-
-
- if (total_bits > 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<output_words; i=i+1) begin
-
- tb_addr = {1'b1, i[5:0]};
- #(CLK_PERIOD);
-
- hash_word = tb_rd_data;
- - $display(" *** hash_word[%0d]: reference = %08x, calculated = %08x",
- i, hash_shreg[511-:32], hash_word);
-
- // compare
- if (hash_shreg[511-:32] !== hash_word) begin
- mismatch = 1;
- num_err = num_err + 1;
- end
-
- hash_shreg = {hash_shreg[511-32:0], {32{1'bX}}};
- end
-
- if (mismatch) $display(" *** Test failed.");
- else $display(" *** Test passed.");
-
- end - - endtask // test_long_message -
-
- //---------------------------------------------------------------- - // sha3_sponge_pump_init; - // - // Make the "sponge" absord input data and then wait for output
- // data to be "squeezed out". - //---------------------------------------------------------------- - task sha3_sponge_pump_init;
-
- begin : sha3_sponge_pump_init_task
-
- reg poll_rdy; // flag to keep waiting while the DUT is busy
-
- // start operation
- tb_dut_init = 1;
- #(CLK_PERIOD);
- tb_dut_init = 0;
-
- // poll ready output until the operation is finished
- poll_rdy = 1;
- while (poll_rdy) begin
- #(CLK_PERIOD);
- poll_rdy = !tb_rdy;
- end
-
- end
-
- endtask // sha3_sponge_pump
-
-
- //---------------------------------------------------------------- - // sha3_sponge_pump_next; - // - // Make the "sponge" absord input data and then wait for output
- // data to be "squeezed out". - //---------------------------------------------------------------- - task sha3_sponge_pump_next;
-
- begin : sha3_sponge_pump_next_task
-
- reg poll_rdy; // flag to keep waiting while the DUT is busy
-
- // start operation
- tb_dut_next = 1;
- #(CLK_PERIOD);
- tb_dut_next = 0;
-
- // poll ready output until the operation is finished
- poll_rdy = 1;
- while (poll_rdy) begin
- #(CLK_PERIOD);
- poll_rdy = !tb_rdy;
- end
-
- end
-
- endtask // sha3_sponge_pump
-
- - //---------------------------------------------------------------- - // sha3_test - // The main test functionality. - //---------------------------------------------------------------- - initial
- - begin : sha3_test - $display("*** Testbench for sha3.v started."); -
- num_err = 0;
- - init_sim(); - reset_dut();
- - test_empty_message(SHA3_224_EMPTY_MSG, `SHA3_224_BLOCK_BITS, `SHA3_224_OUTPUT_BITS); - test_empty_message(SHA3_256_EMPTY_MSG, `SHA3_256_BLOCK_BITS, `SHA3_256_OUTPUT_BITS); - test_empty_message(SHA3_384_EMPTY_MSG, `SHA3_384_BLOCK_BITS, `SHA3_384_OUTPUT_BITS); - test_empty_message(SHA3_512_EMPTY_MSG, `SHA3_512_BLOCK_BITS, `SHA3_512_OUTPUT_BITS);
-
- test_short_message(SHA3_224_SHORT_MSG, `SHA3_224_BLOCK_BITS, `SHA3_224_OUTPUT_BITS);
- test_short_message(SHA3_256_SHORT_MSG, `SHA3_256_BLOCK_BITS, `SHA3_256_OUTPUT_BITS);
- test_short_message(SHA3_384_SHORT_MSG, `SHA3_384_BLOCK_BITS, `SHA3_384_OUTPUT_BITS);
- test_short_message(SHA3_512_SHORT_MSG, `SHA3_512_BLOCK_BITS, `SHA3_512_OUTPUT_BITS);
-
- test_long_message(SHA3_224_LONG_MSG, `SHA3_224_BLOCK_BITS, `SHA3_224_OUTPUT_BITS);
- test_long_message(SHA3_256_LONG_MSG, `SHA3_256_BLOCK_BITS, `SHA3_256_OUTPUT_BITS);
- test_long_message(SHA3_384_LONG_MSG, `SHA3_384_BLOCK_BITS, `SHA3_384_OUTPUT_BITS);
- test_long_message(SHA3_512_LONG_MSG, `SHA3_512_BLOCK_BITS, `SHA3_512_OUTPUT_BITS);
- - $display("*** Testbench for sha3.v done.");
-
- if (num_err == 0)
- $display(" *** All tests passed.");
- else
- $display(" *** %0d tests not passed.", num_err);
- - $finish;
- - end // sha3_test
- + end // sha3_test + endmodule // tb_sha3 //====================================================================== |