Compare commits
5 Commits
frost
...
snapshot/i
Author | SHA1 | Date | |
---|---|---|---|
|
0364ec762e | ||
|
aadffabe42 | ||
|
8e17e7030a | ||
|
929e2cda40 | ||
|
41eac9273f |
@ -22,7 +22,7 @@ buildscript {
|
||||
|
||||
allprojects {
|
||||
group = "fr.acinq.secp256k1"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
@ -17,34 +17,87 @@
|
||||
void JNI_ThrowByName(JNIEnv *penv, const char *name, const char *msg)
|
||||
{
|
||||
jclass cls = (*penv)->FindClass(penv, name);
|
||||
if (cls != NULL) {
|
||||
if (cls != NULL)
|
||||
{
|
||||
(*penv)->ThrowNew(penv, cls, msg);
|
||||
(*penv)->DeleteLocalRef(penv, cls);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* secp256k1 uses callbacks for errors that are either hw pbs or bugs in the calling library, for example
|
||||
* passing parameters with values that are explicitly defined as illegal in the API, and should never be called for normal operations
|
||||
* But if they are, default behaviour is to print an error to stderr and abort which is not what we want especially in mobile apps
|
||||
* => we set up string pointers in every method, and custom callback that will set them to the message passed in by sec256k1's callbacks, which
|
||||
* we turn into specific Sec256k1 exceptions
|
||||
*/
|
||||
#define SETUP_ERROR_CALLBACKS \
|
||||
char *error_callback_message = NULL; \
|
||||
char *illegal_callback_message = NULL; \
|
||||
secp256k1_context_set_error_callback(ctx, my_error_callback_fn, &error_callback_message); \
|
||||
secp256k1_context_set_illegal_callback(ctx, my_illegal_callback_fn, &illegal_callback_message);
|
||||
|
||||
#define CHECKRESULT(errorcheck, message) { \
|
||||
if (errorcheck) { \
|
||||
#define CHECKRESULT(errorcheck, message) \
|
||||
{ \
|
||||
if (error_callback_message) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1ErrorCallbackException", error_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (illegal_callback_message) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1IllegalCallbackException", illegal_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (errorcheck) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECKRESULT1(errorcheck, message, dosomething) { \
|
||||
if (errorcheck) { \
|
||||
#define CHECKRESULT1(errorcheck, message, dosomething) \
|
||||
{ \
|
||||
if (error_callback_message) \
|
||||
{ \
|
||||
dosomething; \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1ErrorCallbackException", error_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (illegal_callback_message) \
|
||||
{ \
|
||||
dosomething; \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1IllegalCallbackException", illegal_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (errorcheck) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
void my_illegal_callback_fn(const char *str, void *data)
|
||||
{
|
||||
if (data != NULL)
|
||||
{
|
||||
*(char **)data = str;
|
||||
}
|
||||
}
|
||||
|
||||
void my_error_callback_fn(const char *str, void *data)
|
||||
{
|
||||
if (data != NULL)
|
||||
{
|
||||
*(char **)data = str;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: fr_acinq_bitcoin_Secp256k1Bindings
|
||||
* Method: secp256k1_context_create
|
||||
* Signature: (I)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1create
|
||||
(JNIEnv *penv, jclass clazz, jint flags)
|
||||
JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1create(JNIEnv *penv, jclass clazz, jint flags)
|
||||
{
|
||||
return (jlong)secp256k1_context_create(flags);
|
||||
}
|
||||
@ -54,10 +107,10 @@ JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1c
|
||||
* Method: secp256k1_context_destroy
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1destroy
|
||||
(JNIEnv *penv, jclass clazz, jlong ctx)
|
||||
JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1destroy(JNIEnv *penv, jclass clazz, jlong ctx)
|
||||
{
|
||||
if (ctx != 0)
|
||||
{
|
||||
if (ctx != 0) {
|
||||
secp256k1_context_destroy((secp256k1_context *)ctx);
|
||||
}
|
||||
}
|
||||
@ -67,16 +120,20 @@ JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1co
|
||||
* Method: secp256k1_ec_seckey_verify
|
||||
* Signature: (J[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1seckey_1verify
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1seckey_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jseckey == NULL) return 0;
|
||||
if ((*penv)->GetArrayLength(penv, jseckey) != 32) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jseckey == NULL)
|
||||
return 0;
|
||||
if ((*penv)->GetArrayLength(penv, jseckey) != 32)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
|
||||
result = secp256k1_ec_seckey_verify(ctx, (unsigned char *)seckey);
|
||||
@ -89,8 +146,7 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
* Method: secp256k1_ec_pubkey_parse
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1parse
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1parse(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pubkeyBytes;
|
||||
@ -98,8 +154,12 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t size;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jpubkey == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
|
||||
@ -123,8 +183,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ec_pubkey_create
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1create
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1create(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey, *pubkey;
|
||||
@ -133,8 +192,12 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t len;
|
||||
jbyteArray jpubkey = 0;
|
||||
|
||||
if (jseckey == NULL) return NULL;
|
||||
if (jctx == 0) return NULL;
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
|
||||
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
|
||||
@ -155,8 +218,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ecdsa_sign
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1sign
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey, *msg, *sig;
|
||||
@ -164,9 +226,14 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
int result = 0;
|
||||
jbyteArray jsig;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jmsg == NULL) return NULL;
|
||||
if (jseckey == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jmsg == NULL)
|
||||
return NULL;
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message key must be 32 bytes");
|
||||
@ -188,8 +255,10 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
|
||||
int GetSignatureFormat(size_t size)
|
||||
{
|
||||
if (size == 64) return SIG_FORMAT_COMPACT;
|
||||
if (size < 64) return SIG_FORMAT_UNKNOWN;
|
||||
if (size == 64)
|
||||
return SIG_FORMAT_COMPACT;
|
||||
if (size < 64)
|
||||
return SIG_FORMAT_UNKNOWN;
|
||||
return SIG_FORMAT_DER;
|
||||
}
|
||||
|
||||
@ -198,8 +267,7 @@ int GetSignatureFormat(size_t size)
|
||||
* Method: secp256k1_ecdsa_verify
|
||||
* Signature: (J[B[B[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pub, *msg, *sig;
|
||||
@ -208,10 +276,16 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
size_t sigSize, pubSize;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jsig == NULL) return 0;
|
||||
if (jmsg == NULL) return 0;
|
||||
if (jpubkey == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jsig == NULL)
|
||||
return 0;
|
||||
if (jmsg == NULL)
|
||||
return 0;
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
sigSize = (*penv)->GetArrayLength(penv, jsig);
|
||||
int sigFormat = GetSignatureFormat(sigSize);
|
||||
@ -223,7 +297,8 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
|
||||
|
||||
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
|
||||
switch(sigFormat) {
|
||||
switch (sigFormat)
|
||||
{
|
||||
case SIG_FORMAT_COMPACT:
|
||||
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char *)sig);
|
||||
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
|
||||
@ -252,8 +327,7 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
* Method: secp256k1_ecdsa_signature_normalize
|
||||
* Signature: (J[B[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1signature_1normalize
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsigin, jbyteArray jsigout)
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1signature_1normalize(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsigin, jbyteArray jsigout)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *sig;
|
||||
@ -263,9 +337,14 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
int return_value = 0;
|
||||
int sigFormat = SIG_FORMAT_UNKNOWN;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jsigin == NULL) return 0;
|
||||
if (jsigout == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jsigin == NULL)
|
||||
return 0;
|
||||
if (jsigout == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jsigin);
|
||||
sigFormat = GetSignatureFormat(size);
|
||||
@ -273,7 +352,8 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jsigout) != 64, "output signature length must be 64 bytes");
|
||||
|
||||
sig = (*penv)->GetByteArrayElements(penv, jsigin, 0);
|
||||
switch(sigFormat) {
|
||||
switch (sigFormat)
|
||||
{
|
||||
case SIG_FORMAT_COMPACT:
|
||||
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature_in, (unsigned char *)sig);
|
||||
(*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0);
|
||||
@ -299,15 +379,19 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
* Method: secp256k1_ec_privkey_negate
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1negate
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1negate(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jseckey == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jseckey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
|
||||
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
|
||||
result = secp256k1_ec_seckey_negate(ctx, (unsigned char *)seckey);
|
||||
@ -321,8 +405,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ec_pubkey_negate
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1negate
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1negate(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pub;
|
||||
@ -330,8 +413,12 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t size;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jpubkey == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
|
||||
@ -357,16 +444,20 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ec_privkey_tweak_add
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1add
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey, *tweak;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jseckey == NULL) return NULL;
|
||||
if (jtweak == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
|
||||
@ -384,8 +475,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ec_pubkey_tweak_add
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1add
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pub, *tweak;
|
||||
@ -393,9 +483,14 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t size;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jpubkey == NULL) return NULL;
|
||||
if (jtweak == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jpubkey == NULL)
|
||||
return NULL;
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
|
||||
@ -425,16 +520,20 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ec_privkey_tweak_mul
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1mul
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1mul(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey, *tweak;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jseckey == NULL) return NULL;
|
||||
if (jtweak == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
|
||||
@ -452,8 +551,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ec_pubkey_tweak_mul
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1mul
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1mul(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pub, *tweak;
|
||||
@ -461,9 +559,14 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t size;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jpubkey == NULL) return NULL;
|
||||
if (jtweak == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jpubkey == NULL)
|
||||
return NULL;
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
|
||||
@ -490,8 +593,10 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
void free_pubkeys(secp256k1_pubkey **pubkeys, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < count; i++) {
|
||||
if (pubkeys[i] != NULL) free(pubkeys[i]);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (pubkeys[i] != NULL)
|
||||
free(pubkeys[i]);
|
||||
}
|
||||
free(pubkeys);
|
||||
}
|
||||
@ -501,8 +606,7 @@ void free_pubkeys(secp256k1_pubkey **pubkeys, size_t count)
|
||||
* Method: secp256k1_ec_pubkey_combine
|
||||
* Signature: (J[[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1combine
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jpubkeys)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1combine(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jpubkeys)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pub;
|
||||
@ -513,13 +617,18 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t i;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jpubkeys == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jpubkeys == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
count = (*penv)->GetArrayLength(penv, jpubkeys);
|
||||
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));
|
||||
|
||||
for(i = 0; i < count; i++) {
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
pubkeys[i] = calloc(1, sizeof(secp256k1_pubkey));
|
||||
jpubkey = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpubkeys, i);
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
@ -547,8 +656,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ecdh
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdh
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jpubkey)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdh(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jpubkey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckeyBytes, *pubkeyBytes, *output;
|
||||
@ -557,9 +665,14 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t size;
|
||||
int result;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jseckey == NULL) return NULL;
|
||||
if (jpubkey == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
if (jpubkey == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "invalid private key size");
|
||||
|
||||
@ -584,8 +697,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_ecdsa_recover
|
||||
* Signature: (J[B[BI)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1recover
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jint recid)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1recover(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jint recid)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *sig, *msg, *pub;
|
||||
@ -597,16 +709,25 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
size_t sigSize, size;
|
||||
int result;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jsig == NULL) return NULL;
|
||||
if (jmsg == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jsig == NULL)
|
||||
return NULL;
|
||||
if (jmsg == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException
|
||||
// CHECKRESULT(recid < 0 || recid > 3, "recid must be 0, 1, 2 or 3")
|
||||
|
||||
sigSize = (*penv)->GetArrayLength(penv, jsig);
|
||||
int sigFormat = GetSignatureFormat(sigSize);
|
||||
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
|
||||
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
|
||||
switch(sigFormat) {
|
||||
switch (sigFormat)
|
||||
{
|
||||
case SIG_FORMAT_COMPACT:
|
||||
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, (unsigned char *)sig, recid);
|
||||
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
|
||||
@ -641,18 +762,22 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_compact_to_der
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1compact_1to_1der
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1compact_1to_1der(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *sig;
|
||||
secp256k1_ecdsa_signature signature;;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
unsigned char der[73];
|
||||
size_t size;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jsig == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jsig == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "invalid signature size");
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jsig);
|
||||
@ -676,8 +801,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_schnorrsig_sign
|
||||
* Signature: (J[B[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1sign
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey, jbyteArray jauxrand32)
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey, jbyteArray jauxrand32)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *seckey, *msg, *sig, *auxrand32 = NULL;
|
||||
@ -686,13 +810,19 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
int result = 0;
|
||||
jbyteArray jsig;
|
||||
|
||||
if (jctx == 0) return NULL;
|
||||
if (jmsg == NULL) return NULL;
|
||||
if (jseckey == NULL) return NULL;
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
if (jmsg == NULL)
|
||||
return NULL;
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
|
||||
if (jauxrand32 != 0) {
|
||||
if (jauxrand32 != 0)
|
||||
{
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jauxrand32) != 32, "auxiliary random data must be 32 bytes");
|
||||
}
|
||||
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
|
||||
@ -701,13 +831,15 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
CHECKRESULT(!result, "secp256k1_keypair_create failed");
|
||||
|
||||
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
|
||||
if (jauxrand32 != 0) {
|
||||
if (jauxrand32 != 0)
|
||||
{
|
||||
auxrand32 = (*penv)->GetByteArrayElements(penv, jauxrand32, 0);
|
||||
}
|
||||
|
||||
result = secp256k1_schnorrsig_sign32(ctx, signature, (unsigned char *)msg, &keypair, auxrand32);
|
||||
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
|
||||
if (auxrand32 != 0) {
|
||||
if (auxrand32 != 0)
|
||||
{
|
||||
(*penv)->ReleaseByteArrayElements(penv, jauxrand32, auxrand32, 0);
|
||||
}
|
||||
CHECKRESULT(!result, "secp256k1_schnorrsig_sign failed");
|
||||
@ -724,18 +856,23 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
* Method: secp256k1_schnorrsig_verify
|
||||
* Signature: (J[B[B[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1verify
|
||||
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *pub, *msg, *sig;
|
||||
secp256k1_xonly_pubkey pubkey;
|
||||
int result = 0;
|
||||
|
||||
if (jctx == 0) return 0;
|
||||
if (jsig == NULL) return 0;
|
||||
if (jmsg == NULL) return 0;
|
||||
if (jpubkey == NULL) return 0;
|
||||
if (jctx == 0)
|
||||
return 0;
|
||||
if (jsig == NULL)
|
||||
return 0;
|
||||
if (jmsg == NULL)
|
||||
return 0;
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "signature must be 64 bytes");
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jpubkey) != 32, "public key must be 32 bytes");
|
||||
|
@ -166,7 +166,17 @@ public interface Secp256k1 {
|
||||
|
||||
internal expect fun getSecpk256k1(): Secp256k1
|
||||
|
||||
public class Secp256k1Exception : RuntimeException {
|
||||
public open class Secp256k1Exception : RuntimeException {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
||||
|
||||
public class Secp256k1ErrorCallbackException : Secp256k1Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
||||
|
||||
public class Secp256k1IllegalCallbackException : Secp256k1Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
@ -4,15 +4,67 @@ import kotlinx.cinterop.*
|
||||
import platform.posix.size_tVar
|
||||
import secp256k1.*
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
private typealias Secp256k1CallbackHandler = (String) -> Unit
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private class CallbackHandler(ctx: CPointer<secp256k1_context>) : AutoCloseable {
|
||||
var illegalCallBackMessage: String? = null
|
||||
val illegalHandler: Secp256k1CallbackHandler = { x: String -> illegalCallBackMessage = x }
|
||||
val illegalCallbackRef = StableRef.create(illegalHandler)
|
||||
var errorCallBackMessage: String? = null
|
||||
val errorHandler: Secp256k1CallbackHandler = { x: String -> errorCallBackMessage = x }
|
||||
val errorCallbackRef = StableRef.create(errorHandler)
|
||||
|
||||
init {
|
||||
secp256k1_context_set_error_callback(
|
||||
ctx, staticCFunction { buffer: CPointer<ByteVar>?, data: COpaquePointer? ->
|
||||
if (data != null) {
|
||||
val callback = data.asStableRef<Secp256k1CallbackHandler>().get()
|
||||
callback(buffer?.toKString() ?: "error callback triggered")
|
||||
}
|
||||
},
|
||||
errorCallbackRef.asCPointer()
|
||||
)
|
||||
secp256k1_context_set_illegal_callback(
|
||||
ctx, staticCFunction { buffer: CPointer<ByteVar>?, data: COpaquePointer? ->
|
||||
if (data != null) {
|
||||
val callback = data.asStableRef<Secp256k1CallbackHandler>().get()
|
||||
callback(buffer?.toKString() ?: "illegal callback triggered")
|
||||
}
|
||||
},
|
||||
illegalCallbackRef.asCPointer()
|
||||
)
|
||||
}
|
||||
|
||||
fun checkForErrors() {
|
||||
errorCallBackMessage?.let { throw Secp256k1ErrorCallbackException(it) }
|
||||
illegalCallBackMessage?.let { throw Secp256k1IllegalCallbackException(it) }
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
// StableRef instances have to be disposed of manually
|
||||
illegalCallbackRef.dispose()
|
||||
errorCallbackRef.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)
|
||||
public object Secp256k1Native : Secp256k1 {
|
||||
|
||||
private val ctx: CPointer<secp256k1_context> by lazy {
|
||||
|
||||
secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt())
|
||||
?: error("Could not create secp256k1 context")
|
||||
}
|
||||
|
||||
private fun Int.requireSuccess(message: String): Int = if (this != 1) throw Secp256k1Exception(message) else this
|
||||
private fun Int.requireSuccess(message: String): Int {
|
||||
return if (this != 1) throw Secp256k1Exception(message) else this
|
||||
}
|
||||
|
||||
private fun Int.requireSuccess(callbackHandler: CallbackHandler, message: String): Int {
|
||||
callbackHandler.checkForErrors()
|
||||
return if (this != 1) throw Secp256k1Exception(message) else this
|
||||
}
|
||||
|
||||
private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature {
|
||||
val sig = alloc<secp256k1_ecdsa_signature>()
|
||||
@ -58,181 +110,225 @@ public object Secp256k1Native : Secp256k1 {
|
||||
public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean {
|
||||
require(message.size == 32)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = allocSignature(signature)
|
||||
return secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) == 1
|
||||
val verify = secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr)
|
||||
callbackHandler.checkForErrors()
|
||||
return verify == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(message.size == 32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = alloc<secp256k1_ecdsa_signature>()
|
||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
|
||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed")
|
||||
return serializeSignature(nSig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean> {
|
||||
require(sig.size >= 64) { "invalid signature ${Hex.encode(sig)}" }
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSig = allocSignature(sig)
|
||||
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
|
||||
callbackHandler.checkForErrors()
|
||||
return Pair(serializeSignature(nSig), isHighS == 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun secKeyVerify(privkey: ByteArray): Boolean {
|
||||
if (privkey.size != 32) return false
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
return secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
|
||||
val result = secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
|
||||
callbackHandler.checkForErrors()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubkeyCreate(privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess("secp256k1_ec_pubkey_create() failed")
|
||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_create() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubkeyParse(pubkey: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
return serializePubkey(nPubkey)
|
||||
val result = serializePubkey(nPubkey)
|
||||
callbackHandler.checkForErrors()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyNegate(privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val negated = privkey.copyOf()
|
||||
val negPriv = toNat(negated)
|
||||
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess("secp256k1_ec_seckey_negate() failed")
|
||||
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess(callbackHandler, "secp256k1_ec_seckey_negate() failed")
|
||||
return negated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val added = privkey.copyOf()
|
||||
val natAdd = toNat(added)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess("secp256k1_ec_seckey_tweak_add() failed")
|
||||
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_seckey_tweak_add() failed")
|
||||
return added
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val multiplied = privkey.copyOf()
|
||||
val natMul = toNat(multiplied)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
|
||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_privkey_tweak_mul() failed")
|
||||
return multiplied
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyNegate(pubkey: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess("secp256k1_ec_pubkey_negate() failed")
|
||||
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_negate() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nTweak = toNat(tweak)
|
||||
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_add() failed")
|
||||
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_add() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nTweak = toNat(tweak)
|
||||
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_mul() failed")
|
||||
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_mul() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray {
|
||||
pubkeys.forEach { require(it.size == 33 || it.size == 65) }
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
||||
val combined = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
|
||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_combine() failed")
|
||||
return serializePubkey(combined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nPrivkey = toNat(privkey)
|
||||
val output = allocArray<UByteVar>(32)
|
||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess("secp256k1_ecdh() failed")
|
||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdh() failed")
|
||||
return output.readBytes(32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray {
|
||||
require(sig.size == 64)
|
||||
require(message.size == 32)
|
||||
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException
|
||||
// require(recid in 0..3)
|
||||
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSig = toNat(sig)
|
||||
val rSig = alloc<secp256k1_ecdsa_recoverable_signature>()
|
||||
secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess("secp256k1_ecdsa_recoverable_signature_parse_compact() failed")
|
||||
secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess(callbackHandler, "secp256k1_ecdsa_recoverable_signature_parse_compact() failed")
|
||||
val nMessage = toNat(message)
|
||||
val pubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess("secp256k1_ecdsa_recover() failed")
|
||||
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess(callbackHandler, "secp256k1_ecdsa_recover() failed")
|
||||
return serializePubkey(pubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun compact2der(sig: ByteArray): ByteArray {
|
||||
require(sig.size == 64)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSig = allocSignature(sig)
|
||||
val natOutput = allocArray<UByteVar>(73)
|
||||
val len = alloc<size_tVar>()
|
||||
len.value = 73.convert()
|
||||
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess("secp256k1_ecdsa_signature_serialize_der() failed")
|
||||
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess(callbackHandler, "secp256k1_ecdsa_signature_serialize_der() failed")
|
||||
return natOutput.readBytes(len.value.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun verifySchnorr(signature: ByteArray, data: ByteArray, pub: ByteArray): Boolean {
|
||||
require(signature.size == 64)
|
||||
require(data.size == 32)
|
||||
require(pub.size == 32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPub = toNat(pub)
|
||||
val pubkey = alloc<secp256k1_xonly_pubkey>()
|
||||
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed")
|
||||
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess(callbackHandler, "secp256k1_xonly_pubkey_parse() failed")
|
||||
val nData = toNat(data)
|
||||
val nSig = toNat(signature)
|
||||
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32, pubkey.ptr) == 1
|
||||
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,17 +336,19 @@ public object Secp256k1Native : Secp256k1 {
|
||||
require(sec.size == 32)
|
||||
require(data.size == 32)
|
||||
auxrand32?.let { require(it.size == 32) }
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSec = toNat(sec)
|
||||
val nData = toNat(data)
|
||||
val nAuxrand32 = auxrand32?.let { toNat(it) }
|
||||
val nSig = allocArray<UByteVar>(64)
|
||||
val keypair = alloc<secp256k1_keypair>()
|
||||
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess("secp256k1_keypair_create() failed")
|
||||
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess("secp256k1_ecdsa_sign() failed")
|
||||
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess(callbackHandler, "secp256k1_keypair_create() failed")
|
||||
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed")
|
||||
return nSig.readBytes(64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun cleanup() {
|
||||
secp256k1_context_destroy(ctx)
|
||||
|
@ -275,6 +275,11 @@ class Secp256k1Test {
|
||||
val pub0 = Secp256k1.ecdsaRecover(sig, message, 0)
|
||||
val pub1 = Secp256k1.ecdsaRecover(sig, message, 1)
|
||||
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1))
|
||||
|
||||
// this is a special case, ecdsaRecover explicitly does not check that recid is valid, which triggers our illegal callback handler
|
||||
assertFailsWith(Secp256k1IllegalCallbackException::class) {
|
||||
Secp256k1.ecdsaRecover(sig, message, 4)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user