aboutsummaryrefslogtreecommitdiff
path: root/bench
diff options
context:
space:
mode:
Diffstat (limited to 'bench')
-rw-r--r--bench/tb_ecdsa256_wrapper.v443
1 files changed, 443 insertions, 0 deletions
diff --git a/bench/tb_ecdsa256_wrapper.v b/bench/tb_ecdsa256_wrapper.v
new file mode 100644
index 0000000..2e11d83
--- /dev/null
+++ b/bench/tb_ecdsa256_wrapper.v
@@ -0,0 +1,443 @@
+//------------------------------------------------------------------------------
+//
+// tb_ecdsa256_wrapper.v
+// -----------------------------------------------------------------------------
+// Testbench for 256-bit curve base point scalar multiplier.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, 2018-2019, 2021 NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module tb_ecdsa256_wrapper;
+
+
+ //
+ // Test Vectors
+ //
+ `include "ecdsa256_test_vector_nsa.vh"
+ `include "ecdsa_test_vector_randomized.vh"
+
+
+ //
+ // Core Parameters
+ //
+ localparam WORD_COUNTER_WIDTH = 3;
+ localparam OPERAND_NUM_WORDS = 8;
+
+
+ //
+ // Register Offsets
+ //
+ localparam CORE_ADDR_NAME0 = 24'h000000;
+ localparam CORE_ADDR_NAME1 = 24'h000001;
+ localparam CORE_ADDR_VERSION = 24'h000002;
+ localparam CORE_ADDR_CONTROL = 24'h000008;
+ localparam CORE_ADDR_STATUS = 24'h000009;
+
+ localparam CORE_ADDR_BUF_K = 24'h000020;
+ localparam CORE_ADDR_BUF_X = 24'h000028;
+ localparam CORE_ADDR_BUF_Y = 24'h000030;
+
+ localparam CORE_CONTROL_BIT_NEXT = 32'h00000002;
+ localparam CORE_STATUS_BIT_VALID = 32'h00000002;
+
+
+ //
+ // STM32 Settings
+ //
+ localparam STM32_FMC_LATENCY = 6;
+
+
+ //
+ // P-256 Domain Parameters
+ //
+ localparam ECDSA_P256_N =
+ {32'hffffffff, 32'h00000000, 32'hffffffff, 32'hffffffff,
+ 32'hbce6faad, 32'ha7179e84, 32'hf3b9cac2, 32'hfc632551};
+
+ localparam ECDSA_P256_GX =
+ {32'h6b17d1f2, 32'he12c4247, 32'hf8bce6e5, 32'h63a440f2,
+ 32'h77037d81, 32'h2deb33a0, 32'hf4a13945, 32'hd898c296};
+
+ localparam ECDSA_P256_GY =
+ {32'h4fe342e2, 32'hfe1a7f9b, 32'h8ee7eb4a, 32'h7c0f9e16,
+ 32'h2bce3357, 32'h6b315ece, 32'hcbb64068, 32'h37bf51f5};
+
+ localparam ECDSA_P256_HX =
+ {32'h7cf27b18, 32'h8d034f7e, 32'h8a523803, 32'h04b51ac3,
+ 32'hc08969e2, 32'h77f21b35, 32'ha60b48fc, 32'h47669978};
+
+ localparam ECDSA_P256_HY =
+ {32'h07775510, 32'hdb8ed040, 32'h293d9ac6, 32'h9f7430db,
+ 32'hba7dade6, 32'h3ce98229, 32'h9e04b79d, 32'h227873d1};
+
+
+ //
+ // FMC Clock (50 MHz)
+ //
+ localparam FMC_CLOCK_PERIOD = 20.0;
+ localparam FMC_CLOCK_PERIOD_HALF = 0.5 * FMC_CLOCK_PERIOD;
+ localparam FMC_CLOCK_PERIOD_QUARTER = 0.5 * FMC_CLOCK_PERIOD_HALF;
+
+ reg fmc_clk = 1'b0;
+
+ initial forever #FMC_CLOCK_PERIOD_HALF fmc_clk = ~fmc_clk;
+
+
+ //
+ // Clock Manager
+ //
+ wire io_clk; // i/o clock
+ wire sys_clk; // system clock
+ wire sys_rst_n; // active-low reset
+
+ alpha_clkmgr clkmgr_inst
+ (
+ .fmc_clk (fmc_clk),
+
+ .io_clk (io_clk),
+ .sys_clk (sys_clk),
+ .sys_rst_n (sys_rst_n),
+ .core_clk ()
+ );
+
+
+ //
+ // FMC Arbiter - FPGA Side
+ //
+ wire [23: 0] sys_fmc_addr;
+ wire sys_fmc_wren;
+ wire sys_fmc_rden;
+ wire [31: 0] sys_fmc_dout;
+ wire [31: 0] sys_fmc_din;
+
+
+ //
+ // FMC Arbiter - STM32 Side
+ //
+ reg [23: 0] fmc_a = {24{1'bX}};
+ reg [31: 0] fmc_d_drive;
+ wire [31: 0] fmc_d_bidir;
+ reg fmc_ne1 = 1'b1;
+ reg fmc_noe = 1'b1;
+ reg fmc_nwe = 1'b1;
+ reg fmc_nl = 1'b1;
+ wire fmc_nwait_dummy;
+
+ assign fmc_d_bidir = fmc_noe ? fmc_d_drive : 32'hZZZZZZZZ;
+
+ fmc_arbiter #(.NUM_ADDR_BITS(24))
+ fmc_arbiter_inst
+ (
+ // fmc bus
+ .fmc_a (fmc_a),
+ .fmc_d (fmc_d_bidir),
+ .fmc_ne1 (fmc_ne1),
+ .fmc_nl (fmc_nl),
+ .fmc_nwe (fmc_nwe),
+ .fmc_noe (fmc_noe),
+ .fmc_nwait (fmc_nwait_dummy),
+
+ // system clock, i/o clock
+ .io_clk (io_clk),
+ .sys_clk (sys_clk),
+
+ // user bus
+ .sys_addr (sys_fmc_addr),
+ .sys_wr_en (sys_fmc_wren),
+ .sys_data_out (sys_fmc_dout),
+ .sys_rd_en (sys_fmc_rden),
+ .sys_data_in (sys_fmc_din)
+ );
+
+ ecdsa256_wrapper uut
+ (
+ .clk (sys_clk),
+ .reset_n (sys_rst_n),
+
+ .cs (sys_fmc_wren | sys_fmc_rden),
+ .we (sys_fmc_wren),
+
+ .address (sys_fmc_addr[5:0]),
+ .write_data (sys_fmc_dout),
+ .read_data (sys_fmc_din)
+ );
+
+
+ //
+ // Testbench Routine
+ //
+ reg ok = 1;
+
+ reg [31:0] core_name0;
+ reg [31:0] core_name1;
+ reg [31:0] core_version;
+
+ initial begin
+
+ /* wait for some time */
+ #4000;
+
+ /* sanity checks */
+ fmc_read(CORE_ADDR_NAME0, core_name0);
+ fmc_read(CORE_ADDR_NAME1, core_name1);
+ fmc_read(CORE_ADDR_VERSION, core_version);
+
+ $display("CORE_NAME0: %x", core_name0);
+ $display("CORE_NAME1: %x", core_name1);
+ $display("CORE_VERSION: %x", core_version);
+
+ /* run tests */
+ $display("1. Q1 = d1 * G...");
+ test_curve_multiplier(ECDSA_P256_D_NSA, ECDSA_P256_QX_NSA, ECDSA_P256_QY_NSA);
+
+ $display("2. R = k * G...");
+ test_curve_multiplier(ECDSA_P256_K_NSA, ECDSA_P256_RX_NSA, ECDSA_P256_RY_NSA);
+
+ $display("3. Q2 = d2 * G...");
+ test_curve_multiplier(ECDSA_P256_D_RANDOM, ECDSA_P256_QX_RANDOM, ECDSA_P256_QY_RANDOM);
+
+ $display("4. O = n * G...");
+ test_curve_multiplier(ECDSA_P256_N, 256'd0, 256'd0);
+
+ $display("5. G = (n + 1) * G...");
+ test_curve_multiplier(ECDSA_P256_N + 256'd1, ECDSA_P256_GX, ECDSA_P256_GY);
+
+ $display("6. H = 2 * G...");
+ test_curve_multiplier(256'd2, ECDSA_P256_HX, ECDSA_P256_HY);
+
+ $display("7. H = (n + 2) * G...");
+ test_curve_multiplier(ECDSA_P256_N + 256'd2, ECDSA_P256_HX, ECDSA_P256_HY);
+
+ /* print result */
+ if (ok) $display("tb_curve_multiplier_256: SUCCESS");
+ else $display("tb_curve_multiplier_256: FAILURE");
+
+ $finish;
+
+ end
+
+
+ //
+ // Test Task
+ //
+ reg p_ok;
+ integer w;
+ reg busy;
+ reg [31:0] reg_control;
+ reg [31:0] reg_status;
+ task test_curve_multiplier;
+
+ input [255:0] k;
+ input [255:0] px;
+ input [255:0] py;
+
+ reg [255:0] k_shreg;
+ reg [255:0] px_shreg;
+ reg [255:0] py_shreg;
+
+ begin
+
+ // initialize shift registers
+ k_shreg = k;
+
+ // write all the words
+ for (w=0; w<OPERAND_NUM_WORDS; w=w+1) begin
+ fmc_write(CORE_ADDR_BUF_K + w, k_shreg[31:0]);
+ k_shreg = {{32{1'bX}}, k_shreg[255:32]};
+ end
+
+ // start operation
+ reg_control = {32{1'b0}};
+ fmc_write(CORE_ADDR_CONTROL, reg_control);
+ reg_control = CORE_CONTROL_BIT_NEXT;
+ fmc_write(CORE_ADDR_CONTROL, reg_control);
+
+ // wait for operation to complete
+ busy = 1;
+ while (busy) begin
+ fmc_read(CORE_ADDR_STATUS, reg_status);
+ if ((reg_status & CORE_STATUS_BIT_VALID) == CORE_STATUS_BIT_VALID) busy = 0;
+ end
+
+ // read result
+ for (w=0; w<OPERAND_NUM_WORDS; w=w+1) begin
+ px_shreg = {{32{1'bX}}, px_shreg[255:32]};
+ py_shreg = {{32{1'bX}}, py_shreg[255:32]};
+ fmc_read(CORE_ADDR_BUF_X + w, px_shreg[255:224]);
+ fmc_read(CORE_ADDR_BUF_Y + w, py_shreg[255:224]);
+ end
+
+ // compare
+ p_ok = (px_shreg === px) &&
+ (py_shreg === py);
+
+ // display results
+ if (p_ok) $display("test_curve_multiplier(): OK");
+ else begin
+ $display("test_curve_multiplier(): ERROR");
+ $display("ref_px == %x", px);
+ $display("calc_px == %x", px_shreg);
+ $display("ref_py == %x", py);
+ $display("calc_py == %x", py_shreg);
+ end
+
+ // update global flag
+ ok = ok && p_ok;
+
+ end
+
+ endtask
+
+
+ //
+ // Helper Function
+ //
+ function [31:0] _fmc_swap;
+ input [31:0] data;
+ _fmc_swap = {data[7:0], data[15:8], data[23:16], data[31:24]};
+ endfunction
+
+
+ //-------------
+ task fmc_write;
+ //-------------
+ input [23: 0] addr;
+ input [31: 0] data;
+ begin
+ fmc_ne1 = 1'b0; // select
+ fmc_nl = 1'b0; // set latch flag
+ fmc_a = addr; // set address
+ fmc_nwe = 1'b0; // set write-enable
+ wait_full_tick(); // mimic latency
+
+ fmc_nl = 1'b1; // clear latch flag
+ fmc_a = {24{1'bX}}; // clear address
+ wait_n_ticks(STM32_FMC_LATENCY); // mimic latency
+
+ fmc_d_drive = _fmc_swap(data); // set data
+
+ wait_half_tick(); // mimic latency
+ wait_quarter_tick();
+
+ fmc_ne1 = 1'b1; // deselect
+ fmc_nwe = 1'b1; // clear write-enable
+ fmc_d_drive = 32'hXXXXXXXX; // clear data
+
+ wait_quarter_tick(); // finish clock period
+ wait_full_tick(); // pause
+ end
+ endtask
+
+ //------------
+ task fmc_read;
+ //------------
+ input [23: 0] addr;
+ output [31: 0] data;
+ begin
+ fmc_ne1 = 1'b0; // select
+ fmc_nl = 1'b0; // set latch flag
+ fmc_a = addr; // set address
+
+ wait_full_tick(); // mimic latency
+
+ fmc_nl = 1'b1; // clear latch flag
+ fmc_a = {24{1'bX}}; // clear address
+ wait_full_tick(); // mimic latency
+ fmc_noe = 1'b0; // tri-state bus
+ wait_n_ticks(STM32_FMC_LATENCY-1); // mimic latency
+
+ wait_half_tick(); // mimic latency
+ data = _fmc_swap(fmc_d_bidir); // sample data
+ wait_half_tick(); // mimic latency
+
+ wait_full_tick(); // mimic latency
+
+ wait_half_tick(); // mimic latency
+ wait_quarter_tick();
+
+ fmc_ne1 = 1'b1; // deselect
+ fmc_noe = 1'b1; // drive bus
+
+ wait_quarter_tick(); // finish clock period
+ wait_full_tick(); // pause
+ end
+ endtask
+
+
+ //
+ // Helper Tasks
+ //
+
+ //----------------------
+ task wait_quarter_tick;
+ //----------------------
+ begin
+ #FMC_CLOCK_PERIOD_QUARTER;
+ end
+ endtask
+
+ //------------------
+ task wait_half_tick;
+ //------------------
+ begin
+ wait_quarter_tick();
+ wait_quarter_tick();
+ end
+ endtask
+
+ //------------------
+ task wait_full_tick;
+ //------------------
+ begin
+ wait_half_tick();
+ wait_half_tick();
+ end
+ endtask
+
+ //----------------
+ task wait_n_ticks;
+ //----------------
+ input integer n;
+ integer i;
+ begin
+ for (i=0; i<n; i=i+1)
+ wait_full_tick();
+ end
+ endtask
+
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------