diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h index 88492dc1a..df5fde235 100644 --- a/src/secp256k1/include/secp256k1_ecdh.h +++ b/src/secp256k1/include/secp256k1_ecdh.h @@ -1,31 +1,55 @@ #ifndef SECP256K1_ECDH_H #define SECP256K1_ECDH_H #include "secp256k1.h" #ifdef __cplusplus extern "C" { #endif +/** A pointer to a function that applies hash function to a point + * + * Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail + * Out: output: pointer to an array to be filled by the function + * In: x: pointer to a 32-byte x coordinate + * y: pointer to a 32-byte y coordinate + * data: Arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ecdh_hash_function)( + unsigned char *output, + const unsigned char *x, + const unsigned char *y, + void *data +); + +/** An implementation of SHA256 hash function that applies to compressed public key. */ +SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; + +/** A default ecdh hash function (currently equal to secp256k1_ecdh_hash_function_sha256). */ +SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; + /** Compute an EC Diffie-Hellman secret in constant time * Returns: 1: exponentiation was successful * 0: scalar was invalid (zero or overflow) * Args: ctx: pointer to a context object (cannot be NULL) - * Out: result: a 32-byte array which will be populated by an ECDH - * secret computed from the point and scalar + * Out: output: pointer to an array to be filled by the function * In: pubkey: a pointer to a secp256k1_pubkey containing an * initialized public key * privkey: a 32-byte scalar with which to multiply the point + * hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used + * data: Arbitrary data pointer that is passed through */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( const secp256k1_context* ctx, - unsigned char *result, + unsigned char *output, const secp256k1_pubkey *pubkey, - const unsigned char *privkey + const unsigned char *privkey, + secp256k1_ecdh_hash_function hashfp, + void *data ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); #ifdef __cplusplus } #endif #endif /* SECP256K1_ECDH_H */ diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c index 5837f4e7d..c1dd5a6ac 100644 --- a/src/secp256k1/src/bench_ecdh.c +++ b/src/secp256k1/src/bench_ecdh.c @@ -1,54 +1,54 @@ /********************************************************************** * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #include #include "include/secp256k1.h" #include "include/secp256k1_ecdh.h" #include "util.h" #include "bench.h" typedef struct { secp256k1_context *ctx; secp256k1_pubkey point; unsigned char scalar[32]; } bench_ecdh_data; static void bench_ecdh_setup(void* arg) { int i; bench_ecdh_data *data = (bench_ecdh_data*)arg; const unsigned char point[] = { 0x03, 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f }; /* create a context with no capabilities */ data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); for (i = 0; i < 32; i++) { data->scalar[i] = i + 1; } CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); } static void bench_ecdh(void* arg) { int i; unsigned char res[32]; bench_ecdh_data *data = (bench_ecdh_data*)arg; for (i = 0; i < 20000; i++) { - CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); } } int main(void) { bench_ecdh_data data; run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); return 0; } diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c index 11e80570e..a74f86211 100644 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,429 +1,431 @@ #include #include #include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" #include "include/secp256k1_ecdh.h" #include "include/secp256k1_recovery.h" #include "include/secp256k1_schnorr.h" SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone (JNIEnv* env, jclass classObject, jlong ctx_l) { const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); (void)classObject;(void)env; return ctx_clone_l; } SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); (void)classObject; return secp256k1_context_randomize(ctx, seed); } SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context (JNIEnv* env, jclass classObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; secp256k1_context_destroy(ctx); (void)classObject;(void)env; } SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* sigdata = { (unsigned char*) (data + 32) }; const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; secp256k1_ecdsa_signature sig; secp256k1_pubkey pubkey; int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); if( ret ) { ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); if( ret ) { ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); } } (void)classObject; return ret; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char* secKey = (unsigned char*) (data + 32); jobjectArray retArray; jbyteArray sigArray, intsByteArray; unsigned char intsarray[2]; secp256k1_ecdsa_signature sig[72]; - int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL); unsigned char outputSer[72]; size_t outputLen = 72; if( ret ) { int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; } intsarray[0] = outputLen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); sigArray = (*env)->NewByteArray(env, outputLen); (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); intsByteArray = (*env)->NewByteArray(env, 2); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); (void)classObject; return secp256k1_ec_seckey_verify(ctx, secKey); } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); secp256k1_pubkey pubkey; jobjectArray retArray; jbyteArray pubkeyArray, intsByteArray; unsigned char intsarray[2]; int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); unsigned char outputSer[65]; size_t outputLen = 65; if( ret ) { int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; } intsarray[0] = outputLen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); pubkeyArray = (*env)->NewByteArray(env, outputLen); (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); intsByteArray = (*env)->NewByteArray(env, 2); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* tweak = (unsigned char*) (privkey + 32); jobjectArray retArray; jbyteArray privArray, intsByteArray; unsigned char intsarray[2]; int privkeylen = 32; int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); intsarray[0] = privkeylen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); privArray = (*env)->NewByteArray(env, privkeylen); (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); (*env)->SetObjectArrayElement(env, retArray, 0, privArray); intsByteArray = (*env)->NewByteArray(env, 2); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* tweak = (unsigned char*) (privkey + 32); jobjectArray retArray; jbyteArray privArray, intsByteArray; unsigned char intsarray[2]; int privkeylen = 32; int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); intsarray[0] = privkeylen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); privArray = (*env)->NewByteArray(env, privkeylen); (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); (*env)->SetObjectArrayElement(env, retArray, 0, privArray); intsByteArray = (*env)->NewByteArray(env, 2); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; /* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* tweak = (unsigned char*) (pkey + publen); jobjectArray retArray; jbyteArray pubArray, intsByteArray; unsigned char intsarray[2]; unsigned char outputSer[65]; size_t outputLen = 65; secp256k1_pubkey pubkey; int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); if( ret ) { ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); } if( ret ) { int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; } intsarray[0] = outputLen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); pubArray = (*env)->NewByteArray(env, outputLen); (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); intsByteArray = (*env)->NewByteArray(env, 2); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* tweak = (unsigned char*) (pkey + publen); jobjectArray retArray; jbyteArray pubArray, intsByteArray; unsigned char intsarray[2]; unsigned char outputSer[65]; size_t outputLen = 65; secp256k1_pubkey pubkey; int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); if ( ret ) { ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); } if( ret ) { int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; } intsarray[0] = outputLen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); pubArray = (*env)->NewByteArray(env, outputLen); (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); intsByteArray = (*env)->NewByteArray(env, 2); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) { (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; return 0; } SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* sigdata = { (unsigned char*) (data + 32) }; const unsigned char* pubdata = { (unsigned char*) (data + 32 + 64) }; secp256k1_pubkey pubkey; int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); if( ret ) { ret = secp256k1_schnorr_verify(ctx, sigdata, data, &pubkey); } (void)classObject; return ret; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char* secKey = (unsigned char*) (data + 32); jobjectArray retArray; jbyteArray sigArray, intsByteArray; unsigned char intsarray[1]; unsigned char sig[64]; intsarray[0] = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL); retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); sigArray = (*env)->NewByteArray(env, 64); (*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig); (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); intsByteArray = (*env)->NewByteArray(env, 1); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* pubdata = (const unsigned char*) (secdata + 32); jobjectArray retArray; jbyteArray outArray, intsByteArray; unsigned char intsarray[1]; secp256k1_pubkey pubkey; unsigned char nonce_res[32]; size_t outputLen = 32; int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); if (ret) { ret = secp256k1_ecdh( ctx, nonce_res, &pubkey, - secdata + secdata, + NULL, + NULL ); } intsarray[0] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); outArray = (*env)->NewByteArray(env, outputLen); (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); (*env)->SetObjectArrayElement(env, retArray, 0, outArray); intsByteArray = (*env)->NewByteArray(env, 1); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; return retArray; } diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h index df3ec5c85..44cb68e75 100644 --- a/src/secp256k1/src/modules/ecdh/main_impl.h +++ b/src/secp256k1/src/modules/ecdh/main_impl.h @@ -1,54 +1,67 @@ /********************************************************************** * Copyright (c) 2015 Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_MODULE_ECDH_MAIN_H #define SECP256K1_MODULE_ECDH_MAIN_H #include "include/secp256k1_ecdh.h" #include "ecmult_const_impl.h" -int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + unsigned char version = (y[31] & 0x01) | 0x02; + secp256k1_sha256 sha; + (void)data; + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &version, 1); + secp256k1_sha256_write(&sha, x, 32); + secp256k1_sha256_finalize(&sha, output); + + return 1; +} + +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) { int ret = 0; int overflow = 0; secp256k1_gej res; secp256k1_ge pt; secp256k1_scalar s; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(result != NULL); + ARG_CHECK(output != NULL); ARG_CHECK(point != NULL); ARG_CHECK(scalar != NULL); + if (hashfp == NULL) { + hashfp = secp256k1_ecdh_hash_function_default; + } secp256k1_pubkey_load(ctx, &pt, point); secp256k1_scalar_set_b32(&s, scalar, &overflow); if (overflow || secp256k1_scalar_is_zero(&s)) { ret = 0; } else { unsigned char x[32]; - unsigned char y[1]; - secp256k1_sha256 sha; + unsigned char y[32]; secp256k1_ecmult_const(&res, &pt, &s, 256); secp256k1_ge_set_gej(&pt, &res); - /* Compute a hash of the point in compressed form - * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not - * expect its output to be secret and has a timing sidechannel. */ + + /* Compute a hash of the point */ secp256k1_fe_normalize(&pt.x); secp256k1_fe_normalize(&pt.y); secp256k1_fe_get_b32(x, &pt.x); - y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + secp256k1_fe_get_b32(y, &pt.y); - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, y, sizeof(y)); - secp256k1_sha256_write(&sha, x, sizeof(x)); - secp256k1_sha256_finalize(&sha, result); - ret = 1; + ret = hashfp(output, x, y, data); } secp256k1_scalar_clear(&s); return ret; } #endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h index 0c53f8ee0..fe26e8fb6 100644 --- a/src/secp256k1/src/modules/ecdh/tests_impl.h +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -1,105 +1,132 @@ /********************************************************************** * Copyright (c) 2015 Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_MODULE_ECDH_TESTS_H #define SECP256K1_MODULE_ECDH_TESTS_H +int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)output; + (void)x; + (void)y; + (void)data; + return 0; +} + +int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)data; + /* Save x and y as uncompressed public key */ + output[0] = 0x04; + memcpy(output + 1, x, 32); + memcpy(output + 33, y, 32); + return 1; +} + void test_ecdh_api(void) { /* Setup context that just counts errors */ secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); secp256k1_pubkey point; unsigned char res[32]; unsigned char s_one[32] = { 0 }; int32_t ecount = 0; s_one[31] = 1; secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); /* Check all NULLs are detected */ - CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); + CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); CHECK(ecount == 0); - CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0); + CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0); CHECK(ecount == 1); - CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0); + CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0); + CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0); CHECK(ecount == 3); - CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); + CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); CHECK(ecount == 3); /* Cleanup */ secp256k1_context_destroy(tctx); } void test_ecdh_generator_basepoint(void) { unsigned char s_one[32] = { 0 }; secp256k1_pubkey point[2]; int i; s_one[31] = 1; /* Check against pubkey creation when the basepoint is the generator */ for (i = 0; i < 100; ++i) { secp256k1_sha256 sha; unsigned char s_b32[32]; - unsigned char output_ecdh[32]; + unsigned char output_ecdh[65]; unsigned char output_ser[32]; - unsigned char point_ser[33]; + unsigned char point_ser[65]; size_t point_ser_len = sizeof(point_ser); secp256k1_scalar s; random_scalar_order(&s); secp256k1_scalar_get_b32(s_b32, &s); - /* compute using ECDH function */ CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); - CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); - /* compute "explicitly" */ CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + + /* compute using ECDH function with custom hash function */ + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + /* compare */ + CHECK(memcmp(output_ecdh, point_ser, 65) == 0); + + /* compute using ECDH function with default hash function */ + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); + /* compute "explicitly" */ CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); - CHECK(point_ser_len == sizeof(point_ser)); secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_finalize(&sha, output_ser); /* compare */ - CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + CHECK(memcmp(output_ecdh, output_ser, 32) == 0); } } void test_bad_scalar(void) { unsigned char s_zero[32] = { 0 }; unsigned char s_overflow[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 }; unsigned char s_rand[32] = { 0 }; unsigned char output[32]; secp256k1_scalar rand; secp256k1_pubkey point; /* Create random point */ random_scalar_order(&rand); secp256k1_scalar_get_b32(s_rand, &rand); CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); /* Try to multiply it by bad values */ - CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0); /* ...and a good one */ s_overflow[31] -= 1; - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1); + + /* Hash function failure results in ecdh failure */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); } void run_ecdh_tests(void) { test_ecdh_api(); test_ecdh_generator_basepoint(); test_bad_scalar(); } #endif /* SECP256K1_MODULE_ECDH_TESTS_H */