Compare commits

...

2 Commits

Author SHA1 Message Date
Moxie Marlinspike
813bdffeb5 Reinstate dynamic memory allocation
// FREEBIE
2016-08-10 15:18:45 -07:00
Moxie Marlinspike
4c2a5e9343 Add VUF support
// FREEBIE
2016-08-09 16:03:21 -07:00
36 changed files with 1581 additions and 178 deletions

View File

@ -11,6 +11,8 @@
#include <jni.h>
#include "curve25519-donna.h"
#include "curve_sigs.h"
#include "xdsa.h"
#include "uxdsa.h"
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_generatePrivateKey
(JNIEnv *env, jobject obj, jbyteArray random)
@ -70,7 +72,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_curve25519_NativeCurve25519
uint8_t* messageBytes = (uint8_t*)(*env)->GetByteArrayElements(env, message, 0);
jsize messageLength = (*env)->GetArrayLength(env, message);
int result = curve25519_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength, randomBytes);
int result = xdsa_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength, randomBytes);
(*env)->ReleaseByteArrayElements(env, signature, signatureBytes, 0);
(*env)->ReleaseByteArrayElements(env, random, randomBytes, 0);
@ -98,6 +100,45 @@ JNIEXPORT jboolean JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Pr
return result;
}
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_calculateUniqueSignature
(JNIEnv *env, jobject obj, jbyteArray random, jbyteArray privateKey, jbyteArray message)
{
jbyteArray signature = (*env)->NewByteArray(env, 96);
uint8_t* signatureBytes = (uint8_t*)(*env)->GetByteArrayElements(env, signature, 0);
uint8_t* randomBytes = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0);
uint8_t* privateKeyBytes = (uint8_t*)(*env)->GetByteArrayElements(env, privateKey, 0);
uint8_t* messageBytes = (uint8_t*)(*env)->GetByteArrayElements(env, message, 0);
jsize messageLength = (*env)->GetArrayLength(env, message);
int result = uxdsa_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength, randomBytes);
(*env)->ReleaseByteArrayElements(env, signature, signatureBytes, 0);
(*env)->ReleaseByteArrayElements(env, random, randomBytes, 0);
(*env)->ReleaseByteArrayElements(env, privateKey, privateKeyBytes, 0);
(*env)->ReleaseByteArrayElements(env, message, messageBytes, 0);
if (result == 0) return signature;
else (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/AssertionError"), "Signature failed!");
}
JNIEXPORT jboolean JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_verifyUniqueSignature
(JNIEnv *env, jobject obj, jbyteArray publicKey, jbyteArray message, jbyteArray signature)
{
uint8_t* signatureBytes = (uint8_t*)(*env)->GetByteArrayElements(env, signature, 0);
uint8_t* publicKeyBytes = (uint8_t*)(*env)->GetByteArrayElements(env, publicKey, 0);
uint8_t* messageBytes = (uint8_t*)(*env)->GetByteArrayElements(env, message, 0);
jsize messageLength = (*env)->GetArrayLength(env, message);
jboolean result = (uxdsa_verify(signatureBytes, publicKeyBytes, messageBytes, messageLength) == 0);
(*env)->ReleaseByteArrayElements(env, signature, signatureBytes, 0);
(*env)->ReleaseByteArrayElements(env, publicKey, publicKeyBytes, 0);
(*env)->ReleaseByteArrayElements(env, message, messageBytes, 0);
return result;
}
JNIEXPORT jboolean JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_smokeCheck
(JNIEnv *env, jobject obj, jint dummy)
{

View File

@ -0,0 +1,59 @@
#ifndef __CRYPTO_ADDITIONS__
#define __CRYPTO_ADDITIONS__
#include "crypto_uint32.h"
#include "fe.h"
#include "ge.h"
#define MAX_MSG_LEN 256
/* aneg = -a */
void sc_neg(unsigned char *aneg, const unsigned char *a);
void fe_montx_to_edy(fe edy, const fe montx);
void ge_p3_to_montx(fe montx, const ge_p3 *ed);
void ge_scalarmult(ge_p3 *h, const unsigned char *a, const ge_p3 *A);
void elligator(fe out, const fe in);
void hash_to_point(ge_p3* out, const unsigned char* in, const unsigned long in_len);
void calculate_Bu(ge_p3* Bu,
unsigned char* buf,
const unsigned char* msg, const unsigned long msg_len);
void calculate_Bu_and_U(ge_p3* Bu,
unsigned char* U,
unsigned char* buf,
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,unsigned long long *mlen,
const unsigned char *sm,unsigned long long smlen,
const unsigned char *pk
);
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);
int crypto_usign_open_modified(
unsigned char *m,unsigned long long *mlen,
const unsigned char *sm,unsigned long long smlen,
const unsigned char *pk, ge_p3* Bu);
#endif

View File

@ -1,38 +1,8 @@
#include <string.h>
#include <stdlib.h>
#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,8 +41,7 @@ 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 mont_x;
fe ed_y;
unsigned char ed_pubkey[32];
unsigned long long some_retval;
@ -81,8 +50,8 @@ int curve25519_verify(const unsigned char* signature,
int result;
if ((verifybuf = malloc(msg_len + 64)) == 0) {
result = -1;
goto err;
result = -1;
goto err;
}
if ((verifybuf2 = malloc(msg_len + 64)) == 0) {
@ -90,6 +59,7 @@ int curve25519_verify(const unsigned char* signature,
goto err;
}
/* Convert the Curve25519 public key into an Ed25519 public key. In
particular, convert Curve25519's "montgomery" x-coordinate into an
Ed25519 "edwards" y-coordinate:
@ -101,11 +71,7 @@ int curve25519_verify(const unsigned char* signature,
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_montx_to_edy(ed_y, mont_x);
fe_tobytes(ed_pubkey, ed_y);
/* Copy the sign bit, and remove it from signature */
@ -122,7 +88,7 @@ int curve25519_verify(const unsigned char* signature,
/* 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);
result = crypto_sign_open_modified(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey);
err:

View File

@ -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);
const unsigned char* msg, const unsigned long msg_len); /* <= 256 bytes */
/* 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.
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

View File

@ -0,0 +1,141 @@
#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 mont_x, const fe in)
{
/* r = in
* v = -A/(1+2r^2)
* e = (v^3 + Av^2 + v)^((q-1)/2) # legendre symbol
* if e == 1 (square) or e == 0 (because v == 0 and 2r^2 + 1 == 0)
* out = v
* if e == -1 (nonsquare)
* out = -v - A
*/
fe A, one, twor2, twor2plus1, twor2plus1inv;
fe v, v2, v3, Av2, e, u, Atemp, uneg;
unsigned int nonsquare;
fe_0(one);
one[0] = 1; /* 1 */
fe_0(A);
A[0] = 486662; /* A = 486662 */
fe_sq2(twor2, in); /* 2r^2 */
fe_add(twor2plus1, twor2, one); /* 1+2r^2 */
fe_invert(twor2plus1inv, twor2plus1); /* 1/(1+2r^2) */
fe_mul(v, twor2plus1inv, A); /* A/(1+2r^2) */
fe_neg(v, v); /* v = -A/(1+2r^2) */
fe_sq(v2, v); /* v^2 */
fe_mul(v3, v2, v); /* v^3 */
fe_mul(Av2, v2, A); /* Av^2 */
fe_add(e, v3, Av2); /* v^3 + Av^2 */
fe_add(e, e, v); /* v^3 + Av^2 + v */
nonsquare = legendre_is_nonsquare(e);
fe_0(Atemp);
fe_cmov(Atemp, A, nonsquare); /* 0, or A if nonsquare */
fe_add(u, v, Atemp); /* v, or v+A if nonsquare */
fe_neg(uneg, u); /* -v, or -v-A if nonsquare */
fe_cmov(u, uneg, nonsquare); /* v, or -v-A if nonsquare */
fe_copy(mont_x, u);
}
void hash_to_point(ge_p3* out, const unsigned char* in, const unsigned long in_len)
{
unsigned char hash[64];
fe h, mont_x;
unsigned char sign_bit;
/* hash and elligator */
crypto_hash_sha512(hash, in, in_len);
sign_bit = hash[31] & 0x80; /* take the high bit as Edwards sign bit */
hash[31] &= 0x7F;
fe_frombytes(h, hash);
elligator(mont_x, h);
fe ed_y;
unsigned char ed_pubkey[32];
fe_montx_to_edy(ed_y, mont_x);
fe_tobytes(ed_pubkey, ed_y);
ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */
ed_pubkey[31] |= sign_bit;
/* decompress full point */
/* WARNING - due to timing-variance, don't use with secret inputs! */
ge_frombytes_negate_vartime(out, ed_pubkey);
/* undo the negation */
fe_neg(out->X, out->X);
fe_neg(out->T, out->T);
/* multiply by 8 (cofactor) to map onto the main subgroup,
* or map small-order points to the neutral element
* (the latter prevents leaking r mod (2, 4, 8) via U) */
ge_p1p1 dbl_result;
ge_p3_dbl(&dbl_result, out);
ge_p1p1_to_p3(out, &dbl_result);
ge_p3_dbl(&dbl_result, out);
ge_p1p1_to_p3(out, &dbl_result);
ge_p3_dbl(&dbl_result, out);
ge_p1p1_to_p3(out, &dbl_result);
}
void calculate_Bu(ge_p3* Bu,
unsigned char* buf,
const unsigned char* msg, const unsigned long msg_len)
{
int count;
/* Calculate SHA512(label(2) || msg) */
buf[0] = 0xFD;
for (count = 1; count < 32; count++)
buf[count] = 0xFF;
memmove(buf+32, msg, msg_len);
hash_to_point(Bu, buf, 32 + msg_len);
}
void calculate_Bu_and_U(ge_p3* Bu,
unsigned char* U,
unsigned char* buf,
const unsigned char* a,
const unsigned char* msg, const unsigned long msg_len)
{
ge_p3 p3;
calculate_Bu(Bu, buf, msg, msg_len);
ge_scalarmult(&p3, a, Bu);
ge_p3_tobytes(U, &p3);
}

View File

@ -0,0 +1,19 @@
#include "fe.h"
#include "crypto_additions.h"
void fe_montx_to_edy(fe edy, const fe montx)
{
/*
ed_y = (mont_x - 1) / (mont_x + 1)
NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
*/
fe one, montx_minus_one, montx_plus_one, inv_montx_plus_one;
fe_1(one);
fe_sub(montx_minus_one, montx, one);
fe_add(montx_plus_one, montx, one);
fe_invert(inv_montx_plus_one, montx_plus_one);
fe_mul(edy, montx_minus_one, inv_montx_plus_one);
}

View File

@ -0,0 +1,22 @@
#include "fe.h"
#include "crypto_additions.h"
void ge_p3_to_montx(fe montx, const ge_p3 *ed)
{
/*
mont_x = (ed_y + 1) / (1 - ed_y)
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
*/
fe edy_plus_one, one_minus_edy, inv_one_minus_edy;
fe_add(edy_plus_one, ed->Y, ed->Z);
fe_sub(one_minus_edy, ed->Z, ed->Y);
fe_invert(inv_one_minus_edy, one_minus_edy);
fe_mul(montx, edy_plus_one, inv_one_minus_edy);
}

View File

@ -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);
}

View File

@ -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: ed_y=1 is converted to mont_x=0 since fe_invert is mod-exp
*/
ge_p3 ed; /* Ed25519 pubkey point */
fe mont_x;
ge_scalarmult_base(&ed, curve25519_privkey_in);
ge_p3_to_montx(mont_x, &ed);
fe_tobytes(curve25519_pubkey_out, mont_x);
}

View File

@ -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

View File

@ -0,0 +1,50 @@
#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,unsigned long long *mlen,
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) {
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;
}

View File

@ -0,0 +1,8 @@
#include "crypto_additions.h"
void sc_clamp(unsigned char* a)
{
a[0] &= 248;
a[31] &= 127;
a[31] |= 64;
}

View File

@ -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};
/* aneg = -a (mod L) */
void sc_neg(unsigned char *aneg, const unsigned char *a)
{
unsigned char zero[32];
memset(zero, 0, 32);
sc_muladd(aneg, Lminus1, a, zero); /* sneg = (-1)s + 0 (mod L) */
}

View File

@ -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);

View File

@ -0,0 +1,96 @@
#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, 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;
// 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;
}

View File

@ -0,0 +1,58 @@
#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 */
return 0;
}

View File

@ -0,0 +1,25 @@
#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_fe(const char* name, const fe in)
{
unsigned char bytes[32];
fe_tobytes(bytes, in);
print_vector(name, bytes);
}
void print_error(const char* error)
{
printf("ERROR: %s\n", error);
abort();
}

View File

@ -0,0 +1,12 @@
#ifndef __UTILITY_H__
#define __UTILITY_H__
#include "fe.h"
void print_vector(const char* name, const unsigned char* v);
void print_fe(const char* name, const fe in);
void print_error(const char* error);
#endif

View File

@ -0,0 +1,80 @@
#include <string.h>
#include <stdio.h>
#include "ge.h"
#include "crypto_additions.h"
int uxdsa_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];
unsigned char A[32];
ge_p3 Bu, 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;
if (sign_bit) {
sc_neg(a, curve25519_privkey);
A[31] &= 0x7F;
}
else
memcpy(a, curve25519_privkey, 32);
calculate_Bu_and_U(&Bu, signature_out, sigbuf, a, msg, msg_len);
/* Perform an Ed25519 signature with explicit private key */
crypto_usign_modified(sigbuf, msg, msg_len, a, A, random, &Bu, signature_out /*U*/);
memmove(signature_out+32, sigbuf, 64);
return 0;
}
int uxdsa_verify(const unsigned char* signature,
const unsigned char* curve25519_pubkey,
const unsigned char* msg, const unsigned long msg_len)
{
fe mont_x;
fe ed_y;
unsigned char ed_pubkey[32];
unsigned long long some_retval;
unsigned char verifybuf[MAX_MSG_LEN + 160]; /* working buffer */
unsigned char verifybuf2[MAX_MSG_LEN + 160]; /* working buffer #2 ?? !!! */
ge_p3 Bu;
if (msg_len > MAX_MSG_LEN) {
return -1;
}
calculate_Bu(&Bu, verifybuf, msg, msg_len);
/* Convert the Curve25519 public key into an Ed25519 public key.
ed_y = (mont_x - 1) / (mont_x + 1)
NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
*/
fe_frombytes(mont_x, curve25519_pubkey);
fe_montx_to_edy(ed_y, mont_x);
fe_tobytes(ed_pubkey, ed_y);
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 = U || h || 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) */
return crypto_usign_open_modified(verifybuf2, &some_retval, verifybuf, 96 + msg_len, ed_pubkey, &Bu);
}

View File

@ -0,0 +1,20 @@
#ifndef __UXDSA_H__
#define __UXDSA_H__
/* WARNING: signing is non-constant time, based on the message (not the private key) */
/* This should be fixed if signing messages with secret contents */
/* returns 0 on success */
int uxdsa_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 uxdsa_verify(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

View File

@ -0,0 +1,78 @@
#include <string.h>
#include "ge.h"
#include "curve_sigs.h"
#include "crypto_sign.h"
#include "crypto_additions.h"
int xdsa_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];
unsigned char A[32];
ge_p3 ed_pubkey_point;
unsigned char sigbuf[MAX_MSG_LEN + 128]; /* working buffer */
unsigned char sign_bit = 0;
if (msg_len > MAX_MSG_LEN) {
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;
if (sign_bit) {
sc_neg(a, curve25519_privkey);
A[31] &= 0x7F;
}
else
memcpy(a, curve25519_privkey, 32);
/* Perform an Ed25519 signature with explicit private key */
crypto_sign_modified(sigbuf, msg, msg_len, a, A, random);
memmove(signature_out, sigbuf, 64);
return 0;
}
int xdsa_verify(const unsigned char* signature,
const unsigned char* curve25519_pubkey,
const unsigned char* msg, const unsigned long msg_len)
{
fe mont_x;
fe ed_y;
unsigned char ed_pubkey[32];
unsigned long long some_retval;
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.
ed_y = (mont_x - 1) / (mont_x + 1)
NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
*/
fe_frombytes(mont_x, curve25519_pubkey);
fe_montx_to_edy(ed_y, mont_x);
fe_tobytes(ed_pubkey, ed_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, then the whole thing gets zeroized
(if bad sig), or contains a copy of msg (good sig) */
return crypto_sign_open_modified(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey);
}

View File

@ -0,0 +1,16 @@
#ifndef __XDSA_H__
#define __XDSA_H__
/* returns 0 on success */
int xdsa_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 xdsa_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

View File

@ -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++)

View File

@ -2,7 +2,7 @@
#include "crypto_verify_32.h"
/*
return 1 if f == 0
return nonzero if f == 0
return 0 if f != 0
Preconditions:

View File

@ -1,106 +1,13 @@
#include <stdio.h>
#include <string.h>
#include "crypto_hash_sha512.h"
#include "curve_sigs.h"
#include "tests.h"
#define MSG_LEN 200
int main(int argc, char* argv[])
{
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[64];
unsigned char msg[MSG_LEN];
unsigned char random[64];
all_fast_tests(0);
/* Initialize pubkey, privkey, msg */
memset(msg, 0, MSG_LEN);
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
privkey[0] &= 248;
privkey[31] &= 63;
privkey[31] |= 64;
privkey[8] = 189; /* just so there's some bits set */
/* SHA512 test */
unsigned char sha512_input[112] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
unsigned char sha512_correct_output[64] =
{
0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
};
unsigned char sha512_actual_output[64];
crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input));
if (memcmp(sha512_actual_output, sha512_correct_output, 64) != 0)
printf("SHA512 bad #1\n");
else
printf("SHA512 good #1\n");
sha512_input[111] ^= 1;
crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input));
if (memcmp(sha512_actual_output, sha512_correct_output, 64) != 0)
printf("SHA512 good #2\n");
else
printf("SHA512 bad #2\n");
/* Signature test */
curve25519_keygen(pubkey, privkey);
curve25519_sign(signature, privkey, msg, MSG_LEN, random);
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
printf("Signature good #1\n");
else
printf("Signature bad #1\n");
signature[0] ^= 1;
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
printf("Signature bad #2\n");
else
printf("Signature good #2\n");
printf("Random testing...\n");
for (int count = 0; count < 10000; count++) {
unsigned char b[64];
crypto_hash_sha512(b, privkey, 32);
memmove(privkey, b, 32);
crypto_hash_sha512(b, privkey, 32);
memmove(random, b, 64);
privkey[0] &= 248;
privkey[31] &= 63;
privkey[31] |= 64;
curve25519_keygen(pubkey, privkey);
curve25519_sign(signature, privkey, msg, MSG_LEN, random);
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0) {
printf("failure #1 %d\n", count);
return -1;
}
if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0) {
printf("failure #2 %d\n", count);
return -1;
}
}
printf("OK\n");
return 1;
curvesigs_slow_test(0, 10000);
xdsa_slow_test(0, 10000);
xdsa_to_curvesigs_slow_test(0, 10000);
uxdsa_slow_test(0, 10000);
return 0;
}

View File

@ -0,0 +1,587 @@
#include <stdio.h>
#include <string.h>
#include "crypto_hash_sha512.h"
#include "keygen.h"
#include "curve_sigs.h"
#include "xdsa.h"
#include "uxdsa.h"
#include "crypto_additions.h"
#include "ge.h"
#include "utility.h"
#include "tests.h"
#define MSG_LEN 200
#define ERROR(msg) {if (!silent) print_error(msg); else return -1; }
#define INFO(msg) {if (!silent) printf("%s\n", msg);}
int sha512_fast_test(int silent)
{
unsigned char sha512_input[112] =
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
unsigned char sha512_correct_output[64] =
{
0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
};
unsigned char sha512_actual_output[64];
crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input));
if (memcmp(sha512_actual_output, sha512_correct_output, 64) != 0)
ERROR("SHA512 #1 BAD")
else
INFO("SHA512 #1 good");
sha512_input[111] ^= 1;
crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input));
if (memcmp(sha512_actual_output, sha512_correct_output, 64) != 0)
INFO("SHA512 #2 good")
else
ERROR("SHA512 #2 BAD");
return 0;
}
int elligator_fast_test(int silent)
{
unsigned char elligator_correct_output[32] =
{
0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36,
0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac, 0x22,
0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72,
0x44, 0x49, 0x15, 0x89, 0x9d, 0x95, 0xf4, 0x6e
};
unsigned char hashtopoint_correct_output[32] =
{
0xce, 0x89, 0x9f, 0xb2, 0x8f, 0xf7, 0x20, 0x91,
0x5e, 0x14, 0xf5, 0xb7, 0x99, 0x08, 0xab, 0x17,
0xaa, 0x2e, 0xe2, 0x45, 0xb4, 0xfc, 0x2b, 0xf6,
0x06, 0x36, 0x29, 0x40, 0xed, 0x7d, 0xe7, 0xed
};
unsigned char calculateu_correct_output[32] =
{
0xa8, 0x36, 0xb5, 0x30, 0xd3, 0xe7, 0x65, 0x54,
0x3e, 0x72, 0xc8, 0x87, 0x7d, 0xa4, 0x12, 0x6d,
0x77, 0xbf, 0x22, 0x0b, 0x72, 0xd5, 0xad, 0x6b,
0xb6, 0xc2, 0x16, 0xb2, 0x92, 0x5f, 0x0f, 0x2a
};
int count;
fe in, out;
unsigned char bytes[32];
fe_0(in);
fe_0(out);
for (count = 0; count < 32; count++) {
bytes[count] = count;
}
fe_frombytes(in, bytes);
elligator(out, in);
fe_tobytes(bytes, out);
if (memcmp(bytes, elligator_correct_output, 32) != 0)
ERROR("Elligator BAD!!!")
else
INFO("Elligator good");
/*
// Test whether Elligator can calculate Legendre == 0
// Answer appears to be yes, since 2r^2 + 1 == 0 has a solution
//
fe NEG1;
fe ONE;
fe TWO;
fe_1(ONE);
fe_add(TWO, ONE, ONE);
fe_neg(NEG1, ONE);
printf("NEG1\n");
legendre_is_nonsquare(out, NEG1);
printf("TWO\n");
legendre_is_nonsquare(out, TWO);
print_error("done");
*/
/* Hash to point vector test */
ge_p3 p3;
unsigned char htp[32];
for (count=0; count < 32; count++) {
htp[count] = count;
}
hash_to_point(&p3, htp, 32);
ge_p3_tobytes(htp, &p3);
if (memcmp(htp, hashtopoint_correct_output, 32) != 0)
ERROR("hash_to_point BAD!!!")
else
INFO("hash_to_point good");
/* calculate_U vector test */
ge_p3 Bu;
unsigned char U[32];
unsigned char Ubuf[200];
unsigned char a[32];
unsigned char Umsg[3];
Umsg[0] = 0;
Umsg[1] = 1;
Umsg[2] = 2;
for (count=0; count < 32; count++) {
a[count] = 8 + count;
}
sc_clamp(a);
calculate_Bu_and_U(&Bu, U, Ubuf, a, Umsg, 3);
if (memcmp(U, calculateu_correct_output, 32) != 0)
ERROR("calculate_U BAD!!!")
else
INFO("calculate_U good");
return 0;
}
int curvesigs_fast_test(int silent)
{
unsigned char signature_correct[64] = {
0xcf, 0x87, 0x3d, 0x03, 0x79, 0xac, 0x20, 0xe8,
0x89, 0x3e, 0x55, 0x67, 0xee, 0x0f, 0x89, 0x51,
0xf8, 0xdb, 0x84, 0x0d, 0x26, 0xb2, 0x43, 0xb4,
0x63, 0x52, 0x66, 0x89, 0xd0, 0x1c, 0xa7, 0x18,
0xac, 0x18, 0x9f, 0xb1, 0x67, 0x85, 0x74, 0xeb,
0xdd, 0xe5, 0x69, 0x33, 0x06, 0x59, 0x44, 0x8b,
0x0b, 0xd6, 0xc1, 0x97, 0x3f, 0x7d, 0x78, 0x0a,
0xb3, 0x95, 0x18, 0x62, 0x68, 0x03, 0xd7, 0x82,
};
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[64];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 0, 64);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
privkey[8] = 189; /* just so there's some bits set */
sc_clamp(privkey);
/* Signature vector test */
curve25519_keygen(pubkey, privkey);
curve25519_sign(signature, privkey, msg, MSG_LEN, random);
if (memcmp(signature, signature_correct, 64) != 0)
ERROR("Curvesig incorrect - BAD")
else
INFO("Curvesig correct - good");
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
INFO("Curvesig #1 verified - good")
else
ERROR("Curvesig #1 didn't verify - BAD");
signature[0] ^= 1;
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("Curvesig #2 verified - BAD")
else
INFO("Curvesig #2 didn't verify - good");
return 0;
}
int xdsa_fast_test(int silent)
{
unsigned char signature_correct[64] = {
0x11, 0xc7, 0xf3, 0xe6, 0xc4, 0xdf, 0x9e, 0x8a,
0x51, 0x50, 0xe1, 0xdb, 0x3b, 0x30, 0xf9, 0x2d,
0xe3, 0xa3, 0xb3, 0xaa, 0x43, 0x86, 0x56, 0x54,
0x5f, 0xa7, 0x39, 0x0f, 0x4b, 0xcc, 0x7b, 0xb2,
0x6c, 0x43, 0x1d, 0x9e, 0x90, 0x64, 0x3e, 0x4f,
0x0e, 0xaa, 0x0e, 0x9c, 0x55, 0x77, 0x66, 0xfa,
0x69, 0xad, 0xa5, 0x76, 0xd6, 0x3d, 0xca, 0xf2,
0xac, 0x32, 0x6c, 0x11, 0xd0, 0xb9, 0x77, 0x02,
};
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[64];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 0, 64);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
privkey[8] = 189; /* just so there's some bits set */
sc_clamp(privkey);
/* Signature vector test */
curve25519_keygen(pubkey, privkey);
xdsa_sign(signature, privkey, msg, MSG_LEN, random);
if (memcmp(signature, signature_correct, 64) != 0)
ERROR("XDSA incorrect - BAD")
else
INFO("XDSA correct - good");
if (xdsa_verify(signature, pubkey, msg, MSG_LEN) == 0)
INFO("XDSA #1 verified - good")
else
ERROR("XDSA #1 didn't verify - BAD");
signature[0] ^= 1;
if (xdsa_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("XDSA #2 verified - BAD")
else
INFO("XDSA #2 didn't verify - good");
return 0;
}
int uxdsa_fast_test(int silent)
{
unsigned char signature_correct[96] = {
0x66, 0x51, 0x0b, 0x68, 0x9e, 0xb7, 0xd8, 0x55,
0x04, 0x62, 0xaf, 0x52, 0x0c, 0x89, 0x69, 0xe8,
0xa9, 0xa5, 0x3d, 0xf3, 0x8e, 0xd6, 0xe6, 0x0f,
0xe8, 0xfe, 0xd6, 0xa8, 0x95, 0x66, 0x9c, 0x19,
0x66, 0x4a, 0x65, 0x25, 0xff, 0xb7, 0x47, 0x74,
0x8e, 0x86, 0x40, 0x55, 0x0f, 0xb1, 0x4a, 0xd1,
0x6d, 0xe0, 0x3d, 0x51, 0xa2, 0xd3, 0x4d, 0xee,
0x64, 0x7e, 0x35, 0x98, 0x42, 0x25, 0x5a, 0x02,
0xf8, 0x8c, 0x1e, 0x23, 0x5b, 0xd5, 0x7f, 0xb9,
0x98, 0x60, 0x55, 0x63, 0xd6, 0xe0, 0x6d, 0xa1,
0x29, 0xd9, 0xfc, 0xee, 0x1c, 0x08, 0x6d, 0x5a,
0x28, 0xa1, 0x27, 0xf0, 0x06, 0xb9, 0x79, 0x03
};
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[96];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 0, 96);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
privkey[8] = 189; /* just so there's some bits set */
sc_clamp(privkey);
/* Signature vector test */
curve25519_keygen(pubkey, privkey);
uxdsa_sign(signature, privkey, msg, MSG_LEN, random);
if (memcmp(signature, signature_correct, 96) != 0)
ERROR("UXDSA incorrect - BAD")
else
INFO("UXDSA correct - good");
if (uxdsa_verify(signature, pubkey, msg, MSG_LEN) == 0)
INFO("UXDSA #1 verified - good")
else
ERROR("UXDSA #1 didn't verify - BAD");
signature[0] ^= 1;
if (uxdsa_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("UXDSA #2 verified - BAD")
else
INFO("UXDSA #2 didn't verify - good");
/* Test U */
unsigned char sigprev[96];
memcpy(sigprev, signature, 96);
sigprev[0] ^= 1; /* undo prev disturbance */
random[0] ^= 1;
uxdsa_sign(signature, privkey, msg, MSG_LEN, random);
if (memcmp(signature, sigprev, 32) != 0)
ERROR("UXDSA U value changed - BAD")
else
INFO("UXDSA U value constant - good");
if (memcmp(signature+32, sigprev+32, 64) == 0)
ERROR("UXDSA (h, s) values didn't change - BAD")
else
INFO("UXDSA (h, s) values changed - good");
return 0;
}
int curvesigs_slow_test(int silent, int iterations)
{
unsigned char signature_10k_correct[64] = {
0xfc, 0xba, 0x55, 0xc4, 0x85, 0x4a, 0x42, 0x25,
0x19, 0xab, 0x08, 0x8d, 0xfe, 0xb5, 0x13, 0xb6,
0x0d, 0x24, 0xbb, 0x16, 0x27, 0x55, 0x71, 0x48,
0xdd, 0x20, 0xb1, 0xcd, 0x2a, 0xd6, 0x7e, 0x35,
0xef, 0x33, 0x4c, 0x7b, 0x6d, 0x94, 0x6f, 0x52,
0xec, 0x43, 0xd7, 0xe6, 0x35, 0x24, 0xcd, 0x5b,
0x5d, 0xdc, 0xb2, 0x32, 0xc6, 0x22, 0x53, 0xf3,
0x38, 0x02, 0xf8, 0x28, 0x28, 0xc5, 0x65, 0x05,
};
int count;
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[64];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 0, 64);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
/* Signature random test */
INFO("Pseudorandom curvesigs...");
for (count = 1; count <= iterations; count++) {
unsigned char b[64];
crypto_hash_sha512(b, signature, 64);
memmove(privkey, b, 32);
crypto_hash_sha512(b, privkey, 32);
memmove(random, b, 64);
sc_clamp(privkey);
curve25519_keygen(pubkey, privkey);
curve25519_sign(signature, privkey, msg, MSG_LEN, random);
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0)
ERROR("Curvesig verify failure #1");
if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("Curvesig verify failure #2");
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 64) != 0)
ERROR("Curvesig signature 10K doesn't match");
}
}
INFO("good");
return 1;
}
int xdsa_slow_test(int silent, int iterations)
{
unsigned char signature_10k_correct[64] = {
0x15, 0x29, 0x03, 0x38, 0x66, 0x16, 0xcd, 0x26,
0xbb, 0x3e, 0xec, 0xe2, 0x9f, 0x72, 0xa2, 0x5c,
0x7d, 0x05, 0xc9, 0xcb, 0x84, 0x3f, 0x92, 0x96,
0xb3, 0xfb, 0xb9, 0xdd, 0xd6, 0xed, 0x99, 0x04,
0xc1, 0xa8, 0x02, 0x16, 0xcf, 0x49, 0x3f, 0xf1,
0xbe, 0x69, 0xf9, 0xf1, 0xcc, 0x16, 0xd7, 0xdc,
0x6e, 0xd3, 0x78, 0xaa, 0x04, 0xeb, 0x71, 0x51,
0x9d, 0xe8, 0x7a, 0x5b, 0xd8, 0x49, 0x7b, 0x05,
};
int count;
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[96];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 1, 64);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
/* Signature random test */
INFO("Pseudorandom XDSA...");
for (count = 1; count <= iterations; count++) {
unsigned char b[64];
crypto_hash_sha512(b, signature, 64);
memmove(privkey, b, 32);
crypto_hash_sha512(b, privkey, 32);
memmove(random, b, 64);
sc_clamp(privkey);
curve25519_keygen(pubkey, privkey);
xdsa_sign(signature, privkey, msg, MSG_LEN, random);
if (xdsa_verify(signature, pubkey, msg, MSG_LEN) != 0)
ERROR("XDSA verify failure #1");
if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (xdsa_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("XDSA verify failure #2");
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 64) != 0)
ERROR("XDSA signature 10K doesn't match");
}
}
INFO("good");
return 1;
}
int xdsa_to_curvesigs_slow_test(int silent, int iterations)
{
unsigned char signature_10k_correct[64] = {
0x33, 0x50, 0xa8, 0x68, 0xcd, 0x9e, 0x74, 0x99,
0xa3, 0x5c, 0x33, 0x75, 0x2b, 0x22, 0x03, 0xf8,
0xb5, 0x0f, 0xea, 0x8c, 0x33, 0x1c, 0x68, 0x8b,
0xbb, 0xf3, 0x31, 0xcf, 0x7c, 0x42, 0x37, 0x35,
0xa0, 0x0e, 0x15, 0xb8, 0x5d, 0x2b, 0xe1, 0xa2,
0x03, 0x77, 0x94, 0x3d, 0x13, 0x5c, 0xd4, 0x9b,
0x6a, 0x31, 0xf4, 0xdc, 0xfe, 0x24, 0xad, 0x54,
0xeb, 0xd2, 0x98, 0x47, 0xf1, 0xcc, 0xbf, 0x0d
};
int count;
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[96];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 2, 64);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
/* Signature random test */
INFO("Pseudorandom XDSA/Curvesigs...");
for (count = 1; count <= iterations; count++) {
unsigned char b[64];
crypto_hash_sha512(b, signature, 64);
memmove(privkey, b, 32);
crypto_hash_sha512(b, privkey, 32);
memmove(random, b, 64);
sc_clamp(privkey);
curve25519_keygen(pubkey, privkey);
xdsa_sign(signature, privkey, msg, MSG_LEN, random);
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0)
ERROR("XDSA/Curvesigs verify failure #1");
if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("XDSA/Curvesigs verify failure #2");
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 64) != 0)
ERROR("XDSA/Curvesigs signature 10K doesn't match");
}
}
INFO("good");
return 1;
}
int uxdsa_slow_test(int silent, int iterations)
{
unsigned char signature_10k_correct[96] = {
0x2d, 0x2a, 0x69, 0x20, 0x0a, 0xe7, 0x76, 0xeb,
0x08, 0xc0, 0x3b, 0x4f, 0x26, 0x82, 0xd5, 0x3c,
0x97, 0xc6, 0xb7, 0x9c, 0x6a, 0xf6, 0x24, 0x91,
0xe1, 0xf9, 0x8f, 0x4f, 0x23, 0xc4, 0xba, 0x28,
0x4b, 0x60, 0x87, 0x07, 0xe5, 0x94, 0xcb, 0xda,
0x1b, 0x03, 0x5a, 0xd4, 0xd0, 0x6d, 0xd9, 0xa0,
0x6a, 0x07, 0xee, 0x7b, 0x98, 0x7c, 0xe1, 0xc4,
0x91, 0x52, 0x0d, 0x08, 0x32, 0xd7, 0x10, 0x03,
0xbd, 0x96, 0x34, 0x11, 0x0c, 0x44, 0x56, 0x95,
0x8b, 0x87, 0xdb, 0x12, 0x97, 0xa9, 0x5a, 0x62,
0x2a, 0x34, 0xb1, 0xb1, 0xe2, 0xb4, 0xf5, 0x3c,
0x34, 0xb6, 0x69, 0x0b, 0x77, 0x0e, 0x49, 0x07,
};
int count;
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[96];
unsigned char msg[MSG_LEN];
unsigned char random[64];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 3, 96);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
INFO("Pseudorandom UXDSA...");
for (count = 1; count <= iterations; count++) {
unsigned char b[64];
crypto_hash_sha512(b, signature, 96);
memmove(privkey, b, 32);
crypto_hash_sha512(b, privkey, 32);
memmove(random, b, 64);
sc_clamp(privkey);
curve25519_keygen(pubkey, privkey);
uxdsa_sign(signature, privkey, msg, MSG_LEN, random);
if (uxdsa_verify(signature, pubkey, msg, MSG_LEN) != 0)
ERROR("UXDSA verify failure #1");
if (b[63] & 1)
signature[count % 96] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (uxdsa_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("UXDSA verify failure #2");
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 96) != 0)
ERROR("UXDSA 10K doesn't match");
}
}
INFO("good");
return 1;
}
int all_fast_tests(int silent)
{
int result;
if ((result = sha512_fast_test(silent)) != 0)
return result;
if ((result = elligator_fast_test(silent)) != 0)
return result;
if ((result = curvesigs_fast_test(silent)) != 0)
return result;
if ((result = xdsa_fast_test(silent)) != 0)
return result;
if ((result = uxdsa_fast_test(silent)) != 0)
return result;
return 0;
}

View File

@ -0,0 +1,22 @@
#ifndef __TESTS_H__
#define __TESTS_H__
/* silent = 0 : prints info+error messages to stdout, abort() on test failure
* silent = 1 : returns 0 for success, anything else for failure
* iterations : hardcoded known-good values are at 10000, so run at least this many
*/
int sha512_fast_test(int silent);
int elligator_fast_test(int silent);
int curvesigs_fast_test(int silent);
int xdsa_fast_test(int silent);
int uxdsa_fast_test(int silent);
int curvesigs_slow_test(int silent, int iterations);
int xdsa_slow_test(int silent, int iterations);
int xdsa_to_curvesigs_slow_test(int silent, int iterations);
int uxdsa_slow_test(int silent, int iterations);
int all_fast_tests(int silent);
#endif

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,4 @@
subprojects {
ext.version_number = "0.2.4"
ext.version_number = "0.2.5-RC1"
ext.group_info = "org.whispersystems"
}

View File

@ -73,6 +73,14 @@ abstract class BaseJavaCurve25519Provider implements Curve25519Provider {
return curve_sigs.curve25519_verify(sha512provider, signature, publicKey, message, message.length) == 0;
}
public byte[] calculateUniqueSignature(byte[] random, byte[] privateKey, byte[] message) {
throw new AssertionError("NYI");
}
public boolean verifyUniqueSignature(byte[] publicKey, byte[] message, byte[] signature) {
throw new AssertionError("NYI");
}
public byte[] getRandom(int length) {
byte[] result = new byte[length];
secureRandomProvider.nextBytes(result);

View File

@ -15,8 +15,12 @@ interface Curve25519Provider {
byte[] generatePublicKey(byte[] privateKey);
byte[] generatePrivateKey();
byte[] generatePrivateKey(byte[] random);
byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message);
boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);
byte[] calculateUniqueSignature(byte[] random, byte[] privateKey, byte[] message);
boolean verifyUniqueSignature(byte[] publicKey, byte[] message, byte[] signature);
byte[] getRandom(int length);
void setRandomProvider(SecureRandomProvider provider);

View File

@ -72,6 +72,12 @@ class NativeCurve25519Provider implements Curve25519Provider {
@Override
public native boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);
@Override
public native byte[] calculateUniqueSignature(byte[] random, byte[] privateKey, byte[] message);
@Override
public native boolean verifyUniqueSignature(byte[] publicKey, byte[] message, byte[] signature);
private native boolean smokeCheck(int dummy);
}

View File

@ -63,4 +63,14 @@ public class OpportunisticCurve25519Provider implements Curve25519Provider {
return delegate.verifySignature(publicKey, message, signature);
}
@Override
public byte[] calculateUniqueSignature(byte[] random, byte[] privateKey, byte[] message) {
return delegate.calculateUniqueSignature(random, privateKey, message);
}
@Override
public boolean verifyUniqueSignature(byte[] publicKey, byte[] message, byte[] signature) {
return delegate.verifyUniqueSignature(publicKey, message, signature);
}
}