This test suite verifies that Python, TypeScript, and Go SDKs produce identical BRC-104 authentication signatures when given identical inputs.
The TypeScript SDK had a critical bug in how it prepared signature data for BRC-104 authentication. This caused signature incompatibility between SDKs, preventing cross-implementation authentication.
Incorrect (TypeScript SDK - buggy):
// Concatenated base64 strings first, then decoded
data: Peer.base64ToBytes(message.initialNonce + sessionNonce)Correct (Go SDK - reference implementation):
// Decoded each nonce separately, then concatenated bytes
initialNonceBytes, _ := base64.StdEncoding.DecodeString(message.InitialNonce)
sessionNonceBytes, _ := base64.StdEncoding.DecodeString(session.SessionNonce)
sigData := append(initialNonceBytes, sessionNonceBytes...)Correct (Python SDK):
# Decoded each nonce separately, then concatenated bytes
initial_nonce_bytes = base64.b64decode(initial_nonce)
session_nonce_bytes = base64.b64decode(session_nonce)
return initial_nonce_bytes + session_nonce_bytesThe bug caused different byte arrays to be signed:
- Buggy approach: Decodes a concatenated base64 string (produces ~32-34 bytes)
- Correct approach: Concatenates individually decoded 32-byte arrays (produces 64 bytes)
This resulted in different signatures and failed authentication between TypeScript clients and Go/Python servers.
ts-sdk/src/auth/Peer.ts(lines 528, 576-578)
Before (buggy):
// Signing
data: Peer.base64ToBytes(message.initialNonce + sessionNonce)
// Verification
const dataToVerify = Peer.base64ToBytes(
(peerSession.sessionNonce ?? '') + (message.initialNonce ?? '')
)After (fixed):
// Signing
data: [
...Peer.base64ToBytes(message.initialNonce),
...Peer.base64ToBytes(sessionNonce)
]
// Verification
const dataToVerify = [
...Peer.base64ToBytes(peerSession.sessionNonce ?? ''),
...Peer.base64ToBytes(message.initialNonce ?? '')
]cross-language-tests/
├── constants.py # Python shared constants
├── constants.ts # TypeScript shared constants
├── constants.go # Go shared constants
├── test_brc104_signatures.py # Python test suite
├── test_brc104_signatures.ts # TypeScript test suite
├── test_brc104_signatures_test.go # Go test suite
├── package.json # TypeScript dependencies
└── README.md # This file
- Python 3.8+
- Node.js 16+
- Go 1.19+
- pytest (for Python tests)
- jest (for TypeScript tests)
cd cross-language-tests
python -m pytest test_brc104_signatures.py -vcd cross-language-tests
npm install
npm testcd cross-language-tests
go test -vAll tests should pass after the fix:
- Python: 9/9 tests passing ✅
- TypeScript: 10/10 tests passing ✅
- Go: 9/9 tests passing ✅
- Verifies correct nonce decoding and concatenation
- Tests both signing and verification data preparation
- Demonstrates the historical bug for documentation
- Ensures identical constants across languages
- Validates nonce decoding correctness
- Tests key ID formatting
- Simulates complete BRC-104 authentication flows
- Tests both server signing and client verification paths
The Go SDK is considered the authoritative reference implementation for BRC-104 authentication. All other SDKs should produce identical results when given identical inputs.
This implementation follows BRC-104: HTTP Transport for BRC-103 Mutual Authentication.
This fix ensures:
- TypeScript clients can authenticate with Go servers
- TypeScript clients can authenticate with Python servers
- All SDKs maintain cryptographic compatibility
- Cross-implementation BRC-104 authentication works correctly
The test_key_derivation.* files test key derivation functions across all three languages to identify any implementation differences that could cause signature verification failures.
Individual tests:
# Python
python3 test_key_derivation.py
# TypeScript
npx ts-node test_key_derivation.ts
# Go
go run test_key_derivation_test.go constants.goCompare all languages:
./compare_key_derivation.shThe key derivation tests:
- Use identical root keys across all languages
- Derive keys with the same inputs (protocol, keyID, counterparty)
- Compare derived private keys
- Compare derived public keys (with
forSelf=TrueandforSelf=False) - Verify that public keys derived from private keys match
forSelf=Trueresults
All three languages should produce:
- Identical private keys when given the same inputs
- Identical public keys for
forSelf=True(should match public key from private key) - Identical public keys for
forSelf=False(different fromforSelf=True)
If any differences are found, this indicates a bug in key derivation that could cause signature verification failures.