diff options
author | Gluzskiy Alexandr <sss@sss.chaoslab.ru> | 2017-02-13 07:56:33 +0300 |
---|---|---|
committer | Gluzskiy Alexandr <sss@sss.chaoslab.ru> | 2017-02-13 09:09:08 +0300 |
commit | 193f645f65ad4ffdec3186e4176b23af10861199 (patch) | |
tree | e1b16b48ac74c5f03f99a98798e849f6dd9752cc /libs/libaxolotl/src/curve25519/ed25519/additions | |
parent | 36c32a13878d3bd94e88bd9c764f1eadb05ea1ed (diff) |
libs:
libaxolotl:
updated libaxolotl (libsignal-c) from (https://github.com/WhisperSystems/libsignal-protocol-c)
Diffstat (limited to 'libs/libaxolotl/src/curve25519/ed25519/additions')
35 files changed, 1374 insertions, 86 deletions
diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/crypto_additions.h b/libs/libaxolotl/src/curve25519/ed25519/additions/crypto_additions.h new file mode 100644 index 0000000000..da4a1cd07b --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/crypto_additions.h @@ -0,0 +1,69 @@ + +#ifndef __CRYPTO_ADDITIONS__ +#define __CRYPTO_ADDITIONS__ + +#include "crypto_uint32.h" +#include "fe.h" +#include "ge.h" + +#define MAX_MSG_LEN 256 + +void sc_neg(unsigned char *b, const unsigned char *a); +void sc_cmov(unsigned char* f, const unsigned char* g, unsigned char b); + +int fe_isequal(const fe f, const fe g); +void fe_mont_rhs(fe v2, const fe u); +void fe_montx_to_edy(fe y, const fe u); +void fe_sqrt(fe b, const fe a); + +int ge_is_small_order(const ge_p3 *p); +int ge_isneutral(const ge_p3* q); +void ge_neg(ge_p3* r, const ge_p3 *p); +void ge_montx_to_p3(ge_p3* p, const fe u, const unsigned char ed_sign_bit); +void ge_p3_to_montx(fe u, const ge_p3 *p); +void ge_scalarmult(ge_p3 *h, const unsigned char *a, const ge_p3 *A); +void ge_scalarmult_cofactor(ge_p3 *q, const ge_p3 *p); + +void elligator(fe u, const fe r); +void hash_to_point(ge_p3* p, const unsigned char* msg, const unsigned long in_len); +void calculate_Bv(ge_p3* Bv, + unsigned char* buf, + const unsigned char* A, + const unsigned char* msg, const unsigned long msg_len); +void calculate_Bv_and_V(ge_p3* Bv, + unsigned char* V, + unsigned char* buf, + const unsigned char* a, + const unsigned char* A, + const unsigned char* msg, const unsigned long msg_len); + +int crypto_sign_modified( + unsigned char *sm, + const unsigned char *m,unsigned long long mlen, + const unsigned char *sk, /* Curve/Ed25519 private key */ + const unsigned char *pk, /* Ed25519 public key */ + const unsigned char *random /* 64 bytes random to hash into nonce */ + ); + +int crypto_sign_open_modified( + unsigned char *m, + const unsigned char *sm,unsigned long long smlen, + const unsigned char *pk + ); + +int crypto_vsign_modified( + unsigned char *sm, + const unsigned char *M,unsigned long Mlen, + const unsigned char *a, + const unsigned char *A, + const unsigned char *random, + const ge_p3 *Bu, + const unsigned char *U); + +int crypto_vsign_open_modified( + unsigned char *m, + const unsigned char *sm,unsigned long long smlen, + const unsigned char *pk, const ge_p3* Bu); + + +#endif diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.c b/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.c index 2a0aa54d4f..7a49b18aaa 100644 --- a/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.c +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.c @@ -3,36 +3,7 @@ #include "ge.h" #include "curve_sigs.h" #include "crypto_sign.h" - -void curve25519_keygen(unsigned char* curve25519_pubkey_out, - const unsigned char* curve25519_privkey_in) -{ - ge_p3 ed; /* Ed25519 pubkey point */ - fe ed_y, ed_y_plus_one, one_minus_ed_y, inv_one_minus_ed_y; - fe mont_x; - - /* Perform a fixed-base multiplication of the Edwards base point, - (which is efficient due to precalculated tables), then convert - to the Curve25519 montgomery-format public key. In particular, - convert Curve25519's "montgomery" x-coordinate into an Ed25519 - "edwards" y-coordinate: - - mont_x = (ed_y + 1) / (1 - ed_y) - - with projective coordinates: - - mont_x = (ed_y + ed_z) / (ed_z - ed_y) - - NOTE: ed_y=1 is converted to mont_x=0 since fe_invert is mod-exp - */ - - ge_scalarmult_base(&ed, curve25519_privkey_in); - fe_add(ed_y_plus_one, ed.Y, ed.Z); - fe_sub(one_minus_ed_y, ed.Z, ed.Y); - fe_invert(inv_one_minus_ed_y, one_minus_ed_y); - fe_mul(mont_x, ed_y_plus_one, inv_one_minus_ed_y); - fe_tobytes(curve25519_pubkey_out, mont_x); -} +#include "crypto_additions.h" int curve25519_sign(unsigned char* signature_out, const unsigned char* curve25519_privkey, @@ -71,18 +42,16 @@ int curve25519_verify(const unsigned char* signature, const unsigned char* curve25519_pubkey, const unsigned char* msg, const unsigned long msg_len) { - fe mont_x, mont_x_minus_one, mont_x_plus_one, inv_mont_x_plus_one; - fe one; - fe ed_y; + fe u; + fe y; unsigned char ed_pubkey[32]; - unsigned long long some_retval; - unsigned char *verifybuf = NULL; /* working buffer */ + unsigned char *verifybuf = NULL; /* working buffer */ unsigned char *verifybuf2 = NULL; /* working buffer #2 */ int result; if ((verifybuf = malloc(msg_len + 64)) == 0) { - result = -1; - goto err; + result = -1; + goto err; } if ((verifybuf2 = malloc(msg_len + 64)) == 0) { @@ -91,22 +60,18 @@ int curve25519_verify(const unsigned char* signature, } /* Convert the Curve25519 public key into an Ed25519 public key. In - particular, convert Curve25519's "montgomery" x-coordinate into an + particular, convert Curve25519's "montgomery" x-coordinate (u) into an Ed25519 "edwards" y-coordinate: - ed_y = (mont_x - 1) / (mont_x + 1) + y = (u - 1) / (u + 1) - NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp + NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp Then move the sign bit into the pubkey from the signature. */ - fe_frombytes(mont_x, curve25519_pubkey); - fe_1(one); - fe_sub(mont_x_minus_one, mont_x, one); - fe_add(mont_x_plus_one, mont_x, one); - fe_invert(inv_mont_x_plus_one, mont_x_plus_one); - fe_mul(ed_y, mont_x_minus_one, inv_mont_x_plus_one); - fe_tobytes(ed_pubkey, ed_y); + fe_frombytes(u, curve25519_pubkey); + fe_montx_to_edy(y, u); + fe_tobytes(ed_pubkey, y); /* Copy the sign bit, and remove it from signature */ ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */ @@ -120,9 +85,8 @@ int curve25519_verify(const unsigned char* signature, /* The below call has a strange API: */ /* verifybuf = R || S || message */ /* verifybuf2 = internal to next call gets a copy of verifybuf, S gets - replaced with pubkey for hashing, then the whole thing gets zeroized - (if bad sig), or contains a copy of msg (good sig) */ - result = crypto_sign_open(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey); + replaced with pubkey for hashing */ + result = crypto_sign_open_modified(verifybuf2, verifybuf, 64 + msg_len, ed_pubkey); err: diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.h b/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.h index b3dbad0155..a2d819aef0 100644 --- a/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.h +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/curve_sigs.h @@ -2,47 +2,16 @@ #ifndef __CURVE_SIGS_H__ #define __CURVE_SIGS_H__ -void curve25519_keygen(unsigned char* curve25519_pubkey_out, /* 32 bytes */ - const unsigned char* curve25519_privkey_in); /* 32 bytes */ - /* returns 0 on success */ int curve25519_sign(unsigned char* signature_out, /* 64 bytes */ const unsigned char* curve25519_privkey, /* 32 bytes */ - const unsigned char* msg, const unsigned long msg_len, + const unsigned char* msg, const unsigned long msg_len, /* <= 256 bytes */ const unsigned char* random); /* 64 bytes */ /* returns 0 on success */ int curve25519_verify(const unsigned char* signature, /* 64 bytes */ const unsigned char* curve25519_pubkey, /* 32 bytes */ - const unsigned char* msg, const unsigned long msg_len); - -/* helper function - modified version of crypto_sign() to use - explicit private key. In particular: - - sk : private key - pk : public key - msg : message - prefix : 0xFE || [0xFF]*31 - random : 64 bytes random - q : main subgroup order - - The prefix is chosen to distinguish the two SHA512 uses below, since - prefix is an invalid encoding for R (it would encode a "field element" - of 2^255 - 2). 0xFF*32 is set aside for use in ECDH protocols, which - is why the first byte here ix 0xFE. + const unsigned char* msg, const unsigned long msg_len); /* <= 256 bytes */ - sig_nonce = SHA512(prefix || sk || msg || random) % q - R = g^sig_nonce - M = SHA512(R || pk || m) - S = sig_nonce + (m * sk) - signature = (R || S) - */ -int crypto_sign_modified( - unsigned char *sm, - const unsigned char *m,unsigned long long mlen, - const unsigned char *sk, /* Curve/Ed25519 private key */ - const unsigned char *pk, /* Ed25519 public key */ - const unsigned char *random /* 64 bytes random to hash into nonce */ - ); #endif diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/elligator.c b/libs/libaxolotl/src/curve25519/ed25519/additions/elligator.c new file mode 100644 index 0000000000..8a8131ff2f --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/elligator.c @@ -0,0 +1,111 @@ +#include <string.h> +#include "fe.h" +#include "ge.h" +#include "crypto_uint32.h" +#include "crypto_hash_sha512.h" +#include "crypto_additions.h" + +unsigned int legendre_is_nonsquare(fe in) +{ + fe temp; + fe_pow22523(temp, in); /* temp = in^((q-5)/8) */ + fe_sq(temp, temp); /* in^((q-5)/4) */ + fe_sq(temp, temp); /* in^((q-5)/2) */ + fe_mul(temp, temp, in); /* in^((q-3)/2) */ + fe_mul(temp, temp, in); /* in^((q-1)/2) */ + + /* temp is now the Legendre symbol: + * 1 = square + * 0 = input is zero + * -1 = nonsquare + */ + unsigned char bytes[32]; + fe_tobytes(bytes, temp); + return 1 & bytes[31]; +} + +void elligator(fe u, const fe r) +{ + /* r = input + * x = -A/(1+2r^2) # 2 is nonsquare + * e = (x^3 + Ax^2 + x)^((q-1)/2) # legendre symbol + * if e == 1 (square) or e == 0 (because x == 0 and 2r^2 + 1 == 0) + * u = x + * if e == -1 (nonsquare) + * u = -x - A + */ + fe A, one, twor2, twor2plus1, twor2plus1inv; + fe x, e, Atemp, uneg; + unsigned int nonsquare; + + fe_1(one); + fe_0(A); + A[0] = 486662; /* A = 486662 */ + + fe_sq2(twor2, r); /* 2r^2 */ + fe_add(twor2plus1, twor2, one); /* 1+2r^2 */ + fe_invert(twor2plus1inv, twor2plus1); /* 1/(1+2r^2) */ + fe_mul(x, twor2plus1inv, A); /* A/(1+2r^2) */ + fe_neg(x, x); /* x = -A/(1+2r^2) */ + + fe_mont_rhs(e, x); /* e = x^3 + Ax^2 + x */ + nonsquare = legendre_is_nonsquare(e); + + fe_0(Atemp); + fe_cmov(Atemp, A, nonsquare); /* 0, or A if nonsquare */ + fe_add(u, x, Atemp); /* x, or x+A if nonsquare */ + fe_neg(uneg, u); /* -x, or -x-A if nonsquare */ + fe_cmov(u, uneg, nonsquare); /* x, or -x-A if nonsquare */ +} + +void hash_to_point(ge_p3* p, const unsigned char* in, const unsigned long in_len) +{ + unsigned char hash[64]; + fe h, u; + unsigned char sign_bit; + ge_p3 p3; + + crypto_hash_sha512(hash, in, in_len); + + /* take the high bit as Edwards sign bit */ + sign_bit = (hash[31] & 0x80) >> 7; + hash[31] &= 0x7F; + fe_frombytes(h, hash); + elligator(u, h); + + ge_montx_to_p3(&p3, u, sign_bit); + ge_scalarmult_cofactor(p, &p3); +} + + +void calculate_Bv(ge_p3* Bv, + unsigned char* buf, + const unsigned char* A, + const unsigned char* msg, const unsigned long msg_len) +{ + int count; + + /* Calculate SHA512(label(2) || A || msg) */ + buf[0] = 0xFD; + for (count = 1; count < 32; count++) + buf[count] = 0xFF; + memmove(buf+32, A, 32); + memmove(buf+64, msg, msg_len); + + hash_to_point(Bv, buf, 64 + msg_len); +} + + +void calculate_Bv_and_V(ge_p3* Bv, + unsigned char* V, + unsigned char* buf, + const unsigned char* a, + const unsigned char* A, + const unsigned char* msg, const unsigned long msg_len) +{ + ge_p3 p3; + + calculate_Bv(Bv, buf, A, msg, msg_len); + ge_scalarmult(&p3, a, Bv); + ge_p3_tobytes(V, &p3); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/fe_isequal.c b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_isequal.c new file mode 100644 index 0000000000..67c5d33c96 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_isequal.c @@ -0,0 +1,14 @@ +#include "fe.h" +#include "crypto_verify_32.h" + +/* +return 1 if f == g +return 0 if f != g +*/ + +int fe_isequal(const fe f, const fe g) +{ + fe h; + fe_sub(h, f, g); + return 1 ^ (1 & (fe_isnonzero(h) >> 8)); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/fe_mont_rhs.c b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_mont_rhs.c new file mode 100644 index 0000000000..bc8393620c --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_mont_rhs.c @@ -0,0 +1,17 @@ +#include "fe.h" + +void fe_mont_rhs(fe v2, fe u) { + fe A, one; + fe u2, Au, inner; + + fe_1(one); + fe_0(A); + A[0] = 486662; /* A = 486662 */ + + fe_sq(u2, u); /* u^2 */ + fe_mul(Au, A, u); /* Au */ + fe_add(inner, u2, Au); /* u^2 + Au */ + fe_add(inner, inner, one); /* u^2 + Au + 1 */ + fe_mul(v2, u, inner); /* u(u^2 + Au + 1) */ +} + diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/fe_montx_to_edy.c b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_montx_to_edy.c new file mode 100644 index 0000000000..b0f8c63276 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_montx_to_edy.c @@ -0,0 +1,19 @@ + +#include "fe.h" +#include "crypto_additions.h" + +void fe_montx_to_edy(fe y, const fe u) +{ + /* + y = (u - 1) / (u + 1) + + NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp + */ + fe one, um1, up1; + + fe_1(one); + fe_sub(um1, u, one); + fe_add(up1, u, one); + fe_invert(up1, up1); + fe_mul(y, um1, up1); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/fe_sqrt.c b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_sqrt.c new file mode 100644 index 0000000000..906d38b93e --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/fe_sqrt.c @@ -0,0 +1,50 @@ +#include <assert.h> +#include "fe.h" +#include "crypto_additions.h" + +/* sqrt(-1) */ +static unsigned char i_bytes[32] = { + 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, + 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f, + 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, + 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b +}; + +/* Preconditions: a is square or zero */ + +void fe_sqrt(fe out, const fe a) +{ + fe exp, b, b2, bi, i; + + fe_frombytes(i, i_bytes); + fe_pow22523(exp, a); /* b = a^(q-5)/8 */ + + /* PRECONDITION: legendre symbol == 1 (square) or 0 (a == zero) */ +#ifndef NDEBUG + fe legendre, zero, one; + + fe_sq(legendre, exp); /* in^((q-5)/4) */ + fe_sq(legendre, legendre); /* in^((q-5)/2) */ + fe_mul(legendre, legendre, a); /* in^((q-3)/2) */ + fe_mul(legendre, legendre, a); /* in^((q-1)/2) */ + + fe_0(zero); + fe_1(one); + assert(fe_isequal(legendre, zero) || fe_isequal(legendre, one)); +#endif + + fe_mul(b, a, exp); /* b = a * a^(q-5)/8 */ + fe_sq(b2, b); /* b^2 = a * a^(q-1)/4 */ + + /* note b^4 == a^2, so b^2 == a or -a + * if b^2 != a, multiply it by sqrt(-1) */ + fe_mul(bi, b, i); + fe_cmov(b, bi, 1 ^ fe_isequal(b2, a)); + fe_copy(out, b); + + /* PRECONDITION: out^2 == a */ +#ifndef NDEBUG + fe_sq(b2, out); + assert(fe_isequal(a, b2)); +#endif +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_is_small_order.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_is_small_order.c new file mode 100644 index 0000000000..845941be2a --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_is_small_order.c @@ -0,0 +1,30 @@ +#include "crypto_additions.h" +#include "ge.h" +#include "utility.h" +#include "stdio.h" + +/* +return 1 if f == g +return 0 if f != g +*/ + +int ge_is_small_order(const ge_p3 *p) +{ + ge_p1p1 p1p1; + ge_p2 p2; + fe zero; + + ge_p3_dbl(&p1p1, p); + ge_p1p1_to_p2(&p2, &p1p1); + + ge_p2_dbl(&p1p1, &p2); + ge_p1p1_to_p2(&p2, &p1p1); + + ge_p2_dbl(&p1p1, &p2); + ge_p1p1_to_p2(&p2, &p1p1); + + fe_0(zero); + + /* Check if 8*p == neutral element == (0, 1) */ + return (fe_isequal(p2.X, zero) & fe_isequal(p2.Y, p2.Z)); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_isneutral.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_isneutral.c new file mode 100644 index 0000000000..d40e443682 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_isneutral.c @@ -0,0 +1,16 @@ +#include "crypto_additions.h" +#include "ge.h" + +/* +return 1 if p is the neutral point +return 0 otherwise +*/ + +int ge_isneutral(const ge_p3 *p) +{ + fe zero; + fe_0(zero); + + /* Check if p == neutral element == (0, 1) */ + return (fe_isequal(p->X, zero) & fe_isequal(p->Y, p->Z)); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_montx_to_p2.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_montx_to_p2.c new file mode 100644 index 0000000000..d123d03580 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_montx_to_p2.c @@ -0,0 +1,69 @@ +#include "fe.h" +#include "ge.h" +#include "assert.h" +#include "crypto_additions.h" +#include "utility.h" + +/* sqrt(-(A+2)) */ +static unsigned char A_bytes[32] = { + 0x06, 0x7e, 0x45, 0xff, 0xaa, 0x04, 0x6e, 0xcc, + 0x82, 0x1a, 0x7d, 0x4b, 0xd1, 0xd3, 0xa1, 0xc5, + 0x7e, 0x4f, 0xfc, 0x03, 0xdc, 0x08, 0x7b, 0xd2, + 0xbb, 0x06, 0xa0, 0x60, 0xf4, 0xed, 0x26, 0x0f +}; + +void ge_montx_to_p2(ge_p2* p, const fe u, const unsigned char ed_sign_bit) +{ + fe x, y, A, v, v2, iv, nx; + + fe_frombytes(A, A_bytes); + + /* given u, recover edwards y */ + /* given u, recover v */ + /* given u and v, recover edwards x */ + + fe_montx_to_edy(y, u); /* y = (u - 1) / (u + 1) */ + + fe_mont_rhs(v2, u); /* v^2 = u(u^2 + Au + 1) */ + fe_sqrt(v, v2); /* v = sqrt(v^2) */ + + fe_mul(x, u, A); /* x = u * sqrt(-(A+2)) */ + fe_invert(iv, v); /* 1/v */ + fe_mul(x, x, iv); /* x = (u/v) * sqrt(-(A+2)) */ + + fe_neg(nx, x); /* negate x to match sign bit */ + fe_cmov(x, nx, fe_isnegative(x) ^ ed_sign_bit); + + fe_copy(p->X, x); + fe_copy(p->Y, y); + fe_1(p->Z); + + /* POSTCONDITION: check that p->X and p->Y satisfy the Ed curve equation */ + /* -x^2 + y^2 = 1 + dx^2y^2 */ +#ifndef NDEBUG + { + fe one, d, x2, y2, x2y2, dx2y2; + + unsigned char dbytes[32] = { + 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, + 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, + 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, + 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52 + }; + + fe_frombytes(d, dbytes); + fe_1(one); + fe_sq(x2, p->X); /* x^2 */ + fe_sq(y2, p->Y); /* y^2 */ + + fe_mul(dx2y2, x2, y2); /* x^2y^2 */ + fe_mul(dx2y2, dx2y2, d); /* dx^2y^2 */ + fe_add(dx2y2, dx2y2, one); /* dx^2y^2 + 1 */ + + fe_neg(x2y2, x2); /* -x^2 */ + fe_add(x2y2, x2y2, y2); /* -x^2 + y^2 */ + + assert(fe_isequal(x2y2, dx2y2)); + } +#endif +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_montx_to_p3.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_montx_to_p3.c new file mode 100644 index 0000000000..7a716c5a72 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_montx_to_p3.c @@ -0,0 +1,70 @@ +#include "fe.h" +#include "ge.h" +#include "assert.h" +#include "crypto_additions.h" +#include "utility.h" + +/* sqrt(-(A+2)) */ +static unsigned char A_bytes[32] = { + 0x06, 0x7e, 0x45, 0xff, 0xaa, 0x04, 0x6e, 0xcc, + 0x82, 0x1a, 0x7d, 0x4b, 0xd1, 0xd3, 0xa1, 0xc5, + 0x7e, 0x4f, 0xfc, 0x03, 0xdc, 0x08, 0x7b, 0xd2, + 0xbb, 0x06, 0xa0, 0x60, 0xf4, 0xed, 0x26, 0x0f +}; + +void ge_montx_to_p3(ge_p3* p, const fe u, const unsigned char ed_sign_bit) +{ + fe x, y, A, v, v2, iv, nx; + + fe_frombytes(A, A_bytes); + + /* given u, recover edwards y */ + /* given u, recover v */ + /* given u and v, recover edwards x */ + + fe_montx_to_edy(y, u); /* y = (u - 1) / (u + 1) */ + + fe_mont_rhs(v2, u); /* v^2 = u(u^2 + Au + 1) */ + fe_sqrt(v, v2); /* v = sqrt(v^2) */ + + fe_mul(x, u, A); /* x = u * sqrt(-(A+2)) */ + fe_invert(iv, v); /* 1/v */ + fe_mul(x, x, iv); /* x = (u/v) * sqrt(-(A+2)) */ + + fe_neg(nx, x); /* negate x to match sign bit */ + fe_cmov(x, nx, fe_isnegative(x) ^ ed_sign_bit); + + fe_copy(p->X, x); + fe_copy(p->Y, y); + fe_1(p->Z); + fe_mul(p->T, p->X, p->Y); + + /* POSTCONDITION: check that p->X and p->Y satisfy the Ed curve equation */ + /* -x^2 + y^2 = 1 + dx^2y^2 */ +#ifndef NDEBUG + { + fe one, d, x2, y2, x2y2, dx2y2; + + unsigned char dbytes[32] = { + 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, + 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, + 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, + 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52 + }; + + fe_frombytes(d, dbytes); + fe_1(one); + fe_sq(x2, p->X); /* x^2 */ + fe_sq(y2, p->Y); /* y^2 */ + + fe_mul(dx2y2, x2, y2); /* x^2y^2 */ + fe_mul(dx2y2, dx2y2, d); /* dx^2y^2 */ + fe_add(dx2y2, dx2y2, one); /* dx^2y^2 + 1 */ + + fe_neg(x2y2, x2); /* -x^2 */ + fe_add(x2y2, x2y2, y2); /* -x^2 + y^2 */ + + assert(fe_isequal(x2y2, dx2y2)); + } +#endif +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_neg.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_neg.c new file mode 100644 index 0000000000..d679713fe0 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_neg.c @@ -0,0 +1,15 @@ +#include "crypto_additions.h" +#include "ge.h" + +/* +return r = -p +*/ + + +void ge_neg(ge_p3* r, const ge_p3 *p) +{ + fe_neg(r->X, p->X); + fe_copy(r->Y, p->Y); + fe_copy(r->Z, p->Z); + fe_neg(r->T, p->T); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_p3_to_montx.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_p3_to_montx.c new file mode 100644 index 0000000000..b539b2f17f --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_p3_to_montx.c @@ -0,0 +1,21 @@ +#include "fe.h" +#include "crypto_additions.h" + +void ge_p3_to_montx(fe u, const ge_p3 *ed) +{ + /* + u = (y + 1) / (1 - y) + or + u = (y + z) / (z - y) + + NOTE: y=1 is converted to u=0 since fe_invert is mod-exp + */ + + fe y_plus_one, one_minus_y, inv_one_minus_y; + + fe_add(y_plus_one, ed->Y, ed->Z); + fe_sub(one_minus_y, ed->Z, ed->Y); + fe_invert(inv_one_minus_y, one_minus_y); + fe_mul(u, y_plus_one, inv_one_minus_y); +} + diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c new file mode 100644 index 0000000000..e4f741b8d8 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c @@ -0,0 +1,140 @@ +#include "crypto_uint32.h" +#include "ge.h" +#include "crypto_additions.h" + +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 */ + crypto_uint32 y = x; /* 0: yes; 1..255: no */ + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + return y; +} + +static unsigned char negative(signed char b) +{ + unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return x; +} + +static void cmov(ge_cached *t,const ge_cached *u,unsigned char b) +{ + fe_cmov(t->YplusX,u->YplusX,b); + fe_cmov(t->YminusX,u->YminusX,b); + fe_cmov(t->Z,u->Z,b); + fe_cmov(t->T2d,u->T2d,b); +} + +static void select(ge_cached *t,const ge_cached *pre, signed char b) +{ + ge_cached minust; + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + + fe_1(t->YplusX); + fe_1(t->YminusX); + fe_1(t->Z); + fe_0(t->T2d); + + cmov(t,pre+0,equal(babs,1)); + cmov(t,pre+1,equal(babs,2)); + cmov(t,pre+2,equal(babs,3)); + cmov(t,pre+3,equal(babs,4)); + cmov(t,pre+4,equal(babs,5)); + cmov(t,pre+5,equal(babs,6)); + cmov(t,pre+6,equal(babs,7)); + cmov(t,pre+7,equal(babs,8)); + fe_copy(minust.YplusX,t->YminusX); + fe_copy(minust.YminusX,t->YplusX); + fe_copy(minust.Z,t->Z); + fe_neg(minust.T2d,t->T2d); + 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(ge_p3 *h, const unsigned char *a, const ge_p3 *A) +{ + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_p3 t0, t1, t2; + ge_cached t, pre[8]; + 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 */ + + // Precomputation: + ge_p3_to_cached(pre+0, A); // A + + ge_p3_dbl(&r, A); + ge_p1p1_to_p3(&t0, &r); + ge_p3_to_cached(pre+1, &t0); // 2A + + ge_add(&r, A, pre+1); + ge_p1p1_to_p3(&t1, &r); + ge_p3_to_cached(pre+2, &t1); // 3A + + ge_p3_dbl(&r, &t0); + ge_p1p1_to_p3(&t0, &r); + ge_p3_to_cached(pre+3, &t0); // 4A + + ge_add(&r, A, pre+3); + ge_p1p1_to_p3(&t2, &r); + ge_p3_to_cached(pre+4, &t2); // 5A + + ge_p3_dbl(&r, &t1); + ge_p1p1_to_p3(&t1, &r); + ge_p3_to_cached(pre+5, &t1); // 6A + + ge_add(&r, A, pre+5); + ge_p1p1_to_p3(&t1, &r); + ge_p3_to_cached(pre+6, &t1); // 7A + + ge_p3_dbl(&r, &t0); + ge_p1p1_to_p3(&t0, &r); + ge_p3_to_cached(pre+7, &t0); // 8A + + ge_p3_0(h); + + for (i = 63;i > 0; i--) { + select(&t,pre,e[i]); + ge_add(&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); + + } + select(&t,pre,e[0]); + ge_add(&r, h, &t); + ge_p1p1_to_p3(h,&r); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult_cofactor.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult_cofactor.c new file mode 100644 index 0000000000..6affbb05d5 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult_cofactor.c @@ -0,0 +1,21 @@ +#include "crypto_additions.h" +#include "ge.h" + +/* +return 8 * p +*/ + +void ge_scalarmult_cofactor(ge_p3 *q, const ge_p3 *p) +{ + ge_p1p1 p1p1; + ge_p2 p2; + + ge_p3_dbl(&p1p1, p); + ge_p1p1_to_p2(&p2, &p1p1); + + ge_p2_dbl(&p1p1, &p2); + ge_p1p1_to_p2(&p2, &p1p1); + + ge_p2_dbl(&p1p1, &p2); + ge_p1p1_to_p3(q, &p1p1); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/keygen.c b/libs/libaxolotl/src/curve25519/ed25519/additions/keygen.c new file mode 100644 index 0000000000..de7cdcd598 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/keygen.c @@ -0,0 +1,21 @@ +#include "ge.h" +#include "keygen.h" +#include "crypto_additions.h" + +void curve25519_keygen(unsigned char* curve25519_pubkey_out, + const unsigned char* curve25519_privkey_in) +{ + /* Perform a fixed-base multiplication of the Edwards base point, + (which is efficient due to precalculated tables), then convert + to the Curve25519 montgomery-format public key. + + NOTE: y=1 is converted to u=0 since fe_invert is mod-exp + */ + + ge_p3 ed; /* Ed25519 pubkey point */ + fe u; + + ge_scalarmult_base(&ed, curve25519_privkey_in); + ge_p3_to_montx(u, &ed); + fe_tobytes(curve25519_pubkey_out, u); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/keygen.h b/libs/libaxolotl/src/curve25519/ed25519/additions/keygen.h new file mode 100644 index 0000000000..e86e7c5582 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/keygen.h @@ -0,0 +1,12 @@ + +#ifndef __KEYGEN_H__ +#define __KEYGEN_H__ + +/* Sets and clears bits to make a random 32 bytes into a private key */ +void sc_clamp(unsigned char* a); + +/* The private key should be 32 random bytes "clamped" by sc_clamp() */ +void curve25519_keygen(unsigned char* curve25519_pubkey_out, /* 32 bytes */ + const unsigned char* curve25519_privkey_in); /* 32 bytes */ + +#endif diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/open_modified.c b/libs/libaxolotl/src/curve25519/ed25519/additions/open_modified.c new file mode 100644 index 0000000000..a156098191 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/open_modified.c @@ -0,0 +1,45 @@ +#include <string.h> +#include "crypto_sign.h" +#include "crypto_hash_sha512.h" +#include "crypto_verify_32.h" +#include "ge.h" +#include "sc.h" +#include "crypto_additions.h" + +int crypto_sign_open_modified( + unsigned char *m, + const unsigned char *sm,unsigned long long smlen, + const unsigned char *pk +) +{ + unsigned char pkcopy[32]; + unsigned char rcopy[32]; + unsigned char scopy[32]; + unsigned char h[64]; + unsigned char rcheck[32]; + ge_p3 A; + ge_p2 R; + + if (smlen < 64) goto badsig; + if (sm[63] & 224) goto badsig; /* strict parsing of s */ + if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig; + + memmove(pkcopy,pk,32); + memmove(rcopy,sm,32); + memmove(scopy,sm + 32,32); + + memmove(m,sm,smlen); + memmove(m + 32,pkcopy,32); + crypto_hash_sha512(h,m,smlen); + sc_reduce(h); + + ge_double_scalarmult_vartime(&R,h,&A,scopy); + ge_tobytes(rcheck,&R); + + if (crypto_verify_32(rcheck,rcopy) == 0) { + return 0; + } + +badsig: + return -1; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/sc_clamp.c b/libs/libaxolotl/src/curve25519/ed25519/additions/sc_clamp.c new file mode 100644 index 0000000000..7788be9071 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/sc_clamp.c @@ -0,0 +1,8 @@ +#include "crypto_additions.h" + +void sc_clamp(unsigned char* a) +{ + a[0] &= 248; + a[31] &= 127; + a[31] |= 64; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/sc_cmov.c b/libs/libaxolotl/src/curve25519/ed25519/additions/sc_cmov.c new file mode 100644 index 0000000000..443a5bb71e --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/sc_cmov.c @@ -0,0 +1,21 @@ +#include "crypto_additions.h" + +/* +Replace (f,g) with (g,g) if b == 1; +replace (f,g) with (f,g) if b == 0. + +Preconditions: b in {0,1}. +*/ + +void sc_cmov(unsigned char* f, const unsigned char* g, unsigned char b) +{ + int count=32; + unsigned char x[32]; + for (count=0; count < 32; count++) + x[count] = f[count] ^ g[count]; + b = -b; + for (count=0; count < 32; count++) + x[count] &= b; + for (count=0; count < 32; count++) + f[count] = f[count] ^ x[count]; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/sc_neg.c b/libs/libaxolotl/src/curve25519/ed25519/additions/sc_neg.c new file mode 100644 index 0000000000..ef407d405e --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/sc_neg.c @@ -0,0 +1,25 @@ +#include <string.h> +#include "crypto_additions.h" +#include "sc.h" + +/* l = order of base point = 2^252 + 27742317777372353535851937790883648493 */ + +/* +static unsigned char l[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x10}; +*/ + +static unsigned char lminus1[32] = {0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + +/* b = -a (mod l) */ +void sc_neg(unsigned char *b, const unsigned char *a) +{ + unsigned char zero[32]; + memset(zero, 0, 32); + sc_muladd(b, lminus1, a, zero); /* b = (-1)a + 0 (mod l) */ +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/sign_modified.c b/libs/libaxolotl/src/curve25519/ed25519/additions/sign_modified.c index 61332e70e7..b2fb8c20d3 100644 --- a/libs/libaxolotl/src/curve25519/ed25519/additions/sign_modified.c +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/sign_modified.c @@ -4,6 +4,7 @@ #include "ge.h" #include "sc.h" #include "zeroize.h" +#include "crypto_additions.h" /* NEW: Compare to pristine crypto_sign() Uses explicit private key for nonce derivation and as scalar, @@ -36,6 +37,7 @@ int crypto_sign_modified( memmove(sm + 32,pk,32); sc_reduce(nonce); + ge_scalarmult_base(&R,nonce); ge_p3_tobytes(sm,&R); @@ -43,5 +45,9 @@ int crypto_sign_modified( sc_reduce(hram); sc_muladd(sm + 32,hram,sk,nonce); /* NEW: Use privkey directly */ + /* Erase any traces of private scalar or + nonce left in the stack from sc_muladd */ + zeroize_stack(); + zeroize(nonce, 64); return 0; } diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/uopen_modified.c b/libs/libaxolotl/src/curve25519/ed25519/additions/uopen_modified.c new file mode 100644 index 0000000000..412f8c4c9b --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/uopen_modified.c @@ -0,0 +1,100 @@ +#include <string.h> +#include "sc.h" +#include "ge.h" +#include "crypto_hash_sha512.h" +#include "crypto_verify_32.h" +#include "crypto_additions.h" +#include "crypto_sign.h" + +int crypto_usign_open_modified( + unsigned char *m,unsigned long long *mlen, + const unsigned char *sm,unsigned long long smlen, + const unsigned char *pk, const ge_p3* Bu +) +{ + ge_p3 U; + unsigned char h[64]; + unsigned char s[64]; + unsigned char strict[64]; + ge_p3 A; + ge_p2 R; + unsigned char hcheck[64]; + int count; + + if (smlen < 96) goto badsig; + if (sm[63] & 224) goto badsig; /* strict parsing of h */ + if (sm[95] & 224) goto badsig; /* strict parsing of s */ + + /* Load -A */ + if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig; + + /* Load -U, h, s */ + ge_frombytes_negate_vartime(&U, sm); + memset(h, 0, 64); + memset(s, 0, 64); + memmove(h, sm + 32, 32); + memmove(s, sm + 64, 32); + + /* Insist that s and h are reduced scalars (strict parsing) */ + memcpy(strict, h, 64); + sc_reduce(strict); + if (memcmp(strict, h, 32) != 0) + goto badsig; + memcpy(strict, s, 64); + sc_reduce(strict); + if (memcmp(strict, s, 32) != 0) + goto badsig; + + /* Reject U (actually -U) if small order */ + if (ge_is_small_order(&U)) + goto badsig; + + // R = sB + h(-A) + ge_double_scalarmult_vartime(&R,h,&A,s); + + // Ru = sBu + h(-U) + ge_p3 sBu, hU; + + // sBu + ge_scalarmult(&sBu, s, Bu); + + // h(-U) + ge_scalarmult(&hU, h, &U); + + // Ru = sBu + h(-U) + ge_p1p1 Rp1p1; + ge_p3 Ru; + ge_cached hUcached; + ge_p3_to_cached(&hUcached, &hU); + ge_add(&Rp1p1, &sBu, &hUcached); + ge_p1p1_to_p3(&Ru, &Rp1p1); + + + // Check h == SHA512(label(4) || A || U || R || Ru || M) + m[0] = 0xFB; + for (count = 1; count < 32; count++) + m[count] = 0xFF; + memmove(m+32, pk, 32); + /* undo the negation for U */ + fe_neg(U.X, U.X); + fe_neg(U.T, U.T); + ge_p3_tobytes(m+64, &U); + ge_tobytes(m+96, &R); + ge_p3_tobytes(m+128, &Ru); + memmove(m+160, sm+96, smlen - 96); + + crypto_hash_sha512(hcheck, m, smlen + 64); + sc_reduce(hcheck); + + if (crypto_verify_32(hcheck, h) == 0) { + memmove(m,m + 64,smlen - 64); + memset(m + smlen - 64,0,64); + *mlen = smlen - 64; + return 0; + } + +badsig: + *mlen = -1; + memset(m,0,smlen); + return -1; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/usign_modified.c b/libs/libaxolotl/src/curve25519/ed25519/additions/usign_modified.c new file mode 100644 index 0000000000..3bbd871b7a --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/usign_modified.c @@ -0,0 +1,62 @@ +#include <string.h> +#include "crypto_sign.h" +#include "crypto_hash_sha512.h" +#include "ge.h" +#include "sc.h" +#include "zeroize.h" +#include "crypto_additions.h" + +/* NEW: Compare to pristine crypto_sign() + Uses explicit private key for nonce derivation and as scalar, + instead of deriving both from a master key. +*/ +int crypto_usign_modified( + unsigned char *sm, + const unsigned char *M,unsigned long Mlen, + const unsigned char *a, + const unsigned char *A, + const unsigned char *random, + const ge_p3 *Bu, + const unsigned char *U +) +{ + unsigned char r[64]; + unsigned char h[64]; + ge_p3 R, Ru; + int count=0; + + /* r = SHA512(label(3) || a || U || random(64)) */ + sm[0] = 0xFC; + for (count = 1; count < 32; count++) + sm[count] = 0xFF; + + memmove(sm + 32, a, 32); /* Use privkey directly for nonce derivation */ + memmove(sm + 64, U, 32); + + memmove(sm + 96, random, 64); /* Add suffix of random data */ + crypto_hash_sha512(r, sm, 160); + + sc_reduce(r); + ge_scalarmult_base(&R, r); + ge_scalarmult(&Ru, r, Bu); + + /* h = SHA512(label(4) || A || U || R || Ru || M) */ + sm[0] = 0xFB; + memmove(sm + 32, A, 32); + memmove(sm + 64, U, 32); + ge_p3_tobytes(sm+96, &R); + ge_p3_tobytes(sm+128, &Ru); + memmove(sm + 160, M, Mlen); + + crypto_hash_sha512(h, sm, Mlen + 160); + sc_reduce(h); + + memmove(sm, h, 32); /* Write h */ + sc_muladd(sm + 32, h, a, r); /* Write s */ + + /* Erase any traces of private scalar or + nonce left in the stack from sc_muladd. */ + zeroize_stack(); + zeroize(r, 64); + return 0; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/utility.c b/libs/libaxolotl/src/curve25519/ed25519/additions/utility.c new file mode 100644 index 0000000000..c59099a9e3 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/utility.c @@ -0,0 +1,29 @@ +#include <stdlib.h> +#include <stdio.h> +#include "utility.h" + +void print_vector(const char* name, const unsigned char* v) +{ + int count; + printf("%s = \n", name); + for (count = 0; count < 32; count++) + printf("%02x ", v[count]); + printf("\n"); +} + +void print_bytes(const char* name, const unsigned char* v, int numbytes) +{ + int count; + printf("%s = \n", name); + for (count = 0; count < numbytes; count++) + printf("%02x ", v[count]); + printf("\n"); +} + +void print_fe(const char* name, const fe in) +{ + unsigned char bytes[32]; + fe_tobytes(bytes, in); + print_vector(name, bytes); +} + diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/utility.h b/libs/libaxolotl/src/curve25519/ed25519/additions/utility.h new file mode 100644 index 0000000000..35348782df --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/utility.h @@ -0,0 +1,11 @@ + +#ifndef __UTILITY_H__ +#define __UTILITY_H__ + +#include "fe.h" + +void print_vector(const char* name, const unsigned char* v); +void print_bytes(const char* name, const unsigned char* v, int numbytes); +void print_fe(const char* name, const fe in); + +#endif diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/vopen_modified.c b/libs/libaxolotl/src/curve25519/ed25519/additions/vopen_modified.c new file mode 100644 index 0000000000..3dfc7fba6f --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/vopen_modified.c @@ -0,0 +1,85 @@ +#include <string.h> +#include "sc.h" +#include "ge.h" +#include "crypto_hash_sha512.h" +#include "crypto_verify_32.h" +#include "crypto_additions.h" +#include "crypto_sign.h" + +int crypto_vsign_open_modified( + unsigned char *m, + const unsigned char *sm,unsigned long long smlen, + const unsigned char *pk, const ge_p3* Bv +) +{ + ge_p3 Vneg, V, Aneg, A, c_V, c_A, h_Vneg, s_Bv; + unsigned char h[32]; + unsigned char s[32]; + ge_p2 R; + unsigned char hcheck[64]; + unsigned char vrf_output[64]; + int count; + + if (smlen < 96) goto badsig; + if (sm[63] & 224) goto badsig; /* strict parsing of h */ + if (sm[95] & 224) goto badsig; /* strict parsing of s */ + + /* Load -A */ + if (ge_frombytes_negate_vartime(&Aneg,pk) != 0) goto badsig; + + /* Load -V, h, s */ + if (ge_frombytes_negate_vartime(&Vneg, sm) != 0) goto badsig; + memmove(h, sm + 32, 32); + memmove(s, sm + 64, 32); + if (h[31] & 224) goto badsig; /* strict parsing of h */ + if (s[31] & 224) goto badsig; /* strict parsing of s */ + + ge_neg(&A, &Aneg); + ge_neg(&V, &Vneg); + ge_scalarmult_cofactor(&c_A, &A); + ge_scalarmult_cofactor(&c_V, &V); + if (ge_isneutral(&c_A) || ge_isneutral(&c_V) || ge_isneutral(Bv)) + goto badsig; + + // R = (s*B) + (h * -A)) + ge_double_scalarmult_vartime(&R, h, &Aneg, s); + + // s * Bv + ge_scalarmult(&s_Bv, s, Bv); + + // h * -V + ge_scalarmult(&h_Vneg, h, &Vneg); + + // Rv = (sc * Bv) + (hc * (-V)) + ge_p1p1 Rp1p1; + ge_p3 Rv; + ge_cached h_Vnegcached; + ge_p3_to_cached(&h_Vnegcached, &h_Vneg); + ge_add(&Rp1p1, &s_Bv, &h_Vnegcached); + ge_p1p1_to_p3(&Rv, &Rp1p1); + + // Check h == SHA512(label(4) || A || V || R || Rv || M) + m[0] = 0xFB; // label 4 + for (count = 1; count < 32; count++) + m[count] = 0xFF; + memmove(m+32, pk, 32); + ge_p3_tobytes(m+64, &V); + ge_tobytes(m+96, &R); + ge_p3_tobytes(m+128, &Rv); + memmove(m+160, sm+96, smlen - 96); + + crypto_hash_sha512(hcheck, m, smlen + 64); + sc_reduce(hcheck); + + if (crypto_verify_32(hcheck, h) == 0) { + ge_p3_tobytes(m+32, &c_V); + m[0] = 0xFA; // label 5 + crypto_hash_sha512(vrf_output, m, 64); + memmove(m, vrf_output, 32); + return 0; + } + +badsig: + memset(m, 0, 32); + return -1; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/vsign_modified.c b/libs/libaxolotl/src/curve25519/ed25519/additions/vsign_modified.c new file mode 100644 index 0000000000..518b851d63 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/vsign_modified.c @@ -0,0 +1,62 @@ +#include <string.h> +#include "crypto_sign.h" +#include "crypto_hash_sha512.h" +#include "ge.h" +#include "sc.h" +#include "zeroize.h" +#include "crypto_additions.h" + +/* NEW: Compare to pristine crypto_sign() + Uses explicit private key for nonce derivation and as scalar, + instead of deriving both from a master key. +*/ +int crypto_vsign_modified( + unsigned char *sm, + const unsigned char *M,unsigned long Mlen, + const unsigned char *a, + const unsigned char *A, + const unsigned char *random, + const ge_p3 *Bv, + const unsigned char *V +) +{ + unsigned char r[64]; + unsigned char h[64]; + ge_p3 R, Rv; + int count=0; + + /* r = SHA512(label(3) || a || V || random(64)) */ + sm[0] = 0xFC; + for (count = 1; count < 32; count++) + sm[count] = 0xFF; + + memmove(sm + 32, a, 32); /* Use privkey directly for nonce derivation */ + memmove(sm + 64, V, 32); + + memmove(sm + 96, random, 64); /* Add suffix of random data */ + crypto_hash_sha512(r, sm, 160); + + sc_reduce(r); + ge_scalarmult_base(&R, r); + ge_scalarmult(&Rv, r, Bv); + + /* h = SHA512(label(4) || A || V || R || Rv || M) */ + sm[0] = 0xFB; + memmove(sm + 32, A, 32); + memmove(sm + 64, V, 32); + ge_p3_tobytes(sm+96, &R); + ge_p3_tobytes(sm+128, &Rv); + memmove(sm + 160, M, Mlen); + + crypto_hash_sha512(h, sm, Mlen + 160); + sc_reduce(h); + + memmove(sm, h, 32); /* Write h */ + sc_muladd(sm + 32, h, a, r); /* Write s */ + + /* Erase any traces of private scalar or + nonce left in the stack from sc_muladd. */ + zeroize_stack(); + zeroize(r, 64); + return 0; +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/vxeddsa.c b/libs/libaxolotl/src/curve25519/ed25519/additions/vxeddsa.c new file mode 100644 index 0000000000..802a73563d --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/vxeddsa.c @@ -0,0 +1,91 @@ +#include <string.h> +#include "ge.h" +#include "crypto_additions.h" +#include "zeroize.h" +#include "vxeddsa.h" +#include "crypto_verify_32.h" + +int vxed25519_sign(unsigned char* signature_out, + const unsigned char* curve25519_privkey, + const unsigned char* msg, const unsigned long msg_len, + const unsigned char* random) +{ + unsigned char a[32], aneg[32]; + unsigned char A[32]; + ge_p3 Bv, ed_pubkey_point; + unsigned char sigbuf[MAX_MSG_LEN + 160]; /* working buffer */ + unsigned char sign_bit = 0; + + if (msg_len > MAX_MSG_LEN) { + memset(signature_out, 0, 96); + return -1; + } + /* Convert the Curve25519 privkey to an Ed25519 public key */ + ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); + ge_p3_tobytes(A, &ed_pubkey_point); + + /* Force Edwards sign bit to zero */ + sign_bit = (A[31] & 0x80) >> 7; + memcpy(a, curve25519_privkey, 32); + sc_neg(aneg, a); + sc_cmov(a, aneg, sign_bit); + A[31] &= 0x7F; + + calculate_Bv_and_V(&Bv, signature_out, sigbuf, a, A, msg, msg_len); + + /* Perform an Ed25519 signature with explicit private key */ + crypto_vsign_modified(sigbuf, msg, msg_len, a, A, random, &Bv, signature_out /*V*/); + memmove(signature_out+32, sigbuf, 64); + + zeroize(a, 32); + zeroize(aneg, 32); + return 0; +} + +int vxed25519_verify(unsigned char* vrf_out, + const unsigned char* signature, + const unsigned char* curve25519_pubkey, + const unsigned char* msg, const unsigned long msg_len) +{ + fe u; + fe y; + unsigned char ed_pubkey[32]; + unsigned char strict[32]; + unsigned char verifybuf[MAX_MSG_LEN + 160]; /* working buffer */ + unsigned char verifybuf2[MAX_MSG_LEN + 160]; /* working buffer #2 ?? !!! */ + ge_p3 Bv; + + if (msg_len > MAX_MSG_LEN) { + return -1; + } + + /* Convert the Curve25519 public key (u) into an Ed25519 public key. + + y = (u - 1) / (u + 1) + + NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp + */ + fe_frombytes(u, curve25519_pubkey); + fe_tobytes(strict, u); + if (crypto_verify_32(strict, curve25519_pubkey) != 0) + return 0; + fe_montx_to_edy(y, u); + fe_tobytes(ed_pubkey, y); + + calculate_Bv(&Bv, verifybuf, ed_pubkey, msg, msg_len); + + memmove(verifybuf, signature, 96); + memmove(verifybuf+96, msg, msg_len); + + /* Then perform a signature verification, return 0 on success */ + /* The below call has a strange API: */ + /* verifybuf = V || h || s || message */ + /* verifybuf2 = used as buffer, gets the VRF output if success */ + if (crypto_vsign_open_modified(verifybuf2, verifybuf, 96 + msg_len, ed_pubkey, &Bv) == 0) { + memmove(vrf_out, verifybuf2, 32); + return 0; + } else { + memset(vrf_out, 0, 32); + return -1; + } +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/vxeddsa.h b/libs/libaxolotl/src/curve25519/ed25519/additions/vxeddsa.h new file mode 100644 index 0000000000..4e48844170 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/vxeddsa.h @@ -0,0 +1,18 @@ + +#ifndef __VXEDDSA_H__ +#define __VXEDDSA_H__ + +/* returns 0 on success */ +int vxed25519_sign(unsigned char* signature_out, /* 96 bytes */ + const unsigned char* curve25519_privkey, /* 32 bytes */ + const unsigned char* msg, const unsigned long msg_len, /* <= 256 bytes */ + const unsigned char* random); /* 64 bytes */ + +/* returns 0 on success */ +int vxed25519_verify(unsigned char* vrf_out, /* 32 bytes */ + const unsigned char* signature, /* 96 bytes */ + const unsigned char* curve25519_pubkey, /* 32 bytes */ + const unsigned char* msg, const unsigned long msg_len); /* <= 256 bytes */ + + +#endif diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/xeddsa.c b/libs/libaxolotl/src/curve25519/ed25519/additions/xeddsa.c new file mode 100644 index 0000000000..ee2964a0d5 --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/xeddsa.c @@ -0,0 +1,82 @@ +#include <string.h> +#include "ge.h" +#include "crypto_additions.h" +#include "zeroize.h" +#include "xeddsa.h" +#include "crypto_verify_32.h" + +int xed25519_sign(unsigned char* signature_out, + const unsigned char* curve25519_privkey, + const unsigned char* msg, const unsigned long msg_len, + const unsigned char* random) +{ + unsigned char a[32], aneg[32]; + unsigned char A[32]; + ge_p3 ed_pubkey_point; + unsigned char *sigbuf; /* working buffer */ + unsigned char sign_bit = 0; + + if ((sigbuf = malloc(msg_len + 128)) == 0) { + memset(signature_out, 0, 64); + return -1; + } + + /* Convert the Curve25519 privkey to an Ed25519 public key */ + ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); + ge_p3_tobytes(A, &ed_pubkey_point); + + /* Force Edwards sign bit to zero */ + sign_bit = (A[31] & 0x80) >> 7; + memcpy(a, curve25519_privkey, 32); + sc_neg(aneg, a); + sc_cmov(a, aneg, sign_bit); + A[31] &= 0x7F; + + /* Perform an Ed25519 signature with explicit private key */ + crypto_sign_modified(sigbuf, msg, msg_len, a, A, random); + memmove(signature_out, sigbuf, 64); + + zeroize(a, 32); + zeroize(aneg, 32); + free(sigbuf); + return 0; +} + +int xed25519_verify(const unsigned char* signature, + const unsigned char* curve25519_pubkey, + const unsigned char* msg, const unsigned long msg_len) +{ + fe u; + fe y; + unsigned char ed_pubkey[32]; + unsigned char strict[32]; + unsigned char verifybuf[MAX_MSG_LEN + 64]; /* working buffer */ + unsigned char verifybuf2[MAX_MSG_LEN + 64]; /* working buffer #2 */ + + if (msg_len > MAX_MSG_LEN) { + return -1; + } + + /* Convert the Curve25519 public key into an Ed25519 public key. + + y = (u - 1) / (u + 1) + + NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp + */ + fe_frombytes(u, curve25519_pubkey); + fe_tobytes(strict, u); + if (crypto_verify_32(strict, curve25519_pubkey) != 0) + return 0; + fe_montx_to_edy(y, u); + fe_tobytes(ed_pubkey, y); + + memmove(verifybuf, signature, 64); + memmove(verifybuf+64, msg, msg_len); + + /* Then perform a normal Ed25519 verification, return 0 on success */ + /* The below call has a strange API: */ + /* verifybuf = R || S || message */ + /* verifybuf2 = internal to next call gets a copy of verifybuf, S gets + replaced with pubkey for hashing */ + return crypto_sign_open_modified(verifybuf2, verifybuf, 64 + msg_len, ed_pubkey); +} diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/xeddsa.h b/libs/libaxolotl/src/curve25519/ed25519/additions/xeddsa.h new file mode 100644 index 0000000000..b86d7f0d9d --- /dev/null +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/xeddsa.h @@ -0,0 +1,16 @@ + +#ifndef __XEDDSA_H__ +#define __XEDDSA_H__ + +/* returns 0 on success */ +int xed25519_sign(unsigned char* signature_out, /* 64 bytes */ + const unsigned char* curve25519_privkey, /* 32 bytes */ + const unsigned char* msg, const unsigned long msg_len, /* <= 256 bytes */ + const unsigned char* random); /* 64 bytes */ + +/* returns 0 on success */ +int xed25519_verify(const unsigned char* signature, /* 64 bytes */ + const unsigned char* curve25519_pubkey, /* 32 bytes */ + const unsigned char* msg, const unsigned long msg_len); /* <= 256 bytes */ + +#endif diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.c b/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.c index 37c1f708bc..187e725eb5 100644 --- a/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.c +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.c @@ -3,7 +3,6 @@ void zeroize(unsigned char* b, size_t len) { size_t count = 0; - unsigned long retval = 0; volatile unsigned char *p = b; for (count = 0; count < len; count++) @@ -13,5 +12,5 @@ void zeroize(unsigned char* b, size_t len) void zeroize_stack() { unsigned char m[ZEROIZE_STACK_SIZE]; - zeroize(m, sizeof m); + zeroize(m, ZEROIZE_STACK_SIZE); } diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.h b/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.h index 80fcffb768..0db68bb4c6 100644 --- a/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.h +++ b/libs/libaxolotl/src/curve25519/ed25519/additions/zeroize.h @@ -3,7 +3,7 @@ #include <stdlib.h> -#define ZEROIZE_STACK_SIZE 2048 +#define ZEROIZE_STACK_SIZE 1024 void zeroize(unsigned char* b, size_t len); |