如果a,b屬於GF(P),則有乘法運算a*b=r (mod p),
其中r滿足0<r<p-1,即a*b除以p的餘數。該操作成為模p乘法。本模組輸入兩個數,完成兩個數的模乘運算。
訊號名 |
方向 |
位寬 |
埠定義 |
clk |
Input |
1 |
時鐘 |
reset |
Input |
1 |
復位 |
multip_en |
Input |
1 |
模乘使能訊號 |
a |
Input |
256 |
整數乘數a |
b |
Input |
256 |
整數乘數b |
product |
output |
256 |
模乘運算結果 |
done |
output |
1 |
模乘完成標識 |
演算法:模乘運算演算法
輸入:a,b∈ [0,n-1], multip_en
輸出:product, done
- 初始化product,product=0;
- 對於i從0到t-1,重複執行
2.1. 若bi=1,則product=product + a<<1;
- Product = product mod p;
- 返回product。
程式碼如下:
module mod_multiplier(
input clk, reset,
input [255:0] a,
input [255:0] b,
output reg [255:0] product,
output reg done
);
/* multiplication using bit shifting and adding */
parameter params_p=29;
//parameter params_p = 256'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; reg [510:0] a_in, count_in;
reg [510:0] b_in,c_in;
reg a_load, b_load, c_load, count_load;
wire [510:0] a_out, count_out;
wire [510:0] b_out, c_out; reg_256 #(511) a_reg(.clk(clk), .load(a_load), .data(a_in), .out(a_out));
reg_256 #(511) b_reg(.clk(clk), .load(b_load), .data(b_in), .out(b_out));
reg_256 #(511) c_reg(.clk(clk), .load(c_load), .data(c_in), .out(c_out));
reg_256 #(511) count(.clk(clk), .load(count_load), .data(count_in), .out(count_out)); reg [2:0] state, next_state;
parameter init = 3'd0;
parameter start = 3'd1;
parameter shift_AB = 3'd2;
parameter reduce_B = 3'd3;
parameter reduce_C = 3'd4;
parameter finish = 3'd5; always@(posedge clk) begin
if(reset)
state <= init;
else
state <= next_state;
end always@(*) begin
next_state = state;
case(state)
init:
next_state = start;
start:
next_state = shift_AB;
shift_AB: begin
if((b_out << 1) >= {255'b0,params_p})
next_state = reduce_B;
else
next_state = reduce_C;
end
reduce_B: begin
if(b_out >= {255'b0,params_p})
next_state = reduce_B;
else
next_state = reduce_C;
end
reduce_C: begin
if(count_out == 8'd254)
next_state = finish;
else
next_state = shift_AB;
end
finish:
next_state = finish;
default: ;
endcase
end always@(*) begin
count_in = count_out;
b_in = b_out;
c_in = c_out;
a_in = a_out; count_load = 1'b0;
a_load = 1'b0;
b_load = 1'b0;
c_load = 1'b0;
product = 256'b0;
done = 1'b0; case(state)
init: begin
done = 1'b0;
count_in = 8'b0;
a_in = a;
b_in = {2'b0, b};
c_in = 510'b0; count_load = 1'b1;
a_load = 1'b1;
b_load = 1'b1;
c_load = 1'b1;
end
start: begin
if(a[0] == 1)
c_in = b_out;
else
c_in = 510'b0;
c_load = 1'b1;
end
shift_AB: begin
a_in = a_out >> 1;
a_load = 1'b1;
b_load = 1'b1;
b_in = b_out << 1;
end
reduce_B: begin
b_load = 1'b1;
if(b_out >= {255'b0, params_p})
b_in = b_out - {255'b0,params_p};
else
b_in = b_out;
end
reduce_C: begin
c_load = 1'b1;
if(a_out[0] == 1'b1) begin
if((c_out + b_out) >= {255'b0, params_p})
c_in = (c_out + b_out) - {255'b0, params_p};
else
c_in = c_out + b_out;
end
else begin
if(c_out >= {255'b0, params_p})
c_in = c_out - params_p;
else
c_in = c_out;
end
count_in = count_out + 8'b01;
count_load = 1'b1;
end
finish: begin
if(c_out < params_p) begin
done = 1'b1;
product = c_out[255:0];
end
else begin
c_in = c_out - {255'b0,params_p};
c_load = 1'b1;
done = 1'b0;
end
end
default: ;
endcase
end endmodule
其中reg256.v模組為暫存模組,主要是暫時儲存一下temp reg。
程式碼如下:
module reg_256 #(parameter size = 256)
(
input clk, load,
input [size-1:0] data,
output reg [size-1:0] out
); always @ (posedge clk)
begin
if (load)
out <= data;
else
out <= out;
end endmodule
模擬採用一條簡單的曲線先驗證結果的正確性,再選用spec256k1曲線來測試模乘速率,
其引數如下所示,後面的模組都會採用這兩條曲線做模擬驗證。此次只需將parameter中的p進行修改即可切換曲線。
sepc256k1曲線引數
p = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F a = 0 b =7 G_x = 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 G_y = 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8 n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 h = 01
testbeach如下所示:
`timescale 1ns/1ns module mod_multiplier_tb(); reg clk, reset;
reg [255:0] a, b;
wire [255:0] product;
wire done; mod_multiplier mult0(
.clk(clk),
.reset(reset),
.a(a),
.b(b),
.product(product),
.done(done)
); always #5 clk = ~clk; initial begin
clk = 0; reset = 1'b1;
#6
reset = 1'b0;
a = 12;
b = 25; /*
a = 256'h09;
b = 256'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFE2F;
*/
/*#5200
$display("ad/p=%d",product);
#20
$stop();*/
end endmodule
P=29時:選用的測試資料點為(12,25),12*25=300 mod 29 = 10(mod 29),結果正確。
P=256‘hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F時,
選用測試點為:a = 256'h09; b = 256'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFE2F;
從時間上來看,運算速率看來跟數的大小無關,而是跟相對於p的大小有關。