Skip to content

Commit 043e340

Browse files
Merge pull request #7409 from BitGo/BTC-2652.add-musig2-fixtures
feat(utxo-lib): add cross-validation tests for MuSig2 implementation
2 parents 9fa37a3 + 9515d04 commit 043e340

14 files changed

+1091
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__/

modules/utxo-lib/bip-0327/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,37 @@ The test suite runs:
171171
4. BitGo legacy p2tr tests
172172
5. BitGo standard p2trMusig2 tests
173173

174+
### TypeScript Cross-Validation Tests
175+
176+
The `test_typescript_fixtures.py` script validates that the Python reference implementation produces identical results to the TypeScript implementation:
177+
178+
```bash
179+
cd modules/utxo-lib/bip-0327
180+
python3 test_typescript_fixtures.py
181+
```
182+
183+
These tests read JSON fixtures from the `musig2/` directory, which are generated by the TypeScript test suite in `test/bitgo/psbt/Musig2Methods.ts`. The fixtures contain:
184+
185+
- **createTapInternalKey.json** - Key aggregation results
186+
- **createTapOutputKey.json** - Tweaked aggregate key results
187+
- **createTapTweak.json** - Taproot tweak computation
188+
- **createAggregateNonce.json** - Nonce aggregation results
189+
- **createMusig2SigningSession.json** - Session context creation
190+
- **musig2PartialSignAndVerify.json** - Partial signature verification
191+
- **musig2AggregateSigs.json** - Signature aggregation and final verification
192+
- **fullSigningFlow.json** - Complete end-to-end signing workflow
193+
194+
The cross-validation tests ensure that:
195+
1. Key aggregation produces identical aggregate public keys
196+
2. Taproot tweaking produces identical output keys
197+
3. Deterministic nonce generation produces identical nonces (using session IDs `0x0101...` and `0x0202...`)
198+
4. Partial signature generation produces identical signatures
199+
5. Partial signature verification works identically
200+
6. Signature aggregation produces identical results
201+
7. Final Schnorr signature verification succeeds in both implementations
202+
203+
The tests use fully deterministic nonce generation with fixed session IDs to ensure bit-for-bit identical outputs between Python and TypeScript. This provides strong confidence that the TypeScript and Python implementations are compatible and produce identical cryptographic outputs at every step of the MuSig2 protocol.
204+
174205
## References
175206

176207
- [BIP327 Specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)

modules/utxo-lib/bip-0327/test_typescript_fixtures.py

Lines changed: 412 additions & 0 deletions
Large diffs are not rendered by default.

modules/utxo-lib/bip-0327/tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ set -e
55
cd "$(dirname "$0")"
66
mypy --no-error-summary reference.py
77
python3 reference.py
8+
python3 test_typescript_fixtures.py
89
python3 gen_vectors_helper.py > /dev/null
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../test/bitgo/fixtures/musig2
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"inputs": {
3+
"pubNonces": [
4+
"027389d7aa456cbe418467f42928601462d77000c3b260e5127f1111b57588b35e036f13a501e1708aa7288a313d71975324e0de1d129acff61e40e1c96ae5976c29",
5+
"02949960a953f58a5bad40d8c6161bac10a52a971a37cfe858ba4a1452524b1691026dca4ba06a76389621d0d5a6965976120eb9dac6b861cf32d674c65e080a7c13"
6+
]
7+
},
8+
"output": {
9+
"aggregateNonce": "0233086bdf4150163179ef61beed827f55b073563e8bde58755ed8bcddc00635a902418bed8a65d3ee02007694fb18b5a1ec202d8b69ece07e2d54dd193ef7373b88"
10+
}
11+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"inputs": {
3+
"pubNonces": [
4+
"027389d7aa456cbe418467f42928601462d77000c3b260e5127f1111b57588b35e036f13a501e1708aa7288a313d71975324e0de1d129acff61e40e1c96ae5976c29",
5+
"02949960a953f58a5bad40d8c6161bac10a52a971a37cfe858ba4a1452524b1691026dca4ba06a76389621d0d5a6965976120eb9dac6b861cf32d674c65e080a7c13"
6+
],
7+
"txHash": "d11d3b06a83bb14c95fad947da2192ad9f6faee3c0fb36ad197a05f943aa7acd",
8+
"pubKeys": [
9+
"03e9fc8f605f59d6a4f5ceb0d27852151013f2bf1965f9adf44ce9ba9821c7f106",
10+
"030710ec162d2199bb828e5d8760f16d65412bbb2c85ec13fe027f77d83a349c62"
11+
],
12+
"internalPubKey": "6d767a69e03d4611485407d777711ee4d1321a84cf82f591db0cd3e179c49821",
13+
"tapTreeRoot": "63a3684763dca2d4bb5d412d01f5ce73214af3d7816b52d7ad549562cc4cd890"
14+
},
15+
"output": {
16+
"sessionKey": {
17+
"aggNonce": "0233086bdf4150163179ef61beed827f55b073563e8bde58755ed8bcddc00635a902418bed8a65d3ee02007694fb18b5a1ec202d8b69ece07e2d54dd193ef7373b88",
18+
"msg": "d11d3b06a83bb14c95fad947da2192ad9f6faee3c0fb36ad197a05f943aa7acd",
19+
"publicKey": "04e5406bdcc45b02e86b30c446fd57375e8bfc8144238d61033d353c8a3641a43d5bc152f290f28255baf6bf18c5de0d67f81921fc4e1c05c3c5625eb7784eab01"
20+
}
21+
}
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"inputs": {
3+
"pubKeys": [
4+
"03e9fc8f605f59d6a4f5ceb0d27852151013f2bf1965f9adf44ce9ba9821c7f106",
5+
"030710ec162d2199bb828e5d8760f16d65412bbb2c85ec13fe027f77d83a349c62"
6+
]
7+
},
8+
"output": {
9+
"tapInternalKey": "6d767a69e03d4611485407d777711ee4d1321a84cf82f591db0cd3e179c49821"
10+
}
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"inputs": {
3+
"internalPubKey": "6d767a69e03d4611485407d777711ee4d1321a84cf82f591db0cd3e179c49821",
4+
"tapTreeRoot": "63a3684763dca2d4bb5d412d01f5ce73214af3d7816b52d7ad549562cc4cd890"
5+
},
6+
"output": {
7+
"tapOutputKey": "e5406bdcc45b02e86b30c446fd57375e8bfc8144238d61033d353c8a3641a43d"
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"inputs": {
3+
"tapInternalKey": "6d767a69e03d4611485407d777711ee4d1321a84cf82f591db0cd3e179c49821",
4+
"tapMerkleRoot": "63a3684763dca2d4bb5d412d01f5ce73214af3d7816b52d7ad549562cc4cd890"
5+
},
6+
"output": {
7+
"tapTweak": "c990a77a31b07eea9d1a616bfe80bd33ba2a7e2a22db0e900a168d87a5e01a2c"
8+
}
9+
}

0 commit comments

Comments
 (0)