secworks / sha256

Hardware implementation of the SHA-256 cryptographic hash function
BSD 2-Clause "Simplified" License
318 stars 90 forks source link

The output sha256 hash value does not meet expectations #22

Open TealerLinkGuo opened 4 months ago

TealerLinkGuo commented 4 months ago

hello sir, I am trying to directly test sha256_core.v without using sha256.v as the top-level module. I have written a testbench for it, but when I input the hexadecimal block value, I did not get the expected hash value output.

Here is my input block data 10a548fa958c10d2d11435456176bc6a555cb3f463a8bd23a7bb29283781f2a71123c60c6ef0923a2ec4c9f75e0e0f9042509594865b46691f962c4dd4642c28

Here is the correct hash value of input block calculated by the online sha256 tool 1b20aa312f1c48723c3e0e17396b01b03926267cacd7d50221379be90ef24ced

Here is the online tool website I use to verify sha256 hash values https://emn178.github.io/online-tools/sha256.html?input=10a548fa958c10d2d11435456176bc6a555cb3f463a8bd23a7bb29283781f2a71123c60c6ef0923a2ec4c9f75e0e0f9042509594865b46691f962c4dd4642c28&input_type=hex&output_type=hex&hmac_enabled=0&hmac_input_type=hex

This is the output digest value I obtained when running testbench 086a42b3642eddf7623eb021d4e496e756a3cd632638fc1b1c75e2c45e0d5302 This is clearly inconsistent with expectations

Here is my testbench

`timescale 1ns/1ps

module sha256_core_tb;

parameter CLK_HALF_PERIOD = 5;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;

reg clk;
reg reset;

reg init;
reg mode;
reg next;

reg [511:0] input_block;

wire ready;
wire [255:0] out_hash;
wire out_valid;

sha256_core dut (
    .clk(clk),
    .reset_n(reset),

    .init(init),
    .next(mode),
    .mode(next),

    .block(input_block),

    .ready(ready),

    .digest(out_hash),
    .digest_valid(out_valid)
);

initial begin
    clk = 0;
    forever begin
        #(CLK_HALF_PERIOD);
        clk = ~clk;
        #(CLK_HALF_PERIOD);
    end
end

task wait_ready;
    begin
      while(!ready) begin
          #(CLK_PERIOD);
        end
    end
endtask // wait_ready

task init_sim;
    begin
      clk = 0;
      reset = 1;

      init = 0;
      next = 0;
      mode = 1;
      input_block = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    end
endtask // init_dut

task reset_dut;
    begin
      reset = 0;
      #(4 * CLK_HALF_PERIOD);
      reset = 1;
    end
endtask // reset_dut

reg [511:0] block;

initial begin

    $dumpfile("sha256.vcd");
    $dumpvars(0, sha256_core_tb);

    init_sim();
    #(CLK_PERIOD);

    reset_dut();
    #(CLK_PERIOD);

    // block = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
    block = 512'h10a548fa958c10d2d11435456176bc6a555cb3f463a8bd23a7bb29283781f2a71123c60c6ef0923a2ec4c9f75e0e0f9042509594865b46691f962c4dd4642c28;
    input_block = block;
    init = 1;

    #(CLK_PERIOD*500)
    $finish;

end

endmodule
secworks commented 4 months ago

Hello, First off, you are not padding the message. As stated in the README:

Note that the core does **NOT** implement padding of final block. The caller is expected to handle padding."

The sha256 tool you use to verify adds a second complete padding block. See the NIST SHA256 specification on padding. In your case the padding block should be:

512'h80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200;

Secondly I can't replicate the results you get. I suggest that you look at the tb_sha256_core.v testbench. If I modify the sha256_core_test task double block test like this:

      // TC2: Double block message.
      tc2_1 = 512'h10a548fa958c10d2d11435456176bc6a555cb3f463a8bd23a7bb29283781f2a71123c60c6ef0923a2ec4c9f75e0e0f9042509594865b46691f962c4dd4642c28;
      res2_1 = 256'h60944998deef165a47f60568c95c5f987fc63dd70361564fa7219be824484884;

      tc2_2 = 512'h80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200;
      res2_2 = 256'h1b20aa312f1c48723c3e0e17396b01b03926267cacd7d50221379be90ef24ced;
      double_block_test(2, tc2_1, res2_1, tc2_2, res2_2);

The test goes through, i.e. it matches the expected behavior.

secworks commented 4 months ago

There probably will be a new top level module that adds padding. But it isn't done yet.

Padding is easy for a CPU to do while the final message block is being processed, but somewhat cumbersome in HW to do.

secworks commented 4 months ago

And your issue makes me realize that the README isn't very helpful unless you actually knows hos the SHA-256 hash function works. I will update the documentation.