Barret modulus block
This commit is contained in:
parent
5555a71810
commit
c558b391dd
|
@ -147,6 +147,28 @@ interface if_axi_stream # (
|
||||||
|
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
|
interface if_axi_mm # (
|
||||||
|
parameter D_BITS = 64,
|
||||||
|
parameter A_BITS = 8
|
||||||
|
)(
|
||||||
|
input i_clk
|
||||||
|
);
|
||||||
|
|
||||||
|
logic [A_BITS-1:0] raddr;
|
||||||
|
logic [A_BITS-1:0] waddr;
|
||||||
|
logic [D_BITS-1:0] rdat;
|
||||||
|
logic [D_BITS-1:0] wdat;
|
||||||
|
logic rval;
|
||||||
|
logic wval;
|
||||||
|
logic rrdy;
|
||||||
|
logic wrdy;
|
||||||
|
|
||||||
|
modport sink (input raddr, waddr, wdat, wval, rrdy, i_clk, output rdat, rval, wrdy);
|
||||||
|
modport source (input rdat, rval, wrdy , i_clk, output raddr, waddr, wdat, wval, rrdy);
|
||||||
|
|
||||||
|
|
||||||
|
endinterface
|
||||||
|
|
||||||
interface if_ram # (
|
interface if_ram # (
|
||||||
parameter RAM_WIDTH = 32,
|
parameter RAM_WIDTH = 32,
|
||||||
parameter RAM_DEPTH = 128
|
parameter RAM_DEPTH = 128
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
Calculates a mod n, using barret reduction.
|
||||||
|
|
||||||
|
We provide an external interface to be hooked up to a multiplier.
|
||||||
|
|
||||||
|
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 barret_mod #(
|
||||||
|
parameter OUT_BITS = 256,
|
||||||
|
parameter IN_BITS = 512,
|
||||||
|
parameter [OUT_BITS-1:0] P = 256'hFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_BAAEDCE6_AF48A03B_BFD25E8C_D0364141,
|
||||||
|
parameter K = $clog2(P) + 1
|
||||||
|
)(
|
||||||
|
input i_clk,
|
||||||
|
input i_rst,
|
||||||
|
input [IN_BITS-1:0] i_dat,
|
||||||
|
input i_val,
|
||||||
|
output logic o_rdy,
|
||||||
|
output logic [OUT_BITS-1:0] o_dat,
|
||||||
|
output logic o_val,
|
||||||
|
input i_rdy,
|
||||||
|
|
||||||
|
// Multiplier interface
|
||||||
|
if_axi_stream.source o_mult,
|
||||||
|
if_axi_stream.sink i_mult_res
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
localparam MAX_IN_BITS = 2*K;
|
||||||
|
localparam [MAX_IN_BITS:0] U = (1 << (2*K)) / P;
|
||||||
|
localparam [MAX_IN_BITS-1:0] P_ = P;
|
||||||
|
logic [MAX_IN_BITS-1:0] c1, c2, c3, c4, c2_;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {IDLE, S0, S1, S2, FINISHED, WAIT_MULT} state_t;
|
||||||
|
state_t state, prev_state;
|
||||||
|
|
||||||
|
always_ff @ (posedge i_clk) begin
|
||||||
|
if (i_rst) begin
|
||||||
|
o_rdy <= 0;
|
||||||
|
o_dat <= 0;
|
||||||
|
o_val <= 0;
|
||||||
|
state <= IDLE;
|
||||||
|
prev_state <= IDLE;
|
||||||
|
c1 <= 0;
|
||||||
|
c2 <= 0;
|
||||||
|
c3 <= 0;
|
||||||
|
c4 <= 0;
|
||||||
|
o_mult.reset_source();
|
||||||
|
i_mult_res.rdy <= 1;
|
||||||
|
end else begin
|
||||||
|
i_mult_res.rdy <= 1;
|
||||||
|
case (state)
|
||||||
|
{IDLE}: begin
|
||||||
|
o_rdy <= 1;
|
||||||
|
o_val <= 0;
|
||||||
|
c2 <= (i_dat >> (K-1))*U; // Using multiplier interface TODO
|
||||||
|
c4 <= i_dat;
|
||||||
|
if (i_val && o_rdy) begin
|
||||||
|
o_rdy <= 0;
|
||||||
|
state <= S0;// WAIT_MULT;
|
||||||
|
o_mult.val <= 1;
|
||||||
|
o_mult.dat[0 +: OUT_BITS + 8] <= i_dat >> (K-1);
|
||||||
|
o_mult.dat[OUT_BITS + 8 +: OUT_BITS + 8] <= U;
|
||||||
|
prev_state <= S0;
|
||||||
|
c2_ <= (i_dat >> (K-1))*U; // Using multiplier interface
|
||||||
|
end
|
||||||
|
end
|
||||||
|
{S0}: begin
|
||||||
|
c3 <= c2 >> (K + 1);
|
||||||
|
state <= S1;
|
||||||
|
end
|
||||||
|
{S1}: begin
|
||||||
|
c4 <= c4 - c3*P; // Using multiplier interface TODO
|
||||||
|
o_mult.val <= 1;
|
||||||
|
o_mult.dat[0 +: OUT_BITS] <= c3;
|
||||||
|
o_mult.dat[OUT_BITS +: OUT_BITS] <= P;
|
||||||
|
state <= S2; //WAIT_MULT;
|
||||||
|
prev_state <= S2;
|
||||||
|
end
|
||||||
|
{S2}: begin
|
||||||
|
if (c4 >= P_) begin
|
||||||
|
c4 <= c4 - P_;
|
||||||
|
end else begin
|
||||||
|
state <= FINISHED;
|
||||||
|
o_dat <= c4;
|
||||||
|
o_val <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
{FINISHED}: begin
|
||||||
|
if (o_val && i_rdy) begin
|
||||||
|
o_val <= 0;
|
||||||
|
state <= IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// In this state we are waiting for a multiply to be finished
|
||||||
|
{WAIT_MULT}: begin
|
||||||
|
if (o_mult.val && o_mult.rdy) o_mult.val <= 0;
|
||||||
|
if (i_mult_res.rdy && i_mult_res.val) begin
|
||||||
|
state <= prev_state;
|
||||||
|
case(prev_state)
|
||||||
|
S0: c2 <= i_mult_res.dat;
|
||||||
|
S2: c4 <= c4 - i_mult_res.dat;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
initial assert (IN_BITS <= MAX_IN_BITS) else $fatal(1, "%m ERROR: IN_BITS[%d] > MAX_IN_BITS[%d] in barret_mod", IN_BITS, MAX_IN_BITS);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
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 barret_mod_tb ();
|
||||||
|
import common_pkg::*;
|
||||||
|
import secp256k1_pkg::*;
|
||||||
|
|
||||||
|
localparam CLK_PERIOD = 100;
|
||||||
|
|
||||||
|
logic clk, rst;
|
||||||
|
|
||||||
|
localparam IN_BITS = 512;
|
||||||
|
localparam OUT_BITS = 256;
|
||||||
|
localparam [OUT_BITS-1:0] P = secp256k1_pkg::n;
|
||||||
|
localparam USE_MULT = 0;
|
||||||
|
|
||||||
|
if_axi_stream #(.DAT_BYTS(IN_BITS/8)) in_if(clk);
|
||||||
|
if_axi_stream #(.DAT_BYTS(OUT_BITS/8)) out_if(clk);
|
||||||
|
if_axi_stream #(.DAT_BYTS(2*((OUT_BITS+16))/8)) mult_in_if(clk);
|
||||||
|
if_axi_stream #(.DAT_BYTS((OUT_BITS+8)/8)) mult_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
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (USE_MULT == 0) begin: MULT_GEN
|
||||||
|
always_ff @ (posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
mult_in_if.rdy <= 0;
|
||||||
|
mult_out_if.reset_source();
|
||||||
|
end else begin
|
||||||
|
mult_in_if.rdy <= 1;
|
||||||
|
if (mult_in_if.rdy && mult_in_if.val) begin
|
||||||
|
mult_out_if.dat <= mult_in_if.dat[0 +: OUT_BITS] * mult_in_if.dat[OUT_BITS +: OUT_BITS];
|
||||||
|
mult_out_if.val <= 1;
|
||||||
|
end
|
||||||
|
if (mult_out_if.val && mult_out_if.rdy) mult_out_if.val <= 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
barret_mod #(
|
||||||
|
.IN_BITS ( IN_BITS ),
|
||||||
|
.OUT_BITS ( OUT_BITS ),
|
||||||
|
.P ( P )
|
||||||
|
)
|
||||||
|
barret_mod (
|
||||||
|
.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 ),
|
||||||
|
.o_val ( out_if.val ),
|
||||||
|
.i_rdy ( out_if.rdy ),
|
||||||
|
|
||||||
|
.o_mult ( mult_in_if ),
|
||||||
|
.i_mult_res ( mult_out_if )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
task test_loop();
|
||||||
|
begin
|
||||||
|
integer signed get_len;
|
||||||
|
logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, get_dat;
|
||||||
|
logic [512*8-1:0] in;
|
||||||
|
integer i, max;
|
||||||
|
|
||||||
|
$display("Running test_loop...");
|
||||||
|
i = 0;
|
||||||
|
max = 10000;
|
||||||
|
|
||||||
|
while (i < max) begin
|
||||||
|
in = random_vector(IN_BITS/8);
|
||||||
|
expected = (in % P);
|
||||||
|
|
||||||
|
fork
|
||||||
|
in_if.put_stream(in, IN_BITS/8);
|
||||||
|
out_if.get_stream(get_dat, get_len);
|
||||||
|
join
|
||||||
|
common_pkg::compare_and_print(get_dat, expected);
|
||||||
|
$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
|
Loading…
Reference in New Issue