From 5117507f25d477db51c96ac717facbb7bbddda6d Mon Sep 17 00:00:00 2001 From: kngako Date: Wed, 21 Aug 2024 17:28:07 +0200 Subject: [PATCH] Full tests on native --- .../kotlin/fr/acinq/secp256k1/Secp256k1.kt | 12 +- .../fr/acinq/secp256k1/Secp256k1Native.kt | 50 +++---- .../kotlin/fr/acinq/secp256k1/FrostTest.kt | 127 ++++++++++++++---- .../resources/frost/frost_nonce_vectors.json | 27 ++-- 4 files changed, 151 insertions(+), 65 deletions(-) diff --git a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt index 5f590b9..c92005e 100644 --- a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt @@ -329,12 +329,12 @@ public interface Secp256k1 { public const val FROST_PARTIAL_SIGNATURE_SIZE: Int = 36 - public const val FROST_SHARE_SIZE: Int = 32 - public const val FROST_TWEAK_CACHE_SIZE: Int = 102 - public const val FROST_SESSION_SIZE: Int = 134 - public const val FROST_SECNONCE_SIZE: Int = 69 - public const val FROST_PUBNONCE_SIZE: Int = 133 - public const val FROST_SERIALIZED_PARTIAL_SIGNATURE_SIZE: Int = 33 + public const val FROST_SHARE_SIZE: Int = 36 + public const val FROST_TWEAK_CACHE_SIZE: Int = 101 + public const val FROST_SESSION_SIZE: Int = 133 + public const val FROST_SECNONCE_SIZE: Int = 68 + public const val FROST_PUBNONCE_SIZE: Int = 132 + public const val FROST_SERIALIZED_PARTIAL_SIGNATURE_SIZE: Int = 32 public const val FROST_SERIALIZED_SHARE_SIZE: Int = 32 public const val FROST_SERIALIZED_PUBNONCE_SIZE: Int = 66 // @formatter:on diff --git a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt index b8c6cb8..aa80158 100644 --- a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt +++ b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt @@ -522,7 +522,7 @@ public object Secp256k1Native : Secp256k1 { } private fun MemScope.serializeFrostShare(nFrostShare: secp256k1_frost_share): ByteArray { - val natOutput = allocArray(Secp256k1.FROST_SHARE_SIZE) + val natOutput = allocArray(Secp256k1.FROST_SERIALIZED_SHARE_SIZE) secp256k1_frost_share_serialize(ctx, natOutput, nFrostShare.ptr).requireSuccess("secp256k1_frost_share_serialize() failed") return natOutput.readBytes(Secp256k1.FROST_SERIALIZED_SHARE_SIZE) } @@ -589,10 +589,10 @@ public object Secp256k1Native : Secp256k1 { vssCommitment: Array ): Int { require(threshold > 1) { "threshold should be greater then 1" } - require(id33.size == 33) { "id size should be 33" } - require(share.size == Secp256k1.FROST_SHARE_SIZE) { "all shares should be of size 32" } + 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}" } - require(vssCommitment.size == threshold) { "all vss commitment array size (${vssCommitment.size}) should be the same as the threshold size ($threshold)" } + require(vssCommitment.size == threshold) { "vss commitment array size (${vssCommitment.size}) should be the same as the threshold size ($threshold)" } vssCommitment.forEach { publicKey -> require(publicKey.size == 33 || publicKey.size == 65) { "vss commitment data size should be 33 or 65" } } @@ -656,7 +656,7 @@ public object Secp256k1Native : Secp256k1 { } override fun frostPublicKeyTweak(xOnlyPublicKey: ByteArray): ByteArray { - require(xOnlyPublicKey.size == Secp256k1.X_ONLY_PUBKEY_SIZE) + require(xOnlyPublicKey.size == Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE) { "pubkey size (${xOnlyPublicKey.size}) should be ${Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE}" } memScoped { val nTweakCache = alloc() @@ -738,18 +738,18 @@ public object Secp256k1Native : Secp256k1 { publicKey: ByteArray?, extraInput32: ByteArray? ): Pair { - require(sessionId32.size == 32) + require(sessionId32.size == 32) { "session id (${sessionId32.size}) size should be 32" } share?.let { - require(share.size == Secp256k1.FROST_SHARE_SIZE) + require(share.size == Secp256k1.FROST_SERIALIZED_SHARE_SIZE) { "share size (${share.size}) should be ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE}" } } msg32?.let { - require(msg32.size == 33) + require(msg32.size == 32) { "msg32 (${sessionId32.size}) size should be 32" } } publicKey?.let { - require(publicKey.size == 33 || publicKey.size == 65) + require(publicKey.size == 32) { "public key (${publicKey.size}) should be 32" } } extraInput32?.let { - require(it.size == 33) + require(it.size == 32) { "extraInput32 (${extraInput32.size}) size should be 32" } } memScoped { @@ -796,18 +796,18 @@ public object Secp256k1Native : Secp256k1 { adaptor: ByteArray? ): ByteArray { publicNonces.forEach { publicNonce -> - require(publicNonce.size == Secp256k1.FROST_PUBNONCE_SIZE) + require(publicNonce.size == Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE) { "pubnonce size (${publicNonce.size}) size should be ${Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE}" } } - require(msg32.size == 32) - require(publicKey.size == 33 || publicKey.size == 65) + 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}" } ids33.forEach { - require(it.size == 33) + require(it.size == 33) { "id33 (${it.size}) size should be 33" } } tweakCache?.let { - require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) { "tweak cache size (${tweakCache.size}) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE}" } } adaptor?.let { - require(it.size == 33 || it.size == 65) + require(it.size == 33 || it.size == 65) { "adaptor public key size (${it.size}) should be 33 or 65" } } memScoped { @@ -861,11 +861,11 @@ public object Secp256k1Native : Secp256k1 { session: ByteArray, tweakCache: ByteArray? ): ByteArray { - require(secnonce.size == Secp256k1.FROST_SECNONCE_SIZE) - require(share.size == Secp256k1.FROST_SHARE_SIZE) - require(session.size == Secp256k1.FROST_SESSION_SIZE) + 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}" } tweakCache?.let { - require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) { "tweak cache size (${tweakCache.size}) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE}" } } @@ -907,12 +907,12 @@ public object Secp256k1Native : Secp256k1 { session: ByteArray, tweakCache: ByteArray? ): Int { - require(partialSig.size == 32) - require(publicNonce.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE) - require(publicShare.size == 33 || publicShare.size == 65) - require(session.size == Secp256k1.FROST_SESSION_SIZE) + 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}" } tweakCache?.let { - require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) { "tweak cache size (${tweakCache.size}) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE}" } } diff --git a/tests/src/commonTest/kotlin/fr/acinq/secp256k1/FrostTest.kt b/tests/src/commonTest/kotlin/fr/acinq/secp256k1/FrostTest.kt index b0fcf69..c3b0c59 100644 --- a/tests/src/commonTest/kotlin/fr/acinq/secp256k1/FrostTest.kt +++ b/tests/src/commonTest/kotlin/fr/acinq/secp256k1/FrostTest.kt @@ -21,8 +21,6 @@ class FrostTest: BaseTest() { val threshold = validTestCases.jsonObject["threshold"]!!.jsonPrimitive.int val ids33 = keyIndices.map { pubkeys[it] }.toTypedArray() - println("Testing $keyIndices") - val result = Secp256k1.frostSharesGen( seed32, threshold, @@ -38,24 +36,18 @@ class FrostTest: BaseTest() { result.first.forEachIndexed { index, share -> - println( - Hex.encode(share) + assertEquals( + expected = Hex.encode(expectedShare[index]), + actual = Hex.encode(share), + "Unexpected $index:share for $keyIndices test case" ) -// assertEquals( -// expected = Hex.encode(expectedShare[index]), -// actual = Hex.encode(share), -// "Unexpected $index:share for $keyIndices test case" -// ) } result.second.forEachIndexed { index, vssCommitment -> - println( - Hex.encode(vssCommitment) + assertEquals( + expected = Hex.encode(expectedVSSCommitment[index]), + actual = Hex.encode(vssCommitment), + "Unexpected $index:vss_commitment for the $keyIndices test case" ) -// assertEquals( -// expected = Hex.encode(expectedVSSCommitment[index]), -// actual = Hex.encode(vssCommitment), -// "Unexpected $index:vss_commitment for the $keyIndices test case" -// ) } assertEquals( expected = Hex.encode(expectedPoK64), @@ -458,28 +450,115 @@ class FrostTest: BaseTest() { null ) -// assertEquals( -// expected = signer.jsonObject["session"]!!.jsonPrimitive.content, -// actual = Hex.encode(session), -// message = "Invalid $signerIndex:session" -// ) + assertEquals( + expected = signer.jsonObject["session"]!!.jsonPrimitive.content, + actual = Hex.encode(session), + message = "Invalid $signerIndex:session" + ) } - - } @Test - fun `frost partial sign `() { + fun `frost partial sign`() { + val tests = readData("frost/frost_nonce_vectors.json") + + val tweakCache = Hex.decode( + tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content + ) + + tests.jsonObject["signers"]!!.jsonArray.forEachIndexed { signerIndex, signer -> + + val secNonce = Hex.decode( + signer.jsonObject["secnonce"]!!.jsonPrimitive.content + ) + + val aggregateShare = Hex.decode( + signer.jsonObject["aggregate_share"]!!.jsonPrimitive.content + ) + + val session = Hex.decode( + signer.jsonObject["session"]!!.jsonPrimitive.content + ) + + + val partialSignature = Secp256k1.frostPartialSign( + secNonce, + aggregateShare, + session, + tweakCache + ) + + assertEquals( + expected = signer.jsonObject["partial_signature"]!!.jsonPrimitive.content, + actual = Hex.encode(partialSignature), + message = "Invalid $signerIndex:partial signature" + ) + } } @Test fun `frost partial signature verify`() { + val tests = readData("frost/frost_nonce_vectors.json") + val tweakCache = Hex.decode( + tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content + ) + + tests.jsonObject["signers"]!!.jsonArray.forEach { signer -> + val partialSignature = Hex.decode( + signer.jsonObject["partial_signature"]!!.jsonPrimitive.content + ) + + val pubNonce = Hex.decode( + signer.jsonObject["pubnonce"]!!.jsonPrimitive.content + ) + + val publicShare = Hex.decode( + signer.jsonObject["public_share"]!!.jsonPrimitive.content + ) + + val session = Hex.decode( + signer.jsonObject["session"]!!.jsonPrimitive.content + ) + + assertEquals( + expected = 1, + actual = Secp256k1.frostPartialSignatureVerify( + partialSignature, + pubNonce, + publicShare, + session, + tweakCache + ), + message = "Failed to verify partial signature" + ) + } } @Test fun `frost partial signature aggregation`() { + val tests = readData("frost/frost_nonce_vectors.json") + val partialSignatures = tests.jsonObject["signers"]!!.jsonArray.map { + Hex.decode(it.jsonObject["partial_signature"]!!.jsonPrimitive.content) + } + + tests.jsonObject["signers"]!!.jsonArray.forEach { signer -> + val session = Hex.decode( + signer.jsonObject["session"]!!.jsonPrimitive.content + ) + + val aggregatedSignature = Secp256k1.frostPartialSignatureAggregate( + session, + partialSignatures.toTypedArray(), + ) + + assertEquals( + expected = tests.jsonObject["aggregate_signature"]!!.jsonPrimitive.content, + actual = Hex.encode(aggregatedSignature), + message = "Invalid aggregate partial signature" + ) + } } } \ No newline at end of file diff --git a/tests/src/commonTest/resources/frost/frost_nonce_vectors.json b/tests/src/commonTest/resources/frost/frost_nonce_vectors.json index 8d91f06..cc31c2d 100644 --- a/tests/src/commonTest/resources/frost/frost_nonce_vectors.json +++ b/tests/src/commonTest/resources/frost/frost_nonce_vectors.json @@ -6,41 +6,48 @@ "03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659", "04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9" ], + "threshold": 3, "aggregate_public_key": "bd5561ef6dbff52d3f73b8cb0c065328988b71d3386d23890744a0dd6ad27c15", + "aggregate_signature": "1c34b007ec896279304e7fbd80730991bd547b50b212fcdd983340c5392bfa6ede56bbf6dd50926cae1723119225572ac555dce37f9b0033a255ef233b5ac539", "session_id": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671", "tweak_cache": "40252e41157cd26adda0440789236d38d3718b982853060ccbb8733f2df5bf6def6155bdeefcc6b83fe690d621b793b08f5b1562a7bef628c4db33f2d0b3f3bf2f541aaa000000000000000000000000000000000000000000000000000000000000000000", "signers": [ { - "session": "5c11a803006f7c9545e2bb3482d468ca0eb3e13070730f9cb3d42402cfa29bb54876d208af362b2645f6cbd0b4b7de7d6e98b48c7dda48bc74d93fdca4b40077f278f868c2a92d82c8961b2f3663c44ea5928338e3cdf1e468a6a84bdd5a9c96158e0176dd0000000000000000000000000000000000000000000000000000000000000000", - "secnonce": "847d4625fe87e00f9562351a9b7de8fc2420caba09535db177fc4fbac5b69b84c8700ae143946a0fffff4083d6377ee19a6448a55241160fbc7c793aace02f289a2fec8f03", + "partial_signature": "12a1bb40ef57c0be9c00641ad59c406a2b8b2624227c48f43291516fc906d935", + "session": "5c11a803011c34b007ec896279304e7fbd80730991bd547b50b212fcdd983340c5392bfa6ee8d4b3288f9364e296c1516a09aa3e34605421a6536e2eaf2a341343b9a76443b59b5c7df0aebbb9fab718c312d862c85d4b25aeb20de84d3ef1a1aad667c3360000000000000000000000000000000000000000000000000000000000000000", + "secnonce": "847d4625fe87e00f9562351a9b7de8fc2420caba09535db177fc4fbac5b69b84c8700ae143946a0fffff4083d6377ee19a6448a55241160fbc7c793aace02f289a2fec8f", "pubnonce": "03203a0450540686854df68f6c1d15661772e4d05c4442ee1e437d86842779ef2202d03839fd99faf7a11ccc319a9adc965c5e094ca3728455059a4911ae96192fae", "aggregate_share": "1cfa28492e84e945343f1167401cdce061202a59e47e050c0c2f7f0c56e8e148", "public_share": "0493effba7e50d3885bb0c4665149abd4fd13622047412f1da4c0e3754ecb1a9183aaadfdf0f2f82e24641e6ed7a0f7ee22a4a8a47c6d2df66daad37a4880fffe2" }, { - "session": "5c11a803001476eca00d1754deddff97f25479a0d9dbddaf6b1895d0b181d3fa0ebefd012c1192ed7ff2480492cbc95bea67211ec7148560882817b0fd655963dc65ae53dd69f0286afb3238617e485141eba41585ab5b92f708905f09cdfed710b070a70c0000000000000000000000000000000000000000000000000000000000000000", - "secnonce": "847d4625e6af707cb69026251afdfc2570a3fbdbbc7e72530354f0777fe2192c6aa8b23969172508dff48f7a21827935cce2ed019c570bb5552f9a3269a8ec34cfd23e2c03", + "partial_signature": "d504eaf51c4985f1f1c6d1fcaef0b4d934752e1e4bfd76cd86c6baed0d915e21", + "session": "5c11a803011c34b007ec896279304e7fbd80730991bd547b50b212fcdd983340c5392bfa6ee8d4b3288f9364e296c1516a09aa3e34605421a6536e2eaf2a341343b9a7644376dba5ba367ff93f06b8230cbbab6b608a175463168ea0a9ee175b7909f438b80000000000000000000000000000000000000000000000000000000000000000", + "secnonce": "847d4625e6af707cb69026251afdfc2570a3fbdbbc7e72530354f0777fe2192c6aa8b23969172508dff48f7a21827935cce2ed019c570bb5552f9a3269a8ec34cfd23e2c", "pubnonce": "035c8f36d2cf868b9ccab3221b3f5eca64d60469a50245d6edc3b4f4bfb4358892023e832dcc0b5b55562ef6f1536679a2e996827747d3b824ca335daf00d51ab788", "aggregate_share": "dd82fcc1806f1a968228c794a7001c18d209871fb3441bae80fd8229f6a9b0dd", "public_share": "048482e27b533879d4f3d68bdb2038bf9480d4ce4cc614d7133238e55179c65a175c684afb7f983e60139542b80f0f12815f3194082f07c93e1f87f3cd1b1c0d8b" }, { - "session": "5c11a803001476eca00d1754deddff97f25479a0d9dbddaf6b1895d0b181d3fa0ebefd012c1192ed7ff2480492cbc95bea67211ec7148560882817b0fd655963dc65ae53dd4e14c7a8b2b8aef94b7a5938d1ad2906e707302cca6bc3be90dba25565803ea40000000000000000000000000000000000000000000000000000000000000000", - "secnonce": "847d4625bd32503f81d016175829db4df8475660c77e28cf6dc7bc8b2f6e3fe6f67282b1cf81dcf2dabd867053461cf602f3e3345f42119066f4c493b85a0744ae7beb0802", + "partial_signature": "0e82e07de474c83387118c9b353b7ebbeeabd0279645d6ae499546df3b301d59", + "session": "5c11a803011c34b007ec896279304e7fbd80730991bd547b50b212fcdd983340c5392bfa6ee8d4b3288f9364e296c1516a09aa3e34605421a6536e2eaf2a341343b9a764436bc4ab3b7a585b2a759366523cb83fb2ff8b166e2503abd0f24ec58868bde3440000000000000000000000000000000000000000000000000000000000000000", + "secnonce": "847d4625bd32503f81d016175829db4df8475660c77e28cf6dc7bc8b2f6e3fe6f67282b1cf81dcf2dabd867053461cf602f3e3345f42119066f4c493b85a0744ae7beb08", "pubnonce": "028b80bb46028338d41101deacd7910e09ba148f75d2c01e9f8f767fa9cdcbbc7e02b0cec1ba331750a22bf3bb8d1b724bd2874f7f0c19c70227f64c463c8c6bcab2", "aggregate_share": "5fe629d5f34fdb3ea2f6e545fc3d2cf1f5ce23a504b144e6ebe928793cc85cb4", "public_share": "04d71784b58d8958141f8f405d56026f214a736e73f9c1f70776fc2e49f4e90fc0a9396bcc7471a83caf4076a18cb6ab4264aa37174ca19e142259aa5f6bb7fea3" }, { - "session": "5c11a803001476eca00d1754deddff97f25479a0d9dbddaf6b1895d0b181d3fa0ebefd012c1192ed7ff2480492cbc95bea67211ec7148560882817b0fd655963dc65ae53ddb68d444ba93f7adad7758d1efaa6895dce34947f18789783b43fcff9ca50c28d0000000000000000000000000000000000000000000000000000000000000000", - "secnonce": "847d4625f2128d893c4b8b62818bbc972d158b0aa96b08dcacba149dd7517b7fc7ddb89b70234941338c242dbca6e27ebf337ae458381ef83bea4ba2baab8df3d7f6b77303", + "partial_signature": "c7158af40413f8174d38a36ae83737f633f183c45e83ec9caa88afe9e0ed9a4a", + "session": "5c11a803011c34b007ec896279304e7fbd80730991bd547b50b212fcdd983340c5392bfa6ee8d4b3288f9364e296c1516a09aa3e34605421a6536e2eaf2a341343b9a7644347dededd1bcf6c4294a994e867475e5c52ef861b240fe8ff717fe73f6bf0426b0000000000000000000000000000000000000000000000000000000000000000", + "secnonce": "847d4625f2128d893c4b8b62818bbc972d158b0aa96b08dcacba149dd7517b7fc7ddb89b70234941338c242dbca6e27ebf337ae458381ef83bea4ba2baab8df3d7f6b773", "pubnonce": "030b4d942e88b7674819f3020c290db1162beda60bae05964bb344378166ec61a20221e3e76bfa50c22b98832d451d51e3b7cdef420a2b06e9a29373449aa77aa46c", "aggregate_share": "71181e5b46742333f12672d85d0e1472770a082f0a62d3d204c9e191fb45ef91", "public_share": "04ec0fb2b4c1ac2d9b761f32cb2972e6d6fb74ed4195d872aeaaf4306bb64eb465580d03102849363ec49c3d1eecdd239337d0a66cdfc4d74c29c824c0f941832a" }, { - "session": "5c11a803001476eca00d1754deddff97f25479a0d9dbddaf6b1895d0b181d3fa0ebefd012c1192ed7ff2480492cbc95bea67211ec7148560882817b0fd655963dc65ae53ddb5fe593c0f5ae3e7da52ff37cbe1e150a3ff4dca3e57a781979b2a79ba7056660000000000000000000000000000000000000000000000000000000000000000", - "secnonce": "847d4625ee1f0f41a485d2399b024b05d9a9b7cbb846cf107dcbfa125a136448cbd20441a5bbea0b8908781249bbd7a5f6c429e1678338d8a2f5a9095a85fd541cb4988403", + "partial_signature": "2117aa4ee9268b714c05bcf3f025ab33fd67119bcba01d62b4b24a8a18db1781", + "session": "5c11a803011c34b007ec896279304e7fbd80730991bd547b50b212fcdd983340c5392bfa6ee8d4b3288f9364e296c1516a09aa3e34605421a6536e2eaf2a341343b9a76443dad0efbc20454b2dc409cb6c7cfec24e3d45d3d417de97e47df531e11ef188450000000000000000000000000000000000000000000000000000000000000000", + "secnonce": "847d4625ee1f0f41a485d2399b024b05d9a9b7cbb846cf107dcbfa125a136448cbd20441a5bbea0b8908781249bbd7a5f6c429e1678338d8a2f5a9095a85fd541cb49884", "pubnonce": "034a67a3dbe320486110fac55f4e7ef4f5c5216766b8e4d635c6f1119a5c5e75a3026ada48e6491d2c9890f65fd3f9d675f644df9224b5beb5fc41b2934bc28d9bcc", "aggregate_share": "15bc5e3eeb4ec318a718b3015b78e8496cc5ede81c05727936ade625532dce55", "public_share": "04b3ad3909e919f1a27faff7a3aec8f04a9ca54a065d9774ae37c3b9903ad4a19b71f11e148b549ef168465d065279f773175b254f64573e7ce30f4aba0954be19"