123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- /*
- * sshbn.h: the assorted conditional definitions of BignumInt and
- * multiply macros used throughout the bignum code to treat numbers as
- * arrays of the most conveniently sized word for the target machine.
- * Exported so that other code (e.g. poly1305) can use it too.
- *
- * This file must export, in whatever ifdef branch it ends up in:
- *
- * - two types: 'BignumInt' and 'BignumCarry'. BignumInt is an
- * unsigned integer type which will be used as the base word size
- * for all bignum operations. BignumCarry is an unsigned integer
- * type used to hold the carry flag taken as input and output by
- * the BignumADC macro (see below).
- *
- * - four constant macros: BIGNUM_INT_BITS, BIGNUM_INT_BYTES,
- * BIGNUM_TOP_BIT, BIGNUM_INT_MASK. These should be more or less
- * self-explanatory, but just in case, they give the number of bits
- * in BignumInt, the number of bytes that works out to, the
- * BignumInt value consisting of only the top bit, and the
- * BignumInt value with all bits set.
- *
- * - four statement macros: BignumADC, BignumMUL, BignumMULADD,
- * BignumMULADD2. These do various kinds of multi-word arithmetic,
- * and all produce two output values.
- * * BignumADC(ret,retc,a,b,c) takes input BignumInt values a,b
- * and a BignumCarry c, and outputs a BignumInt ret = a+b+c and
- * a BignumCarry retc which is the carry off the top of that
- * addition.
- * * BignumMUL(rh,rl,a,b) returns the two halves of the
- * double-width product a*b.
- * * BignumMULADD(rh,rl,a,b,addend) returns the two halves of the
- * double-width value a*b + addend.
- * * BignumMULADD2(rh,rl,a,b,addend1,addend2) returns the two
- * halves of the double-width value a*b + addend1 + addend2.
- *
- * Every branch of the main ifdef below defines the type BignumInt and
- * the value BIGNUM_INT_BITS. The other three constant macros are
- * filled in by common code further down.
- *
- * Most branches also define a macro DEFINE_BIGNUMDBLINT containing a
- * typedef statement which declares a type _twice_ the length of a
- * BignumInt. This causes the common code further down to produce a
- * default implementation of the four statement macros in terms of
- * that double-width type, and also to defined BignumCarry to be
- * BignumInt.
- *
- * However, if a particular compile target does not have a type twice
- * the length of the BignumInt you want to use but it does provide
- * some alternative means of doing add-with-carry and double-word
- * multiply, then the ifdef branch in question can just define
- * BignumCarry and the four statement macros itself, and that's fine
- * too.
- */
- #if defined __SIZEOF_INT128__
- /*
- * 64-bit BignumInt using gcc/clang style 128-bit BignumDblInt.
- *
- * gcc and clang both provide a __uint128_t type on 64-bit targets
- * (and, when they do, indicate its presence by the above macro),
- * using the same 'two machine registers' kind of code generation
- * that 32-bit targets use for 64-bit ints.
- */
- typedef unsigned long long BignumInt;
- #define BIGNUM_INT_BITS 64
- #define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt
- #elif defined _MSC_VER && defined _M_AMD64
- /*
- * 64-bit BignumInt, using Visual Studio x86-64 compiler intrinsics.
- *
- * 64-bit Visual Studio doesn't provide very much in the way of help
- * here: there's no int128 type, and also no inline assembler giving
- * us direct access to the x86-64 MUL or ADC instructions. However,
- * there are compiler intrinsics giving us that access, so we can
- * use those - though it turns out we have to be a little careful,
- * since they seem to generate wrong code if their pointer-typed
- * output parameters alias their inputs. Hence all the internal temp
- * variables inside the macros.
- */
- #include <intrin.h>
- typedef unsigned char BignumCarry; /* the type _addcarry_u64 likes to use */
- typedef unsigned __int64 BignumInt;
- #define BIGNUM_INT_BITS 64
- #define BignumADC(ret, retc, a, b, c) do \
- { \
- BignumInt ADC_tmp; \
- (retc) = _addcarry_u64(c, a, b, &ADC_tmp); \
- (ret) = ADC_tmp; \
- } while (0)
- #define BignumMUL(rh, rl, a, b) do \
- { \
- BignumInt MULADD_hi; \
- (rl) = _umul128(a, b, &MULADD_hi); \
- (rh) = MULADD_hi; \
- } while (0)
- #define BignumMULADD(rh, rl, a, b, addend) do \
- { \
- BignumInt MULADD_lo, MULADD_hi; \
- MULADD_lo = _umul128(a, b, &MULADD_hi); \
- MULADD_hi += _addcarry_u64(0, MULADD_lo, (addend), &(rl)); \
- (rh) = MULADD_hi; \
- } while (0)
- #define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
- { \
- BignumInt MULADD_lo1, MULADD_lo2, MULADD_hi; \
- MULADD_lo1 = _umul128(a, b, &MULADD_hi); \
- MULADD_hi += _addcarry_u64(0, MULADD_lo1, (addend1), &MULADD_lo2); \
- MULADD_hi += _addcarry_u64(0, MULADD_lo2, (addend2), &(rl)); \
- (rh) = MULADD_hi; \
- } while (0)
- #elif defined __GNUC__ || defined _LLP64 || __STDC__ >= 199901L
- /* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */
- typedef unsigned int BignumInt;
- #define BIGNUM_INT_BITS 32
- #define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
- #elif defined _MSC_VER && defined _M_IX86
- /* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
- typedef unsigned int BignumInt;
- #define BIGNUM_INT_BITS 32
- #define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt
- #elif defined _LP64
- /*
- * 32-bit BignumInt, using unsigned long itself as BignumDblInt.
- *
- * Only for platforms where long is 64 bits, of course.
- */
- typedef unsigned int BignumInt;
- #define BIGNUM_INT_BITS 32
- #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
- #else
- /*
- * 16-bit BignumInt, using unsigned long as BignumDblInt.
- *
- * This is the final fallback for real emergencies: C89 guarantees
- * unsigned short/long to be at least the required sizes, so this
- * should work on any C implementation at all. But it'll be
- * noticeably slow, so if you find yourself in this case you
- * probably want to move heaven and earth to find an alternative!
- */
- typedef unsigned short BignumInt;
- #define BIGNUM_INT_BITS 16
- #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
- #endif
- /*
- * Common code across all branches of that ifdef: define the three
- * easy constant macros in terms of BIGNUM_INT_BITS.
- */
- #define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
- #define BIGNUM_TOP_BIT (((BignumInt)1) << (BIGNUM_INT_BITS-1))
- #define BIGNUM_INT_MASK (BIGNUM_TOP_BIT | (BIGNUM_TOP_BIT-1))
- /*
- * Common code across _most_ branches of the ifdef: define a set of
- * statement macros in terms of the BignumDblInt type provided. In
- * this case, we also define BignumCarry to be the same thing as
- * BignumInt, for simplicity.
- */
- #ifdef DEFINE_BIGNUMDBLINT
- typedef BignumInt BignumCarry;
- #define BignumADC(ret, retc, a, b, c) do \
- { \
- DEFINE_BIGNUMDBLINT; \
- BignumDblInt ADC_temp = (BignumInt)(a); \
- ADC_temp += (BignumInt)(b); \
- ADC_temp += (c); \
- (ret) = (BignumInt)ADC_temp; \
- (retc) = (BignumCarry)(ADC_temp >> BIGNUM_INT_BITS); \
- } while (0)
-
- #define BignumMUL(rh, rl, a, b) do \
- { \
- DEFINE_BIGNUMDBLINT; \
- BignumDblInt MUL_temp = (BignumInt)(a); \
- MUL_temp *= (BignumInt)(b); \
- (rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
- (rl) = (BignumInt)(MUL_temp); \
- } while (0)
-
- #define BignumMULADD(rh, rl, a, b, addend) do \
- { \
- DEFINE_BIGNUMDBLINT; \
- BignumDblInt MUL_temp = (BignumInt)(a); \
- MUL_temp *= (BignumInt)(b); \
- MUL_temp += (BignumInt)(addend); \
- (rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
- (rl) = (BignumInt)(MUL_temp); \
- } while (0)
-
- #define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
- { \
- DEFINE_BIGNUMDBLINT; \
- BignumDblInt MUL_temp = (BignumInt)(a); \
- MUL_temp *= (BignumInt)(b); \
- MUL_temp += (BignumInt)(addend1); \
- MUL_temp += (BignumInt)(addend2); \
- (rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
- (rl) = (BignumInt)(MUL_temp); \
- } while (0)
- #endif /* DEFINE_BIGNUMDBLINT */
|