All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.fr.acinq.lightning.wire.RouteBlinding.kt Maven / Gradle / Ivy

There is a newer version: 1.8.4
Show newest version
package fr.acinq.lightning.wire

import fr.acinq.bitcoin.ByteVector
import fr.acinq.bitcoin.PublicKey
import fr.acinq.bitcoin.io.ByteArrayInput
import fr.acinq.bitcoin.io.ByteArrayOutput
import fr.acinq.bitcoin.io.Input
import fr.acinq.bitcoin.io.Output


sealed class RouteBlindingEncryptedDataTlv : Tlv {
    /** Some padding can be added to ensure all payloads are the same size to improve privacy. */
    data class Padding(val dummy: ByteVector) : RouteBlindingEncryptedDataTlv() {
        override val tag: Long get() = Padding.tag
        override fun write(out: Output) = LightningCodecs.writeBytes(dummy, out)

        companion object : TlvValueReader {
            const val tag: Long = 1
            override fun read(input: Input): Padding =
                Padding(ByteVector(LightningCodecs.bytes(input, input.availableBytes)))
        }
    }

    /** Id of the next node. */
    data class OutgoingNodeId(val nodeId: PublicKey) : RouteBlindingEncryptedDataTlv() {
        override val tag: Long get() = OutgoingNodeId.tag
        override fun write(out: Output) = LightningCodecs.writeBytes(nodeId.value, out)

        companion object : TlvValueReader {
            const val tag: Long = 4
            override fun read(input: Input): OutgoingNodeId =
                OutgoingNodeId(PublicKey(LightningCodecs.bytes(input, 33)))
        }
    }

    /**
     * The final recipient may store some data in the encrypted payload for itself to avoid storing it locally.
     * It can for example put a payment_hash to verify that the route is used for the correct invoice.
     * It should use that field to detect when blinded routes are used outside of their intended use (malicious probing)
     * and react accordingly (ignore the message or send an error depending on the use-case).
     */
    data class PathId(val data: ByteVector) : RouteBlindingEncryptedDataTlv() {
        override val tag: Long get() = PathId.tag
        override fun write(out: Output) = LightningCodecs.writeBytes(data, out)

        companion object : TlvValueReader {
            const val tag: Long = 6
            override fun read(input: Input): PathId =
                PathId(ByteVector(LightningCodecs.bytes(input, input.availableBytes)))
        }
    }

    /** Blinding override for the rest of the route. */
    data class NextBlinding(val blinding: PublicKey) : RouteBlindingEncryptedDataTlv() {
        override val tag: Long get() = NextBlinding.tag
        override fun write(out: Output) = LightningCodecs.writeBytes(blinding.value, out)

        companion object : TlvValueReader {
            const val tag: Long = 8
            override fun read(input: Input): NextBlinding =
                NextBlinding(PublicKey(LightningCodecs.bytes(input, 33)))
        }
    }
}

data class RouteBlindingEncryptedData(val records: TlvStream) {
    val nextNodeId = records.get()?.nodeId
    val pathId = records.get()?.data
    val nextBlindingOverride = records.get()?.blinding

    fun write(out: Output) = tlvSerializer.write(records, out)

    fun write(): ByteArray {
        val out = ByteArrayOutput()
        write(out)
        return out.toByteArray()
    }

    companion object {
        val tlvSerializer = TlvStreamSerializer(
            false, @Suppress("UNCHECKED_CAST") mapOf(
                RouteBlindingEncryptedDataTlv.Padding.tag to RouteBlindingEncryptedDataTlv.Padding.Companion as TlvValueReader,
                RouteBlindingEncryptedDataTlv.OutgoingNodeId.tag to RouteBlindingEncryptedDataTlv.OutgoingNodeId.Companion as TlvValueReader,
                RouteBlindingEncryptedDataTlv.PathId.tag to RouteBlindingEncryptedDataTlv.PathId.Companion as TlvValueReader,
                RouteBlindingEncryptedDataTlv.NextBlinding.tag to RouteBlindingEncryptedDataTlv.NextBlinding.Companion as TlvValueReader,
            )
        )

        fun read(input: Input): RouteBlindingEncryptedData = RouteBlindingEncryptedData(tlvSerializer.read(input))

        fun read(bytes: ByteArray): RouteBlindingEncryptedData = read(ByteArrayInput(bytes))
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy