Top level file changes

This commit is contained in:
bsdevlin 2019-03-25 14:56:05 -04:00
parent 58fd5658c5
commit 65e3723d21
12 changed files with 966 additions and 220 deletions

View File

@ -55,8 +55,10 @@ generate
c = (1 << 32) + (1 << 9) + (1 << 8) + (1 << 7) + (1 << 6) + (1 << 4) + 1;
end
always_ff @ (posedge i_clk) begin
res0 <= i_dat[511:256]*c + i_dat[255:0];
res1 <= res0[511:256]*c + res0[255:0];
if (~o_val || (o_val && i_rdy)) begin
res0 <= i_dat[511:256]*c + i_dat[255:0];
res1 <= res0[511:256]*c + res0[255:0];
end
end
end else begin
logic [256*2-1:0] res0_, res1_;
@ -65,8 +67,10 @@ generate
res1_ = (res0[511:256] << 32) + (res0[511:256] << 9) + (res0[511:256] << 8) + (res0[511:256] << 7) + (res0[511:256] << 6) + (res0[511:256] << 4) + res0[511:256]+ res0[255:0];
end
always_ff @ (posedge i_clk) begin
res0 <= res0_;
res1 <= res1_;
if (~o_val || (o_val && i_rdy)) begin
res0 <= res0_;
res1 <= res1_;
end
end
end
endgenerate
@ -81,17 +85,20 @@ always_ff @ (posedge i_clk) begin
ctl <= 0;
o_err <= 0;
end else begin
o_val <= 0;
val <= val << 1;
ctl <= {ctl, i_ctl};
err <= err << 1;
val[0] <= i_val;
err[0] <= i_err;
//o_val <= 0;
if (~o_val || (o_val && i_rdy)) begin
val <= val << 1;
ctl <= {ctl, i_ctl};
err <= err << 1;
val[0] <= i_val;
err[0] <= i_err;
o_dat <= res1 >= p_eq ? res1 - p_eq : res1;
o_err <= err[1] || (res1 >= 2*p_eq);
o_val <= val[1];
o_ctl <= ctl[1];
o_dat <= res1 >= p_eq ? res1 - p_eq : res1;
o_err <= err[1] || (res1 >= 2*p_eq);
o_val <= val[1];
o_ctl <= ctl[1];
end
end
end

View File

@ -1,6 +1,6 @@
/*
This performs a 256 bit multiplication followed by modulus
operation.
This performs a 256 bit multiplication followed by optional modulus
operation. Modulus is either n or p depending on ctl.
Using Karatsuba-Ofman multiplication, where the factor of splitting
is parameterized.
@ -33,6 +33,7 @@ module secp256k1_mult_mod #(
input [255:0] i_dat_b,
input [CTL_BITS-1:0] i_ctl,
input i_val,
input i_cmd, // 0 = mod p, 1 = mod n
input i_err,
output logic o_rdy,
// output
@ -40,33 +41,40 @@ module secp256k1_mult_mod #(
output logic [CTL_BITS-1:0] o_ctl,
input i_rdy,
output logic o_val,
output logic o_err
output logic o_err
);
import secp256k1_pkg::*;
import common_pkg::*;
localparam KARATSUBA_LEVEL = 2;
if_axi_stream #(.DAT_BYTS(512/8)) int_if(i_clk);
if_axi_stream #(.DAT_BYTS(512/8), .CTL_BITS(CTL_BITS+1)) int_if(i_clk);
if_axi_stream #(.DAT_BYTS(256/8), .CTL_BITS(CTL_BITS)) out_mod_p_if(i_clk);
if_axi_stream #(.DAT_BYTS(256/8), .CTL_BITS(CTL_BITS)) out_mod_n_if(i_clk);
// If barret mod block is using an EXTERNAL multiplier this needs to be connected to a multiplier
if_axi_stream #(.DAT_BYTS(512/8), .CTL_BITS(CTL_BITS)) out_brt_mult_if(i_clk);
if_axi_stream #(.DAT_BYTS(512/8), .CTL_BITS(CTL_BITS)) in_brt_mult_if(i_clk);
logic [KARATSUBA_LEVEL-1:0] err;
karatsuba_ofman_mult # (
.BITS ( 256 ),
.LEVEL ( KARATSUBA_LEVEL ),
.CTL_BITS ( CTL_BITS )
.CTL_BITS ( CTL_BITS + 1 )
)
karatsuba_ofman_mult (
.i_clk ( i_clk ),
.i_ctl ( i_ctl ),
.i_dat_a( i_dat_a ),
.i_dat_b( i_dat_b ),
.i_val ( i_val ),
.o_rdy ( o_rdy ),
.o_dat ( int_if.dat ),
.o_val ( int_if.val ),
.i_rdy ( int_if.rdy ),
.o_ctl ( int_if.ctl )
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_ctl ( {i_cmd, i_ctl} ),
.i_dat_a( i_dat_a ),
.i_dat_b( i_dat_b ),
.i_val ( i_val ),
.o_rdy ( o_rdy ),
.o_dat ( int_if.dat ),
.o_val ( int_if.val ),
.i_rdy ( int_if.rdy ),
.o_ctl ( int_if.ctl )
);
always_ff @ (posedge i_clk) begin
@ -84,6 +92,38 @@ always_comb begin
int_if.eop = 0;
end
// Depending on ctl, we mux output
logic wait_barret, int_if_rdy_n, int_if_rdy_p;
always_ff @ (posedge i_clk) begin
if (i_rst) begin
wait_barret <= 0;
end else begin
if (int_if.val && int_if.rdy && int_if.ctl[CTL_BITS] == 1) begin
wait_barret <= 1;
end
if (out_mod_n_if.val && out_mod_n_if.rdy) begin
wait_barret <= 0;
end
end
end
always_comb begin
out_mod_p_if.rdy = i_rdy;// && (wait_barret == 0);
out_mod_n_if.rdy = i_rdy;// && (wait_barret == 1);
out_mod_n_if.err = 0;
int_if.rdy = int_if.ctl[CTL_BITS] == 0 ? int_if_rdy_p : int_if_rdy_n;
if (wait_barret)
int_if.rdy = 0;
o_dat = out_mod_p_if.val ? out_mod_p_if.dat : out_mod_n_if.dat;
o_ctl = out_mod_p_if.val ? out_mod_p_if.ctl : out_mod_n_if.ctl;
o_err = out_mod_p_if.val ? out_mod_p_if.err : out_mod_n_if.err;
o_val = out_mod_p_if.val ? out_mod_p_if.val : out_mod_n_if.val;
end
secp256k1_mod #(
.USE_MULT ( 0 ),
.CTL_BITS ( CTL_BITS )
@ -92,15 +132,37 @@ secp256k1_mod (
.i_clk( i_clk ),
.i_rst( i_rst ),
.i_dat( int_if.dat ),
.i_val( int_if.val ),
.i_ctl( int_if.ctl ),
.i_val( int_if.val && int_if.ctl[CTL_BITS] == 0 && ~wait_barret),
.i_ctl( int_if.ctl[CTL_BITS-1:0] ),
.i_err( int_if.err ),
.o_rdy( int_if.rdy ),
.o_dat( o_dat ),
.o_ctl( o_ctl ),
.o_err( o_err ),
.i_rdy( i_rdy ),
.o_val( o_val )
.o_rdy( int_if_rdy_p ),
.o_dat( out_mod_p_if.dat ),
.o_ctl( out_mod_p_if.ctl ),
.o_err( out_mod_p_if.err ),
.i_rdy( out_mod_p_if.rdy ),
.o_val( out_mod_p_if.val )
);
barret_mod #(
.IN_BITS ( 512 ),
.OUT_BITS ( 256 ),
.CTL_BITS ( CTL_BITS ),
.P ( secp256k1_pkg::n ),
.MULTIPLIER( "ACCUM_MULT" ) // [ACCUM_MULT || KARATSUBA || EXTERNAL]
)
barret_mod (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_dat ( int_if.dat ),
.i_val ( int_if.val && int_if.ctl[CTL_BITS] == 1 && ~wait_barret),
.i_ctl ( int_if.ctl[CTL_BITS-1:0] ),
.o_rdy ( int_if_rdy_n ),
.o_ctl ( out_mod_n_if.ctl ),
.o_dat ( out_mod_n_if.dat ),
.o_val ( out_mod_n_if.val ),
.i_rdy ( out_mod_n_if.rdy ),
.o_mult_if ( out_brt_mult_if ),
.i_mult_if ( in_brt_mult_if )
);

View File

@ -40,6 +40,10 @@ package secp256k1_pkg;
parameter SIG_VER_R = 16; // 256 bits
parameter SIG_VER_Q = 20; // 512 bits
parameter SIG_VER_W = 28; // 256 bits - Result of invert(s)
parameter SIG_VER_U1 = 32; // 256 bits
parameter SIG_VER_U2 = 36; // 256 bits
parameter SIG_VER_X = 40; // Result of (u1.P + u2.Q) 256 * 3 bits as is in jb coords.
parameter SIG_VER_X_AFF = 52; // 256 bits, SIG_VER_X result's X in affine coords.
// Expected to be in Jacobian coordinates
typedef struct packed {
@ -49,7 +53,8 @@ package secp256k1_pkg;
jb_point_t G_p = {x: secp256k1_pkg::Gx, y: secp256k1_pkg::Gy, z:1};
typedef struct packed {
logic [5:0] padding;
logic [3:0] padding;
logic FAILED_SIG_VER;
logic X_INFINITY_POINT;
logic OUT_OF_RANGE_S;
logic OUT_OF_RANGE_R;

View File

@ -34,10 +34,10 @@ module secp256k1_point_add
output logic o_err,
// Interface to 256bit multiplier (mod p)
if_axi_stream.source o_mult_if,
if_axi_stream.source i_mult_if,
if_axi_stream.sink i_mult_if,
// Interface to only mod reduction block
if_axi_stream.source o_mod_if,
if_axi_stream.source i_mod_if
if_axi_stream.sink i_mod_if
);
/*
@ -114,6 +114,8 @@ always_ff @ (posedge i_clk) begin
o_mod_if.dat <= 0;
i_mult_if.rdy <= 0;
i_mod_if.rdy <= 0;
o_mod_if.ctl <= 0;
o_mult_if.ctl <= 0;
eq_val <= 0;
state <= IDLE;
eq_wait <= 0;

View File

@ -71,9 +71,9 @@ always_comb begin
o_mult_if.eop = 1;
o_mod_if.sop = 1;
o_mod_if.eop = 1;
o_mod_if.err = 1;
o_mod_if.err = 0;
o_mod_if.mod = 0;
o_mult_if.err = 1;
o_mult_if.err = 0;
o_mult_if.mod = 0;
end
@ -84,7 +84,9 @@ always_ff @ (posedge i_clk) begin
o_rdy <= 0;
o_p <= 0;
o_mult_if.val <= 0;
o_mult_if.ctl <= 0;
o_mod_if.val <= 0;
o_mod_if.ctl <= 0;
o_mult_if.dat <= 0;
o_mod_if.dat <= 0;
i_mult_if.rdy <= 0;

View File

@ -21,6 +21,7 @@
module secp256k1_point_mult
import secp256k1_pkg::*;
#(
parameter RESOURCE_SHARE = "NO"
)(
input i_clk, i_rst,
// Input point and value to multiply
@ -32,7 +33,17 @@ module secp256k1_point_mult
output jb_point_t o_p,
input logic i_rdy,
output logic o_val,
output logic o_err
output logic o_err,
// Interface to 256bit multiplier (mod p) (if RESOURCE_SHARE == "YES")
if_axi_stream.source o_mult_if,
if_axi_stream.sink i_mult_if,
// Interface to only mod reduction block (if RESOURCE_SHARE == "YES")
if_axi_stream.source o_mod_if,
if_axi_stream.sink i_mod_if,
// We provide another input so that the final point addition can be done
input jb_point_t i_p2,
input i_p2_val
);
// [0] is connection from/to dbl block, [1] is add block, [2] is arbitrated value
@ -47,7 +58,7 @@ logic p_dbl_in_val, p_dbl_in_rdy, p_dbl_out_err, p_dbl_out_val, p_dbl_out_rdy, p
logic p_add_in_val, p_add_in_rdy, p_add_out_err, p_add_out_val, p_add_out_rdy, p_add_done;
logic special_dbl;
enum {IDLE, DOUBLE_ADD, FINISHED} state;
enum {IDLE, DOUBLE_ADD, ADD_ONLY, FINISHED} state;
always_ff @ (posedge i_clk) begin
if (i_rst) begin
@ -80,8 +91,22 @@ always_ff @ (posedge i_clk) begin
p_n <= i_p;
k_l <= i_k;
if (o_rdy && i_val) begin
o_rdy <= 0;
state <= DOUBLE_ADD;
end
if (o_rdy && i_p2_val) begin
o_rdy <= 0;
p_n <= i_p;
p_q <= i_p2;
state <= ADD_ONLY;
// Check for special cases to determine double or add
if (i_p.x == i_p2.x && i_p.y == i_p2.y) begin
p_dbl_in_val <= 1;
end else begin
p_add_in_val <= 1;
end
end
end
{DOUBLE_ADD}: begin
p_dbl_in_val <= (p_dbl_in_val && p_dbl_in_rdy) ? 0 : p_dbl_in_val;
@ -132,6 +157,21 @@ always_ff @ (posedge i_clk) begin
end
end
{ADD_ONLY}: begin
p_dbl_in_val <= (p_dbl_in_val && p_dbl_in_rdy) ? 0 : p_dbl_in_val;
p_add_in_val <= (p_add_in_val && p_add_in_rdy) ? 0 : p_add_in_val;
if (p_dbl_out_val && p_dbl_out_rdy) begin
state <= FINISHED;
o_p <= p_dbl;
o_val <= 1;
end
if (p_add_out_val && p_add_out_rdy) begin
state <= FINISHED;
o_p <= p_add;
o_val <= 1;
end
end
{FINISHED}: begin
if (i_rdy && o_val) begin
o_val <= 0;
@ -189,11 +229,13 @@ secp256k1_point_add secp256k1_point_add(
);
// We add arbitrators to these to share with the point add module
localparam ARB_BIT = 5;
packet_arb # (
.DAT_BYTS ( 512/8 ),
.CTL_BITS ( 8 ),
.NUM_IN ( 2 ),
.PIPELINE ( 0 )
.DAT_BYTS ( 512/8 ),
.CTL_BITS ( 8 ),
.NUM_IN ( 2 ),
.OVR_WRT_BIT ( ARB_BIT ),
.PIPELINE ( 0 )
)
packet_arb_mult (
.i_clk ( i_clk ),
@ -203,10 +245,11 @@ packet_arb_mult (
);
packet_arb # (
.DAT_BYTS ( 512/8 ),
.CTL_BITS ( 8 ),
.NUM_IN ( 2 ),
.PIPELINE ( 0 )
.DAT_BYTS ( 512/8 ),
.CTL_BITS ( 8 ),
.NUM_IN ( 2 ),
.OVR_WRT_BIT ( ARB_BIT ),
.PIPELINE ( 0 )
)
packet_arb_mod (
.i_clk ( i_clk ),
@ -219,12 +262,14 @@ always_comb begin
mod_out_if[0].copy_if_comb(mod_out_if[2].to_struct());
mod_out_if[1].copy_if_comb(mod_out_if[2].to_struct());
mod_out_if[0].ctl = {1'd0, mod_out_if[2].ctl[6:0]};
mod_out_if[1].ctl = {1'd0, mod_out_if[2].ctl[6:0]};
mod_out_if[0].ctl = mod_out_if[2].ctl;
mod_out_if[1].ctl = mod_out_if[2].ctl;
mod_out_if[0].ctl[ARB_BIT] = 0;
mod_out_if[1].ctl[ARB_BIT] = 0;
mod_out_if[1].val = mod_out_if[2].val && mod_out_if[2].ctl[7] == 1;
mod_out_if[0].val = mod_out_if[2].val && mod_out_if[2].ctl[7] == 0;
mod_out_if[2].rdy = mod_out_if[2].ctl[7] == 0 ? mod_out_if[0].rdy : mod_out_if[1].rdy;
mod_out_if[1].val = mod_out_if[2].val && mod_out_if[2].ctl[ARB_BIT] == 1;
mod_out_if[0].val = mod_out_if[2].val && mod_out_if[2].ctl[ARB_BIT] == 0;
mod_out_if[2].rdy = mod_out_if[2].ctl[ARB_BIT] == 0 ? mod_out_if[0].rdy : mod_out_if[1].rdy;
mod_out_if[2].sop = 1;
mod_out_if[2].eop = 1;
@ -235,54 +280,97 @@ always_comb begin
mult_out_if[0].copy_if_comb(mult_out_if[2].to_struct());
mult_out_if[1].copy_if_comb(mult_out_if[2].to_struct());
mult_out_if[0].ctl = {1'd0, mult_out_if[2].ctl[6:0]};
mult_out_if[1].ctl = {1'd0, mult_out_if[2].ctl[6:0]};
mult_out_if[0].ctl = mult_out_if[2].ctl;
mult_out_if[1].ctl = mult_out_if[2].ctl;
mult_out_if[0].ctl[ARB_BIT] = 0;
mult_out_if[1].ctl[ARB_BIT] = 0;
mult_out_if[1].val = mult_out_if[2].val && mult_out_if[2].ctl[7] == 1;
mult_out_if[0].val = mult_out_if[2].val && mult_out_if[2].ctl[7] == 0;
mult_out_if[2].rdy = mult_out_if[2].ctl[7] == 0 ? mult_out_if[0].rdy : mult_out_if[1].rdy;
mult_out_if[1].val = mult_out_if[2].val && mult_out_if[2].ctl[ARB_BIT] == 1;
mult_out_if[0].val = mult_out_if[2].val && mult_out_if[2].ctl[ARB_BIT] == 0;
mult_out_if[2].rdy = mult_out_if[2].ctl[ARB_BIT] == 0 ? mult_out_if[0].rdy : mult_out_if[1].rdy;
mult_out_if[2].sop = 1;
mult_out_if[2].eop = 1;
mult_out_if[2].mod = 0;
end
secp256k1_mult_mod #(
.CTL_BITS ( 8 )
)
secp256k1_mult_mod (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_dat_a ( mult_in_if[2].dat[0 +: 256] ),
.i_dat_b ( mult_in_if[2].dat[256 +: 256] ),
.i_val ( mult_in_if[2].val ),
.i_err ( mult_in_if[2].err ),
.i_ctl ( mult_in_if[2].ctl ),
.o_rdy ( mult_in_if[2].rdy ),
.o_dat ( mult_out_if[2].dat ),
.i_rdy ( mult_out_if[2].rdy ),
.o_val ( mult_out_if[2].val ),
.o_ctl ( mult_out_if[2].ctl ),
.o_err ( mult_out_if[2].err )
);
secp256k1_mod #(
.USE_MULT ( 0 ),
.CTL_BITS ( 8 )
)
secp256k1_mod (
.i_clk( i_clk ),
.i_rst( i_rst ),
.i_dat( mod_in_if[2].dat ),
.i_val( mod_in_if[2].val ),
.i_err( mod_in_if[2].err ),
.i_ctl( mod_in_if[2].ctl ),
.o_rdy( mod_in_if[2].rdy ),
.o_dat( mod_out_if[2].dat ),
.o_ctl( mod_out_if[2].ctl ),
.o_err( mod_out_if[2].err ),
.i_rdy( mod_out_if[2].rdy ),
.o_val( mod_out_if[2].val )
);
generate
if (RESOURCE_SHARE == "YES") begin: RESOURCE_GEN
always_comb begin
o_mult_if.val = mult_in_if[2].val;
o_mult_if.dat = mult_in_if[2].dat;
o_mult_if.ctl = mult_in_if[2].ctl;
o_mult_if.err = 0;
o_mult_if.mod = 0;
o_mult_if.sop = 1;
o_mult_if.eop = 1;
mult_in_if[2].rdy = o_mult_if.rdy;
o_mod_if.val = mod_in_if[2].val;
o_mod_if.dat = mod_in_if[2].dat;
o_mod_if.ctl = mod_in_if[2].ctl;
o_mod_if.err = 0;
o_mod_if.mod = 0;
o_mod_if.sop = 1;
o_mod_if.eop = 1;
mod_in_if[2].rdy = o_mod_if.rdy;
i_mult_if.rdy = mult_out_if[2].rdy;
mult_out_if[2].val = i_mult_if.val;
mult_out_if[2].dat = i_mult_if.dat;
mult_out_if[2].ctl = i_mult_if.ctl;
i_mod_if.rdy = mod_out_if[2].rdy;
mod_out_if[2].val = i_mod_if.val;
mod_out_if[2].dat = i_mod_if.dat;
mod_out_if[2].ctl = i_mod_if.ctl;
end
end else begin
always_comb begin
o_mult_if.reset_source();
i_mult_if.rdy = 0;
o_mod_if.reset_source();
i_mod_if.rdy = 0;
end
secp256k1_mult_mod #(
.CTL_BITS ( 8 )
)
secp256k1_mult_mod (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_dat_a ( mult_in_if[2].dat[0 +: 256] ),
.i_dat_b ( mult_in_if[2].dat[256 +: 256] ),
.i_val ( mult_in_if[2].val ),
.i_err ( mult_in_if[2].err ),
.i_ctl ( mult_in_if[2].ctl ),
.i_cmd ( 1'd0 ),
.o_rdy ( mult_in_if[2].rdy ),
.o_dat ( mult_out_if[2].dat ),
.i_rdy ( mult_out_if[2].rdy ),
.o_val ( mult_out_if[2].val ),
.o_ctl ( mult_out_if[2].ctl ),
.o_err ( mult_out_if[2].err )
);
secp256k1_mod #(
.USE_MULT ( 0 ),
.CTL_BITS ( 8 )
)
secp256k1_mod (
.i_clk( i_clk ),
.i_rst( i_rst ),
.i_dat( mod_in_if[2].dat ),
.i_val( mod_in_if[2].val ),
.i_err( mod_in_if[2].err ),
.i_ctl( mod_in_if[2].ctl ),
.o_rdy( mod_in_if[2].rdy ),
.o_dat( mod_out_if[2].dat ),
.o_ctl( mod_out_if[2].ctl ),
.o_err( mod_out_if[2].err ),
.i_rdy( mod_out_if[2].rdy ),
.o_val( mod_out_if[2].val )
);
end
endgenerate
endmodule

View File

@ -1,4 +1,7 @@
module secp256k1_top (
module secp256k1_top #(
parameter DAT_BYTS = 8,
parameter DAT_BITS = DAT_BYTS*8
)(
input i_clk,
input i_rst,
// Command interface
@ -12,41 +15,50 @@ import secp256k1_pkg::*;
import zcash_fpga_pkg::*;
// Register map is used for storing command data
logic [REGISTER_SIZE/64-1:0][63:0] register_map;
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 multiplier (karatsuba)
logic [255:0] mult_dat_a, mult_dat_b;
logic mult_dat_val;
if_axi_stream #(.DAT_BYTS(512/8)) mult_out_if(i_clk);
// 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);
// TODO just have one multiplier (unless doulbe & add is parallel)
//one multiplier that barret reduction can share?
// [0] is connection from/to point_mult0 block, [1] is add point_mult1 block, 2 is this state machine, [3] is arbitrated value
if_axi_stream #(.DAT_BYTS(256*2/8), .CTL_BITS(8)) mult_in_if [3:0] (i_clk);
if_axi_stream #(.DAT_BYTS(256/8), .CTL_BITS(8)) mult_out_if [3:0] (i_clk);
if_axi_stream #(.DAT_BYTS(256*2/8), .CTL_BITS(8)) mod_in_if [2:0] (i_clk);
if_axi_stream #(.DAT_BYTS(256/8), .CTL_BITS(8)) mod_out_if [2:0] (i_clk);
jb_point_t pt_mult0_in_p, pt_mult0_out_p, pt_mult1_in_p, pt_mult1_out_p, pt_X0, pt_X1, pt_X, pt_mult0_in_p2;
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
// Controlling state machine
typedef enum {IDLE,
VERIFY_SECP256K1_SIG_PARSE, // Parse inputs
GET_INDEX,
VERIFY_SECP256K1_SIG_PARSE,
CALC_S_INV,
POINT_DBL,
POINT_ADD,
CALC_U1_U2,
CALC_X,
CALC_X_JACOB,
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
logic [255:0] r, w;
// Other temporary values - could use RAM insead?
logic [255:0] e, r, w, u1, u2;
logic [63:0] index;
logic w_val, u1_val, u2_val;
logic [5:0] cnt; // Counter for parsing command inputs
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;
@ -57,33 +69,74 @@ end
always_ff @ (posedge i_clk) begin
if (i_rst) begin
msg <= 0;
secp256k1_state <= IDLE;
if_cmd_tx.reset_source();
if_cmd_rx.reset_sink();
if_cmd_rx.rdy <= 0;
cnt <= 0;
mult_out_if.rdy <= 0;
register_file_a.reset_source();
mult_dat_a <= 0;
mult_dat_b <= 0;
mult_dat_val <= 0;
w <= 0;
w_val <= 0;
r <= 0;
u1 <= 0;
u1_val <= 0;
u2 <= 0;
u2_val <= 0;
e <= 0;
bin_inv_in_if.reset_source();
bin_inv_out_if.rdy <= 0;
secp256k1_ver <= 0;
inv_p <= secp256k1_pkg::n;
pt_X <= 0;
pt_X0 <= 0;
pt_X1 <= 0;
pt_mult0_in_p <= 0;
pt_mult1_in_p <= 0;
pt_mult0_in_k <= 0;
pt_mult1_in_k <= 0;
pt_mult0_in_val <= 0;
pt_mult0_out_rdy <= 0;
pt_mult1_in_val <= 0;
pt_mult1_out_rdy <= 0;
pt_mult0_in_p2_val <= 0;
mult_out_if[2].rdy <= 0;
mult_in_if[2].reset_source();
index <= 0;
end else begin
register_file_a.en <= 1;
register_file_a.wr <= 0;
register_file_a.rd <= 1;
mult_out_if.rdy <= 1;
bin_inv_out_if.rdy <= 1;
mult_dat_val <= 0;
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;
pt_mult0_out_rdy <= 1;
pt_mult1_out_rdy <= 1;
if (pt_mult0_in_val && pt_mult0_in_rdy)
pt_mult0_in_val <= 0;
if (pt_mult1_in_val && pt_mult1_in_rdy)
pt_mult1_in_val <= 0;
if (bin_inv_in_if.val && bin_inv_in_if.rdy)
bin_inv_in_if.val <= 0;
if (pt_mult0_in_p2_val && pt_mult0_in_rdy)
pt_mult0_in_p2_val <= 0;
case(secp256k1_state)
{IDLE}: begin
inv_p <= secp256k1_pkg::n;
w_val <= 0;
u1_val <= 0;
u2_val <= 0;
secp256k1_ver <= 0;
if_cmd_rx.rdy <= 1;
header_l <= header;
@ -91,8 +144,10 @@ always_ff @ (posedge i_clk) begin
if (if_cmd_rx.val && if_cmd_rx.rdy) begin
case(header.cmd)
{VERIFY_SECP256K1_SIG}: begin
register_map[CURR_CMD] <= header;
secp256k1_state <= VERIFY_SECP256K1_SIG_PARSE;
register_file_a.we <= 1;
register_file_a.a <= CURR_CMD;
register_file_a.d <= header;
secp256k1_state <= GET_INDEX;
end
default: begin
if (~if_cmd_rx.eop) begin
@ -103,16 +158,23 @@ always_ff @ (posedge i_clk) begin
endcase
end
end
{GET_INDEX}: begin
if (if_cmd_rx.val && if_cmd_rx.rdy) begin
index <= if_cmd_rx.dat;
secp256k1_state <= VERIFY_SECP256K1_SIG_PARSE;
end
if_cmd_rx.rdy <= 1;
end
{VERIFY_SECP256K1_SIG_PARSE}: begin
if_cmd_rx.rdy <= 1;
if (if_cmd_rx.val && if_cmd_rx.rdy) begin
register_file_a.wr <= 1;
register_file_a.we <= 1;
cnt <= cnt + 1;
if (cnt == 19) secp256k1_state <= CALC_S_INV;
end
if (bin_inv_in_if.val && bin_inv_in_if.rdy)
bin_inv_in_if.val <= 0;
if (cnt == 19) begin
secp256k1_state <= CALC_S_INV;
bin_inv_out_if.rdy <= 1;
end
end
case(cnt) inside
[0:3]: begin
@ -123,19 +185,26 @@ always_ff @ (posedge i_clk) begin
if (cnt == 3) begin
bin_inv_in_if.val <= 1;
end
end
end
[4:7]: begin
// We can load R into the karatsuba multiplier
register_file_a.a <= SIG_VER_R + (cnt % 4);
r[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat; // TODO remove
register_file_a.d <= if_cmd_rx.dat;
mult_dat_a[(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
e[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
register_file_a.a <= SIG_VER_HASH + (cnt % 4);
register_file_a.d <= if_cmd_rx.dat;
end
[12:19]: begin
register_file_a.a <= SIG_VER_Q + (cnt % 8);
pt_mult1_in_p.z <= 1;
if (cnt % 8 < 4) begin
pt_mult1_in_p.x[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
end else begin
pt_mult1_in_p.y[(cnt % 4)*64 +: 64] <= if_cmd_rx.dat;
end
register_file_a.d <= if_cmd_rx.dat;
end
endcase
@ -143,27 +212,160 @@ always_ff @ (posedge i_clk) begin
{CALC_S_INV}: begin
// Wait until bin_inv_out_if.val
if (bin_inv_in_if.dat >= secp256k1_pkg::n) secp256k1_ver.OUT_OF_RANGE_S <= 1;
if (mult_dat_a >= secp256k1_pkg::n) secp256k1_ver.OUT_OF_RANGE_R <= 1;
if (bin_inv_out.val && bin_inv_out.rdy) begin
w <= bin_inv_out.dat;
if (mult_in_if[2].dat >= secp256k1_pkg::n) secp256k1_ver.OUT_OF_RANGE_R <= 1;
if (bin_inv_out_if.val && bin_inv_out_if.rdy) begin
bin_inv_out_if.rdy <= 0;
w <= bin_inv_out_if.dat;
w_val <= 1;
// Start calculating U2
mult_in_if[2].ctl <= 1; // mod n
mult_in_if[2].dat[256 +: 256] <= bin_inv_out_if.dat;
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
{CALC_U1_U2}: begin
if (mult_in_if[2].val && mult_in_if[2].rdy) begin
cnt[1:0] <= 2'b01;
mult_in_if[2].val <= 0;
// Calculate U1
mult_in_if[2].dat[0 +: 256] <= e;
mult_in_if[2].val <= 1;
if (cnt[1:0] == 2'b01) begin
mult_in_if[2].val <= 0;
end
end
// Check for result
// TODO load into RAM
if (mult_out_if[2].val && mult_out_if[2].rdy) begin
case(cnt[1])
{1'd0}: begin
pt_mult0_in_k <= mult_out_if[2].dat;
// TODO write this to RAM
u1 <= mult_out_if[2].dat;
pt_mult0_in_k <= mult_out_if[2].dat;
pt_mult0_in_p.z <= 1;
pt_mult0_in_p.x <= secp256k1_pkg::Gx;
pt_mult0_in_p.y <= secp256k1_pkg::Gy;
pt_mult0_in_val <= 1;
u1_val <= 1;
cnt[1] <= 1;
end
{1'd1}: begin
pt_mult1_in_k <= mult_out_if[2].dat;
pt_mult1_in_val <= 1;
u2 <= mult_out_if[2].dat;
u2_val <= 1;
cnt <= 0;
secp256k1_state <= CALC_X;
end
endcase
end
end
{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_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
// Do the final inversion back to jacobian coords of the X, so need inverse of Z^2
if (cnt[2:0] == 3'b100 && pt_mult0_out_rdy && pt_mult0_out_val) begin
// Check for infinity
if (pt_mult0_out_p.z == 0)
secp256k1_ver.X_INFINITY_POINT <= 1;
cnt <= 0;
// Just store our value temp
pt_mult0_in_p2 <= pt_mult0_out_p;
secp256k1_state <= CALC_X_JACOB;
mult_in_if[2].val <= 1;
mult_in_if[2].dat <= {pt_mult0_out_p.z, pt_mult0_out_p.z};
mult_in_if[2].ctl <= 0; // mod p
// Here we either do a final inverstion to get the original .x value or we can do special checks
end
end
{CALC_X_JACOB}: begin
case(cnt)
0: begin
if (mult_out_if[2].rdy && mult_out_if[2].val) begin
bin_inv_in_if.dat <= mult_out_if[2].dat;
inv_p <= secp256k1_pkg::p_eq;
bin_inv_in_if.val <= 1;
bin_inv_out_if.rdy <= 1;
end
// Need to do final multiplication
if (bin_inv_out_if.val && bin_inv_out_if.rdy) begin
mult_in_if[2].val <= 1;
mult_in_if[2].dat <= {bin_inv_out_if.dat, pt_mult0_in_p2.x};
mult_in_if[2].ctl <= 0; // mod p
cnt <= 1;
end
end
{1}: begin
// Do one more multiplication but mod n
if (mult_out_if[2].rdy && mult_out_if[2].val) begin
mult_in_if[2].val <= 1;
mult_in_if[2].dat <= {256'd1, mult_out_if[2].dat};
mult_in_if[2].ctl <= 1; // mod n
cnt <= 2;
end
end
{2}: begin
if (mult_out_if[2].rdy && mult_out_if[2].val) begin
if (mult_out_if[2].dat != r) begin
secp256k1_ver.FAILED_SIG_VER <= 1;
end
cnt <= 3;
end
end
{3}: begin
cnt <= $bits(verify_secp256k1_sig_rpl_t)/8;
msg <= verify_secp256k1_sig_rpl(secp256k1_ver, index);
secp256k1_state <= FINISHED;
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;
if (if_cmd_rx.rdy && if_cmd_rx.val && if_cmd_rx.eop)
secp256k1_state <= IDLE;
end
endcase
end
end
// TODO could provide write access
always_comb begin
end
always_ff @ (posedge i_clk) begin
if (i_rst) begin
if_axi_mm.reset_sink();
@ -171,7 +373,7 @@ always_ff @ (posedge i_clk) begin
end else begin
if_axi_mm.rd_dat_val <= 0;
register_file_b.en <= 1;
register_file_b.rd <= 1;
register_file_b.re <= 1;
register_file_b.a <= if_axi_mm.addr/8;
if_axi_mm_rd <= if_axi_mm.rd;
if (if_axi_mm_rd) begin
@ -192,69 +394,198 @@ bram #(
);
// Calculate binary inverse mod n
begin: BINARY_INVERSE_MOD_N
bin_inv #(
.BITS ( 256 )
)(
.i_clk ( i_clk ),
.i_rst ( i_rst) ,
.i_dat ( bin_inv_in_if.dat ),
.i_p ( inv_p ),
.i_val ( bin_inv_in_if.val ),
.o_rdy ( bin_inv_in_if.rdy ),
.o_dat ( bin_inv_out_if.dat ),
.o_val ( bin_inv_out_if.val ),
.i_rdy ( bin_inv_out_if.rdy )
);
end
// 256 bit Karatsuba_ofman multiplier
begin: KARATSUBA_OFMAN_MULT
localparam KARATSUBA_LEVEL = 2;
logic [KARATSUBA_LEVEL-1:0] val;
karatsuba_ofman_mult # (
.BITS ( 256 ),
.LEVEL ( KARATSUBA_LEVEL )
)
karatsuba_ofman_mult (
.i_clk ( i_clk ),
.i_dat_a( mult_dat_a ),
.i_dat_b( mult_dat_b ),
.o_dat ( mult_out_if.dat )
);
always_ff @ (posedge i_clk) begin
if (i_rst) begin
mult_out_if.val <= 0;
end else begin
val <= {val, mult_dat_val};
end
end
end
// Modulo p reducer (shared with arbitrator)
// Modulo n reducer (output from karatsuba multiplier)
barret_mod #(
.IN_BITS ( 512 ),
.OUT_BITS ( 256 ),
.P ( secp256k1_pkg::n )
)
barret_mod (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_dat ( in_if.dat ),
.i_val ( in_if.val ),
.o_rdy ( in_if.rdy ),
.o_dat ( out_if.dat ),
.o_val ( out_if.val ),
.i_rdy ( out_if.rdy )
bin_inv #(
.BITS ( 256 )
)
bin_inv (
.i_clk ( i_clk ),
.i_rst ( i_rst) ,
.i_dat ( bin_inv_in_if.dat ),
.i_p ( inv_p ),
.i_val ( bin_inv_in_if.val ),
.o_rdy ( bin_inv_in_if.rdy ),
.o_dat ( bin_inv_out_if.dat ),
.o_val ( bin_inv_out_if.val ),
.i_rdy ( bin_inv_out_if.rdy )
);
// 256 bit Karatsuba_ofman multiplier (shared with arbitrator)
// Point double module or Point multiply module
localparam RESOURCE_SHARE = "YES";
localparam ARB_BIT = 6;
// Shared multiplier with cmd to control modulo p or modulo n
secp256k1_mult_mod #(
.CTL_BITS ( 8 )
)
secp256k1_mult_mod (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_dat_a ( mult_in_if[3].dat[0 +: 256] ),
.i_dat_b ( mult_in_if[3].dat[256 +: 256] ),
.i_val ( mult_in_if[3].val ),
.i_err ( mult_in_if[3].err ),
.i_ctl ( mult_in_if[3].ctl ),
.i_cmd ( mult_in_if[3].ctl[ARB_BIT +: 2] == 2 ? mult_in_if[3].ctl[0] : 1'd0 ),
.o_rdy ( mult_in_if[3].rdy ),
.o_dat ( mult_out_if[3].dat ),
.i_rdy ( mult_out_if[3].rdy ),
.o_val ( mult_out_if[3].val ),
.o_ctl ( mult_out_if[3].ctl ),
.o_err ( mult_out_if[3].err )
);
secp256k1_mod #(
.USE_MULT ( 0 ),
.CTL_BITS ( 8 )
)
secp256k1_mod (
.i_clk( i_clk ),
.i_rst( i_rst ),
.i_dat( mod_in_if[2].dat ),
.i_val( mod_in_if[2].val ),
.i_err( mod_in_if[2].err ),
.i_ctl( mod_in_if[2].ctl ),
.o_rdy( mod_in_if[2].rdy ),
.o_dat( mod_out_if[2].dat ),
.o_ctl( mod_out_if[2].ctl ),
.o_err( mod_out_if[2].err ),
.i_rdy( mod_out_if[2].rdy ),
.o_val( mod_out_if[2].val )
);
packet_arb # (
.DAT_BYTS ( 512/8 ),
.CTL_BITS ( 8 ),
.NUM_IN ( 3 ),
.OVR_WRT_BIT ( ARB_BIT ),
.PIPELINE ( 1 )
)
packet_arb_mult (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_axi ( mult_in_if[2:0] ),
.o_axi ( mult_in_if[3] )
);
packet_arb # (
.DAT_BYTS ( 512/8 ),
.CTL_BITS ( 8 ),
.NUM_IN ( 2 ),
.OVR_WRT_BIT ( ARB_BIT ),
.PIPELINE ( 0 )
)
packet_arb_mod (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_axi ( mod_in_if[1:0] ),
.o_axi ( mod_in_if[2] )
);
always_comb begin
mod_out_if[0].copy_if_comb(mod_out_if[2].to_struct());
mod_out_if[1].copy_if_comb(mod_out_if[2].to_struct());
mod_out_if[0].ctl = mod_out_if[2].ctl;
mod_out_if[1].ctl = mod_out_if[2].ctl;
mod_out_if[0].ctl[ARB_BIT] = 0;
mod_out_if[1].ctl[ARB_BIT] = 0;
mod_out_if[1].val = mod_out_if[2].val && mod_out_if[2].ctl[ARB_BIT] == 1;
mod_out_if[0].val = mod_out_if[2].val && mod_out_if[2].ctl[ARB_BIT] == 0;
mod_out_if[2].rdy = mod_out_if[2].ctl[ARB_BIT] == 0 ? mod_out_if[0].rdy : mod_out_if[1].rdy;
mod_out_if[2].sop = 1;
mod_out_if[2].eop = 1;
mod_out_if[2].mod = 0;
end
always_comb begin
mult_out_if[0].copy_if_comb(mult_out_if[3].to_struct());
mult_out_if[1].copy_if_comb(mult_out_if[3].to_struct());
mult_out_if[2].copy_if_comb(mult_out_if[3].to_struct());
mult_out_if[0].ctl = mult_out_if[3].ctl;
mult_out_if[1].ctl = mult_out_if[3].ctl;
mult_out_if[2].ctl = mult_out_if[3].ctl;
mult_out_if[0].ctl[ARB_BIT +: 2] = 0;
mult_out_if[1].ctl[ARB_BIT +: 2] = 0;
mult_out_if[2].ctl[ARB_BIT +: 2] = 0;
mult_out_if[1].val = mult_out_if[3].val && mult_out_if[3].ctl[ARB_BIT +: 2] == 1;
mult_out_if[0].val = mult_out_if[3].val && mult_out_if[3].ctl[ARB_BIT +: 2] == 0;
mult_out_if[2].val = mult_out_if[3].val && mult_out_if[3].ctl[ARB_BIT +: 2] == 2;
if (mult_out_if[3].ctl[ARB_BIT +: 2] == 0)
mult_out_if[3].rdy = mult_out_if[0].rdy;
else if (mult_out_if[3].ctl[ARB_BIT +: 2] == 1)
mult_out_if[3].rdy = mult_out_if[1].rdy;
else
mult_out_if[3].rdy = mult_out_if[2].rdy;
mult_out_if[3].sop = 1;
mult_out_if[3].eop = 1;
mult_out_if[3].mod = 0;
end
secp256k1_point_mult #(
.RESOURCE_SHARE ( RESOURCE_SHARE )
)
secp256k1_point_mult0 (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_p ( pt_mult0_in_p ),
.i_k ( pt_mult0_in_k ),
.i_val ( pt_mult0_in_val ),
.o_rdy ( pt_mult0_in_rdy ),
.o_p ( pt_mult0_out_p ),
.i_rdy ( pt_mult0_out_rdy ),
.o_val ( pt_mult0_out_val ),
.o_err ( pt_mult0_out_err ),
.o_mult_if ( mult_in_if[0] ),
.i_mult_if ( mult_out_if[0] ),
.o_mod_if ( mod_in_if[0] ),
.i_mod_if ( mod_out_if[0] ),
.i_p2 ( pt_mult0_in_p2 ),
.i_p2_val ( pt_mult0_in_p2_val )
);
secp256k1_point_mult #(
.RESOURCE_SHARE ( RESOURCE_SHARE )
)
secp256k1_point_mult1 (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_p ( pt_mult1_in_p ),
.i_k ( pt_mult1_in_k ),
.i_val ( pt_mult1_in_val ),
.o_rdy ( pt_mult1_in_rdy ),
.o_p ( pt_mult1_out_p ),
.i_rdy ( pt_mult1_out_rdy ),
.o_val ( pt_mult1_out_val ),
.o_err ( pt_mult1_out_err ),
.o_mult_if ( mult_in_if[1] ),
.i_mult_if ( mult_out_if[1] ),
.o_mod_if ( mod_in_if[1] ),
.i_mod_if ( mod_out_if[1] ),
.i_p2 ( '0 ),
.i_p2_val ( 1'b0 )
);
// Task to help build reply messages. Assume no message will be more than MAX_BYT_MSG bytes
task send_message(input logic [$clog2(MAX_BYT_MSG)-1:0] msg_size);
if (~if_cmd_tx.val || (if_cmd_tx.rdy && if_cmd_tx.val)) begin
if_cmd_tx.dat <= msg;
if_cmd_tx.val <= 1;
if_cmd_tx.sop <= cnt == msg_size;
if_cmd_tx.eop <= (cnt <= DAT_BYTS);
if_cmd_tx.mod <= cnt < DAT_BYTS ? cnt : 0;
cnt <= (cnt > DAT_BYTS) ? (cnt - DAT_BYTS) : 0;
msg <= msg >> DAT_BITS;
if (cnt == 0) begin
if_cmd_tx.val <= 0;
secp256k1_state <= IDLE;
end
end
endtask
endmodule

View File

@ -23,9 +23,13 @@ package zcash_fpga_pkg;
import equihash_pkg::cblockheader_sol_t;
import equihash_pkg::N;
import equihash_pkg::K;
import secp256k1_pkg::secp256k1_ver_t;
parameter FPGA_VERSION = 32'h01_00_00; //v1.0.0
localparam [63:0] FPGA_CMD_CAP = {{62'd0},
parameter bit ENB_VERIFY_SECP256K1_SIG = 1;
localparam [63:0] FPGA_CMD_CAP = {{61'd0},
ENB_VERIFY_SECP256K1_SIG,
(equihash_pkg::N == 144 && equihash_pkg::K == 5), // N = 144, K = 5 for VERIFY_EQUIHASH command
(equihash_pkg::N == 200 && equihash_pkg::K == 9)}; // N = 200, K = 9 for VERIFY_EQUIHASH command
@ -39,10 +43,11 @@ package zcash_fpga_pkg;
VERIFY_SECP256K1_SIG = 'h0000_01_01,
// Replies from the FPGA
RESET_FPGA_RPL = 'h80_00_00_00,
FPGA_STATUS_RPL = 'h80_00_00_01,
FPGA_IGNORE_RPL = 'h80_00_00_02,
VERIFY_EQUIHASH_RPL = 'h80_00_01_00
RESET_FPGA_RPL = 'h80_00_00_00,
FPGA_STATUS_RPL = 'h80_00_00_01,
FPGA_IGNORE_RPL = 'h80_00_00_02,
VERIFY_EQUIHASH_RPL = 'h80_00_01_00,
VERIFY_SECP256K1_SIG_RPL = 'h80_00_01_01
} command_t;
// Data sent to the FPGA must start with a header aligned to
@ -89,6 +94,22 @@ package zcash_fpga_pkg;
header_t hdr;
} verify_equihash_rpl_t;
typedef struct packed {
logic [255:0] Qy;
logic [255:0] Qx;
logic [255:0] hash;
logic [255:0] s;
logic [255:0] r;
logic [63:0] index;
header_t hdr;
} verify_secp256k1_sig_t;
typedef struct packed {
secp256k1_ver_t bm;
logic [63:0] index;
header_t hdr;
} verify_secp256k1_sig_rpl_t;
// We have a function for building each type of reply from the FPGA
function fpga_reset_rpl_t get_fpga_reset_rpl();
get_fpga_reset_rpl.hdr = '{cmd:RESET_FPGA_RPL, len:$bits(fpga_reset_rpl_t)/8};
@ -108,11 +129,17 @@ package zcash_fpga_pkg;
get_fpga_status_rpl.fpga_state = fpga_state;
endfunction
function verify_equihash_rpl_t get_verify_equihash_rpl(input equihash_bm_t mask, logic [63:0] equihash_index);
function verify_equihash_rpl_t get_verify_equihash_rpl(input equihash_bm_t mask, logic [63:0] index);
get_verify_equihash_rpl.hdr = '{cmd:VERIFY_EQUIHASH_RPL, len:$bits(verify_equihash_rpl_t)/8};
get_verify_equihash_rpl.index = equihash_index;
get_verify_equihash_rpl.index = index;
get_verify_equihash_rpl.bm = mask;
endfunction
function verify_secp256k1_sig_rpl_t verify_secp256k1_sig_rpl(input secp256k1_ver_t mask, logic [63:0] index);
verify_secp256k1_sig_rpl.hdr = '{cmd:VERIFY_SECP256K1_SIG_RPL, len:$bits(verify_secp256k1_sig_rpl_t)/8};
verify_secp256k1_sig_rpl.index = index;
verify_secp256k1_sig_rpl.bm = mask;
endfunction
endpackage

View File

@ -24,7 +24,7 @@ localparam CLK_PERIOD = 100;
logic clk, rst;
if_axi_stream #(.DAT_BYTS(512/8)) in_if(clk);
if_axi_stream #(.DAT_BYTS(512/8), .CTL_BITS(1)) in_if(clk);
if_axi_stream #(.DAT_BYTS(256/8)) out_if(clk);
initial begin
@ -52,6 +52,7 @@ always_ff @ (posedge clk)
secp256k1_mult_mod secp256k1_mult_mod (
.i_clk( clk ),
.i_rst( rst ),
.i_cmd( in_if.ctl ),
.i_dat_a( in_if.dat[0 +: 256] ),
.i_dat_b( in_if.dat[256 +: 256] ),
.i_val( in_if.val ),
@ -69,18 +70,19 @@ begin
logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, get_dat;
logic [255:0] in_a, in_b;
integer i, max;
logic type_ctl;
$display("Running test_loop...");
i = 0;
max = 10000;
while (i < max) begin
in_a = random_vector(256/8) % p_eq;
in_b = random_vector(256/8) % p_eq;
expected = (in_a * in_b) % p_eq;
type_ctl = $random;
in_a = random_vector(256/8) % (type_ctl == 0 ? p_eq : secp256k1_pkg::n);
in_b = random_vector(256/8) % (type_ctl== 0 ? p_eq : secp256k1_pkg::n);
expected = (in_a * in_b) % (type_ctl == 0 ? p_eq : secp256k1_pkg::n);
fork
in_if.put_stream({in_b, in_a}, 512/8);
in_if.put_stream({in_b, in_a}, 512/8, type_ctl);
out_if.get_stream(get_dat, get_len);
join
@ -93,11 +95,58 @@ begin
end
endtask;
task test_pipeline();
begin
logic type_cmd [10];
logic [255:0] in_a [10];
logic [255:0] in_b [10];
logic [511:0] expected [10];
integer max = 10;
$display("Running test_pipeline...");
for(int i = 0; i < 10; i++) begin
type_cmd[i] = $random;
in_a[i] = random_vector(256/8) % (type_cmd[i] == 0 ? p_eq : secp256k1_pkg::n);
in_b[i] = random_vector(256/8) % (type_cmd[i]== 0 ? p_eq : secp256k1_pkg::n);
expected[i] = (in_a[i] * in_b[i]) % (type_cmd[i] == 0 ? p_eq : secp256k1_pkg::n);
end
fork
begin
for(int i = 0; i < max; i++) begin
while (!in_if.rdy ) @(posedge in_if.i_clk);
in_if.sop = 1;
in_if.eop = 1;
in_if.ctl = type_cmd[i];
in_if.dat = {in_a[i], in_b[i]};
in_if.val = 1;
@(posedge in_if.i_clk);
while (!(in_if.rdy && in_if.val)) @(posedge in_if.i_clk);
end
in_if.val = 0;
end
begin
integer signed get_len;
logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat;
for(int i = 0; i < max; i++) begin
out_if.get_stream(get_dat, get_len);
common_pkg::compare_and_print(get_dat, expected[i]);
$display("test_pipeline PASSED loop %d/%d", i, max);
end
end
join
$display("test_pipeline PASSED");
end
endtask;
initial begin
out_if.rdy = 0;
in_if.ctl = 0;
in_if.err = 0;
in_if.val = 0;
#(40*CLK_PERIOD);
test_pipeline();
test_loop();
#1us $finish();

View File

@ -93,6 +93,7 @@ secp256k1_mult_mod (
.i_val ( mult_in_if.val ),
.i_err ( mult_in_if.err ),
.i_ctl ( mult_in_if.ctl ),
.i_cmd ( 1'd0 ),
.o_rdy ( mult_in_if.rdy ),
.o_dat ( mult_out_if.dat ),
.i_rdy ( mult_out_if.rdy ),

View File

@ -27,6 +27,12 @@ logic clk, rst;
if_axi_stream #(.DAT_BYTS(256*3/8)) in_if(clk);
if_axi_stream #(.DAT_BYTS(256*3/8)) out_if(clk);
if_axi_stream #(.DAT_BYTS(256*2/8), .CTL_BITS(8)) mult_in_if(clk);
if_axi_stream #(.DAT_BYTS(256/8), .CTL_BITS(8)) mult_out_if(clk);
if_axi_stream #(.DAT_BYTS(256*2/8), .CTL_BITS(8)) mod_in_if(clk);
if_axi_stream #(.DAT_BYTS(256/8), .CTL_BITS(8)) mod_out_if(clk);
jb_point_t in_p, out_p;
logic [255:0] k_in;
@ -59,8 +65,19 @@ always_ff @ (posedge clk)
$error(1, "%m %t ERROR: output .err asserted", $time);
end
always_comb begin
mult_out_if.sop = 1;
mult_out_if.eop = 1;
mult_out_if.mod = 0;
mod_out_if.sop = 1;
mod_out_if.eop = 1;
mod_out_if.mod = 0;
end
secp256k1_point_mult secp256k1_point_mult (
secp256k1_point_mult #(
.RESOURCE_SHARE ("YES")
)
secp256k1_point_mult (
.i_clk ( clk ),
.i_rst ( rst ),
.i_p ( in_if.dat ),
@ -70,7 +87,50 @@ secp256k1_point_mult secp256k1_point_mult (
.o_p ( out_p ),
.i_rdy ( out_if.rdy ),
.o_val ( out_if.val ),
.o_err ( out_if.err )
.o_err ( out_if.err ),
.o_mult_if ( mult_in_if ),
.i_mult_if ( mult_out_if ),
.o_mod_if ( mod_in_if ),
.i_mod_if ( mod_out_if )
);
secp256k1_mult_mod #(
.CTL_BITS ( 8 )
)
secp256k1_mult_mod (
.i_clk ( clk ),
.i_rst ( rst ),
.i_dat_a ( mult_in_if.dat[0 +: 256] ),
.i_dat_b ( mult_in_if.dat[256 +: 256] ),
.i_val ( mult_in_if.val ),
.i_err ( mult_in_if.err ),
.i_ctl ( mult_in_if.ctl ),
.i_cmd (1'd0 ),
.o_rdy ( mult_in_if.rdy ),
.o_dat ( mult_out_if.dat ),
.i_rdy ( mult_out_if.rdy ),
.o_val ( mult_out_if.val ),
.o_ctl ( mult_out_if.ctl ),
.o_err ( mult_out_if.err )
);
secp256k1_mod #(
.USE_MULT ( 0 ),
.CTL_BITS ( 8 )
)
secp256k1_mod (
.i_clk( clk ),
.i_rst( rst ),
.i_dat( mod_in_if.dat ),
.i_val( mod_in_if.val ),
.i_err( mod_in_if.err ),
.i_ctl( mod_in_if.ctl ),
.o_rdy( mod_in_if.rdy ),
.o_dat( mod_out_if.dat ),
.o_ctl( mod_out_if.ctl ),
.o_err( mod_out_if.err ),
.i_rdy( mod_out_if.rdy ),
.o_val( mod_out_if.val )
);
// Test a point

View File

@ -0,0 +1,112 @@
/*
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
`timescale 1ps/1ps
module secp256k1_top_tb ();
import common_pkg::*;
import secp256k1_pkg::*;
import zcash_fpga_pkg::*;
localparam CLK_PERIOD = 1000;
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;
repeat(2) #(20*CLK_PERIOD) rst = ~rst;
end
initial begin
clk = 0;
forever #(CLK_PERIOD/2) clk = ~clk;
end
// Check for errors
always_ff @ (posedge clk)
if (out_if.val && out_if.err) begin
out_if.rdy = 1;
$error(1, "%m %t ERROR: output .err asserted", $time);
end
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 )
);
// Test a point
task test(input integer k, input logic [255:0] hash, r, s, Qx, Qy);
begin
integer signed get_len;
logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, get_dat;
integer start_time, finish_time;
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;
verify_secp256k1_sig.index = k;
verify_secp256k1_sig.hash = hash;
verify_secp256k1_sig.r = r;
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);
$display("test #%d PASSED in %d clocks", integer'(k), (finish_time-start_time)/CLK_PERIOD);
end
endtask;
initial begin
out_if.rdy = 0;
in_if.val = 0;
mm_if.reset_source();
#(40*CLK_PERIOD);
test(1, 256'h4c7dbc46486ad9569442d69b558db99a2612c4f003e6631b593942f531e67fd4,
256'h808a2c66c5b90fa1477d7820fc57a8b7574cdcb8bd829bdfcf98aa9c41fde3b4,
256'h7d4a15dda75c683f002305c2d6ebeebf6c6590f48e128497f118f43250f9924f,
256'hdbe7be814625d52029f94f956147df9347b56e6b5f1cb70bf5d6069ecd8405dd,
256'h3feab712653c82df859affc1c287a5353cbe7ca59b83d6d55d97fc04f243c19f);
#1us $finish();
end
endmodule