Explicit Signature & PubKey formats + bug fixes
This commit is contained in:
parent
b67cafed38
commit
4bdc836556
@ -4,7 +4,7 @@ plugins {
|
||||
`maven-publish`
|
||||
}
|
||||
group = "fr.acinq.secp256k1"
|
||||
version = "0.1.0-1.4-M2"
|
||||
version = "0.2.0-1.4-M2"
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
|
@ -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
|
||||
(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;
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
@ -91,10 +91,14 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
||||
int ret = secp256k1_ecdsa_sign(ctx, &sig, data, secKey, NULL, NULL);
|
||||
|
||||
unsigned char outputSer[72];
|
||||
size_t outputLen = 72;
|
||||
size_t outputLen = compact ? 64 : 72;
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, &sig ); (void)ret2;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
@ -117,30 +121,44 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
||||
return retArray;
|
||||
}
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1normalize
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jint siglen, jboolean compact, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||
unsigned char* sigdata = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
jobjectArray retArray;
|
||||
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];
|
||||
size_t outputLen = 64;
|
||||
int ret2 = 0;
|
||||
if (ret) {
|
||||
ret2 = secp256k1_ecdsa_signature_normalize(ctx, &sig, &sig);
|
||||
}
|
||||
|
||||
unsigned char outputSer[72];
|
||||
size_t outputLen = compact ? 64 : 72;
|
||||
|
||||
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[1] = ret;
|
||||
intsarray[2] = ret2;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*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)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
intsByteArray = (*env)->NewByteArray(env, 3);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 3, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
@ -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
|
||||
(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;
|
||||
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);
|
||||
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
size_t outputLen = compressed ? 33 : 65;
|
||||
|
||||
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;
|
||||
@ -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
|
||||
(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;
|
||||
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);
|
||||
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
size_t outputLen = compressed ? 33 : 65;
|
||||
|
||||
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;
|
||||
@ -412,7 +430,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1p
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
size_t outputLen = publen;
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
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 ) {
|
||||
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;
|
||||
@ -456,7 +474,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1p
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
size_t outputLen = publen;
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
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 ) {
|
||||
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;
|
||||
@ -501,7 +519,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p
|
||||
secp256k1_pubkey pubkey1, pubkey2;
|
||||
const secp256k1_pubkey *pubkeys[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
size_t outputLen = publen1;
|
||||
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey1, pubdata1, publen1);
|
||||
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);
|
||||
}
|
||||
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[1] = ret;
|
||||
@ -588,7 +606,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
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;
|
||||
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_pubkey pub;
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
size_t outputLen = compressed ? 33 : 65;
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[1];
|
||||
@ -605,7 +623,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa
|
||||
if (ret) {
|
||||
ret = secp256k1_ecdsa_recover(ctx, &pub, &sig, msgdata);
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,18 +90,18 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* 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
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
(JNIEnv *, jclass, jobject, jboolean, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_sign_compact
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
* Method: secp256k1_ecdsa_normalize
|
||||
* Signature: (Ljava/nio/ByteBuffer;I114:1ZJ)[[B
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1normalize
|
||||
(JNIEnv *, jclass, jobject, jint, jboolean, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
@ -114,18 +114,18 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* 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
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
(JNIEnv *, jclass, jobject, jboolean, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* 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
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
(JNIEnv *, jclass, jobject, jlong, jint, jboolean);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
@ -146,10 +146,10 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* 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
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
(JNIEnv *, jclass, jobject, jlong, jint, jboolean);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -19,19 +19,23 @@ package fr.acinq.secp256k1
|
||||
import kotlin.jvm.JvmStatic
|
||||
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 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 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()
|
||||
|
||||
@ -51,7 +55,7 @@ public expect object Secp256k1 {
|
||||
|
||||
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
|
||||
}
|
@ -2,6 +2,7 @@ package fr.acinq.secp256k1
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
|
||||
@ -20,10 +21,10 @@ class Secp256k1Test {
|
||||
val sig: ByteArray = Hex.decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
|
||||
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
|
||||
result = Secp256k1.verify(data, sig, pub)
|
||||
assertEquals(result, true, "testVerifyPos")
|
||||
assertTrue(result, "testVerifyPos")
|
||||
val sigCompact: ByteArray = Hex.decode("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
|
||||
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())
|
||||
result = Secp256k1.verify(data, sig, pub)
|
||||
//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())
|
||||
result = Secp256k1.secKeyVerify(sec)
|
||||
//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())
|
||||
result = Secp256k1.secKeyVerify(sec)
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals(result, false, "testSecKeyVerifyNeg")
|
||||
assertFalse(result, "testSecKeyVerifyNeg")
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,11 +71,11 @@ class Secp256k1Test {
|
||||
@Test
|
||||
fun testPubKeyCreatePos() {
|
||||
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()
|
||||
assertEquals(
|
||||
pubkeyString,
|
||||
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
|
||||
pubkeyString,
|
||||
"testPubKeyCreatePos"
|
||||
)
|
||||
}
|
||||
@ -85,26 +86,26 @@ class Secp256k1Test {
|
||||
@Test
|
||||
fun testPubKeyCreateNeg() {
|
||||
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()
|
||||
assertEquals(pubkeyString, "", "testPubKeyCreateNeg")
|
||||
assertEquals("", pubkeyString, "testPubKeyCreateNeg")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPubKeyNegatePos() {
|
||||
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()
|
||||
assertEquals(
|
||||
pubkeyString,
|
||||
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
|
||||
pubkeyString,
|
||||
"testPubKeyCreatePos"
|
||||
)
|
||||
val pubkey1: ByteArray = Secp256k1.pubKeyNegate(pubkey)
|
||||
val pubkeyString1: String = Hex.encode(pubkey1).toUpperCase()
|
||||
assertEquals(
|
||||
pubkeyString1,
|
||||
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2DDEFC12B6B8E73968536514302E69ED1DDB24B999EFEE79C12D03AB17E79E1989",
|
||||
pubkeyString1,
|
||||
"testPubKeyNegatePos"
|
||||
)
|
||||
}
|
||||
@ -115,11 +116,11 @@ class Secp256k1Test {
|
||||
@Test
|
||||
fun testPubKeyParse() {
|
||||
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()
|
||||
assertEquals(
|
||||
pubkeyString,
|
||||
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
|
||||
pubkeyString,
|
||||
"testPubKeyAdd"
|
||||
)
|
||||
}
|
||||
@ -131,8 +132,8 @@ class Secp256k1Test {
|
||||
val pub3: ByteArray = Secp256k1.pubKeyAdd(pub1, pub2)
|
||||
val pubkeyString: String = Hex.encode(pub3).toUpperCase()
|
||||
assertEquals(
|
||||
pubkeyString,
|
||||
"04531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE3379E92C265E71E481BA82A84675A47AC705A200FCD524E92D93B0E7386F26A5458",
|
||||
pubkeyString,
|
||||
"testPubKeyAdd"
|
||||
)
|
||||
}
|
||||
@ -144,15 +145,28 @@ class Secp256k1Test {
|
||||
fun testSignPos() {
|
||||
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||
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()
|
||||
assertEquals(
|
||||
sigString,
|
||||
"30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
|
||||
sigString,
|
||||
"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
|
||||
*/
|
||||
@ -160,20 +174,20 @@ class Secp256k1Test {
|
||||
fun testSignNeg() {
|
||||
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||
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)
|
||||
assertEquals(sigString, "", "testSignNeg")
|
||||
assertEquals("", sigString, "testSignNeg")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSignCompactPos() {
|
||||
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||
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()
|
||||
assertEquals(
|
||||
sigString,
|
||||
"182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A21C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
|
||||
sigString,
|
||||
"testSignCompactPos"
|
||||
)
|
||||
//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 sec1: ByteArray = Secp256k1.privKeyNegate(sec)
|
||||
assertEquals(
|
||||
Hex.encode(sec1).toUpperCase(),
|
||||
"981A9A7DD677A622518DA068D66D5F824E5F22F084B8A0E2F195B5662F300C11",
|
||||
Hex.encode(sec1).toUpperCase(),
|
||||
"testPrivKeyNegate"
|
||||
)
|
||||
val sec2: ByteArray = Secp256k1.privKeyNegate(sec1)
|
||||
@ -201,7 +215,11 @@ class Secp256k1Test {
|
||||
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
|
||||
val resultArr: ByteArray = Secp256k1.privKeyTweakAdd(sec, data)
|
||||
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 resultArr: ByteArray = Secp256k1.privKeyTweakMul(sec, data)
|
||||
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 sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||
assertEquals(
|
||||
sigString,
|
||||
"0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF",
|
||||
sigString,
|
||||
"testPrivKeyAdd_2"
|
||||
)
|
||||
}
|
||||
@ -242,8 +264,8 @@ class Secp256k1Test {
|
||||
val resultArr: ByteArray = Secp256k1.pubKeyTweakMul(pub, data)
|
||||
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||
assertEquals(
|
||||
sigString,
|
||||
"04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589",
|
||||
sigString,
|
||||
"testPrivKeyMul_2"
|
||||
)
|
||||
}
|
||||
@ -255,7 +277,7 @@ class Secp256k1Test {
|
||||
fun testRandomize() {
|
||||
val seed: ByteArray = Hex.decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()) //sha256hash of "random"
|
||||
val result: Boolean = Secp256k1.randomize(seed)
|
||||
assertEquals(result, true, "testRandomize")
|
||||
assertTrue(result, "testRandomize")
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -265,8 +287,8 @@ class Secp256k1Test {
|
||||
val resultArr: ByteArray = Secp256k1.createECDHSecret(sec, pub)
|
||||
val ecdhString: String = Hex.encode(resultArr).toUpperCase()
|
||||
assertEquals(
|
||||
ecdhString,
|
||||
"2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043",
|
||||
ecdhString,
|
||||
"testCreateECDHSecret"
|
||||
)
|
||||
}
|
||||
@ -275,10 +297,10 @@ class Secp256k1Test {
|
||||
fun testEcdsaRecover() {
|
||||
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||
val pub: ByteArray = Secp256k1.computePubkey(sec)
|
||||
val sig: ByteArray = Secp256k1.signCompact(data, sec)
|
||||
val pub0: ByteArray = Secp256k1.ecdsaRecover(sig, data, 0)
|
||||
val pub1: ByteArray = Secp256k1.ecdsaRecover(sig, data, 1)
|
||||
val pub: ByteArray = Secp256k1.computePubkey(sec, PubKeyFormat.UNCOMPRESSED)
|
||||
val sig: ByteArray = Secp256k1.sign(data, sec, SigFormat.COMPACT)
|
||||
val pub0: ByteArray = Secp256k1.ecdsaRecover(sig, data, 0, PubKeyFormat.UNCOMPRESSED)
|
||||
val pub1: ByteArray = Secp256k1.ecdsaRecover(sig, data, 1, PubKeyFormat.UNCOMPRESSED)
|
||||
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1), "testEcdsaRecover")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 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 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()
|
||||
|
||||
@ -58,7 +58,7 @@ public actual object Secp256k1 {
|
||||
|
||||
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)
|
||||
|
||||
|
@ -92,14 +92,15 @@ public object NativeSecp256k1 {
|
||||
/**
|
||||
* libsecp256k1 Create an ECDSA signature.
|
||||
*
|
||||
* @param data Message hash, 32 bytes
|
||||
* @param sec Secret key, 32 bytes
|
||||
* @param data Message hash, 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
|
||||
* @throws AssertFailException in case of failure
|
||||
*/
|
||||
@JvmStatic
|
||||
@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)
|
||||
val byteBuff = pack(data, sec)
|
||||
val retByteArray: Array<ByteArray>
|
||||
@ -107,6 +108,7 @@ public object NativeSecp256k1 {
|
||||
retByteArray = try {
|
||||
secp256k1_ecdsa_sign(
|
||||
byteBuff,
|
||||
compact,
|
||||
Secp256k1Context.getContext()
|
||||
)
|
||||
} finally {
|
||||
@ -123,27 +125,18 @@ public object NativeSecp256k1 {
|
||||
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
|
||||
@Throws(AssertFailException::class)
|
||||
public fun signCompact(data: ByteArray, sec: ByteArray): ByteArray {
|
||||
require(data.size == 32 && sec.size <= 32)
|
||||
val byteBuff = pack(data, sec)
|
||||
public fun signatureNormalize(sig: ByteArray, compact: Boolean): Pair<ByteArray, Boolean> {
|
||||
require(sig.size == 64 || sig.size in 70..73)
|
||||
val byteBuff = pack(sig)
|
||||
val retByteArray: Array<ByteArray>
|
||||
r.lock()
|
||||
retByteArray = try {
|
||||
secp256k1_ecdsa_sign_compact(
|
||||
secp256k1_ecdsa_normalize(
|
||||
byteBuff,
|
||||
sig.size,
|
||||
compact,
|
||||
Secp256k1Context.getContext()
|
||||
)
|
||||
} finally {
|
||||
@ -152,12 +145,13 @@ public object NativeSecp256k1 {
|
||||
val sigArr = retByteArray[0]
|
||||
val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
||||
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
||||
val retBool = BigInteger(byteArrayOf(retByteArray[1][2])).toInt()
|
||||
NativeSecp256k1Util.assertEquals(
|
||||
sigArr.size,
|
||||
sigLen,
|
||||
"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
|
||||
@JvmStatic
|
||||
@Throws(AssertFailException::class)
|
||||
public fun computePubkey(seckey: ByteArray): ByteArray {
|
||||
public fun computePubkey(seckey: ByteArray, compressed: Boolean): ByteArray {
|
||||
require(seckey.size == 32)
|
||||
val byteBuff = pack(seckey)
|
||||
val retByteArray: Array<ByteArray>
|
||||
@ -199,6 +193,7 @@ public object NativeSecp256k1 {
|
||||
retByteArray = try {
|
||||
secp256k1_ec_pubkey_create(
|
||||
byteBuff,
|
||||
compressed,
|
||||
Secp256k1Context.getContext()
|
||||
)
|
||||
} finally {
|
||||
@ -218,7 +213,7 @@ public object NativeSecp256k1 {
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(AssertFailException::class)
|
||||
public fun parsePubkey(pubkey: ByteArray): ByteArray {
|
||||
public fun parsePubkey(pubkey: ByteArray, compressed: Boolean): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
val byteBuff = pack(pubkey)
|
||||
val retByteArray: Array<ByteArray>
|
||||
@ -227,7 +222,8 @@ public object NativeSecp256k1 {
|
||||
secp256k1_ec_pubkey_parse(
|
||||
byteBuff,
|
||||
Secp256k1Context.getContext(),
|
||||
pubkey.size
|
||||
pubkey.size,
|
||||
compressed
|
||||
)
|
||||
} finally {
|
||||
r.unlock()
|
||||
@ -235,7 +231,7 @@ public object NativeSecp256k1 {
|
||||
val pubArr = retByteArray[0]
|
||||
BigInteger(byteArrayOf(retByteArray[1][0])).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
|
||||
}
|
||||
|
||||
@ -456,7 +452,7 @@ public object NativeSecp256k1 {
|
||||
val pubArr = retByteArray[0]
|
||||
val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF
|
||||
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.")
|
||||
return pubArr
|
||||
}
|
||||
@ -494,7 +490,7 @@ public object NativeSecp256k1 {
|
||||
|
||||
@JvmStatic
|
||||
@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(message.size == 32)
|
||||
val byteBuff = pack(sig, message)
|
||||
@ -504,14 +500,15 @@ public object NativeSecp256k1 {
|
||||
secp256k1_ecdsa_recover(
|
||||
byteBuff,
|
||||
Secp256k1Context.getContext(),
|
||||
recid
|
||||
recid,
|
||||
compressed
|
||||
)
|
||||
} finally {
|
||||
r.unlock()
|
||||
}
|
||||
val resArr = retByteArray[0]
|
||||
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.")
|
||||
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_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_sign(byteBuff: ByteBuffer, context: Long): Array<ByteArray>
|
||||
@JvmStatic private external fun secp256k1_ecdsa_sign_compact(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_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_pubkey_create(byteBuff: ByteBuffer, context: Long): Array<ByteArray>
|
||||
@JvmStatic private external fun secp256k1_ec_pubkey_parse(
|
||||
byteBuff: ByteBuffer,
|
||||
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_ec_pubkey_create(byteBuff: ByteBuffer, compressed: Boolean, context: Long): Array<ByteArray>
|
||||
@JvmStatic private external fun secp256k1_ec_pubkey_parse(byteBuff: ByteBuffer, context: Long, inputLen: Int, compressed: Boolean): 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_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>
|
||||
}
|
@ -7,10 +7,6 @@ import secp256k1.*
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
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 {
|
||||
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")
|
||||
@ -19,22 +15,34 @@ public actual object Secp256k1 {
|
||||
private fun Int.requireSuccess() = require(this == 1) { "secp256k1 native function call failed" }
|
||||
|
||||
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 nativeBytes = toNat(input)
|
||||
val result = when (sigFormat) {
|
||||
SIG_FORMAT_COMPACT -> secp256k1_ecdsa_signature_parse_compact(ctx, sig.ptr, nativeBytes)
|
||||
SIG_FORMAT_DER -> secp256k1_ecdsa_signature_parse_der(ctx, sig.ptr, nativeBytes, input.size.toULong())
|
||||
else -> 0
|
||||
|
||||
val result = when (input.size) {
|
||||
64 -> secp256k1_ecdsa_signature_parse_compact(ctx, sig.ptr, nativeBytes)
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
val natPub = toNat(pubkey)
|
||||
val pub = alloc<secp256k1_pubkey>()
|
||||
@ -61,68 +69,59 @@ public actual object Secp256k1 {
|
||||
require(data.size == 32)
|
||||
require(pub.size == 33 || pub.size == 65)
|
||||
memScoped {
|
||||
val pubkey = allocPublicKey(pub)
|
||||
val natData = toNat(data)
|
||||
val parsedSig = allocSignature(signature)
|
||||
return secp256k1_ecdsa_verify(ctx, parsedSig.ptr, natData, pubkey.ptr) == 1
|
||||
val nPubkey = allocPublicKey(pub)
|
||||
val nData = toNat(data)
|
||||
val nSig = allocSignature(signature)
|
||||
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(data.size == 32)
|
||||
memScoped {
|
||||
val natSec = toNat(sec)
|
||||
val natData = toNat(data)
|
||||
val natSig = alloc<secp256k1_ecdsa_signature>()
|
||||
val result = secp256k1_ecdsa_sign(ctx, natSig.ptr, natData, natSec, null, null)
|
||||
val nSec = toNat(sec)
|
||||
val nData = toNat(data)
|
||||
val nSig = alloc<secp256k1_ecdsa_signature>()
|
||||
val result = secp256k1_ecdsa_sign(ctx, nSig.ptr, nData, nSec, null, null)
|
||||
if (result == 0) return ByteArray(0)
|
||||
val natOutput = allocArray<UByteVar>(72)
|
||||
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())
|
||||
return serializeSignature(nSig, format)
|
||||
}
|
||||
}
|
||||
|
||||
public actual fun signCompact(data: ByteArray, sec: ByteArray): ByteArray {
|
||||
require(data.size == 32)
|
||||
require(sec.size <= 32)
|
||||
public actual fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair<ByteArray, Boolean> {
|
||||
require(sig.size == 64 || sig.size in 70..73)
|
||||
memScoped {
|
||||
val natSec = toNat(sec)
|
||||
val natData = toNat(data)
|
||||
val natSig = alloc<secp256k1_ecdsa_signature>()
|
||||
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)
|
||||
val nSig = allocSignature(sig)
|
||||
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
|
||||
return Pair(serializeSignature(nSig, format), isHighS == 1)
|
||||
}
|
||||
}
|
||||
|
||||
public actual fun secKeyVerify(seckey: ByteArray): Boolean {
|
||||
require(seckey.size == 32)
|
||||
memScoped {
|
||||
val natSec = toNat(seckey)
|
||||
return secp256k1_ec_seckey_verify(ctx, natSec) == 1
|
||||
val nSec = toNat(seckey)
|
||||
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)
|
||||
memScoped {
|
||||
val natSec = toNat(seckey)
|
||||
val pubkey = alloc<secp256k1_pubkey>()
|
||||
val result = secp256k1_ec_pubkey_create(ctx, pubkey.ptr, natSec)
|
||||
val nSec = toNat(seckey)
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
val result = secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nSec)
|
||||
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)
|
||||
memScoped {
|
||||
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 nTweak = toNat(tweak)
|
||||
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 nTweak = toNat(tweak)
|
||||
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 {
|
||||
require(pubkey1.size == 33 || pubkey2.size == 65)
|
||||
require(pubkey1.size == 33 || pubkey1.size == 65)
|
||||
require(pubkey2.size == 33 || pubkey2.size == 65)
|
||||
memScoped {
|
||||
val nPubkey1 = allocPublicKey(pubkey1)
|
||||
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()
|
||||
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(message.size == 32)
|
||||
memScoped {
|
||||
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()
|
||||
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()
|
||||
return serializePubkey(pubkey, 65)
|
||||
return serializePubkey(pubkey, format.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user