Compare commits

...

24 Commits

Author SHA1 Message Date
Moxie Marlinspike
70fae57d6d Bump version to 0.5.0 2018-05-04 04:36:11 -07:00
Moxie Marlinspike
0c38f1602b Include support for arm64 and amd64 2018-05-04 04:35:33 -07:00
Moxie Marlinspike
0e7a6a1b2b Bump version to 0.4.1
// FREEBIE
2017-06-23 09:16:36 -07:00
Trevor Perrin
35658a785d Cleanups to VRF (defensive programming, tests, fix bounds-check)
Remove unused functions

Closes #22
// FREEBIE
2017-06-23 09:15:03 -07:00
Moxie Marlinspike
ac0f2c764b Bump version to 0.4.0
// FREEBIE
2017-06-22 09:20:43 -07:00
Trevor Perrin
b71b9f135d Generalized EdDSA, new VRF
Closes #21
// FREEBIE
2017-06-22 09:20:36 -07:00
Moxie Marlinspike
f3dcb98f39 Exclude external junit from Android tests
// FREEBIE
2017-06-22 09:16:20 -07:00
Moxie Marlinspike
e25a858c97 Bump version to 0.3.1
// FREEBIE
2017-03-31 13:52:35 -07:00
Moxie Marlinspike
7587cb3fd0 The functions are currently unused, but Stef pointed out that
the xeddsa and vxeddsa verify strictness check had a return
value incompatible with the verify function's return value,
causing a strictness check failure to be interpreted as a
signature verification success.

This change also removes some other old/vestigial code.

// FREEBIE
2017-03-31 12:58:07 -07:00
Moxie Marlinspike
ac14bb499e Copy public domain statement from SUPERCOP
// FREEBIE
2016-10-20 16:33:46 -07:00
Moxie Marlinspike
fea698a4d6 Bump version to 0.3.0
// FREEBIE
2016-10-18 12:28:35 -07:00
Moxie Marlinspike
f596383883 uniqueSignature -> vrfSignature
// FREEBIE
2016-10-18 11:12:25 -07:00
Moxie Marlinspike
40106e80ea maven -> jcenter
// FREEBIE
2016-10-17 15:27:30 -07:00
Moxie Marlinspike
5423528ed8 uxed25519 -> vxed25519
// FREEBIE
2016-10-17 15:22:12 -07:00
Moxie Marlinspike
afba05a10e Update gradle
// FREEBIE
2016-10-17 15:20:29 -07:00
Moxie Marlinspike
6cf507f4ec Bump version to 0.2.5
// FREEBIE
2016-08-20 09:53:45 -07:00
Moxie Marlinspike
5451c449e8 xed25519
// FREEBIE
2016-08-18 10:54:34 -07:00
Moxie Marlinspike
a6128a4304 uxdsa improvements
// FREEBIE
2016-08-14 10:15:23 -07:00
Moxie Marlinspike
37b015bc99 Plumb unique signatures through Curve25519 interface
// FREEBIE
2016-08-11 17:56:32 -07:00
Moxie Marlinspike
a6b7aa9456 Validate arguments
Fixes #11

// FREEBIE
2016-08-11 17:28:23 -07:00
Moxie Marlinspike
2f388f601a Dynamically allocated xdsa buffer
// FREEBIE
2016-08-11 17:25:34 -07:00
Moxie Marlinspike
dadb8510a9 Remove unused variable
This will also get rearranged in the new codegen

Fixes #6
// FREEBIE
2016-08-11 17:06:03 -07:00
Moxie Marlinspike
d0049e0227 Break up fe_mul method
Fixes #9

// FREEBIE
2016-08-11 16:58:51 -07:00
Moxie Marlinspike
b9f2ac4fde Add VUF support
// FREEBIE
2016-08-11 16:58:42 -07:00
71 changed files with 3139 additions and 235 deletions

View File

@ -1,10 +1,10 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'com.android.tools.build:gradle:2.2.0'
}
}
@ -44,7 +44,9 @@ repositories {
dependencies {
compile project(':java')
androidTestCompile project(":tests")
androidTestCompile (project(":tests")) {
exclude module: 'junit'
}
}
signing {

View File

@ -10,8 +10,11 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcurve25519-ref10
LOCAL_SRC_FILES := $(wildcard ed25519/*.c) $(wildcard ed25519/additions/*.c) $(wildcard ed25519/nacl_sha512/*.c)
LOCAL_C_INCLUDES := ed25519/nacl_includes ed25519/additions ed25519/sha512 ed25519
LOCAL_SRC_FILES := $(wildcard ed25519/*.c) $(wildcard ed25519/additions/*.c) \
$(wildcard ed25519/additions/generalized/*.c) $(wildcard ed25519/nacl_sha512/*.c) \
ed25519/tests/internal_fast_tests.c
LOCAL_C_INCLUDES := ed25519/nacl_includes ed25519/additions ed25519/additions/generalized ed25519/tests ed25519/sha512 ed25519
include $(BUILD_STATIC_LIBRARY)
@ -19,7 +22,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libcurve25519
LOCAL_SRC_FILES := curve25519-jni.c
LOCAL_C_INCLUDES := ed25519/additions
LOCAL_C_INCLUDES := ed25519/additions ed25519/additions/generalized ed25519/tests
LOCAL_STATIC_LIBRARIES := libcurve25519-donna libcurve25519-ref10

View File

@ -1 +1 @@
APP_ABI := armeabi armeabi-v7a x86 mips
APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a x86_64

View File

@ -11,6 +11,9 @@
#include <jni.h>
#include "curve25519-donna.h"
#include "curve_sigs.h"
#include "xeddsa.h"
#include "internal_fast_tests.h"
#include "gen_x.h"
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_generatePrivateKey
(JNIEnv *env, jobject obj, jbyteArray random)
@ -70,7 +73,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 = xed25519_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength, randomBytes);
(*env)->ReleaseByteArrayElements(env, signature, signatureBytes, 0);
(*env)->ReleaseByteArrayElements(env, random, randomBytes, 0);
@ -98,8 +101,59 @@ JNIEXPORT jboolean JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Pr
return result;
}
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_calculateVrfSignature
(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 = generalized_xveddsa_25519_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength, randomBytes, NULL, 0);
(*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 jbyteArray JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_verifyVrfSignature
(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);
jbyteArray vrf = (*env)->NewByteArray(env, 32);
uint8_t* vrfBytes = (uint8_t*)(*env)->GetByteArrayElements(env, vrf, 0);
int result = generalized_xveddsa_25519_verify(vrfBytes, signatureBytes, publicKeyBytes, messageBytes, messageLength, NULL, 0);
(*env)->ReleaseByteArrayElements(env, signature, signatureBytes, 0);
(*env)->ReleaseByteArrayElements(env, publicKey, publicKeyBytes, 0);
(*env)->ReleaseByteArrayElements(env, message, messageBytes, 0);
(*env)->ReleaseByteArrayElements(env, vrf, vrfBytes, 0);
if (result == 0) return vrf;
else (*env)->ThrowNew(env, (*env)->FindClass(env, "org/whispersystems/curve25519/VrfSignatureVerificationFailedException"), "Invalid signature");
}
JNIEXPORT jboolean JNICALL Java_org_whispersystems_curve25519_NativeCurve25519Provider_smokeCheck
(JNIEnv *env, jobject obj, jint dummy)
{
return 1;
}
JNIEXPORT jboolean JNICALL Java_org_whispersystems_curve25519_NativeCurve25519ProviderTest_internalTest
(JNIEnv *env)
{
jboolean result = (all_fast_tests(1) == 0);
return result;
}

View File

@ -0,0 +1,45 @@
#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);
int fe_isreduced(const unsigned char* s);
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_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);
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
);
#endif

View File

@ -1,38 +1,9 @@
#include <string.h>
#include <stdlib.h>
#include <string.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,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:

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,80 @@
#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;
unsigned char bytes[32];
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
*/
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);
}

View File

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

View File

@ -0,0 +1,14 @@
#include "fe.h"
#include "crypto_verify_32.h"
int fe_isreduced(const unsigned char* s)
{
fe f;
unsigned char strict[32];
fe_frombytes(f, s);
fe_tobytes(strict, f);
if (crypto_verify_32(strict, s) != 0)
return 0;
return 1;
}

View File

@ -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) */
}

View File

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

View File

@ -0,0 +1,51 @@
#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;
#ifndef NDEBUG
fe legendre, zero, one;
#endif
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_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
}

View File

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

View File

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

View File

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

View File

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

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

View File

@ -0,0 +1,15 @@
#include "ge.h"
/*
r = p + q
*/
void ge_p3_add(ge_p3 *r, const ge_p3 *p, const ge_p3 *q)
{
ge_cached p_cached;
ge_p1p1 r_p1p1;
ge_p3_to_cached(&p_cached, p);
ge_add(&r_p1p1, q, &p_cached);
ge_p1p1_to_p3(r, &r_p1p1);
}

View File

@ -0,0 +1,19 @@
#ifndef _GEN_CONSTANTS_H__
#define _GEN_CONSTANTS_H__
#define LABELSETMAXLEN 512
#define LABELMAXLEN 128
#define BUFLEN 1024
#define BLOCKLEN 128 /* SHA512 */
#define HASHLEN 64 /* SHA512 */
#define POINTLEN 32
#define SCALARLEN 32
#define RANDLEN 32
#define SIGNATURELEN 64
#define VRFSIGNATURELEN 96
#define VRFOUTPUTLEN 32
#define MSTART 2048
#define MSGMAXLEN 1048576
#endif

View File

@ -0,0 +1,16 @@
#ifndef __GEN_CRYPTO_ADDITIONS__
#define __GEN_CRYPTO_ADDITIONS__
#include "crypto_uint32.h"
#include "fe.h"
#include "ge.h"
int sc_isreduced(const unsigned char* s);
int point_isreduced(const unsigned char* p);
void ge_p3_add(ge_p3 *r, const ge_p3 *p, const ge_p3 *q);
#endif

View File

@ -0,0 +1,349 @@
#include <string.h>
#include "gen_eddsa.h"
#include "gen_labelset.h"
#include "gen_constants.h"
#include "gen_crypto_additions.h"
#include "crypto_hash_sha512.h"
#include "crypto_verify_32.h"
#include "zeroize.h"
#include "ge.h"
#include "sc.h"
#include "crypto_additions.h"
#include "utility.h"
/* B: base point
* R: commitment (point),
r: private nonce (scalar)
K: encoded public key
k: private key (scalar)
Z: 32-bytes random
M: buffer containing message, message starts at M_start, continues for M_len
r = hash(B || labelset || Z || pad1 || k || pad2 || labelset || K || extra || M) (mod q)
*/
int generalized_commit(unsigned char* R_bytes, unsigned char* r_scalar,
const unsigned char* labelset, const unsigned long labelset_len,
const unsigned char* extra, const unsigned long extra_len,
const unsigned char* K_bytes, const unsigned char* k_scalar,
const unsigned char* Z,
unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len)
{
ge_p3 R_point;
unsigned char hash[HASHLEN];
unsigned char* bufstart = NULL;
unsigned char* bufptr = NULL;
unsigned char* bufend = NULL;
unsigned long prefix_len = 0;
if (labelset_validate(labelset, labelset_len) != 0)
goto err;
if (R_bytes == NULL || r_scalar == NULL ||
K_bytes == NULL || k_scalar == NULL ||
Z == NULL || M_buf == NULL)
goto err;
if (extra == NULL && extra_len != 0)
goto err;
if (extra != NULL && extra_len == 0)
goto err;
if (extra != NULL && labelset_is_empty(labelset, labelset_len))
goto err;
if (HASHLEN != 64)
goto err;
prefix_len = 0;
prefix_len += POINTLEN + labelset_len + RANDLEN;
prefix_len += ((BLOCKLEN - (prefix_len % BLOCKLEN)) % BLOCKLEN);
prefix_len += SCALARLEN;
prefix_len += ((BLOCKLEN - (prefix_len % BLOCKLEN)) % BLOCKLEN);
prefix_len += labelset_len + POINTLEN + extra_len;
if (prefix_len > M_start)
goto err;
bufstart = M_buf + M_start - prefix_len;
bufptr = bufstart;
bufend = M_buf + M_start;
bufptr = buffer_add(bufptr, bufend, B_bytes, POINTLEN);
bufptr = buffer_add(bufptr, bufend, labelset, labelset_len);
bufptr = buffer_add(bufptr, bufend, Z, RANDLEN);
bufptr = buffer_pad(bufstart, bufptr, bufend);
bufptr = buffer_add(bufptr, bufend, k_scalar, SCALARLEN);
bufptr = buffer_pad(bufstart, bufptr, bufend);
bufptr = buffer_add(bufptr, bufend, labelset, labelset_len);
bufptr = buffer_add(bufptr, bufend, K_bytes, POINTLEN);
bufptr = buffer_add(bufptr, bufend, extra, extra_len);
if (bufptr != bufend || bufptr != M_buf + M_start || bufptr - bufstart != prefix_len)
goto err;
crypto_hash_sha512(hash, M_buf + M_start - prefix_len, prefix_len + M_len);
sc_reduce(hash);
ge_scalarmult_base(&R_point, hash);
ge_p3_tobytes(R_bytes, &R_point);
memcpy(r_scalar, hash, SCALARLEN);
zeroize(hash, HASHLEN);
zeroize(bufstart, prefix_len);
return 0;
err:
zeroize(hash, HASHLEN);
zeroize(M_buf, M_start);
return -1;
}
/* if is_labelset_empty(labelset):
return hash(R || K || M) (mod q)
else:
return hash(B || labelset || R || labelset || K || extra || M) (mod q)
*/
int generalized_challenge(unsigned char* h_scalar,
const unsigned char* labelset, const unsigned long labelset_len,
const unsigned char* extra, const unsigned long extra_len,
const unsigned char* R_bytes,
const unsigned char* K_bytes,
unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len)
{
unsigned char hash[HASHLEN];
unsigned char* bufstart = NULL;
unsigned char* bufptr = NULL;
unsigned char* bufend = NULL;
unsigned long prefix_len = 0;
if (h_scalar == NULL)
goto err;
memset(h_scalar, 0, SCALARLEN);
if (labelset_validate(labelset, labelset_len) != 0)
goto err;
if (R_bytes == NULL || K_bytes == NULL || M_buf == NULL)
goto err;
if (extra == NULL && extra_len != 0)
goto err;
if (extra != NULL && extra_len == 0)
goto err;
if (extra != NULL && labelset_is_empty(labelset, labelset_len))
goto err;
if (HASHLEN != 64)
goto err;
if (labelset_is_empty(labelset, labelset_len)) {
if (2*POINTLEN > M_start)
goto err;
if (extra != NULL || extra_len != 0)
goto err;
memcpy(M_buf + M_start - (2*POINTLEN), R_bytes, POINTLEN);
memcpy(M_buf + M_start - (1*POINTLEN), K_bytes, POINTLEN);
prefix_len = 2*POINTLEN;
} else {
prefix_len = 3*POINTLEN + 2*labelset_len + extra_len;
if (prefix_len > M_start)
goto err;
bufstart = M_buf + M_start - prefix_len;
bufptr = bufstart;
bufend = M_buf + M_start;
bufptr = buffer_add(bufptr, bufend, B_bytes, POINTLEN);
bufptr = buffer_add(bufptr, bufend, labelset, labelset_len);
bufptr = buffer_add(bufptr, bufend, R_bytes, POINTLEN);
bufptr = buffer_add(bufptr, bufend, labelset, labelset_len);
bufptr = buffer_add(bufptr, bufend, K_bytes, POINTLEN);
bufptr = buffer_add(bufptr, bufend, extra, extra_len);
if (bufptr == NULL)
goto err;
if (bufptr != bufend || bufptr != M_buf + M_start || bufptr - bufstart != prefix_len)
goto err;
}
crypto_hash_sha512(hash, M_buf + M_start - prefix_len, prefix_len + M_len);
sc_reduce(hash);
memcpy(h_scalar, hash, SCALARLEN);
return 0;
err:
return -1;
}
/* return r + kh (mod q) */
int generalized_prove(unsigned char* out_scalar,
const unsigned char* r_scalar, const unsigned char* k_scalar, const unsigned char* h_scalar)
{
sc_muladd(out_scalar, h_scalar, k_scalar, r_scalar);
zeroize_stack();
return 0;
}
/* R = s*B - h*K */
int generalized_solve_commitment(unsigned char* R_bytes_out, ge_p3* K_point_out,
const ge_p3* B_point, const unsigned char* s_scalar,
const unsigned char* K_bytes, const unsigned char* h_scalar)
{
ge_p3 Kneg_point;
ge_p2 R_calc_point_p2;
ge_p3 sB;
ge_p3 hK;
ge_p3 R_calc_point_p3;
if (ge_frombytes_negate_vartime(&Kneg_point, K_bytes) != 0)
return -1;
if (B_point == NULL) {
ge_double_scalarmult_vartime(&R_calc_point_p2, h_scalar, &Kneg_point, s_scalar);
ge_tobytes(R_bytes_out, &R_calc_point_p2);
}
else {
// s * Bv
ge_scalarmult(&sB, s_scalar, B_point);
// h * -K
ge_scalarmult(&hK, h_scalar, &Kneg_point);
// R = sB - hK
ge_p3_add(&R_calc_point_p3, &sB, &hK);
ge_p3_tobytes(R_bytes_out, &R_calc_point_p3);
}
if (K_point_out) {
ge_neg(K_point_out, &Kneg_point);
}
return 0;
}
int generalized_eddsa_25519_sign(
unsigned char* signature_out,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* eddsa_25519_privkey_scalar,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* random,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char labelset[LABELSETMAXLEN];
unsigned long labelset_len = 0;
unsigned char R_bytes[POINTLEN];
unsigned char r_scalar[SCALARLEN];
unsigned char h_scalar[SCALARLEN];
unsigned char s_scalar[SCALARLEN];
unsigned char* M_buf = NULL;
if (signature_out == NULL)
goto err;
memset(signature_out, 0, SIGNATURELEN);
if (eddsa_25519_pubkey_bytes == NULL)
goto err;
if (eddsa_25519_privkey_scalar == NULL)
goto err;
if (msg == NULL)
goto err;
if (customization_label == NULL && customization_label_len != 0)
goto err;
if (customization_label_len > LABELMAXLEN)
goto err;
if (msg_len > MSGMAXLEN)
goto err;
if ((M_buf = malloc(msg_len + MSTART)) == 0)
goto err;
memcpy(M_buf + MSTART, msg, msg_len);
if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN, NULL, 0,
customization_label, customization_label_len) != 0)
goto err;
if (generalized_commit(R_bytes, r_scalar, labelset, labelset_len, NULL, 0,
eddsa_25519_pubkey_bytes, eddsa_25519_privkey_scalar,
random, M_buf, MSTART, msg_len) != 0)
goto err;
if (generalized_challenge(h_scalar, labelset, labelset_len, NULL, 0,
R_bytes, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0)
goto err;
if (generalized_prove(s_scalar, r_scalar, eddsa_25519_privkey_scalar, h_scalar) != 0)
goto err;
memcpy(signature_out, R_bytes, POINTLEN);
memcpy(signature_out + POINTLEN, s_scalar, SCALARLEN);
zeroize(r_scalar, SCALARLEN);
zeroize_stack();
free(M_buf);
return 0;
err:
zeroize(r_scalar, SCALARLEN);
zeroize_stack();
free(M_buf);
return -1;
}
int generalized_eddsa_25519_verify(
const unsigned char* signature,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char labelset[LABELSETMAXLEN];
unsigned long labelset_len = 0;
const unsigned char* R_bytes = NULL;
const unsigned char* s_scalar = NULL;
unsigned char h_scalar[SCALARLEN];
unsigned char* M_buf = NULL;
unsigned char R_calc_bytes[POINTLEN];
if (signature == NULL)
goto err;
if (eddsa_25519_pubkey_bytes == NULL)
goto err;
if (msg == NULL)
goto err;
if (customization_label == NULL && customization_label_len != 0)
goto err;
if (customization_label_len > LABELMAXLEN)
goto err;
if (msg_len > MSGMAXLEN)
goto err;
if ((M_buf = malloc(msg_len + MSTART)) == 0)
goto err;
memcpy(M_buf + MSTART, msg, msg_len);
if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN, NULL, 0,
customization_label, customization_label_len) != 0)
goto err;
R_bytes = signature;
s_scalar = signature + POINTLEN;
if (!point_isreduced(eddsa_25519_pubkey_bytes))
goto err;
if (!point_isreduced(R_bytes))
goto err;
if (!sc_isreduced(s_scalar))
goto err;
if (generalized_challenge(h_scalar, labelset, labelset_len,
NULL, 0, R_bytes, eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0)
goto err;
if (generalized_solve_commitment(R_calc_bytes, NULL, NULL,
s_scalar, eddsa_25519_pubkey_bytes, h_scalar) != 0)
goto err;
if (crypto_verify_32(R_bytes, R_calc_bytes) != 0)
goto err;
free(M_buf);
return 0;
err:
free(M_buf);
return -1;
}

View File

@ -0,0 +1,65 @@
#ifndef __GEN_EDDSA_H__
#define __GEN_EDDSA_H__
#include "ge.h"
/* B: base point
R: commitment (point),
r: private nonce (scalar)
K: encoded public key
k: private key (scalar)
Z: 32-bytes random
M: buffer containing message, message starts at M_start, continues for M_len
r = hash(B || labelset || Z || pad1 || k || pad2 || labelset || K || extra || M) (mod q)
*/
int generalized_commit(unsigned char* R_bytes, unsigned char* r_scalar,
const unsigned char* labelset, const unsigned long labelset_len,
const unsigned char* extra, const unsigned long extra_len,
const unsigned char* K_bytes, const unsigned char* k_scalar,
const unsigned char* Z,
unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len);
/* if is_labelset_empty(labelset):
return hash(R || K || M) (mod q)
else:
return hash(B || labelset || R || labelset || K || extra || M) (mod q)
*/
int generalized_challenge(unsigned char* h_scalar,
const unsigned char* labelset, const unsigned long labelset_len,
const unsigned char* extra, const unsigned long extra_len,
const unsigned char* R_bytes,
const unsigned char* K_bytes,
unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len);
/* return r + kh (mod q) */
int generalized_prove(unsigned char* out_scalar,
const unsigned char* r_scalar,
const unsigned char* k_scalar,
const unsigned char* h_scalar);
/* R = B^s / K^h */
int generalized_solve_commitment(unsigned char* R_bytes_out, ge_p3* K_point_out,
const ge_p3* B_point, const unsigned char* s_scalar,
const unsigned char* K_bytes, const unsigned char* h_scalar);
int generalized_eddsa_25519_sign(
unsigned char* signature_out,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* eddsa_25519_privkey_scalar,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* random,
const unsigned char* customization_label,
const unsigned long customization_label_len);
int generalized_eddsa_25519_verify(
const unsigned char* signature,
const unsigned char* eddsa_25519_pubkey,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len);
#endif

View File

@ -0,0 +1,157 @@
#include <stdlib.h>
#include <string.h>
#include "gen_labelset.h"
#include "gen_constants.h"
const unsigned char B_bytes[] = {
0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
};
unsigned char* buffer_add(unsigned char* bufptr, const unsigned char* bufend,
const unsigned char* in, const unsigned long in_len)
{
unsigned long count = 0;
if (bufptr == NULL || bufend == NULL || bufptr > bufend)
return NULL;
if (in == NULL && in_len != 0)
return NULL;
if (bufend - bufptr < in_len)
return NULL;
for (count=0; count < in_len; count++) {
if (bufptr >= bufend)
return NULL;
*bufptr++ = *in++;
}
return bufptr;
}
unsigned char* buffer_pad(const unsigned char* buf, unsigned char* bufptr, const unsigned char* bufend)
{
unsigned long count = 0;
unsigned long pad_len = 0;
if (buf == NULL || bufptr == NULL || bufend == NULL || bufptr >= bufend || bufptr < buf)
return NULL;
pad_len = (BLOCKLEN - ((bufptr-buf) % BLOCKLEN)) % BLOCKLEN;
if (bufend - bufptr < pad_len)
return NULL;
for (count=0; count < pad_len; count++) {
if (bufptr >= bufend)
return NULL;
*bufptr++ = 0;
}
return bufptr;
}
int labelset_new(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen,
const unsigned char* protocol_name, const unsigned char protocol_name_len,
const unsigned char* customization_label, const unsigned char customization_label_len)
{
unsigned char* bufptr;
*labelset_len = 0;
if (labelset == NULL)
return -1;
if (labelset_len == NULL)
return -1;
if (labelset_maxlen > LABELSETMAXLEN)
return -1;
if (labelset_maxlen < 3 + protocol_name_len + customization_label_len)
return -1;
if (protocol_name == NULL && protocol_name_len != 0)
return -1;
if (customization_label == NULL && customization_label_len != 0)
return -1;
if (protocol_name_len > LABELMAXLEN)
return -1;
if (customization_label_len > LABELMAXLEN)
return -1;
bufptr = labelset;
*bufptr++ = 2;
*bufptr++ = protocol_name_len;
bufptr = buffer_add(bufptr, labelset + labelset_maxlen, protocol_name, protocol_name_len);
if (bufptr != NULL && bufptr < labelset + labelset_maxlen)
*bufptr++ = customization_label_len;
bufptr = buffer_add(bufptr, labelset + labelset_maxlen,
customization_label, customization_label_len);
if (bufptr != NULL && bufptr - labelset == 3 + protocol_name_len + customization_label_len) {
*labelset_len = bufptr - labelset;
return 0;
}
return -1;
}
int labelset_add(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen,
const unsigned char* label, const unsigned char label_len)
{
unsigned char* bufptr;
if (labelset_len == NULL)
return -1;
if (*labelset_len > LABELSETMAXLEN || labelset_maxlen > LABELSETMAXLEN)
return -1;
if (*labelset_len >= labelset_maxlen || *labelset_len + label_len + 1 > labelset_maxlen)
return -1;
if (*labelset_len < 3 || labelset_maxlen < 4)
return -1;
if (label_len > LABELMAXLEN)
return -1;
labelset[0]++;
labelset[*labelset_len] = label_len;
bufptr = labelset + *labelset_len + 1;
bufptr = buffer_add(bufptr, labelset + labelset_maxlen, label, label_len);
if (bufptr == NULL)
return -1;
if (bufptr - labelset >= labelset_maxlen)
return -1;
if (bufptr - labelset != *labelset_len + 1 + label_len)
return -1;
*labelset_len += (1 + label_len);
return 0;
}
int labelset_validate(const unsigned char* labelset, const unsigned long labelset_len)
{
unsigned char num_labels = 0;
unsigned char count = 0;
unsigned long offset = 0;
unsigned char label_len = 0;
if (labelset == NULL)
return -1;
if (labelset_len < 3 || labelset_len > LABELSETMAXLEN)
return -1;
num_labels = labelset[0];
offset = 1;
for (count = 0; count < num_labels; count++) {
label_len = labelset[offset];
if (label_len > LABELMAXLEN)
return -1;
offset += 1 + label_len;
if (offset > labelset_len)
return -1;
}
if (offset != labelset_len)
return -1;
return 0;
}
int labelset_is_empty(const unsigned char* labelset, const unsigned long labelset_len)
{
if (labelset_len != 3)
return 0;
return 1;
}

View File

@ -0,0 +1,23 @@
#ifndef __GEN_LABELSET_H__
#define __GEN_LABELSET_H__
extern const unsigned char B_bytes[];
unsigned char* buffer_add(unsigned char* bufptr, const unsigned char* bufend,
const unsigned char* in, const unsigned long in_len);
unsigned char* buffer_pad(const unsigned char* buf, unsigned char* bufptr, const unsigned char* bufend);
int labelset_new(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen,
const unsigned char* protocol_name, const unsigned char protocol_name_len,
const unsigned char* customization_label, const unsigned char customization_label_len);
int labelset_add(unsigned char* labelset, unsigned long* labelset_len, const unsigned long labelset_maxlen,
const unsigned char* label, const unsigned char label_len);
int labelset_validate(const unsigned char* labelset, const unsigned long labelset_len);
int labelset_is_empty(const unsigned char* labelset, const unsigned long labelset_len);
#endif

View File

@ -0,0 +1,312 @@
#include <string.h>
#include "gen_eddsa.h"
#include "gen_veddsa.h"
#include "gen_constants.h"
#include "gen_labelset.h"
#include "gen_crypto_additions.h"
#include "crypto_hash_sha512.h"
#include "crypto_verify_32.h"
#include "crypto_additions.h"
#include "zeroize.h"
#include "ge.h"
#include "sc.h"
#include "utility.h"
static int generalized_calculate_Bv(ge_p3* Bv_point,
const unsigned char* labelset, const unsigned long labelset_len,
const unsigned char* K_bytes,
unsigned char* M_buf, const unsigned long M_start, const unsigned long M_len)
{
unsigned char* bufptr;
unsigned long prefix_len = 0;
if (labelset_validate(labelset, labelset_len) != 0)
return -1;
if (Bv_point == NULL || K_bytes == NULL || M_buf == NULL)
return -1;
prefix_len = 2*POINTLEN + labelset_len;
if (prefix_len > M_start)
return -1;
bufptr = M_buf + M_start - prefix_len;
bufptr = buffer_add(bufptr, M_buf + M_start, B_bytes, POINTLEN);
bufptr = buffer_add(bufptr, M_buf + M_start, labelset, labelset_len);
bufptr = buffer_add(bufptr, M_buf + M_start, K_bytes, POINTLEN);
if (bufptr == NULL || bufptr != M_buf + M_start)
return -1;
hash_to_point(Bv_point, M_buf + M_start - prefix_len, prefix_len + M_len);
if (ge_isneutral(Bv_point))
return -1;
return 0;
}
static int generalized_calculate_vrf_output(unsigned char* vrf_output,
const unsigned char* labelset, const unsigned long labelset_len,
const ge_p3* cKv_point)
{
unsigned char buf[BUFLEN];
unsigned char* bufptr = buf;
unsigned char* bufend = buf + BUFLEN;
unsigned char cKv_bytes[POINTLEN];
unsigned char hash[HASHLEN];
if (vrf_output == NULL)
return -1;
memset(vrf_output, 0, VRFOUTPUTLEN);
if (labelset_len + 2*POINTLEN > BUFLEN)
return -1;
if (labelset_validate(labelset, labelset_len) != 0)
return -1;
if (cKv_point == NULL)
return -1;
if (VRFOUTPUTLEN > HASHLEN)
return -1;
ge_p3_tobytes(cKv_bytes, cKv_point);
bufptr = buffer_add(bufptr, bufend, B_bytes, POINTLEN);
bufptr = buffer_add(bufptr, bufend, labelset, labelset_len);
bufptr = buffer_add(bufptr, bufend, cKv_bytes, POINTLEN);
if (bufptr == NULL)
return -1;
if (bufptr - buf > BUFLEN)
return -1;
crypto_hash_sha512(hash, buf, bufptr - buf);
memcpy(vrf_output, hash, VRFOUTPUTLEN);
return 0;
}
int generalized_veddsa_25519_sign(
unsigned char* signature_out,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* eddsa_25519_privkey_scalar,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* random,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char labelset[LABELSETMAXLEN];
unsigned long labelset_len = 0;
ge_p3 Bv_point;
ge_p3 Kv_point;
ge_p3 Rv_point;
unsigned char Bv_bytes[POINTLEN];
unsigned char Kv_bytes[POINTLEN];
unsigned char Rv_bytes[POINTLEN];
unsigned char R_bytes[POINTLEN];
unsigned char r_scalar[SCALARLEN];
unsigned char h_scalar[SCALARLEN];
unsigned char s_scalar[SCALARLEN];
unsigned char extra[3*POINTLEN];
unsigned char* M_buf = NULL;
char* protocol_name = "VEdDSA_25519_SHA512_Elligator2";
if (signature_out == NULL)
goto err;
memset(signature_out, 0, VRFSIGNATURELEN);
if (eddsa_25519_pubkey_bytes == NULL)
goto err;
if (eddsa_25519_privkey_scalar == NULL)
goto err;
if (msg == NULL)
goto err;
if (customization_label == NULL && customization_label_len != 0)
goto err;
if (customization_label_len > LABELMAXLEN)
goto err;
if (msg_len > MSGMAXLEN)
goto err;
if ((M_buf = malloc(msg_len + MSTART)) == 0) {
goto err;
}
memcpy(M_buf + MSTART, msg, msg_len);
// labelset = new_labelset(protocol_name, customization_label)
if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN,
(unsigned char*)protocol_name, strlen(protocol_name),
customization_label, customization_label_len) != 0)
goto err;
// labelset1 = add_label(labels, "1")
// Bv = hash(hash(labelset1 || K) || M)
// Kv = k * Bv
labelset_add(labelset, &labelset_len, LABELSETMAXLEN, (unsigned char*)"1", 1);
if (generalized_calculate_Bv(&Bv_point, labelset, labelset_len,
eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0)
goto err;
ge_scalarmult(&Kv_point, eddsa_25519_privkey_scalar, &Bv_point);
ge_p3_tobytes(Bv_bytes, &Bv_point);
ge_p3_tobytes(Kv_bytes, &Kv_point);
// labelset2 = add_label(labels, "2")
// R, r = commit(labelset2, (Bv || Kv), (K,k), Z, M)
labelset[labelset_len-1] = (unsigned char)'2';
memcpy(extra, Bv_bytes, POINTLEN);
memcpy(extra + POINTLEN, Kv_bytes, POINTLEN);
if (generalized_commit(R_bytes, r_scalar,
labelset, labelset_len,
extra, 2*POINTLEN,
eddsa_25519_pubkey_bytes, eddsa_25519_privkey_scalar,
random, M_buf, MSTART, msg_len) != 0)
goto err;
// Rv = r * Bv
ge_scalarmult(&Rv_point, r_scalar, &Bv_point);
ge_p3_tobytes(Rv_bytes, &Rv_point);
// labelset3 = add_label(labels, "3")
// h = challenge(labelset3, (Bv || Kv || Rv), R, K, M)
labelset[labelset_len-1] = (unsigned char)'3';
memcpy(extra + 2*POINTLEN, Rv_bytes, POINTLEN);
if (generalized_challenge(h_scalar,
labelset, labelset_len,
extra, 3*POINTLEN,
R_bytes, eddsa_25519_pubkey_bytes,
M_buf, MSTART, msg_len) != 0)
goto err;
// s = prove(r, k, h)
if (generalized_prove(s_scalar, r_scalar, eddsa_25519_privkey_scalar, h_scalar) != 0)
goto err;
// return (Kv || h || s)
memcpy(signature_out, Kv_bytes, POINTLEN);
memcpy(signature_out + POINTLEN, h_scalar, SCALARLEN);
memcpy(signature_out + POINTLEN + SCALARLEN, s_scalar, SCALARLEN);
zeroize(r_scalar, SCALARLEN);
zeroize_stack();
free(M_buf);
return 0;
err:
zeroize(r_scalar, SCALARLEN);
zeroize_stack();
free(M_buf);
return -1;
}
int generalized_veddsa_25519_verify(
unsigned char* vrf_out,
const unsigned char* signature,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char labelset[LABELSETMAXLEN];
unsigned long labelset_len = 0;
const unsigned char* Kv_bytes;
const unsigned char* h_scalar;
const unsigned char* s_scalar;
ge_p3 Bv_point, K_point, Kv_point, cK_point, cKv_point;
unsigned char Bv_bytes[POINTLEN];
unsigned char R_calc_bytes[POINTLEN];
unsigned char Rv_calc_bytes[POINTLEN];
unsigned char h_calc_scalar[SCALARLEN];
unsigned char extra[3*POINTLEN];
unsigned char* M_buf = NULL;
char* protocol_name = "VEdDSA_25519_SHA512_Elligator2";
if (vrf_out == NULL)
goto err;
memset(vrf_out, 0, VRFOUTPUTLEN);
if (signature == NULL)
goto err;
if (eddsa_25519_pubkey_bytes == NULL)
goto err;
if (msg == NULL)
goto err;
if (customization_label == NULL && customization_label_len != 0)
goto err;
if (customization_label_len > LABELMAXLEN)
goto err;
if (msg_len > MSGMAXLEN)
goto err;
if ((M_buf = malloc(msg_len + MSTART)) == 0) {
goto err;
}
memcpy(M_buf + MSTART, msg, msg_len);
Kv_bytes = signature;
h_scalar = signature + POINTLEN;
s_scalar = signature + POINTLEN + SCALARLEN;
if (!point_isreduced(eddsa_25519_pubkey_bytes))
goto err;
if (!point_isreduced(Kv_bytes))
goto err;
if (!sc_isreduced(h_scalar))
goto err;
if (!sc_isreduced(s_scalar))
goto err;
// labelset = new_labelset(protocol_name, customization_label)
if (labelset_new(labelset, &labelset_len, LABELSETMAXLEN,
(unsigned char*)protocol_name, strlen(protocol_name),
customization_label, customization_label_len) != 0)
goto err;
// labelset1 = add_label(labels, "1")
// Bv = hash(hash(labelset1 || K) || M)
labelset_add(labelset, &labelset_len, LABELSETMAXLEN, (unsigned char*)"1", 1);
if (generalized_calculate_Bv(&Bv_point, labelset, labelset_len,
eddsa_25519_pubkey_bytes, M_buf, MSTART, msg_len) != 0)
goto err;
ge_p3_tobytes(Bv_bytes, &Bv_point);
// R = solve_commitment(B, s, K, h)
if (generalized_solve_commitment(R_calc_bytes, &K_point, NULL,
s_scalar, eddsa_25519_pubkey_bytes, h_scalar) != 0)
goto err;
// Rv = solve_commitment(Bv, s, Kv, h)
if (generalized_solve_commitment(Rv_calc_bytes, &Kv_point, &Bv_point,
s_scalar, Kv_bytes, h_scalar) != 0)
goto err;
ge_scalarmult_cofactor(&cK_point, &K_point);
ge_scalarmult_cofactor(&cKv_point, &Kv_point);
if (ge_isneutral(&cK_point) || ge_isneutral(&cKv_point) || ge_isneutral(&Bv_point))
goto err;
// labelset3 = add_label(labels, "3")
// h = challenge(labelset3, (Bv || Kv || Rv), R, K, M)
labelset[labelset_len-1] = (unsigned char)'3';
memcpy(extra, Bv_bytes, POINTLEN);
memcpy(extra + POINTLEN, Kv_bytes, POINTLEN);
memcpy(extra + 2*POINTLEN, Rv_calc_bytes, POINTLEN);
if (generalized_challenge(h_calc_scalar,
labelset, labelset_len,
extra, 3*POINTLEN,
R_calc_bytes, eddsa_25519_pubkey_bytes,
M_buf, MSTART, msg_len) != 0)
goto err;
// if bytes_equal(h, h')
if (crypto_verify_32(h_scalar, h_calc_scalar) != 0)
goto err;
// labelset4 = add_label(labels, "4")
// v = hash(labelset4 || c*Kv)
labelset[labelset_len-1] = (unsigned char)'4';
if (generalized_calculate_vrf_output(vrf_out, labelset, labelset_len, &cKv_point) != 0)
goto err;
free(M_buf);
return 0;
err:
free(M_buf);
return -1;
}

View File

@ -0,0 +1,23 @@
#ifndef __GEN_VEDDSA_H__
#define __GEN_VEDDSA_H__
int generalized_veddsa_25519_sign(
unsigned char* signature_out,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* eddsa_25519_privkey_scalar,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* random,
const unsigned char* customization_label,
const unsigned long customization_label_len);
int generalized_veddsa_25519_verify(
unsigned char* vrf_out,
const unsigned char* signature,
const unsigned char* eddsa_25519_pubkey_bytes,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len);
#endif

View File

@ -0,0 +1,131 @@
#include <string.h>
#include "crypto_additions.h"
#include "gen_x.h"
#include "gen_constants.h"
#include "gen_eddsa.h"
#include "gen_veddsa.h"
#include "gen_crypto_additions.h"
#include "zeroize.h"
static int convert_25519_pubkey(unsigned char* ed_pubkey_bytes, const unsigned char* x25519_pubkey_bytes) {
fe u;
fe y;
/* Convert the X25519 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
*/
if (!fe_isreduced(x25519_pubkey_bytes))
return -1;
fe_frombytes(u, x25519_pubkey_bytes);
fe_montx_to_edy(y, u);
fe_tobytes(ed_pubkey_bytes, y);
return 0;
}
static int calculate_25519_keypair(unsigned char* K_bytes, unsigned char* k_scalar,
const unsigned char* x25519_privkey_scalar)
{
unsigned char kneg[SCALARLEN];
ge_p3 ed_pubkey_point;
unsigned char sign_bit = 0;
if (SCALARLEN != 32)
return -1;
/* Convert the Curve25519 privkey to an Ed25519 public key */
ge_scalarmult_base(&ed_pubkey_point, x25519_privkey_scalar);
ge_p3_tobytes(K_bytes, &ed_pubkey_point);
/* Force Edwards sign bit to zero */
sign_bit = (K_bytes[31] & 0x80) >> 7;
memcpy(k_scalar, x25519_privkey_scalar, 32);
sc_neg(kneg, k_scalar);
sc_cmov(k_scalar, kneg, sign_bit);
K_bytes[31] &= 0x7F;
zeroize(kneg, SCALARLEN);
return 0;
}
int generalized_xeddsa_25519_sign(unsigned char* signature_out,
const unsigned char* x25519_privkey_scalar,
const unsigned char* msg, const unsigned long msg_len,
const unsigned char* random,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char K_bytes[POINTLEN];
unsigned char k_scalar[SCALARLEN];
int retval = -1;
if (calculate_25519_keypair(K_bytes, k_scalar, x25519_privkey_scalar) != 0)
return -1;
retval = generalized_eddsa_25519_sign(signature_out,
K_bytes, k_scalar,
msg, msg_len, random,
customization_label, customization_label_len);
zeroize(k_scalar, SCALARLEN);
return retval;
}
int generalized_xveddsa_25519_sign(
unsigned char* signature_out,
const unsigned char* x25519_privkey_scalar,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* random,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char K_bytes[POINTLEN];
unsigned char k_scalar[SCALARLEN];
int retval = -1;
if (calculate_25519_keypair(K_bytes, k_scalar, x25519_privkey_scalar) != 0)
return -1;
retval = generalized_veddsa_25519_sign(signature_out, K_bytes, k_scalar,
msg, msg_len, random,
customization_label, customization_label_len);
zeroize(k_scalar, SCALARLEN);
return retval;
}
int generalized_xeddsa_25519_verify(
const unsigned char* signature,
const unsigned char* x25519_pubkey_bytes,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char K_bytes[POINTLEN];
if (convert_25519_pubkey(K_bytes, x25519_pubkey_bytes) != 0)
return -1;
return generalized_eddsa_25519_verify(signature, K_bytes, msg, msg_len,
customization_label, customization_label_len);
}
int generalized_xveddsa_25519_verify(
unsigned char* vrf_out,
const unsigned char* signature,
const unsigned char* x25519_pubkey_bytes,
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len)
{
unsigned char K_bytes[POINTLEN];
if (convert_25519_pubkey(K_bytes, x25519_pubkey_bytes) != 0)
return -1;
return generalized_veddsa_25519_verify(vrf_out, signature, K_bytes, msg, msg_len,
customization_label, customization_label_len);
}

View File

@ -0,0 +1,37 @@
#ifndef __GEN_X_H
#define __GEN_X_H
int generalized_xeddsa_25519_sign(unsigned char* signature_out, /* 64 bytes */
const unsigned char* x25519_privkey_scalar, /* 32 bytes */
const unsigned char* msg, const unsigned long msg_len,
const unsigned char* random, /* 32 bytes */
const unsigned char* customization_label,
const unsigned long customization_label_len);
int generalized_xeddsa_25519_verify(
const unsigned char* signature, /* 64 bytes */
const unsigned char* x25519_pubkey_bytes, /* 32 bytes */
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len);
int generalized_xveddsa_25519_sign(
unsigned char* signature_out, /* 96 bytes */
const unsigned char* x25519_privkey_scalar, /* 32 bytes */
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* random, /* 32 bytes */
const unsigned char* customization_label,
const unsigned long customization_label_len);
int generalized_xveddsa_25519_verify(
unsigned char* vrf_out, /* 32 bytes */
const unsigned char* signature, /* 96 bytes */
const unsigned char* x25519_pubkey_bytes, /* 32 bytes */
const unsigned char* msg,
const unsigned long msg_len,
const unsigned char* customization_label,
const unsigned long customization_label_len);
#endif

View File

@ -0,0 +1,12 @@
#include<string.h>
#include "fe.h"
#include "crypto_additions.h"
int point_isreduced(const unsigned char* p)
{
unsigned char strict[32];
memmove(strict, p, 32);
strict[31] &= 0x7F; /* mask off sign bit */
return fe_isreduced(strict);
}

View File

@ -0,0 +1,17 @@
#include <string.h>
#include "fe.h"
#include "sc.h"
#include "crypto_additions.h"
#include "crypto_verify_32.h"
int sc_isreduced(const unsigned char* s)
{
unsigned char strict[64];
memset(strict, 0, 64);
memmove(strict, s, 32);
sc_reduce(strict);
if (crypto_verify_32(strict, s) != 0)
return 0;
return 1;
}

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

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,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;
}

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,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];
}

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};
/* 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) */
}

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

View File

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

View File

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

View File

@ -0,0 +1,80 @@
#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 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
*/
if (!fe_isreduced(curve25519_pubkey))
return -1;
fe_frombytes(u, curve25519_pubkey);
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);
}

View File

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

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

View File

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

View File

@ -1,4 +0,0 @@
#define CRYPTO_SECRETKEYBYTES 64
#define CRYPTO_PUBLICKEYBYTES 32
#define CRYPTO_BYTES 64
#define CRYPTO_DETERMINISTIC 1

View File

@ -2,13 +2,22 @@
#include "crypto_verify_32.h"
/*
return 1 if f == 0
return nonzero if f == 0
return 0 if f != 0
Preconditions:
|f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*/
/* TREVOR'S COMMENT
*
* I think the above comment is wrong. Instead:
*
* return 0 if f == 0
* return -1 if f != 0
*
* */
static const unsigned char zero[32];
int fe_isnonzero(const fe f)

View File

@ -1,106 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "crypto_hash_sha512.h"
#include "curve_sigs.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];
/* 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;
}

View File

@ -0,0 +1,469 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "crypto_hash_sha512.h"
#include "keygen.h"
#include "curve_sigs.h"
#include "xeddsa.h"
#include "crypto_additions.h"
#include "ge.h"
#include "utility.h"
#include "gen_crypto_additions.h"
#include "gen_x.h"
#include "internal_fast_tests.h"
#include <assert.h>
#define ERROR(...) do {if (!silent) { printf(__VA_ARGS__); abort(); } else return -1; } while (0)
#define INFO(...) do {if (!silent) printf(__VA_ARGS__);} while (0)
#define TEST(msg, cond) \
do { \
if ((cond)) { \
INFO("%s good\n", msg); \
} \
else { \
ERROR("%s BAD!!!\n", msg); \
} \
} while (0)
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));
TEST("SHA512 #1", memcmp(sha512_actual_output, sha512_correct_output, 64) == 0);
sha512_input[111] ^= 1;
crypto_hash_sha512(sha512_actual_output, sha512_input, sizeof(sha512_input));
TEST("SHA512 #2", memcmp(sha512_actual_output, sha512_correct_output, 64) != 0);
return 0;
}
int strict_fast_test(int silent)
{
unsigned char unreduced1[32] = {
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
};
unsigned char unreduced2[32] = {
0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
};
unsigned char unreduced3[32] = {
0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
};
unsigned char q[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, 0x00, 0x10,
};
unsigned char qminus1[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,
};
unsigned char qplus1[32] = {
0xee, 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,
};
TEST("fe_isreduced",
(fe_isreduced(unreduced1) == 0) &&
(fe_isreduced(unreduced2) == 0) &&
(fe_isreduced(unreduced3) == 1)
);
TEST("sc_isreduced",
(sc_isreduced(q) == 0) &&
(sc_isreduced(qminus1) == 1) &&
(sc_isreduced(qplus1) == 0)
);
return 0;
}
int ge_fast_test(int silent)
{
const unsigned char B_bytes[] = {
0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
};
const unsigned char misc_bytes[] = {
0x57, 0x17, 0xfa, 0xce, 0xca, 0xb9, 0xdf, 0x0e,
0x90, 0x67, 0xaa, 0x46, 0xba, 0x83, 0x2f, 0xeb,
0x1c, 0x49, 0xd0, 0x21, 0xb1, 0x33, 0xff, 0x11,
0xc9, 0x7a, 0xb8, 0xcf, 0xe3, 0x29, 0x46, 0x17,
};
unsigned char q_scalar[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, 0x00, 0x10,
};
unsigned char c_scalar[32] = {
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char neutral_bytes[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* unsigned char one_scalar[32] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char B_bytes[] = {
0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
};
*/
ge_p3 point1, point2, B_point, misc_point, miscneg_point;
unsigned char output1[32], output2[32];
if (ge_frombytes_negate_vartime(&B_point, B_bytes) != 0)
TEST("Failure to parse point #1", 0);
if (ge_frombytes_negate_vartime(&miscneg_point, misc_bytes) != 0)
TEST("Failure to parse point #2", 0);
ge_neg(&B_point, &B_point);
ge_neg(&misc_point, &miscneg_point);
/* q*B == neutral */
ge_scalarmult_base(&point1, q_scalar);
ge_scalarmult(&point2, q_scalar, &B_point);
ge_p3_tobytes(output1, &point1);
ge_p3_tobytes(output2, &point2);
TEST("qB == qB", memcmp(output1, output2, 32) == 0 && memcmp(output1, neutral_bytes, 32) == 0);
TEST("qB isneutral", ge_isneutral(&point1 ) && ge_isneutral(&point2) && !ge_isneutral(&B_point));
/* cB == cB, cX == cX */
ge_scalarmult_cofactor(&point1, &B_point);
ge_scalarmult_base(&point2, c_scalar);
ge_p3_tobytes(output1, &point1);
ge_p3_tobytes(output2, &point2);
TEST("cB == cB", memcmp(output1, output2, 32) == 0);
ge_scalarmult_cofactor(&point1, &misc_point);
ge_scalarmult(&point2, c_scalar, &misc_point);
ge_p3_tobytes(output1, &point1);
ge_p3_tobytes(output2, &point2);
TEST("cX == cX", memcmp(output1, output2, 32) == 0);
/* */
ge_p3_add(&point1, &misc_point, &miscneg_point);
TEST("X + -X isneutral", ge_isneutral(&point1));
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_output1[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 hashtopoint_correct_output2[32] =
{
0xa0, 0x35, 0xbb, 0xa9, 0x4d, 0x30, 0x55, 0x33,
0x0d, 0xce, 0xc2, 0x7f, 0x83, 0xde, 0x79, 0xd0,
0x89, 0x67, 0x72, 0x4c, 0x07, 0x8d, 0x68, 0x9d,
0x61, 0x52, 0x1d, 0xf9, 0x2c, 0x5c, 0xba, 0x77
};
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);
TEST("Elligator vector", memcmp(bytes, elligator_correct_output, 32) == 0);
/* Elligator(0) == 0 test */
fe_0(in);
elligator(out, in);
TEST("Elligator(0) == 0", memcmp(in, out, 32) == 0);
/* ge_montx_to_p3(0) -> order2 point test */
fe one, negone, zero;
fe_1(one);
fe_0(zero);
fe_sub(negone, zero, one);
ge_p3 p3;
ge_montx_to_p3(&p3, zero, 0);
TEST("ge_montx_to_p3(0) == order 2 point",
fe_isequal(p3.X, zero) &&
fe_isequal(p3.Y, negone) &&
fe_isequal(p3.Z, one) &&
fe_isequal(p3.T, zero));
/* Hash to point vector test */
unsigned char htp[32];
for (count=0; count < 32; count++) {
htp[count] = count;
}
hash_to_point(&p3, htp, 32);
ge_p3_tobytes(htp, &p3);
TEST("hash_to_point #1", memcmp(htp, hashtopoint_correct_output1, 32) == 0);
for (count=0; count < 32; count++) {
htp[count] = count+1;
}
hash_to_point(&p3, htp, 32);
ge_p3_tobytes(htp, &p3);
TEST("hash_to_point #2", memcmp(htp, hashtopoint_correct_output2, 32) == 0);
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,
};
const int MSG_LEN = 200;
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);
TEST("Curvesig sign", memcmp(signature, signature_correct, 64) == 0);
TEST("Curvesig verify #1", curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0);
signature[0] ^= 1;
TEST("Curvesig verify #2", curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0);
return 0;
}
int xeddsa_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,
};
const int MSG_LEN = 200;
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);
xed25519_sign(signature, privkey, msg, MSG_LEN, random);
TEST("XEdDSA sign", memcmp(signature, signature_correct, 64) == 0);
TEST("XEdDSA verify #1", xed25519_verify(signature, pubkey, msg, MSG_LEN) == 0);
signature[0] ^= 1;
TEST("XEdDSA verify #2", xed25519_verify(signature, pubkey, msg, MSG_LEN) != 0);
memset(pubkey, 0xFF, 32);
TEST("XEdDSA verify #3", xed25519_verify(signature, pubkey, msg, MSG_LEN) != 0);
return 0;
}
int generalized_xeddsa_fast_test(int silent)
{
unsigned char signature1[64];
unsigned char signature2[64];
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char msg1[1000];
unsigned char msg2[1000];
unsigned char random[64];
memset(signature1, 0, 64);
memset(signature2, 0, 64);
memset(privkey, 0xF0, 32);
memset(pubkey, 2, 32);
memset(msg1, 0x10, 1000);
memset(msg2, 0x20, 1000);
memset(random, 0xBC, 64);
sc_clamp(privkey);
curve25519_keygen(pubkey, privkey);
msg2[0] = 1;
TEST("generalized xeddsa sign #1", generalized_xeddsa_25519_sign(signature1, privkey, msg1, 100, random, NULL, 0) == 0);
TEST("generalized xeddsa sign #2", generalized_xeddsa_25519_sign(signature2, privkey, msg2, 100, random, NULL, 0) == 0);
TEST("generalized (old) xeddsa verify #1", xed25519_verify(signature1, pubkey, msg1, 100) == 0);
TEST("generalized (old) xeddsa verify #2", xed25519_verify(signature2, pubkey, msg2, 100) == 0);
TEST("generalized (old) xeddsa verify #3", xed25519_verify(signature1, pubkey, msg2, 100) != 0);
TEST("generalized (old) xeddsa verify #4", xed25519_verify(signature2, pubkey, msg1, 100) != 0);
TEST("generalized xeddsa verify #1", generalized_xeddsa_25519_verify(signature1, pubkey, msg1, 100, NULL, 0) == 0);
TEST("generalized xeddsa verify #2", generalized_xeddsa_25519_verify(signature2, pubkey, msg2, 100, NULL, 0) == 0);
TEST("generalized xeddsa verify #3", generalized_xeddsa_25519_verify(signature1, pubkey, msg2, 100, NULL, 0) != 0);
TEST("generalized xeddsa verify #4", generalized_xeddsa_25519_verify(signature2, pubkey, msg1, 100, NULL, 0) != 0);
return 0;
}
int generalized_xveddsa_fast_test(int silent)
{
unsigned char signature1[96];
unsigned char signature2[96];
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char msg1[1000];
unsigned char msg2[1000];
unsigned char random[64];
unsigned char vrf[32];
memset(signature1, 0, 64);
memset(signature2, 0, 64);
memset(privkey, 1, 32);
memset(pubkey, 2, 32);
memset(msg1, 0x11, 1000);
memset(msg2, 0x22, 1000);
memset(random, 0xAB, 64);
sc_clamp(privkey);
curve25519_keygen(pubkey, privkey);
msg2[0] ^= 1;
TEST("generalized xveddsa sign #1", generalized_xveddsa_25519_sign(signature1, privkey, msg1, 100, random, NULL, 0) == 0);
TEST("generalized xveddsa sign #2", generalized_xveddsa_25519_sign(signature2, privkey, msg2, 100, random, (unsigned char*)"abc", 3) == 0);
TEST("generalized xveddsa verify #1", generalized_xveddsa_25519_verify(vrf, signature1, pubkey, msg1, 100, NULL, 0) == 0);
TEST("generalized xveddsa verify #2", generalized_xveddsa_25519_verify(vrf, signature2, pubkey, msg2, 100, (unsigned char*)"abc", 3) == 0);
TEST("generalized xveddsa verify #3", generalized_xveddsa_25519_verify(vrf, signature1, pubkey, msg2, 100, NULL, 0) != 0);
TEST("generalized xveddsa verify #4", generalized_xveddsa_25519_verify(vrf, signature2, pubkey, msg1, 100, (unsigned char*)"abc", 3) != 0);
unsigned char signature3[96];
unsigned char vrf3[96];
random[0] ^= 1;
TEST("generalized xveddsa sign #3", generalized_xveddsa_25519_sign(signature3, privkey, msg1, 100, random, NULL, 0) == 0);
TEST("generalized xveddsa verify #5", generalized_xveddsa_25519_verify(vrf, signature1, pubkey, msg1, 100, NULL, 0) == 0);
TEST("generalized xveddsa verify #6", generalized_xveddsa_25519_verify(vrf3, signature3, pubkey, msg1, 100, NULL, 0) == 0);
TEST("generalized xveddsa VRFs equal", memcmp(vrf, vrf3, 32) == 0);
TEST("generalized xveddsa Kv equal", memcmp(signature1+0, signature3+0, 32) == 0);
TEST("generalized xveddsa h not equal", memcmp(signature1+32, signature3+32, 32) != 0);
TEST("generalized xveddsa s not equal", memcmp(signature1+64, signature3+64, 32) != 0);
return 0;
}
int all_fast_tests(int silent)
{
int result;
if ((result = sha512_fast_test(silent)) != 0)
return -1;
if ((result = strict_fast_test(silent)) != 0)
return -2;
if ((result = ge_fast_test(silent)) != 0)
return -3;
if ((result = elligator_fast_test(silent)) != 0)
return -3;
if ((result = curvesigs_fast_test(silent)) != 0)
return -4;
if ((result = xeddsa_fast_test(silent)) != 0)
return -5;
if ((result = generalized_xeddsa_fast_test(silent)) != 0)
return -6;
if ((result = generalized_xveddsa_fast_test(silent)) != 0)
return -7;
return 0;
}

View File

@ -0,0 +1,19 @@
#ifndef __INTERNAL_FAST_TESTS_H__
#define __INTERNAL_FAST_TESTS_H__
/* silent = 0 : prints info+error messages to stdout, abort() on test failure
* silent = 1 : returns 0 for success, anything else for failure
*/
int sha512_fast_test(int silent);
int strict_fast_test(int silent);
int elligator_fast_test(int silent);
int curvesigs_fast_test(int silent);
int xeddsa_fast_test(int silent);
int vxeddsa_fast_test(int silent);
int generalized_xeddsa_fast_test(int silent);
int generalized_xveddsa_fast_test(int silent);
int all_fast_tests(int silent);
#endif

View File

@ -0,0 +1,371 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "crypto_hash_sha512.h"
#include "keygen.h"
#include "curve_sigs.h"
#include "xeddsa.h"
#include "crypto_additions.h"
#include "ge.h"
#include "utility.h"
#include "gen_x.h"
#include "internal_slow_tests.h"
#include <assert.h>
#define ERROR(...) do {if (!silent) { printf(__VA_ARGS__); abort(); } else return -1; } while (0)
#define INFO(...) do {if (!silent) printf(__VA_ARGS__);} while (0)
#define TEST(msg, cond) \
do { \
if ((cond)) { \
INFO("%s good\n", msg); \
} \
else { \
ERROR("%s BAD!!!\n", msg); \
} \
} while (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;
const int MSG_LEN = 200;
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...\n");
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 %d\n", count);
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 %d\n", count);
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 64) != 0)
ERROR("Curvesig signature 10K doesn't match %d\n", count);
}
if (count == 100000)
print_bytes("100K curvesigs", signature, 64);
if (count == 1000000)
print_bytes("1M curvesigs", signature, 64);
if (count == 10000000)
print_bytes("10M curvesigs", signature, 64);
}
INFO("good\n");
return 0;
}
int xeddsa_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;
const int MSG_LEN = 200;
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 XEdDSA...\n");
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);
xed25519_sign(signature, privkey, msg, MSG_LEN, random);
if (xed25519_verify(signature, pubkey, msg, MSG_LEN) != 0)
ERROR("XEdDSA verify failure #1 %d\n", count);
if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (xed25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("XEdDSA verify failure #2 %d\n", count);
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 64) != 0)
ERROR("XEDSA signature 10K doesn't match %d\n", count);
}
if (count == 100000)
print_bytes("100K XEdDSA", signature, 64);
if (count == 1000000)
print_bytes("1M XEdDSA", signature, 64);
if (count == 10000000)
print_bytes("10M XEdDSA", signature, 64);
}
INFO("good\n");
return 0;
}
int xeddsa_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;
const int MSG_LEN = 200;
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 XEdDSA/Curvesigs...\n");
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);
xed25519_sign(signature, privkey, msg, MSG_LEN, random);
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) != 0)
ERROR("XEdDSA/Curvesigs verify failure #1 %d\n", count);
if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (curve25519_verify(signature, pubkey, msg, MSG_LEN) == 0)
ERROR("XEdDSA/Curvesigs verify failure #2 %d\n", count);
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 64) != 0)
ERROR("XEdDSA/Curvesigs signature 10K doesn't match %d\n", count);
}
if (count == 100000)
print_bytes("100K XEdDSA/C", signature, 64);
if (count == 1000000)
print_bytes("1M XEdDSA/C", signature, 64);
if (count == 10000000)
print_bytes("10M XEdDSA/C", signature, 64);
}
INFO("good\n");
return 0;
}
int generalized_xveddsa_slow_test(int silent, int iterations)
{
unsigned char signature_10k_correct[96] = {
0x89, 0x21, 0xf5, 0x2f, 0x37, 0x72, 0x08, 0x55,
0x18, 0x9d, 0x24, 0xed, 0x86, 0xb1, 0x7a, 0x02,
0xbf, 0x29, 0x5e, 0xa7, 0x45, 0xdc, 0x80, 0x03,
0x7f, 0x4f, 0xca, 0x79, 0xe0, 0x95, 0xd0, 0xa1,
0xb5, 0x99, 0xbe, 0xbd, 0xef, 0xbe, 0xa4, 0xdc,
0x0c, 0x07, 0x6a, 0xf7, 0x7f, 0xe1, 0x1c, 0xb8,
0x18, 0x84, 0xb8, 0xb4, 0xcf, 0x38, 0x7d, 0x98,
0x37, 0xd8, 0x40, 0x23, 0x42, 0x12, 0x70, 0x06,
0xb0, 0xd1, 0x0c, 0xc0, 0x1c, 0xa6, 0x9a, 0x2f,
0xb4, 0x02, 0xd6, 0x37, 0x22, 0xe9, 0xfb, 0x00,
0x22, 0x02, 0x5a, 0xf4, 0x40, 0x43, 0xb8, 0xe9,
0xf4, 0x13, 0x44, 0x16, 0x19, 0x8d, 0x7e, 0x02,
};
unsigned char signature_100k_correct[96] = {
0xc4, 0x99, 0x64, 0x1f, 0x94, 0x95, 0xf4, 0x57,
0xa0, 0xb9, 0x3d, 0xc3, 0xb5, 0x2e, 0x1e, 0xdd,
0x92, 0xf2, 0x4c, 0xb2, 0x01, 0x36, 0x3d, 0xf2,
0xea, 0x2c, 0xdc, 0x32, 0x21, 0x5f, 0xc5, 0xd2,
0xff, 0x16, 0x41, 0x71, 0x3a, 0x77, 0x79, 0xeb,
0x67, 0x20, 0xc4, 0xec, 0x39, 0xe1, 0x54, 0x2d,
0x40, 0x10, 0xf9, 0xca, 0xc5, 0x21, 0x0a, 0x47,
0x63, 0x99, 0x23, 0x04, 0x9d, 0x03, 0x1a, 0x06,
0x00, 0xb9, 0x56, 0x7e, 0xef, 0xee, 0x0b, 0x40,
0x59, 0xc1, 0x86, 0xd9, 0xa7, 0x87, 0x70, 0xec,
0x05, 0x89, 0xbe, 0x71, 0x43, 0xd1, 0xf5, 0x61,
0x5e, 0x00, 0x41, 0xde, 0x1f, 0x41, 0x2d, 0x0e,
};
/*
unsigned char signature_1m_correct[96] = {
0xf8, 0xb1, 0x20, 0xf2, 0x1e, 0x5c, 0xbf, 0x5f,
0xea, 0x07, 0xcb, 0xb5, 0x77, 0xb8, 0x03, 0xbc,
0xcb, 0x6d, 0xf1, 0xc1, 0xa5, 0x03, 0x05, 0x7b,
0x01, 0x63, 0x9b, 0xf9, 0xed, 0x3e, 0x57, 0x47,
0xd2, 0x5b, 0xf4, 0x7e, 0x7c, 0x45, 0xce, 0xfc,
0x06, 0xb3, 0xf4, 0x05, 0x81, 0x9f, 0x53, 0xb0,
0x18, 0xe3, 0xfa, 0xcb, 0xb2, 0x52, 0x3e, 0x57,
0xcb, 0x34, 0xcc, 0x81, 0x60, 0xb9, 0x0b, 0x04,
0x07, 0x79, 0xc0, 0x53, 0xad, 0xc4, 0x4b, 0xd0,
0xb5, 0x7d, 0x95, 0x4e, 0xbe, 0xa5, 0x75, 0x0c,
0xd4, 0xbf, 0xa7, 0xc0, 0xcf, 0xba, 0xe7, 0x7c,
0xe2, 0x90, 0xef, 0x61, 0xa9, 0x29, 0x66, 0x0d,
};
unsigned char signature_10m_correct[96] = {
0xf5, 0xa4, 0xbc, 0xec, 0xc3, 0x3d, 0xd0, 0x43,
0xd2, 0x81, 0x27, 0x9e, 0xf0, 0x4c, 0xbe, 0xf3,
0x77, 0x01, 0x56, 0x41, 0x0e, 0xff, 0x0c, 0xb9,
0x66, 0xec, 0x4d, 0xe0, 0xb7, 0x25, 0x63, 0x6b,
0x5c, 0x08, 0x39, 0x80, 0x4e, 0x37, 0x1b, 0x2c,
0x46, 0x6f, 0x86, 0x99, 0x1c, 0x4e, 0x31, 0x60,
0xdb, 0x4c, 0xfe, 0xc5, 0xa2, 0x4d, 0x71, 0x2b,
0xd6, 0xd0, 0xc3, 0x98, 0x88, 0xdb, 0x0e, 0x0c,
0x68, 0x4a, 0xd3, 0xc7, 0x56, 0xac, 0x8d, 0x95,
0x7b, 0xbd, 0x99, 0x50, 0xe8, 0xd3, 0xea, 0xf3,
0x7b, 0x26, 0xf2, 0xa2, 0x2b, 0x02, 0x58, 0xca,
0xbd, 0x2c, 0x2b, 0xf7, 0x77, 0x58, 0xfe, 0x09,
};
*/
int count;
const int MSG_LEN = 200;
unsigned char privkey[32];
unsigned char pubkey[32];
unsigned char signature[96];
unsigned char msg[MSG_LEN];
unsigned char random[64];
unsigned char vrf_out[32];
memset(privkey, 0, 32);
memset(pubkey, 0, 32);
memset(signature, 3, 96);
memset(msg, 0, MSG_LEN);
memset(random, 0, 64);
INFO("Pseudorandom XVEdDSA...\n");
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);
generalized_xveddsa_25519_sign(signature, privkey, msg, MSG_LEN, random, NULL, 0);
if (generalized_xveddsa_25519_verify(vrf_out, signature, pubkey, msg, MSG_LEN, NULL, 0) != 0)
ERROR("XVEdDSA verify failure #1 %d\n", count);
if (b[63] & 1)
signature[count % 96] ^= 1;
else
msg[count % MSG_LEN] ^= 1;
if (generalized_xveddsa_25519_verify(vrf_out, signature, pubkey, msg, MSG_LEN, NULL, 0) == 0)
ERROR("XVEdDSA verify failure #2 %d\n", count);
if (count == 10000)
print_bytes("10K XVEdDSA", signature, 96);
if (count == 100000)
print_bytes("100K XVEdDSA", signature, 96);
if (count == 1000000)
print_bytes("1M XVEdDSA", signature, 96);
if (count == 10000000)
print_bytes("10M XVEdDSA", signature, 96);
if (count == 100000000)
print_bytes("100M XVEdDSA", signature, 96);
if (count == 10000) {
if (memcmp(signature, signature_10k_correct, 96) != 0)
ERROR("XVEDDSA 10K doesn't match %d\n", count);
}
if (count == 100000) {
if (memcmp(signature, signature_100k_correct, 96) != 0)
ERROR("XVEDDSA 100K doesn't match %d\n", count);
}
/*
if (count == 1000000) {
if (memcmp(signature, signature_1m_correct, 96) != 0)
ERROR("XVEDDSA 1m doesn't match %d\n", count);
}
if (count == 10000000) {
if (memcmp(signature, signature_10m_correct, 96) != 0)
ERROR("XVEDDSA 10m doesn't match %d\n", count);
}
if (count == 100000000) {
if (memcmp(signature, signature_100m_correct, 96) != 0)
ERROR("XVEDDSA 100m doesn't match %d\n", count);
}
*/
}
INFO("good\n");
return 0;
}

View File

@ -0,0 +1,15 @@
#ifndef __INTERNAL_SLOW_TESTS_H__
#define __INTERNAL_SLOW_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 curvesigs_slow_test(int silent, int iterations);
int xeddsa_slow_test(int silent, int iterations);
int xeddsa_to_curvesigs_slow_test(int silent, int iterations);
int generalized_xveddsa_slow_test(int silent, int iterations);
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -5,4 +5,12 @@ public class NativeCurve25519ProviderTest extends Curve25519ProviderTest {
protected Curve25519Provider createProvider() throws NoSuchProviderException {
return new NativeCurve25519Provider();
}
private native boolean internalTest();
public void testInternalTest() throws Exception {
assertTrue(internalTest());
}
}

View File

@ -1,7 +1,16 @@
package org.whispersystems.curve25519;
import java.util.Arrays;
import java.util.Random;
public class NativeCurve25519Test extends Curve25519Test {
private final byte[] PUBLIC_KEY = new byte[]{(byte) 0x21, (byte) 0xf7, (byte) 0x34, (byte) 0x5f, (byte) 0x56, (byte) 0xd9, (byte) 0x60, (byte) 0x2f, (byte) 0x15, (byte) 0x23, (byte) 0x29, (byte) 0x8f, (byte) 0x4f, (byte) 0x6f, (byte) 0xce, (byte) 0xcb, (byte) 0x14, (byte) 0xdd, (byte) 0xe2, (byte) 0xd5, (byte) 0xb9, (byte) 0xa9, (byte) 0xb4, (byte) 0x8b, (byte) 0xca, (byte) 0x82, (byte) 0x42, (byte) 0x68, (byte) 0x14, (byte) 0x92, (byte) 0xb9, (byte) 0x20};
private final byte[] PRIVATE_KEY = new byte[]{(byte) 0x38, (byte) 0x61, (byte) 0x1d, (byte) 0x25, (byte) 0x3b, (byte) 0xea, (byte) 0x85, (byte) 0xa2, (byte) 0x03, (byte) 0x80, (byte) 0x53, (byte) 0x43, (byte) 0xb7, (byte) 0x4a, (byte) 0x93, (byte) 0x6d, (byte) 0x3b, (byte) 0x13, (byte) 0xb9, (byte) 0xe3, (byte) 0x12, (byte) 0x14, (byte) 0x53, (byte) 0xe9, (byte) 0x74, (byte) 0x0b, (byte) 0x6b, (byte) 0x82, (byte) 0x7e, (byte) 0x33, (byte) 0x7e, (byte) 0x5d};
private final byte[] MESSAGE = new byte[]{(byte) 0x54, (byte) 0x68, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x75, (byte) 0x6e, (byte) 0x69, (byte) 0x71, (byte) 0x75, (byte) 0x65, (byte) 0x2e};
private final byte[] VRF = new byte[]{(byte) 0x45, (byte) 0xdc, (byte) 0x7b, (byte) 0x81, (byte) 0x6b, (byte) 0x01, (byte) 0xb3, (byte) 0x6c, (byte) 0xfa, (byte) 0x16, (byte) 0x45, (byte) 0xdc, (byte) 0xae, (byte) 0x8a, (byte) 0xc9, (byte) 0xbc, (byte) 0x8e, (byte) 0x52, (byte) 0x3c, (byte) 0xd8, (byte) 0x6d, (byte) 0x00, (byte) 0x7d, (byte) 0x19, (byte) 0x95, (byte) 0x3f, (byte) 0x03, (byte) 0xe7, (byte) 0xd5, (byte) 0x45, (byte) 0x54, (byte) 0xa0};
@Override
public void testCheckProvider() throws NoSuchProviderException {
assertTrue(Curve25519.getInstance(getProviderName()).isNative());
@ -12,4 +21,37 @@ public class NativeCurve25519Test extends Curve25519Test {
return "native";
}
public void testUniqueSignatures() throws Exception {
Curve25519KeyPair keys = getInstance().generateKeyPair();
Random random = new Random(System.currentTimeMillis());
for (int i=1;i<=256;i++) {
byte[] message = new byte[i];
random.nextBytes(message);
byte[] signature = getInstance().calculateVrfSignature(keys.getPrivateKey(), message);
byte[] vrf = getInstance().verifyVrfSignature(keys.getPublicKey(), message, signature);
assertFalse(getInstance().verifySignature(keys.getPublicKey(), message, signature));
message[Math.abs(random.nextInt()) % message.length] ^= 0x01;
try {
getInstance().verifyVrfSignature(keys.getPublicKey(), message, signature);
throw new AssertionError("Should have failed");
} catch (VrfSignatureVerificationFailedException e) {
// good
}
}
}
public void testUniqueSignatureVector() throws Exception {
Curve25519KeyPair keys = new Curve25519KeyPair(PUBLIC_KEY, PRIVATE_KEY);
byte[] signature = getInstance().calculateVrfSignature(keys.getPrivateKey(), MESSAGE);
byte[] vrf = getInstance().verifyVrfSignature(keys.getPublicKey(), MESSAGE, signature);
assertTrue(Arrays.equals(vrf, VRF));
}
}

View File

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

View File

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

View File

@ -70,6 +70,14 @@ public class Curve25519 {
* @return A 32-byte shared secret.
*/
public byte[] calculateAgreement(byte[] publicKey, byte[] privateKey) {
if (publicKey == null || privateKey == null) {
throw new IllegalArgumentException("Keys must not be null!");
}
if (publicKey.length != 32 || privateKey.length != 32) {
throw new IllegalArgumentException("Keys must be 32 bytes!");
}
return provider.calculateAgreement(privateKey, publicKey);
}
@ -81,6 +89,10 @@ public class Curve25519 {
* @return A 64-byte signature.
*/
public byte[] calculateSignature(byte[] privateKey, byte[] message) {
if (privateKey == null || privateKey.length != 32) {
throw new IllegalArgumentException("Invalid private key length!");
}
byte[] random = provider.getRandom(64);
return provider.calculateSignature(random, privateKey, message);
}
@ -94,9 +106,56 @@ public class Curve25519 {
* @return true if valid, false if not.
*/
public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) {
if (publicKey == null || publicKey.length != 32) {
throw new IllegalArgumentException("Invalid public key!");
}
if (message == null || signature == null || signature.length != 64) {
return false;
}
return provider.verifySignature(publicKey, message, signature);
}
/**
* Calculates a Unique Curve25519 signature.
*
* @param privateKey The private Curve25519 key to create the signature with.
* @param message The message to sign.
* @return A 96-byte signature.
*/
public byte[] calculateVrfSignature(byte[] privateKey, byte[] message) {
if (privateKey == null || privateKey.length != 32) {
throw new IllegalArgumentException("Invalid private key!");
}
byte[] random = provider.getRandom(64);
return provider.calculateVrfSignature(random, privateKey, message);
}
/**
* Verify a Unique Curve25519 signature.
*
* @param publicKey The Curve25519 public key the unique signature belongs to.
* @param message The message that was signed.
* @param signature The unique signature to verify.
*
* @return The vrf for this signature.
*/
public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
throws VrfSignatureVerificationFailedException
{
if (publicKey == null || publicKey.length != 32) {
throw new IllegalArgumentException("Invalid public key!");
}
if (message == null || signature == null || signature.length != 96) {
throw new VrfSignatureVerificationFailedException("Invalid message or signature format");
}
return provider.verifyVrfSignature(publicKey, message, signature);
}
private static Curve25519Provider constructNativeProvider(SecureRandomProvider random) throws NoSuchProviderException {
return constructClass("NativeCurve25519Provider", random);
}

View File

@ -15,8 +15,13 @@ 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[] calculateVrfSignature(byte[] random, byte[] privateKey, byte[] message);
byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
throws VrfSignatureVerificationFailedException;
byte[] getRandom(int length);
void setRandomProvider(SecureRandomProvider provider);

View File

@ -0,0 +1,16 @@
package org.whispersystems.curve25519;
public class VrfSignatureVerificationFailedException extends Exception {
public VrfSignatureVerificationFailedException() {
super();
}
public VrfSignatureVerificationFailedException(String message) {
super(message);
}
public VrfSignatureVerificationFailedException(Exception exception) {
super(exception);
}
}

View File

@ -6,7 +6,6 @@ public class curve_sigs {
byte[] curve25519_privkey_in)
{
ge_p3 ed = new ge_p3(); /* Ed25519 pubkey point */
int[] ed_y = new int[10];
int[] ed_y_plus_one = new int[10];
int[] one_minus_ed_y = new int[10];
int[] inv_one_minus_ed_y = new int[10];

View File

@ -37,7 +37,7 @@ Can get away with 11 carries, but then data flow is much deeper.
With tighter constraints on inputs can squeeze carries into int32.
*/
public static void fe_mul(int[] h,int[] f,int[] g)
public static long[] fe_mul1(int[] f,int[] g)
{
int f0 = f[0];
int f1 = f[1];
@ -173,16 +173,36 @@ public static void fe_mul(int[] h,int[] f,int[] g)
long f9g7_38 = f9_2 * (long) g7_19;
long f9g8_19 = f9 * (long) g8_19;
long f9g9_38 = f9_2 * (long) g9_19;
long h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
long h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
long h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
long h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
long h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
long h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
long h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38;
long h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19;
long h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38;
long h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ;
long h[] = new long[10];
h[0] = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
h[1] = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
h[2] = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
h[3] = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
h[4] = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
h[5] = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
h[6] = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38;
h[7] = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19;
h[8] = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38;
h[9] = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ;
return h;
}
public static void fe_mul(int[] h,int[] f,int[] g)
{
long[] hr = fe_mul1(f, g);
long h0 = hr[0];
long h1 = hr[1];
long h2 = hr[2];
long h3 = hr[3];
long h4 = hr[4];
long h5 = hr[5];
long h6 = hr[6];
long h7 = hr[7];
long h8 = hr[8];
long h9 = hr[9];
long carry0;
long carry1;
long carry2;

View File

@ -1,6 +1,6 @@
#Tue Jan 06 14:11:31 PST 2015
#Mon Oct 17 15:10:52 PDT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

View File

@ -1,4 +1,4 @@
/**
/*
* Copyright (C) 2014-2016 Open Whisper Systems
*
* Licensed according to the LICENSE file in this repository.
@ -6,28 +6,17 @@
package org.whispersystems.curve25519;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class JCESecureRandomProvider implements SecureRandomProvider {
@Override
public void nextBytes(byte[] output) {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.nextBytes(output);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
new SecureRandom().nextBytes(output);
}
@Override
public int nextInt(int maxValue) {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
return secureRandom.nextInt(maxValue);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
return new SecureRandom().nextInt(maxValue);
}
}

View File

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

View File

@ -63,4 +63,16 @@ public class OpportunisticCurve25519Provider implements Curve25519Provider {
return delegate.verifySignature(publicKey, message, signature);
}
@Override
public byte[] calculateVrfSignature(byte[] random, byte[] privateKey, byte[] message) {
return delegate.calculateVrfSignature(random, privateKey, message);
}
@Override
public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
throws VrfSignatureVerificationFailedException
{
return delegate.verifyVrfSignature(publicKey, message, signature);
}
}