diff options
Diffstat (limited to '')
-rw-r--r-- | web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/unacl/scalarmult.c | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/unacl/scalarmult.c b/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/unacl/scalarmult.c new file mode 100644 index 00000000..488aac78 --- /dev/null +++ b/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/unacl/scalarmult.c @@ -0,0 +1,761 @@ +/* ======================= + ============================ C/C++ HEADER FILE ============================= + ======================= + + Collection of all required submodules from naclM0 required for curve25519 + scalar multiplication (not including randomization, etc.) alone. + + Library naclM0 largely bases on work avrNacl of M. Hutter and P. Schwabe. + + Will compile to the two functions + + int + crypto_scalarmult_base_curve25519( + unsigned char* q, + const unsigned char* n + ); + + int + crypto_scalarmult_curve25519 ( + unsigned char* r, + const unsigned char* s, + const unsigned char* p + ); + + Requires inttypes.h header and the four external assembly functions + + extern void + fe25519_reduceTo256Bits_asm ( + fe25519 *res, + const UN_512bitValue *in + ); + + extern void + fe25519_mpyWith121666_asm ( + fe25519* out, + const fe25519* in + ); + + extern void + multiply256x256_asm ( + UN_512bitValue* result, + const UN_256bitValue* x, + const UN_256bitValue* y + ); + + extern void + square256_asm ( + UN_512bitValue* result, + const UN_256bitValue* x + ); + + \file scalarmult.c + + \Author B. Haase, Endress + Hauser Conducta GmbH & Co. KG + + License: CC Common Creative license Attribution 4.0 International (CC BY 4.0) + http://creativecommons.org/licenses/by/4.0/ + ============================================================================*/ + +#include <inttypes.h> + +// comment out this line if implementing conditional swaps by data moves +//#define DH_SWAP_BY_POINTERS + +// Define the symbol to 0 in order to only use ladder steps +//#define DH_REPLACE_LAST_THREE_LADDERSTEPS_WITH_DOUBLINGS 1 + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; +typedef uintptr_t uintptr; + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef intptr_t intptr; + +// Note that it's important to define the unit8 as first union member, so that +// an array of uint8 may be used as initializer. +typedef union UN_256bitValue_ +{ + uint8 as_uint8[32]; + uint16 as_uint16[16]; + uint32 as_uint32[8]; + uint64 as_uint64[4]; +} UN_256bitValue; + +// Note that it's important to define the unit8 as first union member, so that +// an array of uint8 may be used as initializer. +typedef union UN_512bitValue_ +{ + uint8 as_uint8[64]; + uint16 as_uint16[32]; + uint32 as_uint32[16]; + uint64 as_uint64[8]; + UN_256bitValue as_256_bitValue[2]; +} UN_512bitValue; + +typedef UN_256bitValue fe25519; + +// **************************************************** +// Assembly functions. +// **************************************************** + +extern void +fe25519_reduceTo256Bits_asm( + fe25519 *res, + const UN_512bitValue *in +); + +#define fe25519_mpyWith121666 fe25519_mpyWith121666_asm +extern void +fe25519_mpyWith121666_asm ( + fe25519* out, + const fe25519* in +); + +#define multiply256x256 multiply256x256_asm +extern void +multiply256x256( + UN_512bitValue* result, + const UN_256bitValue* x, + const UN_256bitValue* y +); + +#define square256 square256_asm +extern void +square256( + UN_512bitValue* result, + const UN_256bitValue* x +); + +// **************************************************** +// C functions for fe25519 +// **************************************************** + +static void +fe25519_cpy( + fe25519* dest, + const fe25519* source +) +{ + uint32 ctr; + + for (ctr = 0; ctr < 8; ctr++) + { + dest->as_uint32[ctr] = source->as_uint32[ctr]; + } +} + +static void +fe25519_unpack( + volatile fe25519* out, + const unsigned char in[32] +) +{ + uint8 ctr; + + for (ctr = 0; ctr < 32; ctr++) + { + out->as_uint8[ctr] = in[ctr]; + } + out->as_uint8[31] &= 0x7f; // make sure that the last bit is cleared. +} + +static void +fe25519_sub( + fe25519* out, + const fe25519* baseValue, + const fe25519* valueToSubstract +) +{ + uint16 ctr; + int64 accu = 0; + + // First subtract the most significant word, so that we may + // reduce the result "on the fly". + accu = baseValue->as_uint32[7]; + accu -= valueToSubstract->as_uint32[7]; + + // We always set bit #31, and compensate this by subtracting 1 from the reduction + // value. + out->as_uint32[7] = ((uint32)accu) | 0x80000000ul; + + accu = 19 * ((int32)(accu >> 31) - 1); + // ^ "-1" is the compensation for the "| 0x80000000ul" above. + // This choice makes sure, that the result will be positive! + + for (ctr = 0; ctr < 7; ctr += 1) + { + accu += baseValue->as_uint32[ctr]; + accu -= valueToSubstract->as_uint32[ctr]; + + out->as_uint32[ctr] = (uint32)accu; + accu >>= 32; + } + accu += out->as_uint32[7]; + out->as_uint32[7] = (uint32)accu; +} + +static void +fe25519_add( + fe25519* out, + const fe25519* baseValue, + const fe25519* valueToAdd +) +{ + uint16 ctr = 0; + uint64 accu = 0; + + // We first add the most significant word, so that we may reduce + // "on the fly". + accu = baseValue->as_uint32[7]; + accu += valueToAdd->as_uint32[7]; + out->as_uint32[7] = ((uint32)accu) & 0x7ffffffful; + + accu = ((uint32)(accu >> 31)) * 19; + + for (ctr = 0; ctr < 7; ctr += 1) + { + accu += baseValue->as_uint32[ctr]; + accu += valueToAdd->as_uint32[ctr]; + + out->as_uint32[ctr] = (uint32)accu; + accu >>= 32; + } + accu += out->as_uint32[7]; + out->as_uint32[7] = (uint32)accu; +} + +static void +fe25519_mul( + fe25519* result, + const fe25519* in1, + const fe25519* in2 +) +{ + UN_512bitValue tmp; + + multiply256x256(&tmp, in1, in2); + fe25519_reduceTo256Bits_asm(result,&tmp); +} + +static void +fe25519_square( + fe25519* result, + const fe25519* in +) +{ + UN_512bitValue tmp; + + square256(&tmp, in); + fe25519_reduceTo256Bits_asm(result,&tmp); +} + +static void +fe25519_reduceCompletely( + volatile fe25519* inout +) +{ + uint32 numberOfTimesToSubstractPrime; + uint32 initialGuessForNumberOfTimesToSubstractPrime = inout->as_uint32[7] >> + 31; + uint64 accu; + uint8 ctr; + + // add one additional 19 to the estimated number of reductions. + // Do the calculation without writing back the results to memory. + // + // The initial guess of required numbers of reductions is based + // on bit #32 of the most significant word. + // This initial guess may be wrong, since we might have a value + // v in the range + // 2^255 - 19 <= v < 2^255 + // . After adding 19 to the value, we will be having the correct + // Number of required subtractions. + accu = initialGuessForNumberOfTimesToSubstractPrime * 19 + 19; + + for (ctr = 0; ctr < 7; ctr++) + { + accu += inout->as_uint32[ctr]; + accu >>= 32; + } + accu += inout->as_uint32[7]; + + numberOfTimesToSubstractPrime = (uint32)(accu >> 31); + + // Do the reduction. + accu = numberOfTimesToSubstractPrime * 19; + + for (ctr = 0; ctr < 7; ctr++) + { + accu += inout->as_uint32[ctr]; + inout->as_uint32[ctr] = (uint32)accu; + accu >>= 32; + } + accu += inout->as_uint32[7]; + inout->as_uint32[7] = accu & 0x7ffffffful; +} + +/// We are already using a packed radix 16 representation for fe25519. The real use for this function +/// is for architectures that use more bits for storing a fe25519 in a representation where multiplication +/// may be calculated more efficiently. +/// Here we simply copy the data. +static void +fe25519_pack( + unsigned char out[32], + volatile fe25519* in +) +{ + uint8 ctr; + + fe25519_reduceCompletely(in); + + for (ctr = 0; ctr < 32; ctr++) + { + out[ctr] = in->as_uint8[ctr]; + } +} + +// Note, that r and x are allowed to overlap! +static void +fe25519_invert_useProvidedScratchBuffers( + fe25519* r, + const fe25519* x, + fe25519* t0, + fe25519* t1, + fe25519* t2 +) +{ + fe25519 *z11 = r; // store z11 in r (in order to save one temporary). + fe25519 *z2_10_0 = t1; + fe25519 *z2_50_0 = t2; + fe25519 *z2_100_0 = z2_10_0; + + uint8 i; + + { + fe25519 *z2 = z2_50_0; + + /* 2 */ fe25519_square(z2, x); + /* 4 */ fe25519_square(t0, z2); + /* 8 */ fe25519_square(t0, t0); + /* 9 */ fe25519_mul(z2_10_0, t0, x); + /* 11 */ fe25519_mul(z11, z2_10_0, z2); + + // z2 is dead. + } + + /* 22 */ fe25519_square(t0, z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(z2_10_0, t0, z2_10_0); + + /* 2^6 - 2^1 */ fe25519_square(t0, z2_10_0); + /* 2^7 - 2^2 */ fe25519_square(t0, t0); + /* 2^8 - 2^3 */ fe25519_square(t0, t0); + /* 2^9 - 2^4 */ fe25519_square(t0, t0); + /* 2^10 - 2^5 */ fe25519_square(t0, t0); + /* 2^10 - 2^0 */ fe25519_mul(z2_10_0, t0, z2_10_0); + + /* 2^11 - 2^1 */ fe25519_square(t0, z2_10_0); + + /* 2^20 - 2^10 */ for (i = 1; i < 10; i ++) + { + fe25519_square(t0, t0); + } + /* 2^20 - 2^0 */ fe25519_mul(z2_50_0, t0, z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(t0, z2_50_0); + + /* 2^40 - 2^20 */ for (i = 1; i < 20; i ++) + { + fe25519_square(t0, t0); + } + /* 2^40 - 2^0 */ fe25519_mul(t0, t0, z2_50_0); + + /* 2^41 - 2^1 */ fe25519_square(t0, t0); + + /* 2^50 - 2^10 */ for (i = 1; i < 10; i ++) + { + fe25519_square(t0, t0); + } + /* 2^50 - 2^0 */ fe25519_mul(z2_50_0, t0, z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(t0, z2_50_0); + + /* 2^100 - 2^50 */ for (i = 1; i < 50; i ++) + { + fe25519_square(t0, t0); + } + /* 2^100 - 2^0 */ fe25519_mul(z2_100_0, t0, z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(t0, z2_100_0); + + /* 2^200 - 2^100 */ for (i = 1; i < 100; i ++) + { + fe25519_square(t0, t0); + } + /* 2^200 - 2^0 */ fe25519_mul(t0, t0, z2_100_0); + + /* 2^250 - 2^50 */ for (i = 0; i < 50; i ++) + { + fe25519_square(t0, t0); + } + /* 2^250 - 2^0 */ fe25519_mul(t0, t0, z2_50_0); + + /* 2^255 - 2^5 */ for (i = 0; i < 5; i ++) + { + fe25519_square(t0, t0); + } + /* 2^255 - 21 */ fe25519_mul(r, t0, z11); +} + +static void +fe25519_setzero( + fe25519* out +) +{ + uint8 ctr; + + for (ctr = 0; ctr < 8; ctr++) + { + out->as_uint32[ctr] = 0; + } +} + +static void +fe25519_setone( + fe25519* out +) +{ + uint8 ctr; + + out->as_uint32[0] = 1; + + for (ctr = 1; ctr < 8; ctr++) + { + out->as_uint32[ctr] = 0; + } +} + +/* +static void +swapPointersConditionally (void **p1, void **p2, uint8 condition) +{ + // Secure version of this code: + // + // if (condition) + // { + // void *temp; + // temp = *p2; + // *p2 = *p1; + // *p1 = temp; + // } + + uintptr mask = condition; + uintptr val1 = (uintptr) *p1; + uintptr val2 = (uintptr) *p2; + uintptr temp = val2 ^ val1; + + mask = (uintptr)( - (intptr) mask ); + temp ^= mask & (temp ^ val1); + val1 ^= mask & (val1 ^ val2); + val2 ^= mask & (val2 ^ temp); + + *p1 = (void *) val1; + *p2 = (void *) val2; +} +*/ + +static void +fe25519_cswap( + fe25519* in1, + fe25519* in2, + int condition +) +{ + int32 mask = condition; + uint32 ctr; + + mask = -mask; + + for (ctr = 0; ctr < 8; ctr++) + { + uint32 val1 = in1->as_uint32[ctr]; + uint32 val2 = in2->as_uint32[ctr]; + uint32 temp = val1; + + val1 ^= mask & (val2 ^ val1); + val2 ^= mask & (val2 ^ temp); + + + in1->as_uint32[ctr] = val1; + in2->as_uint32[ctr] = val2; + } +} + +// **************************************************** +// Scalarmultiplication implementation. +// **************************************************** + +typedef struct _ST_curve25519ladderstepWorkingState +{ + // The base point in affine coordinates + fe25519 x0; + + // The two working points p, q, in projective coordinates. Possibly randomized. + fe25519 xp; + fe25519 zp; + fe25519 xq; + fe25519 zq; + + volatile UN_256bitValue s; + + int nextScalarBitToProcess; + uint8 previousProcessedBit; + +#ifdef DH_SWAP_BY_POINTERS + fe25519 *pXp; + fe25519 *pZp; + fe25519 *pXq; + fe25519 *pZq; +#endif + +} ST_curve25519ladderstepWorkingState; + +static void +curve25519_ladderstep( + ST_curve25519ladderstepWorkingState* pState +) +{ + // Implements the "ladd-1987-m-3" differential-addition-and-doubling formulas + // Source: 1987 Montgomery "Speeding the Pollard and elliptic curve methods of factorization", page 261, + // fifth and sixth displays, plus common-subexpression elimination. + // + // Notation from the explicit formulas database: + // (X2,Z2) corresponds to (xp,zp), + // (X3,Z3) corresponds to (xq,zq) + // Result (X4,Z4) (X5,Z5) expected in (xp,zp) and (xq,zq) + // + // A = X2+Z2; AA = A^2; B = X2-Z2; BB = B^2; E = AA-BB; C = X3+Z3; D = X3-Z3; + // DA = D*A; CB = C*B; t0 = DA+CB; t1 = t0^2; X5 = Z1*t1; t2 = DA-CB; + // t3 = t2^2; Z5 = X1*t3; X4 = AA*BB; t4 = a24*E; t5 = BB+t4; Z4 = E*t5 ; + // + // Re-Ordered for using less temporaries. + + fe25519 t1, t2; + + #ifdef DH_SWAP_BY_POINTERS + fe25519 *b1=pState->pXp; fe25519 *b2=pState->pZp; + fe25519 *b3=pState->pXq; fe25519 *b4=pState->pZq; + #else + fe25519 *b1=&pState->xp; fe25519 *b2=&pState->zp; + fe25519 *b3=&pState->xq; fe25519 *b4=&pState->zq; + #endif + + fe25519 *b5= &t1; fe25519 *b6=&t2; + + fe25519_add(b5,b1,b2); // A = X2+Z2 + fe25519_sub(b6,b1,b2); // B = X2-Z2 + fe25519_add(b1,b3,b4); // C = X3+Z3 + fe25519_sub(b2,b3,b4); // D = X3-Z3 + fe25519_mul(b3,b2,b5); // DA= D*A + fe25519_mul(b2,b1,b6); // CB= C*B + fe25519_add(b1,b2,b3); // T0= DA+CB + fe25519_sub(b4,b3,b2); // T2= DA-CB + fe25519_square(b3,b1); // X5==T1= T0^2 + fe25519_square(b1,b4); // T3= t2^2 + fe25519_mul(b4,b1,&pState->x0); // Z5=X1*t3 + fe25519_square(b1,b5); // AA=A^2 + fe25519_square(b5,b6); // BB=B^2 + fe25519_sub(b2,b1,b5); // E=AA-BB + fe25519_mul(b1,b5,b1); // X4= AA*BB + fe25519_mpyWith121666 (b6,b2); // T4 = a24*E + fe25519_add(b6,b6,b5); // T5 = BB + t4 + fe25519_mul(b2,b6,b2); // Z4 = E*t5 +} + +static void +curve25519_cswap( + ST_curve25519ladderstepWorkingState* state, + uint8 b +) +{ + #ifdef DH_SWAP_BY_POINTERS + swapPointersConditionally ((void **) &state->pXp,(void **) &state->pXq,b); + swapPointersConditionally ((void **) &state->pZp,(void **) &state->pZq,b); + #else + fe25519_cswap (&state->xp, &state->xq,b); + fe25519_cswap (&state->zp, &state->zq,b); + #endif +} + +#if DH_REPLACE_LAST_THREE_LADDERSTEPS_WITH_DOUBLINGS + +static void +curve25519_doublePointP (ST_curve25519ladderstepWorkingState* pState) +{ + // Implement the doubling formula "dbl-1987-m-3" + // from 1987 Montgomery "Speeding the Pollard and elliptic curve methods of factorization", + // page 261, sixth display, plus common-subexpression elimination. + // + // Three operand code: + // A = X1+Z1 + // AA = A^2 + // B = X1-Z1 + // BB = B^2 + // C = AA-BB + // X3 = AA*BB + // t0 = a24*C + // t1 = BB+t0 + // Z3 = C*t1 + + // Double the point input in the state variable "P". Use the State variable "Q" as temporary + // for storing A, AA and B, BB. Use the same temporary variable for A and AA respectively and + // B, BB respectively. + #ifdef DH_SWAP_BY_POINTERS + fe25519 *pA = pState->pXq; + fe25519 *pB = pState->pZq; + fe25519 *pX = pState->pXp; + fe25519 *pZ = pState->pZp; + #else + fe25519 *pA = &pState->xq; + fe25519 *pB = &pState->zq; + fe25519 *pX = &pState->xp; + fe25519 *pZ = &pState->zp; + #endif + + // A = X1+Z1 + fe25519_add(pA, pX, pZ); + // AA = A^2 + fe25519_square (pA,pA); + // B = X1-Z1 + fe25519_sub(pB, pX, pZ); + // BB = B^2 + fe25519_square (pB,pB); + // X3 = AA*BB + fe25519_mul (pX,pA,pB); + // C = AA-BB + fe25519_sub (pZ,pA,pB); + // t0 = a24*C + fe25519_mpyWith121666 (pA,pZ); + // t1 = BB+t0 + fe25519_add (pB,pA,pB); + // Z3 = C*t1 + fe25519_mul (pZ,pZ,pB); +} + +#endif // #ifdef DH_REPLACE_LAST_THREE_LADDERSTEPS_WITH_DOUBLINGS + +int +crypto_scalarmult_curve25519( + unsigned char* r, + const unsigned char* s, + const unsigned char* p +) +{ + ST_curve25519ladderstepWorkingState state; + unsigned char i; + + + // Prepare the scalar within the working state buffer. + for (i = 0; i < 32; i++) + { + state.s.as_uint8 [i] = s[i]; + } +#if DH_REPLACE_LAST_THREE_LADDERSTEPS_WITH_DOUBLINGS + // Due to explicit final doubling for the last three bits instead of a full ladderstep, + // the following line is no longer necessary. +#else + state.s.as_uint8 [0] &= 248; +#endif + state.s.as_uint8 [31] &= 127; + state.s.as_uint8 [31] |= 64; + + // Copy the affine x-axis of the base point to the state. + fe25519_unpack (&state.x0, p); + + // Prepare the working points within the working state struct. + + fe25519_setone (&state.zq); + fe25519_cpy (&state.xq, &state.x0); + + fe25519_setone(&state.xp); + fe25519_setzero(&state.zp); + + state.nextScalarBitToProcess = 254; + +#ifdef DH_SWAP_BY_POINTERS + // we need to initially assign the pointers correctly. + state.pXp = &state.xp; + state.pZp = &state.zp; + state.pXq = &state.xq; + state.pZq = &state.zq; +#endif + + state.previousProcessedBit = 0; + +#if DH_REPLACE_LAST_THREE_LADDERSTEPS_WITH_DOUBLINGS + // Process all the bits except for the last three where we explicitly double the result. + while (state.nextScalarBitToProcess >= 3) +#else + // Process all the bits except for the last three where we explicitly double the result. + while (state.nextScalarBitToProcess >= 0) +#endif + { + uint8 byteNo = state.nextScalarBitToProcess >> 3; + uint8 bitNo = state.nextScalarBitToProcess & 7; + uint8 bit; + uint8 swap; + + bit = 1 & (state.s.as_uint8 [byteNo] >> bitNo); + swap = bit ^ state.previousProcessedBit; + state.previousProcessedBit = bit; + curve25519_cswap(&state, swap); + curve25519_ladderstep(&state); + state.nextScalarBitToProcess --; + } + + curve25519_cswap(&state,state.previousProcessedBit); + +#if DH_REPLACE_LAST_THREE_LADDERSTEPS_WITH_DOUBLINGS + curve25519_doublePointP (&state); + curve25519_doublePointP (&state); + curve25519_doublePointP (&state); +#endif + +#ifdef DH_SWAP_BY_POINTERS + // optimize for stack usage. + fe25519_invert_useProvidedScratchBuffers (state.pZp, state.pZp, state.pXq,state.pZq,&state.x0); + fe25519_mul(state.pXp, state.pXp, state.pZp); + fe25519_reduceCompletely(state.pXp); + + fe25519_pack (r, state.pXp); +#else + // optimize for stack usage. + fe25519_invert_useProvidedScratchBuffers (&state.zp, &state.zp, &state.xq, &state.zq, &state.x0); + fe25519_mul(&state.xp, &state.xp, &state.zp); + fe25519_reduceCompletely(&state.xp); + + fe25519_pack (r, &state.xp); +#endif + + return 0; +} + +int +crypto_scalarmult_curve25519_base( + unsigned char* q, + const unsigned char* n +) +{ + static const uint8 base[32] = + { + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return crypto_scalarmult_curve25519(q, n, base); +} |