Files
mantra-kmp/composeApp/src/commonMain/kotlin/press/mantra/compose/extensions/Credentials.kt
T
2026-08-15 15:42:34 +02:00

70 lines
2.2 KiB
Kotlin

package press.mantra.compose.extensions
import co.touchlab.kermit.Logger
import com.vitorpamplona.quartz.nip19Bech32.bech32.Bech32
import fr.acinq.bitcoin.PrivateKey
import fr.acinq.secp256k1.Hex
import io.ktor.utils.io.core.toByteArray
fun String.assureValidNsec() = if (startsWith("nsec")) this else this.hexToNsecHrp()
fun String.assureValidNpub() = if (startsWith("npub")) this else this.hexToNpubHrp()
fun String.assureValidPubKeyHex() = if (startsWith("npub")) this.bech32ToHexOrThrow() else this
fun String.hexToNoteHrp() =
Bech32.encodeBytes(
hrp = "note",
data = Hex.decode(this),
encoding = Bech32.Encoding.Bech32,
)
fun String.hexToNpubHrp() =
Bech32.encodeBytes(
hrp = "npub",
data = Hex.decode(this),
encoding = Bech32.Encoding.Bech32,
)
fun String.hexToNsecHrp() =
Bech32.encodeBytes(
hrp = "nsec",
data = Hex.decode(this),
encoding = Bech32.Encoding.Bech32,
)
fun String.urlToLnUrlHrp() =
Bech32.encodeBytes(
hrp = "lnurl",
data = this.toByteArray(),
encoding = Bech32.Encoding.Bech32,
)
fun String.bech32ToHexOrThrow() = Bech32.decodeBytes(bech32 = this).second.toHex()
fun String.bech32ToHexOrNull() = runCatching { this.bech32ToHexOrThrow() }.getOrNull()
fun ByteArray.toNpub() = Bech32.encodeBytes(hrp = "npub", this, Bech32.Encoding.Bech32)
@OptIn(ExperimentalStdlibApi::class)
fun ByteArray.toHex() = Hex.encode(this)
@Throws(IllegalArgumentException::class)
fun String.bechToBytesOrThrow(hrp: String? = null): ByteArray {
val decodedForm = Bech32.decodeBytes(this)
hrp?.also { require(it == decodedForm.first) }
return decodedForm.second
}
fun String.extractKeyPairFromPrivateKeyOrThrow(): Pair<String, String> {
return try {
val nsec = this.assureValidNsec()
val decoded = Bech32.decodeBytes(nsec)
val pubkey = PrivateKey(decoded.second).publicKey().value.toByteArray()
nsec to pubkey.toNpub()
} catch (error: IllegalArgumentException) {
Logger.withTag("String.extractKeyPairFromPrivateKeyOrThrow").w(error) { error.message ?: "" }
throw press.mantra.compose.exceptions.InvalidNostrPrivateKeyException()
}
}