Clean up and enrich tests (#35)
* Harmonize parameter names * Document methods * Replace pubKeyAdd with pubKeyCombine * Clean-up tests
This commit is contained in:
committed by
GitHub
parent
3389795a52
commit
f695e7453d
@@ -20,41 +20,104 @@ import kotlin.jvm.JvmStatic
|
||||
|
||||
public interface Secp256k1 {
|
||||
|
||||
public fun verify(signature: ByteArray, data: ByteArray, pub: ByteArray): Boolean
|
||||
/**
|
||||
* Verify an ECDSA signature.
|
||||
*
|
||||
* @param signature signature using either compact encoding (64 bytes) or der-encoding.
|
||||
* @param message message signed.
|
||||
* @param pubkey signer's public key.
|
||||
*/
|
||||
public fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean
|
||||
|
||||
public fun sign(data: ByteArray, sec: ByteArray): ByteArray
|
||||
/**
|
||||
* Create a normalized ECDSA signature.
|
||||
*
|
||||
* @param message message to sign.
|
||||
* @param privkey signer's private key.
|
||||
*/
|
||||
public fun sign(message: ByteArray, privkey: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Convert an ECDSA signature to a normalized lower-S form (bitcoin standardness rule).
|
||||
* Returns the normalized signature and a boolean set to true if the input signature was not normalized.
|
||||
*
|
||||
* @param sig signature that should be normalized.
|
||||
*/
|
||||
public fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean>
|
||||
|
||||
public fun secKeyVerify(seckey: ByteArray): Boolean
|
||||
/**
|
||||
* Verify the validity of a private key.
|
||||
*/
|
||||
public fun secKeyVerify(privkey: ByteArray): Boolean
|
||||
|
||||
public fun pubkeyCreate(seckey: ByteArray): ByteArray
|
||||
/**
|
||||
* Get the public key corresponding to the given private key.
|
||||
*/
|
||||
public fun pubkeyCreate(privkey: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Parse a serialized public key.
|
||||
*/
|
||||
public fun pubkeyParse(pubkey: ByteArray): ByteArray
|
||||
|
||||
public fun cleanup()
|
||||
|
||||
/**
|
||||
* Negate the given private key.
|
||||
*/
|
||||
public fun privKeyNegate(privkey: ByteArray): ByteArray
|
||||
|
||||
public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Tweak a private key by adding tweak to it.
|
||||
*/
|
||||
public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Tweak a private key by multiplying it by a tweak.
|
||||
*/
|
||||
public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Negate the given public key.
|
||||
*/
|
||||
public fun pubKeyNegate(pubkey: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Tweak a public key by adding tweak times the generator to it.
|
||||
*/
|
||||
public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Tweak a public key by multiplying it by a tweak value.
|
||||
*/
|
||||
public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray
|
||||
|
||||
public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray
|
||||
/**
|
||||
* Add a number of public keys together.
|
||||
*/
|
||||
public fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray
|
||||
|
||||
public fun ecdh(seckey: ByteArray, pubkey: ByteArray): ByteArray
|
||||
/**
|
||||
* Compute an elliptic curve Diffie-Hellman secret.
|
||||
*/
|
||||
public fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Recover a public key from an ECDSA signature.
|
||||
*
|
||||
* @param sig ecdsa compact signature (64 bytes).
|
||||
* @param message message signed.
|
||||
* @param recid recoveryId (should have been provided with the signature to allow recovery).
|
||||
*/
|
||||
public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray
|
||||
|
||||
/**
|
||||
* Convert a compact ECDSA signature (64 bytes) to a der-encoded ECDSA signature.
|
||||
*/
|
||||
public fun compact2der(sig: ByteArray): ByteArray
|
||||
|
||||
public fun pubKeyCompress(pubkey: ByteArray) : ByteArray {
|
||||
/**
|
||||
* Serialize a public key to compact form (33 bytes).
|
||||
*/
|
||||
public fun pubKeyCompress(pubkey: ByteArray): ByteArray {
|
||||
return when {
|
||||
pubkey.size == 33 && (pubkey[0] == 2.toByte() || pubkey[0] == 3.toByte()) -> pubkey
|
||||
pubkey.size == 65 && pubkey[0] == 4.toByte() -> {
|
||||
@@ -66,14 +129,20 @@ public interface Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the secp256k1 context from dynamic memory.
|
||||
*/
|
||||
public fun cleanup()
|
||||
|
||||
public companion object : Secp256k1 by getSecpk256k1() {
|
||||
@JvmStatic public fun get(): Secp256k1 = this
|
||||
@JvmStatic
|
||||
public fun get(): Secp256k1 = this
|
||||
}
|
||||
}
|
||||
|
||||
internal expect fun getSecpk256k1(): Secp256k1
|
||||
|
||||
public class Secp256k1Exception : RuntimeException {
|
||||
public constructor() : super() {}
|
||||
public constructor(message: String?) : super(message) {}
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public object Secp256k1Native : Secp256k1 {
|
||||
|
||||
private val ctx: CPointer<secp256k1_context> by lazy {
|
||||
secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt())
|
||||
?: error("Could not create segp256k1 context")
|
||||
?: error("Could not create secp256k1 context")
|
||||
}
|
||||
|
||||
private fun Int.requireSuccess(message: String): Int = if (this != 1) throw Secp256k1Exception(message) else this
|
||||
@@ -55,25 +55,25 @@ public object Secp256k1Native : Secp256k1 {
|
||||
return pinned.addressOf(0)
|
||||
}
|
||||
|
||||
public override fun verify(signature: ByteArray, data: ByteArray, pub: ByteArray): Boolean {
|
||||
require(data.size == 32)
|
||||
require(pub.size == 33 || pub.size == 65)
|
||||
public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean {
|
||||
require(message.size == 32)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pub)
|
||||
val nData = toNat(data)
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = allocSignature(signature)
|
||||
return secp256k1_ecdsa_verify(ctx, nSig.ptr, nData, nPubkey.ptr) == 1
|
||||
return secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) == 1
|
||||
}
|
||||
}
|
||||
|
||||
public override fun sign(data: ByteArray, sec: ByteArray): ByteArray {
|
||||
require(sec.size == 32)
|
||||
require(data.size == 32)
|
||||
public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(message.size == 32)
|
||||
memScoped {
|
||||
val nSec = toNat(sec)
|
||||
val nData = toNat(data)
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = alloc<secp256k1_ecdsa_signature>()
|
||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nData, nSec, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
|
||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
|
||||
return serializeSignature(nSig)
|
||||
}
|
||||
}
|
||||
@@ -87,20 +87,20 @@ public object Secp256k1Native : Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
public override fun secKeyVerify(seckey: ByteArray): Boolean {
|
||||
require(seckey.size == 32)
|
||||
public override fun secKeyVerify(privkey: ByteArray): Boolean {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
val nSec = toNat(seckey)
|
||||
return secp256k1_ec_seckey_verify(ctx, nSec) == 1
|
||||
val nPrivkey = toNat(privkey)
|
||||
return secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubkeyCreate(seckey: ByteArray): ByteArray {
|
||||
require(seckey.size == 32)
|
||||
public override fun pubkeyCreate(privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
val nSec = toNat(seckey)
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nSec).requireSuccess("secp256k1_ec_pubkey_create() failed")
|
||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess("secp256k1_ec_pubkey_create() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
@@ -113,10 +113,6 @@ public object Secp256k1Native : Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
public override fun cleanup() {
|
||||
secp256k1_context_destroy(ctx)
|
||||
}
|
||||
|
||||
public override fun privKeyNegate(privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
@@ -127,17 +123,6 @@ public object Secp256k1Native : Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
val multiplied = privkey.copyOf()
|
||||
val natMul = toNat(multiplied)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
|
||||
return multiplied
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
@@ -149,6 +134,17 @@ public object Secp256k1Native : Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
val multiplied = privkey.copyOf()
|
||||
val natMul = toNat(multiplied)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
|
||||
return multiplied
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyNegate(pubkey: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
@@ -178,26 +174,24 @@ public object Secp256k1Native : Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray {
|
||||
require(pubkey1.size == 33 || pubkey1.size == 65)
|
||||
require(pubkey2.size == 33 || pubkey2.size == 65)
|
||||
public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray {
|
||||
pubkeys.forEach { require(it.size == 33 || it.size == 65) }
|
||||
memScoped {
|
||||
val nPubkey1 = allocPublicKey(pubkey1)
|
||||
val nPubkey2 = allocPublicKey(pubkey2)
|
||||
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
||||
val combined = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, cValuesOf(nPubkey1.ptr, nPubkey2.ptr), 2.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
|
||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
|
||||
return serializePubkey(combined)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun ecdh(seckey: ByteArray, pubkey: ByteArray): ByteArray {
|
||||
require(seckey.size == 32)
|
||||
public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nSeckey = toNat(seckey)
|
||||
val nPrivkey = toNat(privkey)
|
||||
val output = allocArray<UByteVar>(32)
|
||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nSeckey, null, null).requireSuccess("secp256k1_ecdh() failed")
|
||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess("secp256k1_ecdh() failed")
|
||||
return output.readBytes(32)
|
||||
}
|
||||
}
|
||||
@@ -227,6 +221,10 @@ public object Secp256k1Native : Secp256k1 {
|
||||
return natOutput.readBytes(len.value.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
public override fun cleanup() {
|
||||
secp256k1_context_destroy(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun getSecpk256k1(): Secp256k1 = Secp256k1Native
|
||||
|
||||
Reference in New Issue
Block a user