Explicit Signature & PubKey formats + bug fixes

This commit is contained in:
Salomon BRYS 2020-06-29 17:10:58 +02:00
parent b67cafed38
commit 4bdc836556
8 changed files with 217 additions and 187 deletions

View File

@ -4,7 +4,7 @@ plugins {
`maven-publish` `maven-publish`
} }
group = "fr.acinq.secp256k1" group = "fr.acinq.secp256k1"
version = "0.1.0-1.4-M2" version = "0.2.0-1.4-M2"
repositories { repositories {
jcenter() jcenter()

View File

@ -76,7 +76,7 @@ SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1ve
} }
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) (JNIEnv* env, jclass classObject, jobject byteBufferObject, jboolean compact, jlong ctx_l)
{ {
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
@ -91,11 +91,15 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
int ret = secp256k1_ecdsa_sign(ctx, &sig, data, secKey, NULL, NULL); int ret = secp256k1_ecdsa_sign(ctx, &sig, data, secKey, NULL, NULL);
unsigned char outputSer[72]; unsigned char outputSer[72];
size_t outputLen = 72; size_t outputLen = compact ? 64 : 72;
if( ret ) { if( ret ) {
if (compact) {
int ret2 = secp256k1_ecdsa_signature_serialize_compact(ctx, outputSer, &sig ); (void)ret2;
} else {
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx, outputSer, &outputLen, &sig ); (void)ret2; int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx, outputSer, &outputLen, &sig ); (void)ret2;
} }
}
intsarray[0] = outputLen; intsarray[0] = outputLen;
intsarray[1] = ret; intsarray[1] = ret;
@ -117,30 +121,44 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
return retArray; return retArray;
} }
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1normalize
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) (JNIEnv* env, jclass classObject, jobject byteBufferObject, jint siglen, jboolean compact, jlong ctx_l)
{ {
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char* sigdata = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
unsigned char* secKey = (unsigned char*) (data + 32);
jobjectArray retArray; jobjectArray retArray;
jbyteArray sigArray, intsByteArray; jbyteArray sigArray, intsByteArray;
unsigned char intsarray[2]; unsigned char intsarray[3];
secp256k1_ecdsa_signature sig[72]; secp256k1_ecdsa_signature sig;
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL); int ret = 0;
if (siglen == 64) {
ret = secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigdata);
} else {
ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
}
unsigned char outputSer[64]; int ret2 = 0;
size_t outputLen = 64; if (ret) {
ret2 = secp256k1_ecdsa_signature_normalize(ctx, &sig, &sig);
}
unsigned char outputSer[72];
size_t outputLen = compact ? 64 : 72;
if( ret ) { if( ret ) {
int ret2 = secp256k1_ecdsa_signature_serialize_compact(ctx,outputSer, sig ); (void)ret2; if (compact) {
int ret3 = secp256k1_ecdsa_signature_serialize_compact(ctx, outputSer, &sig ); (void)ret3;
} else {
int ret3 = secp256k1_ecdsa_signature_serialize_der(ctx, outputSer, &outputLen, &sig ); (void)ret3;
}
} }
intsarray[0] = outputLen; intsarray[0] = outputLen;
intsarray[1] = ret; intsarray[1] = ret;
intsarray[2] = ret2;
retArray = (*env)->NewObjectArray(env, 2, retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"), (*env)->FindClass(env, "[B"),
@ -150,15 +168,15 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray); (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
intsByteArray = (*env)->NewByteArray(env, 2); intsByteArray = (*env)->NewByteArray(env, 3);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); (*env)->SetByteArrayRegion(env, intsByteArray, 0, 3, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject; (void)classObject;
return retArray; return retArray;
}
}
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
@ -172,7 +190,7 @@ SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1secke
} }
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) (JNIEnv* env, jclass classObject, jobject byteBufferObject, jboolean compressed, jlong ctx_l)
{ {
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
@ -186,10 +204,10 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
unsigned char outputSer[65]; unsigned char outputSer[65];
size_t outputLen = 65; size_t outputLen = compressed ? 33 : 65;
if( ret ) { if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED );(void)ret2;
} }
intsarray[0] = outputLen; intsarray[0] = outputLen;
@ -213,7 +231,7 @@ 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* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen, jboolean compressed)
{ {
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
const unsigned char* pubkeydata = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* pubkeydata = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
@ -227,10 +245,10 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, inputlen); int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, inputlen);
unsigned char outputSer[65]; unsigned char outputSer[65];
size_t outputLen = 65; size_t outputLen = compressed ? 33 : 65;
if( ret ) { if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, SECP256K1_EC_UNCOMPRESSED );(void)ret2; int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED );(void)ret2;
} }
intsarray[0] = outputLen; intsarray[0] = outputLen;
@ -412,7 +430,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1p
jbyteArray pubArray, intsByteArray; jbyteArray pubArray, intsByteArray;
unsigned char intsarray[2]; unsigned char intsarray[2];
unsigned char outputSer[65]; unsigned char outputSer[65];
size_t outputLen = 65; size_t outputLen = publen;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
@ -422,7 +440,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1p
} }
if( ret ) { if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, publen == 33 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);(void)ret2;
} }
intsarray[0] = outputLen; intsarray[0] = outputLen;
@ -456,7 +474,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1p
jbyteArray pubArray, intsByteArray; jbyteArray pubArray, intsByteArray;
unsigned char intsarray[2]; unsigned char intsarray[2];
unsigned char outputSer[65]; unsigned char outputSer[65];
size_t outputLen = 65; size_t outputLen = publen;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
@ -466,7 +484,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1p
} }
if( ret ) { if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, publen == 33 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);(void)ret2;
} }
intsarray[0] = outputLen; intsarray[0] = outputLen;
@ -501,7 +519,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p
secp256k1_pubkey pubkey1, pubkey2; secp256k1_pubkey pubkey1, pubkey2;
const secp256k1_pubkey *pubkeys[2]; const secp256k1_pubkey *pubkeys[2];
unsigned char outputSer[65]; unsigned char outputSer[65];
size_t outputLen = 65; size_t outputLen = publen1;
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey1, pubdata1, publen1); int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey1, pubdata1, publen1);
if (ret) { if (ret) {
@ -514,7 +532,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p
ret = secp256k1_ec_pubkey_combine(ctx, &result, pubkeys, 2); ret = secp256k1_ec_pubkey_combine(ctx, &result, pubkeys, 2);
} }
if (ret) { if (ret) {
ret = secp256k1_ec_pubkey_serialize(ctx, outputSer, &outputLen, &result, SECP256K1_EC_UNCOMPRESSED ); ret = secp256k1_ec_pubkey_serialize(ctx, outputSer, &outputLen, &result, publen1 == 33 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED );
} }
intsarray[0] = outputLen; intsarray[0] = outputLen;
intsarray[1] = ret; intsarray[1] = ret;
@ -588,7 +606,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
* Signature: (Ljava/nio/ByteBuffer;JI)[[B * Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/ */
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover
(JNIEnv *env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recid) (JNIEnv *env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recid, jboolean compressed)
{ {
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
const unsigned char* sigdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* sigdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
@ -596,7 +614,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa
secp256k1_ecdsa_recoverable_signature sig; secp256k1_ecdsa_recoverable_signature sig;
secp256k1_pubkey pub; secp256k1_pubkey pub;
unsigned char outputSer[65]; unsigned char outputSer[65];
size_t outputLen = 65; size_t outputLen = compressed ? 33 : 65;
jobjectArray retArray; jobjectArray retArray;
jbyteArray pubArray, intsByteArray; jbyteArray pubArray, intsByteArray;
unsigned char intsarray[1]; unsigned char intsarray[1];
@ -605,7 +623,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa
if (ret) { if (ret) {
ret = secp256k1_ecdsa_recover(ctx, &pub, &sig, msgdata); ret = secp256k1_ecdsa_recover(ctx, &pub, &sig, msgdata);
if (ret) { if (ret) {
ret = secp256k1_ec_pubkey_serialize(ctx, outputSer, &outputLen, &pub, SECP256K1_EC_UNCOMPRESSED ); ret = secp256k1_ec_pubkey_serialize(ctx, outputSer, &outputLen, &pub, compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED );
} }
} }

View File

@ -90,18 +90,18 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_sign * Method: secp256k1_ecdsa_sign
* Signature: (Ljava/nio/ByteBuffer;J)[[B * Signature: (Ljava/nio/ByteBuffer;ZJ)[[B
*/ */
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
(JNIEnv *, jclass, jobject, jlong); (JNIEnv *, jclass, jobject, jboolean, jlong);
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_sign_compact * Method: secp256k1_ecdsa_normalize
* Signature: (Ljava/nio/ByteBuffer;J)[[B * Signature: (Ljava/nio/ByteBuffer;I114:1ZJ)[[B
*/ */
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1normalize
(JNIEnv *, jclass, jobject, jlong); (JNIEnv *, jclass, jobject, jint, jboolean, jlong);
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
@ -114,18 +114,18 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ec_pubkey_create * Method: secp256k1_ec_pubkey_create
* Signature: (Ljava/nio/ByteBuffer;J)[[B * Signature: (Ljava/nio/ByteBuffer;ZJ)[[B
*/ */
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
(JNIEnv *, jclass, jobject, jlong); (JNIEnv *, jclass, jobject, jboolean, jlong);
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ec_pubkey_parse * Method: secp256k1_ec_pubkey_parse
* Signature: (Ljava/nio/ByteBuffer;JI)[[B * Signature: (Ljava/nio/ByteBuffer;JIZ)[[B
*/ */
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
(JNIEnv *, jclass, jobject, jlong, jint); (JNIEnv *, jclass, jobject, jlong, jint, jboolean);
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
@ -146,10 +146,10 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
/* /*
* Class: org_bitcoin_NativeSecp256k1 * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_recover * Method: secp256k1_ecdsa_recover
* Signature: (Ljava/nio/ByteBuffer;JI)[[B * Signature: (Ljava/nio/ByteBuffer;JIZ)[[B
*/ */
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover
(JNIEnv *, jclass, jobject, jlong, jint); (JNIEnv *, jclass, jobject, jlong, jint, jboolean);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -19,19 +19,23 @@ package fr.acinq.secp256k1
import kotlin.jvm.JvmStatic import kotlin.jvm.JvmStatic
import kotlin.jvm.Synchronized import kotlin.jvm.Synchronized
public enum class SigFormat(internal val size: Int) { COMPACT(64), DER(72) }
public enum class PubKeyFormat(internal val size: Int) { COMPRESSED(33), UNCOMPRESSED(65) }
public expect object Secp256k1 { public expect object Secp256k1 {
public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean
public fun sign(data: ByteArray, sec: ByteArray): ByteArray public fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray
public fun signCompact(data: ByteArray, sec: ByteArray): ByteArray public fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair<ByteArray, Boolean>
public fun secKeyVerify(seckey: ByteArray): Boolean public fun secKeyVerify(seckey: ByteArray): Boolean
public fun computePubkey(seckey: ByteArray): ByteArray public fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray
public fun parsePubkey(pubkey: ByteArray): ByteArray public fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray
public fun cleanup() public fun cleanup()
@ -51,7 +55,7 @@ public expect object Secp256k1 {
public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray
public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray
public fun randomize(seed: ByteArray): Boolean public fun randomize(seed: ByteArray): Boolean
} }

View File

@ -2,6 +2,7 @@ package fr.acinq.secp256k1
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -20,10 +21,10 @@ class Secp256k1Test {
val sig: ByteArray = Hex.decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()) val sig: ByteArray = Hex.decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()) val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
result = Secp256k1.verify(data, sig, pub) result = Secp256k1.verify(data, sig, pub)
assertEquals(result, true, "testVerifyPos") assertTrue(result, "testVerifyPos")
val sigCompact: ByteArray = Hex.decode("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()) val sigCompact: ByteArray = Hex.decode("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
result = Secp256k1.verify(data, sigCompact, pub) result = Secp256k1.verify(data, sigCompact, pub)
assertEquals(result, true, "testVerifyPos") assertTrue(result, "testVerifyPos")
} }
/** /**
@ -37,7 +38,7 @@ class Secp256k1Test {
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()) val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
result = Secp256k1.verify(data, sig, pub) result = Secp256k1.verify(data, sig, pub)
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
assertEquals(result, false, "testVerifyNeg") assertFalse(result, "testVerifyNeg")
} }
/** /**
@ -49,7 +50,7 @@ class Secp256k1Test {
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
result = Secp256k1.secKeyVerify(sec) result = Secp256k1.secKeyVerify(sec)
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
assertEquals(result, true, "testSecKeyVerifyPos") assertTrue(result, "testSecKeyVerifyPos")
} }
/** /**
@ -61,7 +62,7 @@ class Secp256k1Test {
val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()) val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase())
result = Secp256k1.secKeyVerify(sec) result = Secp256k1.secKeyVerify(sec)
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
assertEquals(result, false, "testSecKeyVerifyNeg") assertFalse(result, "testSecKeyVerifyNeg")
} }
/** /**
@ -70,11 +71,11 @@ class Secp256k1Test {
@Test @Test
fun testPubKeyCreatePos() { fun testPubKeyCreatePos() {
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
val resultArr: ByteArray = Secp256k1.computePubkey(sec) val resultArr: ByteArray = Secp256k1.computePubkey(sec, PubKeyFormat.UNCOMPRESSED)
val pubkeyString: String = Hex.encode(resultArr).toUpperCase() val pubkeyString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
pubkeyString,
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6", "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
pubkeyString,
"testPubKeyCreatePos" "testPubKeyCreatePos"
) )
} }
@ -85,26 +86,26 @@ class Secp256k1Test {
@Test @Test
fun testPubKeyCreateNeg() { fun testPubKeyCreateNeg() {
val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()) val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase())
val resultArr: ByteArray = Secp256k1.computePubkey(sec) val resultArr: ByteArray = Secp256k1.computePubkey(sec, PubKeyFormat.UNCOMPRESSED)
val pubkeyString: String = Hex.encode(resultArr).toUpperCase() val pubkeyString: String = Hex.encode(resultArr).toUpperCase()
assertEquals(pubkeyString, "", "testPubKeyCreateNeg") assertEquals("", pubkeyString, "testPubKeyCreateNeg")
} }
@Test @Test
fun testPubKeyNegatePos() { fun testPubKeyNegatePos() {
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
val pubkey: ByteArray = Secp256k1.computePubkey(sec) val pubkey: ByteArray = Secp256k1.computePubkey(sec, PubKeyFormat.UNCOMPRESSED)
val pubkeyString: String = Hex.encode(pubkey).toUpperCase() val pubkeyString: String = Hex.encode(pubkey).toUpperCase()
assertEquals( assertEquals(
pubkeyString,
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6", "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
pubkeyString,
"testPubKeyCreatePos" "testPubKeyCreatePos"
) )
val pubkey1: ByteArray = Secp256k1.pubKeyNegate(pubkey) val pubkey1: ByteArray = Secp256k1.pubKeyNegate(pubkey)
val pubkeyString1: String = Hex.encode(pubkey1).toUpperCase() val pubkeyString1: String = Hex.encode(pubkey1).toUpperCase()
assertEquals( assertEquals(
pubkeyString1,
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2DDEFC12B6B8E73968536514302E69ED1DDB24B999EFEE79C12D03AB17E79E1989", "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2DDEFC12B6B8E73968536514302E69ED1DDB24B999EFEE79C12D03AB17E79E1989",
pubkeyString1,
"testPubKeyNegatePos" "testPubKeyNegatePos"
) )
} }
@ -115,11 +116,11 @@ class Secp256k1Test {
@Test @Test
fun testPubKeyParse() { fun testPubKeyParse() {
val pub: ByteArray = Hex.decode("02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase()) val pub: ByteArray = Hex.decode("02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase())
val resultArr: ByteArray = Secp256k1.parsePubkey(pub) val resultArr: ByteArray = Secp256k1.parsePubkey(pub, PubKeyFormat.UNCOMPRESSED)
val pubkeyString: String = Hex.encode(resultArr).toUpperCase() val pubkeyString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
pubkeyString,
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6", "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
pubkeyString,
"testPubKeyAdd" "testPubKeyAdd"
) )
} }
@ -131,8 +132,8 @@ class Secp256k1Test {
val pub3: ByteArray = Secp256k1.pubKeyAdd(pub1, pub2) val pub3: ByteArray = Secp256k1.pubKeyAdd(pub1, pub2)
val pubkeyString: String = Hex.encode(pub3).toUpperCase() val pubkeyString: String = Hex.encode(pub3).toUpperCase()
assertEquals( assertEquals(
pubkeyString,
"04531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE3379E92C265E71E481BA82A84675A47AC705A200FCD524E92D93B0E7386F26A5458", "04531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE3379E92C265E71E481BA82A84675A47AC705A200FCD524E92D93B0E7386F26A5458",
pubkeyString,
"testPubKeyAdd" "testPubKeyAdd"
) )
} }
@ -144,15 +145,28 @@ class Secp256k1Test {
fun testSignPos() { fun testSignPos() {
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing" val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
val resultArr: ByteArray = Secp256k1.sign(data, sec) val resultArr: ByteArray = Secp256k1.sign(data, sec, SigFormat.DER)
val sigString: String = Hex.encode(resultArr).toUpperCase() val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
sigString,
"30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9", "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
sigString,
"testSignPos" "testSignPos"
) )
} }
@Test
fun testSignatureNormalize() {
val data: ByteArray = Hex.decode("30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9".toLowerCase())
val (resultArr, isHighS) = Secp256k1.signatureNormalize(data, SigFormat.COMPACT)
val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals(
"182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A21C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
sigString,
"testSignPos"
)
assertFalse(isHighS, "isHighS")
}
/** /**
* This tests sign() for a invalid secretkey * This tests sign() for a invalid secretkey
*/ */
@ -160,20 +174,20 @@ class Secp256k1Test {
fun testSignNeg() { fun testSignNeg() {
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing" val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()) val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase())
val resultArr: ByteArray = Secp256k1.sign(data, sec) val resultArr: ByteArray = Secp256k1.sign(data, sec, SigFormat.DER)
val sigString: String = Hex.encode(resultArr) val sigString: String = Hex.encode(resultArr)
assertEquals(sigString, "", "testSignNeg") assertEquals("", sigString, "testSignNeg")
} }
@Test @Test
fun testSignCompactPos() { fun testSignCompactPos() {
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing" val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
val resultArr: ByteArray = Secp256k1.signCompact(data, sec) val resultArr: ByteArray = Secp256k1.sign(data, sec, SigFormat.COMPACT)
val sigString: String = Hex.encode(resultArr).toUpperCase() val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
sigString,
"182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A21C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9", "182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A21C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
sigString,
"testSignCompactPos" "testSignCompactPos"
) )
//assertEquals( sigString, "30 44 02 20 182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A2 02 20 1C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); //assertEquals( sigString, "30 44 02 20 182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A2 02 20 1C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
@ -184,8 +198,8 @@ class Secp256k1Test {
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
val sec1: ByteArray = Secp256k1.privKeyNegate(sec) val sec1: ByteArray = Secp256k1.privKeyNegate(sec)
assertEquals( assertEquals(
Hex.encode(sec1).toUpperCase(),
"981A9A7DD677A622518DA068D66D5F824E5F22F084B8A0E2F195B5662F300C11", "981A9A7DD677A622518DA068D66D5F824E5F22F084B8A0E2F195B5662F300C11",
Hex.encode(sec1).toUpperCase(),
"testPrivKeyNegate" "testPrivKeyNegate"
) )
val sec2: ByteArray = Secp256k1.privKeyNegate(sec1) val sec2: ByteArray = Secp256k1.privKeyNegate(sec1)
@ -201,7 +215,11 @@ class Secp256k1Test {
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak" val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
val resultArr: ByteArray = Secp256k1.privKeyTweakAdd(sec, data) val resultArr: ByteArray = Secp256k1.privKeyTweakAdd(sec, data)
val sigString: String = Hex.encode(resultArr).toUpperCase() val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals(sigString, "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3", "testPrivKeyAdd_1") assertEquals(
"A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3",
sigString,
"testPrivKeyAdd_1"
)
} }
/** /**
@ -213,7 +231,11 @@ class Secp256k1Test {
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak" val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
val resultArr: ByteArray = Secp256k1.privKeyTweakMul(sec, data) val resultArr: ByteArray = Secp256k1.privKeyTweakMul(sec, data)
val sigString: String = Hex.encode(resultArr).toUpperCase() val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals(sigString, "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC", "testPrivKeyMul_1") assertEquals(
"97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC",
sigString,
"testPrivKeyMul_1"
)
} }
/** /**
@ -226,8 +248,8 @@ class Secp256k1Test {
val resultArr: ByteArray = Secp256k1.pubKeyTweakAdd(pub, data) val resultArr: ByteArray = Secp256k1.pubKeyTweakAdd(pub, data)
val sigString: String = Hex.encode(resultArr).toUpperCase() val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
sigString,
"0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF", "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF",
sigString,
"testPrivKeyAdd_2" "testPrivKeyAdd_2"
) )
} }
@ -242,8 +264,8 @@ class Secp256k1Test {
val resultArr: ByteArray = Secp256k1.pubKeyTweakMul(pub, data) val resultArr: ByteArray = Secp256k1.pubKeyTweakMul(pub, data)
val sigString: String = Hex.encode(resultArr).toUpperCase() val sigString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
sigString,
"04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589", "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589",
sigString,
"testPrivKeyMul_2" "testPrivKeyMul_2"
) )
} }
@ -255,7 +277,7 @@ class Secp256k1Test {
fun testRandomize() { fun testRandomize() {
val seed: ByteArray = Hex.decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()) //sha256hash of "random" val seed: ByteArray = Hex.decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()) //sha256hash of "random"
val result: Boolean = Secp256k1.randomize(seed) val result: Boolean = Secp256k1.randomize(seed)
assertEquals(result, true, "testRandomize") assertTrue(result, "testRandomize")
} }
@Test @Test
@ -265,8 +287,8 @@ class Secp256k1Test {
val resultArr: ByteArray = Secp256k1.createECDHSecret(sec, pub) val resultArr: ByteArray = Secp256k1.createECDHSecret(sec, pub)
val ecdhString: String = Hex.encode(resultArr).toUpperCase() val ecdhString: String = Hex.encode(resultArr).toUpperCase()
assertEquals( assertEquals(
ecdhString,
"2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043", "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043",
ecdhString,
"testCreateECDHSecret" "testCreateECDHSecret"
) )
} }
@ -275,10 +297,10 @@ class Secp256k1Test {
fun testEcdsaRecover() { fun testEcdsaRecover() {
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing" val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()) val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
val pub: ByteArray = Secp256k1.computePubkey(sec) val pub: ByteArray = Secp256k1.computePubkey(sec, PubKeyFormat.UNCOMPRESSED)
val sig: ByteArray = Secp256k1.signCompact(data, sec) val sig: ByteArray = Secp256k1.sign(data, sec, SigFormat.COMPACT)
val pub0: ByteArray = Secp256k1.ecdsaRecover(sig, data, 0) val pub0: ByteArray = Secp256k1.ecdsaRecover(sig, data, 0, PubKeyFormat.UNCOMPRESSED)
val pub1: ByteArray = Secp256k1.ecdsaRecover(sig, data, 1) val pub1: ByteArray = Secp256k1.ecdsaRecover(sig, data, 1, PubKeyFormat.UNCOMPRESSED)
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1), "testEcdsaRecover") assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1), "testEcdsaRecover")
} }
} }

View File

@ -30,15 +30,15 @@ public actual object Secp256k1 {
public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean = NativeSecp256k1.verify(data, signature, pub) public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean = NativeSecp256k1.verify(data, signature, pub)
public actual fun sign(data: ByteArray, sec: ByteArray): ByteArray = NativeSecp256k1.sign(data, sec) public actual fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray = NativeSecp256k1.sign(data, sec, format == SigFormat.COMPACT)
public actual fun signCompact(data: ByteArray, sec: ByteArray): ByteArray = NativeSecp256k1.signCompact(data, sec) public actual fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair<ByteArray, Boolean> = NativeSecp256k1.signatureNormalize(sig, format == SigFormat.COMPACT)
public actual fun secKeyVerify(seckey: ByteArray): Boolean = NativeSecp256k1.secKeyVerify(seckey) public actual fun secKeyVerify(seckey: ByteArray): Boolean = NativeSecp256k1.secKeyVerify(seckey)
public actual fun computePubkey(seckey: ByteArray): ByteArray = NativeSecp256k1.computePubkey(seckey) public actual fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray = NativeSecp256k1.computePubkey(seckey, format == PubKeyFormat.COMPRESSED)
public actual fun parsePubkey(pubkey: ByteArray): ByteArray = NativeSecp256k1.parsePubkey(pubkey) public actual fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray = NativeSecp256k1.parsePubkey(pubkey, format == PubKeyFormat.COMPRESSED)
public actual fun cleanup(): Unit = NativeSecp256k1.cleanup() public actual fun cleanup(): Unit = NativeSecp256k1.cleanup()
@ -58,7 +58,7 @@ public actual object Secp256k1 {
public actual fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray = NativeSecp256k1.createECDHSecret(seckey, pubkey) public actual fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray = NativeSecp256k1.createECDHSecret(seckey, pubkey)
public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray = NativeSecp256k1.ecdsaRecover(sig, message, recid) public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray = NativeSecp256k1.ecdsaRecover(sig, message, recid, format == PubKeyFormat.COMPRESSED)
public actual fun randomize(seed: ByteArray): Boolean = NativeSecp256k1.randomize(seed) public actual fun randomize(seed: ByteArray): Boolean = NativeSecp256k1.randomize(seed)

View File

@ -94,12 +94,13 @@ public object NativeSecp256k1 {
* *
* @param data Message hash, 32 bytes * @param data Message hash, 32 bytes
* @param sec Secret key, 32 bytes * @param sec Secret key, 32 bytes
* @param compact True for compact signature, false for DER
* @return a signature, or an empty array is signing failed * @return a signature, or an empty array is signing failed
* @throws AssertFailException in case of failure * @throws AssertFailException in case of failure
*/ */
@JvmStatic @JvmStatic
@Throws(AssertFailException::class) @Throws(AssertFailException::class)
public fun sign(data: ByteArray, sec: ByteArray): ByteArray { public fun sign(data: ByteArray, sec: ByteArray, compact: Boolean): ByteArray {
require(data.size == 32 && sec.size <= 32) require(data.size == 32 && sec.size <= 32)
val byteBuff = pack(data, sec) val byteBuff = pack(data, sec)
val retByteArray: Array<ByteArray> val retByteArray: Array<ByteArray>
@ -107,6 +108,7 @@ public object NativeSecp256k1 {
retByteArray = try { retByteArray = try {
secp256k1_ecdsa_sign( secp256k1_ecdsa_sign(
byteBuff, byteBuff,
compact,
Secp256k1Context.getContext() Secp256k1Context.getContext()
) )
} finally { } finally {
@ -123,27 +125,18 @@ public object NativeSecp256k1 {
return if (retVal == 0) ByteArray(0) else sigArr return if (retVal == 0) ByteArray(0) else sigArr
} }
/**
* libsecp256k1 Create an ECDSA signature.
*
* @param data Message hash, 32 bytes
* @param sec Secret key, 32 bytes
*
*
* Return values
* @return a signature, or an empty array is signing failed
* @throws AssertFailException in case of failure
*/
@JvmStatic @JvmStatic
@Throws(AssertFailException::class) @Throws(AssertFailException::class)
public fun signCompact(data: ByteArray, sec: ByteArray): ByteArray { public fun signatureNormalize(sig: ByteArray, compact: Boolean): Pair<ByteArray, Boolean> {
require(data.size == 32 && sec.size <= 32) require(sig.size == 64 || sig.size in 70..73)
val byteBuff = pack(data, sec) val byteBuff = pack(sig)
val retByteArray: Array<ByteArray> val retByteArray: Array<ByteArray>
r.lock() r.lock()
retByteArray = try { retByteArray = try {
secp256k1_ecdsa_sign_compact( secp256k1_ecdsa_normalize(
byteBuff, byteBuff,
sig.size,
compact,
Secp256k1Context.getContext() Secp256k1Context.getContext()
) )
} finally { } finally {
@ -152,12 +145,13 @@ public object NativeSecp256k1 {
val sigArr = retByteArray[0] val sigArr = retByteArray[0]
val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
val retBool = BigInteger(byteArrayOf(retByteArray[1][2])).toInt()
NativeSecp256k1Util.assertEquals( NativeSecp256k1Util.assertEquals(
sigArr.size, sigArr.size,
sigLen, sigLen,
"Got bad signature length." "Got bad signature length."
) )
return if (retVal == 0) ByteArray(0) else sigArr return (if (retVal == 0) ByteArray(0) else sigArr) to (retBool == 1)
} }
/** /**
@ -191,7 +185,7 @@ public object NativeSecp256k1 {
//TODO add a 'compressed' arg //TODO add a 'compressed' arg
@JvmStatic @JvmStatic
@Throws(AssertFailException::class) @Throws(AssertFailException::class)
public fun computePubkey(seckey: ByteArray): ByteArray { public fun computePubkey(seckey: ByteArray, compressed: Boolean): ByteArray {
require(seckey.size == 32) require(seckey.size == 32)
val byteBuff = pack(seckey) val byteBuff = pack(seckey)
val retByteArray: Array<ByteArray> val retByteArray: Array<ByteArray>
@ -199,6 +193,7 @@ public object NativeSecp256k1 {
retByteArray = try { retByteArray = try {
secp256k1_ec_pubkey_create( secp256k1_ec_pubkey_create(
byteBuff, byteBuff,
compressed,
Secp256k1Context.getContext() Secp256k1Context.getContext()
) )
} finally { } finally {
@ -218,7 +213,7 @@ public object NativeSecp256k1 {
*/ */
@JvmStatic @JvmStatic
@Throws(AssertFailException::class) @Throws(AssertFailException::class)
public fun parsePubkey(pubkey: ByteArray): ByteArray { public fun parsePubkey(pubkey: ByteArray, compressed: Boolean): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
val byteBuff = pack(pubkey) val byteBuff = pack(pubkey)
val retByteArray: Array<ByteArray> val retByteArray: Array<ByteArray>
@ -227,7 +222,8 @@ public object NativeSecp256k1 {
secp256k1_ec_pubkey_parse( secp256k1_ec_pubkey_parse(
byteBuff, byteBuff,
Secp256k1Context.getContext(), Secp256k1Context.getContext(),
pubkey.size pubkey.size,
compressed
) )
} finally { } finally {
r.unlock() r.unlock()
@ -235,7 +231,7 @@ public object NativeSecp256k1 {
val pubArr = retByteArray[0] val pubArr = retByteArray[0]
BigInteger(byteArrayOf(retByteArray[1][0])).toInt() BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
NativeSecp256k1Util.assertEquals(pubArr.size, 65, "Got bad pubkey length.") NativeSecp256k1Util.assertEquals(pubArr.size, if (compressed) 33 else 65, "Got bad pubkey length.")
return if (retVal == 0) ByteArray(0) else pubArr return if (retVal == 0) ByteArray(0) else pubArr
} }
@ -456,7 +452,7 @@ public object NativeSecp256k1 {
val pubArr = retByteArray[0] val pubArr = retByteArray[0]
val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
NativeSecp256k1Util.assertEquals(65, pubLen, "Got bad pubkey length.") NativeSecp256k1Util.assertEquals(pubkey1.size, pubLen, "Got bad pubkey length.")
NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.")
return pubArr return pubArr
} }
@ -494,7 +490,7 @@ public object NativeSecp256k1 {
@JvmStatic @JvmStatic
@Throws(AssertFailException::class) @Throws(AssertFailException::class)
public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray { public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, compressed: Boolean): ByteArray {
require(sig.size == 64) require(sig.size == 64)
require(message.size == 32) require(message.size == 32)
val byteBuff = pack(sig, message) val byteBuff = pack(sig, message)
@ -504,14 +500,15 @@ public object NativeSecp256k1 {
secp256k1_ecdsa_recover( secp256k1_ecdsa_recover(
byteBuff, byteBuff,
Secp256k1Context.getContext(), Secp256k1Context.getContext(),
recid recid,
compressed
) )
} finally { } finally {
r.unlock() r.unlock()
} }
val resArr = retByteArray[0] val resArr = retByteArray[0]
val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
NativeSecp256k1Util.assertEquals(resArr.size, 65, "Got bad result length.") NativeSecp256k1Util.assertEquals(resArr.size, if (compressed) 33 else 65, "Got bad result length.")
NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.")
return resArr return resArr
} }
@ -549,23 +546,12 @@ public object NativeSecp256k1 {
@JvmStatic private external fun secp256k1_pubkey_tweak_mul(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array<ByteArray> @JvmStatic private external fun secp256k1_pubkey_tweak_mul(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array<ByteArray>
@JvmStatic private external fun secp256k1_destroy_context(context: Long) @JvmStatic private external fun secp256k1_destroy_context(context: Long)
@JvmStatic private external fun secp256k1_ecdsa_verify(byteBuff: ByteBuffer, context: Long, sigLen: Int, pubLen: Int): Int @JvmStatic private external fun secp256k1_ecdsa_verify(byteBuff: ByteBuffer, context: Long, sigLen: Int, pubLen: Int): Int
@JvmStatic private external fun secp256k1_ecdsa_sign(byteBuff: ByteBuffer, context: Long): Array<ByteArray> @JvmStatic private external fun secp256k1_ecdsa_sign(byteBuff: ByteBuffer, compact: Boolean, context: Long): Array<ByteArray>
@JvmStatic private external fun secp256k1_ecdsa_sign_compact(byteBuff: ByteBuffer, context: Long): Array<ByteArray> @JvmStatic private external fun secp256k1_ecdsa_normalize(byteBuff: ByteBuffer, sigLen: Int, compact: Boolean, context: Long): Array<ByteArray>
@JvmStatic private external fun secp256k1_ec_seckey_verify(byteBuff: ByteBuffer, context: Long): Int @JvmStatic private external fun secp256k1_ec_seckey_verify(byteBuff: ByteBuffer, context: Long): Int
@JvmStatic private external fun secp256k1_ec_pubkey_create(byteBuff: ByteBuffer, context: Long): Array<ByteArray> @JvmStatic private external fun secp256k1_ec_pubkey_create(byteBuff: ByteBuffer, compressed: Boolean, context: Long): Array<ByteArray>
@JvmStatic private external fun secp256k1_ec_pubkey_parse( @JvmStatic private external fun secp256k1_ec_pubkey_parse(byteBuff: ByteBuffer, context: Long, inputLen: Int, compressed: Boolean): Array<ByteArray>
byteBuff: ByteBuffer, @JvmStatic private external fun secp256k1_ec_pubkey_add(byteBuff: ByteBuffer, context: Long, lent1: Int, len2: Int): Array<ByteArray>
context: Long,
inputLen: Int
): Array<ByteArray>
@JvmStatic private external fun secp256k1_ec_pubkey_add(
byteBuff: ByteBuffer,
context: Long,
lent1: Int,
len2: Int
): Array<ByteArray>
@JvmStatic private external fun secp256k1_ecdh(byteBuff: ByteBuffer, context: Long, inputLen: Int): Array<ByteArray> @JvmStatic private external fun secp256k1_ecdh(byteBuff: ByteBuffer, context: Long, inputLen: Int): Array<ByteArray>
@JvmStatic private external fun secp256k1_ecdsa_recover(byteBuff: ByteBuffer, context: Long, recid: Int): Array<ByteArray> @JvmStatic private external fun secp256k1_ecdsa_recover(byteBuff: ByteBuffer, context: Long, recid: Int, compressed: Boolean): Array<ByteArray>
} }

View File

@ -7,10 +7,6 @@ import secp256k1.*
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
public actual object Secp256k1 { public actual object Secp256k1 {
private const val SIG_FORMAT_UNKNOWN = 0
private const val SIG_FORMAT_COMPACT = 1
private const val SIG_FORMAT_DER = 2
private val ctx: CPointer<secp256k1_context> by lazy { 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()) secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt())
?: error("Could not create segp256k1 context") ?: error("Could not create segp256k1 context")
@ -19,22 +15,34 @@ public actual object Secp256k1 {
private fun Int.requireSuccess() = require(this == 1) { "secp256k1 native function call failed" } private fun Int.requireSuccess() = require(this == 1) { "secp256k1 native function call failed" }
private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature { private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature {
val sigFormat = when (input.size) {
64 -> SIG_FORMAT_COMPACT
70, 71, 72, 73 -> SIG_FORMAT_DER
else -> SIG_FORMAT_UNKNOWN
}
val sig = alloc<secp256k1_ecdsa_signature>() val sig = alloc<secp256k1_ecdsa_signature>()
val nativeBytes = toNat(input) val nativeBytes = toNat(input)
val result = when (sigFormat) {
SIG_FORMAT_COMPACT -> secp256k1_ecdsa_signature_parse_compact(ctx, sig.ptr, nativeBytes) val result = when (input.size) {
SIG_FORMAT_DER -> secp256k1_ecdsa_signature_parse_der(ctx, sig.ptr, nativeBytes, input.size.toULong()) 64 -> secp256k1_ecdsa_signature_parse_compact(ctx, sig.ptr, nativeBytes)
else -> 0 in 70..73 -> secp256k1_ecdsa_signature_parse_der(ctx, sig.ptr, nativeBytes, input.size.convert())
else -> error("Unknown signature format")
} }
require(result == 1) { "cannot parse signature (size = ${input.size}, format = $sigFormat sig = ${Hex.encode(input)}" } require(result == 1) { "cannot parse signature (size = ${input.size} sig = ${Hex.encode(input)}" }
return sig return sig
} }
private fun MemScope.serializeSignature(signature: secp256k1_ecdsa_signature, format: SigFormat): ByteArray {
val natOutput = allocArray<UByteVar>(format.size)
when (format) {
SigFormat.DER -> {
val outputLen = alloc<size_tVar>()
outputLen.value = 72.convert()
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, outputLen.ptr, signature.ptr).requireSuccess()
return natOutput.readBytes(outputLen.value.toInt())
}
SigFormat.COMPACT -> {
secp256k1_ecdsa_signature_serialize_compact(ctx, natOutput, signature.ptr).requireSuccess()
return natOutput.readBytes(64)
}
}
}
private fun MemScope.allocPublicKey(pubkey: ByteArray): secp256k1_pubkey { private fun MemScope.allocPublicKey(pubkey: ByteArray): secp256k1_pubkey {
val natPub = toNat(pubkey) val natPub = toNat(pubkey)
val pub = alloc<secp256k1_pubkey>() val pub = alloc<secp256k1_pubkey>()
@ -61,68 +69,59 @@ public actual object Secp256k1 {
require(data.size == 32) require(data.size == 32)
require(pub.size == 33 || pub.size == 65) require(pub.size == 33 || pub.size == 65)
memScoped { memScoped {
val pubkey = allocPublicKey(pub) val nPubkey = allocPublicKey(pub)
val natData = toNat(data) val nData = toNat(data)
val parsedSig = allocSignature(signature) val nSig = allocSignature(signature)
return secp256k1_ecdsa_verify(ctx, parsedSig.ptr, natData, pubkey.ptr) == 1 return secp256k1_ecdsa_verify(ctx, nSig.ptr, nData, nPubkey.ptr) == 1
} }
} }
public actual fun sign(data: ByteArray, sec: ByteArray): ByteArray { public actual fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray {
require(sec.size == 32) require(sec.size == 32)
require(data.size == 32) require(data.size == 32)
memScoped { memScoped {
val natSec = toNat(sec) val nSec = toNat(sec)
val natData = toNat(data) val nData = toNat(data)
val natSig = alloc<secp256k1_ecdsa_signature>() val nSig = alloc<secp256k1_ecdsa_signature>()
val result = secp256k1_ecdsa_sign(ctx, natSig.ptr, natData, natSec, null, null) val result = secp256k1_ecdsa_sign(ctx, nSig.ptr, nData, nSec, null, null)
if (result == 0) return ByteArray(0) if (result == 0) return ByteArray(0)
val natOutput = allocArray<UByteVar>(72) return serializeSignature(nSig, format)
val outputLen = alloc<size_tVar>()
outputLen.value = 72.convert()
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, outputLen.ptr, natSig.ptr).requireSuccess()
return natOutput.readBytes(outputLen.value.toInt())
} }
} }
public actual fun signCompact(data: ByteArray, sec: ByteArray): ByteArray { public actual fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair<ByteArray, Boolean> {
require(data.size == 32) require(sig.size == 64 || sig.size in 70..73)
require(sec.size <= 32)
memScoped { memScoped {
val natSec = toNat(sec) val nSig = allocSignature(sig)
val natData = toNat(data) val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
val natSig = alloc<secp256k1_ecdsa_signature>() return Pair(serializeSignature(nSig, format), isHighS == 1)
secp256k1_ecdsa_sign(ctx, natSig.ptr, natData, natSec, null, null).requireSuccess()
val natCompact = allocArray<UByteVar>(64)
secp256k1_ecdsa_signature_serialize_compact(ctx, natCompact, natSig.ptr).requireSuccess()
return natCompact.readBytes(64)
} }
} }
public actual fun secKeyVerify(seckey: ByteArray): Boolean { public actual fun secKeyVerify(seckey: ByteArray): Boolean {
require(seckey.size == 32) require(seckey.size == 32)
memScoped { memScoped {
val natSec = toNat(seckey) val nSec = toNat(seckey)
return secp256k1_ec_seckey_verify(ctx, natSec) == 1 return secp256k1_ec_seckey_verify(ctx, nSec) == 1
} }
} }
public actual fun computePubkey(seckey: ByteArray): ByteArray { public actual fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray {
require(seckey.size == 32) require(seckey.size == 32)
memScoped { memScoped {
val natSec = toNat(seckey) val nSec = toNat(seckey)
val pubkey = alloc<secp256k1_pubkey>() val nPubkey = alloc<secp256k1_pubkey>()
val result = secp256k1_ec_pubkey_create(ctx, pubkey.ptr, natSec) val result = secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nSec)
if (result == 0) return ByteArray(0) if (result == 0) return ByteArray(0)
return serializePubkey(pubkey, 65) return serializePubkey(nPubkey, format.size)
} }
} }
public actual fun parsePubkey(pubkey: ByteArray): ByteArray { public actual fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
return serializePubkey(nPubkey, 65) return serializePubkey(nPubkey, format.size)
} }
} }
@ -177,7 +176,7 @@ public actual object Secp256k1 {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nTweak = toNat(tweak) val nTweak = toNat(tweak)
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess() secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess()
return serializePubkey(nPubkey, 65) return serializePubkey(nPubkey, pubkey.size)
} }
} }
@ -187,18 +186,19 @@ public actual object Secp256k1 {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nTweak = toNat(tweak) val nTweak = toNat(tweak)
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess() secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess()
return serializePubkey(nPubkey, 65) return serializePubkey(nPubkey, pubkey.size)
} }
} }
public actual fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { public actual fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray {
require(pubkey1.size == 33 || pubkey2.size == 65) require(pubkey1.size == 33 || pubkey1.size == 65)
require(pubkey2.size == 33 || pubkey2.size == 65)
memScoped { memScoped {
val nPubkey1 = allocPublicKey(pubkey1) val nPubkey1 = allocPublicKey(pubkey1)
val nPubkey2 = allocPublicKey(pubkey2) val nPubkey2 = allocPublicKey(pubkey2)
val combined = nativeHeap.alloc<secp256k1_pubkey>() val combined = alloc<secp256k1_pubkey>()
secp256k1_ec_pubkey_combine(ctx, combined.ptr, cValuesOf(nPubkey1.ptr, nPubkey2.ptr), 2.convert()).requireSuccess() secp256k1_ec_pubkey_combine(ctx, combined.ptr, cValuesOf(nPubkey1.ptr, nPubkey2.ptr), 2.convert()).requireSuccess()
return serializePubkey(combined, 65) return serializePubkey(combined, pubkey1.size)
} }
} }
@ -214,17 +214,17 @@ public actual object Secp256k1 {
} }
} }
public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray { public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray {
require(sig.size == 64) require(sig.size == 64)
require(message.size == 32) require(message.size == 32)
memScoped { memScoped {
val nSig = toNat(sig) val nSig = toNat(sig)
val rSig = nativeHeap.alloc<secp256k1_ecdsa_recoverable_signature>() 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(ctx, rSig.ptr, nSig, recid).requireSuccess()
val nMessage = toNat(message) val nMessage = toNat(message)
val pubkey = nativeHeap.alloc<secp256k1_pubkey>() val pubkey = alloc<secp256k1_pubkey>()
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess() secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess()
return serializePubkey(pubkey, 65) return serializePubkey(pubkey, format.size)
} }
} }