Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/commonMain/kotlin/fr/acinq/lightning/payment/PaymentRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import fr.acinq.bitcoin.Script.tail
import fr.acinq.bitcoin.io.ByteArrayInput
import fr.acinq.bitcoin.io.ByteArrayOutput
import fr.acinq.lightning.*
import fr.acinq.lightning.Lightning.randomBytes
import fr.acinq.lightning.Lightning.randomBytes32
import fr.acinq.lightning.serialization.ByteVector32KSerializer
import fr.acinq.lightning.serialization.ByteVectorKSerializer
Expand Down Expand Up @@ -157,6 +158,19 @@ data class PaymentRequest(
return Features(activated = features.activated.filter { (f, _) -> bolt11Features.contains(f) })
}

/**
* To avoid collision on payment preimages, we use a mix of randomness and timestamping.
* The end of the preimage contains a timestamp and the rest (at least 192 bits) comes from our RNG.
* This ensures that even if the randomness fails, it's unlikely that preimages will be reused.
*/
fun generatePreimage(): ByteVector32 {
val timestamp = ByteArrayOutput()
LightningCodecs.writeTU64(currentTimestampMillis(), timestamp)
val timestampBytes = timestamp.toByteArray()
val random = randomBytes(32 - timestampBytes.size)
return ByteVector32(random + timestampBytes)
}

fun create(
chainHash: ByteVector32,
amount: MilliSatoshi?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package fr.acinq.lightning.payment

import fr.acinq.bitcoin.*
import fr.acinq.bitcoin.io.ByteArrayInput
import fr.acinq.lightning.*
import fr.acinq.lightning.tests.utils.LightningTestSuite
import fr.acinq.lightning.utils.*
import fr.acinq.lightning.wire.LightningCodecs
import fr.acinq.secp256k1.Hex
import kotlin.test.*

Expand Down Expand Up @@ -317,6 +319,18 @@ class PaymentRequestTestsCommon : LightningTestSuite() {
assertEquals(ref, check)
}

@Test
fun `insert current timestamp in payment preimage generation`() {
val now = currentTimestampMillis()
val pr1 = PaymentRequest.generatePreimage()
val preimageTimestamp = LightningCodecs.tu64(ByteArrayInput(pr1.takeRight(6).toByteArray()))
assertTrue(now <= preimageTimestamp)
assertTrue(preimageTimestamp <= now + 5000)

val pr2 = PaymentRequest.generatePreimage()
assertNotEquals(pr1, pr2)
}

@Test
fun `reject invalid invoices`() {
val refs = listOf(
Expand Down