From 800fc6c9b5d0c9c6706e5333101cc12af351a327 Mon Sep 17 00:00:00 2001 From: "Pavel V. Shatov (Meister)" Date: Fri, 9 Nov 2018 17:55:22 +0300 Subject: Added randomized test vector. --- vectors/ed25519/ed25519_test_vector_randomized.h | 10 + vectors/ed25519/ed25519_test_vector_randomized.vh | 10 + vectors/ed25519/ed25519_test_vectors.h | 91 ------- vectors/ed25519/ed25519_test_vectors_rfc8032.h | 91 +++++++ vectors/ed25519/format_test_vector.py | 297 ++++++++++++++++++++++ vectors/ed25519/regenerate_test_vector.py | 97 +++++++ vectors/ed25519/test.key | 3 + 7 files changed, 508 insertions(+), 91 deletions(-) create mode 100644 vectors/ed25519/ed25519_test_vector_randomized.h create mode 100644 vectors/ed25519/ed25519_test_vector_randomized.vh delete mode 100644 vectors/ed25519/ed25519_test_vectors.h create mode 100644 vectors/ed25519/ed25519_test_vectors_rfc8032.h create mode 100644 vectors/ed25519/format_test_vector.py create mode 100644 vectors/ed25519/regenerate_test_vector.py create mode 100644 vectors/ed25519/test.key (limited to 'vectors/ed25519') diff --git a/vectors/ed25519/ed25519_test_vector_randomized.h b/vectors/ed25519/ed25519_test_vector_randomized.h new file mode 100644 index 0000000..a0b1be2 --- /dev/null +++ b/vectors/ed25519/ed25519_test_vector_randomized.h @@ -0,0 +1,10 @@ +/* Generated automatically, do not edit. */ + +#define ED25519_D_HASHED_LSB_6 \ + {0xd113a775, 0xbfac968b, 0x5bf260cc, 0x37789168, \ + 0x05382510, 0x82f24eae, 0xbd117736, 0xa026eb91} + +#define ED25519_Q_Y_6 \ + {0xd77e1772, 0x5eef1ad5, 0x47a37ed5, 0xc524d9b5, \ + 0x3b52c180, 0x961658d5, 0x62b991b1, 0x1fc5a8f9} + diff --git a/vectors/ed25519/ed25519_test_vector_randomized.vh b/vectors/ed25519/ed25519_test_vector_randomized.vh new file mode 100644 index 0000000..6200e13 --- /dev/null +++ b/vectors/ed25519/ed25519_test_vector_randomized.vh @@ -0,0 +1,10 @@ +/* Generated automatically, do not edit. */ + +localparam [255:0] ED25519_D_HASHED_LSB_6 = + {32'hd113a775, 32'hbfac968b, 32'h5bf260cc, 32'h37789168, + 32'h05382510, 32'h82f24eae, 32'hbd117736, 32'ha026eb91}; + +localparam [255:0] ED25519_Q_Y_6 = + {32'hd77e1772, 32'h5eef1ad5, 32'h47a37ed5, 32'hc524d9b5, + 32'h3b52c180, 32'h961658d5, 32'h62b991b1, 32'h1fc5a8f9}; + diff --git a/vectors/ed25519/ed25519_test_vectors.h b/vectors/ed25519/ed25519_test_vectors.h deleted file mode 100644 index ce9b0ec..0000000 --- a/vectors/ed25519/ed25519_test_vectors.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Values taken from RFC 8032 */ - - -/* - * TEST 1 - * - * private_key == 9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 - * - */ - -/* lower 256 bits of SHA512(private_key) */ -#define ED25519_D_HASHED_LSB_1 \ - {0x0FE94D90, 0x06F020A5, 0xA3C080D9, 0x6827FFFD, \ - 0x3C010AC0, 0xF12E7A42, 0xCB33284F, 0x86837C35} - -/* corresponding public key (reverse byte order, as-is from RFC) */ -#define ED25519_Q_Y_1 \ - {0xd75a9801, 0x82b10ab7, 0xd54bfed3, 0xc964073a, \ - 0x0ee172f3, 0xdaa62325, 0xaf021a68, 0xf707511a} - - -/* - * TEST 2 - * - * private_key == 4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb - * - */ - -/* lower 256 bits of SHA512(private_key) */ -#define ED25519_D_HASHED_LSB_2 \ - {0x112e502e, 0xb0249a25, 0x5e1c827f, 0x3b6b6c7f, \ - 0x0a79f4ca, 0x8575a915, 0x28d58258, 0xd79ebd6e} - -/* corresponding public key (reverse byte order, as-is from RFC) */ -#define ED25519_Q_Y_2 \ - {0x3d4017c3, 0xe843895a, 0x92b70aa7, 0x4d1b7ebc, \ - 0x9c982ccf, 0x2ec4968c, 0xc0cd55f1, 0x2af4660c} - - -/* - * TEST 3 - * - * private_key == c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7 - * - */ - -/* lower 256 bits of SHA512(private_key) */ -#define ED25519_D_HASHED_LSB_3 \ - {0x9ca91e99, 0x81a12513, 0x1bf5c2c5, 0x4e7f4dba, \ - 0x113dc215, 0x5ba52390, 0x8402d95e, 0x758b9a90} - -/* corresponding public key (reverse byte order, as-is from RFC) */ -#define ED25519_Q_Y_3 \ - {0xfc51cd8e, 0x6218a1a3, 0x8da47ed0, 0x0230f058, \ - 0x0816ed13, 0xba3303ac, 0x5deb9115, 0x48908025} - - -/* - * TEST 4 - * - * private_key == f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5 - * - */ - -/* lower 256 bits of SHA512(private_key) */ -#define ED25519_D_HASHED_LSB_4 \ - {0xc8cc88f4, 0x4f786eb8, 0x6a0e2682, 0x9ca4b304, \ - 0xaa44b27f, 0xf2de6e4b, 0xd386f80e, 0x8d889c60} - -/* corresponding public key (reverse byte order, as-is from RFC) */ -#define ED25519_Q_Y_4 \ - {0x278117fc, 0x144c7234, 0x0f67d0f2, 0x316e8386, \ - 0xceffbf2b, 0x2428c9c5, 0x1fef7c59, 0x7f1d426e} - - -/* - * TEST 5 - * - * private_key == 833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42 - * - */ - -/* lower 256 bits of SHA512(private_key) */ -#define ED25519_D_HASHED_LSB_5 \ - {0x85b64172, 0xc7528f1a, 0xf4a5a85d, 0xd6dbd872, \ - 0x92a0079b, 0xf113570b, 0xec4be059, 0x4fcedd30} - -/* corresponding public key (reverse byte order, as-is from RFC) */ -#define ED25519_Q_Y_5 \ - {0xec172b93, 0xad5e563b, 0xf4932c70, 0xe1245034, \ - 0xc35467ef, 0x2efd4d64, 0xebf81968, 0x3467e2bf} diff --git a/vectors/ed25519/ed25519_test_vectors_rfc8032.h b/vectors/ed25519/ed25519_test_vectors_rfc8032.h new file mode 100644 index 0000000..ce9b0ec --- /dev/null +++ b/vectors/ed25519/ed25519_test_vectors_rfc8032.h @@ -0,0 +1,91 @@ +/* Values taken from RFC 8032 */ + + +/* + * TEST 1 + * + * private_key == 9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 + * + */ + +/* lower 256 bits of SHA512(private_key) */ +#define ED25519_D_HASHED_LSB_1 \ + {0x0FE94D90, 0x06F020A5, 0xA3C080D9, 0x6827FFFD, \ + 0x3C010AC0, 0xF12E7A42, 0xCB33284F, 0x86837C35} + +/* corresponding public key (reverse byte order, as-is from RFC) */ +#define ED25519_Q_Y_1 \ + {0xd75a9801, 0x82b10ab7, 0xd54bfed3, 0xc964073a, \ + 0x0ee172f3, 0xdaa62325, 0xaf021a68, 0xf707511a} + + +/* + * TEST 2 + * + * private_key == 4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb + * + */ + +/* lower 256 bits of SHA512(private_key) */ +#define ED25519_D_HASHED_LSB_2 \ + {0x112e502e, 0xb0249a25, 0x5e1c827f, 0x3b6b6c7f, \ + 0x0a79f4ca, 0x8575a915, 0x28d58258, 0xd79ebd6e} + +/* corresponding public key (reverse byte order, as-is from RFC) */ +#define ED25519_Q_Y_2 \ + {0x3d4017c3, 0xe843895a, 0x92b70aa7, 0x4d1b7ebc, \ + 0x9c982ccf, 0x2ec4968c, 0xc0cd55f1, 0x2af4660c} + + +/* + * TEST 3 + * + * private_key == c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7 + * + */ + +/* lower 256 bits of SHA512(private_key) */ +#define ED25519_D_HASHED_LSB_3 \ + {0x9ca91e99, 0x81a12513, 0x1bf5c2c5, 0x4e7f4dba, \ + 0x113dc215, 0x5ba52390, 0x8402d95e, 0x758b9a90} + +/* corresponding public key (reverse byte order, as-is from RFC) */ +#define ED25519_Q_Y_3 \ + {0xfc51cd8e, 0x6218a1a3, 0x8da47ed0, 0x0230f058, \ + 0x0816ed13, 0xba3303ac, 0x5deb9115, 0x48908025} + + +/* + * TEST 4 + * + * private_key == f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5 + * + */ + +/* lower 256 bits of SHA512(private_key) */ +#define ED25519_D_HASHED_LSB_4 \ + {0xc8cc88f4, 0x4f786eb8, 0x6a0e2682, 0x9ca4b304, \ + 0xaa44b27f, 0xf2de6e4b, 0xd386f80e, 0x8d889c60} + +/* corresponding public key (reverse byte order, as-is from RFC) */ +#define ED25519_Q_Y_4 \ + {0x278117fc, 0x144c7234, 0x0f67d0f2, 0x316e8386, \ + 0xceffbf2b, 0x2428c9c5, 0x1fef7c59, 0x7f1d426e} + + +/* + * TEST 5 + * + * private_key == 833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42 + * + */ + +/* lower 256 bits of SHA512(private_key) */ +#define ED25519_D_HASHED_LSB_5 \ + {0x85b64172, 0xc7528f1a, 0xf4a5a85d, 0xd6dbd872, \ + 0x92a0079b, 0xf113570b, 0xec4be059, 0x4fcedd30} + +/* corresponding public key (reverse byte order, as-is from RFC) */ +#define ED25519_Q_Y_5 \ + {0xec172b93, 0xad5e563b, 0xf4932c70, 0xe1245034, \ + 0xc35467ef, 0x2efd4d64, 0xebf81968, 0x3467e2bf} diff --git a/vectors/ed25519/format_test_vector.py b/vectors/ed25519/format_test_vector.py new file mode 100644 index 0000000..e0173d3 --- /dev/null +++ b/vectors/ed25519/format_test_vector.py @@ -0,0 +1,297 @@ +# +# format_test_vector.py +# ----------------------------------------- +# Formats test vector for ed25519_fpga_model +# +# Author: Pavel Shatov +# Copyright (c) 2017-2018, 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. +# + + +# +USAGE = "USAGE: format_test_vector.py [openssl_binary]" +# + +# +# This script reads the test vector generated by regenerate_test_vector.py +# and writes nicely formatted C header file and Verilog include file. +# + +# +# IMPORTANT: As far as I understand, this will only work with OpenSSL 1.1.1, +# versions 1.1.0 and 1.0.2 don't seem to support the Ed25519 algoritm. If you +# system library is the older version, you can pass the location of the +# specific OpenSSL binary to use on the command line. +# + + +# +# imports +# +import sys +import subprocess +import hashlib + + +# +# variables +# +OPENSSL = "" + + +# +# format one test vector +# +def format_c_header(f, d, qy): + + # write all numbers in vector + format_c_array(f, d, "#define ED25519_D_HASHED_LSB_6" + " \\\n") + format_c_array(f, qy, "#define ED25519_Q_Y_6" + " \\\n") + + +# +# format one test vector +# +def format_verilog_include(f, d, qy): + + # write all numbers in vector + format_verilog_concatenation(f, d, "localparam [255:0] ED25519_D_HASHED_LSB_6 =\n") + format_verilog_concatenation(f, qy, "localparam [255:0] ED25519_Q_Y_6 =\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") + +# +# nicely format wide number into Verilog concatenation +# +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, qy where + # d is the private key and qy is the corresponding public key + # +def get_key(openssl, party): + + # generate private key filename + key_file = party + ".key" + + # retrieve key components using openssl + openssl_command = [openssl, "pkey", "-in", key_file, "-noout", "-text"] + openssl_stdout = subprocess.check_output(openssl_command).decode("utf-8") + stdout_lines = openssl_stdout.splitlines() + + key_priv = "" + key_pub = "" + + found_priv = False + found_pub = False + + # process lines looking for "priv:" and "pub:" markers + for line in stdout_lines: + + # found private key marker? + if line == "priv:": + found_priv = True + found_pub = False + continue + + # found public key marker? + if line == "pub:": + found_pub = True + 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 colons + # * check length (256 bits) + key_priv = key_priv.replace(":", "") + if len(key_priv) != (256 / 4): sys.exit() + + # do some cleanup and sanity checking on public key + # * remove colons + # * check length (256 bits) + key_pub = key_pub.replace(":", "") + if len(key_pub) != (256 / 4): sys.exit() + + # convert to byte arrays + key_priv_bytes = bytes.fromhex(key_priv) + key_pub_bytes = bytes.fromhex(key_pub) + + # hash private key + key_priv_hashed_bytes = hashlib.sha512(key_priv_bytes).digest() + + # take the lower half and reverse byte order + key_priv_hashed_lsb_bytes = key_priv_hashed_bytes[:32][::-1] + + # done + return key_priv_hashed_lsb_bytes, key_pub_bytes + + +if __name__ == "__main__": + + # detect whether user requested some specific binary + if len(sys.argv) == 1: + OPENSSL = "openssl" + print("Using system OpenSSL library.") + elif len(sys.argv) == 2: + OPENSSL = sys.argv[1] + print("Using OpenSSL binary '" + OPENSSL + "'...") + else: + print(USAGE) + + if len(OPENSSL) > 0: + + # open output files + file_h = open('ed25519_test_vector_randomized.h', 'w') + file_v = open('ed25519_test_vector_randomized.vh', 'w') + + # write headers + file_h.write("/* Generated automatically, do not edit. */\n\n") + file_v.write("/* Generated automatically, do not edit. */\n\n") + + # load keys + d, qy = get_key(OPENSSL, "test") + + # convert to integers + d_int = int(d.hex(), 16) + qy_int = int(qy.hex(), 16) + + # format numbers and write to file + format_c_header(file_h, d_int, qy_int) + format_verilog_include(file_v, d_int, qy_int) + + # done + file_h.close() + file_v.close() + + # everything went just fine + print("Test vector formatted.") + +# +# End of file +# diff --git a/vectors/ed25519/regenerate_test_vector.py b/vectors/ed25519/regenerate_test_vector.py new file mode 100644 index 0000000..295fe33 --- /dev/null +++ b/vectors/ed25519/regenerate_test_vector.py @@ -0,0 +1,97 @@ +# +# regenerate_test_vector.py +# ------------------------------------------------------------ +# Generates a new randomized test vector for ed25519_fpga_model +# +# Author: Pavel Shatov +# Copyright (c) 2017-2018, 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. +# + +# +USAGE = "USAGE: regenerate_test_vector.py [openssl_binary]" +# + +# +# This script generates a new randomized test vector that contains a +# private key +# + +# +# IMPORTANT: As far as I understand, this will only work with OpenSSL 1.1.1, +# versions 1.1.0 and 1.0.2 don't seem to support the Ed25519 algoritm. If you +# system library is the older version, you can pass the location of the +# specific OpenSSL binary to use on the command line. +# + +# +# imports +# +import sys +import subprocess + +# +# variables +# +SECRET_KEY = "test.key" + +OPENSSL = "" + + +# +# openssl_genpkey +# +def openssl_genpkey(binary, filename): + + subprocess.call([binary, "genpkey", "-algorithm", "Ed25519", "-out", filename]) + + +# +# __main__ +# +if __name__ == "__main__": + + # detect whether user requested some specific binary + if len(sys.argv) == 1: + OPENSSL = "openssl" + print("Using system OpenSSL library.") + elif len(sys.argv) == 2: + OPENSSL = sys.argv[1] + print("Using OpenSSL binary '" + OPENSSL + "'...") + else: + print(USAGE) + + # generate two new private keys + if len(OPENSSL) > 0: + openssl_genpkey(OPENSSL, SECRET_KEY) + + +# +# End of file +# diff --git a/vectors/ed25519/test.key b/vectors/ed25519/test.key new file mode 100644 index 0000000..518de37 --- /dev/null +++ b/vectors/ed25519/test.key @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIHqdYrc9RO2uJhy+P7QWTIcmkYtG/8tNhP9ieVB5OqWP +-----END PRIVATE KEY----- -- cgit v1.2.3