From 91e584462544b0113abd4e6ee56cc942cf3f79b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Fri, 14 Dec 2018 12:17:50 -0500 Subject: [PATCH] Enable x25519 64-bit code path for Microsoft compilers --- donna.h | 19 ++++++++++++++----- donna_64.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/donna.h b/donna.h index 2c0f3ea8..e80b2666 100644 --- a/donna.h +++ b/donna.h @@ -39,14 +39,23 @@ int curve25519(byte sharedKey[32], const byte secretKey[32], const byte othersKe //****************************** Internal ******************************// -#if (UINTPTR_MAX == 0xffffffff) || !defined(CRYPTOPP_WORD128_AVAILABLE) -# define CRYPTOPP_CURVE25519_32BIT 1 -#else +// CRYPTOPP_WORD128_AVAILABLE mostly depends upon GCC support for +// __SIZEOF_INT128__. If __SIZEOF_INT128__ is not available then Moon +// provides routines for MSC and GCC. It should cover most platforms, +// but there are gaps like MS ARM64 and XLC. We tried to enable the +// 64-bit path for SunCC from 12.5 but we got the dreaded compile +// error "The operand ___LCM cannot be assigned to". + +#if defined(CRYPTOPP_WORD128_AVAILABLE) || \ + (defined(_MSC_VER) && defined(_M_X64)) || \ + (defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))) # define CRYPTOPP_CURVE25519_64BIT 1 +#else +# define CRYPTOPP_CURVE25519_32BIT 1 #endif -// Benchmarking on a modern Core i5-6400 shows SSE2 on Linux is -// not profitable. Here are the numbers in milliseconds/operation: +// Benchmarking on a modern 64-bit Core i5-6400 shows SSE2 on Linux +// is not profitable. Here are the numbers in milliseconds/operation: // // * Langley, C++, 0.050 // * Moon, C++: 0.040 diff --git a/donna_64.cpp b/donna_64.cpp index 810ee01f..8c14ff05 100644 --- a/donna_64.cpp +++ b/donna_64.cpp @@ -13,6 +13,12 @@ #include "misc.h" #include "cpu.h" +#if defined(_MSC_VER) +# include +# pragma intrinsic(_umul128) +# pragma intrinsic(__shiftright128) +#endif + // Squash MS LNK4221 and libtool warnings extern const char DONNA64_FNAME[] = __FILE__; @@ -26,21 +32,49 @@ using CryptoPP::word32; using CryptoPP::sword32; using CryptoPP::word64; using CryptoPP::sword64; -using CryptoPP::word128; using CryptoPP::GetBlock; using CryptoPP::LittleEndian; typedef word64 bignum25519[5]; -#define lo128(a) ((word64)a) -#define hi128(a) ((word64)(a >> 64)) +#if defined(CRYPTOPP_WORD128_AVAILABLE) +using CryptoPP::word128; +# define lo128(a) ((word64)a) +# define hi128(a) ((word64)(a >> 64)) +# define add128(a,b) a += b; +# define add128_64(a,b) a += (word64)b; +# define mul64x64_128(out,a,b) out = (word128)a * b; +# define shr128(out,in,shift) out = (word64)(in >> (shift)); +// # define shl128(out,in,shift) out = (word64)((in << shift) >> 64); -#define add128(a,b) a += b; -#define add128_64(a,b) a += (word64)b; -#define mul64x64_128(out,a,b) out = (word128)a * b; -#define shr128(out,in,shift) out = (word64)(in >> (shift)); -#define shl128(out,in,shift) out = (word64)((in << shift) >> 64); +#elif defined(_MSC_VER) +struct word128 { word64 lo, hi; }; +# define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); +# define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); +// # define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); +# define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) +// # define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) +# define add128(a,b) { word64 p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } +# define add128_64(a,b) { word64 p = a.lo; a.lo += b; a.hi += (a.lo < p); } +# define lo128(a) (a.lo) +# define hi128(a) (a.hi) + +#elif defined(__GNUC__) +struct word128 { word64 lo, hi; }; +# define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); +# define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; +// # define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; +# define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) +// # define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) +# define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); +# define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); +# define lo128(a) (a.lo) +# define hi128(a) (a.hi) +#else +// https://groups.google.com/forum/#!forum/cryptopp-users +# error "Unsupported platform" +#endif #define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) @@ -317,7 +351,7 @@ curve25519_contract(byte *out, const bignum25519 input) { */ inline void curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, word64 iswap) { - const word64 swap = (word64)(-(int64_t)iswap); + const word64 swap = (word64)(-(sword64)iswap); word64 x0,x1,x2,x3,x4; x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0;