Binary inversion module and testbench
This commit is contained in:
parent
b94b2a7c5d
commit
5555a71810
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Calculates inversion mod P using binary gcd algorithm.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
module bin_inv #(
|
||||
parameter BITS,
|
||||
parameter [BITS-1:0] P
|
||||
)(
|
||||
input i_clk,
|
||||
input i_rst,
|
||||
input [BITS-1:0] i_dat,
|
||||
input i_val,
|
||||
output logic o_rdy,
|
||||
output logic [BITS-1:0] o_dat,
|
||||
output logic o_val,
|
||||
input i_rdy
|
||||
);
|
||||
|
||||
logic [BITS:0] x1, x2, u, v;
|
||||
|
||||
enum {IDLE,
|
||||
U_STATE,
|
||||
V_STATE,
|
||||
UPDATE,
|
||||
FINISHED} state;
|
||||
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
x1 <= 0;
|
||||
x2 <= 0;
|
||||
u <= 0;
|
||||
v <= 0;
|
||||
o_rdy <= 0;
|
||||
o_val <= 0;
|
||||
o_dat <= 0;
|
||||
state <= IDLE;
|
||||
end else begin
|
||||
o_rdy <= 0;
|
||||
case(state)
|
||||
IDLE: begin
|
||||
o_rdy <= 1;
|
||||
o_val <= 0;
|
||||
if (o_rdy && i_val) begin
|
||||
o_rdy <= 0;
|
||||
u <= i_dat;
|
||||
v <= P;
|
||||
x1 <= 1;
|
||||
x2 <= 0;
|
||||
state <= U_STATE;
|
||||
end
|
||||
end
|
||||
U_STATE: begin
|
||||
if (u % 2 == 1) begin
|
||||
state <= V_STATE;
|
||||
end else begin
|
||||
u <= u/2;
|
||||
if (x1 % 2 == 0) begin
|
||||
x1 <= x1/2;
|
||||
end else begin
|
||||
x1 <= (x1 + P)/2;
|
||||
end
|
||||
if ((u/2) % 2 == 1) begin
|
||||
state <= V_STATE;
|
||||
end
|
||||
end
|
||||
end
|
||||
V_STATE: begin
|
||||
if (v % 2 == 1) begin
|
||||
state <= UPDATE;
|
||||
end else begin
|
||||
v <= v/2;
|
||||
if (x2 % 2 == 0) begin
|
||||
x2 <= x2/2;
|
||||
end else begin
|
||||
x2 <= (x2 + P)/2;
|
||||
end
|
||||
if ((v/2 % 2) == 1) begin
|
||||
state <= UPDATE;
|
||||
end
|
||||
end
|
||||
end
|
||||
UPDATE: begin
|
||||
state <= U_STATE;
|
||||
if (u >= v) begin
|
||||
u <= u - v;
|
||||
x1 <= x1 + (x1 >= x2 ? 0 : P) - x2;
|
||||
if (u - v == 1 || v == 1) begin
|
||||
state <= FINISHED;
|
||||
end
|
||||
end else begin
|
||||
v <= v - u;
|
||||
x2 <= x2 + (x2 >= x1 ? 0 : P) - x1;
|
||||
if (v - u == 1 || u == 1) begin
|
||||
state <= FINISHED;
|
||||
end
|
||||
end
|
||||
end
|
||||
FINISHED: begin
|
||||
if (~o_val || (o_val && i_rdy)) begin
|
||||
o_val <= 1;
|
||||
o_dat <= (u == 1) ? x1 : x2;
|
||||
if (o_val && i_rdy) begin
|
||||
o_val <= 0;
|
||||
o_rdy <= 1;
|
||||
state <= IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
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 bin_inv_tb ();
|
||||
import common_pkg::*;
|
||||
import secp256k1_pkg::*;
|
||||
|
||||
localparam CLK_PERIOD = 100;
|
||||
|
||||
logic clk, rst;
|
||||
|
||||
if_axi_stream #(.DAT_BYTS(256/8)) in_if(clk);
|
||||
if_axi_stream #(.DAT_BYTS(256/8)) out_if(clk);
|
||||
|
||||
initial begin
|
||||
rst = 0;
|
||||
repeat(2) #(20*CLK_PERIOD) rst = ~rst;
|
||||
end
|
||||
|
||||
initial begin
|
||||
clk = 0;
|
||||
forever #CLK_PERIOD clk = ~clk;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
out_if.sop = 1;
|
||||
out_if.eop = 1;
|
||||
out_if.ctl = 0;
|
||||
out_if.mod = 0;
|
||||
end
|
||||
|
||||
// Check for errors
|
||||
always_ff @ (posedge clk)
|
||||
if (out_if.val && out_if.err)
|
||||
$error(1, "%m %t ERROR: output .err asserted", $time);
|
||||
|
||||
bin_inv #(
|
||||
.P ( secp256k1_pkg::p_eq ),
|
||||
.BITS ( 256 )
|
||||
)
|
||||
bin_inv (
|
||||
.i_clk( clk ),
|
||||
.i_rst( rst ),
|
||||
.i_dat( in_if.dat ),
|
||||
.i_val( in_if.val ),
|
||||
.o_rdy( in_if.rdy ),
|
||||
.o_dat( out_if.dat ),
|
||||
.i_rdy( out_if.rdy ),
|
||||
.o_val( out_if.val )
|
||||
);
|
||||
|
||||
task test_loop();
|
||||
begin
|
||||
integer signed get_len;
|
||||
logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, get_dat;
|
||||
logic [255:0] in;
|
||||
integer i, max;
|
||||
|
||||
$display("Running test_loop...");
|
||||
i = 0;
|
||||
max = 10000;
|
||||
|
||||
while (i < max) begin
|
||||
in = random_vector(256/8) % p_eq;
|
||||
|
||||
fork
|
||||
in_if.put_stream(in, 256/8);
|
||||
out_if.get_stream(get_dat, get_len);
|
||||
join
|
||||
|
||||
assert(get_dat < p_eq) else $fatal(1, "%m %t ERROR: test_loop value was >= p:\n%d", $time, get_dat);
|
||||
assert((get_dat*in) % p_eq == 1) else $fatal(1, "%m %t ERROR: test_loop (get_dat*in) % p_eq != 1", $time);
|
||||
|
||||
$display("test_loop PASSED loop %d/%d", i, max);
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
$display("test_loop PASSED");
|
||||
end
|
||||
endtask;
|
||||
|
||||
initial begin
|
||||
out_if.rdy = 0;
|
||||
in_if.val = 0;
|
||||
#(40*CLK_PERIOD);
|
||||
|
||||
test_loop();
|
||||
|
||||
#1us $finish();
|
||||
end
|
||||
endmodule
|
|
@ -42,7 +42,7 @@ module secp256k1_mult_mod (
|
|||
import secp256k1_pkg::*;
|
||||
import common_pkg::*;
|
||||
|
||||
localparam KARATSUBA_LEVEL = 3;
|
||||
localparam KARATSUBA_LEVEL = 2;
|
||||
if_axi_stream #(.DAT_BYTS(512/8)) int_if(i_clk);
|
||||
|
||||
always_comb o_rdy = int_if.rdy;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
module secp256k1_top ();
|
||||
module secp256k1_top (
|
||||
input i_clk,
|
||||
input i_rst,
|
||||
input i_val,
|
||||
output logic o_rdy,
|
||||
output logic o_val
|
||||
|
||||
|
||||
// inversion
|
||||
|
||||
// multiplication
|
||||
|
||||
// addition
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue