Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onion message test vector #2628

Merged
merged 5 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -35,34 +35,34 @@ object OnionMessages {
timeout: FiniteDuration,
maxAttempts: Int)

case class IntermediateNode(nodeId: PublicKey, padding: Option[ByteVector] = None)
case class IntermediateNode(nodeId: PublicKey, customTlvs: Set[GenericTlv] = Set.empty)

// @formatter:off
sealed trait Destination
case class BlindedPath(route: Sphinx.RouteBlinding.BlindedRoute) extends Destination
case class Recipient(nodeId: PublicKey, pathId: Option[ByteVector], padding: Option[ByteVector] = None) extends Destination
case class Recipient(nodeId: PublicKey, pathId: Option[ByteVector], customTlvs: Set[GenericTlv] = Set.empty) extends Destination
// @formatter:on

private def buildIntermediatePayloads(intermediateNodes: Seq[IntermediateNode], nextTlvs: Set[RouteBlindingEncryptedDataTlv]): Seq[ByteVector] = {
if (intermediateNodes.isEmpty) {
Nil
} else {
(intermediateNodes.tail.map(node => Set(OutgoingNodeId(node.nodeId))) :+ nextTlvs)
.zip(intermediateNodes).map { case (tlvs, hop) => hop.padding.map(Padding).toSet[RouteBlindingEncryptedDataTlv] ++ tlvs }
.map(tlvs => RouteBlindingEncryptedDataCodecs.blindedRouteDataCodec.encode(TlvStream(tlvs)).require.bytes)
(intermediateNodes.tail.map(node => Set[RouteBlindingEncryptedDataTlv](OutgoingNodeId(node.nodeId))) :+ nextTlvs)
.zip(intermediateNodes).map { case (tlvs, hop) => TlvStream(tlvs, hop.customTlvs) }
.map(tlvs => RouteBlindingEncryptedDataCodecs.blindedRouteDataCodec.encode(tlvs).require.bytes)
}
}

def buildRoute(blindingSecret: PrivateKey,
intermediateNodes: Seq[IntermediateNode],
recipient: Recipient): Sphinx.RouteBlinding.BlindedRoute = {
val intermediatePayloads = buildIntermediatePayloads(intermediateNodes, Set(OutgoingNodeId(recipient.nodeId)))
val tlvs: Set[RouteBlindingEncryptedDataTlv] = Set(recipient.padding.map(Padding), recipient.pathId.map(PathId)).flatten
val lastPayload = RouteBlindingEncryptedDataCodecs.blindedRouteDataCodec.encode(TlvStream(tlvs)).require.bytes
val tlvs: Set[RouteBlindingEncryptedDataTlv] = Set(recipient.pathId.map(PathId)).flatten
val lastPayload = RouteBlindingEncryptedDataCodecs.blindedRouteDataCodec.encode(TlvStream(tlvs, recipient.customTlvs)).require.bytes
Sphinx.RouteBlinding.create(blindingSecret, intermediateNodes.map(_.nodeId) :+ recipient.nodeId, intermediatePayloads :+ lastPayload).route
}

private def buildRouteFrom(originKey: PrivateKey,
private[message] def buildRouteFrom(originKey: PrivateKey,
blindingSecret: PrivateKey,
intermediateNodes: Seq[IntermediateNode],
destination: Destination): Option[Sphinx.RouteBlinding.BlindedRoute] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ object OfferPayment {
val blindedRoute = blindedRoutes(attemptNumber % blindedRoutes.length)
OnionMessages.BlindedPath(blindedRoute)
case Right(nodeId) =>
OnionMessages.Recipient(nodeId, None, None)
OnionMessages.Recipient(nodeId, None, Set.empty)
}
// TODO: Find a path made of channels as some nodes may refuse to relay messages to nodes with which they don't have a channel.
val intermediateNodesToRecipient = Nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ sealed trait RouteBlindingEncryptedDataTlv extends Tlv

object RouteBlindingEncryptedDataTlv {

/** Some padding can be added to ensure all payloads are the same size to improve privacy. */
case class Padding(dummy: ByteVector) extends RouteBlindingEncryptedDataTlv
t-bast marked this conversation as resolved.
Show resolved Hide resolved

/** Id of the outgoing channel, used to identify the next node. */
case class OutgoingChannelId(shortChannelId: ShortChannelId) extends RouteBlindingEncryptedDataTlv

Expand Down Expand Up @@ -111,7 +108,6 @@ object RouteBlindingEncryptedDataCodecs {
import scodec.codecs._
import scodec.{Attempt, Codec, DecodeResult}

private val padding: Codec[Padding] = tlvField(bytes)
private val outgoingChannelId: Codec[OutgoingChannelId] = tlvField(shortchannelid)
private val outgoingNodeId: Codec[OutgoingNodeId] = fixedLengthTlvField(33, publicKey)
private val pathId: Codec[PathId] = tlvField(bytes)
Expand All @@ -121,7 +117,6 @@ object RouteBlindingEncryptedDataCodecs {
private val allowedFeatures: Codec[AllowedFeatures] = tlvField(featuresCodec)

private val encryptedDataTlvCodec = discriminated[RouteBlindingEncryptedDataTlv].by(varint)
.typecase(UInt64(1), padding)
.typecase(UInt64(2), outgoingChannelId)
.typecase(UInt64(4), outgoingNodeId)
.typecase(UInt64(6), pathId)
Expand Down
Loading