Squashed 'lib/ed25519/' content from commit 1fc4a2f
git-subtree-dir: lib/ed25519 git-subtree-split: 1fc4a2ff69fe111875bd5efcc8523e40b18cf673
This commit is contained in:
commit
498dfabf98
21 changed files with 5306 additions and 0 deletions
BIN
ed25519_32.dll
Normal file
BIN
ed25519_32.dll
Normal file
Binary file not shown.
BIN
ed25519_64.dll
Normal file
BIN
ed25519_64.dll
Normal file
Binary file not shown.
166
readme.md
Normal file
166
readme.md
Normal file
|
@ -0,0 +1,166 @@
|
|||
Ed25519
|
||||
=======
|
||||
|
||||
This is a portable implementation of [Ed25519](http://ed25519.cr.yp.to/) based
|
||||
on the SUPERCOP "ref10" implementation. Additionally there is key exchanging
|
||||
and scalar addition included to further aid building a PKI using Ed25519. All
|
||||
code is in the public domain.
|
||||
|
||||
All code is pure ANSI C without any dependencies, except for the random seed
|
||||
generation which uses standard OS cryptography APIs (`CryptGenRandom` on
|
||||
Windows, `/dev/urandom` on nix). If you wish to be entirely portable define
|
||||
`ED25519_NO_SEED`. This disables the `ed25519_create_seed` function, so if your
|
||||
application requires key generation you must supply your own seeding function
|
||||
(which is simply a 256 bit (32 byte) cryptographic random number generator).
|
||||
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
On a Windows machine with an Intel Pentium B970 @ 2.3GHz I got the following
|
||||
speeds (running on only one a single core):
|
||||
|
||||
Seed generation: 64us (15625 per second)
|
||||
Key generation: 88us (11364 per second)
|
||||
Message signing (short message): 87us (11494 per second)
|
||||
Message verifying (short message): 228us (4386 per second)
|
||||
Scalar addition: 100us (10000 per second)
|
||||
Key exchange: 220us (4545 per second)
|
||||
|
||||
The speeds on other machines may vary. Sign/verify times will be higher with
|
||||
longer messages. The implementation significantly benefits from 64 bit
|
||||
architectures, if possible compile as 64 bit.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Simply add all .c and .h files in the `src/` folder to your project and include
|
||||
`ed25519.h` in any file you want to use the API. If you prefer to use a shared
|
||||
library, only copy `ed25519.h` and define `ED25519_DLL` before importing. A
|
||||
windows DLL is pre-built.
|
||||
|
||||
There are no defined types for seeds, private keys, public keys, shared secrets
|
||||
or signatures. Instead simple `unsigned char` buffers are used with the
|
||||
following sizes:
|
||||
|
||||
```c
|
||||
unsigned char seed[32];
|
||||
unsigned char signature[64];
|
||||
unsigned char public_key[32];
|
||||
unsigned char private_key[64];
|
||||
unsigned char scalar[32];
|
||||
unsigned char shared_secret[32];
|
||||
```
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
```c
|
||||
int ed25519_create_seed(unsigned char *seed);
|
||||
```
|
||||
|
||||
Creates a 32 byte random seed in `seed` for key generation. `seed` must be a
|
||||
writable 32 byte buffer. Returns 0 on success, and nonzero on failure.
|
||||
|
||||
```c
|
||||
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key,
|
||||
const unsigned char *seed);
|
||||
```
|
||||
|
||||
Creates a new key pair from the given seed. `public_key` must be a writable 32
|
||||
byte buffer, `private_key` must be a writable 64 byte buffer and `seed` must be
|
||||
a 32 byte buffer.
|
||||
|
||||
```c
|
||||
void ed25519_sign(unsigned char *signature,
|
||||
const unsigned char *message, size_t message_len,
|
||||
const unsigned char *public_key, const unsigned char *private_key);
|
||||
```
|
||||
|
||||
Creates a signature of the given message with the given key pair. `signature`
|
||||
must be a writable 64 byte buffer. `message` must have at least `message_len`
|
||||
bytes to be read.
|
||||
|
||||
```c
|
||||
int ed25519_verify(const unsigned char *signature,
|
||||
const unsigned char *message, size_t message_len,
|
||||
const unsigned char *public_key);
|
||||
```
|
||||
|
||||
Verifies the signature on the given message using `public_key`. `signature`
|
||||
must be a readable 64 byte buffer. `message` must have at least `message_len`
|
||||
bytes to be read. Returns 1 if the signature matches, 0 otherwise.
|
||||
|
||||
```c
|
||||
void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key,
|
||||
const unsigned char *scalar);
|
||||
```
|
||||
|
||||
Adds `scalar` to the given key pair where scalar is a 32 byte buffer (possibly
|
||||
generated with `ed25519_create_seed`), generating a new key pair. You can
|
||||
calculate the public key sum without knowing the private key and vice versa by
|
||||
passing in `NULL` for the key you don't know. This is useful for enforcing
|
||||
randomness on a key pair by a third party while only knowing the public key,
|
||||
among other things. Warning: the last bit of the scalar is ignored - if
|
||||
comparing scalars make sure to clear it with `scalar[31] &= 127`.
|
||||
|
||||
|
||||
```c
|
||||
void ed25519_key_exchange(unsigned char *shared_secret,
|
||||
const unsigned char *public_key, const unsigned char *private_key);
|
||||
```
|
||||
|
||||
Performs a key exchange on the given public key and private key, producing a
|
||||
shared secret. It is recommended to hash the shared secret before using it.
|
||||
`shared_secret` must be a 32 byte writable buffer where the shared secret will
|
||||
be stored.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
```c
|
||||
unsigned char seed[32], public_key[32], private_key[64], signature[64];
|
||||
unsigned char other_public_key[32], other_private_key[64], shared_secret[32];
|
||||
const unsigned char message[] = "TEST MESSAGE";
|
||||
|
||||
/* create a random seed, and a key pair out of that seed */
|
||||
if (ed25519_create_seed(seed)) {
|
||||
printf("error while generating seed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ed25519_create_keypair(public_key, private_key, seed);
|
||||
|
||||
/* create signature on the message with the key pair */
|
||||
ed25519_sign(signature, message, strlen(message), public_key, private_key);
|
||||
|
||||
/* verify the signature */
|
||||
if (ed25519_verify(signature, message, strlen(message), public_key)) {
|
||||
printf("valid signature\n");
|
||||
} else {
|
||||
printf("invalid signature\n");
|
||||
}
|
||||
|
||||
/* create a dummy keypair to use for a key exchange, normally you'd only have
|
||||
the public key and receive it through some communication channel */
|
||||
if (ed25519_create_seed(seed)) {
|
||||
printf("error while generating seed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ed25519_create_keypair(other_public_key, other_private_key, seed);
|
||||
|
||||
/* do a key exchange with other_public_key */
|
||||
ed25519_key_exchange(shared_secret, other_public_key, private_key);
|
||||
|
||||
/*
|
||||
the magic here is that ed25519_key_exchange(shared_secret, public_key,
|
||||
other_private_key); would result in the same shared_secret
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
All code is in the public domain.
|
56
src/add_scalar.c
Normal file
56
src/add_scalar.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "ed25519.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
|
||||
/* see http://crypto.stackexchange.com/a/6215/4697 */
|
||||
void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
|
||||
const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
|
||||
|
||||
unsigned char n[32];
|
||||
ge_p3 nB;
|
||||
ge_p1p1 A_p1p1;
|
||||
ge_p3 A;
|
||||
ge_p3 public_key_unpacked;
|
||||
ge_cached T;
|
||||
|
||||
int i;
|
||||
|
||||
/* copy the scalar and clear highest bit */
|
||||
for (i = 0; i < 31; ++i) {
|
||||
n[i] = scalar[i];
|
||||
}
|
||||
n[31] = scalar[31] & 127;
|
||||
|
||||
/* private key: a = n + t */
|
||||
if (private_key) {
|
||||
sc_muladd(private_key, SC_1, n, private_key);
|
||||
}
|
||||
|
||||
/* public key: A = nB + T */
|
||||
if (public_key) {
|
||||
/* if we know the private key we don't need a point addition, which is faster */
|
||||
/* using a "timing attack" you could find out wether or not we know the private
|
||||
key, but this information seems rather useless - if this is important pass
|
||||
public_key and private_key seperately in 2 function calls */
|
||||
if (private_key) {
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
} else {
|
||||
/* unpack public key into T */
|
||||
ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
|
||||
fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */
|
||||
fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */
|
||||
ge_p3_to_cached(&T, &public_key_unpacked);
|
||||
|
||||
/* calculate n*B */
|
||||
ge_scalarmult_base(&nB, n);
|
||||
|
||||
/* A = n*B + T */
|
||||
ge_add(&A_p1p1, &nB, &T);
|
||||
ge_p1p1_to_p3(&A, &A_p1p1);
|
||||
}
|
||||
|
||||
/* pack public key */
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
}
|
38
src/ed25519.h
Normal file
38
src/ed25519.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(ED25519_BUILD_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllexport)
|
||||
#elif defined(ED25519_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllimport)
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ED25519_NO_SEED
|
||||
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
|
||||
#endif
|
||||
|
||||
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
|
||||
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
|
||||
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key);
|
||||
void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
|
||||
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
41
src/fe.h
Normal file
41
src/fe.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef FE_H
|
||||
#define FE_H
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
|
||||
/*
|
||||
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 t[3]+2^102 t[4]+...+2^230 t[9].
|
||||
Bounds on each t[i] vary depending on context.
|
||||
*/
|
||||
|
||||
|
||||
typedef int32_t fe[10];
|
||||
|
||||
|
||||
void fe_0(fe h);
|
||||
void fe_1(fe h);
|
||||
|
||||
void fe_frombytes(fe h, const unsigned char *s);
|
||||
void fe_tobytes(unsigned char *s, const fe h);
|
||||
|
||||
void fe_copy(fe h, const fe f);
|
||||
int fe_isnegative(const fe f);
|
||||
int fe_isnonzero(const fe f);
|
||||
void fe_cmov(fe f, const fe g, unsigned int b);
|
||||
void fe_cswap(fe f, fe g, unsigned int b);
|
||||
|
||||
void fe_neg(fe h, const fe f);
|
||||
void fe_add(fe h, const fe f, const fe g);
|
||||
void fe_invert(fe out, const fe z);
|
||||
void fe_sq(fe h, const fe f);
|
||||
void fe_sq2(fe h, const fe f);
|
||||
void fe_mul(fe h, const fe f, const fe g);
|
||||
void fe_mul121666(fe h, fe f);
|
||||
void fe_pow22523(fe out, const fe z);
|
||||
void fe_sub(fe h, const fe f, const fe g);
|
||||
|
||||
#endif
|
72
src/fixedint.h
Normal file
72
src/fixedint.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Portable header to provide the 32 and 64 bits type.
|
||||
|
||||
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
|
||||
*/
|
||||
|
||||
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
|
||||
#include <stdint.h>
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
|
||||
#include <limits.h>
|
||||
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FIXEDINT_H_INCLUDED
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* (u)int32_t */
|
||||
#ifndef uint32_t
|
||||
#if (ULONG_MAX == 0xffffffffUL)
|
||||
typedef unsigned long uint32_t;
|
||||
#elif (UINT_MAX == 0xffffffffUL)
|
||||
typedef unsigned int uint32_t;
|
||||
#elif (USHRT_MAX == 0xffffffffUL)
|
||||
typedef unsigned short uint32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef int32_t
|
||||
#if (LONG_MAX == 0x7fffffffL)
|
||||
typedef signed long int32_t;
|
||||
#elif (INT_MAX == 0x7fffffffL)
|
||||
typedef signed int int32_t;
|
||||
#elif (SHRT_MAX == 0x7fffffffL)
|
||||
typedef signed short int32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* (u)int64_t */
|
||||
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__GNUC__)
|
||||
__extension__ typedef long long int64_t;
|
||||
__extension__ typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##UI64
|
||||
#define INT64_C(v) v ##I64
|
||||
#endif
|
||||
#endif
|
467
src/ge.c
Normal file
467
src/ge.c
Normal file
|
@ -0,0 +1,467 @@
|
|||
#include "ge.h"
|
||||
#include "precomp_data.h"
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YplusX);
|
||||
fe_mul(r->Y, r->Y, q->YminusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
static void slide(signed char *r, const unsigned char *a) {
|
||||
int i;
|
||||
int b;
|
||||
int k;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r[i] = 1 & (a[i >> 3] >> (i & 7));
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (r[i]) {
|
||||
for (b = 1; b <= 6 && i + b < 256; ++b) {
|
||||
if (r[i + b]) {
|
||||
if (r[i] + (r[i + b] << b) <= 15) {
|
||||
r[i] += r[i + b] << b;
|
||||
r[i + b] = 0;
|
||||
} else if (r[i] - (r[i + b] << b) >= -15) {
|
||||
r[i] -= r[i + b] << b;
|
||||
|
||||
for (k = i + b; k < 256; ++k) {
|
||||
if (!r[k]) {
|
||||
r[k] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
r[k] = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
r = a * A + b * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
*/
|
||||
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p3 A2;
|
||||
int i;
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_p3_to_cached(&Ai[0], A);
|
||||
ge_p3_dbl(&t, A);
|
||||
ge_p1p1_to_p3(&A2, &t);
|
||||
ge_add(&t, &A2, &Ai[0]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[1], &u);
|
||||
ge_add(&t, &A2, &Ai[1]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[2], &u);
|
||||
ge_add(&t, &A2, &Ai[2]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[3], &u);
|
||||
ge_add(&t, &A2, &Ai[3]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[4], &u);
|
||||
ge_add(&t, &A2, &Ai[4]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[5], &u);
|
||||
ge_add(&t, &A2, &Ai[5]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[6], &u);
|
||||
ge_add(&t, &A2, &Ai[6]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[7], &u);
|
||||
ge_p2_0(r);
|
||||
|
||||
for (i = 255; i >= 0; --i) {
|
||||
if (aslide[i] || bslide[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
ge_p2_dbl(&t, r);
|
||||
|
||||
if (aslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Ai[aslide[i] / 2]);
|
||||
} else if (aslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
|
||||
}
|
||||
|
||||
if (bslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
|
||||
} else if (bslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
|
||||
}
|
||||
|
||||
ge_p1p1_to_p2(r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const fe d = {
|
||||
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
|
||||
};
|
||||
|
||||
static const fe sqrtm1 = {
|
||||
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
|
||||
};
|
||||
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
fe u;
|
||||
fe v;
|
||||
fe v3;
|
||||
fe vxx;
|
||||
fe check;
|
||||
fe_frombytes(h->Y, s);
|
||||
fe_1(h->Z);
|
||||
fe_sq(u, h->Y);
|
||||
fe_mul(v, u, d);
|
||||
fe_sub(u, u, h->Z); /* u = y^2-1 */
|
||||
fe_add(v, v, h->Z); /* v = dy^2+1 */
|
||||
fe_sq(v3, v);
|
||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||
fe_sq(h->X, v3);
|
||||
fe_mul(h->X, h->X, v);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^7 */
|
||||
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
|
||||
fe_mul(h->X, h->X, v3);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
|
||||
fe_sq(vxx, h->X);
|
||||
fe_mul(vxx, vxx, v);
|
||||
fe_sub(check, vxx, u); /* vx^2-u */
|
||||
|
||||
if (fe_isnonzero(check)) {
|
||||
fe_add(check, vxx, u); /* vx^2+u */
|
||||
|
||||
if (fe_isnonzero(check)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fe_mul(h->X, h->X, sqrtm1);
|
||||
}
|
||||
|
||||
if (fe_isnegative(h->X) == (s[31] >> 7)) {
|
||||
fe_neg(h->X, h->X);
|
||||
}
|
||||
|
||||
fe_mul(h->T, h->X, h->Y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yplusx);
|
||||
fe_mul(r->Y, r->Y, q->yminusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yminusx);
|
||||
fe_mul(r->Y, r->Y, q->yplusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
fe_mul(r->T, p->X, p->Y);
|
||||
}
|
||||
|
||||
|
||||
void ge_p2_0(ge_p2 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
||||
fe t0;
|
||||
|
||||
fe_sq(r->X, p->X);
|
||||
fe_sq(r->Z, p->Y);
|
||||
fe_sq2(r->T, p->Z);
|
||||
fe_add(r->Y, p->X, p->Y);
|
||||
fe_sq(t0, r->Y);
|
||||
fe_add(r->Y, r->Z, r->X);
|
||||
fe_sub(r->Z, r->Z, r->X);
|
||||
fe_sub(r->X, t0, r->Y);
|
||||
fe_sub(r->T, r->T, r->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_0(ge_p3 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
fe_0(h->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
|
||||
ge_p2 q;
|
||||
ge_p3_to_p2(&q, p);
|
||||
ge_p2_dbl(r, &q);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
static const fe d2 = {
|
||||
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
|
||||
};
|
||||
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
|
||||
fe_add(r->YplusX, p->Y, p->X);
|
||||
fe_sub(r->YminusX, p->Y, p->X);
|
||||
fe_copy(r->Z, p->Z);
|
||||
fe_mul(r->T2d, p->T, d2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
|
||||
fe_copy(r->X, p->X);
|
||||
fe_copy(r->Y, p->Y);
|
||||
fe_copy(r->Z, p->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char equal(signed char b, signed char c) {
|
||||
unsigned char ub = b;
|
||||
unsigned char uc = c;
|
||||
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
||||
uint64_t y = x; /* 0: yes; 1..255: no */
|
||||
y -= 1; /* large: yes; 0..254: no */
|
||||
y >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) y;
|
||||
}
|
||||
|
||||
static unsigned char negative(signed char b) {
|
||||
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
||||
x >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) x;
|
||||
}
|
||||
|
||||
static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) {
|
||||
fe_cmov(t->yplusx, u->yplusx, b);
|
||||
fe_cmov(t->yminusx, u->yminusx, b);
|
||||
fe_cmov(t->xy2d, u->xy2d, b);
|
||||
}
|
||||
|
||||
|
||||
static void select(ge_precomp *t, int pos, signed char b) {
|
||||
ge_precomp minust;
|
||||
unsigned char bnegative = negative(b);
|
||||
unsigned char babs = b - (((-bnegative) & b) << 1);
|
||||
fe_1(t->yplusx);
|
||||
fe_1(t->yminusx);
|
||||
fe_0(t->xy2d);
|
||||
cmov(t, &base[pos][0], equal(babs, 1));
|
||||
cmov(t, &base[pos][1], equal(babs, 2));
|
||||
cmov(t, &base[pos][2], equal(babs, 3));
|
||||
cmov(t, &base[pos][3], equal(babs, 4));
|
||||
cmov(t, &base[pos][4], equal(babs, 5));
|
||||
cmov(t, &base[pos][5], equal(babs, 6));
|
||||
cmov(t, &base[pos][6], equal(babs, 7));
|
||||
cmov(t, &base[pos][7], equal(babs, 8));
|
||||
fe_copy(minust.yplusx, t->yminusx);
|
||||
fe_copy(minust.yminusx, t->yplusx);
|
||||
fe_neg(minust.xy2d, t->xy2d);
|
||||
cmov(t, &minust, bnegative);
|
||||
}
|
||||
|
||||
/*
|
||||
h = a * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
|
||||
Preconditions:
|
||||
a[31] <= 127
|
||||
*/
|
||||
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||
signed char e[64];
|
||||
signed char carry;
|
||||
ge_p1p1 r;
|
||||
ge_p2 s;
|
||||
ge_precomp t;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
e[2 * i + 0] = (a[i] >> 0) & 15;
|
||||
e[2 * i + 1] = (a[i] >> 4) & 15;
|
||||
}
|
||||
|
||||
/* each e[i] is between 0 and 15 */
|
||||
/* e[63] is between 0 and 7 */
|
||||
carry = 0;
|
||||
|
||||
for (i = 0; i < 63; ++i) {
|
||||
e[i] += carry;
|
||||
carry = e[i] + 8;
|
||||
carry >>= 4;
|
||||
e[i] -= carry << 4;
|
||||
}
|
||||
|
||||
e[63] += carry;
|
||||
/* each e[i] is between -8 and 8 */
|
||||
ge_p3_0(h);
|
||||
|
||||
for (i = 1; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
|
||||
ge_p3_dbl(&r, h);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
|
||||
for (i = 0; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YminusX);
|
||||
fe_mul(r->Y, r->Y, q->YplusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
74
src/ge.h
Normal file
74
src/ge.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
#ifndef GE_H
|
||||
#define GE_H
|
||||
|
||||
#include "fe.h"
|
||||
|
||||
|
||||
/*
|
||||
ge means group element.
|
||||
|
||||
Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||
satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||
where d = -121665/121666.
|
||||
|
||||
Representations:
|
||||
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||
ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
} ge_p2;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p3;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p1p1;
|
||||
|
||||
typedef struct {
|
||||
fe yplusx;
|
||||
fe yminusx;
|
||||
fe xy2d;
|
||||
} ge_precomp;
|
||||
|
||||
typedef struct {
|
||||
fe YplusX;
|
||||
fe YminusX;
|
||||
fe Z;
|
||||
fe T2d;
|
||||
} ge_cached;
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h);
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
||||
void ge_p2_0(ge_p2 *h);
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
|
||||
void ge_p3_0(ge_p3 *h);
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
|
||||
|
||||
#endif
|
79
src/key_exchange.c
Normal file
79
src/key_exchange.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include "ed25519.h"
|
||||
#include "fe.h"
|
||||
|
||||
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
unsigned char e[32];
|
||||
unsigned int i;
|
||||
|
||||
fe x1;
|
||||
fe x2;
|
||||
fe z2;
|
||||
fe x3;
|
||||
fe z3;
|
||||
fe tmp0;
|
||||
fe tmp1;
|
||||
|
||||
int pos;
|
||||
unsigned int swap;
|
||||
unsigned int b;
|
||||
|
||||
/* copy the private key and make sure it's valid */
|
||||
for (i = 0; i < 32; ++i) {
|
||||
e[i] = private_key[i];
|
||||
}
|
||||
|
||||
e[0] &= 248;
|
||||
e[31] &= 63;
|
||||
e[31] |= 64;
|
||||
|
||||
/* unpack the public key and convert edwards to montgomery */
|
||||
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
|
||||
fe_frombytes(x1, public_key);
|
||||
fe_1(tmp1);
|
||||
fe_add(tmp0, x1, tmp1);
|
||||
fe_sub(tmp1, tmp1, x1);
|
||||
fe_invert(tmp1, tmp1);
|
||||
fe_mul(x1, tmp0, tmp1);
|
||||
|
||||
fe_1(x2);
|
||||
fe_0(z2);
|
||||
fe_copy(x3, x1);
|
||||
fe_1(z3);
|
||||
|
||||
swap = 0;
|
||||
for (pos = 254; pos >= 0; --pos) {
|
||||
b = e[pos / 8] >> (pos & 7);
|
||||
b &= 1;
|
||||
swap ^= b;
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
swap = b;
|
||||
|
||||
/* from montgomery.h */
|
||||
fe_sub(tmp0, x3, z3);
|
||||
fe_sub(tmp1, x2, z2);
|
||||
fe_add(x2, x2, z2);
|
||||
fe_add(z2, x3, z3);
|
||||
fe_mul(z3, tmp0, x2);
|
||||
fe_mul(z2, z2, tmp1);
|
||||
fe_sq(tmp0, tmp1);
|
||||
fe_sq(tmp1, x2);
|
||||
fe_add(x3, z3, z2);
|
||||
fe_sub(z2, z3, z2);
|
||||
fe_mul(x2, tmp1, tmp0);
|
||||
fe_sub(tmp1, tmp1, tmp0);
|
||||
fe_sq(z2, z2);
|
||||
fe_mul121666(z3, tmp1);
|
||||
fe_sq(x3, x3);
|
||||
fe_add(tmp0, tmp0, z3);
|
||||
fe_mul(z3, x1, z2);
|
||||
fe_mul(z2, tmp1, tmp0);
|
||||
}
|
||||
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
|
||||
fe_invert(z2, z2);
|
||||
fe_mul(x2, x2, z2);
|
||||
fe_tobytes(shared_secret, x2);
|
||||
}
|
16
src/keypair.c
Normal file
16
src/keypair.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
|
||||
|
||||
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
|
||||
ge_p3 A;
|
||||
|
||||
sha512(seed, 32, private_key);
|
||||
private_key[0] &= 248;
|
||||
private_key[31] &= 63;
|
||||
private_key[31] |= 64;
|
||||
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
1391
src/precomp_data.h
Normal file
1391
src/precomp_data.h
Normal file
File diff suppressed because it is too large
Load diff
809
src/sc.c
Normal file
809
src/sc.c
Normal file
|
@ -0,0 +1,809 @@
|
|||
#include "fixedint.h"
|
||||
#include "sc.h"
|
||||
|
||||
static uint64_t load_3(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
|
||||
result = (uint64_t) in[0];
|
||||
result |= ((uint64_t) in[1]) << 8;
|
||||
result |= ((uint64_t) in[2]) << 16;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint64_t load_4(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
|
||||
result = (uint64_t) in[0];
|
||||
result |= ((uint64_t) in[1]) << 8;
|
||||
result |= ((uint64_t) in[2]) << 16;
|
||||
result |= ((uint64_t) in[3]) << 24;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Input:
|
||||
s[0]+256*s[1]+...+256^63*s[63] = s
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
Overwrites s in place.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||
int64_t s8 = 2097151 & load_3(s + 21);
|
||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
|
||||
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
|
||||
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
|
||||
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
|
||||
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
|
||||
int64_t s16 = 2097151 & load_3(s + 42);
|
||||
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
|
||||
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
|
||||
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
|
||||
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
|
||||
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
|
||||
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
|
||||
int64_t s23 = (load_4(s + 60) >> 3);
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s23 = 0;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s22 = 0;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s21 = 0;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s20 = 0;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s19 = 0;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
s18 = 0;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s17 = 0;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s16 = 0;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s15 = 0;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s14 = 0;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s13 = 0;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (unsigned char) (s0 >> 0);
|
||||
s[1] = (unsigned char) (s0 >> 8);
|
||||
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||
s[3] = (unsigned char) (s1 >> 3);
|
||||
s[4] = (unsigned char) (s1 >> 11);
|
||||
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||
s[6] = (unsigned char) (s2 >> 6);
|
||||
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||
s[8] = (unsigned char) (s3 >> 1);
|
||||
s[9] = (unsigned char) (s3 >> 9);
|
||||
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||
s[11] = (unsigned char) (s4 >> 4);
|
||||
s[12] = (unsigned char) (s4 >> 12);
|
||||
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||
s[14] = (unsigned char) (s5 >> 7);
|
||||
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||
s[16] = (unsigned char) (s6 >> 2);
|
||||
s[17] = (unsigned char) (s6 >> 10);
|
||||
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
|
||||
s[19] = (unsigned char) (s7 >> 5);
|
||||
s[20] = (unsigned char) (s7 >> 13);
|
||||
s[21] = (unsigned char) (s8 >> 0);
|
||||
s[22] = (unsigned char) (s8 >> 8);
|
||||
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
|
||||
s[24] = (unsigned char) (s9 >> 3);
|
||||
s[25] = (unsigned char) (s9 >> 11);
|
||||
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||
s[27] = (unsigned char) (s10 >> 6);
|
||||
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||
s[29] = (unsigned char) (s11 >> 1);
|
||||
s[30] = (unsigned char) (s11 >> 9);
|
||||
s[31] = (unsigned char) (s11 >> 17);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t c0 = 2097151 & load_3(c);
|
||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||
int64_t c8 = 2097151 & load_3(c + 21);
|
||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||
int64_t c11 = (load_4(c + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = c0 + a0 * b0;
|
||||
s1 = c1 + a0 * b1 + a1 * b0;
|
||||
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
|
||||
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
|
||||
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
|
||||
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
|
||||
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
|
||||
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||
s21 = a10 * b11 + a11 * b10;
|
||||
s22 = a11 * b11;
|
||||
s23 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1 << 20)) >> 21;
|
||||
s19 += carry18;
|
||||
s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1 << 20)) >> 21;
|
||||
s21 += carry20;
|
||||
s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1 << 20)) >> 21;
|
||||
s23 += carry22;
|
||||
s22 -= carry22 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1 << 20)) >> 21;
|
||||
s18 += carry17;
|
||||
s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1 << 20)) >> 21;
|
||||
s20 += carry19;
|
||||
s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1 << 20)) >> 21;
|
||||
s22 += carry21;
|
||||
s21 -= carry21 << 21;
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s23 = 0;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s22 = 0;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s21 = 0;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s20 = 0;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s19 = 0;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
s18 = 0;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s17 = 0;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s16 = 0;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s15 = 0;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s14 = 0;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s13 = 0;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (unsigned char) (s0 >> 0);
|
||||
s[1] = (unsigned char) (s0 >> 8);
|
||||
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||
s[3] = (unsigned char) (s1 >> 3);
|
||||
s[4] = (unsigned char) (s1 >> 11);
|
||||
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||
s[6] = (unsigned char) (s2 >> 6);
|
||||
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||
s[8] = (unsigned char) (s3 >> 1);
|
||||
s[9] = (unsigned char) (s3 >> 9);
|
||||
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||
s[11] = (unsigned char) (s4 >> 4);
|
||||
s[12] = (unsigned char) (s4 >> 12);
|
||||
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||
s[14] = (unsigned char) (s5 >> 7);
|
||||
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||
s[16] = (unsigned char) (s6 >> 2);
|
||||
s[17] = (unsigned char) (s6 >> 10);
|
||||
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
|
||||
s[19] = (unsigned char) (s7 >> 5);
|
||||
s[20] = (unsigned char) (s7 >> 13);
|
||||
s[21] = (unsigned char) (s8 >> 0);
|
||||
s[22] = (unsigned char) (s8 >> 8);
|
||||
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
|
||||
s[24] = (unsigned char) (s9 >> 3);
|
||||
s[25] = (unsigned char) (s9 >> 11);
|
||||
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||
s[27] = (unsigned char) (s10 >> 6);
|
||||
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||
s[29] = (unsigned char) (s11 >> 1);
|
||||
s[30] = (unsigned char) (s11 >> 9);
|
||||
s[31] = (unsigned char) (s11 >> 17);
|
||||
}
|
12
src/sc.h
Normal file
12
src/sc.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef SC_H
|
||||
#define SC_H
|
||||
|
||||
/*
|
||||
The set of scalars is \Z/l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s);
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
||||
|
||||
#endif
|
40
src/seed.c
Normal file
40
src/seed.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "ed25519.h"
|
||||
|
||||
#ifndef ED25519_NO_SEED
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <Wincrypt.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
int ed25519_create_seed(unsigned char *seed) {
|
||||
#ifdef _WIN32
|
||||
HCRYPTPROV prov;
|
||||
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!CryptGenRandom(prov, 32, seed)) {
|
||||
CryptReleaseContext(prov, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CryptReleaseContext(prov, 0);
|
||||
#else
|
||||
FILE *f = fopen("/dev/urandom", "rb");
|
||||
|
||||
if (f == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fread(seed, 1, 32, f);
|
||||
fclose(f);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
275
src/sha512.c
Normal file
275
src/sha512.c
Normal file
|
@ -0,0 +1,275 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||
*
|
||||
* LibTomCrypt is a library that provides various cryptographic
|
||||
* algorithms in a highly modular and flexible manner.
|
||||
*
|
||||
* The library is free for all purposes without any express
|
||||
* guarantee it works.
|
||||
*
|
||||
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
||||
*/
|
||||
|
||||
#include "fixedint.h"
|
||||
#include "sha512.h"
|
||||
|
||||
/* the K array */
|
||||
static const uint64_t K[80] = {
|
||||
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
|
||||
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
|
||||
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
|
||||
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
|
||||
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
|
||||
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
|
||||
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
|
||||
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
|
||||
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
|
||||
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
|
||||
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
|
||||
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
|
||||
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
|
||||
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
|
||||
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
|
||||
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
|
||||
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
|
||||
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
|
||||
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
|
||||
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
|
||||
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
|
||||
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
|
||||
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
|
||||
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
|
||||
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
|
||||
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
|
||||
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
|
||||
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
|
||||
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
|
||||
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
|
||||
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
|
||||
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
|
||||
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
|
||||
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
|
||||
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
|
||||
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
|
||||
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
|
||||
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
|
||||
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
|
||||
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* Various logical functions */
|
||||
|
||||
#define ROR64c(x, y) \
|
||||
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
|
||||
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
#define STORE64H(x, y) \
|
||||
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
|
||||
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
|
||||
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
|
||||
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
|
||||
|
||||
#define LOAD64H(x, y) \
|
||||
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
|
||||
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
|
||||
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
|
||||
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
|
||||
|
||||
|
||||
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
|
||||
#define Maj(x,y,z) (((x | y) & z) | (x & y))
|
||||
#define S(x, n) ROR64c(x, n)
|
||||
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
|
||||
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
|
||||
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
|
||||
#endif
|
||||
|
||||
/* compress 1024-bits */
|
||||
static int sha512_compress(sha512_context *md, unsigned char *buf)
|
||||
{
|
||||
uint64_t S[8], W[80], t0, t1;
|
||||
int i;
|
||||
|
||||
/* copy state into S */
|
||||
for (i = 0; i < 8; i++) {
|
||||
S[i] = md->state[i];
|
||||
}
|
||||
|
||||
/* copy the state into 1024-bits into W[0..15] */
|
||||
for (i = 0; i < 16; i++) {
|
||||
LOAD64H(W[i], buf + (8*i));
|
||||
}
|
||||
|
||||
/* fill W[16..79] */
|
||||
for (i = 16; i < 80; i++) {
|
||||
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
||||
}
|
||||
|
||||
/* Compress */
|
||||
#define RND(a,b,c,d,e,f,g,h,i) \
|
||||
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
||||
t1 = Sigma0(a) + Maj(a, b, c);\
|
||||
d += t0; \
|
||||
h = t0 + t1;
|
||||
|
||||
for (i = 0; i < 80; i += 8) {
|
||||
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
|
||||
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
|
||||
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
|
||||
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
|
||||
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
|
||||
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
|
||||
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
|
||||
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
|
||||
}
|
||||
|
||||
#undef RND
|
||||
|
||||
|
||||
|
||||
/* feedback */
|
||||
for (i = 0; i < 8; i++) {
|
||||
md->state[i] = md->state[i] + S[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the hash state
|
||||
@param md The hash state you wish to initialize
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_init(sha512_context * md) {
|
||||
if (md == NULL) return 1;
|
||||
|
||||
md->curlen = 0;
|
||||
md->length = 0;
|
||||
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
|
||||
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
|
||||
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
|
||||
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
|
||||
md->state[4] = UINT64_C(0x510e527fade682d1);
|
||||
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
|
||||
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
|
||||
md->state[7] = UINT64_C(0x5be0cd19137e2179);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Process a block of memory though the hash
|
||||
@param md The hash state
|
||||
@param in The data to hash
|
||||
@param inlen The length of the data (octets)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
|
||||
{
|
||||
size_t n;
|
||||
size_t i;
|
||||
int err;
|
||||
if (md == NULL) return 1;
|
||||
if (in == NULL) return 1;
|
||||
if (md->curlen > sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
while (inlen > 0) {
|
||||
if (md->curlen == 0 && inlen >= 128) {
|
||||
if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
|
||||
return err;
|
||||
}
|
||||
md->length += 128 * 8;
|
||||
in += 128;
|
||||
inlen -= 128;
|
||||
} else {
|
||||
n = MIN(inlen, (128 - md->curlen));
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
md->buf[i + md->curlen] = in[i];
|
||||
}
|
||||
|
||||
|
||||
md->curlen += n;
|
||||
in += n;
|
||||
inlen -= n;
|
||||
if (md->curlen == 128) {
|
||||
if ((err = sha512_compress (md, md->buf)) != 0) {
|
||||
return err;
|
||||
}
|
||||
md->length += 8*128;
|
||||
md->curlen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Terminate the hash to get the digest
|
||||
@param md The hash state
|
||||
@param out [out] The destination of the hash (64 bytes)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_final(sha512_context * md, unsigned char *out)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (md == NULL) return 1;
|
||||
if (out == NULL) return 1;
|
||||
|
||||
if (md->curlen >= sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* increase the length of the message */
|
||||
md->length += md->curlen * UINT64_C(8);
|
||||
|
||||
/* append the '1' bit */
|
||||
md->buf[md->curlen++] = (unsigned char)0x80;
|
||||
|
||||
/* if the length is currently above 112 bytes we append zeros
|
||||
* then compress. Then we can fall back to padding zeros and length
|
||||
* encoding like normal.
|
||||
*/
|
||||
if (md->curlen > 112) {
|
||||
while (md->curlen < 128) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
sha512_compress(md, md->buf);
|
||||
md->curlen = 0;
|
||||
}
|
||||
|
||||
/* pad upto 120 bytes of zeroes
|
||||
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
|
||||
* > 2^64 bits of data... :-)
|
||||
*/
|
||||
while (md->curlen < 120) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
|
||||
/* store length */
|
||||
STORE64H(md->length, md->buf+120);
|
||||
sha512_compress(md, md->buf);
|
||||
|
||||
/* copy output */
|
||||
for (i = 0; i < 8; i++) {
|
||||
STORE64H(md->state[i], out+(8*i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
|
||||
{
|
||||
sha512_context ctx;
|
||||
int ret;
|
||||
if ((ret = sha512_init(&ctx))) return ret;
|
||||
if ((ret = sha512_update(&ctx, message, message_len))) return ret;
|
||||
if ((ret = sha512_final(&ctx, out))) return ret;
|
||||
return 0;
|
||||
}
|
21
src/sha512.h
Normal file
21
src/sha512.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef SHA512_H
|
||||
#define SHA512_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
/* state */
|
||||
typedef struct sha512_context_ {
|
||||
uint64_t length, state[8];
|
||||
size_t curlen;
|
||||
unsigned char buf[128];
|
||||
} sha512_context;
|
||||
|
||||
|
||||
int sha512_init(sha512_context * md);
|
||||
int sha512_final(sha512_context * md, unsigned char *out);
|
||||
int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
|
||||
int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
|
||||
|
||||
#endif
|
31
src/sign.c
Normal file
31
src/sign.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
|
||||
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
sha512_context hash;
|
||||
unsigned char hram[64];
|
||||
unsigned char r[64];
|
||||
ge_p3 R;
|
||||
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, private_key + 32, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, r);
|
||||
|
||||
sc_reduce(r);
|
||||
ge_scalarmult_base(&R, r);
|
||||
ge_p3_tobytes(signature, &R);
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, hram);
|
||||
|
||||
sc_reduce(hram);
|
||||
sc_muladd(signature + 32, hram, private_key, r);
|
||||
}
|
77
src/verify.c
Normal file
77
src/verify.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
|
||||
unsigned char r = 0;
|
||||
|
||||
r = x[0] ^ y[0];
|
||||
#define F(i) r |= x[i] ^ y[i]
|
||||
F(1);
|
||||
F(2);
|
||||
F(3);
|
||||
F(4);
|
||||
F(5);
|
||||
F(6);
|
||||
F(7);
|
||||
F(8);
|
||||
F(9);
|
||||
F(10);
|
||||
F(11);
|
||||
F(12);
|
||||
F(13);
|
||||
F(14);
|
||||
F(15);
|
||||
F(16);
|
||||
F(17);
|
||||
F(18);
|
||||
F(19);
|
||||
F(20);
|
||||
F(21);
|
||||
F(22);
|
||||
F(23);
|
||||
F(24);
|
||||
F(25);
|
||||
F(26);
|
||||
F(27);
|
||||
F(28);
|
||||
F(29);
|
||||
F(30);
|
||||
F(31);
|
||||
#undef F
|
||||
|
||||
return !r;
|
||||
}
|
||||
|
||||
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
|
||||
unsigned char h[64];
|
||||
unsigned char checker[32];
|
||||
sha512_context hash;
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
|
||||
if (signature[63] & 224) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, h);
|
||||
|
||||
sc_reduce(h);
|
||||
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
|
||||
ge_tobytes(checker, &R);
|
||||
|
||||
if (!consttime_equal(checker, signature)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
150
test.c
Normal file
150
test.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* #define ED25519_DLL */
|
||||
#include "src/ed25519.h"
|
||||
|
||||
#include "src/ge.h"
|
||||
#include "src/sc.h"
|
||||
|
||||
|
||||
int main() {
|
||||
unsigned char public_key[32], private_key[64], seed[32], scalar[32];
|
||||
unsigned char other_public_key[32], other_private_key[64];
|
||||
unsigned char shared_secret[32], other_shared_secret[32];
|
||||
unsigned char signature[64];
|
||||
|
||||
clock_t start;
|
||||
clock_t end;
|
||||
int i;
|
||||
|
||||
const unsigned char message[] = "Hello, world!";
|
||||
const int message_len = strlen((char*) message);
|
||||
|
||||
/* create a random seed, and a keypair out of that seed */
|
||||
ed25519_create_seed(seed);
|
||||
ed25519_create_keypair(public_key, private_key, seed);
|
||||
|
||||
/* create signature on the message with the keypair */
|
||||
ed25519_sign(signature, message, message_len, public_key, private_key);
|
||||
|
||||
/* verify the signature */
|
||||
if (ed25519_verify(signature, message, message_len, public_key)) {
|
||||
printf("valid signature\n");
|
||||
} else {
|
||||
printf("invalid signature\n");
|
||||
}
|
||||
|
||||
/* create scalar and add it to the keypair */
|
||||
ed25519_create_seed(scalar);
|
||||
ed25519_add_scalar(public_key, private_key, scalar);
|
||||
|
||||
/* create signature with the new keypair */
|
||||
ed25519_sign(signature, message, message_len, public_key, private_key);
|
||||
|
||||
/* verify the signature with the new keypair */
|
||||
if (ed25519_verify(signature, message, message_len, public_key)) {
|
||||
printf("valid signature\n");
|
||||
} else {
|
||||
printf("invalid signature\n");
|
||||
}
|
||||
|
||||
/* make a slight adjustment and verify again */
|
||||
signature[44] ^= 0x10;
|
||||
if (ed25519_verify(signature, message, message_len, public_key)) {
|
||||
printf("did not detect signature change\n");
|
||||
} else {
|
||||
printf("correctly detected signature change\n");
|
||||
}
|
||||
|
||||
/* generate two keypairs for testing key exchange */
|
||||
ed25519_create_seed(seed);
|
||||
ed25519_create_keypair(public_key, private_key, seed);
|
||||
ed25519_create_seed(seed);
|
||||
ed25519_create_keypair(other_public_key, other_private_key, seed);
|
||||
|
||||
/* create two shared secrets - from both perspectives - and check if they're equal */
|
||||
ed25519_key_exchange(shared_secret, other_public_key, private_key);
|
||||
ed25519_key_exchange(other_shared_secret, public_key, other_private_key);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if (shared_secret[i] != other_shared_secret[i]) {
|
||||
printf("key exchange was incorrect\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 32) {
|
||||
printf("key exchange was correct\n");
|
||||
}
|
||||
|
||||
/* test performance */
|
||||
printf("testing seed generation performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_create_seed(seed);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per seed\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
|
||||
printf("testing key generation performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_create_keypair(public_key, private_key, seed);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per keypair\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
printf("testing sign performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_sign(signature, message, message_len, public_key, private_key);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
printf("testing verify performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_verify(signature, message, message_len, public_key);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
|
||||
printf("testing keypair scalar addition performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_add_scalar(public_key, private_key, scalar);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per keypair\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
printf("testing public key scalar addition performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_add_scalar(public_key, NULL, scalar);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per key\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
printf("testing key exchange performance: ");
|
||||
start = clock();
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
ed25519_key_exchange(shared_secret, other_public_key, private_key);
|
||||
}
|
||||
end = clock();
|
||||
|
||||
printf("%fus per shared secret\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue