diff --git a/ip_cores/sha256/src/rtl/sha256_pkg.sv b/ip_cores/sha256/src/rtl/sha256_pkg.sv
new file mode 100644
index 0000000..b3dda68
--- /dev/null
+++ b/ip_cores/sha256/src/rtl/sha256_pkg.sv
@@ -0,0 +1,40 @@
+/*
+ The SHA256 package file.
+
+ 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 .
+*/
+
+package sha256_pkg;
+
+ // K values used during each round
+ parameter [63:0][31:0] K = {
+ 32'hc67178f2,32'hbef9a3f7,32'ha4506ceb,32'h90befffa,32'h8cc70208,32'h84c87814,32'h78a5636f,32'h748f82ee,
+ 32'h682e6ff3,32'h5b9cca4f,32'h4ed8aa4a,32'h391c0cb3,32'h34b0bcb5,32'h2748774c,32'h1e376c08,32'h19a4c116,
+ 32'h106aa070,32'hf40e3585,32'hd6990624,32'hd192e819,32'hc76c51a3,32'hc24b8b70,32'ha81a664b,32'ha2bfe8a1,
+ 32'h92722c85,32'h81c2c92e,32'h766a0abb,32'h650a7354,32'h53380d13,32'h4d2c6dfc,32'h2e1b2138,32'h27b70a85,
+ 32'h14292967,32'h06ca6351,32'hd5a79147,32'hc6e00bf3,32'hbf597fc7,32'hb00327c8,32'ha831c66d,32'h983e5152,
+ 32'h76f988da,32'h5cb0a9dc,32'h4a7484aa,32'h2de92c6f,32'h240ca1cc,32'h0fc19dc6,32'hefbe4786,32'he49b69c1,
+ 32'hc19bf174,32'h9bdc06a7,32'h80deb1fe,32'h72be5d74,32'h550c7dc3,32'h243185be,32'h12835b01,32'hd807aa98,
+ 32'hab1c5ed5,32'h923f82a4,32'h59f111f1,32'h3956c25b,32'he9b5dba5,32'hb5c0fbcf,32'h71374491,32'h428a2f98
+ };
+
+ // Initial values used for H
+ parameter [7:0][31:0] IV = {
+ 32'h5be0cd19, 32'h1f83d9ab, 32'h9b05688c, 32'h510e527f,
+ 32'ha54ff53a, 32'h3c6ef372, 32'hbb67ae85, 32'h6a09e667
+ };
+
+endpackage
\ No newline at end of file
diff --git a/ip_cores/sha256/src/rtl/sha256_top.sv b/ip_cores/sha256/src/rtl/sha256_top.sv
new file mode 100644
index 0000000..808a953
--- /dev/null
+++ b/ip_cores/sha256/src/rtl/sha256_top.sv
@@ -0,0 +1,224 @@
+/*
+ This is an implementation of the SHA256 hash algorithm.
+
+ Takes an AXI stream 512 bit interface. We back pressure the input
+ if the message size is > 512 bits while we process the 64 rounds.
+
+ 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 .
+ */
+
+module sha256_top
+ import sha256_pkg::*;
+(
+ input i_clk, i_rst,
+
+ if_axi_stream.sink i_block, // Message stream to be hashed, must be 512 bits
+ if_axi_stream.source o_hash // Resulting hash digest (32 bytes)
+);
+
+localparam DAT_BYTS = 64;
+localparam DAT_BITS = DAT_BYTS*8; // Must be 512
+
+logic [7:0][31:0] V; // Internal state, V[0] == A, V[7] == H
+logic [31:0] T1, T2;
+logic [15:0][31:0] W;
+logic [15:0] W_nxt;
+logic eop_l, padding_only, final_block;
+logic [63:0] bit_len;
+logic [$clog2(64)-1:0] rnd_cntr;
+
+enum {SHA_IDLE = 0,
+ SHA_ROUNDS = 1,
+ SHA_UPDATE_HV = 2,
+ SHA_FINAL = 3} sha_state;
+
+// Used to make compression function easier to read
+localparam A = 0;
+localparam B = 1;
+localparam C = 2;
+localparam D = 3;
+localparam E = 4;
+localparam F = 5;
+localparam G = 6;
+localparam H = 7;
+
+
+always_ff @ (posedge i_clk) begin
+ if (i_rst) begin
+ sha_state <= SHA_IDLE;
+ rnd_cntr <= 0;
+ o_hash.reset_source();
+ i_block.rdy <= 0;
+ bit_len <= 0;
+ W <= 0;
+ eop_l <= 0;
+ padding_only <= 0;
+ final_block <= 0;
+ end else begin
+ o_hash.sop <= 1;
+ o_hash.eop <= 1;
+ case(sha_state)
+ SHA_IDLE: begin
+ update_HV(1);
+ rnd_cntr <= 0;
+ final_block <= 0;
+ eop_l <= 0;
+ padding_only <= 0;
+ i_block.rdy <= 1;
+ // As soon as we have one write on the input we can start
+ if (i_block.rdy && i_block.val && i_block.sop) begin
+ W <= i_block.dat;
+ bit_len <= DAT_BITS;
+ i_block.rdy <= 0;
+ if (i_block.eop)
+ msg_eop();
+ sha_state <= SHA_ROUNDS;
+ end
+ end
+ SHA_ROUNDS: begin
+ for (int i = 0; i < 16; i++) W[i] <= W[i+i];
+ W[15] <= W_nxt;
+ compress();
+ rnd_cntr <= rnd_cntr + 1;
+ if (rnd_cntr == 62) begin
+ rnd_cntr <= 0;
+ i_block.rdy <= ~(final_block || padding_only);
+ sha_state <= SHA_UPDATE_HV;
+ end
+ end
+ SHA_UPDATE_HV: begin
+ update_H(0);
+ if (final_block) begin
+ sha_state <= SHA_FINAL;
+ i_block.rdy <= 0;
+ end else if (padding_only) begin
+ final_block <= 1;
+ W <= 0;
+ W[(64-8)*8 +: 64] <= bit_len;
+ W[(bit_len/8) % 64 +: 8] <= 1;
+ end else if (i_block.rdy && i_block.val) begin
+ W <= i_block.dat;
+ bit_len <= bit_len + DAT_BITS;
+ if (i_block.eop) begin
+ msg_eop();
+ i_block.rdy <= 0;
+ end
+ sha_state <= SHA_ROUNDS;
+ end
+ end
+ SHA_FINAL: begin
+ o_hash.val <= 1;
+ o_hash.dat <= H;
+ if (o_hash.val && o_hash.rdy) begin
+ o_hash.val <= 0;
+ sha_state <= SHA_IDLE;
+ end
+ end
+ endcase
+ end
+end
+
+// On the msg .eop we need to make sure we add padding if there is space other
+// wise set a flag so next time we call we only add the padding block
+task msg_eop();
+
+ eop_l <= 1;
+ 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
+ padding_only <= 1; // Means we need one block extra with only len (and possibly the terminating 0x1)
+ end else begin
+ final_block <= 1; // This is the final block and includes padding
+ end
+
+ for (int i = 0; i < 64; i++)
+ M[i*8 +: 8] <= (i_block.mod == 0 || i < i_block.mod) ? i_block.dat[i*8 +: 8] : 0;
+
+ if (i_block.mod != 0)
+ M[i_block.mod*8 +: 8] <= 1;
+
+ if (i_block.mod < 64-9)
+ M[(64-8)*8 +: 64] <= bit_len + i_block.mod*8;
+
+endtask
+
+always_comb begin
+ W_nxt = little_sig1(W[14]) + W[9] + little_sig0(W[1]) + W[0];
+end
+always_comb begin
+ T1 = V[H] + big_sig1(V[E]) + ch(V[E], V[F], V[G]) + sha256_pkg::K[rnd_cntr] + W[0];
+ T2 = big_sig0(V[A]) + maj(V[A], V[B], V[C]);
+end
+
+task compress();
+ V[H] <= V[G];
+ V[G] <= V[F];
+ V[F] <= V[E];
+ V[E] <= V[D] + T1;
+ V[D] <= V[C];
+ V[C] <= V[B];
+ V[B] <= V[A];
+ V[A] <= T1 + T2;
+endtask
+
+task update_HV(logic init);
+ if (init) begin
+ for (int i = 0; i < 8; i++) begin
+ H[i] <= sha256_pkg::IV[i];
+ V[i] <= sha256_pkg::IV[i];
+ end
+ end else begin
+ for (int i = 0; i < 8; i++) begin
+ H[i] <= H[i] + V[i];
+ V[i] <= H[i] + V[i];
+ end
+ end
+endtask
+
+function [31:0] litte_sig0(input logic [31:0] in);
+ litte_sig0 = {rotr(in, 7)} ^ {rotr(in, 18)} ^ {shr(in, 3)};
+endfunction
+
+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
\ No newline at end of file
diff --git a/ip_cores/sha256/src/tb/sha256_top_tb.sv b/ip_cores/sha256/src/tb/sha256_top_tb.sv
new file mode 100644
index 0000000..87ff33a
--- /dev/null
+++ b/ip_cores/sha256/src/tb/sha256_top_tb.sv
@@ -0,0 +1,76 @@
+/*
+ The SHA256 testbench.
+
+ 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 .
+ */
+
+module sha256_top_tb();
+
+import common_pkg::*;
+
+logic clk, rst;
+
+if_axi_stream #(.DAT_BYTS(64)) i_block(clk);
+if_axi_stream #(.DAT_BYTS(32)) out_hash(clk);
+
+initial begin
+ rst = 0;
+ #100ns rst = 1;
+ #100ns rst = 0;
+end
+
+initial begin
+ clk = 0;
+ forever #10ns clk = ~clk;
+end
+
+sha256_top DUT (
+ .i_clk ( clk ),
+ .i_rst ( rst ),
+ .i_block ( i_block ),
+ .o_hash ( out_hash )
+);
+
+
+// This test runs the hash which is shown in the RFC, for "abc"
+task rfc_test();
+ begin
+ integer signed get_len;
+ logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat;
+ $display("Running rfc_test...\n");
+ expected = 'h239900d4ed8623b95a92f1dba88ad31895cc3345ded552c22d79ab2a39c5877dd1a2ffdb6fbb124bb7c45a68142f214ce9f6129fb697276a0d4d1c983fa580ba;
+ i_block.put_stream("cba", 3);
+ out_hash.get_stream(get_dat, get_len);
+ common_pkg::compare_and_print(get_dat, expected);
+ $display("rfc_test PASSED");
+ end
+endtask
+
+
+// Main testbench calls
+initial begin
+ i_block.reset_source();
+ out_hash.rdy = 1;
+
+ #200ns;
+
+ rfc_test();
+
+ #10us $finish();
+
+end
+
+endmodule
\ No newline at end of file