Implement musig2

This commit is contained in:
sstone
2023-12-12 10:02:27 +01:00
parent 3a983128c2
commit 951c843e27
12 changed files with 1029 additions and 9 deletions

View File

@@ -352,6 +352,119 @@ class Secp256k1Test {
}
}
@Test
fun testMusig2GenerateNonce() {
val pubkey = Hex.decode("02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9")
val sessionId = Hex.decode("0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F")
val nonce = Secp256k1.musigNonceGen(sessionId, null, pubkey, null, null, null)
val pubnonce = Hex.encode(nonce.copyOfRange(132, 132 + 66)).uppercase()
assertEquals("02C96E7CB1E8AA5DAC64D872947914198F607D90ECDE5200DE52978AD5DED63C000299EC5117C2D29EDEE8A2092587C3909BE694D5CFF0667D6C02EA4059F7CD9786", pubnonce)
}
@Test
fun testMusig2AggregateNonce() {
val nonces = listOf(
"020151C80F435648DF67A22B749CD798CE54E0321D034B92B709B567D60A42E66603BA47FBC1834437B3212E89A84D8425E7BF12E0245D98262268EBDCB385D50641",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833",
"020151C80F435648DF67A22B749CD798CE54E0321D034B92B709B567D60A42E6660279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60379BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"04FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B831",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A602FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"
).map { Hex.decode(it) }
val agg1 = Secp256k1.musigNonceAgg(arrayOf(nonces[0], nonces[1]))
assertEquals("035FE1873B4F2967F52FEA4A06AD5A8ECCBE9D0FD73068012C894E2E87CCB5804B024725377345BDE0E9C33AF3C43C0A29A9249F2F2956FA8CFEB55C8573D0262DC8", Hex.encode(agg1).uppercase())
val agg2 = Secp256k1.musigNonceAgg(arrayOf(nonces[2], nonces[3]))
assertEquals("035FE1873B4F2967F52FEA4A06AD5A8ECCBE9D0FD73068012C894E2E87CCB5804B000000000000000000000000000000000000000000000000000000000000000000", Hex.encode(agg2).uppercase())
assertFails {
Secp256k1.musigNonceAgg(arrayOf(nonces[0], nonces[4]))
}
assertFails {
Secp256k1.musigNonceAgg(arrayOf(nonces[5], nonces[1]))
}
assertFails {
Secp256k1.musigNonceAgg(arrayOf(nonces[6], nonces[1]))
}
}
@Test
fun testMusig2AggregatePubkey() {
val pubkeys = listOf(
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
"020000000000000000000000000000000000000000000000000000000000000005",
"02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30",
"04F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
).map { Hex.decode(it) }
val agg1 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[1], pubkeys[2]), null)
assertEquals("90539EEDE565F5D054F32CC0C220126889ED1E5D193BAF15AEF344FE59D4610C", Hex.encode(agg1).uppercase())
val cache = ByteArray(197)
val agg2 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[1], pubkeys[2]), cache)
assertEquals("90539EEDE565F5D054F32CC0C220126889ED1E5D193BAF15AEF344FE59D4610C", Hex.encode(agg2).uppercase())
val agg3 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[2], pubkeys[1], pubkeys[0]), null)
assertEquals("6204DE8B083426DC6EAF9502D27024D53FC826BF7D2012148A0575435DF54B2B", Hex.encode(agg3).uppercase())
val agg4 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[0], pubkeys[0]), null)
assertEquals("B436E3BAD62B8CD409969A224731C193D051162D8C5AE8B109306127DA3AA935", Hex.encode(agg4).uppercase())
val agg5 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[0], pubkeys[1], pubkeys[1]), null)
assertEquals("69BC22BFA5D106306E48A20679DE1D7389386124D07571D0D872686028C26A3E", Hex.encode(agg5).uppercase())
}
@Test
fun testMusig2TweakPubkeys() {
val pubkeys = listOf(
"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
"024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
"02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337"
).map { Hex.decode(it) }.toTypedArray()
val cache = ByteArray(197)
val agg1 = Secp256k1.musigPubkeyAdd(pubkeys, cache)
assertEquals("b6d830642403fc82511aca5ff98a5e76fcef0f89bffc1aadbe78ee74cd5a5716", Hex.encode(agg1))
val agg2 = Secp256k1.musigPubkeyTweakAdd(cache, Hex.decode("7468697320636f756c64206265206120424950333220747765616b2e2e2e2e00"))
assertEquals("04791e4f22a21f19bd9798eceab92ad2ccc18f2d6660e91ae4c0709aaebf1aa9023701f468b0eddf8973495a5327f2169d9c6a50eb6a0f87c0fbee90a4067eb230", Hex.encode(agg2))
val agg3 = Secp256k1.musigPubkeyXonlyTweakAdd(cache, Hex.decode("7468697320636f756c64206265206120746170726f6f7420747765616b2e2e00"))
assertEquals("04537a081a8d32ff700ca86aaa77a423e9b8d1480938076b645c68ee39d263c93948026928799b2d942cb5851db397015b26b1759de1b9ab2c691ced64a2eef836", Hex.encode(agg3))
}
@Test
fun testMusig2SigningSession() {
val privkeys = listOf(
"0101010101010101010101010101010101010101010101010101010101010101",
"0202020202020202020202020202020202020202020202020202020202020202",
).map { Hex.decode(it) }.toTypedArray()
val pubkeys = privkeys.map { Secp256k1.pubkeyCreate(it) }
val sessionId = Hex.decode("0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F")
val nonces = pubkeys.map { Secp256k1.musigNonceGen(sessionId, null, it, null, null, null) }
val secnonces = nonces.map { it.copyOfRange(0, 132) }
val pubnonces = nonces.map { it.copyOfRange(132, 132 + 66) }
val aggnonce = Secp256k1.musigNonceAgg(pubnonces.toTypedArray())
val caches = (0 until 2).map { ByteArray(197) }
val aggpubkey = Secp256k1.musigPubkeyAdd(pubkeys.toTypedArray(), caches[0])
Secp256k1.musigPubkeyAdd(pubkeys.toTypedArray(), caches[1])
val msg32 = Hex.decode("0303030303030303030303030303030303030303030303030303030303030303")
val sessions = (0 until 2).map { Secp256k1.musigNonceProcess(aggnonce, msg32, caches[it], null) }
val psigs = (0 until 2).map {
val psig = Secp256k1.musigPartialSign(secnonces[it], privkeys[it], caches[it], sessions[it])
val check = Secp256k1.musigPartialSigVerify(psig, pubnonces[it], pubkeys[it], caches[it], sessions[it])
assertEquals(1, check)
psig
}
val sig = Secp256k1.musigPartialSigAgg(sessions[0], psigs.toTypedArray())
val check = Secp256k1.verifySchnorr(sig, msg32, aggpubkey)
assertTrue(check)
}
@Test
fun testInvalidArguments() {
assertFails {