aboutsummaryrefslogtreecommitdiff
path: root/test_vectors
diff options
context:
space:
mode:
authorPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2018-02-26 13:05:17 +0300
committerPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2018-02-26 13:05:17 +0300
commit71fba5c6662d6bbe74366c03b531a5f86b25bbbb (patch)
tree6e15bce58eadd3a5d13535bd23f083f2bfb5cdd2 /test_vectors
Initial commit of C reference model for ECDH cores.
Diffstat (limited to 'test_vectors')
-rw-r--r--test_vectors/alice_p256.key8
-rw-r--r--test_vectors/alice_p384.key9
-rw-r--r--test_vectors/bob_p256.key8
-rw-r--r--test_vectors/bob_p384.key9
-rw-r--r--test_vectors/ecdh_test_vectors.h74
-rw-r--r--test_vectors/format_test_vectors.py450
-rw-r--r--test_vectors/regenerate_test_vectors.py71
7 files changed, 629 insertions, 0 deletions
diff --git a/test_vectors/alice_p256.key b/test_vectors/alice_p256.key
new file mode 100644
index 0000000..ae4ebb1
--- /dev/null
+++ b/test_vectors/alice_p256.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIEBNSvo4ZaPW+SHMtHzepOknbD1FboTRlmMyTa+MXi9EoAoGCCqGSM49
+AwEHoUQDQgAEbzthrz150bZ8EoNpH+joct6B4XoGtdThru3NVwm/HRvRNFvMoCLq
+iVOwTC0R/CT4Czt/hHt53u7ZLsQw2Ow8mA==
+-----END EC PRIVATE KEY-----
diff --git a/test_vectors/alice_p384.key b/test_vectors/alice_p384.key
new file mode 100644
index 0000000..04aba40
--- /dev/null
+++ b/test_vectors/alice_p384.key
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDDnM9nbuIZ7Vzy7wL2JnIjbZpMi6AQ1waTisN2xXnVzcfaEpZUF2SPI
+v5bcEcOuUFqgBwYFK4EEACKhZANiAASLhScIGDEffx7y8E2zjmiyPACL+xTiDLA3
+76Qhw8PfbaN8SE6FXamB2oZlgHID/zbXSPUV738mcgzopw4ggnKWjuaomq7M2Pth
+s1Nkxw37SOtcaFyBC9nLLRhPsQlqsw8=
+-----END EC PRIVATE KEY-----
diff --git a/test_vectors/bob_p256.key b/test_vectors/bob_p256.key
new file mode 100644
index 0000000..f1e17bc
--- /dev/null
+++ b/test_vectors/bob_p256.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIHFZpDvoMiRxGf6usnqSRm4rB8jfKbvX6tMjKvhEmVqVoAoGCCqGSM49
+AwEHoUQDQgAEBRRgjcLcaiF0sITWFoqtE0rNP1JuSdwyv5hyqqS+mdlySvp1TGcr
+ceh8m9rh4rFfeE9ID+tiBA4oGVO96jgpRg==
+-----END EC PRIVATE KEY-----
diff --git a/test_vectors/bob_p384.key b/test_vectors/bob_p384.key
new file mode 100644
index 0000000..7e5b303
--- /dev/null
+++ b/test_vectors/bob_p384.key
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDBWAYINcFIkpd1t2xPgoV52hp5qvje6IjV5Kvn2qb8RStH9MZ3YGB4G
+RPFUSE5zp1qgBwYFK4EEACKhZANiAAQ3q1VtBlLGueNSxkNFAr4Zn7nFDyreBJsG
+5QwwzasGc2nv4MBuEUp28TOBddtPSYIhzdrg8Re2VnydR3vB/F0kOyZlHhQG8e6z
+QYVSc5yTlWd0yE0gztwVkv1d4Eu/mK0=
+-----END EC PRIVATE KEY-----
diff --git a/test_vectors/ecdh_test_vectors.h b/test_vectors/ecdh_test_vectors.h
new file mode 100644
index 0000000..7fbb746
--- /dev/null
+++ b/test_vectors/ecdh_test_vectors.h
@@ -0,0 +1,74 @@
+/* Generated automatically, do not edit. */
+
+#define P_256_DA \
+ {0x404d4afa, 0x3865a3d6, 0xf921ccb4, 0x7cdea4e9, \
+ 0x276c3d45, 0x6e84d196, 0x63324daf, 0x8c5e2f44}
+
+#define P_256_QA_X \
+ {0x6f3b61af, 0x3d79d1b6, 0x7c128369, 0x1fe8e872, \
+ 0xde81e17a, 0x06b5d4e1, 0xaeedcd57, 0x09bf1d1b}
+
+#define P_256_QA_Y \
+ {0xd1345bcc, 0xa022ea89, 0x53b04c2d, 0x11fc24f8, \
+ 0x0b3b7f84, 0x7b79deee, 0xd92ec430, 0xd8ec3c98}
+
+#define P_256_DB \
+ {0x7159a43b, 0xe8322471, 0x19feaeb2, 0x7a92466e, \
+ 0x2b07c8df, 0x29bbd7ea, 0xd3232af8, 0x44995a95}
+
+#define P_256_QB_X \
+ {0x0514608d, 0xc2dc6a21, 0x74b084d6, 0x168aad13, \
+ 0x4acd3f52, 0x6e49dc32, 0xbf9872aa, 0xa4be99d9}
+
+#define P_256_QB_Y \
+ {0x724afa75, 0x4c672b71, 0xe87c9bda, 0xe1e2b15f, \
+ 0x784f480f, 0xeb62040e, 0x281953bd, 0xea382946}
+
+#define P_256_S_X \
+ {0xa001c11b, 0x0d04b6c3, 0xbe99551e, 0x9115b811, \
+ 0x0a41a0b7, 0x59c3e3f2, 0xfb636df1, 0xeb0e9a42}
+
+#define P_256_S_Y \
+ {0x14ed5674, 0x62b6ba27, 0x2ba0e01b, 0x2647d725, \
+ 0x5919bf5e, 0xcbb542f7, 0x659d40de, 0x324524ac}
+
+#define P_384_DA \
+ {0xe733d9db, 0xb8867b57, 0x3cbbc0bd, 0x899c88db, \
+ 0x669322e8, 0x0435c1a4, 0xe2b0ddb1, 0x5e757371, \
+ 0xf684a595, 0x05d923c8, 0xbf96dc11, 0xc3ae505a}
+
+#define P_384_QA_X \
+ {0x8b852708, 0x18311f7f, 0x1ef2f04d, 0xb38e68b2, \
+ 0x3c008bfb, 0x14e20cb0, 0x37efa421, 0xc3c3df6d, \
+ 0xa37c484e, 0x855da981, 0xda866580, 0x7203ff36}
+
+#define P_384_QA_Y \
+ {0xd748f515, 0xef7f2672, 0x0ce8a70e, 0x20827296, \
+ 0x8ee6a89a, 0xaeccd8fb, 0x61b35364, 0xc70dfb48, \
+ 0xeb5c685c, 0x810bd9cb, 0x2d184fb1, 0x096ab30f}
+
+#define P_384_DB \
+ {0x5601820d, 0x705224a5, 0xdd6ddb13, 0xe0a15e76, \
+ 0x869e6abe, 0x37ba2235, 0x792af9f6, 0xa9bf114a, \
+ 0xd1fd319d, 0xd8181e06, 0x44f15448, 0x4e73a75a}
+
+#define P_384_QB_X \
+ {0x37ab556d, 0x0652c6b9, 0xe352c643, 0x4502be19, \
+ 0x9fb9c50f, 0x2ade049b, 0x06e50c30, 0xcdab0673, \
+ 0x69efe0c0, 0x6e114a76, 0xf1338175, 0xdb4f4982}
+
+#define P_384_QB_Y \
+ {0x21cddae0, 0xf117b656, 0x7c9d477b, 0xc1fc5d24, \
+ 0x3b26651e, 0x1406f1ee, 0xb3418552, 0x739c9395, \
+ 0x6774c84d, 0x20cedc15, 0x92fd5de0, 0x4bbf98ad}
+
+#define P_384_S_X \
+ {0x15ac62cb, 0xbb51e1ed, 0xd41d489f, 0xdfa05d45, \
+ 0x115f4ef2, 0x269fbd26, 0x3f6c7364, 0x673f0b19, \
+ 0x489e8a7b, 0xdfad6d40, 0x277edf9f, 0x62220c51}
+
+#define P_384_S_Y \
+ {0xa0b846fe, 0xa76973b4, 0x12dfae76, 0x2b3b6587, \
+ 0xf62be0a3, 0x73da36ef, 0x8992e7c9, 0x6cf7619d, \
+ 0xa2d6c0a2, 0xd31ad05d, 0xb3a16a95, 0x0cb7055f}
+
diff --git a/test_vectors/format_test_vectors.py b/test_vectors/format_test_vectors.py
new file mode 100644
index 0000000..a49b34b
--- /dev/null
+++ b/test_vectors/format_test_vectors.py
@@ -0,0 +1,450 @@
+#
+# format_test_vectors.py
+# ------------------------------------------
+# Formats test vectors for ecdsa_fpga_model
+#
+# Author: Pavel Shatov
+# Copyright (c) 2017, NORDUnet A/S
+# All rights reserved.
+#
+# 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.
+#
+
+#
+# This script reads the test vectors generated by regenerate_test_vectors.py
+# and writes nicely formatted C header file and Verilog include file.
+#
+
+#
+# imports
+#
+import sys
+import subprocess
+from fastecdsa.curve import P256
+from fastecdsa.curve import P384
+from fastecdsa.point import Point
+
+# list of curve names of interest
+CURVE_P256 = "p256"
+CURVE_P384 = "p384"
+
+# the base point for p-256
+P256_GX = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
+P256_GY = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
+
+# the base point for p-384
+P384_GX = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7
+P384_GY = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f
+
+
+#
+# get part of string between two markers
+#
+#def string_between(s, s_left, s_right):
+# s_begin = s.index(s_left) + len(s_left)
+# s_end = s.index(s_right, s_begin)
+# return s[s_begin:s_end]
+
+#
+# load message from file
+#
+#def read_message(key):
+# with open(key + ".txt", "r") as f:
+# return f.readlines()[0]
+#
+#
+# read modulus from file
+#
+#def read_modulus(key):
+# openssl_command = ["openssl", "rsa", "-in", key + ".key", "-noout", "-modulus"]
+# openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+# return openssl_stdout.strip().split("=")[1]
+
+#
+# read private exponent from file
+#
+#def read_secret(key):
+# openssl_command = ["openssl", "rsa", "-in", key + ".key", "-noout", "-text"]
+# openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+# openssl_secret = string_between(openssl_stdout, "privateExponent", "prime1")
+# openssl_secret = openssl_secret.replace(":", "")
+# openssl_secret = openssl_secret.replace("\n", "")
+# openssl_secret = openssl_secret.replace(" ", "")
+# return openssl_secret
+
+#
+# read part of private key from file
+#
+#def read_prime1(key):
+# openssl_command = ["openssl", "rsa", "-in", key + ".key", "-noout", "-text"]
+# openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+# openssl_secret = string_between(openssl_stdout, "prime1", "prime2")
+# openssl_secret = openssl_secret.replace(":", "")
+# openssl_secret = openssl_secret.replace("\n", "")
+# openssl_secret = openssl_secret.replace(" ", "")
+# return openssl_secret
+#def read_prime2(key):
+# openssl_command = ["openssl", "rsa", "-in", key + ".key", "-noout", "-text"]
+# openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+# openssl_secret = string_between(openssl_stdout, "prime2", "exponent1")
+# openssl_secret = openssl_secret.replace(":", "")
+# openssl_secret = openssl_secret.replace("\n", "")
+# openssl_secret = openssl_secret.replace(" ", "")
+# return openssl_secret
+
+#
+# read prive exponent from file
+#
+#def read_exponent1(key):
+# openssl_command = ["openssl", "rsa", "-in", key + ".key", "-noout", "-text"]
+# openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+# openssl_secret = string_between(openssl_stdout, "exponent1", "exponent2")
+# openssl_secret = openssl_secret.replace(":", "")
+# openssl_secret = openssl_secret.replace("\n", "")
+# openssl_secret = openssl_secret.replace(" ", "")
+# return openssl_secret
+#def read_exponent2(key):
+# openssl_command = ["openssl", "rsa", "-in", key + ".key", "-noout", "-text"]
+# openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+# openssl_secret = string_between(openssl_stdout, "exponent2", "coefficient")
+# openssl_secret = openssl_secret.replace(":", "")
+# openssl_secret = openssl_secret.replace("\n", "")
+# openssl_secret = openssl_secret.replace(" ", "")
+# return openssl_secret
+
+#
+# format one test vector
+#
+def format_c_header(f, curve, da, qax, qay, db, qbx, qby, sx, sy):
+
+ if curve == CURVE_P256: curve_str = "P_256"
+ if curve == CURVE_P384: curve_str = "P_384"
+
+ # write all numbers in vector
+ format_c_array(f, da, "#define " + curve_str + "_DA" + " \\\n")
+ format_c_array(f, qax, "#define " + curve_str + "_QA_X" + " \\\n")
+ format_c_array(f, qay, "#define " + curve_str + "_QA_Y" + " \\\n")
+
+ format_c_array(f, db, "#define " + curve_str + "_DB" + " \\\n")
+ format_c_array(f, qbx, "#define " + curve_str + "_QB_X" + " \\\n")
+ format_c_array(f, qby, "#define " + curve_str + "_QB_Y" + " \\\n")
+
+ format_c_array(f, sx, "#define " + curve_str + "_S_X" + " \\\n")
+ format_c_array(f, sy, "#define " + curve_str + "_S_Y" + " \\\n")
+
+
+#
+# format one test vector
+#
+#def format_verilog_include(f, key, n, m, d, s, p, q, dp, dq, mp, mq):
+#
+# # calculate factor to bring message into Montgomery domain
+# factor = calc_montgomery_factor(int(key), n)
+# factor_p = calc_montgomery_factor(int(key)//2, p);
+# factor_q = calc_montgomery_factor(int(key)//2, q);
+#
+# # calculate helper coefficients for Montgomery multiplication
+# n_coeff = calc_montgomery_n_coeff(int(key), n)
+# p_coeff = calc_montgomery_n_coeff(int(key)//2, p)
+# q_coeff = calc_montgomery_n_coeff(int(key)//2, q)
+#
+# # calculate the extra coefficient Montgomery multiplication brings in
+# coeff = modinv(1 << int(key), n)
+#
+# # convert m into Montgomery representation
+# m_factor = (m * factor * coeff) % n
+#
+# # write all numbers
+# format_verilog_concatenation(f, m, "localparam [" + str(int(key)-1) + ":0] M_" + key + " =\n")
+# format_verilog_concatenation(f, n, "localparam [" + str(int(key)-1) + ":0] N_" + key + " =\n")
+# format_verilog_concatenation(f, n_coeff, "localparam [" + str(int(key)-1) + ":0] N_COEFF_" + key + " =\n")
+# format_verilog_concatenation(f, factor, "localparam [" + str(int(key)-1) + ":0] FACTOR_" + key + " =\n")
+# format_verilog_concatenation(f, coeff, "localparam [" + str(int(key)-1) + ":0] COEFF_" + key + " =\n")
+# format_verilog_concatenation(f, m_factor, "localparam [" + str(int(key)-1) + ":0] M_FACTOR_" + key + " =\n")
+# format_verilog_concatenation(f, d, "localparam [" + str(int(key)-1) + ":0] D_" + key + " =\n")
+# format_verilog_concatenation(f, s, "localparam [" + str(int(key)-1) + ":0] S_" + key + " =\n")
+#
+# format_verilog_concatenation(f, p, "localparam [" + str(int(key)//2-1) + ":0] P_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, q, "localparam [" + str(int(key)//2-1) + ":0] Q_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, p_coeff, "localparam [" + str(int(key)//2-1) + ":0] P_COEFF_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, q_coeff, "localparam [" + str(int(key)//2-1) + ":0] Q_COEFF_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, factor_p, "localparam [" + str(int(key)//2-1) + ":0] FACTOR_P_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, factor_q, "localparam [" + str(int(key)//2-1) + ":0] FACTOR_Q_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, dp, "localparam [" + str(int(key)//2-1) + ":0] DP_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, dq, "localparam [" + str(int(key)//2-1) + ":0] DQ_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, mp, "localparam [" + str(int(key)//2-1) + ":0] MP_" + str(int(key)//2) + " =\n")
+# format_verilog_concatenation(f, mq, "localparam [" + str(int(key)//2-1) + ":0] MQ_" + str(int(key)//2) + " =\n")
+
+
+#
+# nicely format multi-word integer into C array initializer
+#
+def format_c_array(f, n, s):
+
+ # print '#define XYZ \'
+ f.write(s)
+
+ # convert number to hex string and prepend it with zeroes if necessary
+ n_hex = hex(n).lstrip("0x").rstrip("L")
+ while (len(n_hex) % 8) > 0:
+ n_hex = "0" + n_hex
+
+ # get number of 32-bit words
+ num_words = len(n_hex) // 8
+
+ # print all words in n
+ w = 0
+ while w < num_words:
+
+ n_part = ""
+
+ # add tab for every new line
+ if w == 0:
+ n_part += "\t{"
+ elif (w % 4) == 0:
+ n_part += "\t "
+
+ # add current word
+ n_part += "0x" + n_hex[8 * w : 8 * (w + 1)]
+
+ # add separator or newline
+ if (w + 1) == num_words:
+ n_part += "}\n"
+ else:
+ n_part += ", "
+ if (w % 4) == 3:
+ n_part += "\\\n"
+
+ w += 1
+
+ # write current part
+ f.write(n_part)
+
+ # write final newline
+ f.write("\n")
+
+
+#def format_verilog_concatenation(f, n, s):
+#
+# # print 'localparam ZZZ ='
+# f.write(s)
+#
+# # convert number to hex string and prepend it with zeroes if necessary
+# n_hex = hex(n).split("0x")[1]
+# while (len(n_hex) % 8) > 0:
+# n_hex = "0" + n_hex
+#
+# # get number of 32-bit words
+# num_words = len(n_hex) // 8
+#
+# # print all words in n
+# w = 0
+# while w < num_words:
+#
+# n_part = ""
+#
+# if w == 0:
+# n_part += "\t{"
+# elif (w % 4) == 0:
+# n_part += "\t "
+#
+# n_part += "32'h" + n_hex[8 * w : 8 * (w + 1)]
+#
+# if (w + 1) == num_words:
+# n_part += "};\n"
+# else:
+# n_part += ", "
+# if (w % 4) == 3:
+# n_part += "\n"
+# w += 1
+#
+# f.write(n_part)
+#
+# f.write("\n")
+
+
+ #
+ # returns d, qx, qy, where
+ # d is private key and qx, qy is the corresponding public key
+ #
+def get_key(party, curve):
+
+ # generate private key filename
+ key_file = party + "_" + curve + ".key"
+
+ # retrieve key components using openssl
+ openssl_command = ["openssl", "ec", "-in", key_file, "-noout", "-text"]
+ openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8")
+ stdout_lines = openssl_stdout.splitlines()
+
+ found_priv = False
+ found_pub = False
+
+ key_priv = ""
+ key_pub = ""
+
+ # process lines looking for "priv:" and "pub:" markers
+ for line in stdout_lines:
+
+ # found private key marker?
+ if line.strip() == "priv:":
+ found_priv = True
+ found_pub = False
+ continue
+
+ # found public key marker?
+ if line.strip() == "pub:": # openssl 1.0.2g prints 'pub: ' (extra space before newline),
+ found_pub = True # so we need compare against line.strip(), not just line
+ found_priv = False
+ continue
+
+ # found part of private key?
+ if found_priv:
+ if not line.startswith(" "):
+ found_priv = False
+ continue
+ else:
+ key_priv += line.strip()
+
+ # found part of public key?
+ if found_pub:
+ if not line.startswith(" "):
+ found_pub = False
+ continue
+ else:
+ key_pub += line.strip()
+
+ # do some cleanup and sanity checking on private key
+ # * remove extra leading zero byte if present
+ # * remove colons
+ # * check length (256 bits or 384 bits)
+ while key_priv.startswith("00"):
+ key_priv = key_priv[2:]
+
+ key_priv = key_priv.replace(":", "")
+
+ if curve == CURVE_P256 and len(key_priv) != 256 / 4: sys.exit()
+ if curve == CURVE_P384 and len(key_priv) != 384 / 4: sys.exit()
+
+ # do some cleanup and sanity checking on public key
+ # * make sure, that uncompressed form marker (0x04) is present and
+ # then remove it
+ # * remove colons
+ # * check length (2x256 or 2x384 bits)
+ if not key_pub.startswith("04"): sys.exit()
+
+ key_pub = key_pub[2:]
+ key_pub = key_pub.replace(":", "")
+
+ if curve == CURVE_P256 and len(key_pub) != 2 * 256 / 4: sys.exit()
+ if curve == CURVE_P384 and len(key_pub) != 2 * 384 / 4: sys.exit()
+
+ # split public key into parts
+ if curve == CURVE_P256:
+ key_pub_x = key_pub[ 0: 64]
+ key_pub_y = key_pub[ 64:128]
+
+ if curve == CURVE_P384:
+ key_pub_x = key_pub[ 0: 96]
+ key_pub_y = key_pub[ 96:192]
+
+ # convert from strings to integers
+ key_priv = int(key_priv, 16)
+ key_pub_x = int(key_pub_x, 16)
+ key_pub_y = int(key_pub_y, 16)
+
+ # another sanity check (make sure, that Q is actually d * G)
+ if curve == CURVE_P256:
+ G = Point(P256_GX, P256_GY, curve=P256)
+ Q = Point(key_pub_x, key_pub_y, curve=P256)
+
+ if curve == CURVE_P384:
+ G = Point(P384_GX, P384_GY, curve=P384)
+ Q = Point(key_pub_x, key_pub_y, curve=P384)
+
+ # multiply using fastecdsa
+ R = key_priv * G
+
+ if R.x != Q.x: sys.exit()
+ if R.y != Q.y: sys.exit()
+
+ # done
+ return key_priv, key_pub_x, key_pub_y
+
+
+if __name__ == "__main__":
+
+ # list of curves to process
+ curves = [CURVE_P256, CURVE_P384]
+
+ # open output files
+ file_h = open('ecdsa_fpga_model_ecdh_vectors.h', 'w')
+# file_v = open('modexp_fpga_model_vectors.v', 'w')
+
+ # write headers
+ file_h.write("/* Generated automatically, do not edit. */\n\n")
+# file_v.write("/* Generated automatically, do not edit. */\n\n")
+
+ # process all the keys
+ for curve in curves:
+
+ # load keys
+ da, qax, qay = get_key("alice", curve)
+ db, qbx, qby = get_key("bob", curve)
+
+ # Alice's public key
+ if (curve == CURVE_P256): QA = Point(qax, qay, curve=P256)
+ if (curve == CURVE_P384): QA = Point(qax, qay, curve=P384)
+
+ # Bob's public key
+ if (curve == CURVE_P256): QB = Point(qbx, qby, curve=P256)
+ if (curve == CURVE_P384): QB = Point(qbx, qby, curve=P384)
+
+ # we derive the shared secret two different ways (from Alice's and
+ # from Bob's perspective, they must be identical of course
+ QAB = da * QB # Alice's secret
+ QBA = db * QA # Bob's secret
+
+ if (QAB.x != QBA.x): sys.exit()
+ if (QBA.y != QAB.y): sys.exit()
+
+ print("Derived shared secret.");
+
+ # format numbers and write to file
+ format_c_header(file_h, curve, da, qax, qay, db, qbx, qby, QAB.x, QBA.y)
+# format_verilog_include(file_v, key, modulus, message, secret, signature, prime1, prime2, exponent1, exponent2, message1, message2)
+
+ # done
+ file_h.close()
+# file_v.close()
+
+ # everything went just fine
+ print("Test vectors formatted.")
+
+#
+# End of file
+#
diff --git a/test_vectors/regenerate_test_vectors.py b/test_vectors/regenerate_test_vectors.py
new file mode 100644
index 0000000..f734854
--- /dev/null
+++ b/test_vectors/regenerate_test_vectors.py
@@ -0,0 +1,71 @@
+#
+# regenerate_test_vectors.py
+# -------------------------------------------------------------------
+# Generates a new set of randomized test vectors for ecdsa_fpga_model
+#
+# Author: Pavel Shatov
+# Copyright (c) 2017, NORDUnet A/S
+# All rights reserved.
+#
+# 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.
+#
+
+#
+# This script generates a pair of test vectors. Each test vector contains two
+# private keys. One test vector is for P-256, the other one is for P-384.
+#
+
+#
+# imports
+#
+import subprocess
+
+CURVE_P256 = "prime256v1"
+CURVE_P384 = "secp384r1"
+
+SECRET_ALICE_256 = "alice_p256.key"
+SECRET_ALICE_384 = "alice_p384.key"
+
+SECRET_BOB_256 = "bob_p256.key"
+SECRET_BOB_384 = "bob_p384.key"
+
+def openssl_ecparam_genkey(curve, file):
+ subprocess.call(["openssl", "ecparam", "-genkey", "-name", curve, "-out", file])
+
+if __name__ == "__main__":
+
+ # generate two new private keys for P-256 curve
+ openssl_ecparam_genkey(CURVE_P256, SECRET_ALICE_256)
+ openssl_ecparam_genkey(CURVE_P256, SECRET_BOB_256)
+
+ # generate two new private keys for P-384 curve
+ openssl_ecparam_genkey(CURVE_P384, SECRET_ALICE_384)
+ openssl_ecparam_genkey(CURVE_P384, SECRET_BOB_384)
+
+#
+# End of file
+#