aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2021-06-07 14:13:23 -0400
committerPaul Selkirk <paul@psgd.org>2021-06-07 14:13:23 -0400
commit4b8d3a9da9a1d2639dd5d3adeaad55f338ead612 (patch)
tree74e7247843ce9775216432b8c48f2a59f30c3fe4
parent2e38d480fa2767b2501a477766149476b0d03537 (diff)
Add mode bits for the various flavors of SHA-3, so that the softwaresha3_mode
driver doesn't have to know that the internal block size is actually 1600 bits. This involves having the "init" state zero-extend the block data, and having "next" only absorb the block bits for that mode.
-rw-r--r--src/rtl/sha3.v86
-rw-r--r--src/rtl/sha3_wrapper.v19
-rw-r--r--src/tb/tb_sha3.v1130
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
//======================================================================