Top level file changes
This commit is contained in:
parent
58fd5658c5
commit
65e3723d21
|
@ -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
|
||||
|
||||
|
|
|
@ -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 )
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue