Bug fix and timeout feature.
Removed memory map from top. Added timeout to secp256k1 in case logic gets stuck.
This commit is contained in:
parent
daf7c65157
commit
a9fd07b8f3
|
@ -41,7 +41,7 @@ package secp256k1_pkg;
|
|||
|
||||
parameter DO_AFFINE_CHECK = "NO"; // Setting this to YES will convert the final result back to affine coordinates to check signature
|
||||
// Requires an inversion and so is slower than doing the check in jacobson coordinates
|
||||
parameter USE_ENDOMORPH = "YES"; // Use the secp256k1 endomorphism to reduce the key bit size. Improves throughput by 2x but uses
|
||||
parameter USE_ENDOMORPH = "NO"; // Use the secp256k1 endomorphism to reduce the key bit size. Improves throughput by 2x but uses
|
||||
// more FPGA logic
|
||||
|
||||
// Use register map for debug, holds information on current operation
|
||||
|
@ -66,7 +66,8 @@ package secp256k1_pkg;
|
|||
} jb_point_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [3:0] padding;
|
||||
logic [2:0] padding;
|
||||
logic TIMEOUT_FAIL;
|
||||
logic FAILED_SIG_VER;
|
||||
logic X_INFINITY_POINT;
|
||||
logic OUT_OF_RANGE_S;
|
||||
|
|
|
@ -6,19 +6,13 @@ module secp256k1_top import secp256k1_pkg::*; #(
|
|||
input i_rst,
|
||||
// Command interface
|
||||
if_axi_stream.sink if_cmd_rx,
|
||||
if_axi_stream.source if_cmd_tx,
|
||||
// Memory map interface for debug
|
||||
if_axi_mm.sink if_axi_mm
|
||||
if_axi_stream.source if_cmd_tx
|
||||
);
|
||||
|
||||
localparam DAT_BYTS = 8;
|
||||
localparam DAT_BITS = DAT_BYTS*8;
|
||||
import zcash_fpga_pkg::*;
|
||||
|
||||
// Register map is used for storing command data
|
||||
if_ram #(.RAM_WIDTH(64), .RAM_DEPTH(REGISTER_SIZE)) register_file_a (i_clk, i_rst);
|
||||
if_ram #(.RAM_WIDTH(64), .RAM_DEPTH(REGISTER_SIZE)) register_file_b (i_clk, i_rst);
|
||||
|
||||
// 256 bit inverse calculation
|
||||
if_axi_stream #(.DAT_BYTS(256/8)) bin_inv_in_if(i_clk);
|
||||
if_axi_stream #(.DAT_BYTS(256/8)) bin_inv_out_if(i_clk);
|
||||
|
@ -34,8 +28,8 @@ logic [255:0] pt_mult0_in_k, pt_mult1_in_k;
|
|||
logic pt_mult0_in_val, pt_mult0_in_rdy, pt_mult0_out_rdy, pt_mult0_out_val, pt_mult0_out_err, pt_mult0_in_p2_val;
|
||||
logic pt_mult1_in_val, pt_mult1_in_rdy, pt_mult1_out_rdy, pt_mult1_out_val, pt_mult1_out_err;
|
||||
|
||||
// Can avoid final inverstion converting from projected coord by some check in c++ code
|
||||
|
||||
// Global timeout in case we get stuck somewhere, we send a failed message back to host
|
||||
logic [(USE_ENDOMORPH == "YES" ? 14 : 15):0] timeout;
|
||||
// Controlling state machine
|
||||
typedef enum {IDLE,
|
||||
GET_INDEX,
|
||||
|
@ -45,14 +39,13 @@ typedef enum {IDLE,
|
|||
CALC_X,
|
||||
CALC_X_AFFINE,
|
||||
CHECK_IN_JB,
|
||||
UPDATE_RAM_VARIABLES,
|
||||
IGNORE,
|
||||
FINISHED} secp256k1_state_t;
|
||||
|
||||
secp256k1_state_t secp256k1_state;
|
||||
header_t header, header_l;
|
||||
secp256k1_ver_t secp256k1_ver;
|
||||
// Other temporary values - could use RAM insead?
|
||||
// Other temporary values
|
||||
logic [255:0] r, u2;
|
||||
logic [63:0] index;
|
||||
logic u2_val;
|
||||
|
@ -61,7 +54,6 @@ localparam MAX_BYT_MSG = 64; // Max bytes in a reply message
|
|||
|
||||
logic [MAX_BYT_MSG*8 -1:0] msg;
|
||||
logic [$clog2(MAX_BYT_MSG)-1:0] cnt; // Counter for parsing command inputs
|
||||
logic if_axi_mm_rd;
|
||||
|
||||
logic [255:0] inv_p;
|
||||
|
||||
|
@ -76,7 +68,6 @@ always_ff @ (posedge i_clk) begin
|
|||
if_cmd_tx.reset_source();
|
||||
if_cmd_rx.rdy <= 0;
|
||||
cnt <= 0;
|
||||
register_file_a.reset_source();
|
||||
r <= 0;
|
||||
u2 <= 0;
|
||||
u2_val <= 0;
|
||||
|
@ -103,12 +94,11 @@ always_ff @ (posedge i_clk) begin
|
|||
mult_in_if[2].reset_source();
|
||||
|
||||
index <= 0;
|
||||
|
||||
timeout <= 0;
|
||||
|
||||
end else begin
|
||||
|
||||
register_file_a.en <= 1;
|
||||
register_file_a.we <= 0;
|
||||
register_file_a.re <= 1;
|
||||
mult_out_if[2].rdy <= 1;
|
||||
mult_in_if[2].sop <= 1;
|
||||
mult_in_if[2].eop <= 1;
|
||||
|
@ -134,6 +124,7 @@ always_ff @ (posedge i_clk) begin
|
|||
|
||||
case(secp256k1_state)
|
||||
{IDLE}: begin
|
||||
timeout <= 0;
|
||||
inv_p <= secp256k1_pkg::n;
|
||||
u2_val <= 0;
|
||||
secp256k1_ver <= 0;
|
||||
|
@ -148,9 +139,6 @@ always_ff @ (posedge i_clk) begin
|
|||
if (if_cmd_rx.val && if_cmd_rx.rdy) begin
|
||||
case(header.cmd)
|
||||
{VERIFY_SECP256K1_SIG}: begin
|
||||
register_file_a.we <= 1;
|
||||
register_file_a.a <= CURR_CMD;
|
||||
register_file_a.d <= header;
|
||||
secp256k1_state <= GET_INDEX;
|
||||
end
|
||||
default: begin
|
||||
|
@ -172,7 +160,6 @@ always_ff @ (posedge i_clk) begin
|
|||
{VERIFY_SECP256K1_SIG_PARSE}: begin
|
||||
if_cmd_rx.rdy <= 1;
|
||||
if (if_cmd_rx.val && if_cmd_rx.rdy) begin
|
||||
register_file_a.we <= 1;
|
||||
cnt <= cnt + 1;
|
||||
if (cnt == 19 && if_cmd_rx.val && if_cmd_rx.rdy) begin
|
||||
secp256k1_state <= CALC_S_INV;
|
||||
|
@ -182,8 +169,6 @@ always_ff @ (posedge i_clk) begin
|
|||
|
||||
case(cnt) inside
|
||||
[0:3]: begin
|
||||
register_file_a.a <= SIG_VER_S/8 + (cnt);
|
||||
register_file_a.d <= if_cmd_rx.dat;
|
||||
// Can start calculating the inverse here
|
||||
bin_inv_in_if.dat[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
|
||||
if (cnt == 3 && if_cmd_rx.val && if_cmd_rx.rdy) begin
|
||||
|
@ -191,25 +176,19 @@ always_ff @ (posedge i_clk) begin
|
|||
end
|
||||
end
|
||||
[4:7]: begin
|
||||
register_file_a.a <= SIG_VER_R/8 + (cnt - 4);
|
||||
r[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat; // TODO remove
|
||||
register_file_a.d <= if_cmd_rx.dat;
|
||||
r[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
|
||||
mult_in_if[2].dat[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
|
||||
end
|
||||
[8:11]: begin
|
||||
pt_mult0_in_k[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
|
||||
register_file_a.a <= SIG_VER_HASH/8 + (cnt - 8);
|
||||
register_file_a.d <= if_cmd_rx.dat;
|
||||
end
|
||||
[12:19]: begin
|
||||
register_file_a.a <= SIG_VER_Q/8 + (cnt - 12);
|
||||
pt_mult0_in_p.z <= 1;
|
||||
if ((cnt-12) < 4) begin
|
||||
pt_mult0_in_p.x[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
|
||||
end else begin
|
||||
pt_mult0_in_p.y[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
|
||||
end
|
||||
register_file_a.d <= if_cmd_rx.dat;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
@ -226,7 +205,6 @@ always_ff @ (posedge i_clk) begin
|
|||
mult_in_if[2].val <= 1;
|
||||
secp256k1_state <= CALC_U1_U2;
|
||||
cnt <= 0;
|
||||
// TODO also write this to RAM
|
||||
// need to do 2 multiplications % n to get u1 and u2
|
||||
end
|
||||
end
|
||||
|
@ -242,8 +220,6 @@ always_ff @ (posedge i_clk) begin
|
|||
end
|
||||
end
|
||||
// Check for result
|
||||
// TODO load into RAM
|
||||
|
||||
if (mult_out_if[2].val && mult_out_if[2].rdy) begin
|
||||
case(cnt[2])
|
||||
{1'd0}: begin
|
||||
|
@ -267,22 +243,19 @@ always_ff @ (posedge i_clk) begin
|
|||
{CALC_X}: begin
|
||||
// Wait for u1.P to finish
|
||||
if (pt_mult0_out_rdy && pt_mult0_out_val) begin
|
||||
// TODO load equation into point ADD
|
||||
pt_X0 <= pt_mult0_out_p;
|
||||
pt_mult0_in_p <= pt_mult0_out_p;
|
||||
cnt[0] <= 1;
|
||||
end
|
||||
// Wait for u2.Q to finish
|
||||
if (pt_mult1_out_rdy && pt_mult1_out_val) begin
|
||||
// TODO load equation into point ADD
|
||||
pt_X1 <= pt_mult1_out_p; // TODO remove these
|
||||
pt_X1 <= pt_mult1_out_p;
|
||||
pt_mult0_in_p2 <= pt_mult1_out_p;
|
||||
cnt[1] <= 1;
|
||||
end
|
||||
|
||||
// Do the final point add
|
||||
if (cnt[2:0] == 3'b011) begin
|
||||
// TODO the final add /checks
|
||||
pt_mult0_in_p2_val <= 1;
|
||||
cnt[2:0] <= 3'b100;
|
||||
end
|
||||
|
@ -394,14 +367,8 @@ always_ff @ (posedge i_clk) begin
|
|||
end
|
||||
endcase
|
||||
end
|
||||
{UPDATE_RAM_VARIABLES}: begin
|
||||
// Here we write all our calculated variables to RAM
|
||||
end
|
||||
|
||||
{FINISHED}: begin
|
||||
// TODO send message back
|
||||
send_message($bits(verify_secp256k1_sig_rpl_t)/8);
|
||||
// TODO also write result into RAM
|
||||
end
|
||||
{IGNORE}: begin
|
||||
if_cmd_rx.rdy <= 1;
|
||||
|
@ -410,47 +377,20 @@ always_ff @ (posedge i_clk) begin
|
|||
end
|
||||
endcase
|
||||
|
||||
// We use this to write to the RAM as results are valid
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
logic if_axi_mm_rd_;
|
||||
|
||||
always_comb begin
|
||||
register_file_b.a = if_axi_mm.addr/8;
|
||||
end
|
||||
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
if_axi_mm.reset_sink();
|
||||
register_file_b.en <= 1;
|
||||
register_file_b.re <= 1;
|
||||
register_file_b.we <= 0;
|
||||
register_file_b.d <= 0;
|
||||
if_axi_mm_rd_ <= 0;
|
||||
end else begin
|
||||
if_axi_mm_rd_ <= if_axi_mm_rd;
|
||||
if_axi_mm.rd_dat_val <= 0;
|
||||
register_file_b.en <= 1;
|
||||
register_file_b.re <= 1;
|
||||
if_axi_mm_rd <= if_axi_mm.rd;
|
||||
if (if_axi_mm_rd_) begin
|
||||
if_axi_mm.rd_dat_val <= 1;
|
||||
if_axi_mm.rd_dat <= register_file_b.q;
|
||||
// Something went wrong - send a message back to host
|
||||
if (&timeout) begin
|
||||
secp256k1_ver.TIMEOUT_FAIL <= 1;
|
||||
end else begin
|
||||
timeout <= timeout + 1;
|
||||
end
|
||||
if (secp256k1_ver.TIMEOUT_FAIL && secp256k1_state != FINISHED) begin
|
||||
cnt <= $bits(verify_secp256k1_sig_rpl_t)/8;
|
||||
msg <= verify_secp256k1_sig_rpl(secp256k1_ver, index);
|
||||
secp256k1_state <= FINISHED;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// BRAM for storing parsed inputs
|
||||
bram #(
|
||||
.RAM_WIDTH ( 64 ),
|
||||
.RAM_DEPTH ( REGISTER_SIZE ),
|
||||
.RAM_PERFORMANCE ( "HIGH_PERFORMANCE" )
|
||||
) register_file (
|
||||
.a ( register_file_a ),
|
||||
.b ( register_file_b )
|
||||
);
|
||||
|
||||
// Calculate binary inverse mod n
|
||||
bin_inv #(
|
||||
|
@ -607,7 +547,7 @@ generate if (USE_ENDOMORPH == "NO") begin
|
|||
.i_p2 ( pt_mult0_in_p2 ),
|
||||
.i_p2_val ( pt_mult0_in_p2_val )
|
||||
);
|
||||
|
||||
|
||||
secp256k1_point_mult #(
|
||||
.RESOURCE_SHARE ( "YES" )
|
||||
)
|
||||
|
@ -630,7 +570,7 @@ generate if (USE_ENDOMORPH == "NO") begin
|
|||
.i_p2_val ( 1'b0 )
|
||||
);
|
||||
end else begin
|
||||
secp256k1_point_mult_endo
|
||||
secp256k1_point_mult_endo
|
||||
secp256k1_point_mult_endo0 (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
|
@ -650,7 +590,7 @@ end else begin
|
|||
.i_p2_val ( pt_mult0_in_p2_val )
|
||||
);
|
||||
|
||||
secp256k1_point_mult_endo
|
||||
secp256k1_point_mult_endo
|
||||
secp256k1_point_mult_endo1 (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
This is the top level of the Zcash FPGA acceleration engine.
|
||||
|
||||
|
||||
We have different interfaces that are all muxed together to provide FPGA
|
||||
with commands and data.
|
||||
|
||||
|
||||
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
*/
|
||||
|
||||
module zcash_fpga_top
|
||||
import zcash_fpga_pkg::*, equihash_pkg::*;
|
||||
|
@ -30,7 +30,7 @@ module zcash_fpga_top
|
|||
input i_clk_core0, i_rst_core0, // Core 0 is the main clock
|
||||
input i_clk_core1, i_rst_core1, // Core 1 is used on logic with faster clock
|
||||
input i_clk_if, i_rst_if, // Command interface clock (e.g. UART / PCIe)
|
||||
|
||||
|
||||
// Command interface input and output
|
||||
if_axi_stream.sink rx_if,
|
||||
if_axi_stream.source tx_if
|
||||
|
@ -42,11 +42,10 @@ if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS)) equihash_axi(i_clk_core0);
|
|||
|
||||
if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS)) secp256k1_out_if(i_clk_core0);
|
||||
if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS)) secp256k1_in_if(i_clk_core0);
|
||||
if_axi_mm secp256k1_mm_if(i_clk_core0);
|
||||
|
||||
equihash_bm_t equihash_mask;
|
||||
logic equihash_mask_val;
|
||||
|
||||
|
||||
always_ff @ (posedge i_clk_core0) begin
|
||||
usr_rst_r <= usr_rst;
|
||||
rst_core0 <= i_rst_core0 || usr_rst_r;
|
||||
|
@ -101,7 +100,7 @@ equihash_verif_top (
|
|||
.i_clk ( i_clk_core0 ),
|
||||
.i_rst ( rst_core0 || ENB_VERIFY_EQUIHASH == 0 ),
|
||||
.i_clk_300 ( i_clk_core1 ), // Faster clock
|
||||
.i_rst_300 ( rst_core1 || ENB_VERIFY_EQUIHASH == 0 ),
|
||||
.i_rst_300 ( rst_core1 || ENB_VERIFY_EQUIHASH == 0 ),
|
||||
.i_axi ( equihash_axi ),
|
||||
.o_mask ( equihash_mask ),
|
||||
.o_mask_val ( equihash_mask_val )
|
||||
|
@ -109,15 +108,12 @@ equihash_verif_top (
|
|||
|
||||
|
||||
// This block is the ECCDSA block for curve secp256k1
|
||||
always_comb begin
|
||||
secp256k1_mm_if.reset_source();
|
||||
end
|
||||
|
||||
secp256k1_top secp256k1_top (
|
||||
.i_clk ( i_clk_core0 ),
|
||||
.i_rst ( rst_core0 || ENB_VERIFY_SECP256K1_SIG == 0 ),
|
||||
.if_cmd_rx ( secp256k1_out_if ),
|
||||
.if_cmd_tx ( secp256k1_in_if ),
|
||||
.if_axi_mm ( secp256k1_mm_if )
|
||||
.if_cmd_tx ( secp256k1_in_if )
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ logic clk, rst;
|
|||
|
||||
if_axi_stream #(.DAT_BYTS(8)) in_if(clk);
|
||||
if_axi_stream #(.DAT_BYTS(8)) out_if(clk);
|
||||
if_axi_mm mm_if(clk);
|
||||
|
||||
initial begin
|
||||
rst = 0;
|
||||
|
@ -51,8 +50,7 @@ secp256k1_top secp256k1_top (
|
|||
.i_clk ( clk ),
|
||||
.i_rst ( rst ),
|
||||
.if_cmd_rx ( in_if ),
|
||||
.if_cmd_tx ( out_if ),
|
||||
.if_axi_mm ( mm_if )
|
||||
.if_cmd_tx ( out_if )
|
||||
);
|
||||
|
||||
// Test a point
|
||||
|
@ -65,7 +63,7 @@ begin
|
|||
logic fail = 0;
|
||||
verify_secp256k1_sig_t verify_secp256k1_sig;
|
||||
verify_secp256k1_sig_rpl_t verify_secp256k1_sig_rpl;
|
||||
|
||||
|
||||
$display("Running test...");
|
||||
verify_secp256k1_sig.hdr.cmd = VERIFY_SECP256K1_SIG;
|
||||
verify_secp256k1_sig.hdr.len = $bits(verify_secp256k1_sig_t)/8;
|
||||
|
@ -75,26 +73,20 @@ begin
|
|||
verify_secp256k1_sig.s = s;
|
||||
verify_secp256k1_sig.Qx = Qx;
|
||||
verify_secp256k1_sig.Qy = Qy;
|
||||
|
||||
|
||||
start_time = $time;
|
||||
fork
|
||||
in_if.put_stream(verify_secp256k1_sig, $bits(verify_secp256k1_sig)/8);
|
||||
out_if.get_stream(get_dat, get_len);
|
||||
join
|
||||
finish_time = $time;
|
||||
|
||||
|
||||
verify_secp256k1_sig_rpl = get_dat;
|
||||
|
||||
|
||||
fail |= verify_secp256k1_sig_rpl.hdr.cmd != VERIFY_SECP256K1_SIG_RPL;
|
||||
fail |= (verify_secp256k1_sig_rpl.bm != 0);
|
||||
fail |= (verify_secp256k1_sig_rpl.index != k);
|
||||
assert (~fail) else $fatal(1, "%m %t ERROR: test failed :\n%p", $time, verify_secp256k1_sig_rpl);
|
||||
|
||||
// Also try reading some RAM values
|
||||
mm_if.get_data(mm_data, SIG_VER_HASH);
|
||||
|
||||
fail |= mm_data != hash[0 +: 64];
|
||||
assert (~fail) else $fatal(1, "%m %t ERROR: mm_if data read back wrong hash", $time);
|
||||
|
||||
$display("test #%d PASSED in %d clocks", integer'(k), (finish_time-start_time)/CLK_PERIOD);
|
||||
end
|
||||
|
@ -104,9 +96,8 @@ endtask;
|
|||
initial begin
|
||||
out_if.rdy = 0;
|
||||
in_if.val = 0;
|
||||
mm_if.reset_source();
|
||||
#(40*CLK_PERIOD);
|
||||
|
||||
/*
|
||||
test(1, 256'h4c7dbc46486ad9569442d69b558db99a2612c4f003e6631b593942f531e67fd4, // message hash
|
||||
256'h1375af664ef2b74079687956fd9042e4e547d57c4438f1fc439cbfcb4c9ba8b, // r
|
||||
256'hde0f72e442f7b5e8e7d53274bf8f97f0674f4f63af582554dbecbb4aa9d5cbcb, // s
|
||||
|
@ -118,6 +109,12 @@ initial begin
|
|||
256'h6abcd5e40fcee8bca6b506228a2dcae67daa5d743e684c4d3fb1cb77e43b48fe, // s
|
||||
256'hb661c143ffbbad5acfe16d427767cdc57fb2e4c019a4753ba68cd02c29e4a153, //Qx
|
||||
256'h6e1fb00fdb9ddd39b55596bfb559bc395f220ae51e46dbe4e4df92d1a5599726); //Qy
|
||||
*/
|
||||
test(3, 256'h10, // message hash
|
||||
256'h10, // r
|
||||
256'h10, // s
|
||||
256'hb661c143ffbbad5acfe16d427767cdc57fb2e4c019a4753ba68cd02c29e4a153, //Qx
|
||||
256'h6e1fb00fdb9ddd39b55596bfb559bc395f220ae51e46dbe4e4df92d1a5599726); //Qy
|
||||
|
||||
#1us $finish();
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue