diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/message/OnionMessages.scala b/eclair-core/src/main/scala/fr/acinq/eclair/message/OnionMessages.scala index aad424fee4..373daa4174 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/message/OnionMessages.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/message/OnionMessages.scala @@ -4,7 +4,7 @@ import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} import fr.acinq.eclair.crypto.Sphinx import fr.acinq.eclair.wire.protocol.MessageOnion.{finalBlindedTlvCodec, messageOnionPerHopPayloadCodec, messageRelayPayloadCodec, relayBlindedTlvCodec} import fr.acinq.eclair.wire.protocol.MessageTlv._ -import fr.acinq.eclair.wire.protocol.{BadOnion, OnionMessage, OnionMessagePayloadTlv, TlvStream} +import fr.acinq.eclair.wire.protocol.{BadOnion, EncryptedRecipientDataTlv, OnionMessage, OnionMessagePayloadTlv, TlvStream} import scodec.bits.ByteVector import scodec.{Attempt, DecodeResult} @@ -14,27 +14,27 @@ object OnionMessages { case class IntermediateNode(nodeId: PublicKey, padding: Option[ByteVector] = None) - case class Recipient(nodeId: PublicKey, pathId: Option[ByteVector], padding: Option[ByteVector] = None) + case class Recipient(nodeId: PublicKey, secret: Option[ByteVector], padding: Option[ByteVector] = None) def buildRoute(blindingSecret: PrivateKey, intermediateNodes: Seq[IntermediateNode], destination: Either[Recipient, Sphinx.RouteBlinding.BlindedRoute]): Sphinx.RouteBlinding.BlindedRoute = { val last = destination match { - case Left(Recipient(nodeId, _, _)) => NextNodeId(nodeId) :: Nil - case Right(Sphinx.RouteBlinding.BlindedRoute(nodeId, blindingKey, _)) => NextNodeId(nodeId) :: BlindingPoint(blindingKey) :: Nil + case Left(Recipient(nodeId, _, _)) => EncryptedRecipientDataTlv.OutgoingNodeId(nodeId) :: Nil + case Right(Sphinx.RouteBlinding.BlindedRoute(nodeId, blindingKey, _)) => EncryptedRecipientDataTlv.OutgoingNodeId(nodeId) :: EncryptedRecipientDataTlv.NextBlinding(blindingKey) :: Nil } val intermediatePayloads = if (intermediateNodes.isEmpty) { Nil } else { - (intermediateNodes.tail.map(node => NextNodeId(node.nodeId) :: Nil) :+ last) - .zip(intermediateNodes).map { case (tlvs, hop) => hop.padding.map(Padding(_) :: Nil).getOrElse(Nil) ++ tlvs } + (intermediateNodes.tail.map(node => EncryptedRecipientDataTlv.OutgoingNodeId(node.nodeId) :: Nil) :+ last) + .zip(intermediateNodes).map { case (tlvs, hop) => hop.padding.map(EncryptedRecipientDataTlv.Padding(_) :: Nil).getOrElse(Nil) ++ tlvs } .map(tlvs => RelayBlindedTlv(TlvStream(tlvs))) .map(relayBlindedTlvCodec.encode(_).require.bytes) } destination match { - case Left(Recipient(nodeId, pathId, padding)) => - val tlvs = padding.map(Padding(_) :: Nil).getOrElse(Nil) ++ pathId.map(PathId(_) :: Nil).getOrElse(Nil) + case Left(Recipient(nodeId, recipientSecret, padding)) => + val tlvs = padding.map(EncryptedRecipientDataTlv.Padding(_) :: Nil).getOrElse(Nil) ++ recipientSecret.map(EncryptedRecipientDataTlv.RecipientSecret(_) :: Nil).getOrElse(Nil) val lastPayload = finalBlindedTlvCodec.encode(FinalBlindedTlv(TlvStream(tlvs))).require.bytes Sphinx.RouteBlinding.create(blindingSecret, intermediateNodes.map(_.nodeId) :+ nodeId, intermediatePayloads :+ lastPayload) case Right(route) => @@ -95,7 +95,7 @@ object OnionMessages { case Success((decrypted, _)) => finalBlindedTlvCodec.decode(decrypted.bits) match { case Attempt.Successful(DecodeResult(messageToSelf, _)) => - ReceiveMessage(finalPayload, messageToSelf.pathId) + ReceiveMessage(finalPayload, messageToSelf.recipientSecret) case Attempt.Failure(_) => DropMessage("Can't decode blinded TLV") } case Failure(_) => DropMessage("Can't decrypt blinded TLV") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/EncryptedRecipientDataTlv.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/EncryptedRecipientDataTlv.scala index 0db83c8dd3..a606ed1893 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/EncryptedRecipientDataTlv.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/EncryptedRecipientDataTlv.scala @@ -42,6 +42,9 @@ object EncryptedRecipientDataTlv { */ case class RecipientSecret(data: ByteVector) extends EncryptedRecipientDataTlv + /** Blinding override for the rest of the route. */ + case class NextBlinding(blinding: PublicKey) extends EncryptedRecipientDataTlv + } object EncryptedRecipientDataCodecs { @@ -55,12 +58,14 @@ object EncryptedRecipientDataCodecs { private val outgoingChannelId: Codec[OutgoingChannelId] = variableSizeBytesLong(varintoverflow, "short_channel_id" | shortchannelid).as[OutgoingChannelId] private val outgoingNodeId: Codec[OutgoingNodeId] = variableSizeBytesLong(varintoverflow, "node_id" | publicKey).as[OutgoingNodeId] private val recipientSecret: Codec[RecipientSecret] = variableSizeBytesLong(varintoverflow, "recipient_secret" | bytes).as[RecipientSecret] + private val nextBlinding: Codec[NextBlinding] = variableSizeBytesLong(varintoverflow, "blinding" | publicKey).as[NextBlinding] private val encryptedRecipientDataTlvCodec = discriminated[EncryptedRecipientDataTlv].by(varint) .typecase(UInt64(1), padding) .typecase(UInt64(2), outgoingChannelId) .typecase(UInt64(4), outgoingNodeId) .typecase(UInt64(6), recipientSecret) + .typecase(UInt64(12), nextBlinding) val encryptedRecipientDataCodec: Codec[TlvStream[EncryptedRecipientDataTlv]] = TlvCodecs.tlvStream[EncryptedRecipientDataTlv](encryptedRecipientDataTlvCodec).complete diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/MessageOnion.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/MessageOnion.scala index 9ae4549840..3e3559b173 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/MessageOnion.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/MessageOnion.scala @@ -3,28 +3,18 @@ package fr.acinq.eclair.wire.protocol import fr.acinq.bitcoin.Crypto.PublicKey import fr.acinq.eclair.UInt64 import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.{BlindedNode, BlindedRoute} +import fr.acinq.eclair.wire.protocol.EncryptedRecipientDataCodecs.encryptedRecipientDataCodec import fr.acinq.eclair.wire.protocol.OnionRoutingCodecs.{ForbiddenTlv, MissingRequiredTlv, onionRoutingPacketCodec} import scodec.bits.ByteVector sealed trait OnionMessagePayloadTlv extends Tlv -sealed trait BlindedTlv extends Tlv - object MessageTlv { - /** Blinding ephemeral public key that should be used to derive shared secrets when using route blinding. */ - case class BlindingPoint(publicKey: PublicKey) extends BlindedTlv - case class ReplyPath(blindedRoute: BlindedRoute) extends OnionMessagePayloadTlv case class EncTlv(bytes: ByteVector) extends OnionMessagePayloadTlv - case class NextNodeId(nodeId: PublicKey) extends BlindedTlv - - case class Padding(bytes: ByteVector) extends BlindedTlv - - case class PathId(bytes: ByteVector) extends BlindedTlv - sealed trait MessagePacket case class MessageRelayPayload(records: TlvStream[OnionMessagePayloadTlv]) extends MessagePacket { @@ -36,13 +26,13 @@ object MessageTlv { val replyPath: Option[MessageTlv.ReplyPath] = records.get[MessageTlv.ReplyPath] } - case class RelayBlindedTlv(records: TlvStream[BlindedTlv]) { - val nextNodeId: PublicKey = records.get[MessageTlv.NextNodeId].get.nodeId - val nextBlinding: Option[PublicKey] = records.get[MessageTlv.BlindingPoint].map(_.publicKey) + case class RelayBlindedTlv(records: TlvStream[EncryptedRecipientDataTlv]) { + val nextNodeId: PublicKey = records.get[EncryptedRecipientDataTlv.OutgoingNodeId].get.nodeId + val nextBlinding: Option[PublicKey] = records.get[EncryptedRecipientDataTlv.NextBlinding].map(_.blinding) } - case class FinalBlindedTlv(records: TlvStream[BlindedTlv]) { - val pathId: Option[ByteVector] = records.get[MessageTlv.PathId].map(_.bytes) + case class FinalBlindedTlv(records: TlvStream[EncryptedRecipientDataTlv]) { + val recipientSecret: Option[ByteVector] = records.get[EncryptedRecipientDataTlv.RecipientSecret].map(_.data) } } @@ -80,30 +70,15 @@ object MessageOnion { case MessageFinalPayload(tlvs) => tlvs }) - private val padding: Codec[Padding] = variableSizeBytesLong(varintoverflow, "padding" | bytes).as[Padding] - - private val nextNodeId: Codec[NextNodeId] = variableSizeBytesLong(varintoverflow, "node_id" | publicKey).as[NextNodeId] - - private val blindingKey: Codec[BlindingPoint] = variableSizeBytesLong(varintoverflow, "blinding" | publicKey).as[BlindingPoint] - - private val pathId: Codec[PathId] = variableSizeBytesLong(varintoverflow, "path_id" | bytes).as[PathId] - - private val blindedTlvCodec: Codec[TlvStream[BlindedTlv]] = TlvCodecs.tlvStream[BlindedTlv]( - discriminated[BlindedTlv].by(varint) - .typecase(UInt64(1), padding) - .typecase(UInt64(4), nextNodeId) - .typecase(UInt64(12), blindingKey) - .typecase(UInt64(14), pathId)).complete - - val relayBlindedTlvCodec: Codec[RelayBlindedTlv] = blindedTlvCodec.narrow({ - case tlvs if tlvs.get[NextNodeId].isEmpty => Attempt.failure(MissingRequiredTlv(UInt64(4))) - case tlvs if tlvs.get[PathId].nonEmpty => Attempt.failure(ForbiddenTlv(UInt64(14))) + val relayBlindedTlvCodec: Codec[RelayBlindedTlv] = encryptedRecipientDataCodec.narrow({ + case tlvs if tlvs.get[EncryptedRecipientDataTlv.OutgoingNodeId].isEmpty => Attempt.failure(MissingRequiredTlv(UInt64(4))) + case tlvs if tlvs.get[EncryptedRecipientDataTlv.RecipientSecret].nonEmpty => Attempt.failure(ForbiddenTlv(UInt64(6))) case tlvs => Attempt.successful(RelayBlindedTlv(tlvs)) }, { case RelayBlindedTlv(tlvs) => tlvs }) - val finalBlindedTlvCodec: Codec[FinalBlindedTlv] = blindedTlvCodec.narrow( + val finalBlindedTlvCodec: Codec[FinalBlindedTlv] = encryptedRecipientDataCodec.narrow( tlvs => Attempt.successful(FinalBlindedTlv(tlvs)) , { case FinalBlindedTlv(tlvs) => tlvs diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/message/OnionMessagesSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/message/OnionMessagesSpec.scala index 44df49fd2e..dc0b54d940 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/message/OnionMessagesSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/message/OnionMessagesSpec.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.message.OnionMessages.{IntermediateNode, Recipient} import fr.acinq.eclair.randomKey import fr.acinq.eclair.wire.protocol.MessageOnion.{finalBlindedTlvCodec, messageRelayPayloadCodec, relayBlindedTlvCodec} import fr.acinq.eclair.wire.protocol.MessageTlv._ -import fr.acinq.eclair.wire.protocol.{OnionMessage, TlvStream} +import fr.acinq.eclair.wire.protocol.{EncryptedRecipientDataTlv, OnionMessage, TlvStream} import org.scalatest.funsuite.AnyFunSuite import scodec.bits.{ByteVector, HexStringSyntax} @@ -65,18 +65,18 @@ class OnionMessagesSpec extends AnyFunSuite { /* * Building the onion manually */ - val messageForAlice = RelayBlindedTlv(TlvStream(NextNodeId(bob.publicKey))) + val messageForAlice = RelayBlindedTlv(TlvStream(EncryptedRecipientDataTlv.OutgoingNodeId(bob.publicKey))) val encodedForAlice = relayBlindedTlvCodec.encode(messageForAlice).require.bytes assert(encodedForAlice == hex"04210324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c") - val messageForBob = RelayBlindedTlv(TlvStream(NextNodeId(carol.publicKey), BlindingPoint(blindingOverride.publicKey))) + val messageForBob = RelayBlindedTlv(TlvStream(EncryptedRecipientDataTlv.OutgoingNodeId(carol.publicKey), EncryptedRecipientDataTlv.NextBlinding(blindingOverride.publicKey))) val encodedForBob = relayBlindedTlvCodec.encode(messageForBob).require.bytes assert(encodedForBob == hex"0421027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa20070c2102989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f") - val messageForCarol = RelayBlindedTlv(TlvStream(Padding(hex"0000000000000000000000000000000000000000000000000000000000000000000000"), NextNodeId(dave.publicKey))) + val messageForCarol = RelayBlindedTlv(TlvStream(EncryptedRecipientDataTlv.Padding(hex"0000000000000000000000000000000000000000000000000000000000000000000000"), EncryptedRecipientDataTlv.OutgoingNodeId(dave.publicKey))) val encodedForCarol = relayBlindedTlvCodec.encode(messageForCarol).require.bytes assert(encodedForCarol == hex"012300000000000000000000000000000000000000000000000000000000000000000000000421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991") - val messageForDave = FinalBlindedTlv(TlvStream(PathId(hex"01234567"))) + val messageForDave = FinalBlindedTlv(TlvStream(EncryptedRecipientDataTlv.RecipientSecret(hex"01234567"))) val encodedForDave = finalBlindedTlvCodec.encode(messageForDave).require.bytes - assert(encodedForDave == hex"0e0401234567") + assert(encodedForDave == hex"060401234567") // Building blinded path Carol -> Dave val routeFromCarol = Sphinx.RouteBlinding.create(blindingOverride, carol.publicKey :: dave.publicKey :: Nil, encodedForCarol :: encodedForDave :: Nil) @@ -91,22 +91,22 @@ class OnionMessagesSpec extends AnyFunSuite { hex"350a336970e870b473ddbc27e3098bfa45bb1aa54f1f637f803d957e6271d8ffeba89da2665d62123763d9b634e30714144a1c165ac9", hex"580a561630da85e8759b8f3b94d74a539c6f0d870a87cf03d4986175865a2985553c997b560c36613bd9184c1a6d41a37027aabdab5433009d8409a1b638eb90373778a05716af2c215b3d31db7b2c2659716e663ba3d9c909", hex"5a0a588285acbceb37dfb38b877a888900539be656233cd74a55c55344fb068f9d8da365340d21db96fb41b76123207daeafdfb1f571e3fea07a22e10da35f03109a0380b3c69fcbed9c698086671809658761cf65ecbc3c07a2e5", - hex"180a16aa0771fd5ff6c494c2dbf1030332864d0d6df61acbf0")) + hex"180a16a20771fd5ff63f8ee26fac46c9de93cf6bd5916a928c")) val sessionKey = PrivateKey(hex"090909090909090909090909090909090909090909090909090909090909090901") val PacketAndSecrets(packet, _) = Sphinx.create(sessionKey,1300, publicKeys, payloads, None) - assert(packet.hmac == ByteVector32(hex"564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac")) + assert(packet.hmac == ByteVector32(hex"cb7f2799a485f0bcb8aea2a954b886d9a4bd9f850afe79bcb4fd32bd6f1146b5")) assert(packet.publicKey == PublicKey(hex"0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967").value) assert(packet.payload == - hex"37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a" + hex"37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494e0a53e9bca19b1422b5a10ac1e11de893d6692e3c9a46a9590f7e1ac9838239d82e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef3ac7aa1585cecd2b7d72c41a11b9526aeaa8cdde73d2dcc2fa94ee18907bc3e6ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d585f983e53873d66b3d04e4b6fbfad1632ac31edf90f948a88742df1089024591680b1d74b28e7ce5bd25e63e7ae369795dfe74c21e24b8bbf02d1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a" ) val onionForAlice = OnionMessage(blindingSecret.publicKey, packet) /* * Building the onion with functions from `OnionMessages` */ - val replyPath = OnionMessages.buildRoute(blindingOverride, IntermediateNode(carol.publicKey, padding = Some(hex"0000000000000000000000000000000000000000000000000000000000000000000000")) :: Nil, Left(Recipient(dave.publicKey, pathId = Some(hex"01234567")))) + val replyPath = OnionMessages.buildRoute(blindingOverride, IntermediateNode(carol.publicKey, padding = Some(hex"0000000000000000000000000000000000000000000000000000000000000000000000")) :: Nil, Left(Recipient(dave.publicKey, secret = Some(hex"01234567")))) assert(replyPath == routeFromCarol) val (_, message) = OnionMessages.buildMessage(sessionKey, blindingSecret, IntermediateNode(alice.publicKey) :: IntermediateNode(bob.publicKey) :: Nil, Right(replyPath), Nil) assert(message == onionForAlice) @@ -154,7 +154,7 @@ class OnionMessagesSpec extends AnyFunSuite { assert(Crypto.sha256(blindingKey.value ++ sharedSecret.bytes) == ByteVector32(hex"bae3d9ea2b06efd1b7b9b49b6cdcaad0e789474a6939ffa54ff5ec9224d5b76c")) val enctlv = hex"6970e870b473ddbc27e3098bfa45bb1aa54f1f637f803d957e6271d8ffeba89da2665d62123763d9b634e30714144a1c165ac9" assert(blindedNodes.head.encryptedPayload == enctlv) - val message = RelayBlindedTlv(TlvStream(NextNodeId(nextNodeId))) + val message = RelayBlindedTlv(TlvStream(EncryptedRecipientDataTlv.OutgoingNodeId(nextNodeId))) assert(relayBlindedTlvCodec.encode(message).require.bytes == encmsg) val relayNext = relayBlindedTlvCodec.decode(encmsg.bits).require.value assert(relayNext.nextNodeId == nextNodeId) @@ -181,7 +181,7 @@ class OnionMessagesSpec extends AnyFunSuite { assert(Crypto.sha256(blindingKey.value ++ sharedSecret.bytes) == ByteVector32(hex"9afb8b2ebc174dcf9e270be24771da7796542398d29d4ff6a4e7b6b4b9205cfe")) val enctlv = hex"1630da85e8759b8f3b94d74a539c6f0d870a87cf03d4986175865a2985553c997b560c36613bd9184c1a6d41a37027aabdab5433009d8409a1b638eb90373778a05716af2c215b3d31db7b2c2659716e663ba3d9c909" assert(blindedHops.head.encryptedPayload == enctlv) - val message = RelayBlindedTlv(TlvStream(NextNodeId(nextNodeId), BlindingPoint(PrivateKey(hex"070707070707070707070707070707070707070707070707070707070707070701").publicKey))) + val message = RelayBlindedTlv(TlvStream(EncryptedRecipientDataTlv.OutgoingNodeId(nextNodeId), EncryptedRecipientDataTlv.NextBlinding(PrivateKey(hex"070707070707070707070707070707070707070707070707070707070707070701").publicKey))) assert(relayBlindedTlvCodec.encode(message).require.bytes == encmsg) val relayNext = relayBlindedTlvCodec.decode(encmsg.bits).require.value assert(relayNext.nextNodeId == nextNodeId) @@ -208,7 +208,7 @@ class OnionMessagesSpec extends AnyFunSuite { assert(Crypto.sha256(blindingKey.value ++ sharedSecret.bytes) == ByteVector32(hex"cc3b918cda6b1b049bdbe469c4dd952935e7c1518dd9c7ed0cd2cd5bc2742b82")) val enctlv = hex"8285acbceb37dfb38b877a888900539be656233cd74a55c55344fb068f9d8da365340d21db96fb41b76123207daeafdfb1f571e3fea07a22e10da35f03109a0380b3c69fcbed9c698086671809658761cf65ecbc3c07a2e5" assert(blindedHops.head.encryptedPayload == enctlv) - val message = RelayBlindedTlv(TlvStream(Padding(hex"0000000000000000000000000000000000000000000000000000000000000000000000"), NextNodeId(nextNodeId))) + val message = RelayBlindedTlv(TlvStream(EncryptedRecipientDataTlv.Padding(hex"0000000000000000000000000000000000000000000000000000000000000000000000"), EncryptedRecipientDataTlv.OutgoingNodeId(nextNodeId))) assert(relayBlindedTlvCodec.encode(message).require.bytes == encmsg) val relayNext = relayBlindedTlvCodec.decode(encmsg.bits).require.value assert(relayNext.nextNodeId == nextNodeId)