Updates to SHA256 core and a difficulty module
This commit is contained in:
parent
547a557a14
commit
e8b6d4b19c
|
@ -37,4 +37,47 @@ package sha256_pkg;
|
||||||
32'ha54ff53a, 32'h3c6ef372, 32'hbb67ae85, 32'h6a09e667
|
32'ha54ff53a, 32'h3c6ef372, 32'hbb67ae85, 32'h6a09e667
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Functions used in bit manipulations
|
||||||
|
function [31:0] little_sig0(input logic [31:0] in);
|
||||||
|
little_sig0 = {rotr(in, 7)} ^ {rotr(in, 18)} ^ {shr(in, 3)};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] little_sig1(input logic [31:0] in);
|
||||||
|
little_sig1 = {rotr(in, 17)} ^ {rotr(in, 19)} ^ {shr(in, 10)};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] big_sig0(input logic [31:0] in);
|
||||||
|
big_sig0 = {rotr(in, 2)} ^ {rotr(in, 13)} ^ {rotr(in, 22)};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] big_sig1(input logic [31:0] in);
|
||||||
|
big_sig1 = {rotr(in, 6)} ^ {rotr(in, 11)} ^ {rotr(in, 25)};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] ch(input logic [31:0] x, y, z);
|
||||||
|
ch = (x & y) ^ (~x & z);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] maj(input logic [31:0] x, y, z);
|
||||||
|
maj = (x & y) ^ (x & z) ^ (y & z);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] rotr(input logic [31:0] in, input int bits);
|
||||||
|
for (int i = 0; i < 32; i++) rotr[i] = in[(i+bits) % 32];
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [31:0] shr(input logic [31:0] in, input int bits);
|
||||||
|
shr = 0;
|
||||||
|
shr = in >> bits;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Swap bytes (used to convert between little and big endian)
|
||||||
|
function [31:0] bs32(input logic [31:0] in);
|
||||||
|
for (int i = 0; i < 4; i++) bs32[i*8 +: 8] = in[(4-1-i)*8 +: 8];
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [63:0] bs64(input logic [63:0] in);
|
||||||
|
for (int i = 0; i < 8; i++) bs64[i*8 +: 8] = in[(8-1-i)*8 +: 8];
|
||||||
|
endfunction
|
||||||
|
|
||||||
endpackage
|
endpackage
|
|
@ -31,14 +31,16 @@ module sha256_top
|
||||||
|
|
||||||
localparam DAT_BYTS = 64;
|
localparam DAT_BYTS = 64;
|
||||||
localparam DAT_BITS = DAT_BYTS*8; // Must be 512
|
localparam DAT_BITS = DAT_BYTS*8; // Must be 512
|
||||||
|
localparam ROUNDS = 64;
|
||||||
|
|
||||||
logic [7:0][31:0] V; // Internal state, V[0] == A, V[7] == H
|
logic [7:0][0:31] V, H; // Internal states, V[0] == A, V[7] == H (in big endian)
|
||||||
logic [31:0] T1, T2;
|
logic [0:31] T1, T2;
|
||||||
logic [15:0][31:0] W;
|
logic [15:0][0:31] W;
|
||||||
logic [15:0] W_nxt;
|
logic [0:31] W_nxt;
|
||||||
logic eop_l, padding_only, final_block;
|
logic padding_only, final_block;
|
||||||
logic [63:0] bit_len;
|
logic [63:0] bit_len;
|
||||||
logic [$clog2(64)-1:0] rnd_cntr;
|
logic [$clog2(ROUNDS)-1:0] rnd_cntr;
|
||||||
|
logic [1:0][0:31] bit_len_c;
|
||||||
|
|
||||||
enum {SHA_IDLE = 0,
|
enum {SHA_IDLE = 0,
|
||||||
SHA_ROUNDS = 1,
|
SHA_ROUNDS = 1,
|
||||||
|
@ -46,14 +48,14 @@ enum {SHA_IDLE = 0,
|
||||||
SHA_FINAL = 3} sha_state;
|
SHA_FINAL = 3} sha_state;
|
||||||
|
|
||||||
// Used to make compression function easier to read
|
// Used to make compression function easier to read
|
||||||
localparam A = 0;
|
localparam VAR_A = 0;
|
||||||
localparam B = 1;
|
localparam VAR_B = 1;
|
||||||
localparam C = 2;
|
localparam VAR_C = 2;
|
||||||
localparam D = 3;
|
localparam VAR_D = 3;
|
||||||
localparam E = 4;
|
localparam VAR_E = 4;
|
||||||
localparam F = 5;
|
localparam VAR_F = 5;
|
||||||
localparam G = 6;
|
localparam VAR_G = 6;
|
||||||
localparam H = 7;
|
localparam VAR_H = 7;
|
||||||
|
|
||||||
|
|
||||||
always_ff @ (posedge i_clk) begin
|
always_ff @ (posedge i_clk) begin
|
||||||
|
@ -64,7 +66,6 @@ always_ff @ (posedge i_clk) begin
|
||||||
i_block.rdy <= 0;
|
i_block.rdy <= 0;
|
||||||
bit_len <= 0;
|
bit_len <= 0;
|
||||||
W <= 0;
|
W <= 0;
|
||||||
eop_l <= 0;
|
|
||||||
padding_only <= 0;
|
padding_only <= 0;
|
||||||
final_block <= 0;
|
final_block <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
|
@ -75,7 +76,6 @@ always_ff @ (posedge i_clk) begin
|
||||||
update_HV(1);
|
update_HV(1);
|
||||||
rnd_cntr <= 0;
|
rnd_cntr <= 0;
|
||||||
final_block <= 0;
|
final_block <= 0;
|
||||||
eop_l <= 0;
|
|
||||||
padding_only <= 0;
|
padding_only <= 0;
|
||||||
i_block.rdy <= 1;
|
i_block.rdy <= 1;
|
||||||
// As soon as we have one write on the input we can start
|
// As soon as we have one write on the input we can start
|
||||||
|
@ -89,26 +89,29 @@ always_ff @ (posedge i_clk) begin
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
SHA_ROUNDS: begin
|
SHA_ROUNDS: begin
|
||||||
for (int i = 0; i < 16; i++) W[i] <= W[i+i];
|
for (int i = 0; i < 15; i++)
|
||||||
|
W[i] <= W[i+1];
|
||||||
W[15] <= W_nxt;
|
W[15] <= W_nxt;
|
||||||
compress();
|
compress();
|
||||||
rnd_cntr <= rnd_cntr + 1;
|
rnd_cntr <= rnd_cntr + 1;
|
||||||
if (rnd_cntr == 62) begin
|
if (rnd_cntr == ROUNDS - 1) begin
|
||||||
rnd_cntr <= 0;
|
rnd_cntr <= 0;
|
||||||
i_block.rdy <= ~(final_block || padding_only);
|
i_block.rdy <= ~(final_block || padding_only);
|
||||||
sha_state <= SHA_UPDATE_HV;
|
sha_state <= SHA_UPDATE_HV;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
SHA_UPDATE_HV: begin
|
SHA_UPDATE_HV: begin
|
||||||
update_H(0);
|
update_HV(0);
|
||||||
if (final_block) begin
|
if (final_block) begin
|
||||||
sha_state <= SHA_FINAL;
|
sha_state <= SHA_FINAL;
|
||||||
i_block.rdy <= 0;
|
i_block.rdy <= 0;
|
||||||
end else if (padding_only) begin
|
end else if (padding_only) begin
|
||||||
final_block <= 1;
|
final_block <= 1;
|
||||||
W <= 0;
|
W <= 0;
|
||||||
W[(64-8)*8 +: 64] <= bit_len;
|
W[15:14] <= {bit_len_c[0], bit_len_c[1]};
|
||||||
W[(bit_len/8) % 64 +: 8] <= 1;
|
if (bit_len % 512 == 0)
|
||||||
|
W[0] <= sha256_pkg::bs32(32'd1);
|
||||||
|
sha_state <= SHA_ROUNDS;
|
||||||
end else if (i_block.rdy && i_block.val) begin
|
end else if (i_block.rdy && i_block.val) begin
|
||||||
W <= i_block.dat;
|
W <= i_block.dat;
|
||||||
bit_len <= bit_len + DAT_BITS;
|
bit_len <= bit_len + DAT_BITS;
|
||||||
|
@ -121,9 +124,15 @@ always_ff @ (posedge i_clk) begin
|
||||||
end
|
end
|
||||||
SHA_FINAL: begin
|
SHA_FINAL: begin
|
||||||
o_hash.val <= 1;
|
o_hash.val <= 1;
|
||||||
o_hash.dat <= H;
|
for (int i = 0; i < 8; i++)
|
||||||
|
o_hash.dat[i*32 +: 32] <= sha256_pkg::bs32(H[i]); // Shift back to little endian
|
||||||
if (o_hash.val && o_hash.rdy) begin
|
if (o_hash.val && o_hash.rdy) begin
|
||||||
o_hash.val <= 0;
|
o_hash.val <= 0;
|
||||||
|
rnd_cntr <= 0;
|
||||||
|
bit_len <= 0;
|
||||||
|
W <= 0;
|
||||||
|
padding_only <= 0;
|
||||||
|
final_block <= 0;
|
||||||
sha_state <= SHA_IDLE;
|
sha_state <= SHA_IDLE;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -135,7 +144,6 @@ end
|
||||||
// wise set a flag so next time we call we only add the padding block
|
// wise set a flag so next time we call we only add the padding block
|
||||||
task msg_eop();
|
task msg_eop();
|
||||||
|
|
||||||
eop_l <= 1;
|
|
||||||
bit_len <= bit_len + (i_block.mod == 0 ? DAT_BITS : i_block.mod*8);
|
bit_len <= bit_len + (i_block.mod == 0 ? DAT_BITS : i_block.mod*8);
|
||||||
if (i_block.mod == 0 || i_block.mod > 64-9) begin
|
if (i_block.mod == 0 || i_block.mod > 64-9) begin
|
||||||
padding_only <= 1; // Means we need one block extra with only len (and possibly the terminating 0x1)
|
padding_only <= 1; // Means we need one block extra with only len (and possibly the terminating 0x1)
|
||||||
|
@ -143,41 +151,52 @@ task msg_eop();
|
||||||
final_block <= 1; // This is the final block and includes padding
|
final_block <= 1; // This is the final block and includes padding
|
||||||
end
|
end
|
||||||
|
|
||||||
for (int i = 0; i < 64; i++)
|
// Every 32 bit word needs to be swapped to big endian
|
||||||
M[i*8 +: 8] <= (i_block.mod == 0 || i < i_block.mod) ? i_block.dat[i*8 +: 8] : 0;
|
for (int i = 0; i < 16; i++)
|
||||||
|
W[i] <= (i_block.mod == 0 || i < i_block.mod) ? sha256_pkg::bs32(i_block.dat[i*32 +: 32]) : 0;
|
||||||
|
|
||||||
if (i_block.mod != 0)
|
if (i_block.mod != 0)
|
||||||
M[i_block.mod*8 +: 8] <= 1;
|
W[i_block.mod/4][8*(i_block.mod % 4) +: 8] <= 8'h80; // Since we operate in big endian
|
||||||
|
|
||||||
if (i_block.mod < 64-9)
|
if (i_block.mod < 64-9)
|
||||||
M[(64-8)*8 +: 64] <= bit_len + i_block.mod*8;
|
W[15:14] <= {bit_len_c[0], bit_len_c[1]};
|
||||||
|
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
W_nxt = little_sig1(W[14]) + W[9] + little_sig0(W[1]) + W[0];
|
bit_len_c = (bit_len + i_block.mod*8);
|
||||||
end
|
|
||||||
always_comb begin
|
W_nxt = sha256_pkg::little_sig1(W[14]) +
|
||||||
T1 = V[H] + big_sig1(V[E]) + ch(V[E], V[F], V[G]) + sha256_pkg::K[rnd_cntr] + W[0];
|
W[9] +
|
||||||
T2 = big_sig0(V[A]) + maj(V[A], V[B], V[C]);
|
sha256_pkg::little_sig0(W[1]) +
|
||||||
|
W[0];
|
||||||
|
|
||||||
|
T1 = V[VAR_H] +
|
||||||
|
sha256_pkg::big_sig1(V[VAR_E]) +
|
||||||
|
sha256_pkg::ch(V[VAR_E], V[VAR_F], V[VAR_G]) +
|
||||||
|
sha256_pkg::K[rnd_cntr] +
|
||||||
|
W[0];
|
||||||
|
|
||||||
|
T2 = sha256_pkg::big_sig0(V[VAR_A]) +
|
||||||
|
sha256_pkg::maj(V[VAR_A], V[VAR_B], V[VAR_C]);
|
||||||
end
|
end
|
||||||
|
|
||||||
task compress();
|
task compress();
|
||||||
V[H] <= V[G];
|
V[VAR_H] <= V[VAR_G];
|
||||||
V[G] <= V[F];
|
V[VAR_G] <= V[VAR_F];
|
||||||
V[F] <= V[E];
|
V[VAR_F] <= V[VAR_E];
|
||||||
V[E] <= V[D] + T1;
|
V[VAR_E] <= V[VAR_D] + T1;
|
||||||
V[D] <= V[C];
|
V[VAR_D] <= V[VAR_C];
|
||||||
V[C] <= V[B];
|
V[VAR_C] <= V[VAR_B];
|
||||||
V[B] <= V[A];
|
V[VAR_B] <= V[VAR_A];
|
||||||
V[A] <= T1 + T2;
|
V[VAR_A] <= T1 + T2;
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
task update_HV(logic init);
|
task update_HV(input logic init);
|
||||||
if (init) begin
|
if (init) begin
|
||||||
for (int i = 0; i < 8; i++) begin
|
for (int i = 0; i < 8; i++) begin
|
||||||
H[i] <= sha256_pkg::IV[i];
|
H[i] <= (sha256_pkg::IV[i]);
|
||||||
V[i] <= sha256_pkg::IV[i];
|
V[i] <= (sha256_pkg::IV[i]);
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
for (int i = 0; i < 8; i++) begin
|
for (int i = 0; i < 8; i++) begin
|
||||||
|
@ -187,38 +206,10 @@ task update_HV(logic init);
|
||||||
end
|
end
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
function [31:0] litte_sig0(input logic [31:0] in);
|
// Check that input size is correct
|
||||||
litte_sig0 = {rotr(in, 7)} ^ {rotr(in, 18)} ^ {shr(in, 3)};
|
initial begin
|
||||||
endfunction
|
assert ($bits(i_block.dat) == DAT_BITS) else $fatal(1, "%m %t ERROR: sha256_top DAT_BITS (%d) does not match interface .dat (%d)", $time, DAT_BITS, $bits(i_block.dat));
|
||||||
|
end
|
||||||
function [31:0] litte_sig1(input logic [31:0] in);
|
|
||||||
litte_sig1 = {rotr(in, 17)} ^ {rotr(in, 19)} ^ {shr(in, 10)};
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function [31:0] big_sig0(input logic [31:0] in);
|
|
||||||
big_sig0 = {rotr(in, 2)} ^ {rotr(in, 13)} ^ {rotr(in, 22)};
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function [31:0] big_sig1(input logic [31:0] in);
|
|
||||||
big_sig1 = {rotr(in, 6)} ^ {rotr(in, 11)} ^ {rotr(in, 25)};
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function [31:0] ch(input logic [31:0] x, y, z);
|
|
||||||
ch = (x & y) ^ (~x & z);
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function [31:0] maj(input logic [31:0] x, y, z);
|
|
||||||
maj = (x & y) ^ (x & z) ^ (y & z);
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function [31:0] rotr(input logic [31:0] in, input int bits);
|
|
||||||
for (int i = 0; i < 32; i++) rotr[i] = in[(i+bits) % 32];
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function [31:0] shr(input logic [31:0] in, input int bits);
|
|
||||||
shr = 0;
|
|
||||||
shr = in >> bits;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
|
@ -22,7 +22,7 @@ module sha256_top_tb();
|
||||||
import common_pkg::*;
|
import common_pkg::*;
|
||||||
|
|
||||||
logic clk, rst;
|
logic clk, rst;
|
||||||
|
logic [255:0] expected;
|
||||||
if_axi_stream #(.DAT_BYTS(64)) i_block(clk);
|
if_axi_stream #(.DAT_BYTS(64)) i_block(clk);
|
||||||
if_axi_stream #(.DAT_BYTS(32)) out_hash(clk);
|
if_axi_stream #(.DAT_BYTS(32)) out_hash(clk);
|
||||||
|
|
||||||
|
@ -45,17 +45,31 @@ sha256_top DUT (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// This test runs the hash which is shown in the RFC, for "abc"
|
// NIST testcase for single 512 bit block "abc"
|
||||||
task rfc_test();
|
task nist_single_block_test();
|
||||||
begin
|
begin
|
||||||
integer signed get_len;
|
integer signed get_len;
|
||||||
logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat;
|
logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat;
|
||||||
$display("Running rfc_test...\n");
|
$display("Running nist_single_block_test...\n");
|
||||||
expected = 'h239900d4ed8623b95a92f1dba88ad31895cc3345ded552c22d79ab2a39c5877dd1a2ffdb6fbb124bb7c45a68142f214ce9f6129fb697276a0d4d1c983fa580ba;
|
expected = 'had1500f261ff10b49c7a1796a36103b02322ae5dde404141eacf018fbf1678ba; // Both in little endian
|
||||||
i_block.put_stream("cba", 3);
|
i_block.put_stream("cba", 3); // abc in little endian
|
||||||
out_hash.get_stream(get_dat, get_len);
|
out_hash.get_stream(get_dat, get_len);
|
||||||
common_pkg::compare_and_print(get_dat, expected);
|
common_pkg::compare_and_print(get_dat, expected);
|
||||||
$display("rfc_test PASSED");
|
$display("nist_single_block_test PASSED");
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// NIST testcase for double 512 bit block "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||||
|
task nist_double_block_test();
|
||||||
|
begin
|
||||||
|
integer signed get_len;
|
||||||
|
logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat;
|
||||||
|
$display("Running nist_double_block_test...\n");
|
||||||
|
expected = 'hc106db19d4edecf66721ff6459e43ca339603e0c9326c0e5b83806d2616a8d24; // Both in little endian
|
||||||
|
i_block.put_stream("qponponmonmlnmlkmlkjlkjikjihjihgihgfhgfegfedfedcedcbdcba", 56);
|
||||||
|
out_hash.get_stream(get_dat, get_len);
|
||||||
|
common_pkg::compare_and_print(get_dat, expected);
|
||||||
|
$display("nist_double_block_test PASSED");
|
||||||
end
|
end
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
@ -67,7 +81,8 @@ initial begin
|
||||||
|
|
||||||
#200ns;
|
#200ns;
|
||||||
|
|
||||||
rfc_test();
|
nist_single_block_test();
|
||||||
|
nist_double_block_test();
|
||||||
|
|
||||||
#10us $finish();
|
#10us $finish();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
This verifies that a Zcash equihash solution has the correct difficulty.
|
||||||
|
|
||||||
|
Take input stream of entire block header (including equihash solution and size) and
|
||||||
|
calculate the SHA256d (double SHA256)
|
||||||
|
|
||||||
|
We take in the stream in DAT_BYTS in a FIFO, and load the output into 512 bit words
|
||||||
|
for the SHA256 block. Then the 256 bit output it inputted into the same SHA256 block.
|
||||||
|
|
||||||
|
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module zcash_verif_equihash_difficulty
|
||||||
|
import zcash_verif_pkg::*;
|
||||||
|
#(
|
||||||
|
parameter DAT_BYTS = 8,
|
||||||
|
)(
|
||||||
|
input i_clk, i_rst,
|
||||||
|
|
||||||
|
if_axi_stream.sink i_axi,
|
||||||
|
input logic [31:0] i_difficulty, // Must be valid on .sop && .val
|
||||||
|
output logic o_difficulty_fail,
|
||||||
|
output logic o_val
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
logic [$clog2($bits(cblockheader_sol_t)/8)-1:0] byt_cnt;
|
||||||
|
logic o_fifo_full, o_fifo_emp;
|
||||||
|
logic [31:0] difficulty;
|
||||||
|
|
||||||
|
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) o_fifo(clk);
|
||||||
|
if_axi_stream #(.DAT_BYTS(64)) i_block(clk);
|
||||||
|
if_axi_stream #(.DAT_BYTS(32)) o_hash(clk);
|
||||||
|
|
||||||
|
enum {IDLE = 0,
|
||||||
|
SHA256_0 = 1,
|
||||||
|
SHA256_1 = 2,
|
||||||
|
FINISHED = 3} state;
|
||||||
|
|
||||||
|
always_ff @ (posedge i_clk) begin
|
||||||
|
if (i_rst) begin
|
||||||
|
o_difficulty_fail <= 0;
|
||||||
|
o_val <= 0;
|
||||||
|
byt_cnt <= 0;
|
||||||
|
i_block.reset_source();
|
||||||
|
o_hash.rdy <= 0;
|
||||||
|
o_fifo.rdy <= 0;
|
||||||
|
difficulty <= 0;
|
||||||
|
state <= IDLE;
|
||||||
|
end else begin
|
||||||
|
o_val <= 0;
|
||||||
|
o_hash.rdy <= 1;
|
||||||
|
|
||||||
|
case(state)
|
||||||
|
IDLE: begin
|
||||||
|
i_block.reset_source();
|
||||||
|
o_fifo.rdy <= 0;
|
||||||
|
byt_cnt <= 0;
|
||||||
|
if (i_axi.rdy && i_axi.val && i_axi.sop) begin
|
||||||
|
difficulty <= i_difficulty;
|
||||||
|
state <= SHA256_0;
|
||||||
|
o_fifo.rdy <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// Convert data to 512 bit wide
|
||||||
|
SHA256_0: begin
|
||||||
|
|
||||||
|
if (o_fifo.rdy && o_fifo.val) begin
|
||||||
|
i_block.val <= 0;
|
||||||
|
byt_cnt <= byt_cnt + DAT_BYTS;
|
||||||
|
i_block.dat[byt_cnt +: DAT_BYTS] <= o_fifo.dat;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (((byt_cnt + DAT_BYTS) % 64 == 0) ||
|
||||||
|
(byt_cnt + DAT_BYTS) == $bits(cblockheader_sol_t)/8) begin
|
||||||
|
i_block.val <= 1;
|
||||||
|
i_block.sop <= (byt_cnt + DAT_BYTS)/64 == 1;
|
||||||
|
i_block.eop <= 0;
|
||||||
|
i_block.mod <= (byt_cnt + DAT_BYTS);
|
||||||
|
o_fifo.rdy <= i_block.rdy;
|
||||||
|
if ((byt_cnt + DAT_BYTS) == $bits(cblockheader_sol_t)/8) begin
|
||||||
|
i_block.eop <= 1;
|
||||||
|
state <= SHA256_1;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
o_fifo.rdy <= 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
SHA256_1: begin
|
||||||
|
if (i_block.val && i_block.rdy) begin
|
||||||
|
i_block.val <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (o_hash.val && o_hash.rdy) begin
|
||||||
|
i_block.val <= 1;
|
||||||
|
i_block.dat <= o_hash.dat;
|
||||||
|
i_block.sop <= 1;
|
||||||
|
i_block.eop <= 1;
|
||||||
|
i_block.mod <= 32;
|
||||||
|
state <= FINISHED;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
FINISHED: begin
|
||||||
|
if (i_block.val && i_block.rdy) begin
|
||||||
|
i_block.val <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (o_hash.val && o_hash.rdy) begin
|
||||||
|
o_difficulty_fail <= check_difficulty(o_hash.dat, difficulty);
|
||||||
|
o_val <= 1;
|
||||||
|
state <= IDLE;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
|
||||||
|
if ( o_fifo_full ) begin
|
||||||
|
o_difficulty_fail <= 1;
|
||||||
|
o_val <= 1;
|
||||||
|
o_hash.rdy <= 1;
|
||||||
|
o_fifo.rdy <= 1;
|
||||||
|
i_block.reset_source();
|
||||||
|
if ( o_fifo_emp )
|
||||||
|
state <= IDLE;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Function to check if difficulty passes - bits is the number of 0s we
|
||||||
|
// need
|
||||||
|
// TODO target function
|
||||||
|
function check_difficulty(input logic [255:0] hash, logic [31:0] bits);
|
||||||
|
check_difficulty = 0;
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
if (i > bits && hash[(64-1-i)*8 +: 8] != 0)
|
||||||
|
check_difficulty = 1;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// FIFO for storing input stream
|
||||||
|
axi_stream_fifo #(
|
||||||
|
.SIZE ( ($bits(cblockheader_sol_t)/8)/DAT_BYTS ),
|
||||||
|
.DAT_BITS ( DAT_BYTS/8 ),
|
||||||
|
.USE_BRAM ( 1 )
|
||||||
|
)
|
||||||
|
axi_stream_fifo (
|
||||||
|
.i_clk ( i_clk ),
|
||||||
|
.i_rst ( i_rst ),
|
||||||
|
.i_axi ( i_axi ),
|
||||||
|
.o_axi ( o_fifo ),
|
||||||
|
.o_full ( o_fifo_full ),
|
||||||
|
.o_emp ( o_fifo_emp )
|
||||||
|
);
|
||||||
|
|
||||||
|
// SHA256 block
|
||||||
|
sha256_top sha256_top (
|
||||||
|
.i_clk ( i_clk ),
|
||||||
|
.i_rst ( i_rst ),
|
||||||
|
.i_block ( i_block ),
|
||||||
|
.o_hash ( o_hash )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -37,6 +37,7 @@ package zcash_verif_pkg;
|
||||||
logic BAD_ZERO_ORDER;
|
logic BAD_ZERO_ORDER;
|
||||||
logic BAD_IDX_ORDER;
|
logic BAD_IDX_ORDER;
|
||||||
logic XOR_NON_ZERO;
|
logic XOR_NON_ZERO;
|
||||||
|
logic DIFFICULTY_FAIL;
|
||||||
} equihash_bm_t;
|
} equihash_bm_t;
|
||||||
|
|
||||||
// Format for equihash input - should be 144 bytes
|
// Format for equihash input - should be 144 bytes
|
||||||
|
|
Loading…
Reference in New Issue