diff --git a/.travis.yml b/.travis.yml index df4136ecd..692882de2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,27 +17,27 @@ compiler: - gcc env: global: - - WIDEMUL=auto BIGNUM=auto STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check WITH_VALGRIND=yes RUN_VALGRIND=no EXTRAFLAGS= HOST= ECDH=no RECOVERY=no ECDSA_S2C=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 GENERATOR=no RANGEPROOF=no WHITELIST=no SCHNORRSIG=no MUSIG=no + - WIDEMUL=auto BIGNUM=auto STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check WITH_VALGRIND=yes RUN_VALGRIND=no EXTRAFLAGS= HOST= ECDH=no RECOVERY=no ECDSA_S2C=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 GENERATOR=no RANGEPROOF=no WHITELIST=no SCHNORRSIG=no MUSIG=no ECDSAADAPTOR=no matrix: - - WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes - - WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes + - WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes + - WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes - WIDEMUL=int64 RECOVERY=yes - - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes + - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes - WIDEMUL=int128 - - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes - - WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes + - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes + - WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes - WIDEMUL=int128 ASM=x86_64 - BIGNUM=no - BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes - - BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes + - BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no - CPPFLAGS=-DDETERMINISTIC - CFLAGS=-O0 CTIMETEST=no - - CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no + - CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no ECDSAADAPTOR=yes - ECMULTGENPRECISION=2 - ECMULTGENPRECISION=8 - - RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD= + - RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes EXTRAFLAGS="--disable-openssl-tests" BUILD= matrix: fast_finish: true include: @@ -85,7 +85,7 @@ matrix: - libc6-dbg:i386 # S390x build (big endian system) - compiler: gcc - env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST= + env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes ECDSAADAPTOR=yes CTIMETEST= arch: s390x # We use this to install macOS dependencies instead of the built in `homebrew` plugin, diff --git a/contrib/travis.sh b/contrib/travis.sh index fb3e4d0cd..fa4ef1c7b 100755 --- a/contrib/travis.sh +++ b/contrib/travis.sh @@ -19,7 +19,7 @@ fi --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-ecdsa-s2c="$ECDSA_S2C" \ --enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \ - --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG"\ + --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \ --with-valgrind="$WITH_VALGRIND" \ --host="$HOST" $EXTRAFLAGS diff --git a/src/modules/ecdsa_adaptor/Makefile.am.include b/src/modules/ecdsa_adaptor/Makefile.am.include index d48d028c9..e855a17a3 100644 --- a/src/modules/ecdsa_adaptor/Makefile.am.include +++ b/src/modules/ecdsa_adaptor/Makefile.am.include @@ -1,3 +1,4 @@ include_HEADERS += include/secp256k1_ecdsa_adaptor.h noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h noinst_HEADERS += src/modules/ecdsa_adaptor/dleq_impl.h +noinst_HEADERS += src/modules/ecdsa_adaptor/tests_impl.h diff --git a/src/modules/ecdsa_adaptor/tests_impl.h b/src/modules/ecdsa_adaptor/tests_impl.h new file mode 100644 index 000000000..61c4ab7d8 --- /dev/null +++ b/src/modules/ecdsa_adaptor/tests_impl.h @@ -0,0 +1,734 @@ +#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H +#define SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H + +#include "include/secp256k1_ecdsa_adaptor.h" + +void rand_scalar(secp256k1_scalar *scalar) { + unsigned char buf32[32]; + secp256k1_testrand256(buf32); + secp256k1_scalar_set_b32(scalar, buf32, NULL); +} + +void rand_point(secp256k1_ge *point) { + secp256k1_scalar x; + secp256k1_gej pointj; + rand_scalar(&x); + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pointj, &x); + secp256k1_ge_set_gej(point, &pointj); +} + +void dleq_tests(void) { + secp256k1_scalar s, e; + unsigned char algo32[32] = { 0 }; + secp256k1_scalar sk; + secp256k1_ge gen2; + secp256k1_ge p1, p2; + + rand_point(&gen2); + rand_scalar(&sk); + secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &p1, &p2, &sk, &gen2); + CHECK(secp256k1_dleq_prove(ctx, &s, &e, algo32, &sk, &gen2, &p1, &p2, NULL, NULL) == 1); + CHECK(secp256k1_dleq_verify(&ctx->ecmult_ctx, &s, &e, &p1, &gen2, &p2) == 1); + + { + secp256k1_scalar tmp; + secp256k1_scalar_set_int(&tmp, 1); + CHECK(secp256k1_dleq_verify(&ctx->ecmult_ctx, &tmp, &e, &p1, &gen2, &p2) == 0); + CHECK(secp256k1_dleq_verify(&ctx->ecmult_ctx, &s, &tmp, &p1, &gen2, &p2) == 0); + } + { + secp256k1_ge p_tmp; + rand_point(&p_tmp); + CHECK(secp256k1_dleq_verify(&ctx->ecmult_ctx, &s, &e, &p_tmp, &gen2, &p2) == 0); + CHECK(secp256k1_dleq_verify(&ctx->ecmult_ctx, &s, &e, &p1, &p_tmp, &p2) == 0); + CHECK(secp256k1_dleq_verify(&ctx->ecmult_ctx, &s, &e, &p1, &gen2, &p_tmp) == 0); + } +} + +void rand_flip_bit(unsigned char *array, size_t n) { + array[secp256k1_testrand_int(n)] ^= 1 << secp256k1_testrand_int(8); +} + +/* Helper function for test_ecdsa_adaptor_spec_vectors + * Checks that the adaptor signature is valid for the public and encryption keys. */ +void test_ecdsa_adaptor_spec_vectors_check_verify(const unsigned char *adaptor_sig162, const unsigned char *msg32, const unsigned char *pubkey33, const unsigned char *encryption_key33, int expected) { + secp256k1_pubkey pubkey; + secp256k1_ge pubkey_ge; + secp256k1_pubkey encryption_key; + secp256k1_ge encryption_key_ge; + + CHECK(secp256k1_eckey_pubkey_parse(&encryption_key_ge, encryption_key33, 33) == 1); + secp256k1_pubkey_save(&encryption_key, &encryption_key_ge); + CHECK(secp256k1_eckey_pubkey_parse(&pubkey_ge, pubkey33, 33) == 1); + secp256k1_pubkey_save(&pubkey, &pubkey_ge); + + CHECK(expected == secp256k1_ecdsa_adaptor_sig_verify(ctx, adaptor_sig162, &pubkey, msg32, &encryption_key)); +} + +/* Helper function for test_ecdsa_adaptor_spec_vectors + * Checks that the signature can be decrypted from the adaptor signature and the decryption key. */ +void test_ecdsa_adaptor_spec_vectors_check_decrypt(const unsigned char *adaptor_sig162, const unsigned char *decryption_key32, const unsigned char *signature64, int expected) { + unsigned char signature[64]; + secp256k1_ecdsa_signature s; + + CHECK(secp256k1_ecdsa_adaptor_decrypt(ctx, &s, decryption_key32, adaptor_sig162) == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &s) == 1); + + CHECK(expected == !(secp256k1_memcmp_var(signature, signature64, 64) & 1)); +} + +/* Helper function for test_ecdsa_adaptor_spec_vectors + * Checks that the decryption key can be recovered from the adaptor signature, encryption key, and the signature. */ +void test_ecdsa_adaptor_spec_vectors_check_recover(const unsigned char *adaptor_sig162, const unsigned char *encryption_key33, const unsigned char *decryption_key32, const unsigned char *signature64, int expected) { + unsigned char deckey32[32] = { 0 }; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey encryption_key; + secp256k1_ge encryption_key_ge; + + CHECK(secp256k1_eckey_pubkey_parse(&encryption_key_ge, encryption_key33, 33) == 1); + secp256k1_pubkey_save(&encryption_key, &encryption_key_ge); + + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature64) == 1); + CHECK(expected == secp256k1_ecdsa_adaptor_recover(ctx, deckey32, &sig, adaptor_sig162, &encryption_key)); + if (decryption_key32 != NULL) { + CHECK(expected == !secp256k1_memcmp_var(deckey32, decryption_key32, 32)); + } +} + +/* Test vectors according to ECDSA adaptor signature spec. See + * https://github.com/discreetlogcontracts/dlcspecs/blob/596a177375932a47306f07e7385f398f52519a83/test/ecdsa_adaptor.json. */ +void test_ecdsa_adaptor_spec_vectors(void) { + { + /* Test vector 0 */ + const unsigned char adaptor_sig[162] = { + 0x03, 0x42, 0x4d, 0x14, 0xa5, 0x47, 0x1c, 0x04, + 0x8a, 0xb8, 0x7b, 0x3b, 0x83, 0xf6, 0x08, 0x5d, + 0x12, 0x5d, 0x58, 0x64, 0x24, 0x9a, 0xe4, 0x29, + 0x7a, 0x57, 0xc8, 0x4e, 0x74, 0x71, 0x0b, 0xb6, + 0x73, 0x02, 0x23, 0xf3, 0x25, 0x04, 0x2f, 0xce, + 0x53, 0x5d, 0x04, 0x0f, 0xee, 0x52, 0xec, 0x13, + 0x23, 0x1b, 0xf7, 0x09, 0xcc, 0xd8, 0x42, 0x33, + 0xc6, 0x94, 0x4b, 0x90, 0x31, 0x7e, 0x62, 0x52, + 0x8b, 0x25, 0x27, 0xdf, 0xf9, 0xd6, 0x59, 0xa9, + 0x6d, 0xb4, 0xc9, 0x9f, 0x97, 0x50, 0x16, 0x83, + 0x08, 0x63, 0x3c, 0x18, 0x67, 0xb7, 0x0f, 0x3a, + 0x18, 0xfb, 0x0f, 0x45, 0x39, 0xa1, 0xae, 0xce, + 0xdc, 0xd1, 0xfc, 0x01, 0x48, 0xfc, 0x22, 0xf3, + 0x6b, 0x63, 0x03, 0x08, 0x3e, 0xce, 0x3f, 0x87, + 0x2b, 0x18, 0xe3, 0x5d, 0x36, 0x8b, 0x39, 0x58, + 0xef, 0xe5, 0xfb, 0x08, 0x1f, 0x77, 0x16, 0x73, + 0x6c, 0xcb, 0x59, 0x8d, 0x26, 0x9a, 0xa3, 0x08, + 0x4d, 0x57, 0xe1, 0x85, 0x5e, 0x1e, 0xa9, 0xa4, + 0x5e, 0xfc, 0x10, 0x46, 0x3b, 0xbf, 0x32, 0xae, + 0x37, 0x80, 0x29, 0xf5, 0x76, 0x3c, 0xeb, 0x40, + 0x17, 0x3f + }; + const unsigned char message_hash[32] = { + 0x81, 0x31, 0xe6, 0xf4, 0xb4, 0x57, 0x54, 0xf2, + 0xc9, 0x0b, 0xd0, 0x66, 0x88, 0xce, 0xea, 0xbc, + 0x0c, 0x45, 0x05, 0x54, 0x60, 0x72, 0x99, 0x28, + 0xb4, 0xee, 0xcf, 0x11, 0x02, 0x6a, 0x9e, 0x2d + }; + const unsigned char pubkey[33] = { + 0x03, 0x5b, 0xe5, 0xe9, 0x47, 0x82, 0x09, 0x67, + 0x4a, 0x96, 0xe6, 0x0f, 0x1f, 0x03, 0x7f, 0x61, + 0x76, 0x54, 0x0f, 0xd0, 0x01, 0xfa, 0x1d, 0x64, + 0x69, 0x47, 0x70, 0xc5, 0x6a, 0x77, 0x09, 0xc4, + 0x2c + }; + const unsigned char encryption_key[33] = { + 0x02, 0xc2, 0x66, 0x2c, 0x97, 0x48, 0x8b, 0x07, + 0xb6, 0xe8, 0x19, 0x12, 0x4b, 0x89, 0x89, 0x84, + 0x92, 0x06, 0x33, 0x4a, 0x4c, 0x2f, 0xbd, 0xf6, + 0x91, 0xf7, 0xb3, 0x4d, 0x2b, 0x16, 0xe9, 0xc2, + 0x93 + }; + const unsigned char decryption_key[32] = { + 0x0b, 0x2a, 0xba, 0x63, 0xb8, 0x85, 0xa0, 0xf0, + 0xe9, 0x6f, 0xa0, 0xf3, 0x03, 0x92, 0x0c, 0x7f, + 0xb7, 0x43, 0x1d, 0xdf, 0xa9, 0x43, 0x76, 0xad, + 0x94, 0xd9, 0x69, 0xfb, 0xf4, 0x10, 0x9d, 0xc8 + }; + const unsigned char signature[64] = { + 0x42, 0x4d, 0x14, 0xa5, 0x47, 0x1c, 0x04, 0x8a, + 0xb8, 0x7b, 0x3b, 0x83, 0xf6, 0x08, 0x5d, 0x12, + 0x5d, 0x58, 0x64, 0x24, 0x9a, 0xe4, 0x29, 0x7a, + 0x57, 0xc8, 0x4e, 0x74, 0x71, 0x0b, 0xb6, 0x73, + 0x29, 0xe8, 0x0e, 0x0e, 0xe6, 0x0e, 0x57, 0xaf, + 0x3e, 0x62, 0x5b, 0xba, 0xe1, 0x67, 0x2b, 0x1e, + 0xca, 0xa5, 0x8e, 0xff, 0xe6, 0x13, 0x42, 0x6b, + 0x02, 0x4f, 0xa1, 0x62, 0x1d, 0x90, 0x33, 0x94 + }; + test_ecdsa_adaptor_spec_vectors_check_verify(adaptor_sig, message_hash, pubkey, encryption_key, 1); + test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 1); + test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); + } + { + /* Test vector 1 */ + const unsigned char adaptor_sig[162] = { + 0x03, 0x60, 0x35, 0xc8, 0x98, 0x60, 0xec, 0x62, + 0xad, 0x15, 0x3f, 0x69, 0xb5, 0xb3, 0x07, 0x7b, + 0xcd, 0x08, 0xfb, 0xb0, 0xd2, 0x8d, 0xc7, 0xf7, + 0xf6, 0xdf, 0x4a, 0x05, 0xcc, 0xa3, 0x54, 0x55, + 0xbe, 0x03, 0x70, 0x43, 0xb6, 0x3c, 0x56, 0xf6, + 0x31, 0x7d, 0x99, 0x28, 0xe8, 0xf9, 0x10, 0x07, + 0x33, 0x57, 0x48, 0xc4, 0x98, 0x24, 0x22, 0x0d, + 0xb1, 0x4a, 0xd1, 0x0d, 0x80, 0xa5, 0xd0, 0x0a, + 0x96, 0x54, 0xaf, 0x09, 0x96, 0xc1, 0x82, 0x4c, + 0x64, 0xc9, 0x0b, 0x95, 0x1b, 0xb2, 0x73, 0x4a, + 0xae, 0xcf, 0x78, 0xd4, 0xb3, 0x61, 0x31, 0xa4, + 0x72, 0x38, 0xc3, 0xfa, 0x2b, 0xa2, 0x5e, 0x2c, + 0xed, 0x54, 0x25, 0x5b, 0x06, 0xdf, 0x69, 0x6d, + 0xe1, 0x48, 0x3c, 0x37, 0x67, 0x24, 0x2a, 0x37, + 0x28, 0x82, 0x6e, 0x05, 0xf7, 0x9e, 0x39, 0x81, + 0xe1, 0x25, 0x53, 0x35, 0x5b, 0xba, 0x8a, 0x01, + 0x31, 0xcd, 0x37, 0x0e, 0x63, 0xe3, 0xda, 0x73, + 0x10, 0x6f, 0x63, 0x85, 0x76, 0xa5, 0xaa, 0xb0, + 0xea, 0x6d, 0x45, 0xc0, 0x42, 0x57, 0x4c, 0x0c, + 0x8d, 0x0b, 0x14, 0xb8, 0xc7, 0xc0, 0x1c, 0xfe, + 0x90, 0x72 + }; + const unsigned char message_hash[32] = { + 0x81, 0x31, 0xe6, 0xf4, 0xb4, 0x57, 0x54, 0xf2, + 0xc9, 0x0b, 0xd0, 0x66, 0x88, 0xce, 0xea, 0xbc, + 0x0c, 0x45, 0x05, 0x54, 0x60, 0x72, 0x99, 0x28, + 0xb4, 0xee, 0xcf, 0x11, 0x02, 0x6a, 0x9e, 0x2d + }; + const unsigned char pubkey[33] = { + 0x03, 0x5b, 0xe5, 0xe9, 0x47, 0x82, 0x09, 0x67, + 0x4a, 0x96, 0xe6, 0x0f, 0x1f, 0x03, 0x7f, 0x61, + 0x76, 0x54, 0x0f, 0xd0, 0x01, 0xfa, 0x1d, 0x64, + 0x69, 0x47, 0x70, 0xc5, 0x6a, 0x77, 0x09, 0xc4, + 0x2c + }; + const unsigned char encryption_key[33] = { + 0x02, 0x4e, 0xee, 0x18, 0xbe, 0x9a, 0x5a, 0x52, + 0x24, 0x00, 0x0f, 0x91, 0x6c, 0x80, 0xb3, 0x93, + 0x44, 0x79, 0x89, 0xe7, 0x19, 0x4b, 0xc0, 0xb0, + 0xf1, 0xad, 0x7a, 0x03, 0x36, 0x97, 0x02, 0xbb, + 0x51 + }; + const unsigned char decryption_key[32] = { + 0xdb, 0x2d, 0xeb, 0xdd, 0xb0, 0x02, 0x47, 0x3a, + 0x00, 0x1d, 0xd7, 0x0b, 0x06, 0xf6, 0xc9, 0x7b, + 0xdc, 0xd1, 0xc4, 0x6b, 0xa1, 0x00, 0x12, 0x37, + 0xfe, 0x0e, 0xe1, 0xae, 0xff, 0xb2, 0xb6, 0xc4 + }; + const unsigned char signature[64] = { + 0x60, 0x35, 0xc8, 0x98, 0x60, 0xec, 0x62, 0xad, + 0x15, 0x3f, 0x69, 0xb5, 0xb3, 0x07, 0x7b, 0xcd, + 0x08, 0xfb, 0xb0, 0xd2, 0x8d, 0xc7, 0xf7, 0xf6, + 0xdf, 0x4a, 0x05, 0xcc, 0xa3, 0x54, 0x55, 0xbe, + 0x4c, 0xea, 0xcf, 0x92, 0x15, 0x46, 0xc0, 0x3d, + 0xd1, 0xbe, 0x59, 0x67, 0x23, 0xad, 0x1e, 0x76, + 0x91, 0xbd, 0xac, 0x73, 0xd8, 0x8c, 0xc3, 0x6c, + 0x42, 0x1c, 0x5e, 0x7f, 0x08, 0x38, 0x43, 0x05 + }; + test_ecdsa_adaptor_spec_vectors_check_verify(adaptor_sig, message_hash, pubkey, encryption_key, 1); + test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 1); + test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); + } + { + /* Test vector 2 */ + const unsigned char adaptor_sig[162] = { + 0x03, 0xf9, 0x4d, 0xca, 0x20, 0x6d, 0x75, 0x82, + 0xc0, 0x15, 0xfb, 0x9b, 0xff, 0xe4, 0xe4, 0x3b, + 0x14, 0x59, 0x1b, 0x30, 0xef, 0x7d, 0x2b, 0x46, + 0x4d, 0x10, 0x3e, 0xc5, 0xe1, 0x16, 0x59, 0x5d, + 0xba, 0x03, 0x12, 0x7f, 0x8a, 0xc3, 0x53, 0x3d, + 0x24, 0x92, 0x80, 0x33, 0x24, 0x74, 0x33, 0x90, + 0x00, 0x92, 0x2e, 0xb6, 0xa5, 0x8e, 0x3b, 0x9b, + 0xf4, 0xfc, 0x7e, 0x01, 0xe4, 0xb4, 0xdf, 0x2b, + 0x7a, 0x41, 0x00, 0xa1, 0xe0, 0x89, 0xf1, 0x6e, + 0x5d, 0x70, 0xbb, 0x89, 0xf9, 0x61, 0x51, 0x6f, + 0x1d, 0xe0, 0x68, 0x4c, 0xc7, 0x9d, 0xb9, 0x78, + 0x49, 0x5d, 0xf2, 0xf3, 0x99, 0xb0, 0xd0, 0x1e, + 0xd7, 0x24, 0x0f, 0xa6, 0xe3, 0x25, 0x2a, 0xed, + 0xb5, 0x8b, 0xdc, 0x6b, 0x58, 0x77, 0xb0, 0xc6, + 0x02, 0x62, 0x8a, 0x23, 0x5d, 0xd1, 0xcc, 0xae, + 0xbd, 0xdd, 0xcb, 0xe9, 0x61, 0x98, 0xc0, 0xc2, + 0x1b, 0xea, 0xd7, 0xb0, 0x5f, 0x42, 0x3b, 0x67, + 0x3d, 0x14, 0xd2, 0x06, 0xfa, 0x15, 0x07, 0xb2, + 0xdb, 0xe2, 0x72, 0x2a, 0xf7, 0x92, 0xb8, 0xc2, + 0x66, 0xfc, 0x25, 0xa2, 0xd9, 0x01, 0xd7, 0xe2, + 0xc3, 0x35 + }; + const unsigned char message_hash[32] = { + 0x81, 0x31, 0xe6, 0xf4, 0xb4, 0x57, 0x54, 0xf2, + 0xc9, 0x0b, 0xd0, 0x66, 0x88, 0xce, 0xea, 0xbc, + 0x0c, 0x45, 0x05, 0x54, 0x60, 0x72, 0x99, 0x28, + 0xb4, 0xee, 0xcf, 0x11, 0x02, 0x6a, 0x9e, 0x2d + }; + const unsigned char pubkey[33] = { + 0x03, 0x5b, 0xe5, 0xe9, 0x47, 0x82, 0x09, 0x67, + 0x4a, 0x96, 0xe6, 0x0f, 0x1f, 0x03, 0x7f, 0x61, + 0x76, 0x54, 0x0f, 0xd0, 0x01, 0xfa, 0x1d, 0x64, + 0x69, 0x47, 0x70, 0xc5, 0x6a, 0x77, 0x09, 0xc4, + 0x2c + }; + const unsigned char encryption_key[33] = { + 0x02, 0x14, 0xcc, 0xb7, 0x56, 0x24, 0x9a, 0xd6, + 0xe7, 0x33, 0xc8, 0x02, 0x85, 0xea, 0x7a, 0xc2, + 0xee, 0x12, 0xff, 0xeb, 0xbc, 0xee, 0x4e, 0x55, + 0x6e, 0x68, 0x10, 0x79, 0x3a, 0x60, 0xc4, 0x5a, + 0xd4 + }; + const unsigned char decryption_key[32] = { + 0x1d, 0xfc, 0xfc, 0x08, 0x80, 0xe7, 0x25, 0x09, + 0x76, 0x8a, 0xb4, 0x6f, 0x25, 0x45, 0xb3, 0x31, + 0x68, 0xb8, 0xb8, 0xdf, 0x8e, 0x4f, 0x5f, 0xeb, + 0x50, 0x59, 0xaa, 0x37, 0x50, 0xee, 0x59, 0xd0 + }; + const unsigned char signature[64] = { + 0x42, 0x4d, 0x14, 0xa5, 0x47, 0x1c, 0x04, 0x8a, + 0xb8, 0x7b, 0x3b, 0x83, 0xf6, 0x08, 0x5d, 0x12, + 0x5d, 0x58, 0x64, 0x24, 0x9a, 0xe4, 0x29, 0x7a, + 0x57, 0xc8, 0x4e, 0x74, 0x71, 0x0b, 0xb6, 0x73, + 0x29, 0xe8, 0x0e, 0x0e, 0xe6, 0x0e, 0x57, 0xaf, + 0x3e, 0x62, 0x5b, 0xba, 0xe1, 0x67, 0x2b, 0x1e, + 0xca, 0xa5, 0x8e, 0xff, 0xe6, 0x13, 0x42, 0x6b, + 0x02, 0x4f, 0xa1, 0x62, 0x1d, 0x90, 0x33, 0x94 + }; + test_ecdsa_adaptor_spec_vectors_check_verify(adaptor_sig, message_hash, pubkey, encryption_key, 0); + test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 0); + test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 0); + } + { + /* Test vector 3 */ + const unsigned char adaptor_sig[162] = { + 0x03, 0xf2, 0xdb, 0x6e, 0x9e, 0xd3, 0x30, 0x92, + 0xcc, 0x0b, 0x89, 0x8f, 0xd6, 0xb2, 0x82, 0xe9, + 0x9b, 0xda, 0xec, 0xcb, 0x3d, 0xe8, 0x5c, 0x2d, + 0x25, 0x12, 0xd8, 0xd5, 0x07, 0xf9, 0xab, 0xab, + 0x29, 0x02, 0x10, 0xc0, 0x1b, 0x5b, 0xed, 0x70, + 0x94, 0xa1, 0x26, 0x64, 0xae, 0xaa, 0xb3, 0x40, + 0x2d, 0x87, 0x09, 0xa8, 0xf3, 0x62, 0xb1, 0x40, + 0x32, 0x8d, 0x1b, 0x36, 0xdd, 0x7c, 0xb4, 0x20, + 0xd0, 0x2f, 0xb6, 0x6b, 0x12, 0x30, 0xd6, 0x1c, + 0x16, 0xd0, 0xcd, 0x0a, 0x2a, 0x02, 0x24, 0x6d, + 0x5a, 0xc7, 0x84, 0x8d, 0xcd, 0x6f, 0x04, 0xfe, + 0x62, 0x70, 0x53, 0xcd, 0x3c, 0x70, 0x15, 0xa7, + 0xd4, 0xaa, 0x6a, 0xc2, 0xb0, 0x43, 0x47, 0x34, + 0x8b, 0xd6, 0x7d, 0xa4, 0x3b, 0xe8, 0x72, 0x25, + 0x15, 0xd9, 0x9a, 0x79, 0x85, 0xfb, 0xfa, 0x66, + 0xf0, 0x36, 0x5c, 0x70, 0x1d, 0xe7, 0x6f, 0xf0, + 0x40, 0x0d, 0xff, 0xdc, 0x9f, 0xa8, 0x4d, 0xdd, + 0xf4, 0x13, 0xa7, 0x29, 0x82, 0x3b, 0x16, 0xaf, + 0x60, 0xaa, 0x63, 0x61, 0xbc, 0x32, 0xe7, 0xcf, + 0xd6, 0x70, 0x1e, 0x32, 0x95, 0x7c, 0x72, 0xac, + 0xe6, 0x7b + }; + const unsigned char encryption_key[33] = { + 0x02, 0x7e, 0xe4, 0xf8, 0x99, 0xbc, 0x9c, 0x5f, + 0x2b, 0x62, 0x6f, 0xa1, 0xa9, 0xb3, 0x7c, 0xe2, + 0x91, 0xc0, 0x38, 0x8b, 0x52, 0x27, 0xe9, 0x0b, + 0x0f, 0xd8, 0xf4, 0xfa, 0x57, 0x61, 0x64, 0xed, + 0xe7 + }; + const unsigned char decryption_key[32] = { + 0x9c, 0xf3, 0xea, 0x9b, 0xe5, 0x94, 0x36, 0x6b, + 0x78, 0xc4, 0x57, 0x16, 0x29, 0x08, 0xaf, 0x3c, + 0x2e, 0xa1, 0x77, 0x05, 0x81, 0x77, 0xe9, 0xc6, + 0xbf, 0x99, 0x04, 0x79, 0x27, 0x77, 0x3a, 0x06 + }; + const unsigned char signature[64] = { + 0xf2, 0xdb, 0x6e, 0x9e, 0xd3, 0x30, 0x92, 0xcc, + 0x0b, 0x89, 0x8f, 0xd6, 0xb2, 0x82, 0xe9, 0x9b, + 0xda, 0xec, 0xcb, 0x3d, 0xe8, 0x5c, 0x2d, 0x25, + 0x12, 0xd8, 0xd5, 0x07, 0xf9, 0xab, 0xab, 0x29, + 0x21, 0x81, 0x1f, 0xe7, 0xb5, 0x3b, 0xec, 0xf3, + 0xb7, 0xaf, 0xfa, 0x94, 0x42, 0xab, 0xaa, 0x93, + 0xc0, 0xab, 0x8a, 0x8e, 0x45, 0xcd, 0x7e, 0xe2, + 0xea, 0x8d, 0x25, 0x8b, 0xfc, 0x25, 0xd4, 0x64 + }; + test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 1); + test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); + } + { + /* Test vector 5 */ + const unsigned char adaptor_sig[162] = { + 0x03, 0xaa, 0x86, 0xd7, 0x80, 0x59, 0xa9, 0x10, + 0x59, 0xc2, 0x9e, 0xc1, 0xa7, 0x57, 0xc4, 0xdc, + 0x02, 0x9f, 0xf6, 0x36, 0xa1, 0xe6, 0xc1, 0x14, + 0x2f, 0xef, 0xe1, 0xe9, 0xd7, 0x33, 0x96, 0x17, + 0xc0, 0x03, 0xa8, 0x15, 0x3e, 0x50, 0xc0, 0xc8, + 0x57, 0x4a, 0x38, 0xd3, 0x89, 0xe6, 0x1b, 0xbb, + 0x0b, 0x58, 0x15, 0x16, 0x9e, 0x06, 0x09, 0x24, + 0xe4, 0xb5, 0xf2, 0xe7, 0x8f, 0xf1, 0x3a, 0xa7, + 0xad, 0x85, 0x8e, 0x0c, 0x27, 0xc4, 0xb9, 0xee, + 0xd9, 0xd6, 0x05, 0x21, 0xb3, 0xf5, 0x4f, 0xf8, + 0x3c, 0xa4, 0x77, 0x4b, 0xe5, 0xfb, 0x3a, 0x68, + 0x0f, 0x82, 0x0a, 0x35, 0xe8, 0x84, 0x0f, 0x4a, + 0xaf, 0x2d, 0xe8, 0x8e, 0x7c, 0x5c, 0xff, 0x38, + 0xa3, 0x7b, 0x78, 0x72, 0x59, 0x04, 0xef, 0x97, + 0xbb, 0x82, 0x34, 0x13, 0x28, 0xd5, 0x59, 0x87, + 0x01, 0x9b, 0xd3, 0x8a, 0xe1, 0x74, 0x5e, 0x3e, + 0xfe, 0x0f, 0x8e, 0xa8, 0xbd, 0xfe, 0xde, 0x0d, + 0x37, 0x8f, 0xc1, 0xf9, 0x6e, 0x94, 0x4a, 0x75, + 0x05, 0x24, 0x9f, 0x41, 0xe9, 0x37, 0x81, 0x50, + 0x9e, 0xe0, 0xba, 0xde, 0x77, 0x29, 0x0d, 0x39, + 0xcd, 0x12 + }; + const unsigned char encryption_key[33] = { + 0x03, 0x51, 0x76, 0xd2, 0x41, 0x29, 0x74, 0x1b, + 0x0f, 0xca, 0xa5, 0xfd, 0x67, 0x50, 0x72, 0x7c, + 0xe3, 0x08, 0x60, 0x44, 0x7e, 0x0a, 0x92, 0xc9, + 0xeb, 0xeb, 0xde, 0xb7, 0xc3, 0xf9, 0x39, 0x95, + 0xed + }; + const unsigned char signature[64] = { + 0xf7, 0xf7, 0xfe, 0x6b, 0xd0, 0x56, 0xfc, 0x4a, + 0xbd, 0x70, 0xd3, 0x35, 0xf7, 0x2d, 0x0a, 0xa1, + 0xe8, 0x40, 0x6b, 0xba, 0x68, 0xf3, 0xe5, 0x79, + 0xe4, 0x78, 0x94, 0x75, 0x32, 0x35, 0x64, 0xa4, + 0x52, 0xc4, 0x61, 0x76, 0xc7, 0xfb, 0x40, 0xaa, + 0x37, 0xd5, 0x65, 0x13, 0x41, 0xf5, 0x56, 0x97, + 0xda, 0xb2, 0x7d, 0x84, 0xa2, 0x13, 0xb3, 0x0c, + 0x93, 0x01, 0x1a, 0x77, 0x90, 0xba, 0xce, 0x8c + }; + test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, NULL, signature, 0); + } +} + +/* Nonce function that returns constant 0 */ +static int ecdsa_adaptor_nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *encryption_key33, const unsigned char *algo16, void *data) { + (void) msg32; + (void) key32; + (void) encryption_key33; + (void) algo16; + (void) data; + (void) nonce32; + return 0; +} + +/* Nonce function that sets nonce to 0 */ +static int ecdsa_adaptor_nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *encryption_key33, const unsigned char *algo16, void *data) { + (void) msg32; + (void) key32; + (void) encryption_key33; + (void) algo16; + (void) data; + + memset(nonce32, 0, 32); + return 1; +} + +/* Nonce function that sets nonce to 0xFF...0xFF */ +static int ecdsa_adaptor_nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *encryption_key33, const unsigned char *algo16, void *data) { + (void) msg32; + (void) key32; + (void) encryption_key33; + (void) algo16; + (void) data; + + memset(nonce32, 0xFF, 32); + return 1; +} + +/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many + * bytes) changes the hash function + */ +void nonce_function_ecdsa_adaptor_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { + unsigned char nonces[2][32]; + CHECK(nonce_function_ecdsa_adaptor(nonces[0], args[0], args[1], args[2], args[3], args[4]) == 1); + secp256k1_testrand_flip(args[n_flip], n_bytes); + CHECK(nonce_function_ecdsa_adaptor(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1); + CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0); +} + +/* Tests for the equality of two sha256 structs. This function only produces a + * correct result if an integer multiple of 64 many bytes have been written + * into the hash functions. */ +void ecdsa_adaptor_test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { + /* Is buffer fully consumed? */ + CHECK((sha1->bytes & 0x3F) == 0); + + CHECK(sha1->bytes == sha2->bytes); + CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); +} + +void run_nonce_function_ecdsa_adaptor_tests(void) { + unsigned char tag[16] = "ECDSAadaptor/non"; + unsigned char aux_tag[16] = "ECDSAadaptor/aux"; + unsigned char algo16[16] = "ECDSAadaptor/non"; + unsigned char dleq_tag[4] = "DLEQ"; + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + unsigned char nonce[32]; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char pk[33]; + unsigned char aux_rand[32]; + unsigned char *args[5]; + int i; + + /* Check that hash initialized by + * secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag)); + secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(&sha_optimized); + ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); + secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha_optimized); + ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_nonce_function_dleq_sha256_tagged_aux has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, dleq_tag, sizeof(dleq_tag)); + secp256k1_nonce_function_dleq_sha256_tagged(&sha_optimized); + ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized); + + secp256k1_testrand256(msg); + secp256k1_testrand256(key); + secp256k1_testrand256(pk); + secp256k1_testrand256(aux_rand); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = msg; + args[1] = key; + args[2] = pk; + args[3] = algo16; + args[4] = aux_rand; + for (i = 0; i < count; i++) { + nonce_function_ecdsa_adaptor_bitflip(args, 0, 32); + nonce_function_ecdsa_adaptor_bitflip(args, 1, 32); + nonce_function_ecdsa_adaptor_bitflip(args, 2, 32); + /* Flip algo16 special case "ECDSAadaptor/non" */ + nonce_function_ecdsa_adaptor_bitflip(args, 3, 16); + /* Flip algo16 again */ + nonce_function_ecdsa_adaptor_bitflip(args, 3, 16); + nonce_function_ecdsa_adaptor_bitflip(args, 4, 32); + } + + /* NULL algo16 is disallowed */ + CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, NULL, NULL) == 0); + /* Empty algo16 is fine */ + memset(algo16, 0x00, 16); + CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo16, NULL) == 1); + /* algo16 with terminating null bytes is fine */ + algo16[1] = 65; + CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo16, NULL) == 1); + /* Other algo16 is fine */ + memset(algo16, 0xFF, 16); + CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo16, NULL) == 1); + + /* NULL aux_rand argument is allowed. */ + CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo16, NULL) == 1); +} + +void test_ecdsa_adaptor_api(void) { + secp256k1_pubkey pubkey; + secp256k1_pubkey enckey; + secp256k1_pubkey zero_pk; + unsigned char sk[32]; + unsigned char msg[32]; + unsigned char sig[162]; + unsigned char deckey[32]; + + /** setup **/ + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + int ecount; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + secp256k1_testrand256(sk); + secp256k1_testrand256(msg); + secp256k1_testrand256(deckey); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, sk) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &enckey, deckey) == 1); + memset(&zero_pk, 0, sizeof(zero_pk)); + + /** main test body **/ + ecount = 0; + CHECK(secp256k1_ecdsa_adaptor_encrypt(none, sig, sk, &enckey, msg, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_adaptor_encrypt(vrfy, sig, sk, &enckey, msg, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, sig, sk, &enckey, msg, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, NULL, sk, &enckey, msg, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, sig, sk, &enckey, NULL, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, sig, NULL, &enckey, msg, NULL, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, sig, sk, NULL, msg, NULL, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, sig, sk, &zero_pk, msg, NULL, NULL) == 0); + CHECK(ecount == 7); + + ecount = 0; + CHECK(secp256k1_ecdsa_adaptor_encrypt(sign, sig, sk, &enckey, msg, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(none, sig, &pubkey, msg, &enckey) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(sign, sig, &pubkey, msg, &enckey) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, sig, &pubkey, msg, &enckey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, NULL, &pubkey, msg, &enckey) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, sig, &pubkey, NULL, &enckey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, sig, &pubkey, msg, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, sig, NULL, msg, &enckey) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, sig, &zero_pk, msg, &enckey) == 0); + CHECK(ecount == 7); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(vrfy, sig, &pubkey, msg, &zero_pk) == 0); + CHECK(ecount == 8); + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + +void adaptor_tests(void) { + unsigned char seckey[32]; + secp256k1_pubkey pubkey; + unsigned char msg[32]; + unsigned char deckey[32]; + secp256k1_pubkey enckey; + unsigned char adaptor_sig[162]; + secp256k1_ecdsa_signature sig; + unsigned char zeros162[162] = { 0 }; + unsigned char zeros64[64] = { 0 }; + unsigned char big[32]; + + secp256k1_testrand256(seckey); + secp256k1_testrand256(msg); + secp256k1_testrand256(deckey); + + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, seckey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &enckey, deckey) == 1); + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, NULL, NULL) == 1); + + /* Test overflowing seckey */ + memset(big, 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, big, &enckey, msg, NULL, NULL) == 0); + CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0); + + /* Test different nonce functions */ + memset(adaptor_sig, 1, sizeof(adaptor_sig)); + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_failing, NULL) == 0); + CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0); + memset(&adaptor_sig, 1, sizeof(adaptor_sig)); + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_0, NULL) == 0); + CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0); + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_overflowing, NULL) == 1); + CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) != 0); + { + /* Test adaptor_sig_serialize roundtrip */ + secp256k1_ge r, rp; + secp256k1_scalar sigr; + secp256k1_scalar sp; + secp256k1_scalar dleq_proof_s, dleq_proof_e; + unsigned char adaptor_sig_tmp[162]; + + CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig) == 1); + + secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s); + CHECK(memcmp(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)) == 0); + } + { + /* Test adaptor_sig_deserialize overflow */ + secp256k1_ge r, rp; + secp256k1_scalar sigr; + secp256k1_scalar sp; + secp256k1_scalar dleq_proof_s, dleq_proof_e; + unsigned char adaptor_sig_tmp[162]; + + /* r */ + memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); + memset(&adaptor_sig_tmp[1], 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig_tmp) == 0); + + /* rp */ + memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); + memset(&adaptor_sig_tmp[34], 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig_tmp) == 0); + + /* sp */ + memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); + memset(&adaptor_sig_tmp[66], 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig_tmp) == 0); + + /* dleq_proof_e */ + memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); + memset(&adaptor_sig_tmp[98], 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig_tmp) == 0); + + /* dleq_proof_s */ + memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); + memset(&adaptor_sig_tmp[130], 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig_tmp) == 0); + } + + /* Test adaptor_sig_verify */ + CHECK(secp256k1_ecdsa_adaptor_sig_verify(ctx, adaptor_sig, &pubkey, msg, &enckey) == 1); + { + unsigned char adaptor_sig_tmp[65]; + memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); + rand_flip_bit(&adaptor_sig_tmp[1], sizeof(adaptor_sig_tmp) - 1); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(ctx, adaptor_sig_tmp, &pubkey, msg, &enckey) == 0); + } + CHECK(secp256k1_ecdsa_adaptor_sig_verify(ctx, adaptor_sig, &enckey, msg, &enckey) == 0); + { + unsigned char msg_tmp[32]; + memcpy(msg_tmp, msg, sizeof(msg_tmp)); + rand_flip_bit(msg_tmp, sizeof(msg_tmp)); + CHECK(secp256k1_ecdsa_adaptor_sig_verify(ctx, adaptor_sig, &pubkey, msg_tmp, &enckey) == 0); + } + CHECK(secp256k1_ecdsa_adaptor_sig_verify(ctx, adaptor_sig, &pubkey, msg, &pubkey) == 0); + + /* Test decryption */ + CHECK(secp256k1_ecdsa_adaptor_decrypt(ctx, &sig, deckey, adaptor_sig) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + + { + /* Test overflowing decryption key */ + secp256k1_ecdsa_signature s; + memset(big, 0xFF, 32); + CHECK(secp256k1_ecdsa_adaptor_decrypt(ctx, &s, big, adaptor_sig) == 0); + CHECK(secp256k1_memcmp_var(&s.data[0], zeros64, sizeof(&s.data[0])) == 0); + } + { + /* Test key recover */ + unsigned char decryption_key_tmp[32]; + CHECK(secp256k1_ecdsa_adaptor_recover(ctx, decryption_key_tmp, &sig, adaptor_sig, &enckey) == 1); + CHECK(memcmp(deckey, decryption_key_tmp, sizeof(deckey)) == 0); + } +} + +void run_ecdsa_adaptor_tests(void) { + int i; + run_nonce_function_ecdsa_adaptor_tests(); + + test_ecdsa_adaptor_api(); + test_ecdsa_adaptor_spec_vectors(); + for (i = 0; i < count; i++) { + dleq_tests(); + } + for (i = 0; i < count; i++) { + adaptor_tests(); + } +} + +#endif /* SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H */ diff --git a/src/tests.c b/src/tests.c index a3ca7ecbf..8e88bbfb6 100644 --- a/src/tests.c +++ b/src/tests.c @@ -5701,6 +5701,10 @@ void run_ecdsa_openssl(void) { # include "modules/ecdsa_s2c/tests_impl.h" #endif +#ifdef ENABLE_MODULE_ECDSA_ADAPTOR +# include "modules/ecdsa_adaptor/tests_impl.h" +#endif + void run_secp256k1_memczero_test(void) { unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; unsigned char buf2[sizeof(buf1)]; @@ -6016,6 +6020,10 @@ int main(int argc, char **argv) { run_ecdsa_s2c_tests(); #endif +#ifdef ENABLE_MODULE_ECDSA_ADAPTOR + run_ecdsa_adaptor_tests(); +#endif + /* util tests */ run_secp256k1_memczero_test(); diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index 9750d185b..e21e4df5c 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -29,6 +29,10 @@ #include "include/secp256k1_ecdsa_s2c.h" #endif +#ifdef ENABLE_MODULE_ECDSA_ADAPTOR +#include "include/secp256k1_ecdsa_adaptor.h" +#endif + int main(void) { secp256k1_context* ctx; secp256k1_ecdsa_signature signature; @@ -181,6 +185,29 @@ int main(void) { } #endif +#ifdef ENABLE_MODULE_ECDSA_ADAPTOR + { + unsigned char adaptor_sig[162]; + unsigned char decryption_key[32]; + + VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + ret = secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, key, &pubkey, msg, NULL, NULL); + VALGRIND_MAKE_MEM_DEFINED(adaptor_sig, sizeof(adaptor_sig)); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + + VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + ret = secp256k1_ecdsa_adaptor_decrypt(ctx, &signature, key, adaptor_sig); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + + VALGRIND_MAKE_MEM_UNDEFINED(&signature, 32); + ret = secp256k1_ecdsa_adaptor_recover(ctx, decryption_key, &signature, adaptor_sig, &pubkey); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + } +#endif + secp256k1_context_destroy(ctx); return 0; }