musig2-0.1.0: test/ApplyTweaks.hs
{-# LANGUAGE OverloadedStrings #-}
module ApplyTweaks (testApplyTweaks) where
import Crypto.Curve.Secp256k1 (Pub, parse_point)
import Crypto.Curve.Secp256k1.MuSig2 (Tweak (..), aggregatedPubkey, applyTweak, mkKeyAggContext)
import Crypto.Curve.Secp256k1.MuSig2.Internal (bytesToInteger, hashTag)
import Data.ByteString (ByteString)
import Data.Maybe (fromJust)
import Test.Tasty
import Test.Tasty.HUnit
import Util (decodeHex, extractXOnly, parsePoint)
-- | Computes taproot tweak from pubkey and merkle root.
computeTaprootTweak :: Pub -> ByteString -> Integer
computeTaprootTweak pubkey merkleRoot =
let pubkeyXOnly = extractXOnly pubkey
tweakHash = hashTag "TapTweak" (pubkeyXOnly <> merkleRoot)
in bytesToInteger tweakHash
-- | Test pubkeys from the Rust's `musig2` crate `test_aggregation_context_tweaks`.
testPubkeys :: [Pub]
testPubkeys =
map
parsePoint
[ "03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
, "02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"
, "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
]
-- | Test case: Sequence of tweaks matching `test_aggregation_context_tweaks` from Rust's `musig2` crate.
testTweakSequence :: TestTree
testTweakSequence =
testCase "Tweak sequence" $ do
let keyAggCtx1 = mkKeyAggContext testPubkeys Nothing
-- Apply first X-only tweak
let tweak1 = XOnlyTweak 0xE8F791FF9225A2AF0102AFFF4A9A723D9612A682A25EBE79802B263CDFCD83BB
keyAggCtx2 = applyTweak keyAggCtx1 tweak1
-- Apply second X-only tweak
let tweak2 = XOnlyTweak 0xAE2EA797CC0FE72AC5B97B97F3C6957D7E4199A167A58EB08BCAFFDA70AC0455
keyAggCtx3 = applyTweak keyAggCtx2 tweak2
-- Apply third plain tweak
let tweak3 = PlainTweak 0xF52ECBC565B3D8BEA2DFD5B75A4F457E54369809322E4120831626F290FA87E0
keyAggCtx4 = applyTweak keyAggCtx3 tweak3
-- Apply fourth plain tweak
let tweak4 = PlainTweak 0x1969AD73CC177FA0B4FCED6DF1F7BF9907E665FDE9BA196A74FED0A3CF5AEF9D
finalKeyAggCtx = applyTweak keyAggCtx4 tweak4
finalAggPk = aggregatedPubkey finalKeyAggCtx
expected = fromJust $ parse_point $ decodeHex "0269434B39A026A4AAC9E6C1AEBDD3993FFA581C8F7F21B6FAAE15608057F5CE85"
expected @=? finalAggPk
-- | Test case: Taproot tweak with merkle root matching `test_aggregation_context_tweaks` from Rust's `musig2` crate.
testTaprootTweak :: TestTree
testTaprootTweak =
testCase "Taproot tweak with merkle root" $ do
let keyAggCtx = mkKeyAggContext testPubkeys Nothing
originalPk = aggregatedPubkey keyAggCtx
merkleRootBytes = decodeHex "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
-- Compute proper taproot tweak hash
taprootTweakValue = computeTaprootTweak originalPk merkleRootBytes
taprootTweak = XOnlyTweak taprootTweakValue
tweakedCtx = applyTweak keyAggCtx taprootTweak
tweakedPk = aggregatedPubkey tweakedCtx
expected = fromJust $ parse_point $ decodeHex "024650cca5e389f62e960f66ca0400927a7727fc6e84b9c38a1fd9a80271377ceb"
expected @=? tweakedPk
-- | Test vectors the Rust's `musig2` crate `test_aggregation_context_tweaks`.
testApplyTweaks :: TestTree
testApplyTweaks =
testGroup
"applying tweaks"
[ testTweakSequence
, testTaprootTweak
]