From bab680f35b16bcc5e93621358c85863ed8bc4f93 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 20 Oct 2017 01:45:49 +0200 Subject: [PATCH] Implement crypto_sign_ed25519_scalarmult() --- .../curve25519/ref10/curve25519_ref10.c | 115 +++++++++++++++++- .../crypto_sign/ed25519/ref10/keypair.c | 30 ++++- .../include/sodium/crypto_sign_ed25519.h | 5 + .../include/sodium/private/curve25519_ref10.h | 2 + 4 files changed, 149 insertions(+), 3 deletions(-) diff --git a/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c b/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c index a76a39d0..3552b63f 100644 --- a/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c +++ b/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c @@ -1572,6 +1572,23 @@ ge_p3_to_cached(ge_cached *r, const ge_p3 *p) fe_mul(r->T2d, p->T, d2); } +static void +ge_p3_to_precomp(ge_precomp *pi, const ge_p3 *p) +{ + fe recip; + fe x; + fe y; + fe xy; + + fe_invert(recip, p->Z); + fe_mul(x, p->X, recip); + fe_mul(y, p->Y, recip); + fe_add(pi->yplusx, y, x); + fe_sub(pi->yminusx, y, x); + fe_mul(xy, x, y); + fe_mul(pi->xy2d, xy, d2); +} + /* r = p */ @@ -1866,11 +1883,105 @@ ge_scalarmult_vartime(ge_p3 *r, const unsigned char *a, const ge_p3 *A) #endif +/* + h = a * p + where a = a[0]+256*a[1]+...+256^31 a[31] + + Preconditions: + a[31] <= 127 + + p is public + */ + +void +ge_scalarmult(ge_p3 *h, const unsigned char *a, const ge_p3 *p) +{ + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_p1p1 t2, t3, t4, t5, t6, t7, t8; + ge_p3 p2, p3, p4, p5, p6, p7, p8; + ge_precomp pi[8]; + ge_precomp t; + int i; + + ge_p3_to_precomp(&pi[1 - 1], p); /* p */ + + ge_p3_dbl(&t2, p); + ge_p1p1_to_p3(&p2, &t2); + ge_p3_to_precomp(&pi[2 - 1], &p2); /* 2p = 2*p */ + + ge_madd(&t3, p, &pi[2 - 1]); + ge_p1p1_to_p3(&p3, &t3); + ge_p3_to_precomp(&pi[3 - 1], &p3); /* 3p = 2p+p */ + + ge_p3_dbl(&t4, &p2); + ge_p1p1_to_p3(&p4, &t4); + ge_p3_to_precomp(&pi[4 - 1], &p4); /* 4p = 2*2p */ + + ge_madd(&t5, p, &pi[4 - 1]); + ge_p1p1_to_p3(&p5, &t5); + ge_p3_to_precomp(&pi[5 - 1], &p5); /* 5p = 4p+p */ + + ge_p3_dbl(&t6, &p3); + ge_p1p1_to_p3(&p6, &t6); + ge_p3_to_precomp(&pi[6 - 1], &p6); /* 6p = 2*3p */ + + ge_madd(&t7, p, &pi[6 - 1]); + ge_p1p1_to_p3(&p7, &t7); + ge_p3_to_precomp(&pi[7 - 1], &p7); /* 7p = 6p+p */ + + ge_p3_dbl(&t8, &p4); + ge_p1p1_to_p3(&p8, &t8); + ge_p3_to_precomp(&pi[8 - 1], &p8); /* 8p = 2*4p */ + + 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 * ((signed char) 1 << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(h); + + for (i = 63; i != 0; i--) { + ge_select(&t, pi, e[i]); + ge_madd(&r, h, &t); + + 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_p2(&s, &r); + ge_p2_dbl(&r, &s); + + ge_p1p1_to_p3(h, &r); /* *16 */ + } + ge_select(&t, pi, e[i]); + ge_madd(&r, h, &t); + + ge_p1p1_to_p3(h, &r); +} + /* h = a * B (with precomputation) where a = a[0]+256*a[1]+...+256^31 a[31] - B is the Ed25519 base point (x,4/5) with x positive. - * + B is the Ed25519 base point (x,4/5) with x positive + (as bytes: 0x5866666666666666666666666666666666666666666666666666666666666666) + Preconditions: a[31] <= 127 */ diff --git a/src/libsodium/crypto_sign/ed25519/ref10/keypair.c b/src/libsodium/crypto_sign/ed25519/ref10/keypair.c index b62a43e1..5ba6fd34 100644 --- a/src/libsodium/crypto_sign/ed25519/ref10/keypair.c +++ b/src/libsodium/crypto_sign/ed25519/ref10/keypair.c @@ -9,6 +9,34 @@ #include "randombytes.h" #include "utils.h" +int +crypto_sign_ed25519_scalarmult(unsigned char *q, const unsigned char *n, + const unsigned char *p) +{ + unsigned char *t = q; + ge_p3 Q; + ge_p3 P; + ge_p3 pl; + + if (_crypto_sign_ed25519_small_order(p) || + ge_frombytes_negate_vartime(&P, p) != 0) { + return -1; + } + ge_mul_l(&pl, &P); + if (fe_isnonzero(pl.X)) { + return -1; + } + memmove(t, n, 32); + t[0] &= 248; + t[31] &= 63; + t[31] |= 64; + ge_scalarmult(&Q, t, &P); + ge_p3_tobytes(q, &Q); + q[31] ^= 0x80; + + return 0; +} + int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed) @@ -16,7 +44,7 @@ crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, ge_p3 A; #ifdef ED25519_NONDETERMINISTIC - memcpy(sk, seed, 32); + memmove(sk, seed, 32); #else crypto_hash_sha512(sk, seed, 32); #endif diff --git a/src/libsodium/include/sodium/crypto_sign_ed25519.h b/src/libsodium/include/sodium/crypto_sign_ed25519.h index 38d2b9dd..fbda77fa 100644 --- a/src/libsodium/include/sodium/crypto_sign_ed25519.h +++ b/src/libsodium/include/sodium/crypto_sign_ed25519.h @@ -87,6 +87,11 @@ int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, SODIUM_EXPORT int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk); +SODIUM_EXPORT +int crypto_sign_ed25519_scalarmult(unsigned char *q, const unsigned char *n, + const unsigned char *p) + __attribute__ ((warn_unused_result)); + SODIUM_EXPORT int crypto_sign_ed25519ph_init(crypto_sign_ed25519ph_state *state); diff --git a/src/libsodium/include/sodium/private/curve25519_ref10.h b/src/libsodium/include/sodium/private/curve25519_ref10.h index 18780028..0494c379 100644 --- a/src/libsodium/include/sodium/private/curve25519_ref10.h +++ b/src/libsodium/include/sodium/private/curve25519_ref10.h @@ -100,6 +100,7 @@ typedef struct { #define ge_p1p1_to_p2 crypto_core_curve25519_ref10_ge_p1p1_to_p2 #define ge_add crypto_core_curve25519_ref10_ge_add +#define ge_scalarmult crypto_core_curve25519_ref10_ge_scalarmult #define ge_scalarmult_base crypto_core_curve25519_ref10_ge_scalarmult_base #define ge_double_scalarmult_vartime crypto_core_curve25519_ref10_ge_double_scalarmult_vartime #define ge_scalarmult_vartime crypto_core_curve25519_ref10_ge_scalarmult_vartime @@ -115,6 +116,7 @@ extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *); extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *); extern void ge_scalarmult_base(ge_p3 *,const unsigned char *); extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *); +extern void ge_scalarmult(ge_p3 *,const unsigned char *,const ge_p3 *); extern void ge_scalarmult_vartime(ge_p3 *,const unsigned char *,const ge_p3 *); extern void ge_mul_l(ge_p3 *r, const ge_p3 *A);