Remove Schnorr experiment
This commit is contained in:
parent
04c8ef36ad
commit
e06e878fd7
|
@ -154,10 +154,6 @@ if ENABLE_MODULE_ECDH
|
||||||
include src/modules/ecdh/Makefile.am.include
|
include src/modules/ecdh/Makefile.am.include
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ENABLE_MODULE_SCHNORR
|
|
||||||
include src/modules/schnorr/Makefile.am.include
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_MODULE_RECOVERY
|
if ENABLE_MODULE_RECOVERY
|
||||||
include src/modules/recovery/Makefile.am.include
|
include src/modules/recovery/Makefile.am.include
|
||||||
endif
|
endif
|
||||||
|
|
20
configure.ac
20
configure.ac
|
@ -119,11 +119,6 @@ AC_ARG_ENABLE(module_ecdh,
|
||||||
[enable_module_ecdh=$enableval],
|
[enable_module_ecdh=$enableval],
|
||||||
[enable_module_ecdh=no])
|
[enable_module_ecdh=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_schnorr,
|
|
||||||
AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]),
|
|
||||||
[enable_module_schnorr=$enableval],
|
|
||||||
[enable_module_schnorr=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_recovery,
|
AC_ARG_ENABLE(module_recovery,
|
||||||
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
|
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
|
||||||
[enable_module_recovery=$enableval],
|
[enable_module_recovery=$enableval],
|
||||||
|
@ -381,9 +376,6 @@ fi
|
||||||
if test x"$use_jni" != x"no"; then
|
if test x"$use_jni" != x"no"; then
|
||||||
AX_JNI_INCLUDE_DIR
|
AX_JNI_INCLUDE_DIR
|
||||||
have_jni_dependencies=yes
|
have_jni_dependencies=yes
|
||||||
if test x"$enable_module_schnorr" = x"no"; then
|
|
||||||
have_jni_dependencies=no
|
|
||||||
fi
|
|
||||||
if test x"$enable_module_ecdh" = x"no"; then
|
if test x"$enable_module_ecdh" = x"no"; then
|
||||||
have_jni_dependencies=no
|
have_jni_dependencies=no
|
||||||
fi
|
fi
|
||||||
|
@ -392,7 +384,7 @@ if test x"$use_jni" != x"no"; then
|
||||||
fi
|
fi
|
||||||
if test "x$have_jni_dependencies" = "xno"; then
|
if test "x$have_jni_dependencies" = "xno"; then
|
||||||
if test x"$use_jni" = x"yes"; then
|
if test x"$use_jni" = x"yes"; then
|
||||||
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.])
|
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
|
||||||
fi
|
fi
|
||||||
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
|
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
|
||||||
use_jni=no
|
use_jni=no
|
||||||
|
@ -421,10 +413,6 @@ if test x"$enable_module_ecdh" = x"yes"; then
|
||||||
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
|
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test x"$enable_module_schnorr" = x"yes"; then
|
|
||||||
AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test x"$enable_module_recovery" = x"yes"; then
|
if test x"$enable_module_recovery" = x"yes"; then
|
||||||
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
|
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
|
||||||
fi
|
fi
|
||||||
|
@ -442,7 +430,6 @@ AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
|
||||||
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
||||||
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
||||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
|
||||||
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
||||||
AC_MSG_NOTICE([Using jni: $use_jni])
|
AC_MSG_NOTICE([Using jni: $use_jni])
|
||||||
|
|
||||||
|
@ -451,12 +438,8 @@ if test x"$enable_experimental" = x"yes"; then
|
||||||
AC_MSG_NOTICE([WARNING: experimental build])
|
AC_MSG_NOTICE([WARNING: experimental build])
|
||||||
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
|
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
|
||||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
|
||||||
AC_MSG_NOTICE([******])
|
AC_MSG_NOTICE([******])
|
||||||
else
|
else
|
||||||
if test x"$enable_module_schnorr" = x"yes"; then
|
|
||||||
AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
|
|
||||||
fi
|
|
||||||
if test x"$enable_module_ecdh" = x"yes"; then
|
if test x"$enable_module_ecdh" = x"yes"; then
|
||||||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
||||||
fi
|
fi
|
||||||
|
@ -476,7 +459,6 @@ AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
|
||||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
|
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
||||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
#ifndef _SECP256K1_SCHNORR_
|
|
||||||
# define _SECP256K1_SCHNORR_
|
|
||||||
|
|
||||||
# include "secp256k1.h"
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
|
|
||||||
* produces non-malleable 64-byte signatures which support public key recovery
|
|
||||||
* batch validation, and multiparty signing.
|
|
||||||
* Returns: 1: signature created
|
|
||||||
* 0: the nonce generation function failed, or the private key was
|
|
||||||
* invalid.
|
|
||||||
* Args: ctx: pointer to a context object, initialized for signing
|
|
||||||
* (cannot be NULL)
|
|
||||||
* Out: sig64: pointer to a 64-byte array where the signature will be
|
|
||||||
* placed (cannot be NULL)
|
|
||||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
|
||||||
* seckey: pointer to a 32-byte secret key (cannot be NULL)
|
|
||||||
* noncefp:pointer to a nonce generation function. If NULL,
|
|
||||||
* secp256k1_nonce_function_default is used
|
|
||||||
* ndata: pointer to arbitrary data used by the nonce generation
|
|
||||||
* function (can be NULL)
|
|
||||||
*/
|
|
||||||
SECP256K1_API int secp256k1_schnorr_sign(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
unsigned char *sig64,
|
|
||||||
const unsigned char *msg32,
|
|
||||||
const unsigned char *seckey,
|
|
||||||
secp256k1_nonce_function noncefp,
|
|
||||||
const void *ndata
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Verify a signature created by secp256k1_schnorr_sign.
|
|
||||||
* Returns: 1: correct signature
|
|
||||||
* 0: incorrect signature
|
|
||||||
* Args: ctx: a secp256k1 context object, initialized for verification.
|
|
||||||
* In: sig64: the 64-byte signature being verified (cannot be NULL)
|
|
||||||
* msg32: the 32-byte message hash being verified (cannot be NULL)
|
|
||||||
* pubkey: the public key to verify with (cannot be NULL)
|
|
||||||
*/
|
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
const unsigned char *sig64,
|
|
||||||
const unsigned char *msg32,
|
|
||||||
const secp256k1_pubkey *pubkey
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Recover an EC public key from a Schnorr signature created using
|
|
||||||
* secp256k1_schnorr_sign.
|
|
||||||
* Returns: 1: public key successfully recovered (which guarantees a correct
|
|
||||||
* signature).
|
|
||||||
* 0: otherwise.
|
|
||||||
* Args: ctx: pointer to a context object, initialized for
|
|
||||||
* verification (cannot be NULL)
|
|
||||||
* Out: pubkey: pointer to a pubkey to set to the recovered public key
|
|
||||||
* (cannot be NULL).
|
|
||||||
* In: sig64: signature as 64 byte array (cannot be NULL)
|
|
||||||
* msg32: the 32-byte message hash assumed to be signed (cannot
|
|
||||||
* be NULL)
|
|
||||||
*/
|
|
||||||
SECP256K1_API int secp256k1_schnorr_recover(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
secp256k1_pubkey *pubkey,
|
|
||||||
const unsigned char *sig64,
|
|
||||||
const unsigned char *msg32
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Generate a nonce pair deterministically for use with
|
|
||||||
* secp256k1_schnorr_partial_sign.
|
|
||||||
* Returns: 1: valid nonce pair was generated.
|
|
||||||
* 0: otherwise (nonce generation function failed)
|
|
||||||
* Args: ctx: pointer to a context object, initialized for signing
|
|
||||||
* (cannot be NULL)
|
|
||||||
* Out: pubnonce: public side of the nonce (cannot be NULL)
|
|
||||||
* privnonce32: private side of the nonce (32 byte) (cannot be NULL)
|
|
||||||
* In: msg32: the 32-byte message hash assumed to be signed (cannot
|
|
||||||
* be NULL)
|
|
||||||
* sec32: the 32-byte private key (cannot be NULL)
|
|
||||||
* noncefp: pointer to a nonce generation function. If NULL,
|
|
||||||
* secp256k1_nonce_function_default is used
|
|
||||||
* noncedata: pointer to arbitrary data used by the nonce generation
|
|
||||||
* function (can be NULL)
|
|
||||||
*
|
|
||||||
* Do not use the output as a private/public key pair for signing/validation.
|
|
||||||
*/
|
|
||||||
SECP256K1_API int secp256k1_schnorr_generate_nonce_pair(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
secp256k1_pubkey *pubnonce,
|
|
||||||
unsigned char *privnonce32,
|
|
||||||
const unsigned char *msg32,
|
|
||||||
const unsigned char *sec32,
|
|
||||||
secp256k1_nonce_function noncefp,
|
|
||||||
const void* noncedata
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
||||||
|
|
||||||
/** Produce a partial Schnorr signature, which can be combined using
|
|
||||||
* secp256k1_schnorr_partial_combine, to end up with a full signature that is
|
|
||||||
* verifiable using secp256k1_schnorr_verify.
|
|
||||||
* Returns: 1: signature created successfully.
|
|
||||||
* 0: no valid signature exists with this combination of keys, nonces
|
|
||||||
* and message (chance around 1 in 2^128)
|
|
||||||
* -1: invalid private key, nonce, or public nonces.
|
|
||||||
* Args: ctx: pointer to context object, initialized for signing (cannot
|
|
||||||
* be NULL)
|
|
||||||
* Out: sig64: pointer to 64-byte array to put partial signature in
|
|
||||||
* In: msg32: pointer to 32-byte message to sign
|
|
||||||
* sec32: pointer to 32-byte private key
|
|
||||||
* pubnonce_others: pointer to pubkey containing the sum of the other's
|
|
||||||
* nonces (see secp256k1_ec_pubkey_combine)
|
|
||||||
* secnonce32: pointer to 32-byte array containing our nonce
|
|
||||||
*
|
|
||||||
* The intended procedure for creating a multiparty signature is:
|
|
||||||
* - Each signer S[i] with private key x[i] and public key Q[i] runs
|
|
||||||
* secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of
|
|
||||||
* private/public nonces.
|
|
||||||
* - All signers communicate their public nonces to each other (revealing your
|
|
||||||
* private nonce can lead to discovery of your private key, so it should be
|
|
||||||
* considered secret).
|
|
||||||
* - All signers combine all the public nonces they received (excluding their
|
|
||||||
* own) using secp256k1_ec_pubkey_combine to obtain an
|
|
||||||
* Rall[i] = sum(R[0..i-1,i+1..n]).
|
|
||||||
* - All signers produce a partial signature using
|
|
||||||
* secp256k1_schnorr_partial_sign, passing in their own private key x[i],
|
|
||||||
* their own private nonce k[i], and the sum of the others' public nonces
|
|
||||||
* Rall[i].
|
|
||||||
* - All signers communicate their partial signatures to each other.
|
|
||||||
* - Someone combines all partial signatures using
|
|
||||||
* secp256k1_schnorr_partial_combine, to obtain a full signature.
|
|
||||||
* - The resulting signature is validatable using secp256k1_schnorr_verify, with
|
|
||||||
* public key equal to the result of secp256k1_ec_pubkey_combine of the
|
|
||||||
* signers' public keys (sum(Q[0..n])).
|
|
||||||
*
|
|
||||||
* Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine
|
|
||||||
* function take their arguments in any order, and it is possible to
|
|
||||||
* pre-combine several inputs already with one call, and add more inputs later
|
|
||||||
* by calling the function again (they are commutative and associative).
|
|
||||||
*/
|
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
unsigned char *sig64,
|
|
||||||
const unsigned char *msg32,
|
|
||||||
const unsigned char *sec32,
|
|
||||||
const secp256k1_pubkey *pubnonce_others,
|
|
||||||
const unsigned char *secnonce32
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
|
||||||
|
|
||||||
/** Combine multiple Schnorr partial signatures.
|
|
||||||
* Returns: 1: the passed signatures were successfully combined.
|
|
||||||
* 0: the resulting signature is not valid (chance of 1 in 2^256)
|
|
||||||
* -1: some inputs were invalid, or the signatures were not created
|
|
||||||
* using the same set of nonces
|
|
||||||
* Args: ctx: pointer to a context object
|
|
||||||
* Out: sig64: pointer to a 64-byte array to place the combined signature
|
|
||||||
* (cannot be NULL)
|
|
||||||
* In: sig64sin: pointer to an array of n pointers to 64-byte input
|
|
||||||
* signatures
|
|
||||||
* n: the number of signatures to combine (at least 1)
|
|
||||||
*/
|
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
unsigned char *sig64,
|
|
||||||
const unsigned char * const * sig64sin,
|
|
||||||
size_t n
|
|
||||||
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -32,7 +32,7 @@ import static org.bitcoin.NativeSecp256k1Util.*;
|
||||||
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
||||||
*
|
*
|
||||||
* <p>To build secp256k1 for use with bitcoinj, run
|
* <p>To build secp256k1 for use with bitcoinj, run
|
||||||
* `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh`
|
* `./configure --enable-jni --enable-experimental --enable-module-ecdh`
|
||||||
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
|
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
|
||||||
* or point the JVM to the folder containing it with -Djava.library.path
|
* or point the JVM to the folder containing it with -Djava.library.path
|
||||||
* </p>
|
* </p>
|
||||||
|
@ -417,36 +417,6 @@ public class NativeSecp256k1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
|
|
||||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
|
||||||
|
|
||||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
|
||||||
if (byteBuff == null) {
|
|
||||||
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
|
||||||
byteBuff.order(ByteOrder.nativeOrder());
|
|
||||||
nativeECDSABuffer.set(byteBuff);
|
|
||||||
}
|
|
||||||
byteBuff.rewind();
|
|
||||||
byteBuff.put(data);
|
|
||||||
byteBuff.put(sec);
|
|
||||||
|
|
||||||
byte[][] retByteArray;
|
|
||||||
|
|
||||||
r.lock();
|
|
||||||
try {
|
|
||||||
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
|
|
||||||
} finally {
|
|
||||||
r.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] sigArr = retByteArray[0];
|
|
||||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
|
||||||
|
|
||||||
assertEquals(sigArr.length, 64, "Got bad signature length.");
|
|
||||||
|
|
||||||
return retVal == 0 ? new byte[0] : sigArr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native long secp256k1_ctx_clone(long context);
|
private static native long secp256k1_ctx_clone(long context);
|
||||||
|
|
||||||
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
||||||
|
@ -471,8 +441,6 @@ public class NativeSecp256k1 {
|
||||||
|
|
||||||
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
|
|
||||||
|
|
||||||
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,22 +167,6 @@ public class NativeSecp256k1Test {
|
||||||
assertEquals( result, true, "testRandomize");
|
assertEquals( result, true, "testRandomize");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This tests signSchnorr() for a valid secretkey
|
|
||||||
*/
|
|
||||||
public static void testSchnorrSign() throws AssertFailException{
|
|
||||||
|
|
||||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
|
||||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
|
||||||
|
|
||||||
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
|
|
||||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
|
||||||
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This tests signSchnorr() for a valid secretkey
|
|
||||||
*/
|
|
||||||
public static void testCreateECDHSecret() throws AssertFailException{
|
public static void testCreateECDHSecret() throws AssertFailException{
|
||||||
|
|
||||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
@ -216,11 +200,6 @@ public class NativeSecp256k1Test {
|
||||||
testSignPos();
|
testSignPos();
|
||||||
testSignNeg();
|
testSignNeg();
|
||||||
|
|
||||||
//Test Schnorr (partial support) //TODO
|
|
||||||
testSchnorrSign();
|
|
||||||
//testSchnorrVerify
|
|
||||||
//testSchnorrRecovery
|
|
||||||
|
|
||||||
//Test privKeyTweakAdd() 1
|
//Test privKeyTweakAdd() 1
|
||||||
testPrivKeyTweakAdd_1();
|
testPrivKeyTweakAdd_1();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "include/secp256k1.h"
|
#include "include/secp256k1.h"
|
||||||
#include "include/secp256k1_ecdh.h"
|
#include "include/secp256k1_ecdh.h"
|
||||||
#include "include/secp256k1_recovery.h"
|
#include "include/secp256k1_recovery.h"
|
||||||
#include "include/secp256k1_schnorr.h"
|
|
||||||
|
|
||||||
|
|
||||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
|
@ -333,39 +332,6 @@ SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1p
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
|
|
||||||
|
|
||||||
intsarray[0] = ret;
|
|
||||||
|
|
||||||
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
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
{
|
{
|
||||||
|
|
|
@ -104,14 +104,6 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
||||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: org_bitcoin_NativeSecp256k1
|
|
||||||
* Method: secp256k1_schnorr_sign
|
|
||||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
|
||||||
*/
|
|
||||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
|
||||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_bitcoin_NativeSecp256k1
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
* Method: secp256k1_ecdh
|
* Method: secp256k1_ecdh
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
include_HEADERS += include/secp256k1_schnorr.h
|
|
||||||
noinst_HEADERS += src/modules/schnorr/main_impl.h
|
|
||||||
noinst_HEADERS += src/modules/schnorr/schnorr.h
|
|
||||||
noinst_HEADERS += src/modules/schnorr/schnorr_impl.h
|
|
||||||
noinst_HEADERS += src/modules/schnorr/tests_impl.h
|
|
||||||
if USE_BENCHMARK
|
|
||||||
noinst_PROGRAMS += bench_schnorr_verify
|
|
||||||
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
|
|
||||||
bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
|
||||||
endif
|
|
|
@ -1,164 +0,0 @@
|
||||||
/**********************************************************************
|
|
||||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#ifndef SECP256K1_MODULE_SCHNORR_MAIN
|
|
||||||
#define SECP256K1_MODULE_SCHNORR_MAIN
|
|
||||||
|
|
||||||
#include "include/secp256k1_schnorr.h"
|
|
||||||
#include "modules/schnorr/schnorr_impl.h"
|
|
||||||
|
|
||||||
static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
|
|
||||||
secp256k1_sha256_t sha;
|
|
||||||
secp256k1_sha256_initialize(&sha);
|
|
||||||
secp256k1_sha256_write(&sha, r32, 32);
|
|
||||||
secp256k1_sha256_write(&sha, msg32, 32);
|
|
||||||
secp256k1_sha256_finalize(&sha, h32);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 ";
|
|
||||||
|
|
||||||
int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
|
||||||
secp256k1_scalar sec, non;
|
|
||||||
int ret = 0;
|
|
||||||
int overflow = 0;
|
|
||||||
unsigned char nonce32[32];
|
|
||||||
unsigned int count = 0;
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
|
||||||
ARG_CHECK(msg32 != NULL);
|
|
||||||
ARG_CHECK(sig64 != NULL);
|
|
||||||
ARG_CHECK(seckey != NULL);
|
|
||||||
if (noncefp == NULL) {
|
|
||||||
noncefp = secp256k1_nonce_function_default;
|
|
||||||
}
|
|
||||||
|
|
||||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
|
||||||
while (1) {
|
|
||||||
ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count);
|
|
||||||
if (!ret) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
|
||||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
|
||||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
if (!ret) {
|
|
||||||
memset(sig64, 0, 64);
|
|
||||||
}
|
|
||||||
memset(nonce32, 0, 32);
|
|
||||||
secp256k1_scalar_clear(&non);
|
|
||||||
secp256k1_scalar_clear(&sec);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
|
|
||||||
secp256k1_ge q;
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
||||||
ARG_CHECK(msg32 != NULL);
|
|
||||||
ARG_CHECK(sig64 != NULL);
|
|
||||||
ARG_CHECK(pubkey != NULL);
|
|
||||||
|
|
||||||
secp256k1_pubkey_load(ctx, &q, pubkey);
|
|
||||||
return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32);
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) {
|
|
||||||
secp256k1_ge q;
|
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
||||||
ARG_CHECK(msg32 != NULL);
|
|
||||||
ARG_CHECK(sig64 != NULL);
|
|
||||||
ARG_CHECK(pubkey != NULL);
|
|
||||||
|
|
||||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) {
|
|
||||||
secp256k1_pubkey_save(pubkey, &q);
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
memset(pubkey, 0, sizeof(*pubkey));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) {
|
|
||||||
int count = 0;
|
|
||||||
int ret = 1;
|
|
||||||
secp256k1_gej Qj;
|
|
||||||
secp256k1_ge Q;
|
|
||||||
secp256k1_scalar sec;
|
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
|
||||||
ARG_CHECK(msg32 != NULL);
|
|
||||||
ARG_CHECK(sec32 != NULL);
|
|
||||||
ARG_CHECK(pubnonce != NULL);
|
|
||||||
ARG_CHECK(privnonce32 != NULL);
|
|
||||||
|
|
||||||
if (noncefp == NULL) {
|
|
||||||
noncefp = secp256k1_nonce_function_default;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
int overflow;
|
|
||||||
ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++);
|
|
||||||
if (!ret) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_set_b32(&sec, privnonce32, &overflow);
|
|
||||||
if (overflow || secp256k1_scalar_is_zero(&sec)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec);
|
|
||||||
secp256k1_ge_set_gej(&Q, &Qj);
|
|
||||||
|
|
||||||
secp256k1_pubkey_save(pubnonce, &Q);
|
|
||||||
break;
|
|
||||||
} while(1);
|
|
||||||
|
|
||||||
secp256k1_scalar_clear(&sec);
|
|
||||||
if (!ret) {
|
|
||||||
memset(pubnonce, 0, sizeof(*pubnonce));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) {
|
|
||||||
int overflow = 0;
|
|
||||||
secp256k1_scalar sec, non;
|
|
||||||
secp256k1_ge pubnon;
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
|
||||||
ARG_CHECK(msg32 != NULL);
|
|
||||||
ARG_CHECK(sig64 != NULL);
|
|
||||||
ARG_CHECK(sec32 != NULL);
|
|
||||||
ARG_CHECK(secnonce32 != NULL);
|
|
||||||
ARG_CHECK(pubnonce_others != NULL);
|
|
||||||
|
|
||||||
secp256k1_scalar_set_b32(&sec, sec32, &overflow);
|
|
||||||
if (overflow || secp256k1_scalar_is_zero(&sec)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_set_b32(&non, secnonce32, &overflow);
|
|
||||||
if (overflow || secp256k1_scalar_is_zero(&non)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others);
|
|
||||||
return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32);
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) {
|
|
||||||
ARG_CHECK(sig64 != NULL);
|
|
||||||
ARG_CHECK(n >= 1);
|
|
||||||
ARG_CHECK(sig64sin != NULL);
|
|
||||||
return secp256k1_schnorr_sig_combine(sig64, n, sig64sin);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,20 +0,0 @@
|
||||||
/***********************************************************************
|
|
||||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
|
||||||
***********************************************************************/
|
|
||||||
|
|
||||||
#ifndef _SECP256K1_MODULE_SCHNORR_H_
|
|
||||||
#define _SECP256K1_MODULE_SCHNORR_H_
|
|
||||||
|
|
||||||
#include "scalar.h"
|
|
||||||
#include "group.h"
|
|
||||||
|
|
||||||
typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32);
|
|
||||||
|
|
||||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
|
||||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
|
||||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
|
|
||||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,207 +0,0 @@
|
||||||
/***********************************************************************
|
|
||||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
|
||||||
***********************************************************************/
|
|
||||||
|
|
||||||
#ifndef _SECP256K1_SCHNORR_IMPL_H_
|
|
||||||
#define _SECP256K1_SCHNORR_IMPL_H_
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "schnorr.h"
|
|
||||||
#include "num.h"
|
|
||||||
#include "field.h"
|
|
||||||
#include "group.h"
|
|
||||||
#include "ecmult.h"
|
|
||||||
#include "ecmult_gen.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom Schnorr-based signature scheme. They support multiparty signing, public key
|
|
||||||
* recovery and batch validation.
|
|
||||||
*
|
|
||||||
* Rationale for verifying R's y coordinate:
|
|
||||||
* In order to support batch validation and public key recovery, the full R point must
|
|
||||||
* be known to verifiers, rather than just its x coordinate. In order to not risk
|
|
||||||
* being more strict in batch validation than normal validation, validators must be
|
|
||||||
* required to reject signatures with incorrect y coordinate. This is only possible
|
|
||||||
* by including a (relatively slow) field inverse, or a field square root. However,
|
|
||||||
* batch validation offers potentially much higher benefits than this cost.
|
|
||||||
*
|
|
||||||
* Rationale for having an implicit y coordinate oddness:
|
|
||||||
* If we commit to having the full R point known to verifiers, there are two mechanism.
|
|
||||||
* Either include its oddness in the signature, or give it an implicit fixed value.
|
|
||||||
* As the R y coordinate can be flipped by a simple negation of the nonce, we choose the
|
|
||||||
* latter, as it comes with nearly zero impact on signing or validation performance, and
|
|
||||||
* saves a byte in the signature.
|
|
||||||
*
|
|
||||||
* Signing:
|
|
||||||
* Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0)
|
|
||||||
*
|
|
||||||
* Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce).
|
|
||||||
* Compute 32-byte r, the serialization of R's x coordinate.
|
|
||||||
* Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order.
|
|
||||||
* Compute scalar s = k - h * x.
|
|
||||||
* The signature is (r, s).
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Verification:
|
|
||||||
* Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s)
|
|
||||||
*
|
|
||||||
* Signature is invalid if s >= order.
|
|
||||||
* Signature is invalid if r >= p.
|
|
||||||
* Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order.
|
|
||||||
* Option 1 (faster for single verification):
|
|
||||||
* Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd.
|
|
||||||
* Signature is valid if the serialization of R's x coordinate equals r.
|
|
||||||
* Option 2 (allows batch validation and pubkey recovery):
|
|
||||||
* Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve.
|
|
||||||
* Signature is valid if R + h * Q + s * G == 0.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
|
||||||
secp256k1_gej Rj;
|
|
||||||
secp256k1_ge Ra;
|
|
||||||
unsigned char h32[32];
|
|
||||||
secp256k1_scalar h, s;
|
|
||||||
int overflow;
|
|
||||||
secp256k1_scalar n;
|
|
||||||
|
|
||||||
if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
n = *nonce;
|
|
||||||
|
|
||||||
secp256k1_ecmult_gen(ctx, &Rj, &n);
|
|
||||||
if (pubnonce != NULL) {
|
|
||||||
secp256k1_gej_add_ge(&Rj, &Rj, pubnonce);
|
|
||||||
}
|
|
||||||
secp256k1_ge_set_gej(&Ra, &Rj);
|
|
||||||
secp256k1_fe_normalize(&Ra.y);
|
|
||||||
if (secp256k1_fe_is_odd(&Ra.y)) {
|
|
||||||
/* R's y coordinate is odd, which is not allowed (see rationale above).
|
|
||||||
Force it to be even by negating the nonce. Note that this even works
|
|
||||||
for multiparty signing, as the R point is known to all participants,
|
|
||||||
which can all decide to flip the sign in unison, resulting in the
|
|
||||||
overall R point to be negated too. */
|
|
||||||
secp256k1_scalar_negate(&n, &n);
|
|
||||||
}
|
|
||||||
secp256k1_fe_normalize(&Ra.x);
|
|
||||||
secp256k1_fe_get_b32(sig64, &Ra.x);
|
|
||||||
hash(h32, sig64, msg32);
|
|
||||||
overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&h, h32, &overflow);
|
|
||||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
|
||||||
secp256k1_scalar_clear(&n);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_mul(&s, &h, key);
|
|
||||||
secp256k1_scalar_negate(&s, &s);
|
|
||||||
secp256k1_scalar_add(&s, &s, &n);
|
|
||||||
secp256k1_scalar_clear(&n);
|
|
||||||
secp256k1_scalar_get_b32(sig64 + 32, &s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
|
||||||
secp256k1_gej Qj, Rj;
|
|
||||||
secp256k1_ge Ra;
|
|
||||||
secp256k1_fe Rx;
|
|
||||||
secp256k1_scalar h, s;
|
|
||||||
unsigned char hh[32];
|
|
||||||
int overflow;
|
|
||||||
|
|
||||||
if (secp256k1_ge_is_infinity(pubkey)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
hash(hh, sig64, msg32);
|
|
||||||
overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&h, hh, &overflow);
|
|
||||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
|
|
||||||
if (overflow) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!secp256k1_fe_set_b32(&Rx, sig64)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_gej_set_ge(&Qj, pubkey);
|
|
||||||
secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s);
|
|
||||||
if (secp256k1_gej_is_infinity(&Rj)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_ge_set_gej_var(&Ra, &Rj);
|
|
||||||
secp256k1_fe_normalize_var(&Ra.y);
|
|
||||||
if (secp256k1_fe_is_odd(&Ra.y)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return secp256k1_fe_equal_var(&Rx, &Ra.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
|
|
||||||
secp256k1_gej Qj, Rj;
|
|
||||||
secp256k1_ge Ra;
|
|
||||||
secp256k1_fe Rx;
|
|
||||||
secp256k1_scalar h, s;
|
|
||||||
unsigned char hh[32];
|
|
||||||
int overflow;
|
|
||||||
|
|
||||||
hash(hh, sig64, msg32);
|
|
||||||
overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&h, hh, &overflow);
|
|
||||||
if (overflow || secp256k1_scalar_is_zero(&h)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
|
|
||||||
if (overflow) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!secp256k1_fe_set_b32(&Rx, sig64)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_gej_set_ge(&Rj, &Ra);
|
|
||||||
secp256k1_scalar_inverse_var(&h, &h);
|
|
||||||
secp256k1_scalar_negate(&s, &s);
|
|
||||||
secp256k1_scalar_mul(&s, &s, &h);
|
|
||||||
secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s);
|
|
||||||
if (secp256k1_gej_is_infinity(&Qj)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_ge_set_gej(pubkey, &Qj);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) {
|
|
||||||
secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
secp256k1_scalar si;
|
|
||||||
int overflow;
|
|
||||||
secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow);
|
|
||||||
if (overflow) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (i) {
|
|
||||||
if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
secp256k1_scalar_add(&s, &s, &si);
|
|
||||||
}
|
|
||||||
if (secp256k1_scalar_is_zero(&s)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(sig64, sig64ins[0], 32);
|
|
||||||
secp256k1_scalar_get_b32(sig64 + 32, &s);
|
|
||||||
secp256k1_scalar_clear(&s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,175 +0,0 @@
|
||||||
/**********************************************************************
|
|
||||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#ifndef SECP256K1_MODULE_SCHNORR_TESTS
|
|
||||||
#define SECP256K1_MODULE_SCHNORR_TESTS
|
|
||||||
|
|
||||||
#include "include/secp256k1_schnorr.h"
|
|
||||||
|
|
||||||
void test_schnorr_end_to_end(void) {
|
|
||||||
unsigned char privkey[32];
|
|
||||||
unsigned char message[32];
|
|
||||||
unsigned char schnorr_signature[64];
|
|
||||||
secp256k1_pubkey pubkey, recpubkey;
|
|
||||||
|
|
||||||
/* Generate a random key and message. */
|
|
||||||
{
|
|
||||||
secp256k1_scalar key;
|
|
||||||
random_scalar_order_test(&key);
|
|
||||||
secp256k1_scalar_get_b32(privkey, &key);
|
|
||||||
secp256k1_rand256_test(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Construct and verify corresponding public key. */
|
|
||||||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
|
|
||||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
|
|
||||||
|
|
||||||
/* Schnorr sign. */
|
|
||||||
CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1);
|
|
||||||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1);
|
|
||||||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1);
|
|
||||||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
|
||||||
/* Destroy signature and verify again. */
|
|
||||||
schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
|
|
||||||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0);
|
|
||||||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 ||
|
|
||||||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Horribly broken hash function. Do not use for anything but tests. */
|
|
||||||
void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
h32[i] = r32[i] ^ msg32[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_schnorr_sign_verify(void) {
|
|
||||||
unsigned char msg32[32];
|
|
||||||
unsigned char sig64[3][64];
|
|
||||||
secp256k1_gej pubkeyj[3];
|
|
||||||
secp256k1_ge pubkey[3];
|
|
||||||
secp256k1_scalar nonce[3], key[3];
|
|
||||||
int i = 0;
|
|
||||||
int k;
|
|
||||||
|
|
||||||
secp256k1_rand256_test(msg32);
|
|
||||||
|
|
||||||
for (k = 0; k < 3; k++) {
|
|
||||||
random_scalar_order_test(&key[k]);
|
|
||||||
|
|
||||||
do {
|
|
||||||
random_scalar_order_test(&nonce[k]);
|
|
||||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while(1);
|
|
||||||
|
|
||||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]);
|
|
||||||
secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]);
|
|
||||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32));
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
int pos = secp256k1_rand_bits(6);
|
|
||||||
int mod = 1 + secp256k1_rand_int(255);
|
|
||||||
sig64[k][pos] ^= mod;
|
|
||||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0);
|
|
||||||
sig64[k][pos] ^= mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_schnorr_threshold(void) {
|
|
||||||
unsigned char msg[32];
|
|
||||||
unsigned char sec[5][32];
|
|
||||||
secp256k1_pubkey pub[5];
|
|
||||||
unsigned char nonce[5][32];
|
|
||||||
secp256k1_pubkey pubnonce[5];
|
|
||||||
unsigned char sig[5][64];
|
|
||||||
const unsigned char* sigs[5];
|
|
||||||
unsigned char allsig[64];
|
|
||||||
const secp256k1_pubkey* pubs[5];
|
|
||||||
secp256k1_pubkey allpub;
|
|
||||||
int n, i;
|
|
||||||
int damage;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0;
|
|
||||||
secp256k1_rand256_test(msg);
|
|
||||||
n = 2 + secp256k1_rand_int(4);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
do {
|
|
||||||
secp256k1_rand256_test(sec[i]);
|
|
||||||
} while (!secp256k1_ec_seckey_verify(ctx, sec[i]));
|
|
||||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i]));
|
|
||||||
CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL));
|
|
||||||
pubs[i] = &pub[i];
|
|
||||||
}
|
|
||||||
if (damage == 1) {
|
|
||||||
nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
|
|
||||||
} else if (damage == 2) {
|
|
||||||
sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
|
|
||||||
}
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
secp256k1_pubkey allpubnonce;
|
|
||||||
const secp256k1_pubkey *pubnonces[4];
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < i; j++) {
|
|
||||||
pubnonces[j] = &pubnonce[j];
|
|
||||||
}
|
|
||||||
for (j = i + 1; j < n; j++) {
|
|
||||||
pubnonces[j - 1] = &pubnonce[j];
|
|
||||||
}
|
|
||||||
CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1));
|
|
||||||
ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1;
|
|
||||||
sigs[i] = sig[i];
|
|
||||||
}
|
|
||||||
if (damage == 3) {
|
|
||||||
sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255);
|
|
||||||
}
|
|
||||||
ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2;
|
|
||||||
if ((ret & 1) == 0) {
|
|
||||||
ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4;
|
|
||||||
}
|
|
||||||
if (damage == 4) {
|
|
||||||
allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
|
|
||||||
}
|
|
||||||
if ((ret & 7) == 0) {
|
|
||||||
ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8;
|
|
||||||
}
|
|
||||||
CHECK((ret == 0) == (damage == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_schnorr_recovery(void) {
|
|
||||||
unsigned char msg32[32];
|
|
||||||
unsigned char sig64[64];
|
|
||||||
secp256k1_ge Q;
|
|
||||||
|
|
||||||
secp256k1_rand256_test(msg32);
|
|
||||||
secp256k1_rand256_test(sig64);
|
|
||||||
secp256k1_rand256_test(sig64 + 32);
|
|
||||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) {
|
|
||||||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_schnorr_tests(void) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 32*count; i++) {
|
|
||||||
test_schnorr_end_to_end();
|
|
||||||
}
|
|
||||||
for (i = 0; i < 32 * count; i++) {
|
|
||||||
test_schnorr_sign_verify();
|
|
||||||
}
|
|
||||||
for (i = 0; i < 16 * count; i++) {
|
|
||||||
test_schnorr_recovery();
|
|
||||||
}
|
|
||||||
for (i = 0; i < 10 * count; i++) {
|
|
||||||
test_schnorr_threshold();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue