diff options
-rw-r--r-- | ed25519/ed25519_fpga_model.cpp | 25 | ||||
-rw-r--r-- | ed25519/ed25519_fpga_model.h | 3 | ||||
-rw-r--r-- | vectors/ed25519/ed25519_test_vector_randomized.h | 10 | ||||
-rw-r--r-- | vectors/ed25519/ed25519_test_vector_randomized.vh | 10 | ||||
-rw-r--r-- | vectors/ed25519/ed25519_test_vectors_rfc8032.h (renamed from vectors/ed25519/ed25519_test_vectors.h) | 0 | ||||
-rw-r--r-- | vectors/ed25519/format_test_vector.py | 297 | ||||
-rw-r--r-- | vectors/ed25519/regenerate_test_vector.py | 97 | ||||
-rw-r--r-- | vectors/ed25519/test.key | 3 |
8 files changed, 438 insertions, 7 deletions
diff --git a/ed25519/ed25519_fpga_model.cpp b/ed25519/ed25519_fpga_model.cpp index 69c184c..d0b5a25 100644 --- a/ed25519/ed25519_fpga_model.cpp +++ b/ed25519/ed25519_fpga_model.cpp @@ -40,7 +40,7 @@ //------------------------------------------------------------------------------ // Mode Switch //------------------------------------------------------------------------------ -#define USE_MICROCODE +//#define USE_MICROCODE //------------------------------------------------------------------------------ @@ -63,11 +63,12 @@ static FPGA_WORD fpga_model_ed25519_bswap (FPGA_WORD w); //------------------------------------------------------------------------------ // Locals //------------------------------------------------------------------------------ -static FPGA_BUFFER ed25519_d_1, ed25519_q_y_1; -static FPGA_BUFFER ed25519_d_2, ed25519_q_y_2; -static FPGA_BUFFER ed25519_d_3, ed25519_q_y_3; -static FPGA_BUFFER ed25519_d_4, ed25519_q_y_4; -static FPGA_BUFFER ed25519_d_5, ed25519_q_y_5; +static FPGA_BUFFER ed25519_d_1, ed25519_q_y_1; // #1 from RFC +static FPGA_BUFFER ed25519_d_2, ed25519_q_y_2; // #2 from RFC +static FPGA_BUFFER ed25519_d_3, ed25519_q_y_3; // #3 from RFC +static FPGA_BUFFER ed25519_d_4, ed25519_q_y_4; // #4 from RFC +static FPGA_BUFFER ed25519_d_5, ed25519_q_y_5; // #5 from RFC +static FPGA_BUFFER ed25519_d_6, ed25519_q_y_6; // randomized //------------------------------------------------------------------------------ @@ -127,6 +128,14 @@ int main() // + // test base point multiplier: Q = d * G + // + printf("Trying to derive public key from private key...\n\n"); + ok = test_ed25519_base_point_multiplier(&ed25519_d_6, &ed25519_q_y_6); + if (!ok) return EXIT_FAILURE; + + + // // everything went just fine // return EXIT_SUCCESS; @@ -144,12 +153,14 @@ static void fpga_model_ed25519_init() FPGA_WORD tmp_d_3[FPGA_OPERAND_NUM_WORDS] = ED25519_D_HASHED_LSB_3; FPGA_WORD tmp_d_4[FPGA_OPERAND_NUM_WORDS] = ED25519_D_HASHED_LSB_4; FPGA_WORD tmp_d_5[FPGA_OPERAND_NUM_WORDS] = ED25519_D_HASHED_LSB_5; + FPGA_WORD tmp_d_6[FPGA_OPERAND_NUM_WORDS] = ED25519_D_HASHED_LSB_6; FPGA_WORD tmp_q_y_1[FPGA_OPERAND_NUM_WORDS] = ED25519_Q_Y_1; FPGA_WORD tmp_q_y_2[FPGA_OPERAND_NUM_WORDS] = ED25519_Q_Y_2; FPGA_WORD tmp_q_y_3[FPGA_OPERAND_NUM_WORDS] = ED25519_Q_Y_3; FPGA_WORD tmp_q_y_4[FPGA_OPERAND_NUM_WORDS] = ED25519_Q_Y_4; FPGA_WORD tmp_q_y_5[FPGA_OPERAND_NUM_WORDS] = ED25519_Q_Y_5; + FPGA_WORD tmp_q_y_6[FPGA_OPERAND_NUM_WORDS] = ED25519_Q_Y_6; /* fill buffers for large multi-word integers */ for ( w_src = 0, w_dst = FPGA_OPERAND_NUM_WORDS - 1; @@ -161,6 +172,7 @@ static void fpga_model_ed25519_init() ed25519_d_3.words[w_dst] = tmp_d_3[w_src]; ed25519_d_4.words[w_dst] = tmp_d_4[w_src]; ed25519_d_5.words[w_dst] = tmp_d_5[w_src]; + ed25519_d_6.words[w_dst] = tmp_d_6[w_src]; // public key is in reverse order ed25519_q_y_1.words[w_dst] = fpga_model_ed25519_bswap(tmp_q_y_1[w_dst]); @@ -168,6 +180,7 @@ static void fpga_model_ed25519_init() ed25519_q_y_3.words[w_dst] = fpga_model_ed25519_bswap(tmp_q_y_3[w_dst]); ed25519_q_y_4.words[w_dst] = fpga_model_ed25519_bswap(tmp_q_y_4[w_dst]); ed25519_q_y_5.words[w_dst] = fpga_model_ed25519_bswap(tmp_q_y_5[w_dst]); + ed25519_q_y_6.words[w_dst] = fpga_model_ed25519_bswap(tmp_q_y_6[w_dst]); } } diff --git a/ed25519/ed25519_fpga_model.h b/ed25519/ed25519_fpga_model.h index edc554c..e5959e8 100644 --- a/ed25519/ed25519_fpga_model.h +++ b/ed25519/ed25519_fpga_model.h @@ -42,7 +42,8 @@ //------------------------------------------------------------------------------ #include "curve25519_fpga_model.h" #include "ed25519_fpga_curve.h" -#include "ed25519_test_vectors.h" +#include "ed25519_test_vectors_rfc8032.h" +#include "ed25519_test_vector_randomized.h" //------------------------------------------------------------------------------ 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_rfc8032.h index ce9b0ec..ce9b0ec 100644 --- a/vectors/ed25519/ed25519_test_vectors.h +++ b/vectors/ed25519/ed25519_test_vectors_rfc8032.h 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----- |