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 ct = rest.dropLast(16)
// Derive shared secret (try even then odd Y)
var sharedSecret: Data
do {
sharedSecret = try deriveSharedSecret(privateKey: recipientKey, publicKey: senderPubkeyData)
} catch {
guard senderPubkeyData.count == 32 else { throw error }
var alt = Data([0x03])
alt.append(senderPubkeyData)
sharedSecret = try deriveSharedSecretDirect(privateKey: recipientKey, publicKey: alt)
// Try decryption with even-Y then odd-Y when sender pubkey is x-only
func attemptDecrypt(using pubKeyData: Data) throws -> Data {
let ss = try deriveSharedSecret(privateKey: recipientKey, publicKey: pubKeyData)
let key = try deriveNIP44V2Key(from: ss)
return try XChaCha20Poly1305Compat.open(
ciphertext: Data(ct),
tag: Data(tag),
key: key,
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(