2020-06-26 17:10:48 +02:00
package fr.acinq.secp256k1
2024-08-22 10:47:18 +02:00
import fr.acinq.secp256k1.Secp256k1Native.toNat
2020-06-26 17:10:48 +02:00
import kotlinx.cinterop.*
2024-08-04 23:53:28 +02:00
import kotlinx.cinterop.ptr
2024-02-14 13:28:22 +01:00
import platform.posix.memcpy
2020-06-26 17:10:48 +02:00
import platform.posix.size_tVar
import secp256k1.*
2024-01-23 15:44:06 +01:00
@OptIn ( ExperimentalUnsignedTypes :: class , ExperimentalForeignApi :: class )
2020-07-01 12:46:04 +02:00
public object Secp256k1Native : Secp256k1 {
2020-06-26 17:10:48 +02:00
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 ( ) )
2021-10-26 17:16:36 +02:00
?: error ( " Could not create secp256k1 context " )
2020-06-26 17:10:48 +02:00
}
2020-07-02 17:52:21 +02:00
private fun Int . requireSuccess ( message : String ) : Int = if ( this != 1 ) throw Secp256k1Exception ( message ) else this
2020-06-26 17:10:48 +02:00
private fun MemScope . allocSignature ( input : ByteArray ) : secp256k1 _ecdsa _signature {
val sig = alloc < secp256k1 _ecdsa _signature > ( )
val nativeBytes = toNat ( input )
2020-06-29 17:10:58 +02:00
2020-07-09 20:16:39 +02:00
val result = when {
input . size == 64 -> secp256k1 _ecdsa _signature _parse _compact ( ctx , sig . ptr , nativeBytes )
input . size < 64 -> throw Secp256k1Exception ( " Unknown signature format " )
else -> secp256k1 _ecdsa _signature _parse _der ( ctx , sig . ptr , nativeBytes , input . size . convert ( ) )
2020-06-26 17:10:48 +02:00
}
2020-07-02 17:52:21 +02:00
result . requireSuccess ( " cannot parse signature (size = ${input.size} sig = ${Hex.encode(input)} " )
2020-06-26 17:10:48 +02:00
return sig
}
2020-07-02 17:52:21 +02:00
private fun MemScope . serializeSignature ( signature : secp256k1 _ecdsa _signature ) : ByteArray {
val natOutput = allocArray < UByteVar > ( 64 )
secp256k1 _ecdsa _signature _serialize _compact ( ctx , natOutput , signature . ptr ) . requireSuccess ( " secp256k1_ecdsa_signature_serialize_compact() failed " )
return natOutput . readBytes ( 64 )
2020-06-29 17:10:58 +02:00
}
2020-06-26 17:10:48 +02:00
private fun MemScope . allocPublicKey ( pubkey : ByteArray ) : secp256k1 _pubkey {
val natPub = toNat ( pubkey )
val pub = alloc < secp256k1 _pubkey > ( )
2020-07-02 17:52:21 +02:00
secp256k1 _ec _pubkey _parse ( ctx , pub . ptr , natPub , pubkey . size . convert ( ) ) . requireSuccess ( " secp256k1_ec_pubkey_parse() failed " )
2020-06-26 17:10:48 +02:00
return pub
}
2024-08-04 23:53:28 +02:00
private fun MemScope . allocXonlyPublicKey ( pubkey : ByteArray ) : secp256k1 _xonly _pubkey {
val natPub = toNat ( pubkey )
val pub = alloc < secp256k1 _xonly _pubkey > ( )
secp256k1 _xonly _pubkey _parse ( ctx , pub . ptr , natPub ) . requireSuccess ( " secp256k1_xonly_pubkey_parse() failed " )
return pub
}
2024-02-14 13:28:22 +01:00
private fun MemScope . allocPublicNonce ( pubnonce : ByteArray ) : secp256k1 _musig _pubnonce {
val nat = toNat ( pubnonce )
val nPubnonce = alloc < secp256k1 _musig _pubnonce > ( )
secp256k1 _musig _pubnonce _parse ( ctx , nPubnonce . ptr , nat ) . requireSuccess ( " secp256k1_musig_pubnonce_parse() failed " )
return nPubnonce
}
private fun MemScope . allocPartialSig ( psig : ByteArray ) : secp256k1 _musig _partial _sig {
val nat = toNat ( psig )
val nPsig = alloc < secp256k1 _musig _partial _sig > ( )
secp256k1 _musig _partial _sig _parse ( ctx , nPsig . ptr , nat ) . requireSuccess ( " secp256k1_musig_partial_sig_parse() failed " )
return nPsig
}
2020-07-02 17:52:21 +02:00
private fun MemScope . serializePubkey ( pubkey : secp256k1 _pubkey ) : ByteArray {
val serialized = allocArray < UByteVar > ( 65 )
2020-06-26 17:10:48 +02:00
val outputLen = alloc < size _tVar > ( )
2020-07-02 17:52:21 +02:00
outputLen . value = 65. convert ( )
secp256k1 _ec _pubkey _serialize ( ctx , serialized , outputLen . ptr , pubkey . ptr , SECP256K1 _EC _UNCOMPRESSED . convert ( ) ) . requireSuccess ( " secp256k1_ec_pubkey_serialize() failed " )
2020-06-26 17:10:48 +02:00
return serialized . readBytes ( outputLen . value . convert ( ) )
}
2024-02-14 13:28:22 +01:00
private fun MemScope . serializeXonlyPubkey ( pubkey : secp256k1 _xonly _pubkey ) : ByteArray {
val serialized = allocArray < UByteVar > ( 32 )
secp256k1 _xonly _pubkey _serialize ( ctx , serialized , pubkey . ptr ) . requireSuccess ( " secp256k1_xonly_pubkey_serialize() failed " )
return serialized . readBytes ( 32 )
}
private fun MemScope . serializePubnonce ( pubnonce : secp256k1 _musig _pubnonce ) : ByteArray {
val serialized = allocArray < UByteVar > ( Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
secp256k1 _musig _pubnonce _serialize ( ctx , serialized , pubnonce . ptr ) . requireSuccess ( " secp256k1_musig_pubnonce_serialize() failed " )
return serialized . readBytes ( Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
}
private fun MemScope . serializeAggnonce ( aggnonce : secp256k1 _musig _aggnonce ) : ByteArray {
val serialized = allocArray < UByteVar > ( Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
secp256k1 _musig _aggnonce _serialize ( ctx , serialized , aggnonce . ptr ) . requireSuccess ( " secp256k1_musig_aggnonce_serialize() failed " )
return serialized . readBytes ( Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
}
2024-04-18 09:54:51 +02:00
private fun DeferScope . toNat ( bytes : ByteArray ) : CPointer < UByteVar > {
2020-06-26 17:10:48 +02:00
val ubytes = bytes . asUByteArray ( )
val pinned = ubytes . pin ( )
this . defer { pinned . unpin ( ) }
return pinned . addressOf ( 0 )
}
2021-10-26 17:16:36 +02:00
public override fun verify ( signature : ByteArray , message : ByteArray , pubkey : ByteArray ) : Boolean {
require ( message . size == 32 )
require ( pubkey . size == 33 || pubkey . size == 65 )
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val nPubkey = allocPublicKey ( pubkey )
val nMessage = toNat ( message )
2020-06-29 17:10:58 +02:00
val nSig = allocSignature ( signature )
2021-10-26 17:16:36 +02:00
return secp256k1 _ecdsa _verify ( ctx , nSig . ptr , nMessage , nPubkey . ptr ) == 1
2020-06-26 17:10:48 +02:00
}
}
2021-10-26 17:16:36 +02:00
public override fun sign ( message : ByteArray , privkey : ByteArray ) : ByteArray {
require ( privkey . size == 32 )
require ( message . size == 32 )
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val nPrivkey = toNat ( privkey )
val nMessage = toNat ( message )
2020-06-29 17:10:58 +02:00
val nSig = alloc < secp256k1 _ecdsa _signature > ( )
2021-10-26 17:16:36 +02:00
secp256k1 _ecdsa _sign ( ctx , nSig . ptr , nMessage , nPrivkey , null , null ) . requireSuccess ( " secp256k1_ecdsa_sign() failed " )
2020-07-02 17:52:21 +02:00
return serializeSignature ( nSig )
2020-06-26 17:10:48 +02:00
}
}
2020-07-02 17:52:21 +02:00
public override fun signatureNormalize ( sig : ByteArray ) : Pair < ByteArray , Boolean > {
2024-04-18 09:54:51 +02:00
require ( sig . size >= 64 ) { " invalid signature ${Hex.encode(sig)} " }
2020-06-26 17:10:48 +02:00
memScoped {
2020-06-29 17:10:58 +02:00
val nSig = allocSignature ( sig )
val isHighS = secp256k1 _ecdsa _signature _normalize ( ctx , nSig . ptr , nSig . ptr )
2020-07-02 17:52:21 +02:00
return Pair ( serializeSignature ( nSig ) , isHighS == 1 )
2020-06-26 17:10:48 +02:00
}
}
2021-10-26 17:16:36 +02:00
public override fun secKeyVerify ( privkey : ByteArray ) : Boolean {
2021-11-05 10:45:49 +01:00
if ( privkey . size != 32 ) return false
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val nPrivkey = toNat ( privkey )
return secp256k1 _ec _seckey _verify ( ctx , nPrivkey ) == 1
2020-06-26 17:10:48 +02:00
}
}
2021-10-26 17:16:36 +02:00
public override fun pubkeyCreate ( privkey : ByteArray ) : ByteArray {
require ( privkey . size == 32 )
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val nPrivkey = toNat ( privkey )
2020-06-29 17:10:58 +02:00
val nPubkey = alloc < secp256k1 _pubkey > ( )
2021-10-26 17:16:36 +02:00
secp256k1 _ec _pubkey _create ( ctx , nPubkey . ptr , nPrivkey ) . requireSuccess ( " secp256k1_ec_pubkey_create() failed " )
2020-07-02 17:52:21 +02:00
return serializePubkey ( nPubkey )
2020-06-26 17:10:48 +02:00
}
}
2020-07-02 17:52:21 +02:00
public override fun pubkeyParse ( pubkey : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( pubkey . size == 33 || pubkey . size == 65 )
memScoped {
val nPubkey = allocPublicKey ( pubkey )
2020-07-02 17:52:21 +02:00
return serializePubkey ( nPubkey )
2020-06-26 17:10:48 +02:00
}
}
2020-07-01 12:46:04 +02:00
public override fun privKeyNegate ( privkey : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( privkey . size == 32 )
memScoped {
val negated = privkey . copyOf ( )
val negPriv = toNat ( negated )
2022-04-11 13:34:59 +02:00
secp256k1 _ec _seckey _negate ( ctx , negPriv ) . requireSuccess ( " secp256k1_ec_seckey_negate() failed " )
2020-06-26 17:10:48 +02:00
return negated
}
}
2021-10-26 17:16:36 +02:00
public override fun privKeyTweakAdd ( privkey : ByteArray , tweak : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( privkey . size == 32 )
2023-12-13 13:42:14 +01:00
require ( tweak . size == 32 )
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val added = privkey . copyOf ( )
val natAdd = toNat ( added )
2020-06-26 17:10:48 +02:00
val natTweak = toNat ( tweak )
2022-04-11 13:34:59 +02:00
secp256k1 _ec _seckey _tweak _add ( ctx , natAdd , natTweak ) . requireSuccess ( " secp256k1_ec_seckey_tweak_add() failed " )
2021-10-26 17:16:36 +02:00
return added
2020-06-26 17:10:48 +02:00
}
}
2021-10-26 17:16:36 +02:00
public override fun privKeyTweakMul ( privkey : ByteArray , tweak : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( privkey . size == 32 )
2023-12-13 13:42:14 +01:00
require ( tweak . size == 32 )
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val multiplied = privkey . copyOf ( )
val natMul = toNat ( multiplied )
2020-06-26 17:10:48 +02:00
val natTweak = toNat ( tweak )
2021-10-26 17:16:36 +02:00
secp256k1 _ec _privkey _tweak _mul ( ctx , natMul , natTweak ) . requireSuccess ( " secp256k1_ec_privkey_tweak_mul() failed " )
return multiplied
2020-06-26 17:10:48 +02:00
}
}
2020-07-01 12:46:04 +02:00
public override fun pubKeyNegate ( pubkey : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( pubkey . size == 33 || pubkey . size == 65 )
memScoped {
val nPubkey = allocPublicKey ( pubkey )
2020-07-02 17:52:21 +02:00
secp256k1 _ec _pubkey _negate ( ctx , nPubkey . ptr ) . requireSuccess ( " secp256k1_ec_pubkey_negate() failed " )
return serializePubkey ( nPubkey )
2020-06-26 17:10:48 +02:00
}
}
2020-07-01 12:46:04 +02:00
public override fun pubKeyTweakAdd ( pubkey : ByteArray , tweak : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( pubkey . size == 33 || pubkey . size == 65 )
2023-12-13 13:42:14 +01:00
require ( tweak . size == 32 )
2020-06-26 17:10:48 +02:00
memScoped {
val nPubkey = allocPublicKey ( pubkey )
val nTweak = toNat ( tweak )
2020-07-02 17:52:21 +02:00
secp256k1 _ec _pubkey _tweak _add ( ctx , nPubkey . ptr , nTweak ) . requireSuccess ( " secp256k1_ec_pubkey_tweak_add() failed " )
return serializePubkey ( nPubkey )
2020-06-26 17:10:48 +02:00
}
}
2020-07-01 12:46:04 +02:00
public override fun pubKeyTweakMul ( pubkey : ByteArray , tweak : ByteArray ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( pubkey . size == 33 || pubkey . size == 65 )
2023-12-13 13:42:14 +01:00
require ( tweak . size == 32 )
2020-06-26 17:10:48 +02:00
memScoped {
val nPubkey = allocPublicKey ( pubkey )
val nTweak = toNat ( tweak )
2020-07-02 17:52:21 +02:00
secp256k1 _ec _pubkey _tweak _mul ( ctx , nPubkey . ptr , nTweak ) . requireSuccess ( " secp256k1_ec_pubkey_tweak_mul() failed " )
return serializePubkey ( nPubkey )
2020-06-26 17:10:48 +02:00
}
}
2021-10-26 17:16:36 +02:00
public override fun pubKeyCombine ( pubkeys : Array < ByteArray > ) : ByteArray {
2023-12-13 13:42:14 +01:00
require ( pubkeys . isNotEmpty ( ) )
2021-10-26 17:16:36 +02:00
pubkeys . forEach { require ( it . size == 33 || it . size == 65 ) }
2020-06-26 17:10:48 +02:00
memScoped {
2021-10-26 17:16:36 +02:00
val nPubkeys = pubkeys . map { allocPublicKey ( it ) . ptr }
2020-06-29 17:10:58 +02:00
val combined = alloc < secp256k1 _pubkey > ( )
2021-10-26 17:16:36 +02:00
secp256k1 _ec _pubkey _combine ( ctx , combined . ptr , nPubkeys . toCValues ( ) , pubkeys . size . convert ( ) ) . requireSuccess ( " secp256k1_ec_pubkey_combine() failed " )
2020-07-02 17:52:21 +02:00
return serializePubkey ( combined )
2020-06-26 17:10:48 +02:00
}
}
2021-10-26 17:16:36 +02:00
public override fun ecdh ( privkey : ByteArray , pubkey : ByteArray ) : ByteArray {
require ( privkey . size == 32 )
2020-06-26 17:10:48 +02:00
require ( pubkey . size == 33 || pubkey . size == 65 )
memScoped {
val nPubkey = allocPublicKey ( pubkey )
2021-10-26 17:16:36 +02:00
val nPrivkey = toNat ( privkey )
2020-06-26 17:10:48 +02:00
val output = allocArray < UByteVar > ( 32 )
2021-10-26 17:16:36 +02:00
secp256k1 _ecdh ( ctx , output , nPubkey . ptr , nPrivkey , null , null ) . requireSuccess ( " secp256k1_ecdh() failed " )
2020-06-26 17:10:48 +02:00
return output . readBytes ( 32 )
}
}
2020-07-02 17:52:21 +02:00
public override fun ecdsaRecover ( sig : ByteArray , message : ByteArray , recid : Int ) : ByteArray {
2020-06-26 17:10:48 +02:00
require ( sig . size == 64 )
require ( message . size == 32 )
2023-12-13 13:42:14 +01:00
require ( recid in 0. . 3 )
2020-06-26 17:10:48 +02:00
memScoped {
val nSig = toNat ( sig )
2020-06-29 17:10:58 +02:00
val rSig = alloc < secp256k1 _ecdsa _recoverable _signature > ( )
2020-07-02 17:52:21 +02:00
secp256k1 _ecdsa _recoverable _signature _parse _compact ( ctx , rSig . ptr , nSig , recid ) . requireSuccess ( " secp256k1_ecdsa_recoverable_signature_parse_compact() failed " )
2020-06-26 17:10:48 +02:00
val nMessage = toNat ( message )
2020-06-29 17:10:58 +02:00
val pubkey = alloc < secp256k1 _pubkey > ( )
2020-07-02 17:52:21 +02:00
secp256k1 _ecdsa _recover ( ctx , pubkey . ptr , rSig . ptr , nMessage ) . requireSuccess ( " secp256k1_ecdsa_recover() failed " )
return serializePubkey ( pubkey )
2020-06-26 17:10:48 +02:00
}
}
2020-07-02 21:39:33 +02:00
public override fun compact2der ( sig : ByteArray ) : ByteArray {
require ( sig . size == 64 )
memScoped {
val nSig = allocSignature ( sig )
val natOutput = allocArray < UByteVar > ( 73 )
val len = alloc < size _tVar > ( )
len . value = 73. convert ( )
secp256k1 _ecdsa _signature _serialize _der ( ctx , natOutput , len . ptr , nSig . ptr ) . requireSuccess ( " secp256k1_ecdsa_signature_serialize_der() failed " )
return natOutput . readBytes ( len . value . toInt ( ) )
}
}
2021-10-26 17:16:36 +02:00
2021-11-23 17:38:46 +01:00
override fun verifySchnorr ( signature : ByteArray , data : ByteArray , pub : ByteArray ) : Boolean {
require ( signature . size == 64 )
require ( data . size == 32 )
require ( pub . size == 32 )
memScoped {
val nPub = toNat ( pub )
val pubkey = alloc < secp256k1 _xonly _pubkey > ( )
secp256k1 _xonly _pubkey _parse ( ctx , pubkey . ptr , nPub ) . requireSuccess ( " secp256k1_xonly_pubkey_parse() failed " )
val nData = toNat ( data )
val nSig = toNat ( signature )
2024-01-23 15:44:06 +01:00
return secp256k1 _schnorrsig _verify ( ctx , nSig , nData , 32u , pubkey . ptr ) == 1
2021-11-23 17:38:46 +01:00
}
}
override fun signSchnorr ( data : ByteArray , sec : ByteArray , auxrand32 : ByteArray ? ) : ByteArray {
require ( sec . size == 32 )
require ( data . size == 32 )
auxrand32 ?. let { require ( it . size == 32 ) }
memScoped {
val nSec = toNat ( sec )
val nData = toNat ( data )
val nAuxrand32 = auxrand32 ?. let { toNat ( it ) }
val nSig = allocArray < UByteVar > ( 64 )
val keypair = alloc < secp256k1 _keypair > ( )
secp256k1 _keypair _create ( ctx , keypair . ptr , nSec ) . requireSuccess ( " secp256k1_keypair_create() failed " )
2022-04-11 13:34:59 +02:00
secp256k1 _schnorrsig _sign32 ( ctx , nSig , nData , keypair . ptr , nAuxrand32 ) . requireSuccess ( " secp256k1_ecdsa_sign() failed " )
2021-11-23 17:38:46 +01:00
return nSig . readBytes ( 64 )
}
}
2024-02-14 13:28:22 +01:00
override fun musigNonceGen ( sessionId32 : ByteArray , privkey : ByteArray ? , aggpubkey : ByteArray , msg32 : ByteArray ? , keyaggCache : ByteArray ? , extraInput32 : ByteArray ? ) : ByteArray {
require ( sessionId32 . size == 32 )
privkey ?. let { require ( it . size == 32 ) }
msg32 ?. let { require ( it . size == 32 ) }
keyaggCache ?. let { require ( it . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE ) }
extraInput32 ?. let { require ( it . size == 32 ) }
val nonce = memScoped {
val secnonce = alloc < secp256k1 _musig _secnonce > ( )
val pubnonce = alloc < secp256k1 _musig _pubnonce > ( )
val nPubkey = allocPublicKey ( aggpubkey )
val nKeyAggCache = keyaggCache ?. let {
val n = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( n . ptr , toNat ( it ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
n
}
2024-04-18 09:54:51 +02:00
secp256k1 _musig _nonce _gen (
ctx ,
secnonce . ptr ,
pubnonce . ptr ,
toNat ( sessionId32 ) ,
privkey ?. let { toNat ( it ) } ,
nPubkey . ptr ,
msg32 ?. let { toNat ( it ) } ,
nKeyAggCache ?. ptr ,
extraInput32 ?. let { toNat ( it ) } ) . requireSuccess ( " secp256k1_musig_nonce_gen() failed " )
2024-02-14 13:28:22 +01:00
val nPubnonce = allocArray < UByteVar > ( Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
secp256k1 _musig _pubnonce _serialize ( ctx , nPubnonce , pubnonce . ptr ) . requireSuccess ( " secp256k1_musig_pubnonce_serialize failed " )
secnonce . ptr . readBytes ( Secp256k1 . MUSIG2 _SECRET _NONCE _SIZE ) + nPubnonce . readBytes ( Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
}
return nonce
}
override fun musigNonceAgg ( pubnonces : Array < ByteArray > ) : ByteArray {
require ( pubnonces . isNotEmpty ( ) )
pubnonces . forEach { require ( it . size == Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE ) }
memScoped {
val nPubnonces = pubnonces . map { allocPublicNonce ( it ) . ptr }
val combined = alloc < secp256k1 _musig _aggnonce > ( )
secp256k1 _musig _nonce _agg ( ctx , combined . ptr , nPubnonces . toCValues ( ) , pubnonces . size . convert ( ) ) . requireSuccess ( " secp256k1_musig_nonce_agg() failed " )
return serializeAggnonce ( combined )
}
}
override fun musigPubkeyAgg ( pubkeys : Array < ByteArray > , keyaggCache : ByteArray ? ) : ByteArray {
require ( pubkeys . isNotEmpty ( ) )
pubkeys . forEach { require ( it . size == 33 || it . size == 65 ) }
keyaggCache ?. let { require ( it . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE ) }
memScoped {
val nPubkeys = pubkeys . map { allocPublicKey ( it ) . ptr }
val combined = alloc < secp256k1 _xonly _pubkey > ( )
val nKeyAggCache = keyaggCache ?. let {
val n = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( n . ptr , toNat ( it ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
n
}
2024-08-01 02:45:16 +02:00
secp256k1 _musig _pubkey _agg ( ctx , null , combined . ptr , nKeyAggCache ?. ptr , nPubkeys . toCValues ( ) , pubkeys . size . convert ( ) ) . requireSuccess ( " secp256k1_musig_nonce_agg() failed " )
2024-04-18 09:54:51 +02:00
val agg = serializeXonlyPubkey ( combined )
2024-02-14 13:28:22 +01:00
keyaggCache ?. let { blob -> nKeyAggCache ?. let { memcpy ( toNat ( blob ) , it . ptr , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) ) } }
return agg
}
}
override fun musigPubkeyTweakAdd ( keyaggCache : ByteArray , tweak32 : ByteArray ) : ByteArray {
require ( keyaggCache . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE )
require ( tweak32 . size == 32 )
memScoped {
val nKeyAggCache = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( nKeyAggCache . ptr , toNat ( keyaggCache ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
val nPubkey = alloc < secp256k1 _pubkey > ( )
secp256k1 _musig _pubkey _ec _tweak _add ( ctx , nPubkey . ptr , nKeyAggCache . ptr , toNat ( tweak32 ) ) . requireSuccess ( " secp256k1_musig_pubkey_ec_tweak_add() failed " )
memcpy ( toNat ( keyaggCache ) , nKeyAggCache . ptr , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
return serializePubkey ( nPubkey )
}
}
override fun musigPubkeyXonlyTweakAdd ( keyaggCache : ByteArray , tweak32 : ByteArray ) : ByteArray {
require ( keyaggCache . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE )
require ( tweak32 . size == 32 )
memScoped {
val nKeyAggCache = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( nKeyAggCache . ptr , toNat ( keyaggCache ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
val nPubkey = alloc < secp256k1 _pubkey > ( )
secp256k1 _musig _pubkey _xonly _tweak _add ( ctx , nPubkey . ptr , nKeyAggCache . ptr , toNat ( tweak32 ) ) . requireSuccess ( " secp256k1_musig_pubkey_xonly_tweak_add() failed " )
memcpy ( toNat ( keyaggCache ) , nKeyAggCache . ptr , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
return serializePubkey ( nPubkey )
}
}
override fun musigNonceProcess ( aggnonce : ByteArray , msg32 : ByteArray , keyaggCache : ByteArray ) : ByteArray {
require ( aggnonce . size == Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
require ( keyaggCache . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE )
require ( msg32 . size == 32 )
memScoped {
val nKeyAggCache = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( nKeyAggCache . ptr , toNat ( keyaggCache ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
val nSession = alloc < secp256k1 _musig _session > ( )
val nAggnonce = alloc < secp256k1 _musig _aggnonce > ( )
secp256k1 _musig _aggnonce _parse ( ctx , nAggnonce . ptr , toNat ( aggnonce ) ) . requireSuccess ( " secp256k1_musig_aggnonce_parse() failed " )
2024-08-01 02:45:16 +02:00
secp256k1 _musig _nonce _process ( ctx , nSession . ptr , nAggnonce . ptr , toNat ( msg32 ) , nKeyAggCache . ptr , null ) . requireSuccess ( " secp256k1_musig_nonce_process() failed " )
2024-02-14 13:28:22 +01:00
val session = ByteArray ( Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE )
memcpy ( toNat ( session ) , nSession . ptr , Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE . toULong ( ) )
return session
}
2024-04-18 09:54:51 +02:00
}
2024-02-14 13:28:22 +01:00
override fun musigPartialSign ( secnonce : ByteArray , privkey : ByteArray , keyaggCache : ByteArray , session : ByteArray ) : ByteArray {
require ( secnonce . size == Secp256k1 . MUSIG2 _SECRET _NONCE _SIZE )
require ( privkey . size == 32 )
require ( keyaggCache . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE )
require ( session . size == Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE )
2024-04-18 09:54:51 +02:00
require ( musigNonceValidate ( secnonce , pubkeyCreate ( privkey ) ) )
2024-02-14 13:28:22 +01:00
memScoped {
val nSecnonce = alloc < secp256k1 _musig _secnonce > ( )
memcpy ( nSecnonce . ptr , toNat ( secnonce ) , Secp256k1 . MUSIG2 _SECRET _NONCE _SIZE . toULong ( ) )
val nKeypair = alloc < secp256k1 _keypair > ( )
secp256k1 _keypair _create ( ctx , nKeypair . ptr , toNat ( privkey ) )
val nPsig = alloc < secp256k1 _musig _partial _sig > ( )
val nKeyAggCache = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( nKeyAggCache . ptr , toNat ( keyaggCache ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
val nSession = alloc < secp256k1 _musig _session > ( )
memcpy ( nSession . ptr , toNat ( session ) , Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE . toULong ( ) )
secp256k1 _musig _partial _sign ( ctx , nPsig . ptr , nSecnonce . ptr , nKeypair . ptr , nKeyAggCache . ptr , nSession . ptr ) . requireSuccess ( " secp256k1_musig_partial_sign failed " )
val psig = ByteArray ( 32 )
secp256k1 _musig _partial _sig _serialize ( ctx , toNat ( psig ) , nPsig . ptr ) . requireSuccess ( " secp256k1_musig_partial_sig_serialize() failed " )
return psig
}
2021-10-26 17:16:36 +02:00
}
2021-11-23 17:38:46 +01:00
2024-02-14 13:28:22 +01:00
override fun musigPartialSigVerify ( psig : ByteArray , pubnonce : ByteArray , pubkey : ByteArray , keyaggCache : ByteArray , session : ByteArray ) : Int {
require ( psig . size == 32 )
require ( pubnonce . size == Secp256k1 . MUSIG2 _PUBLIC _NONCE _SIZE )
require ( pubkey . size == 33 || pubkey . size == 65 )
require ( keyaggCache . size == Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE )
require ( session . size == Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE )
memScoped {
val nPSig = allocPartialSig ( psig )
val nPubnonce = allocPublicNonce ( pubnonce )
val nPubkey = allocPublicKey ( pubkey )
val nKeyAggCache = alloc < secp256k1 _musig _keyagg _cache > ( )
memcpy ( nKeyAggCache . ptr , toNat ( keyaggCache ) , Secp256k1 . MUSIG2 _PUBLIC _KEYAGG _CACHE _SIZE . toULong ( ) )
val nSession = alloc < secp256k1 _musig _session > ( )
memcpy ( nSession . ptr , toNat ( session ) , Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE . toULong ( ) )
return secp256k1 _musig _partial _sig _verify ( ctx , nPSig . ptr , nPubnonce . ptr , nPubkey . ptr , nKeyAggCache . ptr , nSession . ptr )
}
}
2021-11-23 17:38:46 +01:00
2024-02-14 13:28:22 +01:00
override fun musigPartialSigAgg ( session : ByteArray , psigs : Array < ByteArray > ) : ByteArray {
require ( session . size == Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE )
require ( psigs . isNotEmpty ( ) )
psigs . forEach { require ( it . size == 32 ) }
memScoped {
val nSession = alloc < secp256k1 _musig _session > ( )
memcpy ( nSession . ptr , toNat ( session ) , Secp256k1 . MUSIG2 _PUBLIC _SESSION _SIZE . toULong ( ) )
val nPsigs = psigs . map { allocPartialSig ( it ) . ptr }
val sig64 = ByteArray ( 64 )
secp256k1 _musig _partial _sig _agg ( ctx , toNat ( sig64 ) , nSession . ptr , nPsigs . toCValues ( ) , psigs . size . convert ( ) ) . requireSuccess ( " secp256k1_musig_partial_sig_agg() failed " )
return sig64
}
}
2024-08-04 23:53:28 +02:00
private fun MemScope . allocFrostShare ( share : ByteArray ) : secp256k1 _frost _share {
val nat = toNat ( share )
val nFrostShare = alloc < secp256k1 _frost _share > ( )
secp256k1 _frost _share _parse ( ctx , nFrostShare . ptr , nat ) . requireSuccess ( " secp256k1_frost_share_parse() failed " )
return nFrostShare
}
private fun MemScope . allocFrostPartialSignature ( partialSignature : ByteArray ) : secp256k1 _frost _partial _sig {
val nat = toNat ( partialSignature )
val nPartialSignature = alloc < secp256k1 _frost _partial _sig > ( )
secp256k1 _frost _partial _sig _parse ( ctx , nPartialSignature . ptr , nat ) . requireSuccess ( " secp256k1_frost_partial_sig_parse() failed " )
return nPartialSignature
}
private fun MemScope . allocFrostPublicNonce ( pubnonce : ByteArray ) : secp256k1 _frost _pubnonce {
val nat = toNat ( pubnonce )
val nPublicNonce = alloc < secp256k1 _frost _pubnonce > ( )
secp256k1 _frost _pubnonce _parse ( ctx , nPublicNonce . ptr , nat ) . requireSuccess ( " secp256k1_frost_pubnonce_parse() failed " )
return nPublicNonce
}
override fun frostSharesGen (
seed32 : ByteArray ,
2024-08-05 22:34:45 +02:00
threshold : Int ,
2024-08-04 23:53:28 +02:00
totalSigners : Int ,
ids33 : Array < ByteArray >
2024-08-07 02:48:25 +02:00
) : Triple < Array < ByteArray > , Array < ByteArray > , ByteArray > {
2024-08-19 21:40:56 +02:00
require ( seed32 . size == 32 ) { " seed size should be 32 " }
require ( threshold > 1 ) { " threshold cannot be less then 1 " }
require ( threshold <= totalSigners ) { " threshold( $threshold ) cannot be greater then totalSigners ( $totalSigners ) " }
require ( ids33 . size == totalSigners ) { " ids33 size need to be the same as totalSigners size " }
ids33 . forEach { require ( it . size == 33 ) { " id33 size must be 33 " } }
2024-08-04 23:53:28 +02:00
memScoped {
val nShares = allocArray < secp256k1 _frost _share > ( ids33 . size )
2024-08-05 22:34:45 +02:00
val nVssCommitment = allocArray < secp256k1 _pubkey > ( threshold )
2024-08-07 02:48:25 +02:00
val pok64 = ByteArray ( 64 )
2024-08-04 23:53:28 +02:00
val nIds33s = ids33 . map { toNat ( it ) }
secp256k1 _frost _shares _gen (
ctx = ctx ,
shares = nShares ,
2024-08-05 22:34:45 +02:00
vss _commitment = nVssCommitment ,
2024-08-04 23:53:28 +02:00
pok64 = toNat ( pok64 ) ,
seed32 = toNat ( seed32 ) ,
threshold = threshold . convert ( ) ,
n _participants = ids33 . size . convert ( ) ,
ids33 = nIds33s . toCValues ( )
)
2024-08-07 02:48:25 +02:00
return Triple (
2024-08-05 22:34:45 +02:00
ids33 . indices . map { serializeFrostShare ( nShares [ it ] ) } . toTypedArray ( ) ,
2024-08-07 02:48:25 +02:00
( 0 until threshold ) . map { serializePubkey ( nVssCommitment [ it ] ) } . toTypedArray ( ) ,
pok64
2024-08-05 22:34:45 +02:00
)
2024-08-04 23:53:28 +02:00
}
}
private fun MemScope . serializeFrostShare ( nFrostShare : secp256k1 _frost _share ) : ByteArray {
2024-08-21 17:28:07 +02:00
val natOutput = allocArray < UByteVar > ( Secp256k1 . FROST _SERIALIZED _SHARE _SIZE )
2024-08-04 23:53:28 +02:00
secp256k1 _frost _share _serialize ( ctx , natOutput , nFrostShare . ptr ) . requireSuccess ( " secp256k1_frost_share_serialize() failed " )
return natOutput . readBytes ( Secp256k1 . FROST _SERIALIZED _SHARE _SIZE )
}
override fun frostShareAggregate (
totalShares : Array < ByteArray > ,
vssCommitments : Array < Array < ByteArray > > ,
2024-08-05 22:34:45 +02:00
totalShareCount : Int ,
threshold : Int ,
2024-08-04 23:53:28 +02:00
id33 : ByteArray
) : Pair < ByteArray , ByteArray > {
2024-08-19 21:40:56 +02:00
require ( totalShares . size == totalShareCount ) { " totalShare array size ( ${totalShares.size} ) should be the same as total share count ( $totalShareCount ) " }
totalShares . forEach { require ( it . size == 32 ) { " all shares should be of size 32 " } }
require ( vssCommitments . size == totalShareCount ) { " vssCommitments array size ${vssCommitments.size} should be the same as total share count ( $totalShareCount ) " }
2024-08-06 00:19:55 +02:00
vssCommitments . forEach { vssCommitment ->
2024-08-19 21:40:56 +02:00
require ( vssCommitment . size == threshold ) { " all vss commitment array size ( ${vssCommitment.size} ) should be the same as the threshold size ( $threshold ) " }
2024-08-06 00:19:55 +02:00
vssCommitment . forEach { publicKey ->
2024-08-19 21:40:56 +02:00
require ( publicKey . size == 33 || publicKey . size == 65 ) { " vss commitment data size should be 33 or 65 " }
2024-08-06 00:19:55 +02:00
}
}
2024-08-19 21:40:56 +02:00
require ( threshold > 1 ) { " threshold should be greater then 1 " }
require ( threshold <= totalShareCount ) { " Threshold can not be greater then the total share count " }
require ( id33 . size == 33 ) { " id size should be 33 " }
2024-08-04 23:53:28 +02:00
memScoped {
2024-08-06 00:19:55 +02:00
val nAggregateShare = alloc < secp256k1 _frost _share > ( )
val nAggregatePublicKey = alloc < secp256k1 _xonly _pubkey > ( )
2024-08-04 23:53:28 +02:00
val nTotalShares = totalShares . map { allocFrostShare ( it ) . ptr }
2024-08-05 22:34:45 +02:00
val nVssCommitments = allocArray < CPointerVar < secp256k1 _pubkey > > ( vssCommitments . size )
2024-08-22 10:47:18 +02:00
vssCommitments . forEachIndexed { index , commitments ->
val pubkeyArray = allocArray < secp256k1 _pubkey > ( commitments . size )
commitments . forEachIndexed { commitmentIndex , pubkeyData ->
pubkeyData . usePinned { pinned ->
if ( secp256k1 _ec _pubkey _parse ( ctx , pubkeyArray [ commitmentIndex ] . ptr , toNat ( pinned . get ( ) ) , pubkeyData . size . convert ( ) ) == 0 ) {
error ( " Failed to parse public key " )
}
2024-08-05 22:34:45 +02:00
}
2024-08-22 10:47:18 +02:00
}
nVssCommitments [ index ] = pubkeyArray
2024-08-04 23:53:28 +02:00
}
2024-08-19 21:40:56 +02:00
val result = secp256k1 _frost _share _agg (
2024-08-04 23:53:28 +02:00
ctx = ctx ,
2024-08-06 00:19:55 +02:00
agg _share = nAggregateShare . ptr ,
agg _pk = nAggregatePublicKey . ptr ,
2024-08-04 23:53:28 +02:00
shares = nTotalShares . toCValues ( ) ,
2024-08-05 22:34:45 +02:00
vss _commitments = nVssCommitments ,
2024-08-04 23:53:28 +02:00
n _shares = totalShareCount . convert ( ) ,
threshold = threshold . convert ( ) ,
id33 = toNat ( id33 )
)
2024-08-19 21:40:56 +02:00
println ( " Aggregate Result: $result " )
2024-08-04 23:53:28 +02:00
return Pair (
2024-08-06 00:19:55 +02:00
serializeFrostShare ( nAggregateShare ) ,
serializeXonlyPubkey ( nAggregatePublicKey )
2024-08-04 23:53:28 +02:00
)
}
}
override fun frostShareVerify (
threshold : Int ,
id33 : ByteArray ,
share : ByteArray ,
vssCommitment : Array < ByteArray >
) : Int {
2024-08-19 21:40:56 +02:00
require ( threshold > 1 ) { " threshold should be greater then 1 " }
2024-08-21 17:28:07 +02:00
require ( id33 . size == 33 ) { " id size ( ${id33.size} ) should be 33 " }
require ( share . size == Secp256k1 . FROST _SERIALIZED _SHARE _SIZE ) { " share size ( ${share.size} ) should be of size ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE} " }
2024-08-06 00:19:55 +02:00
2024-08-21 17:28:07 +02:00
require ( vssCommitment . size == threshold ) { " vss commitment array size ( ${vssCommitment.size} ) should be the same as the threshold size ( $threshold ) " }
2024-08-06 00:19:55 +02:00
vssCommitment . forEach { publicKey ->
2024-08-19 21:40:56 +02:00
require ( publicKey . size == 33 || publicKey . size == 65 ) { " vss commitment data size should be 33 or 65 " }
2024-08-06 00:19:55 +02:00
}
2024-08-04 23:53:28 +02:00
memScoped {
val nFrostShare = allocFrostShare ( share )
2024-08-22 10:47:18 +02:00
// val nVssCommitment = vssCommitment.map { allocPublicKey(it).ptr }.toCValues()
val nVssCommitment = allocArray < CPointerVar < secp256k1 _pubkey > > ( vssCommitment . size )
vssCommitment . forEachIndexed { index , pubkeyData ->
pubkeyData . usePinned { pinned ->
if ( secp256k1 _ec _pubkey _parse ( ctx , nVssCommitment [ index ] , toNat ( pinned . get ( ) ) , pubkeyData . size . convert ( ) ) == 0 ) {
error ( " Failed to parse public key " )
}
}
}
2024-08-04 23:53:28 +02:00
return secp256k1 _frost _share _verify (
ctx = ctx ,
2024-08-22 10:47:18 +02:00
threshold = vssCommitment . size . convert ( ) ,
id33 = toNat ( id33 ) ,
2024-08-04 23:53:28 +02:00
share = nFrostShare . ptr ,
2024-08-22 10:47:18 +02:00
vss _commitment = nVssCommitment
2024-08-04 23:53:28 +02:00
)
}
}
2024-08-05 22:34:45 +02:00
override fun frostComputePublicShare (
threshold : Int ,
id33 : ByteArray ,
vssCommitments : Array < Array < ByteArray > > ,
totalSignersCount : Int
) : ByteArray {
2024-08-18 01:27:04 +02:00
require ( threshold > 1 )
2024-08-06 00:19:55 +02:00
require ( threshold <= totalSignersCount )
require ( id33 . size == 33 )
require ( vssCommitments . size == totalSignersCount )
vssCommitments . forEach { vssCommitment ->
require ( vssCommitment . size == threshold )
vssCommitment . forEach { publicKey ->
require ( publicKey . size == 33 || publicKey . size == 65 )
}
}
2024-08-04 23:53:28 +02:00
memScoped {
2024-08-06 00:19:55 +02:00
val nPublicShare = alloc < secp256k1 _pubkey > ( )
2024-08-05 22:34:45 +02:00
val nVssCommitments = allocArray < CPointerVar < secp256k1 _pubkey > > ( vssCommitments . size )
2024-08-22 10:47:18 +02:00
vssCommitments . forEachIndexed { index , commitments ->
val pubkeyArray = allocArray < secp256k1 _pubkey > ( commitments . size )
commitments . forEachIndexed { commitmentIndex , pubkeyData ->
pubkeyData . usePinned { pinned ->
if ( secp256k1 _ec _pubkey _parse ( ctx , pubkeyArray [ commitmentIndex ] . ptr , toNat ( pinned . get ( ) ) , pubkeyData . size . convert ( ) ) == 0 ) {
error ( " Failed to parse public key " )
}
2024-08-05 22:34:45 +02:00
}
2024-08-22 10:47:18 +02:00
}
nVssCommitments [ index ] = pubkeyArray
2024-08-04 23:53:28 +02:00
}
2024-08-05 22:34:45 +02:00
2024-08-22 10:47:18 +02:00
val result = secp256k1 _frost _compute _pubshare (
2024-08-04 23:53:28 +02:00
ctx = ctx ,
2024-08-06 00:19:55 +02:00
pubshare = nPublicShare . ptr ,
2024-08-04 23:53:28 +02:00
threshold = threshold . convert ( ) ,
id33 = toNat ( id33 ) ,
vss _commitments = nVssCommitments ,
2024-08-05 22:34:45 +02:00
n _participants = totalSignersCount . convert ( )
2024-08-04 23:53:28 +02:00
)
2024-08-22 10:47:18 +02:00
println ( " Compute pubshare result: $result " )
2024-08-06 00:19:55 +02:00
return serializePubkey ( nPublicShare )
2024-08-04 23:53:28 +02:00
}
}
2024-08-06 00:19:55 +02:00
override fun frostPublicKeyTweak ( xOnlyPublicKey : ByteArray ) : ByteArray {
2024-08-21 17:28:07 +02:00
require ( xOnlyPublicKey . size == Secp256k1 . SERIALIZED _X _ONLY _PUBKEY _SIZE ) { " pubkey size ( ${xOnlyPublicKey.size} ) should be ${Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE} " }
2024-08-06 00:19:55 +02:00
2024-08-04 23:53:28 +02:00
memScoped {
val nTweakCache = alloc < secp256k1 _frost _tweak _cache > ( )
2024-08-06 00:19:55 +02:00
val nPublicKey = allocXonlyPublicKey ( xOnlyPublicKey )
2024-08-04 23:53:28 +02:00
secp256k1 _frost _pubkey _tweak (
ctx = ctx ,
tweak _cache = nTweakCache . ptr ,
agg _pk = nPublicKey . ptr
)
return serializeFrostTweakCache ( nTweakCache )
}
}
override fun frostPublicKeyEcTweakAdd ( tweakCache : ByteArray , tweak32 : ByteArray ) : ByteArray {
2024-08-06 00:19:55 +02:00
require ( tweakCache . size == Secp256k1 . FROST _TWEAK _CACHE _SIZE )
require ( tweak32 . size == 32 )
2024-08-04 23:53:28 +02:00
memScoped {
val nTweakCache = alloc < secp256k1 _frost _tweak _cache > ( )
memcpy ( nTweakCache . ptr , toNat ( tweakCache ) , Secp256k1 . FROST_TWEAK_CACHE_SIZE . toULong ( ) )
val nPublicKey = alloc < secp256k1 _pubkey > ( )
secp256k1 _frost _pubkey _ec _tweak _add (
ctx = ctx ,
output _pubkey = nPublicKey . ptr ,
tweak _cache = nTweakCache . ptr ,
tweak32 = toNat ( tweak32 )
)
return serializePubkey ( nPublicKey )
}
}
private fun MemScope . serializeFrostTweakCache ( nTweakCache : secp256k1 _frost _tweak _cache ) : ByteArray {
val natOutput = ByteArray ( Secp256k1 . FROST _TWEAK _CACHE _SIZE )
memcpy ( toNat ( natOutput ) , nTweakCache . ptr , Secp256k1 . FROST_TWEAK_CACHE_SIZE . toULong ( ) )
return natOutput
}
2024-08-13 01:41:45 +02:00
override fun frostPublicKeyXonlyTweakAdd ( tweakCache : ByteArray , tweak32 : ByteArray ) : ByteArray ? {
2024-08-06 00:19:55 +02:00
require ( tweakCache . size == Secp256k1 . FROST _TWEAK _CACHE _SIZE )
require ( tweak32 . size == 32 )
2024-08-04 23:53:28 +02:00
memScoped {
val nPublicKey = alloc < secp256k1 _pubkey > ( )
val nTweakCache = alloc < secp256k1 _frost _tweak _cache > ( )
memcpy ( nTweakCache . ptr , toNat ( tweakCache ) , Secp256k1 . FROST_TWEAK_CACHE_SIZE . toULong ( ) )
secp256k1 _frost _pubkey _xonly _tweak _add (
ctx = ctx ,
output _pubkey = nPublicKey . ptr ,
tweak _cache = nTweakCache . ptr ,
tweak32 = toNat ( tweak32 )
)
2024-08-13 01:41:45 +02:00
return serializePubkey ( nPublicKey )
2024-08-04 23:53:28 +02:00
}
}
private fun MemScope . serializeFrostSecnonce ( nTweakCache : secp256k1 _frost _secnonce ) : ByteArray {
val natOutput = ByteArray ( Secp256k1 . FROST _SECNONCE _SIZE )
memcpy ( toNat ( natOutput ) , nTweakCache . ptr , Secp256k1 . FROST_SECNONCE_SIZE . toULong ( ) )
return natOutput
}
private fun MemScope . serializeFrostPubnonce ( nPubnonce : secp256k1 _frost _pubnonce ) : ByteArray {
val natOutput = allocArray < UByteVar > ( Secp256k1 . FROST _SERIALIZED _PUBNONCE _SIZE )
secp256k1 _frost _pubnonce _serialize ( ctx , natOutput , nPubnonce . ptr ) . requireSuccess ( " secp256k1_frost_pubnonce_serialize() failed " )
return natOutput . readBytes ( Secp256k1 . FROST _SERIALIZED _PUBNONCE _SIZE )
}
override fun frostNonceGen (
sessionId32 : ByteArray ,
2024-08-07 02:48:25 +02:00
share : ByteArray ? ,
msg32 : ByteArray ? ,
publicKey : ByteArray ? ,
2024-08-04 23:53:28 +02:00
extraInput32 : ByteArray ?
) : Pair < ByteArray , ByteArray > {
2024-08-21 17:28:07 +02:00
require ( sessionId32 . size == 32 ) { " session id ( ${sessionId32.size} ) size should be 32 " }
2024-08-07 02:48:25 +02:00
share ?. let {
2024-08-21 17:28:07 +02:00
require ( share . size == Secp256k1 . FROST _SERIALIZED _SHARE _SIZE ) { " share size ( ${share.size} ) should be ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE} " }
2024-08-07 02:48:25 +02:00
}
msg32 ?. let {
2024-08-21 17:28:07 +02:00
require ( msg32 . size == 32 ) { " msg32 ( ${sessionId32.size} ) size should be 32 " }
2024-08-07 02:48:25 +02:00
}
publicKey ?. let {
2024-08-21 17:28:07 +02:00
require ( publicKey . size == 32 ) { " public key ( ${publicKey.size} ) should be 32 " }
2024-08-07 02:48:25 +02:00
}
2024-08-06 00:19:55 +02:00
extraInput32 ?. let {
2024-08-21 17:28:07 +02:00
require ( it . size == 32 ) { " extraInput32 ( ${extraInput32.size} ) size should be 32 " }
2024-08-06 00:19:55 +02:00
}
2024-08-04 23:53:28 +02:00
memScoped {
2024-08-06 00:19:55 +02:00
val nFrostSecnonce = alloc < secp256k1 _frost _secnonce > ( )
val nPublicNonce = alloc < secp256k1 _frost _pubnonce > ( )
2024-08-04 23:53:28 +02:00
2024-08-07 02:48:25 +02:00
val nShare = share ?. let { allocFrostShare ( it ) }
val nPublicKey = publicKey ?. let { allocXonlyPublicKey ( it ) }
2024-08-04 23:53:28 +02:00
val nExtraInput32 = extraInput32 ?. let {
toNat ( it )
}
secp256k1 _frost _nonce _gen (
ctx = ctx ,
2024-08-06 00:19:55 +02:00
secnonce = nFrostSecnonce . ptr ,
pubnonce = nPublicNonce . ptr ,
2024-08-04 23:53:28 +02:00
session _id32 = toNat ( sessionId32 ) ,
2024-08-07 02:48:25 +02:00
agg _share = nShare ?. ptr ,
msg32 = msg32 ?. let { toNat ( it ) } ,
agg _pk = nPublicKey ?. ptr ,
2024-08-04 23:53:28 +02:00
extra _input32 = nExtraInput32
)
return Pair (
2024-08-06 00:19:55 +02:00
serializeFrostSecnonce ( nFrostSecnonce ) ,
serializeFrostPubnonce ( nPublicNonce )
2024-08-04 23:53:28 +02:00
)
}
}
private fun MemScope . serializeFrostSession ( nSession : secp256k1 _frost _session ) : ByteArray {
val natOutput = ByteArray ( Secp256k1 . FROST _SESSION _SIZE )
memcpy ( toNat ( natOutput ) , nSession . ptr , Secp256k1 . FROST_SESSION_SIZE . toULong ( ) )
return natOutput
}
override fun frostNonceProcess (
publicNonces : Array < ByteArray > ,
2024-08-21 21:35:27 +02:00
threshold : Int ,
2024-08-04 23:53:28 +02:00
msg32 : ByteArray ,
publicKey : ByteArray ,
id33 : ByteArray ,
ids33 : Array < ByteArray > ,
2024-08-07 02:48:25 +02:00
tweakCache : ByteArray ? ,
2024-08-04 23:53:28 +02:00
adaptor : ByteArray ?
) : ByteArray {
2024-08-06 00:19:55 +02:00
publicNonces . forEach { publicNonce ->
2024-08-21 17:28:07 +02:00
require ( publicNonce . size == Secp256k1 . FROST _SERIALIZED _PUBNONCE _SIZE ) { " pubnonce size ( ${publicNonce.size} ) size should be ${Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE} " }
2024-08-06 00:19:55 +02:00
}
2024-08-21 17:28:07 +02:00
require ( msg32 . size == 32 ) { " msg32 ( ${msg32.size} ) size should be 32 " }
require ( publicKey . size == Secp256k1 . SERIALIZED _X _ONLY _PUBKEY _SIZE ) { " publicKey size ( ${publicKey.size} ) size should be ${Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE} " }
2024-08-21 21:35:27 +02:00
require ( ids33 . size == threshold ) { " ids33 array size much match public nonces array size " }
2024-08-06 00:19:55 +02:00
ids33 . forEach {
2024-08-21 17:28:07 +02:00
require ( it . size == 33 ) { " id33 ( ${it.size} ) size should be 33 " }
2024-08-06 00:19:55 +02:00
}
2024-08-07 02:48:25 +02:00
tweakCache ?. let {
2024-08-21 17:28:07 +02:00
require ( tweakCache . size == Secp256k1 . FROST _TWEAK _CACHE _SIZE ) { " tweak cache size ( ${tweakCache.size} ) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE} " }
2024-08-07 02:48:25 +02:00
}
2024-08-06 00:19:55 +02:00
adaptor ?. let {
2024-08-21 17:28:07 +02:00
require ( it . size == 33 || it . size == 65 ) { " adaptor public key size ( ${it.size} ) should be 33 or 65 " }
2024-08-06 00:19:55 +02:00
}
2024-08-04 23:53:28 +02:00
memScoped {
val nSession = alloc < secp256k1 _frost _session > ( ) ;
val nPublicNonces = publicNonces . map { allocFrostPublicNonce ( it ) . ptr }
val nPublicKey = allocXonlyPublicKey ( publicKey )
val nIds33 = ids33 . map { toNat ( it ) }
2024-08-07 02:48:25 +02:00
val nTweakCache = tweakCache ?. let {
alloc < secp256k1 _frost _tweak _cache > ( )
} ?. also { nTweakCache ->
memcpy ( nTweakCache . ptr , toNat ( tweakCache ) , Secp256k1 . FROST_TWEAK_CACHE_SIZE . toULong ( ) )
}
2024-08-04 23:53:28 +02:00
val nAdaptor = adaptor ?. let {
allocPublicKey ( it ) . ptr
}
2024-08-21 22:28:30 +02:00
2024-08-04 23:53:28 +02:00
secp256k1 _frost _nonce _process (
ctx = ctx ,
session = nSession . ptr ,
pubnonces = nPublicNonces . toCValues ( ) ,
n _pubnonces = publicNonces . size . convert ( ) ,
msg32 = toNat ( msg32 ) ,
agg _pk = nPublicKey . ptr ,
my _id33 = toNat ( id33 ) ,
ids33 = nIds33 . toCValues ( ) ,
2024-08-07 02:48:25 +02:00
tweak _cache = nTweakCache ?. ptr ,
2024-08-04 23:53:28 +02:00
adaptor = nAdaptor
)
return serializeFrostSession (
nSession = nSession
)
}
}
private fun MemScope . serializeFrostPartialSignature ( nPartialSignature : secp256k1 _frost _partial _sig ) : ByteArray {
val natOutput = allocArray < UByteVar > ( Secp256k1 . FROST _SERIALIZED _PARTIAL _SIGNATURE _SIZE )
secp256k1 _frost _partial _sig _serialize ( ctx , natOutput , nPartialSignature . ptr ) . requireSuccess ( " secp256k1_frost_partial_sig_serialize() failed " )
return natOutput . readBytes ( Secp256k1 . FROST _SERIALIZED _PARTIAL _SIGNATURE _SIZE )
}
override fun frostPartialSign (
secnonce : ByteArray ,
share : ByteArray ,
session : ByteArray ,
2024-08-07 02:48:25 +02:00
tweakCache : ByteArray ?
2024-08-04 23:53:28 +02:00
) : ByteArray {
2024-08-21 17:28:07 +02:00
require ( secnonce . size == Secp256k1 . FROST _SECNONCE _SIZE ) { " secnonce size ( ${secnonce.size} ) should be of size ${Secp256k1.FROST_SECNONCE_SIZE} " }
require ( share . size == Secp256k1 . FROST _SERIALIZED _SHARE _SIZE ) { " share size ( ${share.size} ) should be of size ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE} " }
require ( session . size == Secp256k1 . FROST _SESSION _SIZE ) { " session size ( ${share.size} ) should be of size ${Secp256k1.FROST_SESSION_SIZE} " }
2024-08-07 02:48:25 +02:00
tweakCache ?. let {
2024-08-21 17:28:07 +02:00
require ( tweakCache . size == Secp256k1 . FROST _TWEAK _CACHE _SIZE ) { " tweak cache size ( ${tweakCache.size} ) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE} " }
2024-08-07 02:48:25 +02:00
}
2024-08-04 23:53:28 +02:00
memScoped {
val nPartialSignature = alloc < secp256k1 _frost _partial _sig > ( ) ;
val nSecnonce = alloc < secp256k1 _frost _secnonce > ( )
memcpy ( nSecnonce . ptr , toNat ( secnonce ) , Secp256k1 . FROST_SECNONCE_SIZE . toULong ( ) )
val nShare = allocFrostShare ( share )
val nSession = alloc < secp256k1 _frost _session > ( )
memcpy ( nSession . ptr , toNat ( session ) , Secp256k1 . FROST_SESSION_SIZE . toULong ( ) )
2024-08-07 02:48:25 +02:00
val nTweakCache = tweakCache ?. let {
alloc < secp256k1 _frost _tweak _cache > ( )
} ?. also { nTweakCache ->
memcpy ( nTweakCache . ptr , toNat ( tweakCache ) , Secp256k1 . FROST_TWEAK_CACHE_SIZE . toULong ( ) )
}
2024-08-04 23:53:28 +02:00
secp256k1 _frost _partial _sign (
ctx ,
nPartialSignature . ptr ,
nSecnonce . ptr ,
nShare . ptr ,
nSession . ptr ,
2024-08-07 02:48:25 +02:00
nTweakCache ?. ptr
2024-08-04 23:53:28 +02:00
)
return serializeFrostPartialSignature ( nPartialSignature )
}
}
override fun frostPartialSignatureVerify (
partialSig : ByteArray ,
publicNonce : ByteArray ,
publicShare : ByteArray ,
session : ByteArray ,
2024-08-07 02:48:25 +02:00
tweakCache : ByteArray ?
2024-08-04 23:53:28 +02:00
) : Int {
2024-08-21 17:28:07 +02:00
require ( partialSig . size == 32 ) { " partialSig ( ${partialSig.size} ) size should be 32 " }
require ( publicNonce . size == Secp256k1 . FROST _SERIALIZED _PUBNONCE _SIZE ) { " public nonce ( ${publicNonce.size} ) size should be ${Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE} " }
require ( publicShare . size == 33 || publicShare . size == 65 ) { " public share size ( ${partialSig.size} ) should be 33 or 65 " }
require ( session . size == Secp256k1 . FROST _SESSION _SIZE ) { " session size ( ${session.size} ) size should be ${Secp256k1.FROST_SESSION_SIZE} " }
2024-08-07 02:48:25 +02:00
tweakCache ?. let {
2024-08-21 17:28:07 +02:00
require ( tweakCache . size == Secp256k1 . FROST _TWEAK _CACHE _SIZE ) { " tweak cache size ( ${tweakCache.size} ) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE} " }
2024-08-07 02:48:25 +02:00
}
2024-08-04 23:53:28 +02:00
memScoped {
val nPartialSignature = allocFrostPartialSignature ( partialSig )
val nPublicNonce = allocFrostPublicNonce ( publicNonce )
val nPublicShare = allocPublicKey ( publicShare )
val nSession = alloc < secp256k1 _frost _session > ( )
memcpy ( nSession . ptr , toNat ( session ) , Secp256k1 . FROST_SESSION_SIZE . toULong ( ) )
2024-08-07 02:48:25 +02:00
val nTweakCache = tweakCache ?. let {
alloc < secp256k1 _frost _tweak _cache > ( )
} ?. also { nTweakCache ->
memcpy ( nTweakCache . ptr , toNat ( tweakCache ) , Secp256k1 . FROST_TWEAK_CACHE_SIZE . toULong ( ) )
}
2024-08-04 23:53:28 +02:00
return secp256k1 _frost _partial _sig _verify (
ctx ,
nPartialSignature . ptr ,
nPublicNonce . ptr ,
nPublicShare . ptr ,
nSession . ptr ,
2024-08-07 02:48:25 +02:00
nTweakCache ?. ptr
2024-08-04 23:53:28 +02:00
)
}
}
2024-08-21 21:35:27 +02:00
override fun frostPartialSignatureAggregate (
session : ByteArray ,
partialSignatures : Array < ByteArray > ,
threshold : Int
) : ByteArray {
require ( threshold > 1 ) { " threshold must be greater then 1 " }
require ( session . size == Secp256k1 . FROST _SESSION _SIZE ) { " session size ( ${session.size} ) should be ${Secp256k1.FROST_SESSION_SIZE} " }
require ( partialSignatures . size == threshold ) { " partialSignatures array size should match the threshold size " }
2024-08-06 00:19:55 +02:00
partialSignatures . forEach { partialSig ->
2024-08-21 21:35:27 +02:00
require ( partialSig . size == 32 ) { " partialSignatures size ( ${partialSig.size} ) should be 32 " }
2024-08-06 00:19:55 +02:00
}
2024-08-04 23:53:28 +02:00
memScoped {
val sig64 = ByteArray ( 64 )
val nSession = alloc < secp256k1 _frost _session > ( ) ;
memcpy ( nSession . ptr , toNat ( session ) , Secp256k1 . FROST_SESSION_SIZE . toULong ( ) )
val nPartialSignatures = partialSignatures . map { allocFrostPartialSignature ( it ) . ptr }
secp256k1 _frost _partial _sig _agg (
ctx ,
toNat ( sig64 ) ,
nSession . ptr ,
nPartialSignatures . toCValues ( ) ,
2024-08-21 21:35:27 +02:00
threshold . convert ( )
2024-08-04 23:53:28 +02:00
)
return sig64
}
}
2024-02-14 13:28:22 +01:00
public override fun cleanup ( ) {
secp256k1 _context _destroy ( ctx )
}
2020-06-26 17:10:48 +02:00
}
2020-07-01 12:46:04 +02:00
internal actual fun getSecpk256k1 ( ) : Secp256k1 = Secp256k1Native