From 71fba5c6662d6bbe74366c03b531a5f86b25bbbb Mon Sep 17 00:00:00 2001 From: "Pavel V. Shatov (Meister)" Date: Mon, 26 Feb 2018 13:05:17 +0300 Subject: Initial commit of C reference model for ECDH cores. --- test_vectors/alice_p256.key | 8 + test_vectors/alice_p384.key | 9 + test_vectors/bob_p256.key | 8 + test_vectors/bob_p384.key | 9 + test_vectors/ecdh_test_vectors.h | 74 ++++++ test_vectors/format_test_vectors.py | 450 ++++++++++++++++++++++++++++++++ test_vectors/regenerate_test_vectors.py | 71 +++++ 7 files changed, 629 insertions(+) create mode 100644 test_vectors/alice_p256.key create mode 100644 test_vectors/alice_p384.key create mode 100644 test_vectors/bob_p256.key create mode 100644 test_vectors/bob_p384.key create mode 100644 test_vectors/ecdh_test_vectors.h create mode 100644 test_vectors/format_test_vectors.py create mode 100644 test_vectors/regenerate_test_vectors.py (limited to 'test_vectors') 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 +# -- cgit v1.2.3