wolfssl/wolfcrypt/src/fe_x25519_128.i
2018-02-19 12:29:49 +01:00

626 lines
19 KiB
OpenEdge ABL

/* fe_x25519_128.i
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
void fe_init()
{
}
/* Convert a number represented as an array of bytes to an array of words with
* 51-bits of data in each word.
*
* in An array of bytes.
* out An array of words.
*/
void fe_frombytes(fe out, const unsigned char *in)
{
out[0] = (((int64_t)((in[ 0] ) )) )
| (((int64_t)((in[ 1] ) )) << 8)
| (((int64_t)((in[ 2] ) )) << 16)
| (((int64_t)((in[ 3] ) )) << 24)
| (((int64_t)((in[ 4] ) )) << 32)
| (((int64_t)((in[ 5] ) )) << 40)
| (((int64_t)((in[ 6] ) & 0x07)) << 48);
out[1] = (((int64_t)((in[ 6] >> 3) & 0x1f)) )
| (((int64_t)((in[ 7] ) )) << 5)
| (((int64_t)((in[ 8] ) )) << 13)
| (((int64_t)((in[ 9] ) )) << 21)
| (((int64_t)((in[10] ) )) << 29)
| (((int64_t)((in[11] ) )) << 37)
| (((int64_t)((in[12] ) & 0x3f)) << 45);
out[2] = (((int64_t)((in[12] >> 6) & 0x03)) )
| (((int64_t)((in[13] ) )) << 2)
| (((int64_t)((in[14] ) )) << 10)
| (((int64_t)((in[15] ) )) << 18)
| (((int64_t)((in[16] ) )) << 26)
| (((int64_t)((in[17] ) )) << 34)
| (((int64_t)((in[18] ) )) << 42)
| (((int64_t)((in[19] ) & 0x01)) << 50);
out[3] = (((int64_t)((in[19] >> 1) & 0x7f)) )
| (((int64_t)((in[20] ) )) << 7)
| (((int64_t)((in[21] ) )) << 15)
| (((int64_t)((in[22] ) )) << 23)
| (((int64_t)((in[23] ) )) << 31)
| (((int64_t)((in[24] ) )) << 39)
| (((int64_t)((in[25] ) & 0x0f)) << 47);
out[4] = (((int64_t)((in[25] >> 4) & 0x0f)) )
| (((int64_t)((in[26] ) )) << 4)
| (((int64_t)((in[27] ) )) << 12)
| (((int64_t)((in[28] ) )) << 20)
| (((int64_t)((in[29] ) )) << 28)
| (((int64_t)((in[30] ) )) << 36)
| (((int64_t)((in[31] ) & 0x7f)) << 44);
}
/* Convert a number represented as an array of words to an array of bytes.
* The array of words is normalized to an array of 51-bit data words and if
* greater than the mod, modulo reduced by the prime 2^255 - 1.
*
* n An array of words.
* out An array of bytes.
*/
void fe_tobytes(unsigned char *out, const fe n)
{
fe in;
int64_t c;
in[0] = n[0];
in[1] = n[1];
in[2] = n[2];
in[3] = n[3];
in[4] = n[4];
/* Normalize to 51-bits of data per word. */
in[0] += (in[4] >> 51) * 19; in[4] &= 0x7ffffffffffff;
in[1] += in[0] >> 51; in[0] &= 0x7ffffffffffff;
in[2] += in[1] >> 51; in[1] &= 0x7ffffffffffff;
in[3] += in[2] >> 51; in[2] &= 0x7ffffffffffff;
in[4] += in[3] >> 51; in[3] &= 0x7ffffffffffff;
in[0] += (in[4] >> 51) * 19;
in[4] &= 0x7ffffffffffff;
c = (in[0] + 19) >> 51;
c = (in[1] + c) >> 51;
c = (in[2] + c) >> 51;
c = (in[3] + c) >> 51;
c = (in[4] + c) >> 51;
in[0] += c * 19;
in[1] += in[0] >> 51; in[0] &= 0x7ffffffffffff;
in[2] += in[1] >> 51; in[1] &= 0x7ffffffffffff;
in[3] += in[2] >> 51; in[2] &= 0x7ffffffffffff;
in[4] += in[3] >> 51; in[3] &= 0x7ffffffffffff;
in[4] &= 0x7ffffffffffff;
out[ 0] = (((byte)((in[0] ) )) );
out[ 1] = (((byte)((in[0] >> 8) )) );
out[ 2] = (((byte)((in[0] >> 16) )) );
out[ 3] = (((byte)((in[0] >> 24) )) );
out[ 4] = (((byte)((in[0] >> 32) )) );
out[ 5] = (((byte)((in[0] >> 40) )) );
out[ 6] = (((byte)((in[0] >> 48) & 0x07)) )
| (((byte)((in[1] ) & 0x1f)) << 3);
out[ 7] = (((byte)((in[1] >> 5) )) );
out[ 8] = (((byte)((in[1] >> 13) )) );
out[ 9] = (((byte)((in[1] >> 21) )) );
out[10] = (((byte)((in[1] >> 29) )) );
out[11] = (((byte)((in[1] >> 37) )) );
out[12] = (((byte)((in[1] >> 45) & 0x3f)) )
| (((byte)((in[2] ) & 0x03)) << 6);
out[13] = (((byte)((in[2] >> 2) )) );
out[14] = (((byte)((in[2] >> 10) )) );
out[15] = (((byte)((in[2] >> 18) )) );
out[16] = (((byte)((in[2] >> 26) )) );
out[17] = (((byte)((in[2] >> 34) )) );
out[18] = (((byte)((in[2] >> 42) )) );
out[19] = (((byte)((in[2] >> 50) & 0x01)) )
| (((byte)((in[3] ) & 0x7f)) << 1);
out[20] = (((byte)((in[3] >> 7) )) );
out[21] = (((byte)((in[3] >> 15) )) );
out[22] = (((byte)((in[3] >> 23) )) );
out[23] = (((byte)((in[3] >> 31) )) );
out[24] = (((byte)((in[3] >> 39) )) );
out[25] = (((byte)((in[3] >> 47) & 0x0f)) )
| (((byte)((in[4] ) & 0x0f)) << 4);
out[26] = (((byte)((in[4] >> 4) )) );
out[27] = (((byte)((in[4] >> 12) )) );
out[28] = (((byte)((in[4] >> 20) )) );
out[29] = (((byte)((in[4] >> 28) )) );
out[30] = (((byte)((in[4] >> 36) )) );
out[31] = (((byte)((in[4] >> 44) & 0x7f)) );
}
/* Set the field element to 1.
*
* n The field element number.
*/
void fe_1(fe n)
{
n[0] = 0x0000000000001;
n[1] = 0x0000000000000;
n[2] = 0x0000000000000;
n[3] = 0x0000000000000;
n[4] = 0x0000000000000;
}
/* Set the field element to 0.
*
* n The field element number.
*/
void fe_0(fe n)
{
n[0] = 0x0000000000000;
n[1] = 0x0000000000000;
n[2] = 0x0000000000000;
n[3] = 0x0000000000000;
n[4] = 0x0000000000000;
}
/* Copy field element a into field element r.
*
* r Field element to copy into.
* a Field element to copy.
*/
void fe_copy(fe r, const fe a)
{
r[0] = a[0];
r[1] = a[1];
r[2] = a[2];
r[3] = a[3];
r[4] = a[4];
}
/* Constant time, conditional swap of field elements a and b.
*
* a A field element.
* b A field element.
* c If 1 then swap and if 0 then don't swap.
*/
void fe_cswap(fe a, fe b, int c)
{
int64_t m = c;
int64_t t0, t1, t2, t3, t4;
/* Convert conditional into mask. */
m = -m;
t0 = m & (a[0] ^ b[0]);
t1 = m & (a[1] ^ b[1]);
t2 = m & (a[2] ^ b[2]);
t3 = m & (a[3] ^ b[3]);
t4 = m & (a[4] ^ b[4]);
a[0] ^= t0;
a[1] ^= t1;
a[2] ^= t2;
a[3] ^= t3;
a[4] ^= t4;
b[0] ^= t0;
b[1] ^= t1;
b[2] ^= t2;
b[3] ^= t3;
b[4] ^= t4;
}
/* Subtract b from a into r. (r = a - b)
*
* r A field element.
* a A field element.
* b A field element.
*/
void fe_sub(fe r, const fe a, const fe b)
{
r[0] = a[0] - b[0];
r[1] = a[1] - b[1];
r[2] = a[2] - b[2];
r[3] = a[3] - b[3];
r[4] = a[4] - b[4];
}
/* Add b to a into r. (r = a + b)
*
* r A field element.
* a A field element.
* b A field element.
*/
void fe_add(fe r, const fe a, const fe b)
{
r[0] = a[0] + b[0];
r[1] = a[1] + b[1];
r[2] = a[2] + b[2];
r[3] = a[3] + b[3];
r[4] = a[4] + b[4];
}
/* Multiply a and b into r. (r = a * b)
*
* r A field element.
* a A field element.
* b A field element.
*/
void fe_mul(fe r, const fe a, const fe b)
{
const __int128_t k19 = 19;
__int128_t t0 = ((__int128_t)a[0]) * b[0];
__int128_t t1 = ((__int128_t)a[0]) * b[1]
+ ((__int128_t)a[1]) * b[0];
__int128_t t2 = ((__int128_t)a[0]) * b[2]
+ ((__int128_t)a[1]) * b[1]
+ ((__int128_t)a[2]) * b[0];
__int128_t t3 = ((__int128_t)a[0]) * b[3]
+ ((__int128_t)a[1]) * b[2]
+ ((__int128_t)a[2]) * b[1]
+ ((__int128_t)a[3]) * b[0];
__int128_t t4 = ((__int128_t)a[0]) * b[4]
+ ((__int128_t)a[1]) * b[3]
+ ((__int128_t)a[2]) * b[2]
+ ((__int128_t)a[3]) * b[1]
+ ((__int128_t)a[4]) * b[0];
__int128_t t5 = ((__int128_t)a[1]) * b[4]
+ ((__int128_t)a[2]) * b[3]
+ ((__int128_t)a[3]) * b[2]
+ ((__int128_t)a[4]) * b[1];
__int128_t t6 = ((__int128_t)a[2]) * b[4]
+ ((__int128_t)a[3]) * b[3]
+ ((__int128_t)a[4]) * b[2];
__int128_t t7 = ((__int128_t)a[3]) * b[4]
+ ((__int128_t)a[4]) * b[3];
__int128_t t8 = ((__int128_t)a[4]) * b[4];
/* Modulo reduce double long word. */
t0 += t5 * k19;
t1 += t6 * k19;
t2 += t7 * k19;
t3 += t8 * k19;
/* Normalize to 51-bits of data per word. */
t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;
t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
r[0] += (t4 >> 51) * k19;
r[4] = t4 & 0x7ffffffffffff;
}
/* Square a and put result in r. (r = a * a)
*
* r A field element.
* a A field element.
* b A field element.
*/
void fe_sq(fe r, const fe a)
{
const __int128_t k19 = 19;
const __int128_t k2 = 2;
__int128_t t0 = ((__int128_t)a[0]) * a[0];
__int128_t t1 = ((__int128_t)a[0]) * a[1] * k2;
__int128_t t2 = ((__int128_t)a[0]) * a[2] * k2
+ ((__int128_t)a[1]) * a[1];
__int128_t t3 = ((__int128_t)a[0]) * a[3] * k2
+ ((__int128_t)a[1]) * a[2] * k2;
__int128_t t4 = ((__int128_t)a[0]) * a[4] * k2
+ ((__int128_t)a[1]) * a[3] * k2
+ ((__int128_t)a[2]) * a[2];
__int128_t t5 = ((__int128_t)a[1]) * a[4] * k2
+ ((__int128_t)a[2]) * a[3] * k2;
__int128_t t6 = ((__int128_t)a[2]) * a[4] * k2
+ ((__int128_t)a[3]) * a[3];
__int128_t t7 = ((__int128_t)a[3]) * a[4] * k2;
__int128_t t8 = ((__int128_t)a[4]) * a[4];
/* Modulo reduce double long word. */
t0 += t5 * k19;
t1 += t6 * k19;
t2 += t7 * k19;
t3 += t8 * k19;
/* Normalize to 51-bits of data per word. */
t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;
t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
r[0] += (t4 >> 51) * k19;
r[4] = t4 & 0x7ffffffffffff;
}
/* Multiply a by 121666 and put result in r. (r = 121666 * a)
*
* r A field element.
* a A field element.
* b A field element.
*/
void fe_mul121666(fe r, fe a)
{
const __int128_t k19 = 19;
const __int128_t k121666 = 121666;
__int128_t t0 = ((__int128_t)a[0]) * k121666;
__int128_t t1 = ((__int128_t)a[1]) * k121666;
__int128_t t2 = ((__int128_t)a[2]) * k121666;
__int128_t t3 = ((__int128_t)a[3]) * k121666;
__int128_t t4 = ((__int128_t)a[4]) * k121666;
/* Normalize to 51-bits of data per word. */
t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;
t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
r[0] += (t4 >> 51) * k19;
r[4] = t4 & 0x7ffffffffffff;
}
/* Find the inverse of a modulo 2^255 - 1 and put result in r.
* (r * a) mod (2^255 - 1) = 1
* Implementation is constant time.
*
* r A field element.
* a A field element.
*/
void fe_invert(fe r, const fe a)
{
fe t0, t1, t2, t3;
int i;
/* a ^ (2^255 - 21) */
fe_sq(t0, a); for (i = 1; i < 1; ++i) fe_sq(t0, t0);
fe_sq(t1, t0); for (i = 1; i < 2; ++i) fe_sq(t1, t1); fe_mul(t1, a, t1);
fe_mul(t0, t0, t1);
fe_sq(t2, t0); for (i = 1; i < 1; ++i) fe_sq(t2, t2); fe_mul(t1, t1, t2);
fe_sq(t2, t1); for (i = 1; i < 5; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
fe_sq(t2, t1); for (i = 1; i < 10; ++i) fe_sq(t2, t2); fe_mul(t2, t2, t1);
fe_sq(t3, t2); for (i = 1; i < 20; ++i) fe_sq(t3, t3); fe_mul(t2, t3, t2);
fe_sq(t2, t2); for (i = 1; i < 10; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
fe_sq(t2, t1); for (i = 1; i < 50; ++i) fe_sq(t2, t2); fe_mul(t2, t2, t1);
fe_sq(t3, t2); for (i = 1; i < 100; ++i) fe_sq(t3, t3); fe_mul(t2, t3, t2);
fe_sq(t2, t2); for (i = 1; i < 50; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
fe_sq(t1, t1); for (i = 1; i < 5; ++i) fe_sq(t1, t1); fe_mul( r, t1, t0);
}
#ifndef CURVE25519_SMALL
/* Scalar multiply the field element a by n using Montgomery Ladder and places
* result in r.
*
* r A field element as an array of bytes.
* n The scalar as an array of bytes.
* a A field element as an array of bytes.
*/
int curve25519(byte* r, byte* n, byte* a)
{
fe x1, x2, z2, x3, z3;
fe t0, t1;
int pos;
unsigned int swap;
unsigned int b;
fe_frombytes(x1, a);
fe_1(x2);
fe_0(z2);
fe_copy(x3, x1);
fe_1(z3);
swap = 0;
for (pos = 254;pos >= 0;--pos) {
b = n[pos / 8] >> (pos & 7);
b &= 1;
swap ^= b;
fe_cswap(x2, x3, swap);
fe_cswap(z2, z3, swap);
swap = b;
fe_sub(t0, x3, z3);
fe_sub(t1, x2, z2);
fe_add(x2, x2, z2);
fe_add(z2, x3, z3);
fe_mul(z3, t0, x2);
fe_mul(z2, z2, t1);
fe_sq(t0, t1);
fe_sq(t1, x2);
fe_add(x3, z3, z2);
fe_sub(z2, z3, z2);
fe_mul(x2, t1, t0);
fe_sub(t1, t1, t0);
fe_sq(z2, z2);
fe_mul121666(z3, t1);
fe_sq(x3, x3);
fe_add(t0, t0, z3);
fe_mul(z3, x1, z2);
fe_mul(z2, t1, t0);
}
fe_cswap(x2, x3, swap);
fe_cswap(z2, z3, swap);
fe_invert(z2, z2);
fe_mul(x2, x2, z2);
fe_tobytes(r, x2);
return 0;
}
#endif /* !CURVE25519_SMALL */
/* The field element value 0 as an array of bytes. */
static const unsigned char zero[32] = {0};
/* Constant time check as to whether a is not 0.
*
* a A field element.
*/
int fe_isnonzero(const fe a)
{
unsigned char s[32];
fe_tobytes(s, a);
return ConstantCompare(s, zero, 32);
}
/* Checks whether a is negative.
*
* a A field element.
*/
int fe_isnegative(const fe a)
{
unsigned char s[32];
fe_tobytes(s, a);
return s[0] & 1;
}
/* Negates field element a and stores the result in r.
*
* r A field element.
* a A field element.
*/
void fe_neg(fe r, const fe a)
{
r[0] = -a[0];
r[1] = -a[1];
r[2] = -a[2];
r[3] = -a[3];
r[4] = -a[4];
}
/* Constant time, conditional move of b into a.
* a is not changed if the condition is 0.
*
* a A field element.
* b A field element.
* c If 1 then copy and if 0 then don't copy.
*/
void fe_cmov(fe a, const fe b, int c)
{
int64_t m = c;
int64_t t0, t1, t2, t3, t4;
/* Convert conditional into mask. */
m = -m;
t0 = m & (a[0] ^ b[0]);
t1 = m & (a[1] ^ b[1]);
t2 = m & (a[2] ^ b[2]);
t3 = m & (a[3] ^ b[3]);
t4 = m & (a[4] ^ b[4]);
a[0] ^= t0;
a[1] ^= t1;
a[2] ^= t2;
a[3] ^= t3;
a[4] ^= t4;
}
void fe_pow22523(fe r, const fe a)
{
fe t0, t1, t2;
int i;
/* a ^ (2^255 - 23) */
fe_sq(t0, a); for (i = 1; i < 1; ++i) fe_sq(t0, t0);
fe_sq(t1, t0); for (i = 1; i < 2; ++i) fe_sq(t1, t1); fe_mul(t1, a, t1);
fe_mul(t0, t0, t1);
fe_sq(t0, t0); for (i = 1; i < 1; ++i) fe_sq(t0, t0); fe_mul(t0, t1, t0);
fe_sq(t1, t0); for (i = 1; i < 5; ++i) fe_sq(t1, t1); fe_mul(t0, t1, t0);
fe_sq(t1, t0); for (i = 1; i < 10; ++i) fe_sq(t1, t1); fe_mul(t1, t1, t0);
fe_sq(t2, t1); for (i = 1; i < 20; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
fe_sq(t1, t1); for (i = 1; i < 10; ++i) fe_sq(t1, t1); fe_mul(t0, t1, t0);
fe_sq(t1, t0); for (i = 1; i < 50; ++i) fe_sq(t1, t1); fe_mul(t1, t1, t0);
fe_sq(t2, t1); for (i = 1; i < 100; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
fe_sq(t1, t1); for (i = 1; i < 50; ++i) fe_sq(t1, t1); fe_mul(t0, t1, t0);
fe_sq(t0, t0); for (i = 1; i < 2; ++i) fe_sq(t0, t0); fe_mul( r, t0, a);
return;
}
/* Double the square of a and put result in r. (r = 2 * a * a)
*
* r A field element.
* a A field element.
* b A field element.
*/
void fe_sq2(fe r, const fe a)
{
const __int128_t k2 = 2;
const __int128_t k19 = 19;
__int128_t t0 = k2 * (((__int128_t)a[0]) * a[0]);
__int128_t t1 = k2 * (((__int128_t)a[0]) * a[1] * k2);
__int128_t t2 = k2 * (((__int128_t)a[0]) * a[2] * k2
+ ((__int128_t)a[1]) * a[1]);
__int128_t t3 = k2 * (((__int128_t)a[0]) * a[3] * k2
+ ((__int128_t)a[1]) * a[2] * k2);
__int128_t t4 = k2 * (((__int128_t)a[0]) * a[4] * k2
+ ((__int128_t)a[1]) * a[3] * k2
+ ((__int128_t)a[2]) * a[2]);
__int128_t t5 = k2 * (((__int128_t)a[1]) * a[4] * k2
+ ((__int128_t)a[2]) * a[3] * k2);
__int128_t t6 = k2 * (((__int128_t)a[2]) * a[4] * k2
+ ((__int128_t)a[3]) * a[3]);
__int128_t t7 = k2 * (((__int128_t)a[3]) * a[4] * k2);
__int128_t t8 = k2 * (((__int128_t)a[4]) * a[4]);
/* Modulo reduce double long word. */
t0 += t5 * k19;
t1 += t6 * k19;
t2 += t7 * k19;
t3 += t8 * k19;
/* Normalize to 51-bits of data per word. */
t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;
t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
r[0] += (t4 >> 51) * k19;
r[4] = t4 & 0x7ffffffffffff;
}
/* Load 3 little endian bytes into a 64-bit word.
*
* in An array of bytes.
* returns a 64-bit word.
*/
uint64_t load_3(const unsigned char *in)
{
uint64_t result;
result = ((((uint64_t)in[0]) ) |
(((uint64_t)in[1]) << 8) |
(((uint64_t)in[2]) << 16));
return result;
}
/* Load 4 little endian bytes into a 64-bit word.
*
* in An array of bytes.
* returns a 64-bit word.
*/
uint64_t load_4(const unsigned char *in)
{
uint64_t result;
result = ((((uint64_t)in[0]) ) |
(((uint64_t)in[1]) << 8) |
(((uint64_t)in[2]) << 16) |
(((uint64_t)in[3]) << 24));
return result;
}