@@ -14,6 +14,7 @@ import fr.acinq.lightning.Lightning.randomBytes32
1414import fr.acinq.lightning.crypto.RouteBlinding
1515import fr.acinq.lightning.message.OnionMessages
1616import fr.acinq.lightning.payment.ContactAddress
17+ import fr.acinq.lightning.payment.UnverifiedContactAddress
1718
1819/* *
1920 * Lightning Bolt 12 offers
@@ -460,6 +461,28 @@ object OfferTypes {
460461 }
461462 }
462463
464+ /* *
465+ * When [[InvoiceRequestPayerAddress]] is included, the invoice request must be signed with the signing key of the offer matching the BIP 353 address.
466+ * This proves that the payer really owns this BIP 353 address.
467+ * See [bLIP 42](https://github.com/lightning/blips/blob/master/blip-0042.md) for more details.
468+ */
469+ data class InvoiceRequestPayerAddressSignature (val offerSigningKey : PublicKey , val signature : ByteVector64 ) : InvoiceRequestTlv() {
470+ override val tag: Long get() = InvoiceRequestPayerAddressSignature .tag
471+ override fun write (out : Output ) {
472+ LightningCodecs .writeBytes(offerSigningKey.value, out )
473+ LightningCodecs .writeBytes(signature, out )
474+ }
475+
476+ companion object : TlvValueReader <InvoiceRequestPayerAddressSignature > {
477+ const val tag: Long = 2_000_001_735L
478+ override fun read (input : Input ): InvoiceRequestPayerAddressSignature {
479+ val offerSigningKey = PublicKey (LightningCodecs .bytes(input, 33 ))
480+ val signature = LightningCodecs .bytes(input, 64 ).byteVector64()
481+ return InvoiceRequestPayerAddressSignature (offerSigningKey, signature)
482+ }
483+ }
484+ }
485+
463486 /* *
464487 * Payment paths to send the payment to.
465488 */
@@ -919,7 +942,7 @@ object OfferTypes {
919942 val payerNote: String? = records.get<InvoiceRequestPayerNote >()?.note
920943 val contactSecret: ByteVector32 ? = records.get<InvoiceRequestContactSecret >()?.contactSecret
921944 val payerOffer: Offer ? = records.get<InvoiceRequestPayerOffer >()?.offer
922- val payerAddress: ContactAddress ? = records.get<InvoiceRequestPayerAddress >()?.address
945+ val payerAddress: UnverifiedContactAddress ? = records.get<InvoiceRequestPayerAddress >()?.let { pa -> records.get< InvoiceRequestPayerAddressSignature >()?. let { ps -> UnverifiedContactAddress (pa. address, ps.offerSigningKey) } }
923946 private val signature: ByteVector64 = records.get<Signature >()!! .signature
924947
925948 fun isValid (): Boolean =
@@ -928,17 +951,23 @@ object OfferTypes {
928951 offer.chains.contains(chain) &&
929952 ((offer.quantityMax == null && quantity_opt == null ) || (offer.quantityMax != null && quantity_opt != null && quantity <= offer.quantityMax)) &&
930953 Features .areCompatible(offer.features, features) &&
954+ checkPayerAddressSignature() &&
931955 checkSignature()
932956
933957 fun requestedAmount (): MilliSatoshi ? = amount ? : offer.amount?.let { it * quantity }
934958
935- fun checkSignature (): Boolean =
936- verifySchnorr(
937- signatureTag,
938- rootHash(removeSignature(records)),
939- signature,
940- payerId
941- )
959+ private fun checkPayerAddressSignature (): Boolean = when (val ps = records.get<InvoiceRequestPayerAddressSignature >()) {
960+ null -> true
961+ else -> {
962+ // The payer address signature covers the invoice request without its top-level signature.
963+ // Note that the standard invoice request signature includes the InvoiceRequestPayerAddressSignature field.
964+ val signedTlvs = TlvStream (records.records.filter { it !is Signature && it !is InvoiceRequestPayerAddressSignature }.toSet(), records.unknown)
965+ val signatureTag = ByteVector ((" lightning" + " invoice_request" + " invreq_payer_bip_353_signature" ).encodeToByteArray())
966+ verifySchnorr(signatureTag, rootHash(signedTlvs), ps.signature, ps.offerSigningKey)
967+ }
968+ }
969+
970+ fun checkSignature (): Boolean = verifySchnorr(signatureTag, rootHash(removeSignature(records)), signature, payerId)
942971
943972 fun encode (): String {
944973 val data = tlvSerializer.write(records)
@@ -951,8 +980,7 @@ object OfferTypes {
951980
952981 companion object {
953982 val hrp = " lnr"
954- val signatureTag: ByteVector =
955- ByteVector ((" lightning" + " invoice_request" + " signature" ).encodeToByteArray())
983+ val signatureTag: ByteVector = ByteVector ((" lightning" + " invoice_request" + " signature" ).encodeToByteArray())
956984
957985 /* *
958986 * Create a request to fetch an invoice for a given offer.
@@ -999,9 +1027,10 @@ object OfferTypes {
9991027 is Left -> return Left (offer.value)
10001028 is Right -> {}
10011029 }
1002- if (records.get<InvoiceRequestMetadata >() == null ) return Left (MissingRequiredTlv (0L ))
1003- if (records.get<InvoiceRequestPayerId >() == null ) return Left (MissingRequiredTlv (88 ))
1004- if (records.get<Signature >() == null ) return Left (MissingRequiredTlv (240 ))
1030+ if (records.get<InvoiceRequestMetadata >() == null ) return Left (MissingRequiredTlv (InvoiceRequestMetadata .tag))
1031+ if (records.get<InvoiceRequestAmount >() == null && records.get<OfferAmount >() == null ) return Left (MissingRequiredTlv (InvoiceRequestAmount .tag))
1032+ if (records.get<InvoiceRequestPayerId >() == null ) return Left (MissingRequiredTlv (InvoiceRequestPayerId .tag))
1033+ if (records.get<Signature >() == null ) return Left (MissingRequiredTlv (Signature .tag))
10051034 if (records.unknown.any { ! isInvoiceRequestTlv(it) }) return Left (ForbiddenTlv (records.unknown.find { ! isInvoiceRequestTlv(it) }!! .tag))
10061035 return Right (InvoiceRequest (records))
10071036 }
@@ -1031,6 +1060,7 @@ object OfferTypes {
10311060 InvoiceRequestContactSecret .tag to InvoiceRequestContactSecret as TlvValueReader <InvoiceRequestTlv >,
10321061 InvoiceRequestPayerOffer .tag to InvoiceRequestPayerOffer as TlvValueReader <InvoiceRequestTlv >,
10331062 InvoiceRequestPayerAddress .tag to InvoiceRequestPayerAddress as TlvValueReader <InvoiceRequestTlv >,
1063+ InvoiceRequestPayerAddressSignature .tag to InvoiceRequestPayerAddressSignature as TlvValueReader <InvoiceRequestTlv >,
10341064 Signature .tag to Signature as TlvValueReader <InvoiceRequestTlv >,
10351065 )
10361066 )
@@ -1073,6 +1103,7 @@ object OfferTypes {
10731103 InvoiceRequestContactSecret .tag to InvoiceRequestContactSecret as TlvValueReader <InvoiceTlv >,
10741104 InvoiceRequestPayerOffer .tag to InvoiceRequestPayerOffer as TlvValueReader <InvoiceTlv >,
10751105 InvoiceRequestPayerAddress .tag to InvoiceRequestPayerAddress as TlvValueReader <InvoiceTlv >,
1106+ InvoiceRequestPayerAddressSignature .tag to InvoiceRequestPayerAddressSignature as TlvValueReader <InvoiceTlv >,
10761107 // Invoice part
10771108 InvoicePaths .tag to InvoicePaths as TlvValueReader <InvoiceTlv >,
10781109 InvoiceBlindedPay .tag to InvoiceBlindedPay as TlvValueReader <InvoiceTlv >,
0 commit comments