ECDSA—模乘模組

jerry_cat發表於2021-08-23

  如果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

  1. 初始化product,product=0;
  2. 對於i從0到t-1,重複執行

    2.1.  若bi=1,則product=product + a<<1;

  1. Product = product mod p;
  2. 返回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的大小有關。

 

相關文章