2018-12-11 21:17:56 +00:00
|
|
|
// donna_64.cpp - written and placed in public domain by Jeffrey Walton
|
2018-12-13 18:25:22 +00:00
|
|
|
// This is a integration of Andrew Moon's public domain code.
|
|
|
|
// Also see curve25519-donna-64bit.h.
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-14 07:14:20 +00:00
|
|
|
// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]",
|
2018-12-13 23:50:42 +00:00
|
|
|
// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658
|
|
|
|
|
2018-12-11 21:17:56 +00:00
|
|
|
#include "pch.h"
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "donna.h"
|
2018-12-13 23:50:42 +00:00
|
|
|
#include "secblock.h"
|
2018-12-13 18:25:22 +00:00
|
|
|
#include "misc.h"
|
2018-12-13 15:19:54 +00:00
|
|
|
#include "cpu.h"
|
2018-12-11 21:17:56 +00:00
|
|
|
|
|
|
|
// Squash MS LNK4221 and libtool warnings
|
|
|
|
extern const char DONNA64_FNAME[] = __FILE__;
|
|
|
|
|
2018-12-14 01:34:39 +00:00
|
|
|
#if defined(CRYPTOPP_CURVE25519_64BIT)
|
2018-12-11 21:17:56 +00:00
|
|
|
|
|
|
|
ANONYMOUS_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
using std::memcpy;
|
|
|
|
using CryptoPP::byte;
|
|
|
|
using CryptoPP::word32;
|
|
|
|
using CryptoPP::sword32;
|
2018-12-13 18:25:22 +00:00
|
|
|
using CryptoPP::word64;
|
2018-12-11 21:17:56 +00:00
|
|
|
using CryptoPP::sword64;
|
|
|
|
using CryptoPP::word128;
|
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
using CryptoPP::GetBlock;
|
|
|
|
using CryptoPP::LittleEndian;
|
|
|
|
|
|
|
|
typedef word64 bignum25519[5];
|
|
|
|
|
|
|
|
#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);
|
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n)
|
|
|
|
|
2018-12-13 19:17:36 +00:00
|
|
|
const byte basePoint[32] = {9};
|
2018-12-13 18:25:22 +00:00
|
|
|
const word64 reduce_mask_51 = ((word64)1 << 51) - 1;
|
2018-12-14 07:14:20 +00:00
|
|
|
// const word64 reduce_mask_52 = ((word64)1 << 52) - 1;
|
2018-12-13 18:25:22 +00:00
|
|
|
|
|
|
|
/* out = in */
|
|
|
|
inline void
|
|
|
|
curve25519_copy(bignum25519 out, const bignum25519 in) {
|
2018-12-13 23:50:42 +00:00
|
|
|
out[0] = in[0]; out[1] = in[1];
|
|
|
|
out[2] = in[2]; out[3] = in[3];
|
2018-12-13 18:25:22 +00:00
|
|
|
out[4] = in[4];
|
|
|
|
}
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
/* out = a + b */
|
|
|
|
inline void
|
|
|
|
curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) {
|
|
|
|
out[0] = a[0] + b[0];
|
|
|
|
out[1] = a[1] + b[1];
|
|
|
|
out[2] = a[2] + b[2];
|
|
|
|
out[3] = a[3] + b[3];
|
|
|
|
out[4] = a[4] + b[4];
|
|
|
|
}
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
const word64 two54m152 = (((word64)1) << 54) - 152;
|
|
|
|
const word64 two54m8 = (((word64)1) << 54) - 8;
|
2018-12-13 18:25:22 +00:00
|
|
|
|
|
|
|
/* out = a - b */
|
|
|
|
inline void
|
|
|
|
curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) {
|
2018-12-13 23:50:42 +00:00
|
|
|
out[0] = a[0] + two54m152 - b[0];
|
|
|
|
out[1] = a[1] + two54m8 - b[1];
|
|
|
|
out[2] = a[2] + two54m8 - b[2];
|
|
|
|
out[3] = a[3] + two54m8 - b[3];
|
|
|
|
out[4] = a[4] + two54m8 - b[4];
|
2018-12-13 18:25:22 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
/* out = (in * scalar) */
|
2018-12-13 18:25:22 +00:00
|
|
|
inline void
|
2018-12-13 23:50:42 +00:00
|
|
|
curve25519_scalar_product(bignum25519 out, const bignum25519 in, const word64 scalar) {
|
|
|
|
word128 a;
|
|
|
|
word64 c;
|
2018-12-13 18:25:22 +00:00
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
#if defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
a = ((word128) in[0]) * scalar; out[0] = (word64)a & reduce_mask_51; c = (word64)(a >> 51);
|
|
|
|
a = ((word128) in[1]) * scalar + c; out[1] = (word64)a & reduce_mask_51; c = (word64)(a >> 51);
|
|
|
|
a = ((word128) in[2]) * scalar + c; out[2] = (word64)a & reduce_mask_51; c = (word64)(a >> 51);
|
|
|
|
a = ((word128) in[3]) * scalar + c; out[3] = (word64)a & reduce_mask_51; c = (word64)(a >> 51);
|
|
|
|
a = ((word128) in[4]) * scalar + c; out[4] = (word64)a & reduce_mask_51; c = (word64)(a >> 51);
|
|
|
|
out[0] += c * 19;
|
|
|
|
#else
|
|
|
|
mul64x64_128(a, in[0], scalar) out[0] = lo128(a) & reduce_mask_51; shr128(c, a, 51);
|
|
|
|
mul64x64_128(a, in[1], scalar) add128_64(a, c) out[1] = lo128(a) & reduce_mask_51; shr128(c, a, 51);
|
|
|
|
mul64x64_128(a, in[2], scalar) add128_64(a, c) out[2] = lo128(a) & reduce_mask_51; shr128(c, a, 51);
|
|
|
|
mul64x64_128(a, in[3], scalar) add128_64(a, c) out[3] = lo128(a) & reduce_mask_51; shr128(c, a, 51);
|
|
|
|
mul64x64_128(a, in[4], scalar) add128_64(a, c) out[4] = lo128(a) & reduce_mask_51; shr128(c, a, 51);
|
|
|
|
out[0] += c * 19;
|
|
|
|
#endif
|
2018-12-13 18:25:22 +00:00
|
|
|
}
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
/* out = a * b */
|
|
|
|
inline void
|
2018-12-13 23:50:42 +00:00
|
|
|
curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) {
|
2018-12-13 18:25:22 +00:00
|
|
|
#if !defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
word128 mul;
|
|
|
|
#endif
|
|
|
|
word128 t[5];
|
|
|
|
word64 r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
|
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
r0 = b[0]; r1 = b[1]; r2 = b[2]; r3 = b[3]; r4 = b[4];
|
|
|
|
s0 = a[0]; s1 = a[1]; s2 = a[2]; s3 = a[3]; s4 = a[4];
|
2018-12-13 18:25:22 +00:00
|
|
|
|
|
|
|
#if defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
t[0] = ((word128) r0) * s0;
|
|
|
|
t[1] = ((word128) r0) * s1 + ((word128) r1) * s0;
|
|
|
|
t[2] = ((word128) r0) * s2 + ((word128) r2) * s0 + ((word128) r1) * s1;
|
|
|
|
t[3] = ((word128) r0) * s3 + ((word128) r3) * s0 + ((word128) r1) * s2 + ((word128) r2) * s1;
|
|
|
|
t[4] = ((word128) r0) * s4 + ((word128) r4) * s0 + ((word128) r3) * s1 + ((word128) r1) * s3 + ((word128) r2) * s2;
|
|
|
|
#else
|
|
|
|
mul64x64_128(t[0], r0, s0)
|
|
|
|
mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul)
|
|
|
|
mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul)
|
|
|
|
mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul)
|
|
|
|
mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul)
|
|
|
|
#endif
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
r1 *= 19; r2 *= 19; r3 *= 19; r4 *= 19;
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
#if defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
t[0] += ((word128) r4) * s1 + ((word128) r1) * s4 + ((word128) r2) * s3 + ((word128) r3) * s2;
|
|
|
|
t[1] += ((word128) r4) * s2 + ((word128) r2) * s4 + ((word128) r3) * s3;
|
|
|
|
t[2] += ((word128) r4) * s3 + ((word128) r3) * s4;
|
|
|
|
t[3] += ((word128) r4) * s4;
|
|
|
|
#else
|
|
|
|
mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul)
|
|
|
|
mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul)
|
|
|
|
mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul)
|
|
|
|
mul64x64_128(mul, r4, s4) add128(t[3], mul)
|
|
|
|
#endif
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51);
|
|
|
|
add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51);
|
|
|
|
add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51);
|
|
|
|
add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51);
|
|
|
|
add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51);
|
|
|
|
r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51;
|
|
|
|
r1 += c;
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4;
|
2018-12-11 21:17:56 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
/* out = in^(2 * count) */
|
2018-12-13 23:50:42 +00:00
|
|
|
inline void
|
2018-12-13 18:25:22 +00:00
|
|
|
curve25519_square_times(bignum25519 out, const bignum25519 in, word64 count) {
|
|
|
|
#if !defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
word128 mul;
|
|
|
|
#endif
|
|
|
|
word128 t[5];
|
|
|
|
word64 r0,r1,r2,r3,r4,c;
|
|
|
|
word64 d0,d1,d2,d4,d419;
|
|
|
|
|
|
|
|
r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4];
|
|
|
|
|
|
|
|
do {
|
|
|
|
d0 = r0 * 2; d1 = r1 * 2;
|
|
|
|
d2 = r2 * 2 * 19;
|
2018-12-13 23:50:42 +00:00
|
|
|
d419 = r4 * 19; d4 = d419 * 2;
|
2018-12-13 18:25:22 +00:00
|
|
|
|
|
|
|
#if defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
t[0] = ((word128) r0) * r0 + ((word128) d4) * r1 + (((word128) d2) * (r3 ));
|
|
|
|
t[1] = ((word128) d0) * r1 + ((word128) d4) * r2 + (((word128) r3) * (r3 * 19));
|
|
|
|
t[2] = ((word128) d0) * r2 + ((word128) r1) * r1 + (((word128) d4) * (r3 ));
|
|
|
|
t[3] = ((word128) d0) * r3 + ((word128) d1) * r2 + (((word128) r4) * (d419 ));
|
|
|
|
t[4] = ((word128) d0) * r4 + ((word128) d1) * r3 + (((word128) r2) * (r2 ));
|
|
|
|
#else
|
|
|
|
mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul)
|
|
|
|
mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul)
|
|
|
|
mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul)
|
|
|
|
mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul)
|
|
|
|
mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul)
|
|
|
|
#endif
|
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51);
|
|
|
|
add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51);
|
|
|
|
add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51);
|
|
|
|
add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51);
|
|
|
|
add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51);
|
|
|
|
r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51;
|
|
|
|
r1 += c;
|
2018-12-13 18:25:22 +00:00
|
|
|
} while(--count);
|
|
|
|
|
|
|
|
out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
curve25519_square(bignum25519 out, const bignum25519 in) {
|
|
|
|
#if !defined(CRYPTOPP_WORD128_AVAILABLE)
|
|
|
|
word128 mul;
|
|
|
|
#endif
|
|
|
|
word128 t[5];
|
|
|
|
word64 r0,r1,r2,r3,r4,c;
|
|
|
|
word64 d0,d1,d2,d4,d419;
|
|
|
|
|
|
|
|
r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4];
|
|
|
|
|
|
|
|
d0 = r0 * 2; d1 = r1 * 2;
|
2018-12-11 21:17:56 +00:00
|
|
|
d2 = r2 * 2 * 19;
|
2018-12-13 23:50:42 +00:00
|
|
|
d419 = r4 * 19; d4 = d419 * 2;
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
#if defined(CRYPTOPP_WORD128_AVAILABLE)
|
2018-12-11 21:17:56 +00:00
|
|
|
t[0] = ((word128) r0) * r0 + ((word128) d4) * r1 + (((word128) d2) * (r3 ));
|
|
|
|
t[1] = ((word128) d0) * r1 + ((word128) d4) * r2 + (((word128) r3) * (r3 * 19));
|
|
|
|
t[2] = ((word128) d0) * r2 + ((word128) r1) * r1 + (((word128) d4) * (r3 ));
|
|
|
|
t[3] = ((word128) d0) * r3 + ((word128) d1) * r2 + (((word128) r4) * (d419 ));
|
|
|
|
t[4] = ((word128) d0) * r4 + ((word128) d1) * r3 + (((word128) r2) * (r2 ));
|
2018-12-13 18:25:22 +00:00
|
|
|
#else
|
|
|
|
mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul)
|
|
|
|
mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul)
|
|
|
|
mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul)
|
|
|
|
mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul)
|
|
|
|
mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul)
|
|
|
|
#endif
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51);
|
|
|
|
add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51);
|
|
|
|
add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51);
|
|
|
|
add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51);
|
|
|
|
add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51);
|
|
|
|
r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51;
|
|
|
|
r1 += c;
|
2018-12-11 21:17:56 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4;
|
2018-12-11 21:17:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
2018-12-13 18:25:22 +00:00
|
|
|
inline void
|
2018-12-13 19:17:36 +00:00
|
|
|
curve25519_expand(bignum25519 out, const byte *in) {
|
2018-12-13 18:25:22 +00:00
|
|
|
word64 x0,x1,x2,x3;
|
|
|
|
|
|
|
|
GetBlock<word64, LittleEndian> block(in);
|
|
|
|
block(x0)(x1)(x2)(x3);
|
|
|
|
|
|
|
|
out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13);
|
|
|
|
out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26);
|
|
|
|
out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39);
|
|
|
|
out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12);
|
2018-12-13 23:50:42 +00:00
|
|
|
out[4] = x3 & reduce_mask_51; /* ignore the top bit */
|
2018-12-11 21:17:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Take a fully reduced polynomial form number and contract it into a
|
|
|
|
* little-endian, 32-byte array
|
|
|
|
*/
|
2018-12-13 18:25:22 +00:00
|
|
|
inline void
|
2018-12-13 19:17:36 +00:00
|
|
|
curve25519_contract(byte *out, const bignum25519 input) {
|
2018-12-13 18:25:22 +00:00
|
|
|
word64 t[5];
|
|
|
|
word64 f, i;
|
|
|
|
|
2018-12-13 23:50:42 +00:00
|
|
|
t[0] = input[0];
|
|
|
|
t[1] = input[1];
|
|
|
|
t[2] = input[2];
|
|
|
|
t[3] = input[3];
|
|
|
|
t[4] = input[4];
|
2018-12-13 18:25:22 +00:00
|
|
|
|
|
|
|
#define curve25519_contract_carry() \
|
|
|
|
t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \
|
|
|
|
t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \
|
|
|
|
t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \
|
|
|
|
t[4] += t[3] >> 51; t[3] &= reduce_mask_51;
|
|
|
|
|
|
|
|
#define curve25519_contract_carry_full() curve25519_contract_carry() \
|
|
|
|
t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51;
|
|
|
|
|
|
|
|
#define curve25519_contract_carry_final() curve25519_contract_carry() \
|
|
|
|
t[4] &= reduce_mask_51;
|
|
|
|
|
|
|
|
curve25519_contract_carry_full()
|
|
|
|
curve25519_contract_carry_full()
|
|
|
|
|
|
|
|
/* now t is between 0 and 2^255-1, properly carried. */
|
|
|
|
/* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
|
|
|
|
t[0] += 19;
|
|
|
|
curve25519_contract_carry_full()
|
|
|
|
|
|
|
|
/* now between 19 and 2^255-1 in both cases, and offset by 19. */
|
2018-12-13 23:50:42 +00:00
|
|
|
t[0] += 0x8000000000000 - 19;
|
|
|
|
t[1] += 0x8000000000000 - 1;
|
|
|
|
t[2] += 0x8000000000000 - 1;
|
|
|
|
t[3] += 0x8000000000000 - 1;
|
|
|
|
t[4] += 0x8000000000000 - 1;
|
2018-12-13 18:25:22 +00:00
|
|
|
|
|
|
|
/* now between 2^255 and 2^256-20, and offset by 2^255. */
|
|
|
|
curve25519_contract_carry_final()
|
|
|
|
|
|
|
|
#define write51full(n,shift) \
|
|
|
|
f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \
|
2018-12-13 19:17:36 +00:00
|
|
|
for (i = 0; i < 8; i++, f >>= 8) *out++ = (byte)f;
|
2018-12-13 18:25:22 +00:00
|
|
|
#define write51(n) write51full(n,13*n)
|
2018-12-13 23:50:42 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
write51(0)
|
|
|
|
write51(1)
|
|
|
|
write51(2)
|
|
|
|
write51(3)
|
2018-12-13 23:50:42 +00:00
|
|
|
|
|
|
|
#undef curve25519_contract_carry
|
|
|
|
#undef curve25519_contract_carry_full
|
|
|
|
#undef curve25519_contract_carry_final
|
|
|
|
#undef write51full
|
|
|
|
#undef write51
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Swap the contents of [qx] and [qpx] iff @swap is non-zero
|
|
|
|
*/
|
|
|
|
inline void
|
|
|
|
curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, word64 iswap) {
|
|
|
|
const word64 swap = (word64)(-(int64_t)iswap);
|
|
|
|
word64 x0,x1,x2,x3,x4;
|
|
|
|
|
|
|
|
x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0;
|
|
|
|
x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1;
|
|
|
|
x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2;
|
|
|
|
x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3;
|
|
|
|
x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In: b = 2^5 - 2^0
|
|
|
|
* Out: b = 2^250 - 2^0
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) {
|
|
|
|
ALIGN(16) bignum25519 t0,c;
|
|
|
|
|
|
|
|
/* 2^5 - 2^0 */ /* b */
|
|
|
|
/* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5);
|
|
|
|
/* 2^10 - 2^0 */ curve25519_mul(b, t0, b);
|
|
|
|
/* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10);
|
|
|
|
/* 2^20 - 2^0 */ curve25519_mul(c, t0, b);
|
|
|
|
/* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20);
|
|
|
|
/* 2^40 - 2^0 */ curve25519_mul(t0, t0, c);
|
|
|
|
/* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10);
|
|
|
|
/* 2^50 - 2^0 */ curve25519_mul(b, t0, b);
|
|
|
|
/* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50);
|
|
|
|
/* 2^100 - 2^0 */ curve25519_mul(c, t0, b);
|
|
|
|
/* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100);
|
|
|
|
/* 2^200 - 2^0 */ curve25519_mul(t0, t0, c);
|
|
|
|
/* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50);
|
|
|
|
/* 2^250 - 2^0 */ curve25519_mul(b, t0, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* z^(p - 2) = z(2^255 - 21)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
curve25519_recip(bignum25519 out, const bignum25519 z) {
|
|
|
|
ALIGN(16) bignum25519 a, t0, b;
|
|
|
|
|
|
|
|
/* 2 */ curve25519_square(a, z); /* a = 2 */
|
|
|
|
/* 8 */ curve25519_square_times(t0, a, 2);
|
|
|
|
/* 9 */ curve25519_mul(b, t0, z); /* b = 9 */
|
|
|
|
/* 11 */ curve25519_mul(a, b, a); /* a = 11 */
|
|
|
|
/* 22 */ curve25519_square(t0, a);
|
|
|
|
/* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b);
|
|
|
|
/* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b);
|
|
|
|
/* 2^255 - 2^5 */ curve25519_square_times(b, b, 5);
|
|
|
|
/* 2^255 - 21 */ curve25519_mul(out, b, a);
|
2018-12-11 21:17:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ANONYMOUS_NAMESPACE_END
|
|
|
|
|
|
|
|
NAMESPACE_BEGIN(CryptoPP)
|
|
|
|
NAMESPACE_BEGIN(Donna)
|
|
|
|
|
2018-12-13 15:19:54 +00:00
|
|
|
int curve25519_CXX(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32])
|
2018-12-11 21:17:56 +00:00
|
|
|
{
|
2018-12-13 23:50:42 +00:00
|
|
|
FixedSizeSecBlock<byte, 32> e;
|
|
|
|
for (size_t i = 0;i < 32;++i)
|
|
|
|
e[i] = secretKey[i];
|
|
|
|
e[0] &= 0xf8; e[31] &= 0x7f; e[31] |= 0x40;
|
|
|
|
|
|
|
|
bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx;
|
|
|
|
bignum25519 q, qx, qpqx, qqx, zzz, zmone;
|
|
|
|
size_t bit, lastbit;
|
|
|
|
|
|
|
|
curve25519_expand(q, othersKey);
|
|
|
|
curve25519_copy(nqx, q);
|
|
|
|
|
|
|
|
/* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and
|
|
|
|
start pre-swapped on bit 254 */
|
|
|
|
lastbit = 1;
|
|
|
|
|
|
|
|
/* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */
|
|
|
|
for (int i = 253; i >= 2; i--) {
|
|
|
|
curve25519_add(qx, nqx, nqz);
|
|
|
|
curve25519_sub(nqz, nqx, nqz);
|
|
|
|
curve25519_add(qpqx, nqpqx, nqpqz);
|
|
|
|
curve25519_sub(nqpqz, nqpqx, nqpqz);
|
|
|
|
curve25519_mul(nqpqx, qpqx, nqz);
|
|
|
|
curve25519_mul(nqpqz, qx, nqpqz);
|
|
|
|
curve25519_add(qqx, nqpqx, nqpqz);
|
|
|
|
curve25519_sub(nqpqz, nqpqx, nqpqz);
|
|
|
|
curve25519_square(nqpqz, nqpqz);
|
|
|
|
curve25519_square(nqpqx, qqx);
|
|
|
|
curve25519_mul(nqpqz, nqpqz, q);
|
|
|
|
curve25519_square(qx, qx);
|
|
|
|
curve25519_square(nqz, nqz);
|
|
|
|
curve25519_mul(nqx, qx, nqz);
|
|
|
|
curve25519_sub(nqz, qx, nqz);
|
|
|
|
curve25519_scalar_product(zzz, nqz, 121665);
|
|
|
|
curve25519_add(zzz, zzz, qx);
|
|
|
|
curve25519_mul(nqz, nqz, zzz);
|
|
|
|
|
|
|
|
bit = (e[i/8] >> (i & 7)) & 1;
|
|
|
|
curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit);
|
|
|
|
curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit);
|
|
|
|
lastbit = bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the final 3 bits are always zero, so we only need to double */
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
curve25519_add(qx, nqx, nqz);
|
|
|
|
curve25519_sub(nqz, nqx, nqz);
|
|
|
|
curve25519_square(qx, qx);
|
|
|
|
curve25519_square(nqz, nqz);
|
|
|
|
curve25519_mul(nqx, qx, nqz);
|
|
|
|
curve25519_sub(nqz, qx, nqz);
|
|
|
|
curve25519_scalar_product(zzz, nqz, 121665);
|
|
|
|
curve25519_add(zzz, zzz, qx);
|
|
|
|
curve25519_mul(nqz, nqz, zzz);
|
|
|
|
}
|
|
|
|
|
|
|
|
curve25519_recip(zmone, nqz);
|
|
|
|
curve25519_mul(nqz, nqx, zmone);
|
|
|
|
curve25519_contract(sharedKey, nqz);
|
2018-12-13 15:19:54 +00:00
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
return 0;
|
2018-12-11 21:17:56 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 15:19:54 +00:00
|
|
|
int curve25519(byte publicKey[32], const byte secretKey[32])
|
|
|
|
{
|
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
|
2018-12-13 18:25:22 +00:00
|
|
|
if (HasSSE2())
|
|
|
|
return curve25519_SSE2(publicKey, secretKey, basePoint);
|
|
|
|
else
|
2018-12-13 15:19:54 +00:00
|
|
|
#endif
|
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
return curve25519_CXX(publicKey, secretKey, basePoint);
|
2018-12-13 15:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int curve25519(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32])
|
|
|
|
{
|
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
|
2018-12-13 18:25:22 +00:00
|
|
|
if (HasSSE2())
|
|
|
|
return curve25519_SSE2(sharedKey, secretKey, othersKey);
|
|
|
|
else
|
2018-12-13 15:19:54 +00:00
|
|
|
#endif
|
|
|
|
|
2018-12-13 18:25:22 +00:00
|
|
|
return curve25519_CXX(sharedKey, secretKey, othersKey);
|
2018-12-13 15:19:54 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 21:17:56 +00:00
|
|
|
NAMESPACE_END // Donna
|
|
|
|
NAMESPACE_END // CryptoPP
|
|
|
|
|
2018-12-14 01:34:39 +00:00
|
|
|
#endif // CRYPTOPP_CURVE25519_64BIT
|