NIP-44 v2 decrypt: try both Y parities for x-only sender pubkeys (even then odd) to fix unwrap authentication failures

This commit is contained in:
jack
2025-08-24 17:09:14 +02:00
parent 914101746a
commit bb5936e39b
+24 -12
View File
@@ -287,19 +287,31 @@ struct NostrProtocol {
let tag = rest.suffix(16) let tag = rest.suffix(16)
let ct = rest.dropLast(16) let ct = rest.dropLast(16)
// Derive shared secret (try even then odd Y) // Try decryption with even-Y then odd-Y when sender pubkey is x-only
var sharedSecret: Data func attemptDecrypt(using pubKeyData: Data) throws -> Data {
do { let ss = try deriveSharedSecret(privateKey: recipientKey, publicKey: pubKeyData)
sharedSecret = try deriveSharedSecret(privateKey: recipientKey, publicKey: senderPubkeyData) let key = try deriveNIP44V2Key(from: ss)
} catch { return try XChaCha20Poly1305Compat.open(
guard senderPubkeyData.count == 32 else { throw error } ciphertext: Data(ct),
var alt = Data([0x03]) tag: Data(tag),
alt.append(senderPubkeyData) key: key,
sharedSecret = try deriveSharedSecretDirect(privateKey: recipientKey, publicKey: alt) nonce24: Data(nonce24)
)
}
// If 32 bytes (x-only) try both parities, otherwise single try
if senderPubkeyData.count == 32 {
let even = Data([0x02]) + senderPubkeyData
if let pt = try? attemptDecrypt(using: even) {
return String(data: pt, encoding: .utf8) ?? ""
}
let odd = Data([0x03]) + senderPubkeyData
let pt = try attemptDecrypt(using: odd)
return String(data: pt, encoding: .utf8) ?? ""
} else {
let pt = try attemptDecrypt(using: senderPubkeyData)
return String(data: pt, encoding: .utf8) ?? ""
} }
let key = try deriveNIP44V2Key(from: sharedSecret)
let pt = try XChaCha20Poly1305Compat.open(ciphertext: Data(ct), tag: Data(tag), key: key, nonce24: Data(nonce24))
return String(data: pt, encoding: .utf8) ?? ""
} }
private static func deriveSharedSecret( private static func deriveSharedSecret(