//------------------------------------------------------------------------------ // // ecdh_fpga_model.cpp // -------------------------------------------- // Curve point scalar multiplier model for ECDH // // Authors: Pavel Shatov // // Copyright (c) 2017-2018, 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. // //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include #include #include #include "ecdh_fpga_model.h" #include "fpga_lowlevel.h" #include "fpga_modular.h" #include "fpga_curve.h" #include "fpga_util.h" //------------------------------------------------------------------------------ // Prototypes //------------------------------------------------------------------------------ bool test_point_multiplier (FPGA_BUFFER *px, FPGA_BUFFER *py, FPGA_BUFFER *k, FPGA_BUFFER *qx, FPGA_BUFFER *qy); bool abuse_point_multiplier (FPGA_BUFFER *qx, FPGA_BUFFER *qy); void print_fpga_buffer (const char *s, FPGA_BUFFER *v); bool compare_fpga_buffers (FPGA_BUFFER *ax, FPGA_BUFFER *ay, FPGA_BUFFER *bx, FPGA_BUFFER *by); //------------------------------------------------------------------------------ int main() //------------------------------------------------------------------------------ { bool ok_a, ok_b, ok_g; // flags // // initialize buffers // fpga_modular_init(); fpga_curve_init(); // // test point multiplier: QA = dA * G // QB = dB * G // printf("Trying to derive public keys from private keys...\n\n"); ok_a = test_point_multiplier(&ecdsa_g_x, &ecdsa_g_y, &ecdh_da, &ecdh_qa_x, &ecdh_qa_y); ok_b = test_point_multiplier(&ecdsa_g_x, &ecdsa_g_y, &ecdh_db, &ecdh_qb_x, &ecdh_qb_y); if (!ok_a || !ok_b) return EXIT_FAILURE; // // test point multiplier: S = dA * QB // S = dB * QA // printf("Trying to derive shared secret key...\n\n"); ok_a = test_point_multiplier(&ecdh_qa_x, &ecdh_qa_y, &ecdh_db, &ecdh_s_x, &ecdh_s_y); ok_b = test_point_multiplier(&ecdh_qb_x, &ecdh_qb_y, &ecdh_da, &ecdh_s_x, &ecdh_s_y); if (!ok_a || !ok_b) return EXIT_FAILURE; // // test point multiplier: O = 0 * QA // O = 0 * QB // printf("Trying to multiply public keys by zero...\n\n"); ok_a = test_point_multiplier(&ecdh_qa_x, &ecdh_qa_y, &ecdsa_zero, &ecdsa_zero, &ecdsa_zero); ok_b = test_point_multiplier(&ecdh_qb_x, &ecdh_qb_y, &ecdsa_zero, &ecdsa_zero, &ecdsa_zero); if (!ok_a || !ok_b) return EXIT_FAILURE; // // test point multiplier: QA = 1 * QA // QB = 1 * QB // printf("Trying to multiply public keys by one...\n\n"); ok_a = test_point_multiplier(&ecdh_qa_x, &ecdh_qa_y, &ecdsa_one, &ecdh_qa_x, &ecdh_qa_y); ok_b = test_point_multiplier(&ecdh_qb_x, &ecdh_qb_y, &ecdsa_one, &ecdh_qb_x, &ecdh_qb_y); if (!ok_a || !ok_b) return EXIT_FAILURE; // // abuse point multiplier // ok_g = abuse_point_multiplier(&ecdsa_g_x, &ecdsa_g_y); ok_a = abuse_point_multiplier(&ecdh_qa_x, &ecdh_qa_y); ok_b = abuse_point_multiplier(&ecdh_qb_x, &ecdh_qb_y); if (!ok_g || !ok_a || !ok_b) return EXIT_FAILURE; // // everything went just fine // return EXIT_SUCCESS; } //------------------------------------------------------------------------------ bool test_point_multiplier(FPGA_BUFFER *px, FPGA_BUFFER *py, FPGA_BUFFER *k, FPGA_BUFFER *qx, FPGA_BUFFER *qy) //------------------------------------------------------------------------------ // // (px,py) - multiplicand // k - multiplier // // qx, qy - expected coordinates of product // // Returns true when point (rx,ry) = k * P matches the point (qx,qy). // //------------------------------------------------------------------------------ { bool ok; // flag FPGA_BUFFER rx, ry; // result /* run the model */ fpga_curve_scalar_multiply(px, py, k, &rx, &ry); /* handle result */ ok = compare_fpga_buffers(qx, qy, &rx, &ry); if (!ok) { printf("\n ERROR\n\n"); return false; } else printf("\n OK\n\n"); // everything went just fine return true; } //------------------------------------------------------------------------------ bool abuse_point_multiplier(FPGA_BUFFER *qx, FPGA_BUFFER *qy) //------------------------------------------------------------------------------ // // This routine tries to abuse the curve point multiplier by triggering the // rarely used code path where the internal adder has to add two identical // points. // //------------------------------------------------------------------------------ { bool ok; // flag // obtain quantity n + 1, n + 2 FPGA_BUFFER two, n1, n2; fpga_modular_add(&ecdsa_one, &ecdsa_one, &two); // n1 = n + 1 fpga_modular_add(&ecdsa_n, &ecdsa_one, &n1); // n1 = n + 1 fpga_modular_add(&n1, &ecdsa_one, &n2); // n2 = n1 + 1 = n + 2 printf("Trying to abuse point multiplier...\n\n"); // make sure, that (n + 1) * Q = Q FPGA_BUFFER qn1_x, qn1_y; fpga_curve_scalar_multiply(qx, qy, &n1, &qn1_x, &qn1_y); ok = compare_fpga_buffers(qx, qy, &qn1_x, &qn1_y); if (! ok) { printf("\n ERROR\n\n"); return false; } else printf("\n OK\n\n"); // we first calculate 2 * Q FPGA_BUFFER q2a_x, q2a_y; fpga_curve_scalar_multiply(qx, qy, &two, &q2a_x, &q2a_y); // we now calculate (n + 2) * Q FPGA_BUFFER q2b_x, q2b_y; fpga_curve_scalar_multiply(qx, qy, &n2, &q2b_x, &q2b_y); // both calculations should produce the same point (Q2a == Q2b) ok = compare_fpga_buffers(&q2a_x, &q2a_y, &q2b_x, &q2b_y); if (! ok) { printf("\n ERROR\n\n"); return false; } else printf("\n OK\n\n"); // everything went just fine return true; } //------------------------------------------------------------------------------ bool compare_fpga_buffers(FPGA_BUFFER *ax, FPGA_BUFFER *ay, FPGA_BUFFER *bx, FPGA_BUFFER *by) //------------------------------------------------------------------------------ // // Compare affine coordinates of two points and return true when they match. // //------------------------------------------------------------------------------ { int w; // word counter // print all the values print_fpga_buffer(" Expected: X = ", ax); print_fpga_buffer(" Calculated: X = ", bx); printf("\n"); print_fpga_buffer(" Expected: Y = ", ay); print_fpga_buffer(" Calculated: Y = ", by); // compare values for (w=0; wwords[w] != bx->words[w]) return false; // compare y if (ay->words[w] != by->words[w]) return false; } // values are the same return true; } //------------------------------------------------------------------------------ void print_fpga_buffer(const char *s, FPGA_BUFFER *buf) //------------------------------------------------------------------------------ // // Pretty print large multi-word integer. // //------------------------------------------------------------------------------ { int w; // word counter // print header printf("%s", s); // print all bytes for (w=OPERAND_NUM_WORDS; w>0; w--) { printf("%08x", buf->words[w-1]); // insert space after every group of 4 bytes if (w > 1) printf(" "); } // print footer printf("\n"); } //------------------------------------------------------------------------------ // End-of-File //------------------------------------------------------------------------------