Initial files for the Blake2B core
This commit is contained in:
parent
ada8931711
commit
361ece0ee3
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>zcash-fpga</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue