Patch improved speed

This commit is contained in:
Hakase
2018-04-02 22:35:58 +09:00
parent 52a6a72200
commit 82a44d2483
11 changed files with 3102 additions and 237 deletions
+483 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -7,14 +7,489 @@
* https://www.openssl.org/source/license.html
*/
/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
* 20141124 (http://bench.cr.yp.to/supercop.html).
*
* The field functions are shared by Ed25519 and X25519 where possible. */
#include <string.h>
#include "ec_lcl.h"
#include <openssl/sha.h>
#if !defined(PEDANTIC) && \
(defined(__SIZEOF_INT128__) && __SIZEOF_INT128__==16)
/*
* Base 2^51 implementation.
*/
# define BASE_2_51_IMPLEMENTED
typedef uint64_t fe51[5];
typedef unsigned __int128 u128;
static const uint64_t MASK51 = 0x7ffffffffffff;
static uint64_t load_7(const uint8_t *in)
{
uint64_t result;
result = in[0];
result |= ((uint64_t)in[1]) << 8;
result |= ((uint64_t)in[2]) << 16;
result |= ((uint64_t)in[3]) << 24;
result |= ((uint64_t)in[4]) << 32;
result |= ((uint64_t)in[5]) << 40;
result |= ((uint64_t)in[6]) << 48;
return result;
}
static uint64_t load_6(const uint8_t *in)
{
uint64_t result;
result = in[0];
result |= ((uint64_t)in[1]) << 8;
result |= ((uint64_t)in[2]) << 16;
result |= ((uint64_t)in[3]) << 24;
result |= ((uint64_t)in[4]) << 32;
result |= ((uint64_t)in[5]) << 40;
return result;
}
static void fe51_frombytes(fe51 h, const uint8_t *s)
{
uint64_t h0 = load_7(s); /* 56 bits */
uint64_t h1 = load_6(s + 7) << 5; /* 53 bits */
uint64_t h2 = load_7(s + 13) << 2; /* 58 bits */
uint64_t h3 = load_6(s + 20) << 7; /* 55 bits */
uint64_t h4 = (load_6(s + 26) & 0x7fffffffffff) << 4; /* 51 bits */
h1 |= h0 >> 51; h0 &= MASK51;
h2 |= h1 >> 51; h1 &= MASK51;
h3 |= h2 >> 51; h2 &= MASK51;
h4 |= h3 >> 51; h3 &= MASK51;
h[0] = h0;
h[1] = h1;
h[2] = h2;
h[3] = h3;
h[4] = h4;
}
static void fe51_tobytes(uint8_t *s, const fe51 h)
{
uint64_t h0 = h[0];
uint64_t h1 = h[1];
uint64_t h2 = h[2];
uint64_t h3 = h[3];
uint64_t h4 = h[4];
uint64_t q;
/* compare to modulus */
q = (h0 + 19) >> 51;
q = (h1 + q) >> 51;
q = (h2 + q) >> 51;
q = (h3 + q) >> 51;
q = (h4 + q) >> 51;
/* full reduce */
h0 += 19 * q;
h1 += h0 >> 51; h0 &= MASK51;
h2 += h1 >> 51; h1 &= MASK51;
h3 += h2 >> 51; h2 &= MASK51;
h4 += h3 >> 51; h3 &= MASK51;
h4 &= MASK51;
/* smash */
s[0] = h0 >> 0;
s[1] = h0 >> 8;
s[2] = h0 >> 16;
s[3] = h0 >> 24;
s[4] = h0 >> 32;
s[5] = h0 >> 40;
s[6] = (h0 >> 48) | ((uint32_t)h1 << 3);
s[7] = h1 >> 5;
s[8] = h1 >> 13;
s[9] = h1 >> 21;
s[10] = h1 >> 29;
s[11] = h1 >> 37;
s[12] = (h1 >> 45) | ((uint32_t)h2 << 6);
s[13] = h2 >> 2;
s[14] = h2 >> 10;
s[15] = h2 >> 18;
s[16] = h2 >> 26;
s[17] = h2 >> 34;
s[18] = h2 >> 42;
s[19] = (h2 >> 50) | ((uint32_t)h3 << 1);
s[20] = h3 >> 7;
s[21] = h3 >> 15;
s[22] = h3 >> 23;
s[23] = h3 >> 31;
s[24] = h3 >> 39;
s[25] = (h3 >> 47) | ((uint32_t)h4 << 4);
s[26] = h4 >> 4;
s[27] = h4 >> 12;
s[28] = h4 >> 20;
s[29] = h4 >> 28;
s[30] = h4 >> 36;
s[31] = h4 >> 44;
}
static void fe51_mul(fe51 h, const fe51 f, const fe51 g)
{
u128 h0, h1, h2, h3, h4;
uint64_t f_i, g0, g1, g2, g3, g4;
f_i = f[0];
h0 = (u128)f_i * (g0 = g[0]);
h1 = (u128)f_i * (g1 = g[1]);
h2 = (u128)f_i * (g2 = g[2]);
h3 = (u128)f_i * (g3 = g[3]);
h4 = (u128)f_i * (g4 = g[4]);
f_i = f[1];
h0 += (u128)f_i * (g4 *= 19);
h1 += (u128)f_i * g0;
h2 += (u128)f_i * g1;
h3 += (u128)f_i * g2;
h4 += (u128)f_i * g3;
f_i = f[2];
h0 += (u128)f_i * (g3 *= 19);
h1 += (u128)f_i * g4;
h2 += (u128)f_i * g0;
h3 += (u128)f_i * g1;
h4 += (u128)f_i * g2;
f_i = f[3];
h0 += (u128)f_i * (g2 *= 19);
h1 += (u128)f_i * g3;
h2 += (u128)f_i * g4;
h3 += (u128)f_i * g0;
h4 += (u128)f_i * g1;
f_i = f[4];
h0 += (u128)f_i * (g1 *= 19);
h1 += (u128)f_i * g2;
h2 += (u128)f_i * g3;
h3 += (u128)f_i * g4;
h4 += (u128)f_i * g0;
/* partial [lazy] reduction */
h3 += (uint64_t)(h2 >> 51); g2 = (uint64_t)h2 & MASK51;
h1 += (uint64_t)(h0 >> 51); g0 = (uint64_t)h0 & MASK51;
h4 += (uint64_t)(h3 >> 51); g3 = (uint64_t)h3 & MASK51;
g2 += (uint64_t)(h1 >> 51); g1 = (uint64_t)h1 & MASK51;
g0 += (uint64_t)(h4 >> 51) * 19; g4 = (uint64_t)h4 & MASK51;
g3 += g2 >> 51; g2 &= MASK51;
g1 += g0 >> 51; g0 &= MASK51;
h[0] = g0;
h[1] = g1;
h[2] = g2;
h[3] = g3;
h[4] = g4;
}
static void fe51_sq(fe51 h, const fe51 f)
{
# if defined(OPENSSL_SMALL_FOOTPRINT)
fe51_mul(h, f, f);
# else
/* dedicated squaring gives 16-25% overall improvement */
uint64_t g0 = f[0];
uint64_t g1 = f[1];
uint64_t g2 = f[2];
uint64_t g3 = f[3];
uint64_t g4 = f[4];
u128 h0, h1, h2, h3, h4;
h0 = (u128)g0 * g0; g0 *= 2;
h1 = (u128)g0 * g1;
h2 = (u128)g0 * g2;
h3 = (u128)g0 * g3;
h4 = (u128)g0 * g4;
g0 = g4; /* borrow g0 */
h3 += (u128)g0 * (g4 *= 19);
h2 += (u128)g1 * g1; g1 *= 2;
h3 += (u128)g1 * g2;
h4 += (u128)g1 * g3;
h0 += (u128)g1 * g4;
g0 = g3; /* borrow g0 */
h1 += (u128)g0 * (g3 *= 19);
h2 += (u128)(g0 * 2) * g4;
h4 += (u128)g2 * g2; g2 *= 2;
h0 += (u128)g2 * g3;
h1 += (u128)g2 * g4;
/* partial [lazy] reduction */
h3 += (uint64_t)(h2 >> 51); g2 = (uint64_t)h2 & MASK51;
h1 += (uint64_t)(h0 >> 51); g0 = (uint64_t)h0 & MASK51;
h4 += (uint64_t)(h3 >> 51); g3 = (uint64_t)h3 & MASK51;
g2 += (uint64_t)(h1 >> 51); g1 = (uint64_t)h1 & MASK51;
g0 += (uint64_t)(h4 >> 51) * 19; g4 = (uint64_t)h4 & MASK51;
g3 += g2 >> 51; g2 &= MASK51;
g1 += g0 >> 51; g0 &= MASK51;
h[0] = g0;
h[1] = g1;
h[2] = g2;
h[3] = g3;
h[4] = g4;
# endif
}
static void fe51_add(fe51 h, const fe51 f, const fe51 g)
{
h[0] = f[0] + g[0];
h[1] = f[1] + g[1];
h[2] = f[2] + g[2];
h[3] = f[3] + g[3];
h[4] = f[4] + g[4];
}
static void fe51_sub(fe51 h, const fe51 f, const fe51 g)
{
/*
* Add 2*modulus to ensure that result remains positive
* even if subtrahend is partially reduced.
*/
h[0] = (f[0] + 0xfffffffffffda) - g[0];
h[1] = (f[1] + 0xffffffffffffe) - g[1];
h[2] = (f[2] + 0xffffffffffffe) - g[2];
h[3] = (f[3] + 0xffffffffffffe) - g[3];
h[4] = (f[4] + 0xffffffffffffe) - g[4];
}
static void fe51_0(fe51 h)
{
h[0] = 0;
h[1] = 0;
h[2] = 0;
h[3] = 0;
h[4] = 0;
}
static void fe51_1(fe51 h)
{
h[0] = 1;
h[1] = 0;
h[2] = 0;
h[3] = 0;
h[4] = 0;
}
static void fe51_copy(fe51 h, const fe51 f)
{
h[0] = f[0];
h[1] = f[1];
h[2] = f[2];
h[3] = f[3];
h[4] = f[4];
}
static void fe51_cswap(fe51 f, fe51 g, unsigned int b)
{
int i;
uint64_t mask = 0 - (uint64_t)b;
for (i = 0; i < 5; i++) {
int64_t x = f[i] ^ g[i];
x &= mask;
f[i] ^= x;
g[i] ^= x;
}
}
static void fe51_invert(fe51 out, const fe51 z)
{
fe51 t0;
fe51 t1;
fe51 t2;
fe51 t3;
int i;
/*
* Compute z ** -1 = z ** (2 ** 255 - 19 - 2) with the exponent as
* 2 ** 255 - 21 = (2 ** 5) * (2 ** 250 - 1) + 11.
*/
/* t0 = z ** 2 */
fe51_sq(t0, z);
/* t1 = t0 ** (2 ** 2) = z ** 8 */
fe51_sq(t1, t0);
fe51_sq(t1, t1);
/* t1 = z * t1 = z ** 9 */
fe51_mul(t1, z, t1);
/* t0 = t0 * t1 = z ** 11 -- stash t0 away for the end. */
fe51_mul(t0, t0, t1);
/* t2 = t0 ** 2 = z ** 22 */
fe51_sq(t2, t0);
/* t1 = t1 * t2 = z ** (2 ** 5 - 1) */
fe51_mul(t1, t1, t2);
/* t2 = t1 ** (2 ** 5) = z ** ((2 ** 5) * (2 ** 5 - 1)) */
fe51_sq(t2, t1);
for (i = 1; i < 5; ++i)
fe51_sq(t2, t2);
/* t1 = t1 * t2 = z ** ((2 ** 5 + 1) * (2 ** 5 - 1)) = z ** (2 ** 10 - 1) */
fe51_mul(t1, t2, t1);
/* Continuing similarly... */
/* t2 = z ** (2 ** 20 - 1) */
fe51_sq(t2, t1);
for (i = 1; i < 10; ++i)
fe51_sq(t2, t2);
fe51_mul(t2, t2, t1);
/* t2 = z ** (2 ** 40 - 1) */
fe51_sq(t3, t2);
for (i = 1; i < 20; ++i)
fe51_sq(t3, t3);
fe51_mul(t2, t3, t2);
/* t2 = z ** (2 ** 10) * (2 ** 40 - 1) */
for (i = 0; i < 10; ++i)
fe51_sq(t2, t2);
/* t1 = z ** (2 ** 50 - 1) */
fe51_mul(t1, t2, t1);
/* t2 = z ** (2 ** 100 - 1) */
fe51_sq(t2, t1);
for (i = 1; i < 50; ++i)
fe51_sq(t2, t2);
fe51_mul(t2, t2, t1);
/* t2 = z ** (2 ** 200 - 1) */
fe51_sq(t3, t2);
for (i = 1; i < 100; ++i)
fe51_sq(t3, t3);
fe51_mul(t2, t3, t2);
/* t2 = z ** ((2 ** 50) * (2 ** 200 - 1) */
for (i = 0; i < 50; ++i)
fe51_sq(t2, t2);
/* t1 = z ** (2 ** 250 - 1) */
fe51_mul(t1, t2, t1);
/* t1 = z ** ((2 ** 5) * (2 ** 250 - 1)) */
for (i = 0; i < 5; ++i)
fe51_sq(t1, t1);
/* Recall t0 = z ** 11; out = z ** (2 ** 255 - 21) */
fe51_mul(out, t1, t0);
}
static void fe51_mul121666(fe51 h, fe51 f)
{
u128 h0 = f[0] * (u128)121666;
u128 h1 = f[1] * (u128)121666;
u128 h2 = f[2] * (u128)121666;
u128 h3 = f[3] * (u128)121666;
u128 h4 = f[4] * (u128)121666;
uint64_t g0, g1, g2, g3, g4;
h3 += (uint64_t)(h2 >> 51); g2 = (uint64_t)h2 & MASK51;
h1 += (uint64_t)(h0 >> 51); g0 = (uint64_t)h0 & MASK51;
h4 += (uint64_t)(h3 >> 51); g3 = (uint64_t)h3 & MASK51;
g2 += (uint64_t)(h1 >> 51); g1 = (uint64_t)h1 & MASK51;
g0 += (uint64_t)(h4 >> 51) * 19; g4 = (uint64_t)h4 & MASK51;
g3 += g2 >> 51; g2 &= MASK51;
g1 += g0 >> 51; g0 &= MASK51;
h[0] = g0;
h[1] = g1;
h[2] = g2;
h[3] = g3;
h[4] = g4;
}
/*
* Duplicate of original x25519_scalar_mult_generic, but using
* fe51_* subroutines.
*/
static void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32])
{
fe51 x1, x2, z2, x3, z3, tmp0, tmp1;
uint8_t e[32];
unsigned swap = 0;
int pos;
memcpy(e, scalar, 32);
e[0] &= 0xf8;
e[31] &= 0x7f;
e[31] |= 0x40;
fe51_frombytes(x1, point);
fe51_1(x2);
fe51_0(z2);
fe51_copy(x3, x1);
fe51_1(z3);
for (pos = 254; pos >= 0; --pos) {
unsigned int b = 1 & (e[pos / 8] >> (pos & 7));
swap ^= b;
fe51_cswap(x2, x3, swap);
fe51_cswap(z2, z3, swap);
swap = b;
fe51_sub(tmp0, x3, z3);
fe51_sub(tmp1, x2, z2);
fe51_add(x2, x2, z2);
fe51_add(z2, x3, z3);
fe51_mul(z3, tmp0, x2);
fe51_mul(z2, z2, tmp1);
fe51_sq(tmp0, tmp1);
fe51_sq(tmp1, x2);
fe51_add(x3, z3, z2);
fe51_sub(z2, z3, z2);
fe51_mul(x2, tmp1, tmp0);
fe51_sub(tmp1, tmp1, tmp0);
fe51_sq(z2, z2);
fe51_mul121666(z3, tmp1);
fe51_sq(x3, x3);
fe51_add(tmp0, tmp0, z3);
fe51_mul(z3, x1, z2);
fe51_mul(z2, tmp1, tmp0);
}
fe51_cswap(x2, x3, swap);
fe51_cswap(z2, z3, swap);
fe51_invert(z2, z2);
fe51_mul(x2, x2, z2);
fe51_tobytes(out, x2);
OPENSSL_cleanse(e, sizeof(e));
}
#endif
/*
* Reference base 2^25.5 implementation.
*/
/*
* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
* 20141124 (http://bench.cr.yp.to/supercop.html).
*
* The field functions are shared by Ed25519 and X25519 where possible.
*/
/* fe means field element. Here the field is \Z/(2^255-19). An element t,
* entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
@@ -3230,6 +3705,7 @@ static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
OPENSSL_cleanse(e, sizeof(e));
}
#if !defined(BASE_2_51_IMPLEMENTED)
/* Replace (f,g) with (g,f) if b == 1;
* replace (f,g) with (f,g) if b == 0.
*
@@ -3366,6 +3842,7 @@ static void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32]) {
x25519_scalar_mult_generic(out, scalar, point);
}
#endif
int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
const uint8_t peer_public_value[32]) {