fix(android): decode Base64 signature before broadcasting transaction
The TSS native bridge returns signatures in Base64 format, but the broadcast function expected hex format. Added Base64 decoding in broadcastTransaction() to properly parse r, s, v components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2365a50b1b
commit
b3822e48eb
|
|
@ -556,7 +556,8 @@
|
|||
"Bash(adb logcat:*)",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(android\\): add 5-minute polling timeout mechanism for keygen/sign\n\nImplements Electron''s checkAndTriggerKeygen\\(\\) polling fallback:\n- Adds polling every 2 seconds with 5-minute timeout\n- Triggers keygen/sign via synthetic session_started event on in_progress status\n- Handles gRPC stream disconnection when app goes to background\n- Shows timeout error in UI via existing error mechanism\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(go list:*)",
|
||||
"Bash(adb install:*)"
|
||||
"Bash(adb install:*)",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(tss\\): add real-time round progress from msg.Type\\(\\) parsing\n\nExtract current round number from tss-lib message type string using\nregex pattern `Round\\(\\\\d+\\)`. This enables real-time progress updates\n\\(1/4, 2/4... for keygen, 1/9, 2/9... for signing\\) instead of only\nshowing completion status.\n\nChanges across all three platforms:\n- tss-wasm/main.go: Add extractRoundFromMessageType\\(\\) and call\n OnProgress with parsed round on each outgoing message\n- service-party-android/tsslib/tsslib.go: Same implementation for\n Android gomobile binding\n- service-party-app/tss-party/main.go: Same implementation for\n Electron subprocess, with isKeygen parameter to distinguish\n keygen \\(4 rounds\\) vs signing \\(9 rounds\\)\n\nSafe fallback: Returns 0 if parsing fails, which doesn''t affect\nprotocol execution - only UI display.\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -2259,20 +2259,43 @@ class TssRepository @Inject constructor(
|
|||
): Result<String> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
// Parse signature (format: 0x + r(64) + s(64) + v(2))
|
||||
val sigHex = signature.removePrefix("0x")
|
||||
if (sigHex.length != 130) {
|
||||
return@withContext Result.failure(Exception("Invalid signature length"))
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] Input signature: ${signature.take(40)}...")
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] Signature length: ${signature.length}")
|
||||
|
||||
// Signature from TSS is Base64 encoded, need to decode and convert to hex
|
||||
// Format after decode: r (32 bytes) + s (32 bytes) + v (1 byte) = 65 bytes
|
||||
val sigBytes = try {
|
||||
android.util.Base64.decode(signature, android.util.Base64.NO_WRAP)
|
||||
} catch (e: Exception) {
|
||||
// If not Base64, try to parse as hex directly
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] Not Base64, trying hex...")
|
||||
signature.removePrefix("0x").hexToByteArray()
|
||||
}
|
||||
|
||||
val rHex = sigHex.substring(0, 64)
|
||||
val sHex = sigHex.substring(64, 128)
|
||||
val vHex = sigHex.substring(128, 130)
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] Decoded signature bytes: ${sigBytes.size}")
|
||||
|
||||
val r = rHex.hexToByteArray()
|
||||
val s = sHex.hexToByteArray()
|
||||
val v = vHex.toInt(16)
|
||||
val recoveryId = if (v >= 27) v - 27 else v
|
||||
if (sigBytes.size != 65) {
|
||||
return@withContext Result.failure(Exception("Invalid signature length: ${sigBytes.size} bytes, expected 65"))
|
||||
}
|
||||
|
||||
// Extract r, s, v from decoded bytes
|
||||
val rBytes = sigBytes.copyOfRange(0, 32)
|
||||
val sBytes = sigBytes.copyOfRange(32, 64)
|
||||
val vByte = sigBytes[64].toInt() and 0xFF
|
||||
|
||||
// Convert to hex for logging
|
||||
val rHex = rBytes.joinToString("") { "%02x".format(it) }
|
||||
val sHex = sBytes.joinToString("") { "%02x".format(it) }
|
||||
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] r: ${rHex.take(16)}...")
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] s: ${sHex.take(16)}...")
|
||||
android.util.Log.d("TssRepository", "[BROADCAST] v: $vByte")
|
||||
|
||||
val recoveryId = if (vByte >= 27) vByte - 27 else vByte
|
||||
|
||||
// Use byte arrays directly for finalizeTransaction
|
||||
val r = rBytes
|
||||
val s = sBytes
|
||||
|
||||
// Finalize transaction with signature
|
||||
val signedTx = TransactionUtils.finalizeTransaction(
|
||||
|
|
|
|||
Loading…
Reference in New Issue