From 361ece0ee33a07b119b7b015b4d0448ea2d26e56 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 12 Feb 2019 00:07:18 +0800 Subject: [PATCH 01/16] Initial files for the Blake2B core --- .project | 11 ++ ip_cores/blake2b/src/rtl/blake2_g.sv | 58 ++++++++ ip_cores/blake2b/src/rtl/blake2_pkg.sv | 50 +++++++ ip_cores/blake2b/src/rtl/blake2_top.sv | 177 +++++++++++++++++++++++ ip_cores/blake2b/src/tb/blake2_g_tb.sv | 46 ++++++ ip_cores/blake2b/src/tb/blake2_top_tb.sv | 88 +++++++++++ 6 files changed, 430 insertions(+) create mode 100644 .project create mode 100644 ip_cores/blake2b/src/rtl/blake2_g.sv create mode 100644 ip_cores/blake2b/src/rtl/blake2_pkg.sv create mode 100644 ip_cores/blake2b/src/rtl/blake2_top.sv create mode 100644 ip_cores/blake2b/src/tb/blake2_g_tb.sv create mode 100644 ip_cores/blake2b/src/tb/blake2_top_tb.sv diff --git a/.project b/.project new file mode 100644 index 0000000..0ef5a74 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + zcash-fpga + + + + + + + + diff --git a/ip_cores/blake2b/src/rtl/blake2_g.sv b/ip_cores/blake2b/src/rtl/blake2_g.sv new file mode 100644 index 0000000..5a18bd6 --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2_g.sv @@ -0,0 +1,58 @@ +module blake2_g +#( + parameter PIPELINES = 1 // Do we want to optionally add pipeline stages +) +( + input i_clk, + input [63:0] i_a, i_b, i_c, i_d, i_m0, i_m1, + output logic [63:0] o_a, o_b, o_c, o_d +); + +logic [63:0] a0, b0, c0, d0, a1, b1, c1, d1, b2, d2, b3, d3; +logic [PIPELINES:0][64*4-1:0] pipeline; + +// Logic used to implement G function +always_comb begin + a0 = i_a + i_b + i_m0; + d0 = i_d ^ a0; + d1 = {d0[0 +: 32], d0[32 +: 32]}; + c0 = i_c + d1; + b0 = i_b ^ c0; + b1 = {b0[0 +: 24], b0[24 +: 40]}; + a1 = a0 + b1 + i_m1; + d2 = d1 ^ a1; + d3 = {d2[0 +: 16], d2[16 +: 48]}; + c1 = c0 + d3; + b2 = b1 ^ c1; + b3 = {b2[0 +: 63], b2[63]}; +end + +// Final output assignment +always_comb begin + o_a = pipeline[PIPELINES][0*64 +: 64]; + o_b = pipeline[PIPELINES][1*64 +: 64]; + o_c = pipeline[PIPELINES][2*64 +: 64]; + o_d = pipeline[PIPELINES][3*64 +: 64]; +end + +// Optional pipelines +generate begin: PIPE_GEN + genvar gv_p; + always_comb begin + pipeline[0][0*64 +: 64] = a1; + pipeline[0][1*64 +: 64] = b3; + pipeline[0][2*64 +: 64] = c1; + pipeline[0][3*64 +: 64] = d3; + end + for (gv_p = 0; gv_p < PIPELINES; gv_p++) begin: PIPE_LOOP_GEN + always_ff @ (posedge i_clk) begin + pipeline[gv_p + 1][0*64 +: 64] <= pipeline[gv_p][0*64 +: 64]; + pipeline[gv_p + 1][1*64 +: 64] <= pipeline[gv_p][1*64 +: 64]; + pipeline[gv_p + 1][2*64 +: 64] <= pipeline[gv_p][2*64 +: 64]; + pipeline[gv_p + 1][3*64 +: 64] <= pipeline[gv_p][3*64 +: 64]; + end + end +end +endgenerate + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2_pkg.sv b/ip_cores/blake2b/src/rtl/blake2_pkg.sv new file mode 100644 index 0000000..614bbbf --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2_pkg.sv @@ -0,0 +1,50 @@ +package blake2_pkg; + +// Initial values + parameter [7:0][63:0] IV = { + 64'h5be0cd19137e2179, + 64'h1f83d9abfb41bd6b, + 64'h9b05688c2b3e6c1f, + 64'h510e527fade682d1, + 64'ha54ff53a5f1d36f1, + 64'h3c6ef372fe94f82b, + 64'hbb67ae8584caa73b, + 64'h6a09e667f3bcc908 + }; + + parameter [15*10-1:0][31:0] SIGMA = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, + 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, + 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, + 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, + 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, + 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, + 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, + 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, + 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 + }; + + + parameter [4*8-1:0][31:0] G_MAPPING = { + 14, 9, 4, 3, + 13, 8, 7, 2, + 12, 11, 6, 1, + 15, 10, 5, 0, + 15, 11, 7, 3, + 14, 10, 6, 2, + 13, 9, 5, 1, + 12, 8, 4, 0 + }; + + // Top 4 bits per entry is the nth G-function unit + // lower 4 bits is the ith output of the G-function + parameter [15:0][5:0] G_FINAL_MAPPING = { + {3'd4,3'd3}, {3'd7,3'd3}, {3'd6,3'd3}, {3'd5,3'd3}, + {3'd5,3'd2}, {3'd4,3'd2}, {3'd7,3'd2}, {3'd6,3'd2}, + {3'd6,3'd1}, {3'd5,3'd1}, {3'd4,3'd1}, {3'd7,3'd1}, + {3'd7,3'd0}, {3'd6,3'd0}, {3'd5,3'd0}, {3'd4, 3'd0} + }; + + +endpackage \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2_top.sv b/ip_cores/blake2b/src/rtl/blake2_top.sv new file mode 100644 index 0000000..3cc9426 --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2_top.sv @@ -0,0 +1,177 @@ +// Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) + +module blake2_top + import blake2_pkg::*; +#( + +) +( + input i_clk, i_rst, + + // Parameter block input + input [7:0] i_digest_byte_len, + input [7:0] i_key_byte_len, + + input [128*8-1:0] i_block, + input i_new_block, + input i_final_block, + input i_val, + + output logic[64*8-1:0] o_digest, + output logic o_rdy, + output logic o_val, + output logic o_err + + +); + +enum {STATE_IDLE = 0, + STATE_ROUNDS = 1, + STATE_NEXT_BLOCK = 2} blake2_state; + +localparam ROUNDS = 12; + +logic [64*8-1:0] parameters; +logic [7:0][63:0] h; // The state vector +logic [15:0][63:0] v; // The local work vector +logic [31:0][63:0] g_out; // Outputs of the G mixing function - use 8 here to save on timing +logic [127:0] t; // Counter - TODO make this smaller - related to param +logic [$clog2(ROUNDS)-1:0] round_cntr; +logic cnt; +logic g_row_col; +logic [15:0][63:0] block_r; // The message block registered and converted to a 2d array +logic final_block_r; + + +// Logic that is for pipelining +always_ff @(posedge i_clk) begin + parameters <= {32'd0, 8'd1, 8'd1, i_key_byte_len, i_digest_byte_len}; + if (i_val && o_rdy) begin + block_r <= i_block; + final_block_r <= i_final_block; + end +end + +// State machine logic for compressing +always_ff @(posedge i_clk) begin + if (i_rst) begin + blake2_state <= STATE_IDLE; + o_val <= 0; + o_rdy <= 0; + h <= 0; + v <= 0; + t <= 0; + g_row_col <= 0; + round_cntr <= 0; + o_err <= 0; + o_digest <= 0; + cnt <= 0; + end else begin + cnt <= cnt + 1; + case (blake2_state) + STATE_IDLE: begin + o_val <= 0; + init_state_vector(); + t <= 0; + o_err <= 0; + o_rdy <= 1; + v <= 0; + g_row_col <= 0; + round_cntr <= 0; + if (o_rdy && i_val && i_new_block) begin + init_local_work_vector(); + blake2_state <= STATE_ROUNDS; + o_rdy <= 0; + end + end + // Here we do the compression over 12 rounds, each round can be done in two clock cycles + // After we do 12 rounds we increment counter t + STATE_ROUNDS: begin + // Update local work vector with output of G function blocks + for (int i = 0; i < 16; i++) + v[i] <= g_out[G_MAPPING[g_row_col*16 + i]]; + + if (g_row_col) + round_cntr <= round_cntr + 1; + g_row_col <= ~g_row_col; + + // Update state vector on the final round + if (round_cntr == ROUNDS-1) begin + + for (int i = 0; i < 7; i++) + h[i] <= h[i] ^ + g_out[G_FINAL_MAPPING[i][5:3]][G_FINAL_MAPPING[i][2:0]] ^ + g_out[G_FINAL_MAPPING[i+8][5:3]][G_FINAL_MAPPING[i][2:0]]; + + blake2_state <= STATE_NEXT_BLOCK; + if (~final_block_r) + o_rdy <= 1; + end + + end + STATE_NEXT_BLOCK: begin + if (final_block_r) begin + blake2_state <= STATE_IDLE; + o_val <= 1; + o_digest <= h; + end else if (o_rdy && i_val) begin + round_cntr <= 0; + init_local_work_vector(); + t <= (t+1) * 128; + blake2_state <= STATE_ROUNDS; + end + end + endcase + end +end + +// 8x G-function blocks. 4 are col and 4 are diagonal +generate begin + genvar gv_g; + for (gv_g = 0; gv_g < 8; gv_g++) begin: G_FUNCTION_GEN + blake2_g + #(.PIPELINES(0)) + blake2_g ( + .i_clk(i_clk), + .i_a(v[(gv_g*4 + 0) % 16]), + .i_b(v[(gv_g*4 + 1) % 16]), + .i_c(v[(gv_g*4 + 2) % 16]), + .i_d(v[(gv_g*4 + 3) % 16]), + .i_m0(block_r[blake2_pkg::SIGMA[(round_cntr % 10) + (gv_g*16)]]), + .i_m1(block_r[blake2_pkg::SIGMA[(round_cntr % 10) + ((gv_g+1))*16]]), + .o_a(g_out[gv_g*4 + 0]), + .o_b(g_out[gv_g*4 + 1]), + .o_c(g_out[gv_g*4 + 2]), + .o_d(g_out[gv_g*4 + 3])); + end +end +endgenerate + + +// Task to initialize the state vector +task init_state_vector(); +begin + for (int i = 0; i < 8; i++) + if (i == 0) + h[i] <= parameters ^ blake2_pkg::IV[i]; + else + h[i] <= blake2_pkg::IV[i]; +end +endtask + +// Task to initialize local work vector for the compression function +task init_local_work_vector(); +begin + for (int i = 0; i < 16; i++) + case (i) inside + 0,1,2,3,4,5,6,7: v[i] <= h[i]; + 8,9,10,11: v[i] <= blake2_pkg::IV[i%8]; + 12: v[i] <= blake2_pkg::IV[i%8] ^ t[63:0]; + 13: v[i] <= blake2_pkg::IV[i%8] ^ t[64 +: 64]; + 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{i_final_block}}; + 15: v[i] <= blake2_pkg::IV[i%8]; + endcase +end +endtask + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/tb/blake2_g_tb.sv b/ip_cores/blake2b/src/tb/blake2_g_tb.sv new file mode 100644 index 0000000..19953c0 --- /dev/null +++ b/ip_cores/blake2b/src/tb/blake2_g_tb.sv @@ -0,0 +1,46 @@ +module blake2_g_tb(); + +logic clk; +logic [63:0] o_a, o_b, o_c, o_d, i_a, i_b, i_c, i_d, i_m0, i_m1; +localparam PIPELINES = 1; + +blake2_g #(.PIPELINES(PIPELINES)) DUT (.i_clk(clk), .o_a(o_a), .o_b(o_b), .o_c(o_c), .o_d(o_d), .i_a(i_a), .i_b(i_b), .i_c(i_c), .i_d(i_d), .i_m0(i_m0), .i_m1(i_m1)); + +initial begin + clk = 0; + forever #10ns clk = ~clk; +end + +task test1(); +begin + @(posedge clk) + i_a = 64'h6a09e667f2bdc948; + i_b = 64'h510e527fade682d1; + i_c = 64'h6a09e667f3bcc908; + i_d = 64'h510e527fade68251; + i_m0 = 64'h0000000000000000; + i_m1 = 64'h0000000000000000; + + repeat (PIPELINES) @(posedge clk); + + #1; + assert (o_a == 64'hf0c9aa0de38b1b89) else $fatal(0, "%m %t:ERROR, o_a did not match", $time); + assert (o_b == 64'hbbdf863401fde49b) else $fatal(0, "%m %t:ERROR, o_b did not match", $time); + assert (o_c == 64'he85eb23c42183d3d) else $fatal(0, "%m %t:ERROR, o_c did not match", $time); + assert (o_d == 64'h7111fd8b6445099d) else $fatal(0, "%m %t:ERROR, o_d did not match", $time); + + $display("test1 PASSED"); +end +endtask + +// Main testbench calls + +initial begin + #100ns; + test1(); + + #100ns $finish(); + +end + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/tb/blake2_top_tb.sv b/ip_cores/blake2b/src/tb/blake2_top_tb.sv new file mode 100644 index 0000000..ac0e9a8 --- /dev/null +++ b/ip_cores/blake2b/src/tb/blake2_top_tb.sv @@ -0,0 +1,88 @@ +module blake2_top_tb(); + +logic clk, rst; +logic [7:0] digest_byte_len, key_byte_len; +logic [128*8-1:0] i_block; +logic i_new_block; +logic i_final_block; +logic i_val; +logic[64*8-1:0] o_digest; +logic o_rdy; +logic o_val; +logic o_err; + +initial begin + rst = 0; + #100ns rst = 1; + #100ns rst = 0; +end + +initial begin + clk = 0; + forever #10ns clk = ~clk; +end + + +blake2_top DUT ( + .i_clk(clk), + .i_rst(rst), + .i_digest_byte_len( digest_byte_len ), + .i_key_byte_len( key_byte_len ), + .i_block(i_block), + .i_new_block(i_new_block), + .i_final_block(i_final_block), + .i_val(i_val), + .o_digest(o_digest), + .o_rdy(o_rdy), + .o_val(o_val), + .o_err(o_err) +); + +// This test runs the hash which is shown in the RFC, for "abc" +task rfc_test(); +begin + i_val = 0; + @(posedge clk); + while (!o_rdy) @(posedge clk); + + @(negedge clk); + i_val = 1; + i_final_block = 1; + i_new_block = 1; + i_block = 'h636261; + + @(negedge clk); + i_val = 0; + + // TODO check rdy goes low + + while (!o_val) @(posedge clk); + + @(posedge clk); + @(posedge clk); + + // TODO verify result + + $display("rfc_test PASSED"); +end +endtask + +// Main testbench calls +initial begin + key_byte_len = 0; + digest_byte_len = 64; + i_block = '0; + i_new_block = '0; + i_final_block = '0; + i_val = '0; + + #200ns; + + + rfc_test(); + + #100ns $finish(); + +end + +endmodule \ No newline at end of file From 7c0d5dab5b6798466b115c842e42799be56ec829 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 12 Feb 2019 00:13:03 +0800 Subject: [PATCH 02/16] Add .xdc file for Xilinx projects --- ip_cores/blake2b/synth/blake2g_top.xdc | 1 + 1 file changed, 1 insertion(+) create mode 100644 ip_cores/blake2b/synth/blake2g_top.xdc diff --git a/ip_cores/blake2b/synth/blake2g_top.xdc b/ip_cores/blake2b/synth/blake2g_top.xdc new file mode 100644 index 0000000..5d8cffe --- /dev/null +++ b/ip_cores/blake2b/synth/blake2g_top.xdc @@ -0,0 +1 @@ +create_clock -period 2.000 -name i_clk -waveform {0.000 1.000} [get_ports -filter { NAME =~ "*clk*" && DIRECTION == "IN" }] From a07b4a7cc6de0e60462c55781bab793398af21c6 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Mon, 11 Feb 2019 21:53:27 -0500 Subject: [PATCH 03/16] Fixes for blake2 engine and testbench passing rfc_test now --- ip_cores/blake2b/src/rtl/blake2_pkg.sv | 68 +++++++++++---------- ip_cores/blake2b/src/rtl/blake2_top.sv | 78 ++++++++++++++---------- ip_cores/blake2b/src/tb/blake2_top_tb.sv | 25 +++++--- ip_cores/common/src/rtl/common_if.sv | 32 ++++++++++ 4 files changed, 130 insertions(+), 73 deletions(-) create mode 100644 ip_cores/common/src/rtl/common_if.sv diff --git a/ip_cores/blake2b/src/rtl/blake2_pkg.sv b/ip_cores/blake2b/src/rtl/blake2_pkg.sv index 614bbbf..6b87d18 100644 --- a/ip_cores/blake2b/src/rtl/blake2_pkg.sv +++ b/ip_cores/blake2b/src/rtl/blake2_pkg.sv @@ -1,6 +1,9 @@ package blake2_pkg; + // User configurable values + parameter [7:0] NN = 64; // Output hash byte length -// Initial values + + // Initial values parameter [7:0][63:0] IV = { 64'h5be0cd19137e2179, 64'h1f83d9abfb41bd6b, @@ -12,39 +15,38 @@ package blake2_pkg; 64'h6a09e667f3bcc908 }; - parameter [15*10-1:0][31:0] SIGMA = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, - 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, - 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, - 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, - 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 - }; + parameter [16*10-1:0][31:0] SIGMA = { + 0, 13, 12, 3, 14, 9, 11, 15, 5, 1, 6, 7, 4, 8, 2, 10, + 5, 10, 4, 1, 7, 13, 2, 12, 8, 0, 3, 11, 9, 14, 15, 6, + 10, 2, 6, 8, 4, 15, 0, 5, 9, 3, 1, 12, 14, 7, 11, 13, + 11, 8, 2, 9, 3, 6, 7, 0, 10, 4, 13, 14, 15, 1, 5, 12, + 9, 1, 14, 15, 5, 7, 13, 4, 3, 8, 11, 0, 10, 6, 12, 2, + 13, 3, 8, 6, 12, 11, 1, 14, 15, 10, 4, 2, 7, 5, 0, 9, + 8, 15, 0, 4, 10, 5, 6, 2, 14, 11, 12, 13, 1, 3, 9, 7, + 4, 9, 1, 7, 6, 3, 14, 10, 13, 15, 2, 5, 0, 12, 8, 11, + 3, 5, 7, 11, 2, 0, 12, 1, 6, 13, 15, 9, 8, 4, 10, 14, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + }; - parameter [4*8-1:0][31:0] G_MAPPING = { - 14, 9, 4, 3, - 13, 8, 7, 2, - 12, 11, 6, 1, - 15, 10, 5, 0, - 15, 11, 7, 3, - 14, 10, 6, 2, - 13, 9, 5, 1, - 12, 8, 4, 0 - }; - - // Top 4 bits per entry is the nth G-function unit - // lower 4 bits is the ith output of the G-function - parameter [15:0][5:0] G_FINAL_MAPPING = { - {3'd4,3'd3}, {3'd7,3'd3}, {3'd6,3'd3}, {3'd5,3'd3}, - {3'd5,3'd2}, {3'd4,3'd2}, {3'd7,3'd2}, {3'd6,3'd2}, - {3'd6,3'd1}, {3'd5,3'd1}, {3'd4,3'd1}, {3'd7,3'd1}, - {3'd7,3'd0}, {3'd6,3'd0}, {3'd5,3'd0}, {3'd4, 3'd0} - }; - + parameter [4*8-1:0][31:0] G_MAPPING = { + 14, 9, 4, 3, + 13, 8, 7, 2, + 12, 11, 6, 1, + 15, 10, 5, 0, + 15, 11, 7, 3, + 14, 10, 6, 2, + 13, 9, 5, 1, + 12, 8, 4, 0 + }; + + // This is so we can get the correct mapping back from the diagonal + // operation + parameter [4*4-1:0][31:0] G_MAPPING_DIAG = { + 3, 15, 11,7, + 6, 2, 14, 10, + 9, 5, 1, 13, + 12, 8 , 4, 0 + }; endpackage \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2_top.sv b/ip_cores/blake2b/src/rtl/blake2_top.sv index 3cc9426..8bc06d0 100644 --- a/ip_cores/blake2b/src/rtl/blake2_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2_top.sv @@ -3,7 +3,6 @@ module blake2_top import blake2_pkg::*; #( - ) ( input i_clk, i_rst, @@ -20,9 +19,9 @@ module blake2_top output logic[64*8-1:0] o_digest, output logic o_rdy, output logic o_val, - output logic o_err - - + output logic o_err, + + if_axi_stream o_hash ); enum {STATE_IDLE = 0, @@ -31,24 +30,27 @@ enum {STATE_IDLE = 0, localparam ROUNDS = 12; -logic [64*8-1:0] parameters; +logic [64*8-1:0] parameters, parameters_r; logic [7:0][63:0] h; // The state vector logic [15:0][63:0] v; // The local work vector logic [31:0][63:0] g_out; // Outputs of the G mixing function - use 8 here to save on timing logic [127:0] t; // Counter - TODO make this smaller - related to param logic [$clog2(ROUNDS)-1:0] round_cntr; logic cnt; -logic g_row_col; +logic g_col; logic [15:0][63:0] block_r; // The message block registered and converted to a 2d array logic final_block_r; +always_comb begin + parameters = {32'd0, 8'd1, 8'd1, i_key_byte_len, blake2_pkg::NN}; +end // Logic that is for pipelining always_ff @(posedge i_clk) begin - parameters <= {32'd0, 8'd1, 8'd1, i_key_byte_len, i_digest_byte_len}; if (i_val && o_rdy) begin block_r <= i_block; final_block_r <= i_final_block; + parameters_r <= parameters; end end @@ -60,26 +62,30 @@ always_ff @(posedge i_clk) begin o_rdy <= 0; h <= 0; v <= 0; - t <= 0; - g_row_col <= 0; + t <= 128; + g_col <= 0; round_cntr <= 0; o_err <= 0; o_digest <= 0; cnt <= 0; + + o_hash.reset(); + end else begin cnt <= cnt + 1; case (blake2_state) STATE_IDLE: begin o_val <= 0; init_state_vector(); - t <= 0; + t <= 128; o_err <= 0; o_rdy <= 1; v <= 0; - g_row_col <= 0; + o_hash.val = 0; + g_col <= 0; round_cntr <= 0; if (o_rdy && i_val && i_new_block) begin - init_local_work_vector(); + init_local_work_vector(i_final_block ? i_digest_byte_len : t); blake2_state <= STATE_ROUNDS; o_rdy <= 0; end @@ -89,19 +95,19 @@ always_ff @(posedge i_clk) begin STATE_ROUNDS: begin // Update local work vector with output of G function blocks for (int i = 0; i < 16; i++) - v[i] <= g_out[G_MAPPING[g_row_col*16 + i]]; + v[i] <= g_col == 0 ? g_out[blake2_pkg::G_MAPPING[i]] : g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]]; - if (g_row_col) + if (g_col) round_cntr <= round_cntr + 1; - g_row_col <= ~g_row_col; + g_col <= ~g_col; // Update state vector on the final round - if (round_cntr == ROUNDS-1) begin + if (round_cntr == ROUNDS-1 && g_col) begin - for (int i = 0; i < 7; i++) + for (int i = 0; i < 8; i++) h[i] <= h[i] ^ - g_out[G_FINAL_MAPPING[i][5:3]][G_FINAL_MAPPING[i][2:0]] ^ - g_out[G_FINAL_MAPPING[i+8][5:3]][G_FINAL_MAPPING[i][2:0]]; + g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ + g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; blake2_state <= STATE_NEXT_BLOCK; if (~final_block_r) @@ -111,13 +117,23 @@ always_ff @(posedge i_clk) begin end STATE_NEXT_BLOCK: begin if (final_block_r) begin - blake2_state <= STATE_IDLE; + o_val <= 1; o_digest <= h; + t <= 128; + if (~o_hash.val) begin + o_hash.dat <= h; + o_hash.val <= 1; + o_hash.sop <= 1; + o_hash.eop <= 1; + end + if (o_hash.rdy) + blake2_state <= STATE_IDLE; + end else if (o_rdy && i_val) begin round_cntr <= 0; - init_local_work_vector(); - t <= (t+1) * 128; + init_local_work_vector(t); + t <= t + 128; blake2_state <= STATE_ROUNDS; end end @@ -133,12 +149,12 @@ generate begin #(.PIPELINES(0)) blake2_g ( .i_clk(i_clk), - .i_a(v[(gv_g*4 + 0) % 16]), - .i_b(v[(gv_g*4 + 1) % 16]), - .i_c(v[(gv_g*4 + 2) % 16]), - .i_d(v[(gv_g*4 + 3) % 16]), - .i_m0(block_r[blake2_pkg::SIGMA[(round_cntr % 10) + (gv_g*16)]]), - .i_m1(block_r[blake2_pkg::SIGMA[(round_cntr % 10) + ((gv_g+1))*16]]), + .i_a(v[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]]), + .i_b(v[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]]), + .i_c(v[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]]), + .i_d(v[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]]), + .i_m0(block_r[blake2_pkg::SIGMA[16*(round_cntr % 10) + (gv_g*2)]]), + .i_m1(block_r[blake2_pkg::SIGMA[16*(round_cntr % 10) + (gv_g*2 + 1)]]), .o_a(g_out[gv_g*4 + 0]), .o_b(g_out[gv_g*4 + 1]), .o_c(g_out[gv_g*4 + 2]), @@ -160,14 +176,14 @@ end endtask // Task to initialize local work vector for the compression function -task init_local_work_vector(); +task init_local_work_vector(input [127:0] cntr); begin for (int i = 0; i < 16; i++) case (i) inside 0,1,2,3,4,5,6,7: v[i] <= h[i]; 8,9,10,11: v[i] <= blake2_pkg::IV[i%8]; - 12: v[i] <= blake2_pkg::IV[i%8] ^ t[63:0]; - 13: v[i] <= blake2_pkg::IV[i%8] ^ t[64 +: 64]; + 12: v[i] <= blake2_pkg::IV[i%8] ^ cntr[63:0]; + 13: v[i] <= blake2_pkg::IV[i%8] ^ cntr[64 +: 64]; 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{i_final_block}}; 15: v[i] <= blake2_pkg::IV[i%8]; endcase diff --git a/ip_cores/blake2b/src/tb/blake2_top_tb.sv b/ip_cores/blake2b/src/tb/blake2_top_tb.sv index ac0e9a8..e8e9493 100644 --- a/ip_cores/blake2b/src/tb/blake2_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2_top_tb.sv @@ -1,5 +1,7 @@ module blake2_top_tb(); +import blake2_pkg::*; + logic clk, rst; logic [7:0] digest_byte_len, key_byte_len; logic [128*8-1:0] i_block; @@ -11,6 +13,8 @@ logic o_rdy; logic o_val; logic o_err; +if_axi_stream #(.DAT_BYTS(blake2_pkg::NN)) out_hash(clk); + initial begin rst = 0; #100ns rst = 1; @@ -35,7 +39,9 @@ blake2_top DUT ( .o_digest(o_digest), .o_rdy(o_rdy), .o_val(o_val), - .o_err(o_err) + .o_err(o_err), + + .o_hash(out_hash) ); // This test runs the hash which is shown in the RFC, for "abc" @@ -49,19 +55,18 @@ begin i_val = 1; i_final_block = 1; i_new_block = 1; + digest_byte_len = 3; + key_byte_len = 0; i_block = 'h636261; @(negedge clk); i_val = 0; - // TODO check rdy goes low + while (!out_hash.val) @(posedge clk); - while (!o_val) @(posedge clk); - - @(posedge clk); - @(posedge clk); - - // TODO verify result + assert (out_hash.dat == 'h239900d4ed8623b95a92f1dba88ad31895cc3345ded552c22d79ab2a39c5877dd1a2ffdb6fbb124bb7c45a68142f214ce9f6129fb697276a0d4d1c983fa580ba) else $fatal(0, "%m %t:ERROR, out_hash.dat did not match, was:\n0x%h", $time, out_hash.dat); + assert (out_hash.sop == 1) else $fatal(0, "%m %t:ERROR, out_hash.sop was not high", $time); + assert (out_hash.eop == 1) else $fatal(0, "%m %t:ERROR, out_hash.sop was not high", $time); $display("rfc_test PASSED"); end @@ -70,11 +75,13 @@ endtask // Main testbench calls initial begin key_byte_len = 0; - digest_byte_len = 64; + digest_byte_len = 3; i_block = '0; i_new_block = '0; i_final_block = '0; i_val = '0; + out_hash.rdy = 1; + #200ns; diff --git a/ip_cores/common/src/rtl/common_if.sv b/ip_cores/common/src/rtl/common_if.sv new file mode 100644 index 0000000..fc4c1d1 --- /dev/null +++ b/ip_cores/common/src/rtl/common_if.sv @@ -0,0 +1,32 @@ + +// Interface for a AXI stream +interface if_axi_stream # ( + parameter DAT_BYTS = 8, + parameter CTL_BYTS = 8 +)( + input i_clk +); + + localparam DAT_BITS = DAT_BYTS*8; + localparam CTL_BITS = CTL_BYTS*8; + + logic rdy; + logic val; + logic err; + logic sop; + logic eop; + logic [CTL_BITS-1:0] ctl; + logic [DAT_BITS-1:0] dat; + logic [$clog2(DAT_BYTS)-1:0] mod; + + task reset(); + val <= 0; + err <= 0; + sop <= 0; + eop <= 0; + dat <= 0; + ctl <= 0; + mod <= 0; + endtask + +endinterface \ No newline at end of file From 191fbef30584874e368fd0f2deea77a8d4567f65 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 12 Feb 2019 17:54:22 -0500 Subject: [PATCH 04/16] Modify readme file change folder name --- {equihash-verifi => equihash_verifi}/README.md | 0 equihash_verifi/src/rtl/equihash_verifi_top.sv | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {equihash-verifi => equihash_verifi}/README.md (100%) create mode 100644 equihash_verifi/src/rtl/equihash_verifi_top.sv diff --git a/equihash-verifi/README.md b/equihash_verifi/README.md similarity index 100% rename from equihash-verifi/README.md rename to equihash_verifi/README.md diff --git a/equihash_verifi/src/rtl/equihash_verifi_top.sv b/equihash_verifi/src/rtl/equihash_verifi_top.sv new file mode 100644 index 0000000..e69de29 From d391cbc992521bcc3420f5d1745d59e135bab584 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Wed, 13 Feb 2019 10:53:19 -0500 Subject: [PATCH 05/16] Updates to testbench to include helper functions, updated synthesis file to meet timing (200MHz) --- .../src/rtl/equihash_verifi_top.sv | 51 ++++ equihash_verifi/synth/equihash_verifi_top.xdc | 1 + ip_cores/blake2b/src/rtl/blake2_pkg.sv | 6 +- ip_cores/blake2b/src/rtl/blake2_top.sv | 229 ++++++++++-------- ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv | 207 ++++++++++++++++ ip_cores/blake2b/src/tb/blake2_top_tb.sv | 108 ++++----- ip_cores/blake2b/synth/blake2g_top.xdc | 2 +- ip_cores/common/src/rtl/common_if.sv | 55 ++++- ip_cores/common/src/rtl/common_pkg.sv | 24 ++ 9 files changed, 513 insertions(+), 170 deletions(-) create mode 100644 equihash_verifi/synth/equihash_verifi_top.xdc create mode 100644 ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv create mode 100644 ip_cores/common/src/rtl/common_pkg.sv diff --git a/equihash_verifi/src/rtl/equihash_verifi_top.sv b/equihash_verifi/src/rtl/equihash_verifi_top.sv index e69de29..42ebc9b 100644 --- a/equihash_verifi/src/rtl/equihash_verifi_top.sv +++ b/equihash_verifi/src/rtl/equihash_verifi_top.sv @@ -0,0 +1,51 @@ +/* + * This module is the top system level for the equihash verifier system. It takes in an AXI stream which + * represents block chain data and verifies that it is correct. + */ + +module equihash_verifi_top( + input i_clk, i_rst, + + if_axi_stream.sink i_data, + output logic o_valid +); + +if_axi_stream #(.DAT_BYTS(128)) blake2b_in(clk); +if_axi_stream #(.DAT_BYTS(64)) blake2b_out(clk); + + +always_ff @ (posedge i_clk) begin + i_data.rdy <= blake2b_in.rdy; + blake2b_in.val <= i_data.val; + blake2b_in.sop <= i_data.sop; + blake2b_in.eop <= i_data.eop; + blake2b_in.dat <= i_data.dat; + blake2b_in.err <= 0; + blake2b_in.mod <= 0; + blake2b_in.ctl <= 0; + + blake2b_out.rdy <= 1; + o_valid <= (blake2b_out.val && blake2b_out.dat == {64{1'b1}}); +end + + +// The Blake2 core for generating hashes + +logic [64*8-1:0] blake2_parameters; +always_comb begin + blake2_parameters = {32'd0, 8'd1, 8'd1, 8'd0, 8'd64}; +end + +blake2_top #( + .EQUIHASH( 1 ) +) +blake2_top ( + .i_clk ( i_clk ), + .i_rst ( i_rst ), + .i_byte_len ( 8'd128 ), + .i_parameters ( blake2_parameters ), + .i_block ( blake2b_in ), + .o_hash ( blake2b_out ) +); + +endmodule \ No newline at end of file diff --git a/equihash_verifi/synth/equihash_verifi_top.xdc b/equihash_verifi/synth/equihash_verifi_top.xdc new file mode 100644 index 0000000..b99f66e --- /dev/null +++ b/equihash_verifi/synth/equihash_verifi_top.xdc @@ -0,0 +1 @@ +create_clock -period 5.000 -name i_clk -waveform {0.000 2.500} [get_ports -filter { NAME =~ "*i_clk*" && DIRECTION == "IN" }] diff --git a/ip_cores/blake2b/src/rtl/blake2_pkg.sv b/ip_cores/blake2b/src/rtl/blake2_pkg.sv index 6b87d18..9654b3c 100644 --- a/ip_cores/blake2b/src/rtl/blake2_pkg.sv +++ b/ip_cores/blake2b/src/rtl/blake2_pkg.sv @@ -1,7 +1,4 @@ package blake2_pkg; - // User configurable values - parameter [7:0] NN = 64; // Output hash byte length - // Initial values parameter [7:0][63:0] IV = { @@ -15,6 +12,7 @@ package blake2_pkg; 64'h6a09e667f3bcc908 }; + // Sigma permutations used for G function blocks and input messages parameter [16*10-1:0][31:0] SIGMA = { 0, 13, 12, 3, 14, 9, 11, 15, 5, 1, 6, 7, 4, 8, 2, 10, 5, 10, 4, 1, 7, 13, 2, 12, 8, 0, 3, 11, 9, 14, 15, 6, @@ -28,7 +26,7 @@ package blake2_pkg; 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; - + // Mapping for each G function block to the state vector v parameter [4*8-1:0][31:0] G_MAPPING = { 14, 9, 4, 3, 13, 8, 7, 2, diff --git a/ip_cores/blake2b/src/rtl/blake2_top.sv b/ip_cores/blake2b/src/rtl/blake2_top.sv index 8bc06d0..2422a40 100644 --- a/ip_cores/blake2b/src/rtl/blake2_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2_top.sv @@ -1,142 +1,155 @@ -// Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) +/* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) + * Personalization string in the input parameter should be "ZcashPoW" followed by n and k in + * little endian order. + */ module blake2_top import blake2_pkg::*; -#( -) ( input i_clk, i_rst, - // Parameter block input - input [7:0] i_digest_byte_len, - input [7:0] i_key_byte_len, - - input [128*8-1:0] i_block, - input i_new_block, - input i_final_block, - input i_val, - - output logic[64*8-1:0] o_digest, - output logic o_rdy, - output logic o_val, - output logic o_err, + input [7:0] i_byte_len, // Length of the input message + input [64*8-1:0] i_parameters, // Input parameters used in the inital state. - if_axi_stream o_hash + if_axi_stream.sink i_block, // Input block with valid and ready signals for flow control + if_axi_stream.source o_hash // Output digest with valid and ready signals for flow control ); enum {STATE_IDLE = 0, STATE_ROUNDS = 1, - STATE_NEXT_BLOCK = 2} blake2_state; + STATE_NEXT_BLOCK = 2, + STATE_FINAL_BLOCK = 3} blake2_state; localparam ROUNDS = 12; -logic [64*8-1:0] parameters, parameters_r; -logic [7:0][63:0] h; // The state vector -logic [15:0][63:0] v; // The local work vector -logic [31:0][63:0] g_out; // Outputs of the G mixing function - use 8 here to save on timing +logic [7:0][63:0] h, h_tmp; // The state vector +logic [15:0][63:0] v, v_tmp; // The local work vector and its intermediate value +logic [31:0][63:0] g_out;//, g_out_r; // Outputs of the G mixing function - use 8 here to save on timing logic [127:0] t; // Counter - TODO make this smaller - related to param -logic [$clog2(ROUNDS)-1:0] round_cntr; -logic cnt; +logic [$clog2(ROUNDS)-1:0] round_cntr, round_cntr_msg, round_cntr_fin; logic g_col; -logic [15:0][63:0] block_r; // The message block registered and converted to a 2d array -logic final_block_r; +logic [15:0][63:0] block, block_r; // The message block registered and converted to a 2d array +logic block_eop_l; // Use to latch if this is the final block -always_comb begin - parameters = {32'd0, 8'd1, 8'd1, i_key_byte_len, blake2_pkg::NN}; +// Pipelining logic that has no reset +always_ff @(posedge i_clk) begin + + //g_out_r <= g_out; + + if (blake2_state == STATE_IDLE) begin + block_r <= 0; + if (i_block.val && i_block.rdy) begin + block_r <= i_block.dat; + end + end + + for (int i = 0; i < 16; i++) + if (g_col == 0/* && blake2_state == STATE_ROUNDS*/) // TODO why do I need this qualifier + v_tmp[i] <= g_out[blake2_pkg::G_MAPPING[i]]; + + for (int i = 0; i < 8; i++) + if (blake2_state == STATE_ROUNDS) + h_tmp[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; //TODO fix + end -// Logic that is for pipelining -always_ff @(posedge i_clk) begin - if (i_val && o_rdy) begin - block_r <= i_block; - final_block_r <= i_final_block; - parameters_r <= parameters; - end +always_comb begin + block = i_block.dat; end // State machine logic for compressing always_ff @(posedge i_clk) begin if (i_rst) begin blake2_state <= STATE_IDLE; - o_val <= 0; - o_rdy <= 0; + i_block.rdy <= 0; h <= 0; v <= 0; t <= 128; g_col <= 0; round_cntr <= 0; - o_err <= 0; - o_digest <= 0; - cnt <= 0; - - o_hash.reset(); - + round_cntr_msg <= 0; + o_hash.reset_source(); + round_cntr_fin <= 0; + block_eop_l <= 0; end else begin - cnt <= cnt + 1; + + if (blake2_state != STATE_NEXT_BLOCK) g_col <= ~g_col; + case (blake2_state) STATE_IDLE: begin - o_val <= 0; - init_state_vector(); + h <= i_parameters ^ blake2_pkg::IV; t <= 128; - o_err <= 0; - o_rdy <= 1; + i_block.rdy <= 1; v <= 0; - o_hash.val = 0; + o_hash.val <= 0; g_col <= 0; round_cntr <= 0; - if (o_rdy && i_val && i_new_block) begin - init_local_work_vector(i_final_block ? i_digest_byte_len : t); + round_cntr_msg <= 0; + round_cntr_fin <= 0; + if (i_block.rdy && i_block.val && i_block.sop) begin + init_local_work_vector(i_byte_len, i_block.eop); blake2_state <= STATE_ROUNDS; - o_rdy <= 0; + g_col <= 0; + i_block.rdy <= 0; + block_eop_l <= i_block.eop; end end // Here we do the compression over 12 rounds, each round can be done in two clock cycles // After we do 12 rounds we increment counter t STATE_ROUNDS: begin - // Update local work vector with output of G function blocks - for (int i = 0; i < 16; i++) - v[i] <= g_col == 0 ? g_out[blake2_pkg::G_MAPPING[i]] : g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]]; - - if (g_col) - round_cntr <= round_cntr + 1; - g_col <= ~g_col; - // Update state vector on the final round - if (round_cntr == ROUNDS-1 && g_col) begin - - for (int i = 0; i < 8; i++) - h[i] <= h[i] ^ - g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ - g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; - - blake2_state <= STATE_NEXT_BLOCK; - if (~final_block_r) - o_rdy <= 1; + // Update local work vector with output of G function blocks depending on column or diagonal operation + for (int i = 0; i < 16; i++) begin + v[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]]; end + if (g_col) begin + round_cntr <= round_cntr + 1; + end else begin + round_cntr_msg <= (round_cntr_msg + 1) % 10; + end + if (round_cntr == ROUNDS-1) + round_cntr_fin <= 1; + + if (round_cntr_fin) begin + if (block_eop_l) + blake2_state <= STATE_FINAL_BLOCK; + else begin + blake2_state <= STATE_NEXT_BLOCK; + i_block.rdy <= 1; + end + end end STATE_NEXT_BLOCK: begin - if (final_block_r) begin - - o_val <= 1; - o_digest <= h; - t <= 128; - if (~o_hash.val) begin - o_hash.dat <= h; - o_hash.val <= 1; - o_hash.sop <= 1; - o_hash.eop <= 1; - end - if (o_hash.rdy) - blake2_state <= STATE_IDLE; - - end else if (o_rdy && i_val) begin - round_cntr <= 0; - init_local_work_vector(t); + round_cntr <= 0; + round_cntr_msg <= 0; + round_cntr_fin <= 0; + if (i_block.rdy && i_block.val) begin + init_local_work_vector(t, i_block.eop); //TODO this wont work with h_tmp + block_eop_l <= i_block.eop; t <= t + 128; + h <= h ^ h_tmp; blake2_state <= STATE_ROUNDS; end end + STATE_FINAL_BLOCK: begin + t <= 128; + round_cntr <= 0; + round_cntr_fin <= 0; + round_cntr_msg <= 0; + if (~o_hash.val || (o_hash.val && o_hash.rdy)) begin + if (~o_hash.val) begin + o_hash.dat <= h ^ h_tmp; + o_hash.val <= 1; + o_hash.sop <= 1; + o_hash.eop <= 1; + end + if (o_hash.rdy) begin + blake2_state <= STATE_IDLE; + i_block.rdy <= 1; + end + end + end endcase end end @@ -145,38 +158,40 @@ end generate begin genvar gv_g; for (gv_g = 0; gv_g < 8; gv_g++) begin: G_FUNCTION_GEN + + // For each G function we want to pipeline the input message to help timing + logic [63:0] m0, m1; + always_ff @ (posedge i_clk) begin + if(blake2_state == STATE_IDLE) begin + m0 <= block[blake2_pkg::SIGMA[gv_g*2]]; + m1 <= block[blake2_pkg::SIGMA[gv_g*2 + 1]]; + end else begin + m0 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2]]; + m1 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2 + 1]]; + end + end + blake2_g #(.PIPELINES(0)) blake2_g ( .i_clk(i_clk), - .i_a(v[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]]), - .i_b(v[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]]), - .i_c(v[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]]), - .i_d(v[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]]), - .i_m0(block_r[blake2_pkg::SIGMA[16*(round_cntr % 10) + (gv_g*2)]]), - .i_m1(block_r[blake2_pkg::SIGMA[16*(round_cntr % 10) + (gv_g*2 + 1)]]), + .i_a(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]]), + .i_b(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]]), + .i_c(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]]), + .i_d(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]]), + .i_m0(m0), + .i_m1(m1), .o_a(g_out[gv_g*4 + 0]), .o_b(g_out[gv_g*4 + 1]), .o_c(g_out[gv_g*4 + 2]), .o_d(g_out[gv_g*4 + 3])); + end end endgenerate - -// Task to initialize the state vector -task init_state_vector(); -begin - for (int i = 0; i < 8; i++) - if (i == 0) - h[i] <= parameters ^ blake2_pkg::IV[i]; - else - h[i] <= blake2_pkg::IV[i]; -end -endtask - // Task to initialize local work vector for the compression function -task init_local_work_vector(input [127:0] cntr); +task init_local_work_vector(input [127:0] cntr, input last_block); begin for (int i = 0; i < 16; i++) case (i) inside @@ -184,7 +199,7 @@ begin 8,9,10,11: v[i] <= blake2_pkg::IV[i%8]; 12: v[i] <= blake2_pkg::IV[i%8] ^ cntr[63:0]; 13: v[i] <= blake2_pkg::IV[i%8] ^ cntr[64 +: 64]; - 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{i_final_block}}; + 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{last_block}}; 15: v[i] <= blake2_pkg::IV[i%8]; endcase end diff --git a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv new file mode 100644 index 0000000..7120235 --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv @@ -0,0 +1,207 @@ +/* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) + * This is a unrolled pipelined version of the hash function required for Equihash. + * A single has takes 25 clock cycles but + */ + +module blake2_pipe_top + import blake2_pkg::*; +#( +) +( + input i_clk, i_rst, + + input [7:0] i_byte_len, // Length of the input message + input [64*8-1:0] i_parameters, // Input parameters used in the inital state + + if_axi_stream.sink i_block, // Input block with valid and ready signals for flow control + if_axi_stream.source o_hash // Output digest with valid and ready signals for flow control +); + +enum {STATE_IDLE = 0, + STATE_ROUNDS = 1, + STATE_NEXT_BLOCK = 2, + STATE_FINAL_BLOCK = 3} blake2_state; + +localparam ROUNDS = 12; + +logic [7:0][63:0] h, h_tmp; // The state vector +logic [15:0][63:0] v, v_tmp; // The local work vector and its intermediate value +logic [31:0][63:0] g_out, g_out_r; // Outputs of the G mixing function - use 8 here to save on timing +logic [127:0] t; // Counter - TODO make this smaller - related to param +logic [$clog2(ROUNDS)-1:0] round_cntr, round_cntr_msg, round_cntr_fin; +logic g_col; +logic [15:0][63:0] block, block_r; // The message block registered and converted to a 2d array +logic block_eop_l; // Use to latch if this is the final block + +// Pipelining logic that has no reset +always_ff @(posedge i_clk) begin + + g_out_r <= g_out; + + if (i_block.val && i_block.rdy) begin + block_r <= i_block.dat; + end + + for (int i = 0; i < 16; i++) + if (g_col == 0) // TODO why do I need this qualifier + v_tmp[i] <= g_out[blake2_pkg::G_MAPPING[i]]; + + for (int i = 0; i < 8; i++) + if (blake2_state == STATE_ROUNDS) + h_tmp[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; //TODO fix + +end + +always_comb begin + block = i_block.dat; +end + +// State machine logic for compressing +always_ff @(posedge i_clk) begin + if (i_rst) begin + blake2_state <= STATE_IDLE; + i_block.rdy <= 0; + h <= 0; + v <= 0; + t <= 128; + g_col <= 0; + round_cntr <= 0; + round_cntr_msg <= 0; + o_hash.reset_source(); + round_cntr_fin <= 0; + block_eop_l <= 0; + end else begin + + g_col <= ~g_col; + + case (blake2_state) + STATE_IDLE: begin + h <= i_parameters ^ blake2_pkg::IV; + t <= 128; + i_block.rdy <= 1; + v <= 0; + o_hash.val <= 0; + g_col <= 0; + round_cntr <= 0; + round_cntr_msg <= 0; + round_cntr_fin <= 0; + if (i_block.rdy && i_block.val && i_block.sop) begin + init_local_work_vector(i_byte_len, i_block.eop); + blake2_state <= STATE_ROUNDS; + g_col <= 0; + i_block.rdy <= 0; + block_eop_l <= i_block.eop; + end + end + // Here we do the compression over 12 rounds, each round can be done in two clock cycles + // After we do 12 rounds we increment counter t + STATE_ROUNDS: begin + + // Update local work vector with output of G function blocks depending on column or diagonal operation + for (int i = 0; i < 16; i++) begin + v[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]]; + end + + if (g_col) begin + round_cntr <= round_cntr + 1; + end else begin + round_cntr_msg <= (round_cntr_msg + 1) % 10; + end + if (round_cntr == ROUNDS-1) + round_cntr_fin <= 1; + + if (round_cntr_fin) begin + if (block_eop_l || EQUIHASH) + blake2_state <= STATE_FINAL_BLOCK; + else begin + blake2_state <= STATE_NEXT_BLOCK; + i_block.rdy <= 1; + end + end + end + STATE_NEXT_BLOCK: begin + round_cntr <= 0; + round_cntr_msg <= 0; + round_cntr_fin <= 0; + if (i_block.rdy && i_block.val) begin + init_local_work_vector(t, i_block.eop); //TODO this wont work with h_tmp + block_eop_l <= i_block.eop; + t <= t + 128; + h <= h ^ h_tmp; + blake2_state <= STATE_ROUNDS; + end + end + STATE_FINAL_BLOCK: begin + t <= 128; + round_cntr <= 0; + round_cntr_fin <= 0; + round_cntr_msg <= 0; + if (~o_hash.val || (o_hash.val && o_hash.rdy)) begin + if (~o_hash.val) begin + o_hash.dat <= h ^ h_tmp; + o_hash.val <= 1; + o_hash.sop <= 1; + o_hash.eop <= 1; + end + if (o_hash.rdy) begin + blake2_state <= STATE_IDLE; + i_block.rdy <= 1; + end + end + end + endcase + end +end + +// 8x G-function blocks. 4 are col and 4 are diagonal +generate begin + genvar gv_g; + for (gv_g = 0; gv_g < 8; gv_g++) begin: G_FUNCTION_GEN + + // For each G function we want to pipeline the input message to help timing + logic [63:0] m0, m1; + always_ff @ (posedge i_clk) begin + if(blake2_state == STATE_IDLE) begin + m0 <= block[blake2_pkg::SIGMA[gv_g*2]]; + m1 <= block[blake2_pkg::SIGMA[gv_g*2 + 1]]; + end else begin + m0 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2]]; + m1 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2 + 1]]; + end + end + + blake2_g + #(.PIPELINES(0)) + blake2_g ( + .i_clk(i_clk), + .i_a(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]]), + .i_b(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]]), + .i_c(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]]), + .i_d(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]]), + .i_m0(m0), + .i_m1(m1), + .o_a(g_out[gv_g*4 + 0]), + .o_b(g_out[gv_g*4 + 1]), + .o_c(g_out[gv_g*4 + 2]), + .o_d(g_out[gv_g*4 + 3])); + + end +end +endgenerate + +// Task to initialize local work vector for the compression function +task init_local_work_vector(input [127:0] cntr, input last_block); +begin + for (int i = 0; i < 16; i++) + case (i) inside + 0,1,2,3,4,5,6,7: v[i] <= h[i]; + 8,9,10,11: v[i] <= blake2_pkg::IV[i%8]; + 12: v[i] <= blake2_pkg::IV[i%8] ^ cntr[63:0]; + 13: v[i] <= blake2_pkg::IV[i%8] ^ cntr[64 +: 64]; + 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{last_block}}; + 15: v[i] <= blake2_pkg::IV[i%8]; + endcase +end +endtask + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/tb/blake2_top_tb.sv b/ip_cores/blake2b/src/tb/blake2_top_tb.sv index e8e9493..578d31e 100644 --- a/ip_cores/blake2b/src/tb/blake2_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2_top_tb.sv @@ -1,19 +1,15 @@ module blake2_top_tb(); import blake2_pkg::*; +import common_pkg::*; logic clk, rst; -logic [7:0] digest_byte_len, key_byte_len; -logic [128*8-1:0] i_block; -logic i_new_block; -logic i_final_block; -logic i_val; -logic[64*8-1:0] o_digest; -logic o_rdy; -logic o_val; -logic o_err; +logic [7:0] i_byte_len; +logic [64*8-1:0] parameters; -if_axi_stream #(.DAT_BYTS(blake2_pkg::NN)) out_hash(clk); +logic [64*8-1:0] expected; +if_axi_stream #(.DAT_BYTS(128)) i_block(clk); +if_axi_stream #(.DAT_BYTS(64)) out_hash(clk); initial begin rst = 0; @@ -28,67 +24,69 @@ end blake2_top DUT ( - .i_clk(clk), - .i_rst(rst), - .i_digest_byte_len( digest_byte_len ), - .i_key_byte_len( key_byte_len ), - .i_block(i_block), - .i_new_block(i_new_block), - .i_final_block(i_final_block), - .i_val(i_val), - .o_digest(o_digest), - .o_rdy(o_rdy), - .o_val(o_val), - .o_err(o_err), - - .o_hash(out_hash) + .i_clk ( clk ), + .i_rst ( rst ), + .i_parameters ( parameters ), + .i_byte_len ( i_byte_len ), + .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 - i_val = 0; - @(posedge clk); - while (!o_rdy) @(posedge clk); - - @(negedge clk); - i_val = 1; - i_final_block = 1; - i_new_block = 1; - digest_byte_len = 3; - key_byte_len = 0; - i_block = 'h636261; - - @(negedge clk); - i_val = 0; - - while (!out_hash.val) @(posedge clk); - - assert (out_hash.dat == 'h239900d4ed8623b95a92f1dba88ad31895cc3345ded552c22d79ab2a39c5877dd1a2ffdb6fbb124bb7c45a68142f214ce9f6129fb697276a0d4d1c983fa580ba) else $fatal(0, "%m %t:ERROR, out_hash.dat did not match, was:\n0x%h", $time, out_hash.dat); - assert (out_hash.sop == 1) else $fatal(0, "%m %t:ERROR, out_hash.sop was not high", $time); - assert (out_hash.eop == 1) else $fatal(0, "%m %t:ERROR, out_hash.sop was not high", $time); - + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + expected = 'h560c602c9cda1e198190f58e6341131f127367051c64f7df7d343e1b4c32a8bbc0eac1bcae463807dca442ae77d5150df700f6a640949a52cd4341dfc1e1044b; + i_byte_len = 3; + i_block.put_stream("hSV", i_byte_len); + out_hash.get_stream(get_dat, get_len); + common_pkg::compare_and_print(get_dat, expected); $display("rfc_test PASSED"); end endtask +// This is a test for hashing random string of 128 bytes +task test_128_bytes(); +begin + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + expected = 'hd2a56bb7bb1ff1fffcf2f151522455e32969ddfeb409b105f45299b8cbd68eb370fd6d45d63981d23cd2686dfd9a76f5b1d134be076f7d08ecc457522042e34a; + i_byte_len = 128; + i_block.put_stream("monek14SFMpNgHz12zMfplMfcHkx6JhKhSWTNwzGiq8UiPa4n4Ehq363oHG92GPDVpvQut4ui5e6XxieeKTn1THLWiMZ0iaOFndxcT6FGPgmHXQ5zJU96X71zfWbvUQs", i_byte_len); + out_hash.get_stream(get_dat, get_len); + common_pkg::compare_and_print(get_dat, expected); + $display("test_128_bytes PASSED"); +end +endtask + +// This is a test for hashing random string of 140 bytes (does two passes which is required for equihash) +task test_140_bytes(); +begin + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + expected = 'h429b65332e3b6701a29664f98c247204858479f55a8c18cc9b0ffa321cda4288fd420a5d47d134949f3b858bff7a696a00d91a07c92055cdd597971cf573281c; + i_byte_len = 140; + i_block.put_stream("6RehRZqUdYD2SB3N35QlQhreiU2XEaSgIGUsreLqV49l8Z5r93FbP567Juqc1IUaVyJKv8qFmtQwXYvZdnrMacAs5H9hBhs5JxAfyDibIM3TjKyiVzXC8lfCqiN1j6fW8FSJY131mVpw", i_byte_len); + out_hash.get_stream(get_dat, get_len); + common_pkg::compare_and_print(get_dat, expected); + $display("test_140_bytes PASSED"); +end +endtask + // Main testbench calls initial begin - key_byte_len = 0; - digest_byte_len = 3; - i_block = '0; - i_new_block = '0; - i_final_block = '0; - i_val = '0; + i_block.reset_source(); + i_byte_len = 3; out_hash.rdy = 1; - - + parameters = {32'd0, 8'd1, 8'd1, 8'd0, 8'd64}; #200ns; - rfc_test(); + //test_128_bytes(); + //test_140_bytes(); - #100ns $finish(); + #10us $finish(); end diff --git a/ip_cores/blake2b/synth/blake2g_top.xdc b/ip_cores/blake2b/synth/blake2g_top.xdc index 5d8cffe..933adcc 100644 --- a/ip_cores/blake2b/synth/blake2g_top.xdc +++ b/ip_cores/blake2b/synth/blake2g_top.xdc @@ -1 +1 @@ -create_clock -period 2.000 -name i_clk -waveform {0.000 1.000} [get_ports -filter { NAME =~ "*clk*" && DIRECTION == "IN" }] +create_clock -period 5.000 -name i_clk -waveform {0.000 2.500} [get_ports -filter { NAME =~ "i_clk" && DIRECTION == "IN" }] diff --git a/ip_cores/common/src/rtl/common_if.sv b/ip_cores/common/src/rtl/common_if.sv index fc4c1d1..841cb93 100644 --- a/ip_cores/common/src/rtl/common_if.sv +++ b/ip_cores/common/src/rtl/common_if.sv @@ -4,9 +4,9 @@ interface if_axi_stream # ( parameter DAT_BYTS = 8, parameter CTL_BYTS = 8 )( - input i_clk + input clk ); - + import common_pkg::*; localparam DAT_BITS = DAT_BYTS*8; localparam CTL_BITS = CTL_BYTS*8; @@ -19,7 +19,11 @@ interface if_axi_stream # ( logic [DAT_BITS-1:0] dat; logic [$clog2(DAT_BYTS)-1:0] mod; - task reset(); + modport sink (input val, err, sop, eop, ctl, dat, output rdy); + modport source (output val, err, sop, eop, ctl, dat, input rdy, import task reset_source()); + + // Task to reset a source interface signals to all 0 + task reset_source(); val <= 0; err <= 0; sop <= 0; @@ -29,4 +33,49 @@ interface if_axi_stream # ( mod <= 0; endtask + // Task used in simulation to drive data on a source interface + task automatic put_stream(input logic [common_pkg::MAX_SIM_BYTS*8-1:0] data, input integer signed len); + logic sop_l=0; + + reset_source(); + @(posedge clk); + + while (len > 0) begin + sop = ~sop_l; + eop = len - DAT_BYTS <= 0; + val = 1; + dat = data; + if (eop) mod = len; + data = data >> DAT_BITS; + sop_l = 1; + len = len - DAT_BYTS; + @(posedge clk); // Go to next clock edge + while (!rdy) @(posedge clk); // If not rdy then wait here + end + reset_source(); + endtask + + // Task used in simulation to get data from a sink interface + task automatic get_stream(ref logic [common_pkg::MAX_SIM_BYTS*8-1:0] data, ref integer signed len); + logic sop_l = 0; + rdy = 1; + len = 0; + data = 0; + @(posedge clk); + + while (1) begin + if (val && rdy) begin + sop_l = sop_l || sop; + if (!sop_l) $warning("%m %t:WARNING, get_stream() .val without seeing .sop", $time); + data[len*8 +: DAT_BITS] = dat; + len = len + (eop ? (mod == 0 ? DAT_BYTS : mod) : DAT_BYTS); + if (eop) break; + end + @(posedge clk); + end + + + endtask + + endinterface \ No newline at end of file diff --git a/ip_cores/common/src/rtl/common_pkg.sv b/ip_cores/common/src/rtl/common_pkg.sv new file mode 100644 index 0000000..a397d1c --- /dev/null +++ b/ip_cores/common/src/rtl/common_pkg.sv @@ -0,0 +1,24 @@ +// Common parameter values and tasks +package common_pkg; + parameter MAX_SIM_BYTS = 1024; // In simulation tasks how big is the logic register for putting / getting data + + // Compare bytes and print if they do not match + task compare_and_print(input logic [MAX_SIM_BYTS*8-1:0] data, expected); + if (data == expected) begin + $display("%m %t INFO: Data matched", $time); + end else begin + $write("exp: 0x"); + while(expected != 0) begin + $write("%x", expected[7:0]); + expected = expected >> 8; + end + $write("\nwas: 0x"); + while(data != 0) begin + $write("%x", data[7:0]); + data = data >> 8; + end + $write("\n"); + $fatal(1, "%m %t ERROR: data did not match", $time); + end + endtask +endpackage \ No newline at end of file From 1992538306bd4edd862e586be134a76dd8162b59 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Wed, 13 Feb 2019 15:23:22 -0500 Subject: [PATCH 06/16] Update to blake2 core to work correctly with messages larger than 128 bytes, added testbench for checking this. --- ip_cores/blake2b/src/rtl/blake2_pkg.sv | 44 ++++++++++---------- ip_cores/blake2b/src/rtl/blake2_top.sv | 51 ++++++++++++++---------- ip_cores/blake2b/src/tb/blake2_top_tb.sv | 12 +++--- 3 files changed, 58 insertions(+), 49 deletions(-) diff --git a/ip_cores/blake2b/src/rtl/blake2_pkg.sv b/ip_cores/blake2b/src/rtl/blake2_pkg.sv index 9654b3c..af48313 100644 --- a/ip_cores/blake2b/src/rtl/blake2_pkg.sv +++ b/ip_cores/blake2b/src/rtl/blake2_pkg.sv @@ -14,37 +14,37 @@ package blake2_pkg; // Sigma permutations used for G function blocks and input messages parameter [16*10-1:0][31:0] SIGMA = { - 0, 13, 12, 3, 14, 9, 11, 15, 5, 1, 6, 7, 4, 8, 2, 10, - 5, 10, 4, 1, 7, 13, 2, 12, 8, 0, 3, 11, 9, 14, 15, 6, - 10, 2, 6, 8, 4, 15, 0, 5, 9, 3, 1, 12, 14, 7, 11, 13, - 11, 8, 2, 9, 3, 6, 7, 0, 10, 4, 13, 14, 15, 1, 5, 12, - 9, 1, 14, 15, 5, 7, 13, 4, 3, 8, 11, 0, 10, 6, 12, 2, - 13, 3, 8, 6, 12, 11, 1, 14, 15, 10, 4, 2, 7, 5, 0, 9, - 8, 15, 0, 4, 10, 5, 6, 2, 14, 11, 12, 13, 1, 3, 9, 7, - 4, 9, 1, 7, 6, 3, 14, 10, 13, 15, 2, 5, 0, 12, 8, 11, - 3, 5, 7, 11, 2, 0, 12, 1, 6, 13, 15, 9, 8, 4, 10, 14, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + 32'd0, 32'd13, 32'd12, 32'd3, 32'd14, 32'd9, 32'd11, 32'd15, 32'd5, 32'd1, 32'd6, 32'd7, 32'd4, 32'd8, 32'd2, 32'd10, + 32'd5, 32'd10, 32'd4, 32'd1, 32'd7, 32'd13, 32'd2, 32'd12, 32'd8, 32'd0, 32'd3, 32'd11, 32'd9, 32'd14, 32'd15, 32'd6, + 32'd10, 32'd2, 32'd6, 32'd8, 32'd4, 32'd15, 32'd0, 32'd5, 32'd9, 32'd3, 32'd1, 32'd12, 32'd14, 32'd7, 32'd11, 32'd13, + 32'd11, 32'd8, 32'd2, 32'd9, 32'd3, 32'd6, 32'd7, 32'd0, 32'd10, 32'd4, 32'd13, 32'd14, 32'd15, 32'd1, 32'd5, 32'd12, + 32'd9, 32'd1, 32'd14, 32'd15, 32'd5, 32'd7, 32'd13, 32'd4, 32'd3, 32'd8, 32'd11, 32'd0, 32'd10, 32'd6, 32'd12, 32'd2, + 32'd13, 32'd3, 32'd8, 32'd6, 32'd12, 32'd11, 32'd1, 32'd14, 32'd15, 32'd10, 32'd4, 32'd2, 32'd7, 32'd5, 32'd0, 32'd9, + 32'd8, 32'd15, 32'd0, 32'd4, 32'd10, 32'd5, 32'd6, 32'd2, 32'd14, 32'd11, 32'd12, 32'd13, 32'd1, 32'd3, 32'd9, 32'd7, + 32'd4, 32'd9, 32'd1, 32'd7, 32'd6, 32'd3, 32'd14, 32'd10, 32'd13, 32'd15, 32'd2, 32'd5, 32'd0, 32'd12, 32'd8, 32'd11, + 32'd3, 32'd5, 32'd7, 32'd11, 32'd2, 32'd0, 32'd12, 32'd1, 32'd6, 32'd13, 32'd15, 32'd9, 32'd8, 32'd4, 32'd10, 32'd14, + 32'd15, 32'd14, 32'd13, 32'd12, 32'd11, 32'd10, 32'd9, 32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2, 32'd1, 32'd0 }; // Mapping for each G function block to the state vector v parameter [4*8-1:0][31:0] G_MAPPING = { - 14, 9, 4, 3, - 13, 8, 7, 2, - 12, 11, 6, 1, - 15, 10, 5, 0, - 15, 11, 7, 3, - 14, 10, 6, 2, - 13, 9, 5, 1, - 12, 8, 4, 0 + 32'd14, 32'd9, 32'd4, 32'd3, + 32'd13, 32'd8, 32'd7, 32'd2, + 32'd12, 32'd11, 32'd6, 32'd1, + 32'd15, 32'd10, 32'd5, 32'd0, + 32'd15, 32'd11, 32'd7, 32'd3, + 32'd14, 32'd10, 32'd6, 32'd2, + 32'd13, 32'd9, 32'd5, 32'd1, + 32'd12, 32'd8, 32'd4, 32'd0 }; // This is so we can get the correct mapping back from the diagonal // operation parameter [4*4-1:0][31:0] G_MAPPING_DIAG = { - 3, 15, 11,7, - 6, 2, 14, 10, - 9, 5, 1, 13, - 12, 8 , 4, 0 + 32'd3, 32'd15, 32'd11, 32'd7, + 32'd6, 32'd2, 32'd14, 32'd10, + 32'd9, 32'd5, 32'd1, 32'd13, + 32'd12, 32'd8 , 32'd4, 32'd0 }; endpackage \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2_top.sv b/ip_cores/blake2b/src/rtl/blake2_top.sv index 2422a40..995120b 100644 --- a/ip_cores/blake2b/src/rtl/blake2_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2_top.sv @@ -1,6 +1,6 @@ /* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) - * Personalization string in the input parameter should be "ZcashPoW" followed by n and k in - * little endian order. + * Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. + * Only only hash is computed at a time, and takes 26 clocks * number of 128 Byte message blocks. */ module blake2_top @@ -24,32 +24,33 @@ localparam ROUNDS = 12; logic [7:0][63:0] h, h_tmp; // The state vector logic [15:0][63:0] v, v_tmp; // The local work vector and its intermediate value -logic [31:0][63:0] g_out;//, g_out_r; // Outputs of the G mixing function - use 8 here to save on timing -logic [127:0] t; // Counter - TODO make this smaller - related to param +logic [31:0][63:0] g_out; // Outputs of the G mixing function - use 8 here to save on timing +logic [127:0] t; // Counter logic [$clog2(ROUNDS)-1:0] round_cntr, round_cntr_msg, round_cntr_fin; logic g_col; logic [15:0][63:0] block, block_r; // The message block registered and converted to a 2d array logic block_eop_l; // Use to latch if this is the final block +logic h_xor_done; +logic [7:0] byte_len_l; // Pipelining logic that has no reset always_ff @(posedge i_clk) begin - //g_out_r <= g_out; + if (blake2_state == STATE_IDLE && ~i_block.rdy) + block_r <= 0; - if (blake2_state == STATE_IDLE) begin - block_r <= 0; - if (i_block.val && i_block.rdy) begin - block_r <= i_block.dat; - end + if (i_block.val && i_block.rdy) begin + block_r <= i_block.dat; end + for (int i = 0; i < 16; i++) - if (g_col == 0/* && blake2_state == STATE_ROUNDS*/) // TODO why do I need this qualifier + if (g_col == 0) v_tmp[i] <= g_out[blake2_pkg::G_MAPPING[i]]; for (int i = 0; i < 8; i++) if (blake2_state == STATE_ROUNDS) - h_tmp[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; //TODO fix + h_tmp[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; end @@ -71,14 +72,16 @@ always_ff @(posedge i_clk) begin o_hash.reset_source(); round_cntr_fin <= 0; block_eop_l <= 0; + h_xor_done <= 0; + byte_len_l <= 0; end else begin - if (blake2_state != STATE_NEXT_BLOCK) g_col <= ~g_col; + g_col <= ~g_col; case (blake2_state) STATE_IDLE: begin h <= i_parameters ^ blake2_pkg::IV; - t <= 128; + t <= 2; i_block.rdy <= 1; v <= 0; o_hash.val <= 0; @@ -87,11 +90,12 @@ always_ff @(posedge i_clk) begin round_cntr_msg <= 0; round_cntr_fin <= 0; if (i_block.rdy && i_block.val && i_block.sop) begin - init_local_work_vector(i_byte_len, i_block.eop); + init_local_work_vector(i_block.eop ? i_byte_len : 128, i_block.eop); blake2_state <= STATE_ROUNDS; g_col <= 0; i_block.rdy <= 0; block_eop_l <= i_block.eop; + byte_len_l <= i_byte_len; end end // Here we do the compression over 12 rounds, each round can be done in two clock cycles @@ -116,7 +120,6 @@ always_ff @(posedge i_clk) begin blake2_state <= STATE_FINAL_BLOCK; else begin blake2_state <= STATE_NEXT_BLOCK; - i_block.rdy <= 1; end end end @@ -124,16 +127,22 @@ always_ff @(posedge i_clk) begin round_cntr <= 0; round_cntr_msg <= 0; round_cntr_fin <= 0; + h_xor_done <= 1; + i_block.rdy <= 1; + if (~h_xor_done) + for (int i = 0; i < 8; i++) + h[i] <= h[i] ^ h_tmp[i]; if (i_block.rdy && i_block.val) begin - init_local_work_vector(t, i_block.eop); //TODO this wont work with h_tmp + init_local_work_vector(i_block.eop ? byte_len_l : t*128, i_block.eop); block_eop_l <= i_block.eop; - t <= t + 128; - h <= h ^ h_tmp; + t <= t + 1; blake2_state <= STATE_ROUNDS; + h_xor_done <= 0; + i_block.rdy <= 0; + g_col <= 0; end end STATE_FINAL_BLOCK: begin - t <= 128; round_cntr <= 0; round_cntr_fin <= 0; round_cntr_msg <= 0; @@ -162,7 +171,7 @@ generate begin // For each G function we want to pipeline the input message to help timing logic [63:0] m0, m1; always_ff @ (posedge i_clk) begin - if(blake2_state == STATE_IDLE) begin + if(blake2_state == STATE_IDLE || blake2_state == STATE_NEXT_BLOCK) begin m0 <= block[blake2_pkg::SIGMA[gv_g*2]]; m1 <= block[blake2_pkg::SIGMA[gv_g*2 + 1]]; end else begin diff --git a/ip_cores/blake2b/src/tb/blake2_top_tb.sv b/ip_cores/blake2b/src/tb/blake2_top_tb.sv index 578d31e..2c6048c 100644 --- a/ip_cores/blake2b/src/tb/blake2_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2_top_tb.sv @@ -37,9 +37,9 @@ task rfc_test(); begin integer signed get_len; logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; - expected = 'h560c602c9cda1e198190f58e6341131f127367051c64f7df7d343e1b4c32a8bbc0eac1bcae463807dca442ae77d5150df700f6a640949a52cd4341dfc1e1044b; + expected = 'h239900d4ed8623b95a92f1dba88ad31895cc3345ded552c22d79ab2a39c5877dd1a2ffdb6fbb124bb7c45a68142f214ce9f6129fb697276a0d4d1c983fa580ba; i_byte_len = 3; - i_block.put_stream("hSV", i_byte_len); + i_block.put_stream("cba", i_byte_len); out_hash.get_stream(get_dat, get_len); common_pkg::compare_and_print(get_dat, expected); $display("rfc_test PASSED"); @@ -65,9 +65,9 @@ task test_140_bytes(); begin integer signed get_len; logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; - expected = 'h429b65332e3b6701a29664f98c247204858479f55a8c18cc9b0ffa321cda4288fd420a5d47d134949f3b858bff7a696a00d91a07c92055cdd597971cf573281c; + expected = 'h2012a869a3b89a69ffc954f6855c7f61a61190553dc487171ec3fe944d04c83cd4c842fff5a8258d5e14b05b7b6f30e8ddcb754d719137ec42fb5cdb562f8c89; i_byte_len = 140; - i_block.put_stream("6RehRZqUdYD2SB3N35QlQhreiU2XEaSgIGUsreLqV49l8Z5r93FbP567Juqc1IUaVyJKv8qFmtQwXYvZdnrMacAs5H9hBhs5JxAfyDibIM3TjKyiVzXC8lfCqiN1j6fW8FSJY131mVpw", i_byte_len); + i_block.put_stream("YbEAEzgJ1tgC3t6vDaJFqlWp1PaL482f7iZZzRj3xXpY2PPupwdTKAaBzB6KuN6j0alaoaFQfNboDbkNv5KDs5d7zN9JssrtOjGJdrVLfvb7uAdnVYoIgIv2zbXUQIPpwWdzEzj1CzX5", i_byte_len); out_hash.get_stream(get_dat, get_len); common_pkg::compare_and_print(get_dat, expected); $display("test_140_bytes PASSED"); @@ -83,8 +83,8 @@ initial begin #200ns; rfc_test(); - //test_128_bytes(); - //test_140_bytes(); + test_128_bytes(); + test_140_bytes(); #10us $finish(); From e86828b7711ea45fcfe61fb3e1a85663f69797ff Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Wed, 13 Feb 2019 15:24:46 -0500 Subject: [PATCH 07/16] Correct name from blake2 -> blake2b --- ip_cores/blake2b/src/rtl/{blake2_g.sv => blake2b_g.sv} | 0 ip_cores/blake2b/src/rtl/{blake2_pkg.sv => blake2b_pkg.sv} | 0 ip_cores/blake2b/src/rtl/{blake2_top.sv => blake2b_top.sv} | 0 ip_cores/blake2b/src/tb/{blake2_g_tb.sv => blake2b_g_tb.sv} | 0 ip_cores/blake2b/src/tb/{blake2_top_tb.sv => blake2b_top_tb.sv} | 0 ip_cores/blake2b/synth/{blake2g_top.xdc => blake2b_top.xdc} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename ip_cores/blake2b/src/rtl/{blake2_g.sv => blake2b_g.sv} (100%) rename ip_cores/blake2b/src/rtl/{blake2_pkg.sv => blake2b_pkg.sv} (100%) rename ip_cores/blake2b/src/rtl/{blake2_top.sv => blake2b_top.sv} (100%) rename ip_cores/blake2b/src/tb/{blake2_g_tb.sv => blake2b_g_tb.sv} (100%) rename ip_cores/blake2b/src/tb/{blake2_top_tb.sv => blake2b_top_tb.sv} (100%) rename ip_cores/blake2b/synth/{blake2g_top.xdc => blake2b_top.xdc} (100%) diff --git a/ip_cores/blake2b/src/rtl/blake2_g.sv b/ip_cores/blake2b/src/rtl/blake2b_g.sv similarity index 100% rename from ip_cores/blake2b/src/rtl/blake2_g.sv rename to ip_cores/blake2b/src/rtl/blake2b_g.sv diff --git a/ip_cores/blake2b/src/rtl/blake2_pkg.sv b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv similarity index 100% rename from ip_cores/blake2b/src/rtl/blake2_pkg.sv rename to ip_cores/blake2b/src/rtl/blake2b_pkg.sv diff --git a/ip_cores/blake2b/src/rtl/blake2_top.sv b/ip_cores/blake2b/src/rtl/blake2b_top.sv similarity index 100% rename from ip_cores/blake2b/src/rtl/blake2_top.sv rename to ip_cores/blake2b/src/rtl/blake2b_top.sv diff --git a/ip_cores/blake2b/src/tb/blake2_g_tb.sv b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv similarity index 100% rename from ip_cores/blake2b/src/tb/blake2_g_tb.sv rename to ip_cores/blake2b/src/tb/blake2b_g_tb.sv diff --git a/ip_cores/blake2b/src/tb/blake2_top_tb.sv b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv similarity index 100% rename from ip_cores/blake2b/src/tb/blake2_top_tb.sv rename to ip_cores/blake2b/src/tb/blake2b_top_tb.sv diff --git a/ip_cores/blake2b/synth/blake2g_top.xdc b/ip_cores/blake2b/synth/blake2b_top.xdc similarity index 100% rename from ip_cores/blake2b/synth/blake2g_top.xdc rename to ip_cores/blake2b/synth/blake2b_top.xdc From 18c08450dfa9d8765e0b3b58be070b9f453ec5d6 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Wed, 13 Feb 2019 15:27:13 -0500 Subject: [PATCH 08/16] Rename modules in files to blake2b --- ip_cores/blake2b/src/rtl/blake2b_g.sv | 2 +- ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv | 211 +------------------ ip_cores/blake2b/src/rtl/blake2b_pkg.sv | 2 +- ip_cores/blake2b/src/rtl/blake2b_top.sv | 42 ++-- ip_cores/blake2b/src/tb/blake2b_g_tb.sv | 4 +- ip_cores/blake2b/src/tb/blake2b_top_tb.sv | 6 +- 6 files changed, 32 insertions(+), 235 deletions(-) diff --git a/ip_cores/blake2b/src/rtl/blake2b_g.sv b/ip_cores/blake2b/src/rtl/blake2b_g.sv index 5a18bd6..aef2d5a 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_g.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_g.sv @@ -1,4 +1,4 @@ -module blake2_g +module blake2b_g #( parameter PIPELINES = 1 // Do we want to optionally add pipeline stages ) diff --git a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv index 7120235..0ec9468 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv @@ -1,207 +1,4 @@ -/* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) - * This is a unrolled pipelined version of the hash function required for Equihash. - * A single has takes 25 clock cycles but - */ - -module blake2_pipe_top - import blake2_pkg::*; -#( -) -( - input i_clk, i_rst, - - input [7:0] i_byte_len, // Length of the input message - input [64*8-1:0] i_parameters, // Input parameters used in the inital state - - if_axi_stream.sink i_block, // Input block with valid and ready signals for flow control - if_axi_stream.source o_hash // Output digest with valid and ready signals for flow control -); - -enum {STATE_IDLE = 0, - STATE_ROUNDS = 1, - STATE_NEXT_BLOCK = 2, - STATE_FINAL_BLOCK = 3} blake2_state; - -localparam ROUNDS = 12; - -logic [7:0][63:0] h, h_tmp; // The state vector -logic [15:0][63:0] v, v_tmp; // The local work vector and its intermediate value -logic [31:0][63:0] g_out, g_out_r; // Outputs of the G mixing function - use 8 here to save on timing -logic [127:0] t; // Counter - TODO make this smaller - related to param -logic [$clog2(ROUNDS)-1:0] round_cntr, round_cntr_msg, round_cntr_fin; -logic g_col; -logic [15:0][63:0] block, block_r; // The message block registered and converted to a 2d array -logic block_eop_l; // Use to latch if this is the final block - -// Pipelining logic that has no reset -always_ff @(posedge i_clk) begin - - g_out_r <= g_out; - - if (i_block.val && i_block.rdy) begin - block_r <= i_block.dat; - end - - for (int i = 0; i < 16; i++) - if (g_col == 0) // TODO why do I need this qualifier - v_tmp[i] <= g_out[blake2_pkg::G_MAPPING[i]]; - - for (int i = 0; i < 8; i++) - if (blake2_state == STATE_ROUNDS) - h_tmp[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; //TODO fix - -end - -always_comb begin - block = i_block.dat; -end - -// State machine logic for compressing -always_ff @(posedge i_clk) begin - if (i_rst) begin - blake2_state <= STATE_IDLE; - i_block.rdy <= 0; - h <= 0; - v <= 0; - t <= 128; - g_col <= 0; - round_cntr <= 0; - round_cntr_msg <= 0; - o_hash.reset_source(); - round_cntr_fin <= 0; - block_eop_l <= 0; - end else begin - - g_col <= ~g_col; - - case (blake2_state) - STATE_IDLE: begin - h <= i_parameters ^ blake2_pkg::IV; - t <= 128; - i_block.rdy <= 1; - v <= 0; - o_hash.val <= 0; - g_col <= 0; - round_cntr <= 0; - round_cntr_msg <= 0; - round_cntr_fin <= 0; - if (i_block.rdy && i_block.val && i_block.sop) begin - init_local_work_vector(i_byte_len, i_block.eop); - blake2_state <= STATE_ROUNDS; - g_col <= 0; - i_block.rdy <= 0; - block_eop_l <= i_block.eop; - end - end - // Here we do the compression over 12 rounds, each round can be done in two clock cycles - // After we do 12 rounds we increment counter t - STATE_ROUNDS: begin - - // Update local work vector with output of G function blocks depending on column or diagonal operation - for (int i = 0; i < 16; i++) begin - v[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]]; - end - - if (g_col) begin - round_cntr <= round_cntr + 1; - end else begin - round_cntr_msg <= (round_cntr_msg + 1) % 10; - end - if (round_cntr == ROUNDS-1) - round_cntr_fin <= 1; - - if (round_cntr_fin) begin - if (block_eop_l || EQUIHASH) - blake2_state <= STATE_FINAL_BLOCK; - else begin - blake2_state <= STATE_NEXT_BLOCK; - i_block.rdy <= 1; - end - end - end - STATE_NEXT_BLOCK: begin - round_cntr <= 0; - round_cntr_msg <= 0; - round_cntr_fin <= 0; - if (i_block.rdy && i_block.val) begin - init_local_work_vector(t, i_block.eop); //TODO this wont work with h_tmp - block_eop_l <= i_block.eop; - t <= t + 128; - h <= h ^ h_tmp; - blake2_state <= STATE_ROUNDS; - end - end - STATE_FINAL_BLOCK: begin - t <= 128; - round_cntr <= 0; - round_cntr_fin <= 0; - round_cntr_msg <= 0; - if (~o_hash.val || (o_hash.val && o_hash.rdy)) begin - if (~o_hash.val) begin - o_hash.dat <= h ^ h_tmp; - o_hash.val <= 1; - o_hash.sop <= 1; - o_hash.eop <= 1; - end - if (o_hash.rdy) begin - blake2_state <= STATE_IDLE; - i_block.rdy <= 1; - end - end - end - endcase - end -end - -// 8x G-function blocks. 4 are col and 4 are diagonal -generate begin - genvar gv_g; - for (gv_g = 0; gv_g < 8; gv_g++) begin: G_FUNCTION_GEN - - // For each G function we want to pipeline the input message to help timing - logic [63:0] m0, m1; - always_ff @ (posedge i_clk) begin - if(blake2_state == STATE_IDLE) begin - m0 <= block[blake2_pkg::SIGMA[gv_g*2]]; - m1 <= block[blake2_pkg::SIGMA[gv_g*2 + 1]]; - end else begin - m0 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2]]; - m1 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2 + 1]]; - end - end - - blake2_g - #(.PIPELINES(0)) - blake2_g ( - .i_clk(i_clk), - .i_a(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]]), - .i_b(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]]), - .i_c(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]]), - .i_d(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]]), - .i_m0(m0), - .i_m1(m1), - .o_a(g_out[gv_g*4 + 0]), - .o_b(g_out[gv_g*4 + 1]), - .o_c(g_out[gv_g*4 + 2]), - .o_d(g_out[gv_g*4 + 3])); - - end -end -endgenerate - -// Task to initialize local work vector for the compression function -task init_local_work_vector(input [127:0] cntr, input last_block); -begin - for (int i = 0; i < 16; i++) - case (i) inside - 0,1,2,3,4,5,6,7: v[i] <= h[i]; - 8,9,10,11: v[i] <= blake2_pkg::IV[i%8]; - 12: v[i] <= blake2_pkg::IV[i%8] ^ cntr[63:0]; - 13: v[i] <= blake2_pkg::IV[i%8] ^ cntr[64 +: 64]; - 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{last_block}}; - 15: v[i] <= blake2_pkg::IV[i%8]; - endcase -end -endtask - -endmodule \ No newline at end of file +/* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) + * Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. + * This is a pipeline-unrolled version for higher performance (but more resource usage) + */ \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv index af48313..7837a1d 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv @@ -1,4 +1,4 @@ -package blake2_pkg; +package blake2b_pkg; // Initial values parameter [7:0][63:0] IV = { diff --git a/ip_cores/blake2b/src/rtl/blake2b_top.sv b/ip_cores/blake2b/src/rtl/blake2b_top.sv index 995120b..c2204ff 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_top.sv @@ -3,8 +3,8 @@ * Only only hash is computed at a time, and takes 26 clocks * number of 128 Byte message blocks. */ -module blake2_top - import blake2_pkg::*; +module blake2b_top + import blake2b_pkg::*; ( input i_clk, i_rst, @@ -46,11 +46,11 @@ always_ff @(posedge i_clk) begin for (int i = 0; i < 16; i++) if (g_col == 0) - v_tmp[i] <= g_out[blake2_pkg::G_MAPPING[i]]; + v_tmp[i] <= g_out[blake2b_pkg::G_MAPPING[i]]; for (int i = 0; i < 8; i++) if (blake2_state == STATE_ROUNDS) - h_tmp[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2_pkg::G_MAPPING_DIAG[i+8]]; + h_tmp[i] <= g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i+8]]; end @@ -80,7 +80,7 @@ always_ff @(posedge i_clk) begin case (blake2_state) STATE_IDLE: begin - h <= i_parameters ^ blake2_pkg::IV; + h <= i_parameters ^ blake2b_pkg::IV; t <= 2; i_block.rdy <= 1; v <= 0; @@ -104,7 +104,7 @@ always_ff @(posedge i_clk) begin // Update local work vector with output of G function blocks depending on column or diagonal operation for (int i = 0; i < 16; i++) begin - v[i] <= g_out[16 + blake2_pkg::G_MAPPING_DIAG[i]]; + v[i] <= g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i]]; end if (g_col) begin @@ -172,22 +172,22 @@ generate begin logic [63:0] m0, m1; always_ff @ (posedge i_clk) begin if(blake2_state == STATE_IDLE || blake2_state == STATE_NEXT_BLOCK) begin - m0 <= block[blake2_pkg::SIGMA[gv_g*2]]; - m1 <= block[blake2_pkg::SIGMA[gv_g*2 + 1]]; + m0 <= block[blake2b_pkg::SIGMA[gv_g*2]]; + m1 <= block[blake2b_pkg::SIGMA[gv_g*2 + 1]]; end else begin - m0 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2]]; - m1 <= block_r[blake2_pkg::SIGMA[16*round_cntr_msg + gv_g*2 + 1]]; + m0 <= block_r[blake2b_pkg::SIGMA[16*round_cntr_msg + gv_g*2]]; + m1 <= block_r[blake2b_pkg::SIGMA[16*round_cntr_msg + gv_g*2 + 1]]; end end - blake2_g + blake2b_g #(.PIPELINES(0)) - blake2_g ( + blake2b_g ( .i_clk(i_clk), - .i_a(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 0)]]), - .i_b(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 1)]]), - .i_c(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 2)]]), - .i_d(gv_g < 4 ? v[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]] : v_tmp[blake2_pkg::G_MAPPING[(gv_g*4 + 3)]]), + .i_a(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 0)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 0)]]), + .i_b(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 1)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 1)]]), + .i_c(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 2)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 2)]]), + .i_d(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 3)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 3)]]), .i_m0(m0), .i_m1(m1), .o_a(g_out[gv_g*4 + 0]), @@ -205,11 +205,11 @@ begin for (int i = 0; i < 16; i++) case (i) inside 0,1,2,3,4,5,6,7: v[i] <= h[i]; - 8,9,10,11: v[i] <= blake2_pkg::IV[i%8]; - 12: v[i] <= blake2_pkg::IV[i%8] ^ cntr[63:0]; - 13: v[i] <= blake2_pkg::IV[i%8] ^ cntr[64 +: 64]; - 14: v[i] <= blake2_pkg::IV[i%8] ^ {64{last_block}}; - 15: v[i] <= blake2_pkg::IV[i%8]; + 8,9,10,11: v[i] <= blake2b_pkg::IV[i%8]; + 12: v[i] <= blake2b_pkg::IV[i%8] ^ cntr[63:0]; + 13: v[i] <= blake2b_pkg::IV[i%8] ^ cntr[64 +: 64]; + 14: v[i] <= blake2b_pkg::IV[i%8] ^ {64{last_block}}; + 15: v[i] <= blake2b_pkg::IV[i%8]; endcase end endtask diff --git a/ip_cores/blake2b/src/tb/blake2b_g_tb.sv b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv index 19953c0..c2334a3 100644 --- a/ip_cores/blake2b/src/tb/blake2b_g_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv @@ -1,10 +1,10 @@ -module blake2_g_tb(); +module blake2b_g_tb(); logic clk; logic [63:0] o_a, o_b, o_c, o_d, i_a, i_b, i_c, i_d, i_m0, i_m1; localparam PIPELINES = 1; -blake2_g #(.PIPELINES(PIPELINES)) DUT (.i_clk(clk), .o_a(o_a), .o_b(o_b), .o_c(o_c), .o_d(o_d), .i_a(i_a), .i_b(i_b), .i_c(i_c), .i_d(i_d), .i_m0(i_m0), .i_m1(i_m1)); +blake2b_g #(.PIPELINES(PIPELINES)) DUT (.i_clk(clk), .o_a(o_a), .o_b(o_b), .o_c(o_c), .o_d(o_d), .i_a(i_a), .i_b(i_b), .i_c(i_c), .i_d(i_d), .i_m0(i_m0), .i_m1(i_m1)); initial begin clk = 0; diff --git a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv index 2c6048c..8b0ae50 100644 --- a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv @@ -1,6 +1,6 @@ -module blake2_top_tb(); +module blake2b_top_tb(); -import blake2_pkg::*; +import blake2b_pkg::*; import common_pkg::*; logic clk, rst; @@ -23,7 +23,7 @@ initial begin end -blake2_top DUT ( +blake2b_top DUT ( .i_clk ( clk ), .i_rst ( rst ), .i_parameters ( parameters ), From 70e1598c451c4c1ebf4d52b952b6dd6f4fb7ff66 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Wed, 13 Feb 2019 16:43:19 -0500 Subject: [PATCH 09/16] Bug updates, now working correctly for all test cases --- ip_cores/blake2b/src/rtl/blake2b_pkg.sv | 2 +- ip_cores/blake2b/src/rtl/blake2b_top.sv | 27 +++++++++-------------- ip_cores/blake2b/src/tb/blake2b_top_tb.sv | 3 +++ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv index 7837a1d..7a22548 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv @@ -10,7 +10,7 @@ package blake2b_pkg; 64'h3c6ef372fe94f82b, 64'hbb67ae8584caa73b, 64'h6a09e667f3bcc908 - }; + }; // Sigma permutations used for G function blocks and input messages parameter [16*10-1:0][31:0] SIGMA = { diff --git a/ip_cores/blake2b/src/rtl/blake2b_top.sv b/ip_cores/blake2b/src/rtl/blake2b_top.sv index c2204ff..a72a43b 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_top.sv @@ -1,4 +1,4 @@ -/* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) +/* Implemented from RFC-7693, The BLAKE2b Cryptographic Hash and Message Authentication Code (MAC) * Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. * Only only hash is computed at a time, and takes 26 clocks * number of 128 Byte message blocks. */ @@ -36,17 +36,15 @@ logic [7:0] byte_len_l; // Pipelining logic that has no reset always_ff @(posedge i_clk) begin - if (blake2_state == STATE_IDLE && ~i_block.rdy) + if (blake2_state == STATE_IDLE) block_r <= 0; - if (i_block.val && i_block.rdy) begin + if (i_block.val && i_block.rdy) block_r <= i_block.dat; - end - - for (int i = 0; i < 16; i++) - if (g_col == 0) - v_tmp[i] <= g_out[blake2b_pkg::G_MAPPING[i]]; + for (int i = 0; i < 16; i++) begin + v_tmp[blake2b_pkg::G_MAPPING[i]] <= g_out[i]; + end for (int i = 0; i < 8; i++) if (blake2_state == STATE_ROUNDS) @@ -99,28 +97,25 @@ always_ff @(posedge i_clk) begin end end // Here we do the compression over 12 rounds, each round can be done in two clock cycles - // After we do 12 rounds we increment counter t STATE_ROUNDS: begin // Update local work vector with output of G function blocks depending on column or diagonal operation - for (int i = 0; i < 16; i++) begin + for (int i = 0; i < 16; i++) v[i] <= g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i]]; - end - if (g_col) begin + if (g_col) round_cntr <= round_cntr + 1; - end else begin + else round_cntr_msg <= (round_cntr_msg + 1) % 10; - end + if (round_cntr == ROUNDS-1) round_cntr_fin <= 1; if (round_cntr_fin) begin if (block_eop_l) blake2_state <= STATE_FINAL_BLOCK; - else begin + else blake2_state <= STATE_NEXT_BLOCK; - end end end STATE_NEXT_BLOCK: begin diff --git a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv index 8b0ae50..a98bc36 100644 --- a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv @@ -37,6 +37,7 @@ 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_byte_len = 3; i_block.put_stream("cba", i_byte_len); @@ -51,6 +52,7 @@ task test_128_bytes(); begin integer signed get_len; logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + $display("Running test_128_bytes..."); expected = 'hd2a56bb7bb1ff1fffcf2f151522455e32969ddfeb409b105f45299b8cbd68eb370fd6d45d63981d23cd2686dfd9a76f5b1d134be076f7d08ecc457522042e34a; i_byte_len = 128; i_block.put_stream("monek14SFMpNgHz12zMfplMfcHkx6JhKhSWTNwzGiq8UiPa4n4Ehq363oHG92GPDVpvQut4ui5e6XxieeKTn1THLWiMZ0iaOFndxcT6FGPgmHXQ5zJU96X71zfWbvUQs", i_byte_len); @@ -65,6 +67,7 @@ task test_140_bytes(); begin integer signed get_len; logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + $display("Running test_140_bytes..."); expected = 'h2012a869a3b89a69ffc954f6855c7f61a61190553dc487171ec3fe944d04c83cd4c842fff5a8258d5e14b05b7b6f30e8ddcb754d719137ec42fb5cdb562f8c89; i_byte_len = 140; i_block.put_stream("YbEAEzgJ1tgC3t6vDaJFqlWp1PaL482f7iZZzRj3xXpY2PPupwdTKAaBzB6KuN6j0alaoaFQfNboDbkNv5KDs5d7zN9JssrtOjGJdrVLfvb7uAdnVYoIgIv2zbXUQIPpwWdzEzj1CzX5", i_byte_len); From 66aad005dfc41e66249aad8980badea23138f204 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Wed, 13 Feb 2019 17:14:15 -0500 Subject: [PATCH 10/16] Add script for generating project when synthesizing in Vivado --- ip_cores/blake2b/scripts/create_project.tcl | 519 ++++++++++++++++++++ 1 file changed, 519 insertions(+) create mode 100644 ip_cores/blake2b/scripts/create_project.tcl diff --git a/ip_cores/blake2b/scripts/create_project.tcl b/ip_cores/blake2b/scripts/create_project.tcl new file mode 100644 index 0000000..691742a --- /dev/null +++ b/ip_cores/blake2b/scripts/create_project.tcl @@ -0,0 +1,519 @@ +#***************************************************************************************** +# Vivado (TM) v2018.3 (64-bit) +# +# create_project.tcl: Tcl script for re-creating project 'blake2b' +# +# Generated by Vivado on Wed Feb 13 16:57:58 -0500 2019 +# IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# run results please launch the synthesis/implementation runs as needed. +# +#***************************************************************************************** +# NOTE: In order to use this script for source control purposes, please make sure that the +# following files are added to the source control system:- +# +# 1. This project restoration tcl script (create_project.tcl) that was generated. +# +# 2. The following source(s) files that were local or imported into the original project. +# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) +# +# +# +# 3. The following remote source files that were added to the original project:- +# +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/rtl/blake2b_g.sv" +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/rtl/blake2b_pkg.sv" +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/common/src/rtl/common_pkg.sv" +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/common/src/rtl/common_if.sv" +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/rtl/blake2b_top.sv" +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/synth/blake2b_top.xdc" +# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/tb/blake2b_top_tb.sv" +# +#***************************************************************************************** + +# Set the reference directory for source file relative paths (by default the value is script directory path) +set script_path [ file dirname [ file normalize [ info script ] ] ] +puts $script_path +set origin_dir $script_path + +# Set the project name +set _xil_proj_name_ "blake2b" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "create_project.tcl" + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Set the directory path for the original project from where this script was exported +set orig_proj_dir "[file normalize "$origin_dir/../proj"]" + +# Create project +create_project ${_xil_proj_name_} $origin_dir/../proj/ -part xcvu9p-flga2104-2L-e + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Set project properties +set obj [current_project] +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "dsa.accelerator_binary_content" -value "bitstream" -objects $obj +set_property -name "dsa.accelerator_binary_format" -value "xclbin2" -objects $obj +set_property -name "dsa.description" -value "Vivado generated DSA" -objects $obj +set_property -name "dsa.dr_bd_base_address" -value "0" -objects $obj +set_property -name "dsa.emu_dir" -value "emu" -objects $obj +set_property -name "dsa.flash_interface_type" -value "bpix16" -objects $obj +set_property -name "dsa.flash_offset_address" -value "0" -objects $obj +set_property -name "dsa.flash_size" -value "1024" -objects $obj +set_property -name "dsa.host_architecture" -value "x86_64" -objects $obj +set_property -name "dsa.host_interface" -value "pcie" -objects $obj +set_property -name "dsa.num_compute_units" -value "60" -objects $obj +set_property -name "dsa.platform_state" -value "pre_synth" -objects $obj +set_property -name "dsa.vendor" -value "xilinx" -objects $obj +set_property -name "dsa.version" -value "0.0" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "part" -value "xcvu9p-flga2104-2L-e" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "Mixed" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + [file normalize "${origin_dir}/../src/rtl/blake2b_g.sv"] \ + [file normalize "${origin_dir}/../src/rtl/blake2b_pkg.sv"] \ + [file normalize "${origin_dir}/../../common/src/rtl/common_pkg.sv"] \ + [file normalize "${origin_dir}/../../common/src/rtl/common_if.sv"] \ + [file normalize "${origin_dir}/../src/rtl/blake2b_top.sv"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sources_1' fileset file properties for remote files +set file "$origin_dir/../src/rtl/blake2b_g.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../src/rtl/blake2b_pkg.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../../common/src/rtl/common_pkg.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../../common/src/rtl/common_if.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../src/rtl/blake2b_top.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + + +# Set 'sources_1' fileset file properties for local files +# None + +# Set 'sources_1' fileset properties +set obj [get_filesets sources_1] +set_property -name "top" -value "blake2b_top" -objects $obj + +# Create 'constrs_1' fileset (if not found) +if {[string equal [get_filesets -quiet constrs_1] ""]} { + create_fileset -constrset constrs_1 +} + +# Set 'constrs_1' fileset object +set obj [get_filesets constrs_1] + +# Add/Import constrs file and set constrs file properties +set file "[file normalize "$origin_dir/../synth/blake2b_top.xdc"]" +set file_added [add_files -norecurse -fileset $obj [list $file]] +set file "$origin_dir/../synth/blake2b_top.xdc" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] +set_property -name "file_type" -value "XDC" -objects $file_obj + +# Set 'constrs_1' fileset properties +set obj [get_filesets constrs_1] +set_property -name "target_part" -value "xcvu9p-flga2104-2L-e" -objects $obj + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +set files [list \ + [file normalize "${origin_dir}/../src/tb/blake2b_top_tb.sv"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sim_1' fileset file properties for remote files +set file "$origin_dir/../src/tb/blake2b_top_tb.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + + +# Set 'sim_1' fileset file properties for local files +# None + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "top" -value "blake2b_top_tb" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +# Set 'utils_1' fileset object +set obj [get_filesets utils_1] +# Empty (no sources present) + +# Set 'utils_1' fileset properties +set obj [get_filesets utils_1] + +# Create 'synth_1' run (if not found) +if {[string equal [get_runs -quiet synth_1] ""]} { + create_run -name synth_1 -part xcvu9p-flga2104-2L-e -flow {Vivado Synthesis 2018} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 +} else { + set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] + set_property flow "Vivado Synthesis 2018" [get_runs synth_1] +} +set obj [get_runs synth_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Synthesis Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'synth_1_synth_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { + create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 +} +set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] +if { $obj != "" } { +set_property -name "display_name" -value "synth_1_synth_report_utilization_0" -objects $obj + +} +set obj [get_runs synth_1] +set_property -name "part" -value "xcvu9p-flga2104-2L-e" -objects $obj +set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj + +# set the current synth run +current_run -synthesis [get_runs synth_1] + +# Create 'impl_1' run (if not found) +if {[string equal [get_runs -quiet impl_1] ""]} { + create_run -name impl_1 -part xcvu9p-flga2104-2L-e -flow {Vivado Implementation 2018} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 +} else { + set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] + set_property flow "Vivado Implementation 2018" [get_runs impl_1] +} +set obj [get_runs impl_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Implementation Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'impl_1_init_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_init_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_opt_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { + create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_opt_report_drc_0" -objects $obj + +} +# Create 'impl_1_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_power_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_place_report_io_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { + create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_place_report_io_0" -objects $obj + +} +# Create 'impl_1_place_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { + create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_place_report_utilization_0" -objects $obj + +} +# Create 'impl_1_place_report_control_sets_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { + create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_place_report_control_sets_0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_1' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_1" -objects $obj + +} +# Create 'impl_1_place_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_place_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_post_place_power_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_phys_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_route_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { + create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_drc_0" -objects $obj + +} +# Create 'impl_1_route_report_methodology_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { + create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_methodology_0" -objects $obj + +} +# Create 'impl_1_route_report_power_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { + create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_power_0" -objects $obj + +} +# Create 'impl_1_route_report_route_status_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { + create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_route_status_0" -objects $obj + +} +# Create 'impl_1_route_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_route_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_incremental_reuse_0" -objects $obj + +} +# Create 'impl_1_route_report_clock_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { + create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_clock_utilization_0" -objects $obj + +} +# Create 'impl_1_route_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_bus_skew_0" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_bus_skew_0" -objects $obj + +} +set obj [get_runs impl_1] +set_property -name "part" -value "xcvu9p-flga2104-2L-e" -objects $obj +set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj +set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj +set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj + +# set the current impl run +current_run -implementation [get_runs impl_1] + +puts "INFO: Project created:${_xil_proj_name_}" +set obj [get_dashboards default_dashboard] + +# Create 'drc_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] ""]} { +create_dashboard_gadget -name {drc_1} -type drc +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj + +# Create 'methodology_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] ""]} { +create_dashboard_gadget -name {methodology_1} -type methodology +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj + +# Create 'power_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] ""]} { +create_dashboard_gadget -name {power_1} -type power +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj + +# Create 'timing_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] ""]} { +create_dashboard_gadget -name {timing_1} -type timing +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj + +# Create 'utilization_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] ""]} { +create_dashboard_gadget -name {utilization_1} -type utilization +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] +set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj +set_property -name "run.step" -value "synth_design" -objects $obj +set_property -name "run.type" -value "synthesis" -objects $obj + +# Create 'utilization_2' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] ""]} { +create_dashboard_gadget -name {utilization_2} -type utilization +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] +set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj + +move_dashboard_gadget -name {utilization_1} -row 0 -col 0 +move_dashboard_gadget -name {power_1} -row 1 -col 0 +move_dashboard_gadget -name {drc_1} -row 2 -col 0 +move_dashboard_gadget -name {timing_1} -row 0 -col 1 +move_dashboard_gadget -name {utilization_2} -row 1 -col 1 +move_dashboard_gadget -name {methodology_1} -row 2 -col 1 +# Set current dashboard to 'default_dashboard' +current_dashboard default_dashboard From ab3e37782ef99ac4850dc500400a150d5c5ccc88 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Fri, 15 Feb 2019 01:58:34 -0500 Subject: [PATCH 11/16] Update license --- ip_cores/blake2b/src/rtl/blake2b_g.sv | 20 ++++++++ ip_cores/blake2b/src/rtl/blake2b_pkg.sv | 19 ++++++++ ip_cores/blake2b/src/rtl/blake2b_top.sv | 25 ++++++++-- ip_cores/blake2b/src/tb/blake2b_g_tb.sv | 19 ++++++++ ip_cores/blake2b/src/tb/blake2b_top_tb.sv | 58 ++++++++++++++++++----- ip_cores/common/src/rtl/common_if.sv | 23 +++++++-- ip_cores/common/src/rtl/common_pkg.sv | 20 +++++++- 7 files changed, 165 insertions(+), 19 deletions(-) diff --git a/ip_cores/blake2b/src/rtl/blake2b_g.sv b/ip_cores/blake2b/src/rtl/blake2b_g.sv index aef2d5a..e6bb2c6 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_g.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_g.sv @@ -1,3 +1,23 @@ +/* + The BLAKE2b g function. + + 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 blake2b_g #( parameter PIPELINES = 1 // Do we want to optionally add pipeline stages diff --git a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv index 7a22548..e73e65f 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv @@ -1,3 +1,22 @@ +/* + The BLAKE2b 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 blake2b_pkg; // Initial values diff --git a/ip_cores/blake2b/src/rtl/blake2b_top.sv b/ip_cores/blake2b/src/rtl/blake2b_top.sv index a72a43b..60a28a9 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_top.sv @@ -1,7 +1,24 @@ -/* Implemented from RFC-7693, The BLAKE2b Cryptographic Hash and Message Authentication Code (MAC) - * Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. - * Only only hash is computed at a time, and takes 26 clocks * number of 128 Byte message blocks. - */ +/* + Implemented from RFC-7693, The BLAKE2b Cryptographic Hash and Message Authentication Code (MAC) + Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. + Only only hash is computed at a time, and takes 26 clocks * number of 128 Byte message blocks. + Does not have functionalty to use a key. + + 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 blake2b_top import blake2b_pkg::*; diff --git a/ip_cores/blake2b/src/tb/blake2b_g_tb.sv b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv index c2334a3..8a47e82 100644 --- a/ip_cores/blake2b/src/tb/blake2b_g_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv @@ -1,3 +1,22 @@ +/* + The BLAKE2b g function 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 blake2b_g_tb(); logic clk; diff --git a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv index a98bc36..2542186 100644 --- a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv @@ -1,5 +1,26 @@ +/* + The BLAKE2b 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 blake2b_top_tb(); +parameter USE_BLAKE2B_PIPE = 1; // This instantiates the pipelined version instead + import blake2b_pkg::*; import common_pkg::*; @@ -22,15 +43,30 @@ initial begin forever #10ns clk = ~clk; end - -blake2b_top DUT ( - .i_clk ( clk ), - .i_rst ( rst ), - .i_parameters ( parameters ), - .i_byte_len ( i_byte_len ), - .i_block ( i_block ), - .o_hash ( out_hash ) -); +generate if ( USE_BLAKE2B_PIPE == 0 ) begin: DUT_GEN + blake2b_top DUT ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_parameters ( parameters ), + .i_byte_len ( i_byte_len ), + .i_block ( i_block ), + .o_hash ( out_hash ) + ); +end else begin + blake2b_pipe_top #( + .ROUNDS ( 12 ), + .MSG_LEN ( 3 ) + ) + DUT ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_parameters ( parameters ), + .i_byte_len ( i_byte_len ), + .i_block ( i_block ), + .o_hash ( out_hash ) + ); +end +endgenerate // This test runs the hash which is shown in the RFC, for "abc" task rfc_test(); @@ -86,8 +122,8 @@ initial begin #200ns; rfc_test(); - test_128_bytes(); - test_140_bytes(); + // test_128_bytes(); + // test_140_bytes(); #10us $finish(); diff --git a/ip_cores/common/src/rtl/common_if.sv b/ip_cores/common/src/rtl/common_if.sv index 841cb93..662f766 100644 --- a/ip_cores/common/src/rtl/common_if.sv +++ b/ip_cores/common/src/rtl/common_if.sv @@ -1,5 +1,22 @@ +/* + Interface for a AXI stream + + 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 . +*/ -// Interface for a AXI stream interface if_axi_stream # ( parameter DAT_BYTS = 8, parameter CTL_BYTS = 8 @@ -19,8 +36,8 @@ interface if_axi_stream # ( logic [DAT_BITS-1:0] dat; logic [$clog2(DAT_BYTS)-1:0] mod; - modport sink (input val, err, sop, eop, ctl, dat, output rdy); - modport source (output val, err, sop, eop, ctl, dat, input rdy, import task reset_source()); + modport sink (input val, err, sop, eop, ctl, dat, mod, output rdy); + modport source (output val, err, sop, eop, ctl, dat, mod, input rdy, import task reset_source()); // Task to reset a source interface signals to all 0 task reset_source(); diff --git a/ip_cores/common/src/rtl/common_pkg.sv b/ip_cores/common/src/rtl/common_pkg.sv index a397d1c..9887a10 100644 --- a/ip_cores/common/src/rtl/common_pkg.sv +++ b/ip_cores/common/src/rtl/common_pkg.sv @@ -1,4 +1,22 @@ -// Common parameter values and tasks +/* + Common parameter values and tasks + + 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 common_pkg; parameter MAX_SIM_BYTS = 1024; // In simulation tasks how big is the logic register for putting / getting data From 0d84ffd424501ef576247b609ade35ef24959781 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Sat, 16 Feb 2019 01:23:49 -0500 Subject: [PATCH 12/16] Add IP for an AXI interface fifo. Add the blake2b_pipe which is a high performance version of blake2b pipeline unrolled. --- ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv | 250 ++++++++++++++++++- ip_cores/blake2b/src/tb/blake2b_top_tb.sv | 7 +- ip_cores/fifo/src/rtl/axi_stream_fifo.sv | 70 ++++++ 3 files changed, 320 insertions(+), 7 deletions(-) create mode 100644 ip_cores/fifo/src/rtl/axi_stream_fifo.sv diff --git a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv index 0ec9468..a443a7c 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv @@ -1,4 +1,246 @@ -/* Implemented from RFC-7693, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) - * Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. - * This is a pipeline-unrolled version for higher performance (but more resource usage) - */ \ No newline at end of file +/* + This is a pipeline unrolled implementation of Blake2b (from RFC-7693) + In order to get maximum throughput, the entire message block is required on the first clock cycle, + so all hashes are single clock with .sop and .eop high. + + Does not support using keys. + + 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 blake2b_pipe_top + import blake2b_pkg::*; +#( + // Since we fully unfold the pipeline, the message byte length is hard-coded + parameter MSG_LEN = 3, + parameter CTL_BITS = 8 +) +( + input i_clk, i_rst, + + input [7:0] i_byte_len, // Length of the input message + input [64*8-1:0] i_parameters, // Input parameters used in the inital state. + + if_axi_stream.sink i_block, // Input block with valid and ready signals for flow control + if_axi_stream.source o_hash // Output digest with valid and ready signals for flow control +); + + +localparam NUM_ROUNDS = 12; +localparam NUM_PASSES = 1 + MSG_LEN/128; +localparam NUM_PIPE = 2 + NUM_PASSES*(NUM_ROUNDS*2) + 2*NUM_PASSES - 1; + +logic [NUM_PIPE-1:0][15:0][63:0] v; +logic [NUM_PIPE-1:0][7:0][63:0] h; +logic [NUM_PIPE-1:0][15:0][63:0] msg; +logic [NUM_PIPE-1:0][CTL_BITS-1:0] ctl; +logic [NUM_PIPE-1:0] eop_l, sop_l, valid; + +generate + genvar g0, g1, g2, g3; + + // Since this is a single pipeline flow we pause if output is not ready + // Simplier than dealing with valid bubbles in the pipeline + always_comb i_block.rdy = o_hash.rdy; + + // Assign the output from the final pipeline stage + always_comb begin + o_hash.val = valid[NUM_PIPE-1]; + o_hash.ctl = ctl[NUM_PIPE-1]; + o_hash.sop = 1; + o_hash.eop = 1; + o_hash.dat = h[NUM_PIPE-1]; + end + + // First stage has special logic + always_ff @ (posedge i_clk) begin + if (i_rst) begin + h[0] <= 0; + v[0] <= 0; + msg[0] <= i_block.dat; + ctl[0] <= i_block.ctl; + v[0] <= 0; + h[0] <= 0; + valid[0] <= 0; + valid[1] <= 0; + end else begin + if (i_block.rdy) begin + // First stage + h[0] <= i_parameters ^ blake2b_pkg::IV; + v[0] <= 0; + msg[0] <= i_block.dat; + ctl[0] <= i_block.ctl; + valid[0] <= i_block.val; + end + if (o_hash.rdy) begin + // Second stage + h[1] <= h[0]; + init_local_work_vector_pipe(1, NUM_PASSES == 1); // initializes v[1] + msg[1] <= msg[0]; + ctl[1] <= ctl[0]; + valid[1] <= valid[0]; + end + end + end + + + for (g0 = 0; g0 < NUM_PASSES; g0++) begin: GEN_PASS + + localparam LAST_BLOCK = (g0 == NUM_PASSES -1); + localparam SR_MSG_BYTS = LAST_BLOCK ? MSG_LEN % 128 : 128; + localparam PIPE_G0 = 2 + NUM_ROUNDS*2 + g0*(NUM_ROUNDS*2 + 2); + + // Each pass after 0 has a shift register for storing that part of the message + if_axi_stream #(.DAT_BYTS(SR_MSG_BYTS)) msg_in(clk); + if_axi_stream #(.DAT_BYTS(SR_MSG_BYTS)) msg_out(clk); + + // At the end of each round are two pipeline stages for updating + // the local state + always_ff @ (posedge i_clk) begin + if (i_rst) begin + valid[PIPE_G0] <= 0; + valid[PIPE_G0+1] <= 0; + end else begin + if (o_hash.rdy) begin + valid[PIPE_G0] <= valid[PIPE_G0-1]; + valid[PIPE_G0+1] <= valid[PIPE_G0]; + end + end + end + + always_ff @ (posedge i_clk) begin + msg_out.rdy <= 0; + // First stage + // Some pipelines not used in this stage + msg[PIPE_G0] <= 0; + ctl[PIPE_G0] <= 0; + v[PIPE_G0] <= 1; + if (o_hash.rdy) begin + for (int i = 0; i < 8; i++) + h[PIPE_G0][i] <= h[PIPE_G0-1][i] ^ v[PIPE_G0-1][i] ^ v[PIPE_G0-1][i+8]; + end + // Second stage + if (o_hash.rdy) begin + h[PIPE_G0+1] <= h[PIPE_G0]; + init_local_work_vector_pipe(PIPE_G0+2, LAST_BLOCK); + // Need to pull msg and ctl from the shift register if we have more than one pass + msg_out.rdy <= 1; + if (g0 > 0) begin + msg[PIPE_G0+1] <= msg_out.dat; + ctl[PIPE_G0+1] <= msg_out.ctl; + end else begin + msg[PIPE_G0+1] <= 0; + ctl[PIPE_G0+1] <= 0; + end + end + + end + + if (g0 > 0) begin: GEN_MSG_FIFO + + always_ff @ (posedge i_clk) begin + if (msg_in.val && msg_in.rdy) begin + msg_in.dat <= i_block.dat[128*8*g0 :+ 128*8]; + msg_in.sop <= 0; + msg_in.eop <= 0; + msg_in.err <= 0; + msg_in.ctl <= i_block.ctl; + msg_in.mod <= LAST_BLOCK ? i_block.mod : 0; + end + end + + always_comb begin + if (g0 == 0) i_block.rdy = msg_in.rdy; + msg_in.val = i_block.val; + end + + axi_stream_fifo #( + .A_BITS ( $clog2(NUM_ROUNDS + 2) ), + .DAT_BITS ( 128*8 ), + .CTL_BITS ( CTL_BITS ) + ) + message_fifo ( + .i_clk ( i_clk ), + .i_rst ( i_rst ), + .i_axi ( msg_in ), + .o_axi ( msg_out ) + ); + + end + + for (g1 = 0; g1 < NUM_ROUNDS; g1++) begin: GEN_ROUND + for (g2 = 0; g2 < 2; g2++) begin: GEN_G_FUNC + + // Each pipeline stage has 4 G function blocks in parallel + localparam PIPE_G2 = 2 + g0*(2 + NUM_ROUNDS*2) + g1*2 + g2; + + always_ff @(posedge i_clk) begin + if (i_rst) begin + valid[PIPE_G2] <= 0; + end else begin + if (o_hash.rdy) valid[PIPE_G2] <= valid[PIPE_G2-1]; + end + end + + always_ff @(posedge i_clk) begin + if (o_hash.rdy) begin + msg[PIPE_G2] <= msg[PIPE_G2-1]; + //if (PIPE_G2 != PIPE_G0) + h[PIPE_G2] <= h[PIPE_G2-1]; + ctl[PIPE_G2] <= ctl[PIPE_G2-1]; // TODO could remove? + end + end + + for (g3 = 0; g3 < 4; g3++) begin: GEN_G_FUNC_COL_DIAG + + blake2b_g + #( .PIPELINES(1) ) + blake2b_g ( + .i_clk(i_clk), + .i_a(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 0)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 0)]]), + .i_b(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 1)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 1)]]), + .i_c(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 2)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 2)]]), + .i_d(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 3)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 3)]]), + .i_m0(msg[PIPE_G2-1][blake2b_pkg::SIGMA[16*(g1%10) + g2*8 + g3*2]]), + .i_m1(msg[PIPE_G2-1][blake2b_pkg::SIGMA[16*(g1%10) + g2*8 + g3*2 + 1]]), + .o_a(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 0] : blake2b_pkg::G_MAPPING[16 + g3*4 + 0]]), + .o_b(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 1] : blake2b_pkg::G_MAPPING[16 + g3*4 + 1]]), + .o_c(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 2] : blake2b_pkg::G_MAPPING[16 + g3*4 + 2]]), + .o_d(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 3] : blake2b_pkg::G_MAPPING[16 + g3*4 + 3]]) + ); + end + end + end + end +endgenerate + +// Task to initialize local work vector for the compression function +// Modified to work with pipeline version +task init_local_work_vector_pipe(input integer j, input last_block); +begin + for (int i = 0; i < 16; i++) + case (i) inside + 0,1,2,3,4,5,6,7: v[j][i] <= h[j-1][i]; + 8,9,10,11: v[j][i] <= blake2b_pkg::IV[i%8]; + 12: v[j][i] <= blake2b_pkg::IV[i%8] ^ (last_block ? (MSG_LEN % 128) : j*128); + 13: v[j][i] <= blake2b_pkg::IV[i%8] ^ j*128 >> 64; + 14: v[j][i] <= blake2b_pkg::IV[i%8] ^ {64{last_block}}; + 15: v[j][i] <= blake2b_pkg::IV[i%8]; + endcase +end +endtask + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv index 2542186..c768b60 100644 --- a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv +++ b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv @@ -20,6 +20,7 @@ module blake2b_top_tb(); parameter USE_BLAKE2B_PIPE = 1; // This instantiates the pipelined version instead +parameter USE_BLAKE2B_PIPE_MSG_LEN = 3; import blake2b_pkg::*; import common_pkg::*; @@ -29,7 +30,7 @@ logic [7:0] i_byte_len; logic [64*8-1:0] parameters; logic [64*8-1:0] expected; -if_axi_stream #(.DAT_BYTS(128)) i_block(clk); +if_axi_stream #(.DAT_BYTS(USE_BLAKE2B_PIPE == 0 ? 128 : USE_BLAKE2B_PIPE_MSG_LEN)) i_block(clk); if_axi_stream #(.DAT_BYTS(64)) out_hash(clk); initial begin @@ -54,8 +55,8 @@ generate if ( USE_BLAKE2B_PIPE == 0 ) begin: DUT_GEN ); end else begin blake2b_pipe_top #( - .ROUNDS ( 12 ), - .MSG_LEN ( 3 ) + .MSG_LEN ( 3 ), + .CTL_BITS ( 8 ) ) DUT ( .i_clk ( clk ), diff --git a/ip_cores/fifo/src/rtl/axi_stream_fifo.sv b/ip_cores/fifo/src/rtl/axi_stream_fifo.sv new file mode 100644 index 0000000..efeccdd --- /dev/null +++ b/ip_cores/fifo/src/rtl/axi_stream_fifo.sv @@ -0,0 +1,70 @@ +/* + This is a simple FIFO implementation using AXI stream source and sink interfaces. + It has a single clock delay from i_axi to o_axi in the case of an empty FIFO. + Only works with power of 2 A_BITS + + 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 axi_stream_fifo #( + parameter A_BITS, + parameter DAT_BITS, + parameter CTL_BITS +) ( + input i_clk, i_rst, + if_axi_stream.sink i_axi, + if_axi_stream.source o_axi +); + +localparam MOD_BITS = $clog2(DAT_BITS/8); + +logic [$clog2(A_BITS):0] rd_ptr, wr_ptr; +logic empty, full; + +logic [A_BITS-1:0][DAT_BITS + CTL_BITS + MOD_BITS + 3 -1:0] ram; + +// Control for full and empty, and assigning outputs from the ram +always_comb begin + empty = (rd_ptr == wr_ptr); + full = (wr_ptr == rd_ptr - 1); + i_axi.rdy = ~full; + o_axi.dat = ram[rd_ptr][0 +: DAT_BITS]; + o_axi.ctl = ram[rd_ptr][DAT_BITS +: CTL_BITS]; + o_axi.mod = ram[rd_ptr][CTL_BITS+DAT_BITS +: MOD_BITS]; + o_axi.sop = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS +: 1]; + o_axi.eop = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS+1 +: 1]; + o_axi.val = ~empty; +end + +// Logic for writing and reading from ram without reset +always_ff @ (posedge i_clk) begin + if (i_axi.val && i_axi.rdy) begin + ram [wr_ptr] <= {i_axi.eop, i_axi.sop, i_axi.mod, i_axi.ctl, i_axi.dat}; + end +end + +// Control logic which requires a reset +always_ff @ (posedge i_clk) begin + if (i_rst) begin + rd_ptr <= 0; + wr_ptr <= 0; + end else begin + wr_ptr <= i_axi.val && i_axi.rdy ? (wr_ptr + 1) : wr_ptr; + rd_ptr <= o_axi.val && o_axi.rdy ? (rd_ptr + 1) : rd_ptr; + end +end + +endmodule \ No newline at end of file From 3244deeaacc834ee9fad1118d442f2bfc176181d Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 19 Feb 2019 09:31:31 -0500 Subject: [PATCH 13/16] Updates to naming of verif project, and extra blocks for testbench, example block file. --- equihash_verifi/README.md | 1 - .../src/rtl/equihash_verifi_top.sv | 51 ------------- ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv | 15 +++- ip_cores/common/src/rtl/common_if.sv | 4 +- zcash_verifi/README.md | 1 + zcash_verifi/src/data/block_241.bin | Bin 0 -> 1619 bytes zcash_verifi/src/rtl/zcash_verif_pkg.sv | 22 ++++++ zcash_verifi/src/rtl/zcash_verif_system.sv | 69 ++++++++++++++++++ .../synth/zcash_verif_top.xdc | 0 9 files changed, 107 insertions(+), 56 deletions(-) delete mode 100644 equihash_verifi/README.md delete mode 100644 equihash_verifi/src/rtl/equihash_verifi_top.sv create mode 100644 zcash_verifi/README.md create mode 100644 zcash_verifi/src/data/block_241.bin create mode 100644 zcash_verifi/src/rtl/zcash_verif_pkg.sv create mode 100644 zcash_verifi/src/rtl/zcash_verif_system.sv rename equihash_verifi/synth/equihash_verifi_top.xdc => zcash_verifi/synth/zcash_verif_top.xdc (100%) diff --git a/equihash_verifi/README.md b/equihash_verifi/README.md deleted file mode 100644 index 8b13789..0000000 --- a/equihash_verifi/README.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/equihash_verifi/src/rtl/equihash_verifi_top.sv b/equihash_verifi/src/rtl/equihash_verifi_top.sv deleted file mode 100644 index 42ebc9b..0000000 --- a/equihash_verifi/src/rtl/equihash_verifi_top.sv +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This module is the top system level for the equihash verifier system. It takes in an AXI stream which - * represents block chain data and verifies that it is correct. - */ - -module equihash_verifi_top( - input i_clk, i_rst, - - if_axi_stream.sink i_data, - output logic o_valid -); - -if_axi_stream #(.DAT_BYTS(128)) blake2b_in(clk); -if_axi_stream #(.DAT_BYTS(64)) blake2b_out(clk); - - -always_ff @ (posedge i_clk) begin - i_data.rdy <= blake2b_in.rdy; - blake2b_in.val <= i_data.val; - blake2b_in.sop <= i_data.sop; - blake2b_in.eop <= i_data.eop; - blake2b_in.dat <= i_data.dat; - blake2b_in.err <= 0; - blake2b_in.mod <= 0; - blake2b_in.ctl <= 0; - - blake2b_out.rdy <= 1; - o_valid <= (blake2b_out.val && blake2b_out.dat == {64{1'b1}}); -end - - -// The Blake2 core for generating hashes - -logic [64*8-1:0] blake2_parameters; -always_comb begin - blake2_parameters = {32'd0, 8'd1, 8'd1, 8'd0, 8'd64}; -end - -blake2_top #( - .EQUIHASH( 1 ) -) -blake2_top ( - .i_clk ( i_clk ), - .i_rst ( i_rst ), - .i_byte_len ( 8'd128 ), - .i_parameters ( blake2_parameters ), - .i_block ( blake2b_in ), - .o_hash ( blake2b_out ) -); - -endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv index a443a7c..47b6af6 100644 --- a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv +++ b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv @@ -3,7 +3,14 @@ In order to get maximum throughput, the entire message block is required on the first clock cycle, so all hashes are single clock with .sop and .eop high. + You can optionally unroll the entire pipeline but this will use a large number of resources. + If you only unroll one pass, you need to interleave the hashes to get the best performance. + So the first part of input message comes on first clock cycle, and the next part comes 26 clocks later. + Does not support using keys. + + Futher optimization to save area is fixing part of input message constant for + all hashes (just have nonce as input that changes and place this in i_block.ctl). Copyright (C) 2019 Benjamin Devlin and Zcash Foundation @@ -24,7 +31,9 @@ module blake2b_pipe_top import blake2b_pkg::*; #( - // Since we fully unfold the pipeline, the message byte length is hard-coded + // Do we fully unroll the pipeline (lot of resources) or just un-roll one pass + parameter FULLY_UNROLL = 0, + // If we fully unfold the pipeline, the message byte length is hard-coded parameter MSG_LEN = 3, parameter CTL_BITS = 8 ) @@ -137,6 +146,8 @@ generate h[PIPE_G0+1] <= h[PIPE_G0]; init_local_work_vector_pipe(PIPE_G0+2, LAST_BLOCK); // Need to pull msg and ctl from the shift register if we have more than one pass + // and we fully unrolled. Otherwise next input will be on input. Assert the control + // matches. msg_out.rdy <= 1; if (g0 > 0) begin msg[PIPE_G0+1] <= msg_out.dat; @@ -149,7 +160,7 @@ generate end - if (g0 > 0) begin: GEN_MSG_FIFO + if (g0 > 0 && FULLY_UNROLL != 0) begin: GEN_MSG_FIFO always_ff @ (posedge i_clk) begin if (msg_in.val && msg_in.rdy) begin diff --git a/ip_cores/common/src/rtl/common_if.sv b/ip_cores/common/src/rtl/common_if.sv index 662f766..756b489 100644 --- a/ip_cores/common/src/rtl/common_if.sv +++ b/ip_cores/common/src/rtl/common_if.sv @@ -15,10 +15,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -*/ +*/ interface if_axi_stream # ( - parameter DAT_BYTS = 8, + parameter DAT_BYTS = 128, parameter CTL_BYTS = 8 )( input clk diff --git a/zcash_verifi/README.md b/zcash_verifi/README.md new file mode 100644 index 0000000..9b9b52b --- /dev/null +++ b/zcash_verifi/README.md @@ -0,0 +1 @@ +This is the design for verifing the Zcash blockchain on an FPGA diff --git a/zcash_verifi/src/data/block_241.bin b/zcash_verifi/src/data/block_241.bin new file mode 100644 index 0000000000000000000000000000000000000000..fbb4089fd0c90dff38fa4b65faeefe65a0c2d332 GIT binary patch literal 1619 zcmaKsc{~#e0LM4?QP^ylIaWg|G1hFQoMSm+CP`&$8*)5PDw<>6524ObpL;P=@Ccgrol8mbCkWuGVhsQj-SlC=-D zwaXj9xsAk9;BTw)>yC;2vx(wB}buIuw=$qovyO_vJJPP?#NcO zCpPIR3N$4yJr6`3Y%Gg`YrVr51)W^t;!-%cVR+0Cx{i@S)N1@{K=&D$o z+2*3!ElO&4&Smf3!Ogmaz>M`~c&a>#@K9R0FBCuUfAS9&C~mFrC$T$rU&%w-J6LoQ zAv}vYoa&5yXRTxbBr;j=U$u}TfNypmvu!^b~gHUX3X;m)$TxTDoy#C?$p$K zAF(^IBSP2G6dJ|DxTNe_C>@^V%#5rtO3&OHRW>`ZM2Qk?IL$e_aBY5Gl(6aDs%-mHXNvW&YhhtSIjnRc08H zlL0$v%CTsoTRiEK-M~yDN`}y~bm?{zDwthes<+tVhC78~IDZJj81x z%iAY>TDwk@^1+*J$gRh|(!#gDCrWa|xOx*#WYYs)Eu>2!9QC(ta3=nBR^+OD-1kx>UB`b7`EUmm+xq|-RWI`$Q28cSFM)79U0$6{NZkEMf-en zSx>39n3fi1nPq$xNxxMgfak{_yMGU(;Pddgy^vyAp4Z@MQ1&fVTF|R!%>XdU|Di%q7vq@h_&%|f-+EHKqZuTA<0tx|L_8yKrdwFc!H915-}?d6JS%zS&Tb zThGRVbxw-rdUi#wpuvN=z75cUm^}+eU^DM)VmyiLv!6k?3vh=jZ>o90NobRnLKR7| zpm;l*FzK>dU53;DuBPg^_M+~^P7*&FT7Plj_(Nps+3)Kx)QZ^e*6fhY%riHeC%qn2 z=P^)}`(CC28d8Tn*sZ+L&#s#mWz~i&4iuv2UmhU|LPD3S7ULhL=(Q#Gi-AA!`g_Fw z$6nbFDaaiL0)84fgjD(00=Y>p!R@0j=4u@rJ7a=!@T8@!gS!#qjKWWn3?r8pebce` ku6}p=^`Tn@VY*eI`i!&hvp1r{s*bm-^7d;-r2Gv31r&bL0ssI2 literal 0 HcmV?d00001 diff --git a/zcash_verifi/src/rtl/zcash_verif_pkg.sv b/zcash_verifi/src/rtl/zcash_verif_pkg.sv new file mode 100644 index 0000000..8a4dfc9 --- /dev/null +++ b/zcash_verifi/src/rtl/zcash_verif_pkg.sv @@ -0,0 +1,22 @@ +/* + Parameter values and tasks for the verification system. + + 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 zcash_verif_pkg; + +endpackage \ No newline at end of file diff --git a/zcash_verifi/src/rtl/zcash_verif_system.sv b/zcash_verifi/src/rtl/zcash_verif_system.sv new file mode 100644 index 0000000..33094c2 --- /dev/null +++ b/zcash_verifi/src/rtl/zcash_verif_system.sv @@ -0,0 +1,69 @@ +/* + This takes in an AXI stream of a block and runs verification + checks (detailed in the architecture document). When all the checks are + completed the o_val will go high, and o_mask bit mask will be 1 for any + checks that failed. + + 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 zcash_verif_system( + input i_clk, i_rst, + + if_axi_stream.sink i_axi, + output logic [31:0] o_mask, + output logic o_val +); + +if_axi_stream #(.DAT_BYTS(128)) blake2b_in(clk); +if_axi_stream #(.DAT_BYTS(64)) blake2b_out(clk); + + +always_ff @ (posedge i_clk) begin + i_data.rdy <= blake2b_in.rdy; + blake2b_in.val <= i_data.val; + blake2b_in.sop <= i_data.sop; + blake2b_in.eop <= i_data.eop; + blake2b_in.dat <= i_data.dat; + blake2b_in.err <= 0; + blake2b_in.mod <= 0; + blake2b_in.ctl <= 0; + + blake2b_out.rdy <= 1; + o_valid <= (blake2b_out.val && blake2b_out.dat == {64{1'b1}}); +end + + +// The Blake2 core for generating hashes + +logic [64*8-1:0] blake2_parameters; +always_comb begin + blake2_parameters = {32'd0, 8'd1, 8'd1, 8'd0, 8'd64}; +end + +blake2_top #( + .EQUIHASH( 1 ) +) +blake2_top ( + .i_clk ( i_clk ), + .i_rst ( i_rst ), + .i_byte_len ( 8'd128 ), + .i_parameters ( blake2_parameters ), + .i_block ( blake2b_in ), + .o_hash ( blake2b_out ) +); + +endmodule \ No newline at end of file diff --git a/equihash_verifi/synth/equihash_verifi_top.xdc b/zcash_verifi/synth/zcash_verif_top.xdc similarity index 100% rename from equihash_verifi/synth/equihash_verifi_top.xdc rename to zcash_verifi/synth/zcash_verif_top.xdc From ca60668859fb54694df13f0c5215f271f2c89227 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 19 Feb 2019 09:31:46 -0500 Subject: [PATCH 14/16] Parsing files --- ip_cores/parsing/src/rtl/file_to_axi.sv | 67 ++++++++++++++++++++++++ ip_cores/parsing/src/rtl/header_adder.sv | 67 ++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 ip_cores/parsing/src/rtl/file_to_axi.sv create mode 100644 ip_cores/parsing/src/rtl/header_adder.sv diff --git a/ip_cores/parsing/src/rtl/file_to_axi.sv b/ip_cores/parsing/src/rtl/file_to_axi.sv new file mode 100644 index 0000000..f7ad9d8 --- /dev/null +++ b/ip_cores/parsing/src/rtl/file_to_axi.sv @@ -0,0 +1,67 @@ +/* + This reads a binary or ASCII file and creates an AXI stream, + used for testbench purposes. Can optionally add in random flow control. + + Only binary is supported at this moment. + + 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 file_to_axi #( + parameter HDR_BYTS, + parameter DAT_BYTS, + parameter BINARY, // 0 for ASCII, 1 for binary + parameter string FILE = "", // Path to file + parameter FP = 0 // Forward pressure, if this is non-zero then this is the % of cycles o_axi.val will be low +) ( + input i_clk, i_rst, + if_axi_stream.source o_axi +); + + +logic [DAT_BYTS*8-1:0] data_temp; +integer fp, r; +logic sop_l; + +initial begin + o_axi.reset_source(); + sop_l = 0; + fp = $fopen(FILE, BINARY ? "rb" : "r"); + if (fp==0) $fatal(1, "%m %t ERROR: file_to_axi could not open file %s", $time, FILE); + + if (BINARY == 0) begin + $fatal(1, "%m %t ERROR: file_to_axi BINARY == 0 not supported", $time); + end else begin + while(!$feof(fp)) begin + r = $fread(o_axi.dat, fp); + o_axi.val = 1; // TODO + o_axi.sop = ~sop_l; + sop_l = 1; + o_axi.eop = $feof(fp); + o_axi.mod = $feof(fp) ? r : 0; + + @(posedge o_axi.clk); + while (!(o_axi.val && o_axi.rdy)) @(posedge o_axi.clk); + end + end + + + o_axi.reset_source(); + $display("%m %t INFO: file_to_axi finished reading file %s", $time, FILE); + $fclose(fp); +end + +endmodule \ No newline at end of file diff --git a/ip_cores/parsing/src/rtl/header_adder.sv b/ip_cores/parsing/src/rtl/header_adder.sv new file mode 100644 index 0000000..bcbc391 --- /dev/null +++ b/ip_cores/parsing/src/rtl/header_adder.sv @@ -0,0 +1,67 @@ +/* + This takes in a AXI stream, appends a header, and outputs the resulting stream. + + 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 header_adder #( + parameter HDR_BYTS, + parameter DAT_BYTS +) ( + input i_clk, i_rst, + + input [HDR_BYTS*8-1:0] i_header, // Must be valid during i_axi.val + if_axi_stream.sink i_axi, + if_axi_stream.source o_axi +); + +logic [(DAT_BYTS+(HDR_BYTS % DAT_BYTS))*8-1:0] dat_buff; +logic sop_l; +logic [$clog2(HDR_BYTS)-1:0] hdr_cnt; + +always_comb begin + i_axi.dat = dat_buff[HDR_BYTS*8 +: DAT_BYTS*8]; +end + +always_ff @ (posedge i_clk) begin + if (i_rst) begin + dat_buff <= 0; + hdr_cnt <= 0; + i_axi.rdy <= 0; + sop_l <= 0; + o_axi.reset_source(); + end else begin + i_axi.rdy <= o_axi.rdy && (hdr_cnt + DAT_BYTS >= HDR_BYTS); + if (~o_axi.val || (~o_axi.val && o_axi.rdy)) begin + o_axi.sop <= ~sop_l; + o_axi.val <= i_axi.val; + o_axi.err <= i_axi.err; + o_axi.ctl <= i_axi.ctl; + o_axi.mod <= (i_axi.mod + HDR_BYTS) % DAT_BYTS; + o_axi.eop <= i_axi.eop; + hdr_cnt <= (hdr_cnt + DAT_BYTS >= HDR_BYTS) ? hdr_cnt : hdr_cnt + DAT_BYTS; + sop_l <= i_axi.sop; + //TODO + dat_buff <= {dat_buff[0 +: (HDR_BYTS % DAT_BYTS)*8], i_axi.dat}; + + + if (i_axi.eop) hdr_cnt <= 0; + + end + end +end + +endmodule \ No newline at end of file From e437c8bd74786ee6e08c5f183c10e0411927d9b5 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 19 Feb 2019 09:32:24 -0500 Subject: [PATCH 15/16] Update readme file --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 742d741..ccaefea 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,22 @@ # zcash-fpga -Repo for ZCash FPGA projects code and documents + +Repo for Zcash FPGA projects code and documents. + +## Overview + +These have been designed targetted for Xilinx boards (US+) and therefore contain Xilinx-specific IP. + +## zcash_verif + +This is the top level for the Zcash verification FPGA board. It targets both Xilinx Virtex UltraScale+ FPGA VCU118 Evaluation Kit, and Amazon EC2 F1 Instances. + +Architecture document is [here]() + +## ip_cores + +These contain custom IP cores used in the projects in this repo. + +* blake2b - A simple implementation of blake2b and a pipline-unrolled version for high performance. +* common - Packages and interfaces that are shared. +* fifo - Fifo implementations +* parsing - Blocks for parsing/processing streams, as well as testbench files. \ No newline at end of file From ada37ef413e67f7bb1ebf56417358f86dd58bd68 Mon Sep 17 00:00:00 2001 From: bsdevlin Date: Tue, 19 Feb 2019 09:36:28 -0500 Subject: [PATCH 16/16] Update fold name to verif --- {zcash_verifi => zcash_verif}/README.md | 0 .../src/data/block_241.bin | Bin .../src/rtl/zcash_verif_pkg.sv | 0 .../src/rtl/zcash_verif_system.sv | 0 .../synth/zcash_verif_top.xdc | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename {zcash_verifi => zcash_verif}/README.md (100%) rename {zcash_verifi => zcash_verif}/src/data/block_241.bin (100%) rename {zcash_verifi => zcash_verif}/src/rtl/zcash_verif_pkg.sv (100%) rename {zcash_verifi => zcash_verif}/src/rtl/zcash_verif_system.sv (100%) rename {zcash_verifi => zcash_verif}/synth/zcash_verif_top.xdc (100%) diff --git a/zcash_verifi/README.md b/zcash_verif/README.md similarity index 100% rename from zcash_verifi/README.md rename to zcash_verif/README.md diff --git a/zcash_verifi/src/data/block_241.bin b/zcash_verif/src/data/block_241.bin similarity index 100% rename from zcash_verifi/src/data/block_241.bin rename to zcash_verif/src/data/block_241.bin diff --git a/zcash_verifi/src/rtl/zcash_verif_pkg.sv b/zcash_verif/src/rtl/zcash_verif_pkg.sv similarity index 100% rename from zcash_verifi/src/rtl/zcash_verif_pkg.sv rename to zcash_verif/src/rtl/zcash_verif_pkg.sv diff --git a/zcash_verifi/src/rtl/zcash_verif_system.sv b/zcash_verif/src/rtl/zcash_verif_system.sv similarity index 100% rename from zcash_verifi/src/rtl/zcash_verif_system.sv rename to zcash_verif/src/rtl/zcash_verif_system.sv diff --git a/zcash_verifi/synth/zcash_verif_top.xdc b/zcash_verif/synth/zcash_verif_top.xdc similarity index 100% rename from zcash_verifi/synth/zcash_verif_top.xdc rename to zcash_verif/synth/zcash_verif_top.xdc