BOLT #4: Onion Routing Protocol
Overview
This document describes the construction of an onion routed packet that is used to route a payment from an origin node to a final node. The packet is routed through a number of intermediate nodes, called hops.
The routing schema is based on the Sphinx construction and is extended with a per-hop payload.
Intermediate nodes forwarding the message can verify the integrity of the packet and can learn which node they should forward the packet to. They cannot learn which other nodes, besides their predecessor or successor, are part of the packet’s route; nor can they learn the length of the route or their position within it. The packet is obfuscated at each hop, to ensure that a network-level attacker cannot associate packets belonging to the same route (i.e. packets belonging to the same route do not share any correlating information). Notice that this does not preclude the possibility of packet association by an attacker via traffic analysis.
The route is constructed by the origin node, which knows the public keys of each intermediate node and of the final node. Knowing each node’s public key allows the origin node to create a shared secret (using ECDH) for each intermediate node and for the final node. The shared secret is then used to generate a pseudo-random stream of bytes (which is used to obfuscate the packet) and a number of keys (which are used to encrypt the payload and compute the HMACs). The HMACs are then in turn used to ensure the integrity of the packet at each hop.
Each hop along the route only sees an ephemeral key for the origin node, in order to hide the sender’s identity. The ephemeral key is blinded by each intermediate hop before forwarding to the next, making the onions unlinkable along the route.
This specification describes version 0 of the packet format and routing mechanism.
A node: - upon receiving a higher version packet than it implements: - MUST report a route failure to the origin node. - MUST discard the packet.
Table of Contents
- Conventions
- Key Generation
- Pseudo Random Byte Stream
- Packet Structure
- Route Blinding
- Accepting and Forwarding a Payment
- Shared Secret
- Blinding Ephemeral Onion Keys
- Packet Construction
- Onion Decryption
- Filler Generation
- Returning Errors
- Successful Payments
- Onion Messages
max_htlc_cltvSelection- Test Vector
- References
- Authors
Conventions
There are a number of conventions adhered to throughout this document:
- HMAC: the integrity verification of the packet is based on
Keyed-Hash Message Authentication Code, as defined by the FIPS
198 Standard/RFC
2104, and using a
SHA256hashing algorithm. - Elliptic curve: for all computations involving elliptic
curves, the Bitcoin curve is used, as specified in
secp256k1 - Pseudo-random stream:
ChaCha20is used to generate a pseudo-random byte stream. For its generation, a fixed 96-bit null-nonce (0x000000000000000000000000) is used, along with a key derived from a shared secret and with a0x00-byte stream of the desired output size as the message. - The terms origin node and final node refer to the initial packet sender and the final packet recipient, respectively.
- The terms hop and node are sometimes used interchangeably, but a hop usually refers to an intermediate node in the route rather than an end node. origin node –> hop –> … –> hop –> final node
- The term processing node refers to the specific node along the route that is currently processing the forwarded packet.
- The term peers refers only to hops that are direct neighbors (in the overlay network): more specifically, sending peers forward packets to receiving peers.
- Each hop in the route has a variable length
hop_payload.- The variable length
hop_payloadis prefixed with abigsizeencoding the length in bytes, excluding the prefix and the trailing HMAC.
- The variable length
- These
hop_payloads are used to build the combined payload in the packet, also referred to ashop_payloadsor the mix-header.
Key Generation
A number of encryption and verification keys are derived from the shared secret:
- rho: used as key when generating the pseudo-random byte stream that is used to obfuscate the per-hop information
- mu: used during the HMAC generation
- um: used during error reporting
- pad: use to generate random filler bytes for the starting mix-header packet
The key generation function takes a key-type
(rho=0x72686F,
mu=0x6d75, um=0x756d,
or pad=0x706164) and a 32-byte secret as
inputs and returns a 32-byte key.
Keys are generated by computing an HMAC (with
SHA256 as hashing algorithm) using the appropriate
key-type (i.e. rho, mu, um, or
pad) as HMAC-key and the 32-byte shared secret as the
message. The resulting HMAC is then returned as the key.
Notice that the key-type does not include a C-style
0x00-termination-byte, e.g. the length of the
rho key-type is 3 bytes, not 4.
Pseudo Random Byte Stream
The pseudo-random byte stream is used to obfuscate the packet
at each hop of the path, so that each hop may only recover the
address and HMAC of the next hop. The pseudo-random byte stream is
generated by encrypting (using ChaCha20) a
0x00-byte stream, of the required length, which is
initialized with a key derived from the shared secret and a 96-bit
zero-nonce (0x000000000000000000000000).
The use of a fixed nonce is safe, since the keys are never reused.
Packet Structure
The packet consists of four sections:
- a
versionbyte - a 33-byte compressed
secp256k1public_key, used during the shared secret generation - a 1300-byte
hop_payloadsconsisting of multiple, variable length,hop_payloadpayloads - a 32-byte
hmac, used to verify the packet’s integrity
The network format of the packet consists of the individual sections serialized into one contiguous byte-stream and then transferred to the packet recipient. Due to the fixed size of the packet, it need not be prefixed by its length when transferred over a connection.
The overall structure of the packet is as follows:
- type:
onion_packet - data:
- [
byte:version] - [
point:public_key] - [
1300*byte:hop_payloads] - [
32*byte:hmac]
- [
For this specification (version 0),
version has a constant value of
0x00.
The hop_payloads field is a structure that holds
obfuscated routing information, and associated HMAC. It is 1300
bytes long and has the following structure:
- type:
hop_payloads - data:
- [
bigsize:length] - [
length*byte:payload] - [
32*byte:hmac] - …
filler
- [
Where, the length, payload, and
hmac are repeated for each hop; and where,
filler consists of obfuscated,
deterministically-generated padding, as detailed in Filler
Generation. Additionally, hop_payloads is
incrementally obfuscated at each hop.
Using the payload field, the origin node is able
to specify the path and structure of the HTLCs forwarded at each
hop. As the payload is protected under the
packet-wide HMAC, the information it contains is fully
authenticated with each pair-wise relationship between the HTLC
sender (origin node) and each hop in the path.
Using this end-to-end authentication, each hop is able to
cross-check the HTLC parameters with the payload’s
specified values and to ensure that the sending peer hasn’t
forwarded an ill-crafted HTLC.
Since no payload TLV value can ever be shorter
than 2 bytes, length values of 0 and 1 are reserved.
(0 indicated a legacy format no longer supported, and
1 is reserved for future use).
payload format
This is formatted according to the Type-Length-Value format defined in BOLT #1.
tlv_stream:payload- types:
- type: 2 (
amt_to_forward) - data:
- [
tu64:amt_to_forward]
- [
- type: 4 (
outgoing_cltv_value) - data:
- [
tu32:outgoing_cltv_value]
- [
- type: 6 (
short_channel_id) - data:
- [
short_channel_id:short_channel_id]
- [
- type: 8 (
payment_data) - data:
- [
32*byte:payment_secret] - [
tu64:total_msat]
- [
- type: 10 (
encrypted_recipient_data) - data:
- [
...*byte:encrypted_recipient_data]
- [
- type: 12 (
current_path_key) - data:
- [
point:path_key]
- [
- type: 16 (
payment_metadata) - data:
- [
...*byte:payment_metadata]
- [
- type: 18 (
total_amount_msat) - data:
- [
tu64:total_msat]
- [
- type: 2 (
short_channel_id is the ID of the outgoing channel
used to route the message; the receiving peer should operate the
other end of this channel.
amt_to_forward is the amount, in millisatoshis, to
forward to the next receiving peer specified within the routing
information, or for the final destination.
For non-final nodes, this includes the origin node’s computed fee for the receiving peer, calculated according to the receiving peer’s advertised fee schema (as described in BOLT #7).
outgoing_cltv_value is the CLTV value that the
outgoing HTLC carrying the packet should have. Inclusion
of this field allows a hop to both authenticate the information
specified by the origin node, and the parameters of the HTLC
forwarded, and ensure the origin node is using the current
cltv_expiry_delta value.
If the values don’t correspond, this indicates that either a
forwarding node has tampered with the intended HTLC values or that
the origin node has an obsolete cltv_expiry_delta
value.
The requirements ensure consistency in responding to an
unexpected outgoing_cltv_value, whether it is the
final node or not, to avoid leaking its position in the route.
Requirements
The creator of encrypted_recipient_data (usually,
the recipient of payment):
- MUST create
encrypted_data_tlvfor each node in the blinded route (including itself). - MUST include
encrypted_data_tlv.payment_relayfor each non-final node. - MUST include exactly one of
encrypted_data_tlv.short_channel_idorencrypted_data_tlv.next_node_idfor each non-final node. - MUST set
encrypted_data_tlv.payment_constraintsfor each non-final node and MAY set it for the final node:max_cltv_expiryto the largest block height at which the route is allowed to be used, starting from the final node’s chosenmax_cltv_expiryheight at which the route should expire, adding the final node’smin_final_cltv_expiry_deltaand then addingencrypted_data_tlv.payment_relay.cltv_expiry_deltaat each hop.htlc_minimum_msatto the largest minimum HTLC value the nodes will allow.
- If it sets
encrypted_data_tlv.allowed_features:- MUST set it to an empty array.
- MUST compute the total fees and CLTV delta of the route as
follows and communicate them to the sender:
total_fee_base_msat(n+1) = (fee_base_msat(n+1) * 1000000 + total_fee_base_msat(n) * (1000000 + fee_proportional_millionths(n+1)) + 1000000 - 1) / 1000000total_fee_proportional_millionths(n+1) = ((total_fee_proportional_millionths(n) + fee_proportional_millionths(n+1)) * 1000000 + total_fee_proportional_millionths(n) * fee_proportional_millionths(n+1) + 1000000 - 1) / 1000000total_cltv_delta = cltv_delta(0) + cltv_delta(1) + ... + cltv_delta(n) + min_final_cltv_expiry_delta
- MUST create the
encrypted_recipient_datafrom theencrypted_data_tlvas required in Route Blinding.
The writer of the TLV payload:
- For every node inside a blinded route:
- MUST include the
encrypted_recipient_dataprovided by the recipient - For the first node in the blinded route:
- MUST include the
path_keyprovided by the recipient incurrent_path_key
- MUST include the
- If it is the final node:
- MUST include
amt_to_forward,outgoing_cltv_valueandtotal_amount_msat. - The value set for
outgoing_cltv_value:- MUST use the current block height as a baseline value.
- if a random
offset was added to improve privacy:
- SHOULD add the offset to the baseline value.
- MUST include
- MUST NOT include any other tlv field.
- MUST include the
- For every node outside of a blinded route:
- MUST include
amt_to_forwardandoutgoing_cltv_value. - For every non-final node:
- MUST include
short_channel_id - MUST NOT include
payment_data
- MUST include
- For the final node:
- MUST NOT include
short_channel_id - if the recipient provided
payment_secret:- MUST include
payment_data - MUST set
payment_secretto the one provided - MUST set
total_msatto the total amount it will send
- MUST include
- if the recipient provided
payment_metadata:- MUST include
payment_metadatawith every HTLC - MUST not apply any limits to the size of
payment_metadataexcept the limits implied by the fixed onion size
- MUST include
- MUST NOT include
- MUST include
The reader:
- If
encrypted_recipient_datais present:- If
path_keyis set in the incomingupdate_add_htlc:- MUST return an error if
current_path_keyis present. - MUST use that
path_keyaspath_keyfor decryption.
- MUST return an error if
- Otherwise:
- MUST return an error if
current_path_keyis not present. - MUST use that
current_path_keyas thepath_keyfor decryption. - SHOULD add a random delay before returning errors.
- MUST return an error if
- MUST return an error if
encrypted_recipient_datadoes not decrypt using thepath_keyas described in Route Blinding. - If
payment_constraintsis present:- MUST return an error if:
- the expiry is greater than
encrypted_recipient_data.payment_constraints.max_cltv_expiry. - the amount is below
encrypted_recipient_data.payment_constraints.htlc_minimum_msat.
- the expiry is greater than
- MUST return an error if:
- If
allowed_featuresis missing:- MUST process the message as if it were present and contained an empty array.
- MUST return an error if:
encrypted_recipient_data.allowed_features.featurescontains an unknown feature bit (even if it is odd).encrypted_recipient_datacontains bothshort_channel_idandnext_node_id.- the payment uses a feature not included in
encrypted_recipient_data.allowed_features.features.
- If it is not the final node:
- MUST return an error if the payload contains other tlv fields
than
encrypted_recipient_dataandcurrent_path_key. - MUST return an error if
encrypted_recipient_datadoes not contain eithershort_channel_idornext_node_id. - MUST return an error if
encrypted_recipient_datadoes not containpayment_relay. - MUST use values from
encrypted_recipient_data.payment_relayto calculateamt_to_forwardandoutgoing_cltv_valueas follows:amt_to_forward = ((amount_msat - fee_base_msat) * 1000000 + 1000000 + fee_proportional_millionths - 1) / (1000000 + fee_proportional_millionths)outgoing_cltv_value = cltv_expiry - payment_relay.cltv_expiry_delta
- MUST return an error if the payload contains other tlv fields
than
- If it is the final node:
- MUST return an error if the payload contains other tlv fields
than
encrypted_recipient_data,current_path_key,amt_to_forward,outgoing_cltv_valueandtotal_amount_msat. - MUST return an error if
amt_to_forward,outgoing_cltv_valueortotal_amount_msatare not present. - MUST return an error if
amt_to_forwardis below what it expects for the payment. - MUST return an error if incoming
cltv_expiry<outgoing_cltv_value. - MUST return an error if incoming
cltv_expiry<current_block_height+min_final_cltv_expiry_delta.
- MUST return an error if the payload contains other tlv fields
than
- If
- Otherwise (it is not part of a blinded route):
- MUST return an error if
path_keyis set in the incomingupdate_add_htlcorcurrent_path_keyis present. - MUST return an error if
amt_to_forwardoroutgoing_cltv_valueare not present. - if it is not the final node:
- MUST return an error if:
short_channel_idis not present,- it cannot forward the HTLC to the peer indicated by the
channel
short_channel_id. - incoming
amount_msat-fee<amt_to_forward(wherefeeis the advertised fee as described in BOLT #7) cltv_expiry-cltv_expiry_delta<outgoing_cltv_value
- MUST return an error if:
- MUST return an error if
- If it is the final node:
- MUST return an error if:
total_msatis not present- incoming
amount_msat<amt_to_forward. - incoming
cltv_expiry<outgoing_cltv_value. - incoming
cltv_expiry<current_block_height+min_final_cltv_expiry_delta.
- MUST return an error if:
Additional requirements are specified here for multi-part payments, and here for blinded payments.
Basic Multi-Part Payments
An HTLC may be part of a larger “multi-part” payment: such
“base” atomic multipath payments will use the same
payment_hash for all paths.
Note that amt_to_forward is the amount for this
HTLC only: a total_msat field containing a greater
value is a promise by the ultimate sender that the rest of the
payment will follow in succeeding HTLCs; we call these outstanding
HTLCs which have the same preimage, an “HTLC set”.
Note that there are two distinct tlv fields that can be used to
transmit total_msat. The last one,
total_amount_msat, was introduced with blinded paths
for which the payment_secret doesn’t make sense.
payment_metadata is to be included in every
payment part, so that invalid payment details can be detected as
early as possible.
Requirements
The writer: - if the invoice offers the basic_mpp
feature: - MAY send more than one HTLC to pay the invoice. - MUST
use the same payment_hash on all HTLCs in the set. -
SHOULD send all payments at approximately the same time. - SHOULD
try to use diverse paths to the recipient for each HTLC. - SHOULD
retry and/or re-divide HTLCs which fail. - if the invoice
specifies an amount: - MUST set
total_msat to at least that amount, and
less than or equal to twice amount. - otherwise: -
MUST set total_msat to the amount it wishes to pay. -
MUST ensure that the total amt_to_forward of the HTLC
set which arrives at the payee is equal to or greater than
total_msat. - MUST NOT send another HTLC if the total
amt_to_forward of the HTLC set is already greater or
equal to total_msat. - MUST include
payment_secret. - otherwise: - MUST set
total_msat equal to amt_to_forward.
The final node: - MUST fail the HTLC if dictated by
Requirements under Failure Messages
- Note: “amount paid” specified there is the
total_msat field. - if it does not support
basic_mpp: - MUST fail the HTLC if
total_msat is not exactly equal to
amt_to_forward. - otherwise, if it supports
basic_mpp: - MUST add it to the HTLC set
corresponding to that payment_hash. - SHOULD fail the
entire HTLC set if total_msat is not the same for all
HTLCs in the set. - if the total amt_to_forward of
this HTLC set is equal to or greater than total_msat:
- SHOULD fulfill all HTLCs in the HTLC set - otherwise, if the
total amt_to_forward of this HTLC set is less than
total_msat: - MUST NOT fulfill any HTLCs in the HTLC
set - MUST fail all HTLCs in the HTLC set after some reasonable
timeout. - SHOULD wait for at least 60 seconds after the initial
HTLC. - SHOULD use mpp_timeout for the failure
message. - MUST require payment_secret for all HTLCs
in the set. - if it fulfills any HTLCs in the HTLC set: - MUST
fulfill the entire HTLC set.
Rationale
If basic_mpp is present it causes a delay to allow
other partial payments to combine. The total amount must be
sufficient for the desired payment, just as it must be for single
payments. But this must be reasonably bounded to avoid a
denial-of-service.
Because invoices do not necessarily specify an amount, and because payers can add noise to the final amount, the total amount must be sent explicitly. The requirements allow exceeding this slightly, as it simplifies adding noise to the amount when splitting, as well as scenarios in which the senders are genuinely independent (friends splitting a bill, for example).
Because a node may need to pay more than its desired amount
(due to the htlc_minimum_msat value of channels in
the desired path), nodes are allowed to pay more than the
total_msat they specified. Otherwise, nodes would be
constrained in which paths they can take when retrying payments
along specific paths. However, no individual HTLC may be for less
than the difference between the total paid and
total_msat.
The restriction on sending an HTLC once the set is over the agreed total prevents the preimage being released before all the partial payments have arrived: that would allow any intermediate node to immediately claim any outstanding partial payments.
An implementation may choose not to fulfill an HTLC set which otherwise meets the amount criterion (eg. some other failure, or invoice timeout), however if it were to fulfill only some of them, intermediary nodes could simply claim the remaining ones.
Route Blinding
- subtype:
blinded_path - data:
- [
sciddir_or_pubkey:first_node_id] - [
point:first_path_key] - [
byte:num_hops] - [
num_hops*blinded_path_hop:path]
- [
- subtype:
blinded_path_hop - data:
- [
point:blinded_node_id] - [
u16:enclen] - [
enclen*byte:encrypted_recipient_data]
- [
A blinded path consists of: 1. an initial introduction point
(first_node_id) 2. an initial key to share a secret
with the first node_id (first_path_key) 3. a series
of tweaked node ids (path.blinded_node_id) 4. a
series of binary blobs encrypted to the nodes
(path.encrypted_recipient_data) to tell them the next
hop.
For example, Dave wants Alice to reach him via public node Bob
then Carol. He creates a chain of public keys (“path_keys”) for
Bob, Carol and finally himself, so he can share a secret with each
of them. These keys are a simple chain, so each node can derive
the next path_key without having to be told
explicitly.
From these shared secrets, Dave creates and encrypts three
encrypted_data_tlvs: 1. encrypted_data_bob: For Bob
to tell him to forward to Carol 2. encrypted_data_carol: For Carol
to tell her to forward to him 3. encrypted_data_dave: For himself
to indicate the path was used, and any metadata he wants.
To mask the node ids, he also derives three blinding factors from the shared secrets, which turn Bob into Bob’, Carol into Carol’ and Dave into Dave’.
So this is the blinded_path he hands to Alice.
first_node_id: Bobfirst_path_key: the first path key for Bobpath: [Bob’, encrypted_data_bob], [Carol’, encrypted_data_carol], [Dave’, encrypted_data_dave]
There are two different ways for Alice to construct an onion which gets to Bob (since he’s probably not a direct peer of hers) which are described in the requirements below.
But after Bob the path is always the same: he will send Carol
the path_key he derived, along with the onion. She
will use the path_key to derive the tweak for the
onion (which Alice encrypted for Carol’ not Carol) so she can
decrypt it, and also to derive the key to decrypt
encrypted_data_tlv which will tell her to forward to
Dave (and possibly additional restrictions Dave specified).
Requirements
Note that the creator of the blinded path (i.e. the recipient) is creating it for the sender to use to create an onion, and for the intermediate nodes to read the instructions, hence there are two reader sections here.
The writer of a blinded_path:
- MUST create a viable path to itself ($`N_r`$) i.e. $`N_0 \rightarrow N_1 \rightarrow ... \rightarrow N_r`$.
- MUST set
first_node_idto $`N_0`$ - MUST create a series of ECDH shared secrets for each node in
the route using the following algorithm:
- $`e_0 \leftarrow \{0;1\}^{256}`$ ($`e_0`$ SHOULD be obtained via CSPRNG)
- $`E_0 = e_0 \cdot G`$
- For every node in the route:
- let $`N_i = k_i * G`$ be the
node_id($`k_i`$ is $`N_i`$’s private key) - $`ss_i = SHA256(e_i * N_i) = SHA256(k_i * E_i)`$ (ECDH shared secret known only by $`N_r`$ and $`N_i`$)
- $`rho_i = HMAC256(\text{"rho"},
ss_i)`$ (key used to encrypt
encrypted_recipient_datafor $`N_i`$ by $`N_r`$) - $`e_{i+1} = SHA256(E_i || ss_i) * e_i`$ (ephemeral private path key, only known by $`N_r`$)
- $`E_{i+1} = SHA256(E_i || ss_i) *
E_i`$ (
path_key. NB: $`N_i`$ MUST NOT learn $`e_i`$)
- let $`N_i = k_i * G`$ be the
- MUST set
first_path_keyto $`E_0`$ - MUST create a series of blinded node IDs $`B_i`$ for each node using the
following algorithm:
- $`B_i =
HMAC256(\text{"blinded\_node\_id"}, ss_i) * N_i`$ (blinded
node_idfor $`N_i`$, private key known only by $`N_i`$) - MUST set
blinded_node_idfor eachblinded_path_hopinpathto $`B_i`$
- $`B_i =
HMAC256(\text{"blinded\_node\_id"}, ss_i) * N_i`$ (blinded
- MAY replace $`E_{i+1}`$ with
a different value, but if it does:
- MUST set
encrypted_data_tlv[i].next_path_key_overrideto $`E_{i+1}`$
- MUST set
- MAY store private data in
encrypted_data_tlv[r].path_idto verify that the route is used in the right context and was created by them - SHOULD add padding data to ensure all
encrypted_data_tlv[i]have the same length - MUST encrypt each
encrypted_data_tlv[i]with ChaCha20-Poly1305 using the corresponding $`rho_i`$ key and an all-zero nonce to produceencrypted_recipient_data[i] - MAY add additional “dummy” hops at the end of the path (which it will ignore on receipt) to obscure the path length.
The reader of the blinded_path: - MUST prepend its
own onion payloads to reach the first_node_id - MUST
include the corresponding encrypted_recipient_data in
each onion payload within path - For the first entry
in path: - if it is sending a payment: - SHOULD
create an unblinded onion payment to first_node_id,
and include first_path_key as
current_path_key. - otherwise: - MUST encrypt the
first blinded path onion to the first
blinded_node_id. - MUST set
next_path_key_override in the prior onion payload to
first_path_key. - For each successive entry in
path: - MUST encrypt the onion to the corresponding
blinded_node_id.
The reader of the encrypted_recipient_data:
- MUST compute:
- $`ss_i = SHA256(k_i * E_i)`$ (standard ECDH)
- $`b_i = HMAC256(\text{"blinded\_node\_id"}, ss_i) * k_i`$
- $`rho_i = HMAC256(\text{"rho"}, ss_i)`$
- MUST decrypt the
encrypted_recipient_datafield using $`rho_i`$ as a key using ChaCha20-Poly1305 and an all-zero nonce key. - If the
encrypted_recipient_datafield is missing, cannot be decrypted into anencrypted_data_tlvor contains unknown even fields:- MUST return an error
- If the
encrypted_data_tlvcontains anext_path_key_override:- MUST use it as the next
path_key.
- MUST use it as the next
- Otherwise:
- MUST use $`E_{i+1} = SHA256(E_i ||
ss_i) * E_i`$ as the next
path_key
- MUST use $`E_{i+1} = SHA256(E_i ||
ss_i) * E_i`$ as the next
- MUST forward the onion and include the next
path_keyin the lightning message for the next node - If it is the final recipient:
- MUST ignore the message if the
path_iddoes not match the blinded route it created for this purpose
- MUST ignore the message if the
Rationale
Route blinding is a lightweight technique to provide recipient anonymity. It’s more flexible than rendezvous routing because it simply replaces the public keys of the nodes in the route with random public keys while letting senders choose what data they put in the onion for each hop. Blinded routes are also reusable in some cases (e.g. onion messages).
Each node in the blinded route needs to receive $`E_i`$ to be able to decrypt the onion
and the encrypted_recipient_data payload.
When concatenating two blinded routes generated by different
nodes, the last node of the first route needs to know the first
path_key of the second route: the
next_path_key_override field must be used to transmit
this information. In theory this method could be used for payments
(not just onion messages), but we recommend using an unblinded
path to reach the first_node_id and using
current_path_key there: this means that the node can
tell it is being used as an introductory point, but also does not
require blinded path support on the nodes to reach that point, and
gives meaningful errors on the unblinded part of the payment.
The final recipient must verify that the blinded route is used
in the right context (e.g. for a specific payment) and was created
by them. Otherwise a malicious sender could create different
blinded routes to all the nodes that they suspect could be the
real recipient and try them until one accepts the message. The
recipient can protect against that by storing $`E_r`$ and the context (e.g. a
payment_hash), and verifying that they match when
receiving the onion. Otherwise, to avoid additional storage cost,
it can put some private context information in the
path_id field (e.g. the
payment_preimage) and verify that when receiving the
onion. Note that it’s important to use private information in that
case, that senders cannot have access to.
Whenever the introduction point receives a failure from the blinded route, it should add a random delay before forwarding the error. Failures are likely to be probing attempts and message timing may help the attacker infer its distance to the final recipient.
Note that nodes in the blinded route return failures through
update_fail_malformed_htlc and therefore do not and
can not provide timing information via attribution data to the
sender.
The padding field can be used to ensure that all
encrypted_recipient_data have the same length. It’s
particularly useful when adding dummy hops at the end of a blinded
route, to prevent the sender from figuring out which node is the
final recipient.
When route blinding is used for payments, the recipient
specifies the fees and expiry that blinded nodes should apply to
the payment instead of letting the sender configure them. The
recipient also adds additional constraints to the payments that
can go through that route to protect against probing attacks that
would let malicious nodes unblind the identity of the blinded
nodes. It should set
payment_constraints.max_cltv_expiry to restrict the
lifetime of a blinded route and reduce the risk that an
intermediate node updates its fees and rejects payments (which
could be used to unblind nodes inside the route).
Inside
encrypted_recipient_data:
encrypted_data_tlv
The encrypted_recipient_data is a TLV stream,
encrypted for a given blinded node, that may contain the following
TLV fields:
tlv_stream:encrypted_data_tlv- types:
- type: 1 (
padding) - data:
- [
...*byte:padding]
- [
- type: 2 (
short_channel_id) - data:
- [
short_channel_id:short_channel_id]
- [
- type: 4 (
next_node_id) - data:
- [
point:node_id]
- [
- type: 6 (
path_id) - data:
- [
...*byte:data]
- [
- type: 8 (
next_path_key_override) - data:
- [
point:path_key]
- [
- type: 10 (
payment_relay) - data:
- [
u16:cltv_expiry_delta] - [
u32:fee_proportional_millionths] - [
tu32:fee_base_msat]
- [
- type: 12 (
payment_constraints) - data:
- [
u32:max_cltv_expiry] - [
tu64:htlc_minimum_msat]
- [
- type: 14 (
allowed_features) - data:
- [
...*byte:features]
- [
- type: 1 (
Rationale
Encrypted recipient data is created by the final recipient to give to the sender, containing instructions for the node on how to handle the message (it can also be created by the sender themselves: the node forwarding cannot tell). It’s used in both payment onions and onion messages onions. See Route Blinding.
Accepting and Forwarding a Payment
Once a node has decoded the payload it either accepts the payment locally, or forwards it to the peer indicated as the next hop in the payload.
Non-strict Forwarding
A node MAY forward an HTLC along an outgoing channel other than
the one specified by short_channel_id, so long as the
receiver has the same node public key intended by
short_channel_id. Thus, if
short_channel_id connects nodes A and B, the HTLC can
be forwarded across any channel connecting A and B. Failure to
adhere will result in the receiver being unable to decrypt the
next hop in the onion packet.
Rationale
In the event that two peers have multiple channels, the downstream node will be able to decrypt the next hop payload regardless of which channel the packet is sent across.
Nodes implementing non-strict forwarding are able to make real-time assessments of channel bandwidths with a particular peer, and use the channel that is locally-optimal.
For example, if the channel specified by
short_channel_id connecting A and B does not have
enough bandwidth at forwarding time, then A is able use a
different channel that does. This can reduce payment latency by
preventing the HTLC from failing due to bandwidth constraints
across short_channel_id, only to have the sender
attempt the same route differing only in the channel between A and
B.
Non-strict forwarding allows nodes to make use of private channels connecting them to the receiving node, even if the channel is not known in the public channel graph.
Recommendation
Implementations using non-strict forwarding should consider applying the same fee schedule to all channels with the same peer, as senders are likely to select the channel which results in the lowest overall cost. Having distinct policies may result in the forwarding node accepting fees based on the most optimal fee schedule for the sender, even though they are providing aggregate bandwidth across all channels with the same peer.
Alternatively, implementations may choose to apply non-strict forwarding only to like-policy channels to ensure their expected fee revenue does not deviate by using an alternate channel.
Payload for the Last Node
When building the route, the origin node MUST use a payload for the final node with the following values:
payment_secret: set to the payment secret specified by the recipient (e.g.payment_secretfrom a BOLT #11 payment invoice)outgoing_cltv_value: set to the final expiry specified by the recipient (e.g.min_final_cltv_expiry_deltafrom a BOLT #11 payment invoice)amt_to_forward: set to the final amount specified by the recipient (e.g.amountfrom a BOLT #11 payment invoice)
This allows the final node to check these values and return errors if needed, but it also eliminates the possibility of probing attacks by the second-to-last node. Such attacks could, otherwise, attempt to discover if the receiving peer is the last one by re-sending HTLCs with different amounts/expiries. The final node will extract its onion payload from the HTLC it has received and compare its values against those of the HTLC. See the Returning Errors section below for more details.
If not for the above, since it need not forward payments, the final node could simply discard its payload.
Shared Secret
The origin node establishes a shared secret with each hop along
the route using Elliptic-curve Diffie-Hellman between the sender’s
ephemeral key at that hop and the hop’s node ID key. The resulting
curve point is serialized to the compressed format and hashed
using SHA256. The hash output is used as the 32-byte
shared secret.
Elliptic-curve Diffie-Hellman (ECDH) is an operation on an EC
private key and an EC public key that outputs a curve point. For
this protocol, the ECDH variant implemented in
libsecp256k1 is used, which is defined over the
secp256k1 elliptic curve. During packet construction,
the sender uses the ephemeral private key and the hop’s public key
as inputs to ECDH, whereas during packet forwarding, the hop uses
the ephemeral public key and its own node ID private key. Because
of the properties of ECDH, they will both derive the same
value.
Blinding Ephemeral Onion Keys
In order to ensure multiple hops along the route cannot be linked by the ephemeral public keys they see, the key is blinded at each hop. The blinding is done in a deterministic way that allows the sender to compute the corresponding blinded private keys during packet construction.
The blinding of an EC public key is a single scalar multiplication of the EC point representing the public key with a 32-byte blinding factor. Due to the commutative property of scalar multiplication, the blinded private key is the multiplicative product of the input’s corresponding private key with the same blinding factor.
The blinding factor itself is computed as a function of the
ephemeral public key and the 32-byte shared secret. Concretely, it
is the SHA256 hash value of the concatenation of the
public key serialized in its compressed format and the shared
secret.
Packet Construction
In the following example, it’s assumed that a sending
node (origin node), n_0, wants to route a packet
to a receiving node (final node), n_r.
First, the sender computes a route
{n_0, n_1, ..., n_{r-1}, n_r}, where n_0
is the sender itself and n_r is the final recipient.
All nodes n_i and n_{i+1} MUST be peers
in the overlay network route. The sender then gathers the public
keys for n_1 to n_r and generates a
random 32-byte sessionkey. Optionally, the sender may
pass in associated data, i.e. data that the packet
commits to but that is not included in the packet itself.
Associated data will be included in the HMACs and must match the
associated data provided during integrity verification at each
hop. The payment_hash is commonly used for this
purpose.
To construct the onion, the sender initializes the ephemeral
private key for the first hop ek_1 to the
sessionkey and derives from it the corresponding
ephemeral public key epk_1 by multiplying with the
secp256k1 base point. For each of the k
hops along the route, the sender then iteratively computes the
shared secret ss_k and ephemeral key for the next hop
ek_{k+1} as follows:
- The sender executes ECDH with the hop’s public key and the
ephemeral private key to obtain a curve point, which is hashed
using
SHA256to produce the shared secretss_k. - The blinding factor is the
SHA256hash of the concatenation between the ephemeral public keyepk_kand the shared secretss_k. - The ephemeral private key for the next hop
ek_{k+1}is computed by multiplying the current ephemeral private keyek_kby the blinding factor. - The ephemeral public key for the next hop
epk_{k+1}is derived from the ephemeral private keyek_{k+1}by multiplying with the base point.
Once the sender has all the required information above, it can
construct the packet. Constructing a packet routed over
r hops requires r 32-byte ephemeral
public keys, r 32-byte shared secrets, r
32-byte blinding factors, and r variable length
hop_payload payloads. The construction returns a
single 1366-byte packet along with the first receiving peer’s
address.
The packet construction is performed in the reverse order of the route, i.e. the last hop’s operations are applied first.
The packet is initialized with 1300 random bytes
derived from a CSPRNG (ChaCha20). The pad key referenced
above is used to extract additional random bytes from a ChaCha20
stream, using it as a CSPRNG for this purpose. Once the
paddingKey has been obtained, ChaCha20 is used with
an all zero nonce, to generate 1300 random bytes. Those random
bytes are then used as the starting state of the mix-header to be
created.
A filler is generated (see Filler Generation) using the shared secret.
For each hop in the route, in reverse order, the sender applies the following operations:
- The rho-key and mu-key are generated using the hop’s shared secret.
shift_sizeis defined as the length of thehop_payloadplus the bigsize encoding of the length and the length of that HMAC. Thus if the payload length islthen theshift_sizeis1 + l + 32forl < 253, otherwise3 + l + 32due to the bigsize encoding ofl.- The
hop_payloadsfield is right-shifted byshift_sizebytes, discarding the lastshift_sizebytes that exceed its 1300-byte size. - The bigsize-serialized length, serialized
hop_payloadandhmacare copied into theshift_sizebytes as the beginning of the mix-header. - The rho-key is used to generate a 1300 byte
pseudo-random stream which is then applied, with
XOR, to thehop_payloadsfield. - If this is the last hop, i.e. the first iteration, then the
tail of the
hop_payloadsfield is overwritten with the routing informationfiller. - The next HMAC is computed (with the mu-key as
HMAC-key) over the concatenated
hop_payloadsand associated data.
The resulting final HMAC value is the HMAC that will be used by the first receiving peer in the route.
The packet generation returns a serialized packet that contains
the version byte, the ephemeral pubkey for the first
hop, the HMAC for the first hop, and the obfuscated
hop_payloads.
The following Go code is an example implementation of the packet construction:
const RoutingInfoSize int32 = 1300
func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey,
hopsData []HopData, assocData []byte) (*OnionPacket, error) {
numHops := len(paymentPath)
hopSharedSecrets := make([][sha256.Size]byte, numHops)
// Initialize ephemeral key for the first hop to the session key.
var ephemeralKey big.Int
ephemeralKey.Set(sessionKey.D)
for i := 0; i < numHops; i++ {
// Perform ECDH and hash the result.
ecdhResult := scalarMult(paymentPath[i], ephemeralKey)
hopSharedSecrets[i] = sha256.Sum256(ecdhResult.SerializeCompressed())
// Derive ephemeral public key from private key.
ephemeralPrivKey := btcec.PrivKeyFromBytes(btcec.S256(), ephemeralKey.Bytes())
ephemeralPubKey := ephemeralPrivKey.PubKey()
// Compute blinding factor.
sha := sha256.New()
sha.Write(ephemeralPubKey.SerializeCompressed())
sha.Write(hopSharedSecrets[i])
var blindingFactor big.Int
blindingFactor.SetBytes(sha.Sum(nil))
// Blind ephemeral key for next hop.
ephemeralKey.Mul(&ephemeralKey, &blindingFactor)
ephemeralKey.Mod(&ephemeralKey, btcec.S256().Params().N)
}
// Generate the padding, called "filler strings" in the paper.
filler := generateHeaderPadding(numHops, hopSharedSecrets)
// Allocate and initialize fields to zero-filled slices
var mixHeader [RoutingInfoSize]byte
var nextHmac [32]byte
// Our starting packet needs to be filled out with random bytes, we
// generate some deterministically using the session private key.
paddingKey := generateKey("pad", sessionKey.Serialize())
paddingBytes := generateCipherStream(paddingKey, RoutingInfoSize)
copy(mixHeader[:], paddingBytes)
// Compute the routing information for each hop along with a
// MAC of the routing information using the shared key for that hop.
for i := numHops - 1; i >= 0; i-- {
rhoKey := generateKey("rho", hopSharedSecrets[i])
muKey := generateKey("mu", hopSharedSecrets[i])
hopsData[i].HMAC = nextHmac
// Shift and obfuscate routing information
streamBytes := generateCipherStream(rhoKey, RoutingInfoSize)
rightShift(mixHeader[:], hopDataSize)
buf := &bytes.Buffer{}
hopsData[i].Encode(buf)
copy(mixHeader[:], buf.Bytes())
xor(mixHeader[:], mixHeader[:], streamBytes[:RoutingInfoSize])
// These need to be overwritten, so every node generates a correct padding
if i == numHops-1 {
copy(mixHeader[len(mixHeader)-len(filler):], filler)
}
packet := append(mixHeader[:], assocData...)
nextHmac = calcMac(muKey, packet)
}
packet := &OnionPacket{
Version: 0x00,
EphemeralKey: sessionKey.PubKey(),
RoutingInfo: mixHeader,
HeaderMAC: nextHmac,
}
return packet, nil
}
Onion Decryption
There are two kinds of onion_packet we use:
onion_routing_packetinupdate_add_htlcfor payments, which contains apayloadTLV (see Adding an HTLC)onion_message_packetinonion_messagefor messages, which contains anonionmsg_tlvTLV (see Onion Messages)
Those sections specify the associated_data to use,
the path_key (if any), the extracted payload format
and handling (including how to determine the next peer, if any),
and how to handle errors. The processing itself is identical.
Requirements
A reader: - if version is not 0: - MUST abort
processing the packet and fail. - if public_key is
not a valid pubkey: - MUST abort processing the packet and fail. -
if the onion is for a payment: - if hmac has
previously been received: - if the preimage is known: - MAY
immediately redeem the HTLC using the preimage. - otherwise: -
MUST abort processing the packet and fail. - if
path_key is specified: - Calculate the
blinding_ss as ECDH(path_key,
node_privkey). - Either: - Tweak
public_key by multiplying by $`HMAC256(\text{"blinded\_node\_id"},
blinding\_ss)`$. - or (equivalently): - Tweak its own
node_privkey below by multiplying by $`HMAC256(\text{"blinded\_node\_id"},
blinding\_ss)`$. - Derive the shared secret ss
as ECDH(public_key, node_privkey) (see
Shared Secret). -
Derive mu as $`HMAC256(\text{"mu"}, ss)`$ (see Key Generation). -
Derive the HMAC as $`HMAC256(mu,
hop\_payloads || associated\_data)`$. - MUST use a constant
time comparison of the computed HMAC and hmac. - If
the computed HMAC and hmac differ: - MUST abort
processing the packet and fail. - Derive rho as $`HMAC256(\text{"rho"}, ss)`$ (see Key Generation). -
Derive bytestream of twice the length of
hop_payloads using rho (see Pseudo Random Byte Stream). -
Set unwrapped_payloads to the XOR of
hop_payloads and bytestream. - Remove a
bigsize from the front of
unwrapped_payloads as payload_length. If
that is malformed: - MUST abort processing the packet and fail. -
If the payload_length is less than two: - MUST abort
processing the packet and fail. - If there are fewer than
payload_length bytes remaining in
unwrapped_payloads: - MUST abort processing the
packet and fail. - Remove payload_length bytes from
the front of unwrapped_payloads, as the current
payload. - If there are fewer than 32 bytes remaining
in unwrapped_payloads: - MUST abort processing the
packet and fail. - Remove 32 bytes as next_hmac from
the front of unwrapped_payloads. - If
unwrapped_payloads is smaller than
hop_payloads: - MUST abort processing the packet and
fail. - If next_hmac is not all-zero (not the final
node): - Derive blinding_tweak as $`SHA256(public\_key || ss)`$ (see Blinding
Ephemeral Onion Keys). - SHOULD forward an onion to the next
peer with: - version set to 0. -
public_key set to the incoming
public_key multiplied by blinding_tweak.
- hop_payloads set to the
unwrapped_payloads, truncated to the incoming
hop_payloads size. - hmac set to
next_hmac. - If it cannot forward: - MUST fail. -
Otherwise (all-zero next_hmac): - This is the final
destination of the onion.
Rationale
In the case where blinded paths are used, the sender did not
actually encrypt this onion for our node_id, but for
a tweaked version: we can derive the tweak used from
path_key which is given alongside the onion. Then we
either tweak our node private key the same way to decrypt the
onion, or tweak to the onion ephemeral key which is mathematically
equivalent.
Filler Generation
Upon receiving a packet, the processing node extracts the information destined for it from the route information and the per-hop payload. The extraction is done by deobfuscating and left-shifting the field. This would make the field shorter at each hop, allowing an attacker to deduce the route length. For this reason, the field is pre-padded before forwarding. Since the padding is part of the HMAC, the origin node will have to pre-generate an identical padding (to that which each hop will generate) in order to compute the HMACs correctly for each hop. The filler is also used to pad the field-length, in the case that the selected route is shorter than 1300 bytes.
Before deobfuscating the hop_payloads, the
processing node pads it with 1300 0x00-bytes, such
that the total length is 2*1300. It then generates
the pseudo-random byte stream, of matching length, and applies it
with XOR to the hop_payloads. This
deobfuscates the information destined for it, while simultaneously
obfuscating the added 0x00-bytes at the end.
In order to compute the correct HMAC, the origin node has to
pre-generate the hop_payloads for each hop, including
the incrementally obfuscated padding added by each hop. This
incrementally obfuscated padding is referred to as the
filler. Keep in mind that while the mix-header is
generated in reverse-route order, the filler is generated in route
order.
The following example code shows how the filler is generated in Go:
const (
// The mix-header in Lightning is a max of 1300 bytes
NumMaxHops int = 20
HopSize = 65
)
func generateFiller(numHops int, sharedSecrets [][sharedSecretSize]byte) []byte {
fillerSize := uint((NumMaxHops + 1) * HopSize)
filler := make([]byte, fillerSize)
// The last hop does not obfuscate, it's not forwarding anymore.
for i := 0; i < numHops-1; i++ {
// Left-shift the field
copy(filler[:], filler[HopSize:])
// Zero-fill the last hop
copy(filler[len(filler)-HopSize:], bytes.Repeat([]byte{0x00}, HopSize))
// Generate pseudo-random byte stream
streamKey := generateKey("rho", sharedSecrets[i])
streamBytes := generateCipherStream(streamKey, fillerSize)
// Obfuscate
xor(filler, filler, streamBytes)
}
// Cut filler down to the correct length (numHops+1)*HopSize
// bytes will be prepended by the packet generation.
return filler[(NumMaxHops-numHops+2)*HopSize:]
}
Note that this example implementation is for demonstration
purposes only; the filler can be generated much more
efficiently. The last hop need not obfuscate the
filler, since it won’t forward the packet any further
and thus need not extract an HMAC either.
Returning Errors
The onion routing protocol includes a mechanism for returning encrypted error messages to the origin node. The returned error messages may be failures reported by any hop, including the final node. The format of the forward packet is not usable for the return path, since no hop besides the origin has access to the information required for its generation. Note that these error messages are not reliable, as they are not placed on-chain due to the possibility of hop failure.
Return packets are limited to 32768 bytes (32 KiB), leaving
room in update_fail_htlc for
attribution_data and future extensions. Earlier
versions permitted larger return packets, so intermediate nodes
truncate them to their first 32768 bytes instead of rejecting the
corresponding message.
Intermediate hops store the shared secret from the forward path and reuse it to authenticate and obfuscate any corresponding return packet during each hop. In addition, each node locally stores data regarding its own sending peer in the route, so it knows where to return-forward any eventual return packets.
Erring node
The node generating the error message builds a return packet consisting of the following fields:
- data:
- [
32*byte:hmac] - [
u16:failure_len] - [
failure_len*byte:failuremsg] - [
u16:pad_len] - [
pad_len*byte:pad]
- [
Where hmac is an HMAC authenticating the remainder
of the packet, with a key generated using the above process, with
key type um, failuremsg as defined
below, and pad as the extra bytes used to conceal
length.
The erring node then generates a new key, using the key type
ammag. This key is then used to generate a
pseudo-random stream, which is in turn applied to the packet using
XOR.
Error handling for HTLCs with path_key is
particularly fraught, since differences in implementations (or
versions) may be leveraged to de-anonymize elements of the blinded
path. Thus the decision turn every error into
invalid_onion_blinding which will be converted to a
normal onion error by the introduction point.
Initialization of
attribution_data
For the layout of attribution data, see Removing
an HTLC: update_fulfill_htlc,
update_fail_htlc, and
update_fail_malformed_htlc.
The htlc_hold_times field specifies the htlc hold
time for each hop in units of 100 milliseconds. For example, a
value of 3 represents 300 ms. Nodes along the path that lack
accurate timing information may report a value of zero.
The erring node puts its hold time at the start of this array and zeroes out the rest. The size of the field is based on the maximum supported number of hops in a route (20).
The field truncated_hmacs contains truncated
authentication codes series for each hop, with the same
um key that is used for hmac in the
return packet. Regular 32 byte HMACs are truncated to the first 4
bytes to save space.
In theory this truncation makes it possible for malicious nodes to guess the HMAC. However, game theory is against them because a wrong guess will get them penalized in future pathfinding.
The size of the field is based on the maximum number of hops in a route (20) and the truncated HMAC size (4 bytes). Each hop adds 20 HMACs, one for each possible position that the hop could be at in the path. This is necessary because only the sender knows the position of each hop in the path.
It is not required to store all 20 * 20 = 400 HMACs. The node in position 0 needs to store an HMAC for every one of the 20 positions. For the node in position 1, the maximum remaining route length is only 19. For that position just 19 HMACs need to be kept, and so on. This makes for a total number of HMACs of 20+19+18+…+1 = 210 HMACs.
The layout of the hmacs field is shown below. The
actual format is much longer, but for readability the format is
described as if the maximum route length would be just three
hops.
hmac_0_2 | hmac_0_1|
hmac_0_0| hmac_1_1|
hmac_1_0| hmac_2_0
hmac_x_y is the hmac added by node x
(counted from the node that is currently handling the failure
message) assuming that this node is y hops away from
the erring node.
Each HMAC is computed from the combination of the following elements, concatenated in the specified order.
The return packet before applying the pseudo-random byte stream.
The concatenation of the first
y+1hold times inhtlc_hold_times. For example,hmac_0_2would cover all three hold times.The concatenation of
ydownstream hmacs that correspond to downstream node positions relative tox. For example,hmac_0_2would coverhmac_1_1andhmac_2_0.
The erring node stores its 20 HMACs at the start of the array
and zeroes out the rest. Strictly speaking the erring node would
only need to add the single hmac_0_0 here, because
there is no downstream data to cover. However, for verification
efficiency at the origin node, we still require all HMACs to be
calculated. The redundant HMACs will cover portions of the
zero-initialized data.
Finally a new key is generated, using the key type
ammagext. This key is then used to generate a
pseudo-random stream, which is in turn applied to the
attribution_data field using XOR.
Requirements
The erring node: - MUST construct the return packet
such that its total length is no more than 32768 bytes (32 KiB). -
MUST set pad such that the failure_len
plus pad_len is at least 256. - SHOULD set
pad such that the failure_len plus
pad_len is equal to 256. Deviating from this may
cause older nodes to be unable to parse the return message. - if
option_attribution_data is advertised: - if
path_key is not set in the incoming
update_add_htlc: - MUST initialize
attribution_data and include it in
update_fail_htlc
Intermediate nodes
Transformation of the return packet
Generate the node’s ammag key, generate the
pseudo-random byte streams, and apply the result to obfuscate the
return packet. This is then stored as the reason
field of the update_htlc_fail message.
This obfuscation step is identical to the obfuscation steps that the erring node carries out.
Transformation of
attribution_data
Shift all existing hold times to the right (4 bytes).
Shift and prune all existing HMACs.
At each step backwards, one HMAC for every hop can be pruned. When HMACs for all 20 positions are present, and it turns out that there is another hop upstream, each existing HMAC that now corresponds to position 21 due to the preceding hop becomes obsolete.
For the simplified three-hop layout above, the shift/prune operation would apply a transformation that results in:
-|-|-|hmac_0'_1|hmac_0'_0|hmac_1'_0The former
hmac_x'_ynow becomeshmac_x+1_y. The left-most HMAC for each hop is discarded.
Update of
attribution_data
Put the node’s hold time at the start of
htlc_hold_times. The shift operation above has opened up a slot for that.Calculate its own 20 truncated HMACs and put them at the start of
hmacsin the newly opened slots.Generate the node’s
ammagextkey, generate the pseudo-random byte stream, and apply the result to obfuscate theattribution_datafield. This obfuscation step is identical to the obfuscation steps that the erring node carries out.
Requirements
The intermediate node: - if the return packet received
from downstream is longer than 32768 bytes: - MUST truncate it to
its first 32768 bytes before transforming the return packet or
updating attribution_data - if
option_attribution_data is advertised: - if
path_key is not set in the incoming
update_add_htlc: - if attribution_data
is received from downstream: - MUST transform
attribution_data as described above - otherwise: -
MUST instantiate an all-zeroes attribution_data block
- MUST update attribution_data as described above -
MUST transform the return packet as described above. - MUST
return-forward the update_htlc_fail message
Origin node
The origin node is able to detect that it’s the intended final
recipient of the return message, because of course, it was the
originator of the corresponding forward packet. When an origin
node receives an update_htlc_fail message matching a
transfer it initiated (i.e. it cannot return-forward the error any
further) it generates the ammag,
ammagext and um keys for each hop in the
route.
It then iteratively decrypts the message, using each hop’s
ammag and ammagext keys. At each hop,
the following steps are carried out:
For origin nodes supporting
option_attribution_data:
Verify the HMAC in
attribution_datathat corresponds to the hop’s position in the path using the hop’sumkey. If the HMAC is invalid, processing of the message can stop and the node should penalize this hop for future path selection. This is what makes the failure ‘attributable’.Because HMACs cover all data including HMACs added by downstream nodes, it is not possible for a malicious node to tamper with the message without revealing themselves. Blame is still only assignable to a pair of nodes though, because it is impossible to know whether sender or receiver modified the message. This is true for other failure cases in Lightning too.
When not every path node supports
option_attribution_data, the origin node will still have attribution data up to the first node downstream without support.Record the reported htlc hold time for this hop.
The origin node can use this information to score nodes on latency. When a zero hold time is reported, the origin node should distribute any potential latency penalty across multiple nodes. This encourages path nodes to provide timing data to avoid being held responsible for the high latency of other nodes.
For all nodes:
Compute the HMAC for the return packet, using the hop’s
umkey.When the computed HMAC matches
hmacin the return packet, the origin node will know that the current hop is the sender of the failure. They can then parsefailuremsg.
The association between the forward and return packets is handled outside of this onion routing protocol, e.g. via association with an HTLC in a payment channel.
Requirements
The origin node: - once the return message has been
decrypted: - SHOULD store a copy of the message. - SHOULD continue
decrypting, until the loop has been repeated 27 times (maximum
route length of tlv payload type). - SHOULD use constant
ammag and um keys to obfuscate the route
length. - When the failure source cannot be identified from the
return packet AND attribution_data is present: -
SHOULD use attribution_data to identify the failure
source
Rationale
The requirements for the origin node should help hide the payment sender. By continuing decrypting 27 times (dummy decryption cycles after the error is found) the erroring node cannot learn its relative position in the route by performing a timing analysis if the sender were to retry the same route multiple times.
Failure Messages
The failure message encapsulated in failuremsg has
an identical format as a normal message: a 2-byte type
failure_code followed by data applicable to that
type. The message data is followed by an optional TLV
stream.
Below is a list of the currently supported
failure_code values, followed by their use case
requirements.
Notice that the failure_codes are not of the same
type as other message types, defined in other BOLTs, as they are
not sent directly on the transport layer but are instead wrapped
inside return packets. The numeric values for the
failure_code may therefore reuse values, that are
also assigned to other message types, without any danger of
causing collisions.
The top byte of failure_code can be read as a set
of flags: * 0x8000 (BADONION): unparsable onion encrypted by
sending peer * 0x4000 (PERM): permanent failure (otherwise
transient) * 0x2000 (NODE): node failure (otherwise channel) *
0x1000 (UPDATE): channel forwarding parameter was violated
The following failure_codes are defined:
- type: NODE|2 (
temporary_node_failure)
General temporary failure of the processing node.
- type: PERM|NODE|2 (
permanent_node_failure)
General permanent failure of the processing node.
- type: PERM|NODE|3
(
required_node_feature_missing)
The processing node has a required feature which was not in this onion.
- type: BADONION|PERM|4
(
invalid_onion_version) - data:
- [
sha256:sha256_of_onion]
- [
The version byte was not understood by the
processing node.
- type: BADONION|PERM|5 (
invalid_onion_hmac) - data:
- [
sha256:sha256_of_onion]
- [
The HMAC of the onion was incorrect when it reached the processing node.
- type: BADONION|PERM|6 (
invalid_onion_key) - data:
- [
sha256:sha256_of_onion]
- [
The ephemeral key was unparsable by the processing node.
- type: UPDATE|7 (
temporary_channel_failure) - data:
- [
u16:len] - [
len*byte:channel_update]
- [
The channel from the processing node was unable to handle this HTLC, but may be able to handle it, or others, later.
- type: PERM|8 (
permanent_channel_failure)
The channel from the processing node is unable to handle any HTLCs.
- type: PERM|9
(
required_channel_feature_missing)
The channel from the processing node requires features not present in the onion.
- type: PERM|10 (
unknown_next_peer)
The onion specified a short_channel_id which
doesn’t match any leading from the processing node.
- type: UPDATE|11 (
amount_below_minimum) - data:
- [
u64:htlc_msat] - [
u16:len] - [
len*byte:channel_update]
- [
The HTLC amount was below the htlc_minimum_msat of
the channel from the processing node.
- type: UPDATE|12 (
fee_insufficient) - data:
- [
u64:htlc_msat] - [
u16:len] - [
len*byte:channel_update]
- [
The fee amount was below that required by the channel from the processing node.
- type: UPDATE|13 (
incorrect_cltv_expiry) - data:
- [
u32:cltv_expiry] - [
u16:len] - [
len*byte:channel_update]
- [
The cltv_expiry does not comply with the
cltv_expiry_delta required by the channel from the
processing node: it does not satisfy the following
requirement:
cltv_expiry - cltv_expiry_delta >= outgoing_cltv_value
- type: UPDATE|14 (
expiry_too_soon) - data:
- [
u16:len] - [
len*byte:channel_update]
- [
The CLTV expiry is too close to the current block height for safe handling by the processing node.
- type: PERM|15
(
incorrect_or_unknown_payment_details) - data:
- [
u64:htlc_msat] - [
u32:height]
- [
The payment_hash is unknown to the final node, the
payment_secret doesn’t match the
payment_hash, the amount for that
payment_hash is too low, the CLTV expiry of the htlc
is too close to the current block height for safe handling or
payment_metadata isn’t present while it should
be.
The htlc_msat parameter is superfluous, but left
in for backwards compatibility. The value of
htlc_msat is required to be at least the value
specified in the final hop onion payload. It therefore does not
have any substantial informative value to the sender (though may
indicate the penultimate node took a lower fee than expected). A
penultimate hop sending an amount or an expiry that is too low for
the htlc is handled through
final_incorrect_cltv_expiry and
final_incorrect_htlc_amount.
The height parameter is set by the final node to
the best known block height at the time of receiving the htlc.
This can be used by the sender to distinguish between sending a
payment with the wrong final CLTV expiry and an intermediate hop
delaying the payment so that the receiver’s invoice CLTV delta
requirement is no longer met.
Note: Originally PERM|16
(incorrect_payment_amount) and 17
(final_expiry_too_soon) were used to differentiate
incorrect htlc parameters from unknown payment hash. Sadly,
sending this response allows for probing attacks whereby a node
which receives an HTLC for forwarding can check guesses as to its
final destination by sending payments with the same hash but much
lower values or expiry heights to potential destinations and check
the response. Care must be taken by implementations to
differentiate the previously non-permanent case for
final_expiry_too_soon (17) from the other, permanent
failures now represented by
incorrect_or_unknown_payment_details (PERM|15).
- type: 18 (
final_incorrect_cltv_expiry) - data:
- [
u32:cltv_expiry]
- [
The CLTV expiry in the HTLC is less than the value in the onion.
- type: 19 (
final_incorrect_htlc_amount) - data:
- [
u64:incoming_htlc_amt]
- [
The amount in the HTLC is less than the value in the onion.
- type: UPDATE|20 (
channel_disabled) - data:
- [
u16:disabled_flags] - [
u16:len] - [
len*byte:channel_update]
- [
The channel from the processing node has been disabled. No
flags for disabled_flags are currently defined, thus
it is currently always two zero bytes.
- type: 21 (
expiry_too_far)
The CLTV expiry in the HTLC is too far in the future.
- type: PERM|22 (
invalid_onion_payload) - data:
- [
bigsize:type] - [
u16:offset]
- [
The decrypted onion per-hop payload was not understood by the
processing node or is incomplete. If the failure can be narrowed
down to a specific tlv type in the payload, the erring node may
include that type and its byte offset in
the decrypted byte stream.
- type: 23 (
mpp_timeout)
The complete amount of the multi-part payment was not received within a reasonable time.
- type: BADONION|PERM|24
(
invalid_onion_blinding) - data:
- [
sha256:sha256_of_onion]
- [
An error occurred within the blinded path.
Requirements
An erring node: - if path_key is set in
the incoming update_add_htlc: - MUST return an
invalid_onion_blinding error. - if
current_path_key is set in the onion payload and it
is not the final node: - MUST return an
invalid_onion_blinding error. - otherwise: - MUST
select one of the above error codes when creating an error
message. - MUST include the appropriate data for that particular
error type. - if there is more than one error: - SHOULD select the
first error it encounters from the list above.
An erring node MAY: - if the per-hop payload in the
onion is invalid (e.g. it is not a valid tlv stream) or is missing
required information (e.g. the amount was not specified): - return
an invalid_onion_payload error. - if an otherwise
unspecified transient error occurs for the entire node: - return a
temporary_node_failure error. - if an otherwise
unspecified permanent error occurs for the entire node: - return a
permanent_node_failure error. - if a node has
requirements advertised in its node_announcement
features, which were NOT included in the onion: -
return a required_node_feature_missing error.
A forwarding node MUST: - if path_key is
set in the incoming update_add_htlc: - return an
invalid_onion_blinding error. - if
current_path_key is set in the onion payload: -
return an invalid_onion_blinding error. - otherwise:
- select one of the above error codes when creating an error
message.
A forwarding node MAY, but a final node MUST
NOT: - if during forwarding to its receiving peer, an otherwise
unspecified, transient error occurs in the outgoing channel
(e.g. channel capacity reached, too many in-flight HTLCs, etc.): -
return a temporary_channel_failure error. - if an
otherwise unspecified, permanent error occurs during forwarding to
its receiving peer (e.g. channel recently closed): - return a
permanent_channel_failure error. - if the outgoing
channel has requirements advertised in its
channel_announcement’s features, which
were NOT included in the onion: - return a
required_channel_feature_missing error. - if the
receiving peer specified by the onion is NOT known: - return an
unknown_next_peer error. - if the HTLC amount is less
than the currently specified minimum amount: - report the amount
of the outgoing HTLC and the current channel setting for the
outgoing channel. - return an amount_below_minimum
error. - if the HTLC does NOT pay a sufficient fee: - report the
amount of the incoming HTLC and the current channel setting for
the outgoing channel. - return a fee_insufficient
error. - if the incoming cltv_expiry minus the
outgoing_cltv_value is below the
cltv_expiry_delta for the outgoing channel: - report
the cltv_expiry of the outgoing HTLC and the current
channel setting for the outgoing channel. - return an
incorrect_cltv_expiry error. - if the
cltv_expiry is unreasonably near the present: -
report the current channel setting for the outgoing channel. -
return an expiry_too_soon error. - if the
cltv_expiry is more than max_htlc_cltv
in the future: - return an expiry_too_far error. - if
the channel is disabled: - report the current channel setting for
the outgoing channel. - return a channel_disabled
error.
A forwarding node and a final node MAY: - if
the onion version byte is unknown: - return an
invalid_onion_version error. - if the onion HMAC is
incorrect: - return an invalid_onion_hmac error. - if
the ephemeral key in the onion is unparsable: - return an
invalid_onion_key error.
A forwarding node MUST NOT, but a final node
MUST: - if the payment hash has already been paid: - MAY treat the
payment hash as unknown. - MAY succeed in accepting the HTLC. - if
the payment_secret doesn’t match the expected value
for that payment_hash, or the
payment_secret is required and is not present: - MUST
fail the HTLC. - MUST return an
incorrect_or_unknown_payment_details error. - if the
amount paid is less than the amount expected: - MUST fail the
HTLC. - MUST return an
incorrect_or_unknown_payment_details error. - if the
payment hash is unknown: - MUST fail the HTLC. - MUST return an
incorrect_or_unknown_payment_details error. - if the
amount paid is more than twice the amount expected: - SHOULD fail
the HTLC. - SHOULD return an
incorrect_or_unknown_payment_details error. - Note:
this allows the origin node to reduce information leakage by
altering the amount while not allowing for accidental gross
overpayment. - if the cltv_expiry value is
unreasonably near the present: - MUST fail the HTLC. - MUST return
an incorrect_or_unknown_payment_details error. - if
the cltv_expiry from the final node’s HTLC is below
outgoing_cltv_value: - MUST return
final_incorrect_cltv_expiry error. - if
amount_msat from the final node’s HTLC is below
amt_to_forward: - MUST return a
final_incorrect_htlc_amount error. - if it returns a
channel_update: - MUST set
short_channel_id to the short_channel_id
used by the incoming onion.
Rationale
In the case of multiple short_channel_id aliases, the
channel_update short_channel_id should
refer to the one the original sender is expecting, to both avoid
confusion and to avoid leaking information about other aliases (or
the real location of the channel UTXO).
The channel_update field used to be mandatory in
messages whose failure_code includes the
UPDATE flag. However, because nodes applying an
update contained in the onion to their gossip data is a massive
fingerprinting vulnerability, the channel_update
field is no longer mandatory and nodes are expected to transition
away from including it. Nodes which do not provide a
channel_update are expected to set the
channel_update len field to zero.
Some nodes may still use the channel_update for
retries of the same payment, however.
Receiving Failure Codes
Requirements
The origin node: - MUST ignore any extra bytes in
failuremsg. - if the final node is returning
the error: - if the PERM bit is set: - SHOULD fail the payment. -
otherwise: - if the error code is understood and valid: - MAY
retry the payment. In particular,
final_expiry_too_soon can occur if the block height
has changed since sending, and in this case
temporary_node_failure could resolve within a few
seconds. - otherwise, an intermediate hop is returning
the error: - if the NODE bit is set: - SHOULD remove all channels
connected with the erring node from consideration. - if the PERM
bit is NOT set: - SHOULD restore the channels as it receives new
channel_updates from its peers. - otherwise: - if
UPDATE is set, AND the channel_update is valid and
more recent than the channel_update used to send the
payment: - MAY consider the channel_update when
calculating routes to retry the payment which failed - MUST NOT
expose the channel_update to third-parties in any
other context, including applying the channel_update
to the local network graph, send the channel_update
to peers as gossip, etc. - SHOULD then retry routing and sending
the payment. - MAY use the data specified in the various failure
types for debugging purposes.
Successful Payments
The update_fulfill_htlc message contains an
optional attribution_data field, identical to the one
used in the failure case described above. With attribution data,
the sender can obtain hold times as reported and committed to by
each hop along the payment path.
In addition, the final node can return data to the origin node
in an optional fulfillment_payload field. It is the
success counterpart of the failure message that an erring node
returns in the reason field of
update_fail_htlc. The final node builds the plaintext
as a fulfillment_payload_tlvs TLV
stream:
tlv_stream:fulfillment_payload_tlvs- types:
- type: 1 (
padding) - data:
- [
...*byte:padding]
- [
- type: 1 (
padding conceals the length of the conveyed data
and is ignored by the origin. Apart from padding, no
record types are defined yet.
The final node generates a key using key type
fulfillment and its shared secret with the origin
node, then encrypts this plaintext with ChaCha20-Poly1305 using
that key and an all-zero nonce, as for
encrypted_recipient_data in route blinding. The
ciphertext and its 16-byte tag are the
fulfillment_payload. Each intermediate node then
obfuscates the fulfillment_payload with its
ammag key, exactly as it obfuscates a failure return
packet; the final node does not, as the ciphertext is already
confidential and forms the innermost layer. The
attribution_data HMACs added by intermediate nodes,
which already cover the hold times, now additionally cover the
fulfillment_payload. For each intermediate HMAC, the
covered fields are, in order: the fulfillment_payload
as received from the downstream node, before the current node
applies its own ammag obfuscation; the hold times;
and the downstream HMACs. The final node’s
attribution_data HMACs do not cover the
fulfillment_payload. With no payload present, there
is nothing extra for intermediate nodes to cover. The final node
still initializes and updates attribution_data, and
the origin still verifies the final node’s
attribution_data HMACs for its reported hold
time.
A successful payment is relayed back with
update_fulfill_htlc, so a
fulfillment_payload propagates back through every
hop, even a blinded path: a blinded final node can originate it,
and blinded hops obfuscate and relay it. The origin can still
recover it, because it shares a secret with every hop, blinded
ones included, computed from each hop’s public key (the blinded
public key for a blinded hop) when it built the onion. Returning a
fulfillment_payload is therefore not gated by the
path_key condition that applies to
attribution_data.
The origin knows the number of hops in the path, so the final
node is its last hop: the origin peels each intermediate hop’s
ammag obfuscation, including obfuscation for blinded
hops whose blinded public keys it used when constructing the
route, and decrypts the fulfillment_payload with the
last hop’s fulfillment key, one operation per hop.
The origin verifies the final node’s attribution_data
HMACs without a fulfillment_payload input. For each
intermediate hop, the origin removes that hop’s ammag
obfuscation from the fulfillment_payload and verifies
the hop’s attribution_data HMACs over the resulting
fulfillment_payload bytes. A recipient that conceals
its position with dummy hops in a blinded path must therefore
originate the fulfillment_payload as though it were
the last hop, applying the obfuscation for the concealed hops
itself, so that this decoding succeeds without revealing its
position.
The two integrity checks cover different extents. The Poly1305
tag is verified end-to-end and detects tampering by any hop,
blinded or not. The attribution_data HMACs are
contributed only by hops with path_key not set, so
they provide per-hop attribution where available, as in the
failure case. This split is intentional:
attribution_data is per-hop data for scoring path
nodes, which the origin cannot do for blinded hops it cannot
identify and whose hold times would aid de-anonymization, whereas
a fulfillment_payload is end-to-end data that reveals
nothing about the intermediate hops.
Like return packets, fulfillment_payload is
limited to 32768 bytes (32 KiB) to leave room for
attribution_data and future extensions. Because
fulfillment_payload was introduced with this limit,
receiving a larger payload is a protocol violation as specified in
BOLT
#2.
Requirements
attribution_data is initialized, transformed,
updated and verified exactly as in the failure case.
The final node: - if
option_attribution_data is advertised: - MAY include
a fulfillment_payload, even when reached through a
blinded path - if it includes a fulfillment_payload:
- MUST ensure the fulfillment_payload is no more than
32768 bytes (32 KiB) - MUST set
fulfillment_payload_tlvs to a serialized TLV stream -
MUST pad with padding such that the serialized
fulfillment_payload_tlvs stream is at least 256 bytes
and a multiple of 256 bytes, excluding the 16-byte Poly1305 tag.
The size calculation includes the type and length bytes of the
padding record; this can require padding to the next
multiple of 256 bytes - SHOULD pad such that the serialized
fulfillment_payload_tlvs stream is exactly 256 bytes
if possible - MUST encrypt the plaintext with ChaCha20-Poly1305 as
above - MUST NOT include the fulfillment_payload in
its attribution_data HMACs - MUST still initialize
and update attribution_data for its reported hold
time
An intermediate node: - if it receives a
fulfillment_payload from the downstream node: - MUST
obfuscate it with its ammag key and include it in the
outgoing update_fulfill_htlc, as it transforms a
return packet - MUST include the fulfillment_payload
as received from the downstream node in its
attribution_data HMACs
The origin node: - MUST recover a
fulfillment_payload by peeling each intermediate
hop’s ammag obfuscation and decrypting it with the
last hop’s fulfillment key - MUST verify the final
node’s attribution_data HMACs as in the failure case,
except that the HMAC input excludes the
fulfillment_payload, and process its reported hold
time - MUST remove an intermediate hop’s ammag
obfuscation from the fulfillment_payload before
verifying that hop’s attribution_data HMACs over the
resulting fulfillment_payload bytes - MUST ignore a
fulfillment_payload whose Poly1305 tag is invalid, or
whose decrypted fulfillment_payload_tlvs stream has
malformed lengths, duplicate or unordered types, or unknown even
types - MUST ignore padding records in a valid
fulfillment_payload_tlvs stream
Onion Messages
Onion messages allow peers to use existing connections to query for invoices (see BOLT 12). Like gossip messages, they are not associated with a particular local channel. Like HTLCs, they use onion messages protocol for end-to-end encryption.
Onion messages use the same form as HTLC
onion_packet, with a slightly more flexible format:
instead of 1300 byte payloads, the payload length is implied by
the total length (minus 66 bytes for the header and trailing
bytes). The onionmsg_payloads themselves are the same
as the hop_payloads format, except there is no
“legacy” length: a 0 length would mean an empty
onionmsg_payload.
Onion messages are unreliable: in particular, they are designed to be cheap to process and require no storage to forward. As a result, there is no error returned from intermediary nodes.
For consistency, all onion messages use Route Blinding.
The
onion_message Message
- type: 513 (
onion_message) (option_onion_messages) - data:
- [
point:path_key] - [
u16:len] - [
len*byte:onion_message_packet]
- [
- type:
onion_message_packet - data:
- [
byte:version] - [
point:public_key] - [
...*byte:onionmsg_payloads] - [
32*byte:hmac]
- [
- type:
onionmsg_payloads - data:
- [
bigsize:length] - [
length*u8:onionmsg_tlv] - [
32*byte:hmac] - …
filler
- [
The onionmsg_tlv itself is a TLV: an intermediate
node expects an encrypted_recipient_data which it can
decrypt into an encrypted_data_tlv using the
path_key which it is handed along with the onion
message.
Field numbers 64 and above are reserved for payloads for the final hop.
tlv_stream:onionmsg_tlv- types:
- type: 2 (
reply_path) - data:
- [
blinded_path:path]
- [
- type: 4 (
encrypted_recipient_data) - data:
- [
...*byte:encrypted_recipient_data]
- [
- type: 64 (
invoice_request) - data:
- [
tlv_invoice_request:invreq]
- [
- type: 66 (
invoice) - data:
- [
tlv_invoice:inv]
- [
- type: 68 (
invoice_error) - data:
- [
tlv_invoice_error:inverr]
- [
- type: 2 (
Requirements
The creator of encrypted_recipient_data (usually,
the recipient of the onion):
- MUST create the
encrypted_recipient_datafrom theencrypted_data_tlvas required in Route Blinding. - MUST NOT include
payment_relayorpayment_constraintsin anyencrypted_data_tlv - MUST include either
next_node_idorshort_channel_idin theencrypted_data_tlvfor each non-final node.
The writer:
- MUST set the
onion_message_packetversionto 0. - MUST construct the
onion_message_packetonionmsg_payloadsas detailed above using Sphinx. - MUST NOT use any
associated_datain the Sphinx construction. - SHOULD set
onion_message_packetlento 1366 or 32834. - SHOULD retry via a different path if it expects a response and doesn’t receive one after a reasonable period.
- For the non-final nodes’
onionmsg_tlv:- MUST NOT set fields other than
encrypted_recipient_data.
- MUST NOT set fields other than
- For the final node’s
onionmsg_tlv:- if the final node is permitted to reply:
- MUST set
reply_pathpath_keyto the initial path key for thefirst_node_id - MUST set
reply_pathfirst_node_idto the unblinded node id of the first node in the reply path. - For every
reply_pathpath:- MUST set
blinded_node_idto the blinded node id to encrypt the onion hop for. - MUST set
encrypted_recipient_datato a valid encryptedencrypted_data_tlvstream which meets the requirements of theonionmsg_tlvwhen used by the recipient. - MAY use
path_idto contain a secret so it can recognize use of thisreply_path.
- MUST set
- MUST set
- otherwise:
- MUST NOT set
reply_path.
- MUST NOT set
- if the final node is permitted to reply:
The reader:
- if it advertises
option_onion_messages_only_channels:- MUST NOT accept onion messages from peers without an established channel.
- otherwise:
- SHOULD accept onion messages from peers without an established channel.
- MAY rate-limit messages by dropping them.
- MUST decrypt
onion_message_packetusing an emptyassociated_data, andpath_key, as described in Onion Decryption to extract anonionmsg_tlv. - If decryption fails, the result is not a valid
onionmsg_tlv, or it contains unknown even types:- MUST ignore the message.
- if
encrypted_data_tlvcontainsallowed_features:- MUST ignore the message if:
encrypted_data_tlv.allowed_features.featurescontains an unknown feature bit (even if it is odd).- the message uses a feature not included in
encrypted_data_tlv.allowed_features.features.
- MUST ignore the message if:
- if it is not the final node according to the onion encryption:
- if the
onionmsg_tlvcontains other tlv fields thanencrypted_recipient_data:- MUST ignore the message.
- if the
encrypted_data_tlvcontainspath_id:- MUST ignore the message.
- otherwise:
- if
next_node_idis present:- the next peer is the peer with that node id.
- otherwise, if
short_channel_idis present and corresponds to an announced short_channel_id or a local alias for a channel:- the next peer is the peer at the other end of that channel.
- otherwise:
- MUST ignore the message.
- SHOULD forward the message using
onion_messageto the next peer. - if it forwards the message:
- MUST set
path_keyin the forwardedonion_messageto the nextpath_keyas calculated in Route Blinding.
- MUST set
- if
- if the
- otherwise (it is the final node):
- if
path_idis set and corresponds to a path the reader has previously published in areply_path:- if the onion message is not a reply to that previous onion:
- MUST ignore the onion message
- if the onion message is not a reply to that previous onion:
- otherwise (unknown or unset
path_id):- if the onion message is a reply to an onion message which
contained a
path_id:- MUST respond (or not respond) exactly as if it did not send the initial onion message.
- if the onion message is a reply to an onion message which
contained a
- if the
onionmsg_tlvcontains more than one payload field:- MUST ignore the message.
- if it wants to send a reply:
- MUST create an onion message using
reply_path. - MUST send the reply via
onion_messageto the node indicated by thefirst_node_id, usingreply_pathpath_keyto send alongreply_pathpath.
- MUST create an onion message using
- if
Rationale
Accepting onion messages from channelless peers is the
baseline: a node that advertises
option_onion_messages is expected to accept onion
messages from any connected peer. This is a SHOULD rather than a
MUST because acceptance is always best effort: a node may still
drop messages due to rate-limiting.
A node that wants to restrict acceptance to channel peers
(e.g. to limit the DoS surface of free bandwidth/CPU for any node
that can connect) advertises
option_onion_messages_only_channels as an explicit
opt-out. A restrictive node should not silently drop these
messages while advertising only the baseline: it has to advertise
the bit, which makes the bit a reliable signal. A sender can
therefore detect it and simply not attempt a relay it knows will
fail, rather than sending a message that is silently dropped.
Care must be taken that replies are only accepted using the exact reply_path given, otherwise probing is possible. That means checking both ways: non-replies don’t use the reply path, and replies always use the reply path.
The requirement to discard messages with
onionmsg_tlv fields which are not strictly required
ensures consistency between current and future implementations.
Even odd fields can be a problem since they are parsed (and thus
may be rejected!) by nodes which understand them, and ignored by
those which don’t.
All onion messages are blinded, even though this overhead is not always necessary (33 bytes here, the 16-byte MAC for each encrypted_data_tlv in the onion). This blinding allows nodes to use a path provided by others without knowing its contents. Using it universally simplifies implementations a little, and makes it more difficult to distinguish onion messages.
len allows larger messages to be sent than the
standard 1300 bytes allowed for an HTLC onion, but this should be
used sparingly as it reduces the anonymity set, hence the
recommendation that it either looks like an HTLC onion, or if
larger, be a fixed size.
Onion messages don’t explicitly require a channel, but for spam-reduction a node may choose to ratelimit such peers, especially messages it is asked to forward.
max_htlc_cltv
Selection
This max_htlc_cltv value is defined as 2016
blocks, based on historical value deployed by Lightning
implementations.
Test Vector
Returning Errors
The test vectors use the following parameters:
pubkey[0] = 0x02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619
htlc_hold_time[0] = 1
pubkey[1] = 0x0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c
htlc_hold_time[1] = 2
pubkey[2] = 0x027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007
htlc_hold_time[2] = 3
pubkey[3] = 0x032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991
htlc_hold_time[3] = 4
pubkey[4] = 0x02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145
htlc_hold_time[4] = 5
nhops = 5
sessionkey = 0x4141414141414141414141414141414141414141414141414141414141414141
failure_source = node 4
failure_message = `incorrect_or_unknown_payment_details`
htlc_msat = 100
height = 800000
tlv data
type = 34001
value = [128, 128, ..., 128] (300 bytes)
The following is an in-depth trace of an example of error message creation:
# creating error message
encoded_failure_message = 400f0000000000000064000c3500fd84d1fd012c80808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808002c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
shared_secret = b5756b9b542727dbafc6765a49488b023a725d631af688fc031217e90770c328
payload = 0140400f0000000000000064000c3500fd84d1fd012c80808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808002c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
um_key = 4da7f2923edce6c2d85987d1d9fa6d88023e6c3a9c3d20f07d3b10b61a78d646
raw_error_packet = fda7e11974f78ca6cc456f2d17ae54463664696e93842548245dd2a2c513a6260140400f0000000000000064000c3500fd84d1fd012c80808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808002c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
# forwarding error packet
shared_secret = b5756b9b542727dbafc6765a49488b023a725d631af688fc031217e90770c328
ammag_key = 2f36bb8822e1f0d04c27b7d8bb7d7dd586e032a3218b8d414afbba6f169a4d68
stream = e9c975b07c9a374ba64fd9be3aae955e917d34d1fa33f2e90f53bbf4394713c6a8c9b16ab5f12fd45edd73c1b0c8b33002df376801ff58aaa94000bf8a86f92620f343baef38a580102395ae3abf9128d1047a0736ff9b83d456740ebbb4aeb3aa9737f18fb4afb4aa074fb26c4d702f42968888550a3bded8c05247e045b866baef0499f079fdaeef6538f31d44deafffdfd3afa2fb4ca9082b8f1c465371a9894dd8c243fb4847e004f5256b3e90e2edde4c9fb3082ddfe4d1e734cacd96ef0706bf63c9984e22dc98851bcccd1c3494351feb458c9c6af41c0044bea3c47552b1d992ae542b17a2d0bba1a096c78d169034ecb55b6e3a7263c26017f033031228833c1daefc0dedb8cf7c3e37c9c37ebfe42f3225c326e8bcfd338804c145b16e34e4f5984bc119af09d471a61f39e9e389c4120cadabc5d9b7b1355a8ccef050ca8ad72f642fc26919927b347808bade4b1c321b08bc363f20745ba2f97f0ced2996a232f55ba28fe7dfa70a9ab0433a085388f25cce8d53de6a2fbd7546377d6ede9027ad173ba1f95767461a3689ef405ab608a21086165c64b02c1782b04a6dba2361a7784603069124e12f2f6dcb1ec7612a4fbf94c0e14631a2bef6190c3d5f35e0c4b32aa85201f449d830fd8f782ec758b0910428e3ec3ca1dba3b6c7d89f69e1ee1b9df3dfbbf6d361e1463886b38d52e8f43b73a3bd48c6f36f5897f514b93364a31d49d1d506340b1315883d425cb36f4ea553430d538fd6f3596d4afc518db2f317dd051abc0d4bfb0a7870c3db70f19fe78d6604bbf088fcb4613f54e67b038277fedcd9680eb97bdffc3be1ab2cbcbafd625b8a7ac34d8c190f98d3064ecd3b95b8895157c6a37f31ef4de094b2cb9dbf8ff1f419ba0ecacb1bb13df0253b826bec2ccca1e745dd3b3e7cc6277ce284d649e7b8285727735ff4ef6cca6c18e2714f4e2a1ac67b25213d3bb49763b3b94e7ebf72507b71fb2fe0329666477ee7cb7ebd6b88ad5add8b217188b1ca0fa13de1ec09cc674346875105be6e0e0d6c8928eb0df23c39a639e04e4aedf535c4e093f08b2c905a14f25c0c0fe47a5a1535ab9eae0d9d67bdd79de13a08d59ee05385c7ea4af1ad3248e61dd22f8990e9e99897d653dd7b1b1433a6d464ea9f74e377f2d8ce99ba7dbc753297644234d25ecb5bd528e2e2082824681299ac30c05354baaa9c3967d86d7c07736f87fc0f63e5036d47235d7ae12178ced3ae36ee5919c093a02579e4fc9edad2c446c656c790704bfc8e2c491a42500aa1d75c8d4921ce29b753f883e17c79b09ea324f1f32ddf1f3284cd70e847b09d90f6718c42e5c94484cc9cbb0df659d255630a3f5a27e7d5dd14fa6b974d1719aa98f01a20fb4b7b1c77b42d57fab3c724339d459ee4a1c6b5d3bd4e08624c786a257872acc9ad3ff62222f2265a658d9f2a007229a5293b67ec91c84c4b4407c228434bad8a815ca9b256c776bd2c9f
error packet for node 4: 146e94a9086dbbed6a0ab6932d00c118a7195dbf69b7d7a12b0e6956fc54b5e0a989f165b5f12fd45edd73a5b0c48630ff5be69500d3d82a29c0803f0a0679a6a073c33a6fb8250090a3152eba3f11a85184fa87b67f1b0354d6f48e3b342e332a17b7710f342f342a87cf32eccdf0afc2160808d58abb5e5840d2c760c538e63a6f841970f97d2e6fe5b8739dc45e2f7f5f532f227bcc2988ab0f9cc6d3f12909cd5842c37bc8c7608475a5ebbe10626d5ecc1f3388ad5f645167b44a4d166f87863fe34918cea25c18059b4c4d9cb414b59f6bc50c1cea749c80c43e2344f5d23159122ed4ab9722503b212016470d9610b46c35dbeebaf2e342e09770b38392a803bc9d2e7c8d6d384ffcbeb74943fe3f64afb2a543a6683c7db3088441c531eeb4647518cb41992f8954f1269fb969630944928c2d2b45593731b5da0c4e70d04a0a57afe4af42e99912fbb4f8883a5ecb9cb29b883cb6bfa0f4db2279ff8c6d2b56a232f55ba28fe7dfa70a9ab0433a085388f25cce8d53de6a2fbd7546377d6ede9027ad173ba1f95767461a3689ef405ab608a21086165c64b02c1782b04a6dba2361a7784603069124e12f2f6dcb1ec7612a4fbf94c0e14631a2bef6190c3d5f35e0c4b32aa85201f449d830fd8f782ec758b0910428e3ec3ca1dba3b6c7d89f69e1ee1b9df3dfbbf6d361e1463886b38d52e8f43b73a3bd48c6f36f5897f514b93364a31d49d1d506340b1315883d425cb36f4ea553430d538fd6f3596d4afc518db2f317dd051abc0d4bfb0a7870c3db70f19fe78d6604bbf088fcb4613f54e67b038277fedcd9680eb97bdffc3be1ab2cbcbafd625b8a7ac34d8c190f98d3064ecd3b95b8895157c6a37f31ef4de094b2cb9dbf8ff1f419ba0ecacb1bb13df0253b826bec2ccca1e745dd3b3e7cc6277ce284d649e7b8285727735ff4ef6cca6c18e2714f4e2a1ac67b25213d3bb49763b3b94e7ebf72507b71fb2fe0329666477ee7cb7ebd6b88ad5add8b217188b1ca0fa13de1ec09cc674346875105be6e0e0d6c8928eb0df23c39a639e04e4aedf535c4e093f08b2c905a14f25c0c0fe47a5a1535ab9eae0d9d67bdd79de13a08d59ee05385c7ea4af1ad3248e61dd22f8990e9e99897d653dd7b1b1433a6d464ea9f74e377f2d8ce99ba7dbc753297644234d25ecb5bd528e2e2082824681299ac30c05354baaa9c3967d86d7c07736f87fc0f63e5036d47235d7ae12178ced3ae36ee5919c093a02579e4fc9edad2c446c656c790704bfc8e2c491a42500aa1d75c8d4921ce29b753f883e17c79b09ea324f1f32ddf1f3284cd70e847b09d90f6718c42e5c94484cc9cbb0df659d255630a3f5a27e7d5dd14fa6b974d1719aa98f01a20fb4b7b1c77b42d57fab3c724339d459ee4a1c6b5d3bd4e08624c786a257872acc9ad3ff62222f2265a658d9f2a007229a5293b67ec91c84c4b4407c228434bad8a815ca9b256c776bd2c9f
attribution data for node 4: d77d0711b5f71d1d1be56bd88b3bb7ebc1792bb739ea7ebc1bc3b031b8bc2df3a50e25aeb99f47d7f7ab39e24187d3f4df9c4333463b053832ee9ac07274a5261b8b2a01fc09ce9ea7cd04d7b585dfb8cf5958e3f3f2a4365d1ec0df1d83c6a6221b5b7d1ff30156a2289a1d3ee559e7c7256bda444bb8e046f860e00b3a59a85e1e1a43de215fd5e6bf646a5deab97b1912c934e31b1cfd344764d6ca7e14ea7b3f2a951aba907c964c0f5d19a44e6d1d7279637321fa598adde927b3087d238f8b426ecde500d318617cdb7a56e6ce3520fc95be41a549973764e4dc483853ecc313947709f1b5199cb077d46e701fa633e11d3e13b03e9212c115ca6fa004b2f3dd912814693b705a561a06da54cdf603677a3abecdc22c7358c2de3cef771b366a568150aeecc86ad1990bb0f4e2865933b03ea0df87901bff467908273dc6cea31cbab0e2b8d398d10b001058c259ed221b7b55762f4c7e49c8c11a45a107b7a2c605c26dc5b0b10d719b1c844670102b2b6a36c43fe4753a78a483fc39166ae28420f112d50c10ee64ca69569a2f690712905236b7c2cb7ac8954f02922d2d918c56d42649261593c47b14b324a65038c3c5be8d3c403ce0c8f19299b1664bf077d7cf1636c4fb9685a8e58b7029fd0939fa07925a60bed339b23f973293598f595e75c8f9d455d7cebe4b5e23357c8bd47d66d6628b39427e37e0aecbabf46c11be6771f7136e108a143ae9bafba0fc47a51b6c7deef4cba54bae906398ee3162a41f2191ca386b628bde7e1dd63d1611aa01a95c456df337c763cb8c3a81a6013aa633739d8cd554c688102211725e6adad165adc1bcd429d020c51b4b25d2117e8bb27eb0cc7020f9070d4ad19ac31a76ebdf5f9246646aeadbfb9a3f1d75bd8237961e786302516a1a781780e8b73f58dc06f307e58bd0eb1d8f5c9111f01312974c1dc777a6a2d3834d8a2a40014e9818d0685cb3919f6b3b788ddc640b0ff9b1854d7098c7dd6f35196e902b26709640bc87935a3914869a807e8339281e9cedaaca99474c3e7bdd35050bb998ab4546f9900904e0e39135e861ff7862049269701081ebce32e4cca992c6967ff0fd239e38233eaf614af31e186635e9439ec5884d798f9174da6ff569d68ed5c092b78bd3f880f5e88a7a8ab36789e1b57b035fb6c32a6358f51f83e4e5f46220bcad072943df8bd9541a61b7dae8f30fa3dd5fb39b1fd9a0b8e802552b78d4ec306ecee15bfe6da14b29ba6d19ce5be4dd478bca74a52429cd5309d404655c3dec85c252
# forwarding error packet
shared_secret = 21e13c2d7cfe7e18836df50872466117a295783ab8aab0e7ecc8c725503ad02d
ammag_key = cd9ac0e09064f039fa43a31dea05f5fe5f6443d40a98be4071af4a9d704be5ad
stream = 617ca1e4624bc3f04fece3aa5a2b615110f421ec62408d16c48ea6c1b7c33fe7084a2bd9d4652fc5068e5052bf6d0acae2176018a3d8c75f37842712913900263cff92f39f3c18aa1f4b20a93e70fc429af7b2b1967ca81a761d40582daf0eb49cef66e3d6fbca0218d3022d32e994b41c884a27c28685ef1eb14603ea80a204b2f2f474b6ad5e71c6389843e3611ebeafc62390b717ca53b3670a33c517ef28a659c251d648bf4c966a4ef187113ec9848bf110816061ca4f2f68e76ceb88bd6208376460b916fb2ddeb77a65e8f88b2e71a2cbf4ea4958041d71c17d05680c051c3676fb0dc8108e5d78fb1e2c44d79a202e9d14071d536371ad47c39a05159e8d6c41d17a1e858faaaf572623aa23a38ffc73a4114cb1ab1cd7f906c6bd4e21b29694f9830d12e8ad4b1ac320b3d5bfb4e534f02cefe9a983d66939581412acb1927eb93e8ed73145cddf24266bdcc95923ecb38c8c9c5f4465335b0f18bf9f2d03fa02d57f258db27983d94378bc796cbe7737180dd7e39a36e461ebcb7ec82b6dcdf9d3f209381f7b3a23e798c4f92e13b4bb972ee977e24f4b83bb59b577c210e1a612c2b035c8271d9bc1fb915776ac6560315b124465866830473aa238c35089cf2adb9c6e9f05ab113c1d0a4a18ba0cb9951b928c0358186532c36d4c3daa65657be141cc22e326f88e445e898893fd5f0a7dd231ee5bc972077b1e12a8e382b75d4b557e895a2adc757f2e451e33e0ae3fb54566ee09155da6ada818aa4a4a2546832a8ba22f0ef9ec6a1c78e03a7c29cb126bcaf81aea61cd8b07ab9f4e5e0ad0d9a3a0c66d2d0a00cc05884d183a68e816e76b75842d55895f5b91c5c1b9f7052763aae8a647aa0799214275b6e781f0816fc9ffb802a0101eb5a2de6b3375d3e3478f892b2de7f1900d8ca9bf188fcba89fc49d03c38fa2587a8ae119abfb295b15fa11cb188796bedc4fdfceef296e44fbfa7e84569cc6346389a421782e40a298e1e2b6f9cae3103c3f39d24541e4ab7b61dafe1a5f2fe936a59d87cccdaf7c226acc451ceec3e81bc4828b4925feeae3526d5e2bf93bd5f4fdc0e069010aea1ae7e0d480d438918598896b776bf08fea124f91b3a13414b56934857707902612fc97b0e5d02cbe6e5901ad304c7e8656390efccf3a1b22e18a2935181b78d5d2c89540ede8b0e6194d0d3945780bf577f622cb12deedbf8210eb1450c298b9ee19f3c7082aabc2bdbd3384f3539dc3766978567135549df0d48287735854a6098fa40a9e48eaa27e0d159beb65dd871e4c0b3fffa65f0375f0d3253f582193135ece60d5b9d8ba6739d87964e992cbec674b728d9eaaed595462c41d15fb497d4baa062368005d13fc99e1402563117a6c140c10363b05196a4cbb6b84ae807d62c748485c15e3316841e4a98c3aac81e3bc996b4baca77eac8cdbe99cc7c5ebeb85c907cefb4abe15cbe87fdc5dc2326019196235ac205934fcf8e3
error packet for node 3: 7512354d6a26781d25e65539772ba049b7ed7c530bf75ab7ef80cf974b978a07a1c3dabc61940011585323f70fa98cfa1d4c868da30b1f751e44a72d9b3f79809c8c51c9f0843daa8fe83587844fedeacb7348362003b31922cbb4d6169b2087b6f8d192d9cfe5363254cd1fde24641bde9e422f170c3eb146f194c48a459ae2889d706dc654235fa9dd20307ea54091d09970bf956c067a3bcc05af03c41e01af949a131533778bf6ee3b546caf2eabe9d53d0fb2e8cc952b7e0f5326a69ed2e58e088729a1d85971c6b2e129a5643f3ac43da031e655b27081f10543262cf9d72d6f64d5d96387ac0d43da3e3a03da0c309af121dcf3e99192efa754eab6960c256ffd4c546208e292e0ab9894e3605db098dc16b40f17c320aa4a0e42fc8b105c22f08c9bc6537182c24e32062c6cd6d7ec7062a0c2c2ecdae1588c82185cdc61d874ee916a7873ac54cddf929354f307e870011704a0e9fbc5c7802d6140134028aca0e78a7e2f3d9e5c7e49e20c3a56b624bfea51196ec9e88e4e56be38ff56031369f45f1e03be826d44a182f270c153ee0d9f8cf9f1f4132f33974e37c7887d5b857365c873cb218cbf20d4be3abdb2a2011b14add0a5672e01e5845421cf6dd6faca1f2f443757aae575c53ab797c2227ecdab03882bbbf4599318cefafa72fa0c9a0f5a51d13c9d0e5d25bfcfb0154ed25895260a9df8743ac188714a3f16960e6e2ff663c08bffda41743d50960ea2f28cda0bc3bd4a180e297b5b41c700b674cb31d99c7f2a1445e121e772984abff2bbe3f42d757ceeda3d03fb1ffe710aecabda21d738b1f4620e757e57b123dbc3c4aa5d9617dfa72f4a12d788ca596af14bea583f502f16fdc13a5e739afb0715424af2767049f6b9aa107f69c5da0e85f6d8c5e46507e14616d5d0b797c3dea8b74a1b12d4e47ba7f57f09d515f6c7314543f78b5e85329d50c5f96ee2f55bbe0df742b4003b24ccbd4598a64413ee4807dc7f2a9c0b92424e4ae1b418a3cdf02ea4da5c3b12139348aa7022cc8272a3a1714ee3e4ae111cffd1bdfd62c503c80bdf27b2feaea0d5ab8fe00f9cec66e570b00fd24b4a2ed9a5f6384f148a4d6325110a41ca5659ebc5b98721d298a52819b6fb150f273383f1c5754d320be428941922da790e17f482989c365c078f7f3ae100965e1b38c052041165295157e1a7c5b7a57671b842d4d85a7d971323ad1f45e17a16c4656d889fc75c12fc3d8033f598306196e29571e414281c5da19c12605f48347ad5b4648e371757cbe1c40adb93052af1d6110cfbf611af5c8fc682b7e2ade3bfca8b5c7717d19fc9f97964ba6025aebbc91a6671e259949dcf40984342118de1f6b514a7786bd4f6598ffbe1604cef476b2a4cb1343db608aca09d1d38fc23e98ee9c65e7f6023a8d1e61fd4f34f753454bd8e858c8ad6be6403edc599c220e03ca917db765980ac781e758179cd93983e9c1e769e4241d47c
attribution data for node 3: 1571e10db7f8aa9f8e7e99caaf9c892e106c817df1d8e3b7b0e39d1c48f631e473e17e205489dd7b3c634cac3be0825cbf01418cd46e83c24b8d9c207742db9a0f0e5bcd888086498159f08080ba7bf36dee297079eb841391ccd3096da76461e314863b6412efe0ffe228d51c6097db10d3edb2e50ea679820613bfe9db11ba02920ab4c1f2a79890d997f1fc022f3ab78f0029cc6de0c90be74d55f4a99bf77a50e20f8d076fe61776190a61d2f41c408871c0279309cba3b60fcdc7efc4a0e90b47cb4a418fc78f362ecc7f15ebbce9f854c09c7be300ebc1a40a69d4c7cb7a19779b6905e82bec221a709c1dab8cbdcde7b527aca3f54bde651aa9f3f2178829cee3f1c0b9292758a40cc63bd998fcd0d3ed4bdcaf1023267b8f8e44130a63ad15f76145936552381eabb6d684c0a3af6ba8efcf207cebaea5b7acdbb63f8e7221102409d10c23f0514dc9f4d0efb2264161a193a999a23e992632710580a0d320f676d367b9190721194514457761af05207cdab2b6328b1b3767eacb36a7ef4f7bd2e16762d13df188e0898b7410f62459458712a44bf594ae662fd89eb300abb6952ff8ad40164f2bcd7f86db5c7650b654b79046de55d51aa8061ce35f867a3e8f5bf98ad920be827101c64fb871d86e53a4b3c0455bfac5784168218aa72cbee86d9c750a9fa63c363a8b43d7bf4b2762516706a306f0aa3be1ec788b5e13f8b24837e53ac414f211e11c7a093cd9653dfa5fba4e377c79adfa5e841e2ddb6afc054fc715c05ddc6c8fc3e1ee3406e1ffceb2df77dc2f02652614d1bfcfaddebaa53ba919c7051034e2c7b7cfaabdf89f26e7f8e3f956d205dfab747ad0cb505b85b54a68439621b25832cbc2898919d0cd7c0a64cfd235388982dd4dd68240cb668f57e1d2619a656ed326f8c92357ee0d9acead3c20008bc5f04ca8059b55d77861c6d04dfc57cfba57315075acbe1451c96cf28e1e328e142890248d18f53b5d3513ce574dea7156cf596fdb3d909095ec287651f9cf1bcdc791c5938a5dd9b47e84c004d24ab3ae74492c7e8dcc1da15f65324be2672947ec82074cac8ce2b925bc555facbbf1b55d63ea6fbea6a785c97d4caf2e1dad9551b7f66c31caae5ebc7c0047e892f201308fcf452c588be0e63d89152113d87bf0dbd01603b4cdc7f0b724b0714a9851887a01f709408882e18230fe810b9fafa58a666654576d8eba3005f07221f55a6193815a672e5db56204053bc4286fa3db38250396309fd28011b5708a26a2d76c4a333b69b6bfd272fb
# forwarding error packet
shared_secret = 3a6b412548762f0dbccce5c7ae7bb8147d1caf9b5471c34120b30bc9c04891cc
ammag_key = 1bf08df8628d452141d56adfd1b25c1530d7921c23cecfc749ac03a9b694b0d3
stream = 6149f48b5a7e8f3d6f5d870b7a698e204cf64452aab4484ff1dee671fe63fd4b5f1b78ee2047dfa61e3d576b149bedaf83058f85f06a3172a3223ad6c4732d96b32955da7d2feb4140e58d86fc0f2eb5d9d1878e6f8a7f65ab9212030e8e915573ebbd7f35e1a430890be7e67c3fb4bbf2def662fa625421e7b411c29ebe81ec67b77355596b05cc155755664e59c16e21410aabe53e80404a615f44ebb31b365ca77a6e91241667b26c6cad24fb2324cf64e8b9dd6e2ce65f1f098cfd1ef41ba2d4c7def0ff165a0e7c84e7597c40e3dffe97d417c144545a0e38ee33ebaae12cc0c14650e453d46bfc48c0514f354773435ee89b7b2810606eb73262c77a1d67f3633705178d79a1078c3a01b5fadc9651feb63603d19decd3a00c1f69af2dab2595931ca50d8280758b1cc91ba2dc43dbbc3d91bf25c08b46c2ecef7a32cec64d4b61ee3a629ef563afe058b71e71bcb69033948bc8728c5ebe65ec596e4f305b9fc159d53f723dfc95b57f3d51717f1c89af97a6d587e89e62efcc92198a1b2bd66e2d875505ea4046c04389f8cb0ee98f0af03af2652e2f3d9a9c48430f2891a4d9b16e7d18099e4a3dd334c24aba1e2450792c2f22092c170da549d43a440021e699bd6c20d8bbf1961100a01ebcce06a4609f5ad93066287acf68294cfa9ea7cea03a508983b134a9f0118b16409a61c06aaa95897d2067cb7cd59123f3e2ccf0e16091571d616c44818f118bb7835a679f5c0eea8cf1bd5479882b2c2a341ec26dbe5da87b3d37d66b1fbd176f71ab203a3b6eaf7f214d579e7d0e4a3e59089ebd26ba04a62403ae7a793516ec16d971d51c5c0107a917d1a70221e6de16edca7cb057c7d06902b5191f298aa4d478a0c3a6260c257eae504ebbf2b591688e6f3f77af770b6f566ae9868d2f26c12574d3bf9323af59f0fe0072ff94ae597c2aa6fbcbf0831989e02f9d3d1b9fd6dd97f509185d9ecbf272e38bd621ee94b97af8e1cd43853a8f6aa6e8372585c71bf88246d064ade524e1e0bd8496b620c4c2d3ae06b6b064c97536aaf8d515046229f72bee8aa398cd0cc21afd5449595016bef4c77cb1e2e9d31fe1ca3ffde06515e6a4331ccc84edf702e5777b10fc844faf17601a4be3235931f6feca4582a8d247c1d6e4773f8fb6de320cf902bbb1767192782dc550d8e266e727a2aa2a414b816d1826ea46af71701537193c22bbcc0123d7ff5a23b0aa8d7967f36fef27b14fe1866ff3ab215eb29e07af49e19174887d71da7e7fe1b7aa1b3c805c063e0fafedf125fa6c57e38cce33a3f7bb35fd8a9f0950de3c22e49743c05f40bc55f960b8a8b5e2fde4bb229f125538438de418cb318d13968532499118cb7dcaaf8b6d635ac4001273bdafd12c8ea0702fb2f0dac81dbaaf68c1c32266382b293fa3951cb952ed5c1bdc41750cdbc0bd62c51bb685616874e251f031a929c06faef5bfcb0857f815ae20620b823f0abecfb5
error packet for node 2: 145bc1c63058f7204abbd2320d422e69fb1b3801a14312f81e5e29e6b5f4774cfed8a25241d3dfb7466e749c1b3261559e49090853612e07bd669dfb5f4c54162fa504138dabd6ebcf0db8017840c35f12a2cfb84f89cc7c8959a6d51815b1d2c5136cedec2e4106bb5f2af9a21bd0a02c40b44ded6e6a90a145850614fb1b0eef2a03389f3f2693bc8a755630fc81fff1d87a147052863a71ad5aebe8770537f333e07d841761ec448257f948540d8f26b1d5b66f86e073746106dfdbb86ac9475acf59d95ece037fba360670d924dce53aaa74262711e62a8fc9eb70cd8618fbedae22853d3053c7f10b1a6f75369d7f73c419baa7dbf9f1fc5895362dcc8b6bd60cca4943ef7143956c91992119bccbe1666a20b7de8a2ff30a46112b53a6bb79b763903ecbd1f1f74952fb1d8eb0950c504df31fe702679c23b463f82a921a2c931500ab08e686cffb2d87258d254fb17843959cccd265a57ba26c740f0f231bb76df932b50c12c10be90174b37d454a3f8b284c849e86578a6182c4a7b2e47dd57d44730a1be9fec4ad07287a397e28dce4fda57e9cdfdb2eb5afdf0d38ef19d982341d18d07a556bb16c1416f480a396f278373b8fd9897023a4ac506e65cf4c306377730f9c8ca63cf47565240b59c4861e52f1dab84d938e96fb31820064d534aca05fd3d2600834fe4caea98f2a748eb8f200af77bd9fbf46141952b9ddda66ef0ebea17ea1e7bb5bce65b6e71554c56dd0d4e14f4cf74c77a150776bf31e7419756c71e7421dc22efe9cf01de9e19fc8808d5b525431b944400db121a77994518d6025711cb25a18774068bba7faaa16d8f65c91bec8768848333156dcb4a08dfbbd9fef392da3e4de13d4d74e83a7d6e46cfe530ee7a6f711e2caf8ad5461ba8177b2ef0a518baf9058ff9156e6aa7b08d938bd8d1485a787809d7b4c8aed97be880708470cd2b2cdf8e2f13428cc4b04ef1f2acbc9562f3693b948d0aa94b0e6113cafa684f8e4a67dc431dfb835726874bef1de36f273f52ee694ec46b0700f77f8538067642a552968e866a72a3f2031ad116663ac17b172b446c5bc705b84777363a9a3fdc6443c07b2f4ef58858122168d4ebbaee920cefc312e1cea870ed6e15eec046ab2073bbf08b0a3366f55cfc6ad4681a12ab0946534e7b6f90ea8992d530ec3daa6b523b3cf03101c60cadd914f30dec932c1ef4341b5a8efac3c921e203574cfe0f1f83433fddb8ccfd273f7c3cab7bc27efe3bb61fdccd5146f1185364b9b621e7fb2b74b51f5ee6be72ab6ff46a6359dc2c855e61469724c1dbeb273df9d2e1c1fb74891239c0019dc12d5c7535f7238f963b761d7102b585372cf021b64c4fc85bfb3161e59d2e298bba44cfd34d6859d9dba9dc6271e5047d525468c814f2ae438474b0a977273036da1a2292f88fcfb89574a6bdca1185b40f8aa54026d5926725f99ef028da1be892e3586361efe15f4a148ff1bc9
attribution data for node 2: 34e34397b8621ec2f2b54dbe6c14073e267324cd60b152bce76aec8729a6ddefb61bc263be4b57bd592aae604a32bea69afe6ef4a6b573c26b17d69381ec1fc9b5aa769d148f2f1f8b5377a73840bb6dc641f68e356323d766fff0aaca5039fe7fc27038195844951a97d5a5b26698a4ca1e9cd4bca1fcca0aac5fee91b18977d2ad0e399ba159733fc98f6e96898ebc39bf0028c9c81619233bab6fad0328aa183a635fac20437fa6e00e899b2527c3697a8ab7342e42d55a679b176ab76671fcd480a9894cb897fa6af0a45b917a162bed6c491972403185df7235502f7ada65769d1bfb12d29f10e25b0d3cc08bbf6de8481ac5c04df32b4533b4f764c2aefb7333202645a629fb16e4a208e9045dc36830759c852b31dd613d8b2b10bbead1ed4eb60c85e8a4517deba5ab53e39867c83c26802beee2ee545bdd713208751added5fc0eb2bc89a5aa2decb18ee37dac39f22a33b60cc1a369d24de9f3d2d8b63c039e248806de4e36a47c7a0aed30edd30c3d62debdf1ad82bf7aedd7edec413850d91c261e12beec7ad1586a9ad25b2db62c58ca17119d61dcc4f3e5c4520c42a8e384a45d8659b338b3a08f9e123a1d3781f5fc97564ccff2c1d97f06fa0150cfa1e20eacabefb0c339ec109336d207cc63d9170752fc58314c43e6d4a528fd0975afa85f3aa186ff1b6b8cb12c97ed4ace295b0ef5f075f0217665b8bb180246b87982d10f43c9866b22878106f5214e99188781180478b07764a5e12876ddcb709e0a0a8dd42cf004c695c6fc1669a6fd0e4a1ca54b024d0d80eac492a9e5036501f36fb25b72a054189294955830e43c18e55668337c8c6733abb09fc2d4ade18d5a853a2b82f7b4d77151a64985004f1d9218f2945b63c56fdebd1e96a2a7e49fa70acb4c39873947b83c191c10e9a8f40f60f3ad5a2be47145c22ea59ed3f5f4e61cb069e875fb67142d281d784bf925cc286eacc2c43e94d08da4924b83e58dbf2e43fa625bdd620eba6d9ce960ff17d14ed1f2dbee7d08eceb540fdc75ff06dabc767267658fad8ce99e2a3236e46d2deedcb51c3c6f81589357edebac9772a70b3d910d83cd1b9ce6534a011e9fa557b891a23b5d88afcc0d9856c6dabeab25eea55e9a248182229e4927f268fe5431672fcce52f434ca3d27d1a2136bae5770bb36920df12fbc01d0e8165610efa04794f414c1417f1d4059435c5385bfe2de83ce0e238d6fd2dbd3c0487c69843298577bfa480fe2a16ab2a0e4bc712cd8b5a14871cda61c993b6835303d9043d7689a
# forwarding error packet
shared_secret = a6519e98832a0b179f62123b3567c106db99ee37bef036e783263602f3488fae
ammag_key = 59ee5867c5c151daa31e36ee42530f429c433836286e63744f2020b980302564
stream = 0f10c86f05968dd91188b998ee45dcddfbf89fe9a99aa6375c42ed5520a257e048456fe417c15219ce39d921555956ae2ff795177c63c819233f3bcb9b8b28e5ac6e33a3f9b87ca62dff43f4cc4a2755830a3b7e98c326b278e2bd31f4a9973ee99121c62873f5bfb2d159d3d48c5851e3b341f9f6634f51939188c3b9ff45feeb11160bb39ce3332168b8e744a92107db575ace7866e4b8f390f1edc4acd726ed106555900a0832575c3a7ad11bb1fe388ff32b99bcf2a0d0767a83cf293a220a983ad014d404bfa20022d8b369fe06f7ecc9c74751dcda0ff39d8bca74bf9956745ba4e5d299e0da8f68a9f660040beac03e795a046640cf8271307a8b64780b0588422f5a60ed7e36d60417562938b400802dac5f87f267204b6d5bcfd8a05b221ec294d883271b06ca709042ed5dbb64a7328d2796195eab4512994fb88919c73b3e5dd7bf68b2136d34cff39b3be266b71e004509bf975a240800bb8ae5eed248423a991ae80ef751b2d03b67fb93ffdd7969d5b500fe446a4ffb4cd04d0767a5d367ebd3f8f260f38ae1e9d9f9a7bd1a99ca1e10ee36bd241f06fc2b481c9b7450d9c9704204666807783264a0e93468e22db4dc4a7a4db2963ddf4366d08e225cf94848aac794bcecb7e850113e38cc3647a03a5dfaa3442b1bb58b1de7fa7f436feb4d7c23cbd2de6d55d4025fcd383cc9d49c0b130e2fd5a9097c216683c842f898a8a2159761cca9aa1c818194e3b7bea6da6652d5189f3b6b0ca1d5398b6d14e311d9c7f00399c29e94deb98496f4cd97c5d7d6a65cabc3791f60d728d6422a422c0cff5f7dfd4ce2d7e8d38dd71ae18763acc832c57275497f61b2620cca13cc64c0c48353f3817016f91448d6fc1cc451ee1f4a429e43292bbcd54fcd807e2c47675bac1781d9d81e9e6dc69028d428f5ee261750f626bcaf416a0e7badadf73fe1922207ae6c5209d16849e4a108f4a6f38694075f55177105ac4c2b97f6a474b94c03257d8d12b0196e2905d914b8c2213a1b9dc9608e1a2a1e03fe0820a813275de83be5e9734875787a9e006eb8574c23ddd49e2347d1ecfcedf3caa0a5dd45666368525b48ac14225d6422f82dbf59860ee4dc78e845d3c57668ce9b9e7a8d012491cef242078b458a956ad67c360fb6d8b86ab201d6217e49b55fa02a1dea2dbe88d0b08d30670d1b93c35cc5e41e088fccb267e41d6151cf8560496e1beeefe680744d9dabb383a4957466b4dc3e2bce7b135211da483d998a22fa687cc609641126c5dee3ed87291067916b5b065f40582163291d48e81ecd975d0d6fd52a31754f8ef15e43a560bd30ea5bf21915bd2e7007e607abbc6261edc8430cc7f789675b1fe83e807c5c475bd5178eba2fc40674706b0a68c6a428e5dec36e413e653c6db1178923ff87e2389a78bf9e93b713de4f4753f9f9d6a361369b609e1970c91ff9bd191c472e0bf2e8681412260ad0ef5855dc39f2084d45
error packet for node 1: 1b4b09a935ce7af95b336baae307f2b400e3a7e808d9b4cf421cc4b3955620acb69dcdb656128dae8857adbd4e6b37fbb1be9c1f2f02e61e9e59a630c4c77cf383cb37b07413aa4de2f2fbf5b40ae40a91a8f4c6d74aeacef1bb1be4ecbc26ec2c824d2bc45db4b9098e732a769788f1cff3f5b41b0d25c132d40dc5ad045ef0043b15332ca3c5a09de2cdb17455a0f82a8f20da08346282823dab062cdbd2111e238528141d69de13de6d83994fbc711e3e269df63a12d3a4177c5c149150eb4dc2f589cd8acabcddba14dec3b0dada12d663b36176cd3c257c5460bab93981ad99f58660efa9b31d7e63b39915329695b3fa60e0a3bdb93e7e29a54ca6a8f360d3848866198f9c3da3ba958e7730847fe1e6478ce8597848d3412b4ae48b06e05ba9a104e648f6eaf183226b5f63ed2e68f77f7e38711b393766a6fab7921b03eba82b5d7cb78e34dc961948d6161eadd7cf5d95d9c56df2ff5faa6ccf85eacdc9ff2fc3abafe41c365a5bd14fd486d6b5e2f24199319e7813e02e798877ffe31a70ae2398d9e31b9e3727e6c1a3c0d995c67d37bb6e72e9660aaaa9232670f382add2edd468927e3303b6142672546997fe105583e7c5a3c4c2b599731308b5416e6c9a3f3ba55b181ad0439d3535356108b059f2cb8742eed7a58d4eba9fe79eaa77c34b12aff1abdaea93197aabd0e74cb271269ca464b3b06aef1d6573df5e1224179616036b368677f26479376681b772d3760e871d99efd34cca5cd6beca95190d967da820b21e5bec60082ea46d776b0517488c84f26d12873912d1f68fafd67bcf4c298e43cfa754959780682a2db0f75f95f0598c0d04fd014c50e4beb86a9e37d95f2bba7e5065ae052dc306555bca203d104c44a538b438c9762de299e1c4ad30d5b4a6460a76484661fc907682af202cd69b9a4473813b2fdc1142f1403a49b7e69a650b7cde9ff133997dcc6d43f049ecac5fce097a21e2bce49c810346426585e3a5a18569b4cddd5ff6bdec66d0b69fcbc5ab3b137b34cc8aefb8b850a764df0e685c81c326611d901c392a519866e132bbb73234f6a358ba284fbafb21aa3605cacbaf9d0c901390a98b7a7dac9d4f0b405f7291c88b2ff45874241c90ac6c5fc895a440453c344d3a365cb929f9c91b9e39cb98b142444aae03a6ae8284c77eb04b0a163813d4c21883df3c0f398f47bf127b5525f222107a2d8fe55289f0cfd3f4bbad6c5387b0594ef8a966afc9e804ccaf75fe39f35c6446f7ee076d433f2f8a44dba1515acc78e589fa8c71b0a006fe14feebd51d0e0aa4e51110d16759eee86192eee90b34432130f387e0ccd2ee71023f1f641cddb571c690107e08f592039fe36d81336a421e89378f351e633932a2f5f697d25b620ffb8e84bb6478e9bd229bf3b164b48d754ae97bd23f319e3c56b3bcdaaeb3bd7fc02ec02066b324cb72a09b6b43dec1097f49d69d3c138ce6f1a6402898baf7568c
attribution data for node 1: 74a4ea61339463642a2182758871b2ea724f31f531aa98d80f1c3043febca41d5ee52e8b1e127e61719a0d078db8909748d57839e58424b91f063c4fbc8a221bef261140e66a9b596ca6d420a973ad54fef30646ae53ccf0855b61f291a81e0ec6dc0f6bf69f0ca0e5889b7e23f577ba67d2a7d6a2aa91264ab9b20630ed52f8ed56cc10a869807cd1a4c2cd802d8433fee5685d6a04edb0bff248a480b93b01904bed3bb31705d1ecb7332004290cc0cd9cc2f7907cf9db28eec02985301668f53fbc28c3e095c8f3a6cd8cab28e5e442fd9ba608b8b12e098731bbfda755393bd403c62289093b40390b2bae337fc87d2606ca028311d73a9ffbdffef56020c735ada30f54e577c6a9ec515ae2739290609503404b118d7494499ecf0457d75015bb60a16288a4959d74cf5ac5d8d6c113de39f748a418d2a7083b90c9c0a09a49149fd1f2d2cde4412e5aa2421eca6fd4f6fe6b2c362ff37d1a0608c931c7ca3b8fefcfd4c44ef9c38357a0767b14f83cb49bd1989fb3f8e2ab202ac98bd8439790764a40bf309ea2205c1632610956495720030a25dc7118e0c868fdfa78c3e9ecce58215579a0581b3bafdb7dbbe53be9e904567fdc0ce1236aab5d22f1ebc18997e3ea83d362d891e04c5785fd5238326f767bce499209f8db211a50e1402160486e98e7235cf397dbb9ae19fd9b79ef589c821c6f99f28be33452405a003b33f4540fe0a41dfcc286f4d7cc10b70552ba7850869abadcd4bb7f256823face853633d6e2a999ac9fcd259c71d08e266db5d744e1909a62c0db673745ad9585949d108ab96640d2bc27fb4acac7fa8b170a30055a5ede90e004df9a44bdc29aeb4a6bec1e85dde1de6aaf01c6a5d12405d0bec22f49026cb23264f8c04b8401d3c2ab6f2e109948b6193b3bec27adfe19fb8afb8a92364d6fc5b219e8737d583e7ff3a4bcb75d53edda3bf3f52896ac36d8a877ad9f296ea6c045603fc62ac4ae41272bde85ef7c3b3fd3538aacfd5b025fefbe277c2906821ecb20e6f75ea479fa3280f9100fb0089203455c56b6bc775e5c2f0f58c63edd63fa3eec0b40da4b276d0d41da2ec0ead865a98d12bc694e23d8eaadd2b4d0ee88e9570c88fb878930f492e036d27998d593e47763927ff7eb80b188864a3846dd2238f7f95f4090ed399ae95deaeb37abca1cf37c397cc12189affb42dca46b4ff6988eb8c060691d155302d448f50ff70a794d97c0408f8cee9385d6a71fa412e36edcb22dbf433db9db4779f27b682ee17fc05e70c8e794b9f7f6d1
# forwarding error packet
shared_secret = 53eb63ea8a3fec3b3cd433b85cd62a4b145e1dda09391b348c4e1cd36a03ea66
ammag_key = 3761ba4d3e726d8abb16cba5950ee976b84937b61b7ad09e741724d7dee12eb5
stream = 3699fd352a948a05f604763c0bca2968d5eaca2b0118602e52e59121f050936c8dd90c24df7dc8cf8f1665e39a6c75e9e2c0900ea245c9ed3b0008148e0ae18bbfaea0c711d67eade980c6f5452e91a06b070bbde68b5494a92575c114660fb53cf04bf686e67ffa4a0f5ae41a59a39a8515cb686db553d25e71e7a97cc2febcac55df2711b6209c502b2f8827b13d3ad2f491c45a0cafe7b4d8d8810e805dee25d676ce92e0619b9c206f922132d806138713a8f69589c18c3fdc5acee41c1234b17ecab96b8c56a46787bba2c062468a13919afc18513835b472a79b2c35f9a91f38eb3b9e998b1000cc4a0dbd62ac1a5cc8102e373526d7e8f3c3a1b4bfb2f8a3947fe350cb89f73aa1bb054edfa9895c0fc971c2b5056dc8665902b51fced6dff80c4d247db977c15a710ce280fbd0ae3ca2a245b1c967aeb5a1a4a441c50bc9ceb33ca64b5ca93bd8b50060520f35a54a148a4112e8762f9d0b0f78a7f46a5f06c7a4b0845d020eb505c9e527aabab71009289a6919520d32af1f9f51ce4b3655c6f1aae1e26a16dc9aae55e9d4a6f91d4ba76e96fcb851161da3fc39d0d97ce30a5855c75ac2f613ff36a24801bcbd33f0ce4a3572b9a2fca21efb3b07897fc07ee71e8b1c0c6f8dbb7d2c4ed13f11249414fc94047d1a4a0be94d45db56af4c1a3bf39c9c5aa18209eaebb9e025f670d4c8cc1ee598c912db154eaa3d0c93cb3957e126c50486bf98c852ad326b5f80a19df6b2791f3d65b8586474f4c5dcb2aca0911d2257d1bb6a1e9fc1435be879e75d23290f9feb93ed40baaeca1c399fc91fb1da3e5f0f5d63e543a8d12fe6f7e654026d3a118ab58cb14bef9328d4af254215eb1f639828cc6405a3ab02d90bb70a798787a52c29b3a28fc67b0908563a65f08112abd4e9115cb01db09460c602aba3ddc375569dc3abe42c61c5ea7feb39ad8b05d8e2718e68806c0e1c34b0bc85492f985f8b3e76197a50d63982b780187078f5c59ebd814afaeffc7b2c6ee39d4f9c8c45fb5f685756c563f4b9d028fe7981b70752f5a31e44ba051ab40f3604c8596f1e95dc9b0911e7ede63d69b5eecd245fbecbcf233cf6eba842c0fec795a5adeab2100b1a1bc62c15046d48ec5709da4af64f59a2e552ddbbdcda1f543bb4b687e79f2253ff0cd9ba4e6bfae8e510e5147273d288fd4336dbd0b6617bf0ef71c0b4f1f9c1dc999c17ad32fe196b1e2b27baf4d59bba8e5193a9595bd786be00c32bae89c5dbed1e994fddffbec49d0e2d270bcc1068850e5d7e7652e274909b3cf5e3bc6bf64def0bbeac974a76d835e9a10bdd7896f27833232d907b7405260e3c986569bb8fdd65a55b020b91149f27bda9e63b4c2cc5370bcc81ef044a68c40c1b178e4265440334cc40f59ab5f82a022532805bfa659257c8d8ab9b4aef6abbd05de284c2eb165ef35737e3d387988c566f7b1ca0b1fc3e7b4ed991b77f23775e1c36a09a991384a33b78
error packet for node 0: 2dd2f49c1f5af0fcad371d96e8cddbdcd5096dc309c1d4e110f955926506b3c03b44c192896f45610741c85ed4074212537e0c118d472ff3a559ae244acd9d783c65977765c5d4e00b723d00f12475aafaafff7b31c1be5a589e6e25f8da2959107206dd42bbcb43438129ce6cce2b6b4ae63edc76b876136ca5ea6cd1c6a04ca86eca143d15e53ccdc9e23953e49dc2f87bb11e5238cd6536e57387225b8fff3bf5f3e686fd08458ffe0211b87d64770db9353500af9b122828a006da754cf979738b4374e146ea79dd93656170b89c98c5f2299d6e9c0410c826c721950c780486cd6d5b7130380d7eaff994a8503a8fef3270ce94889fe996da66ed121741987010f785494415ca991b2e8b39ef2df6bde98efd2aec7d251b2772485194c8368451ad49c2354f9d30d95367bde316fec6cbdddc7dc0d25e99d3075e13d3de0822669861dafcd29de74eac48b64411987285491f98d78584d0c2a163b7221ea796f9e8671b2bb91e38ef5e18aaf32c6c02f2fb690358872a1ed28166172631a82c2568d23238017188ebbd48944a147f6cdb3690d5f88e51371cb70adf1fa02afe4ed8b581afc8bcc5104922843a55d52acde09bc9d2b71a663e178788280f3c3eae127d21b0b95777976b3eb17be40a702c244d0e5f833ff49dae6403ff44b131e66df8b88e33ab0a58e379f2c34bf5113c66b9ea8241fc7aa2b1fa53cf4ed3cdd91d407730c66fb039ef3a36d4050dde37d34e80bcfe02a48a6b14ae28227b1627b5ad07608a7763a531f2ffc96dff850e8c583461831b19feffc783bc1beab6301f647e9617d14c92c4b1d63f5147ccda56a35df8ca4806b8884c4aa3c3cc6a174fdc2232404822569c01aba686c1df5eecc059ba97e9688c8b16b70f0d24eacfdba15db1c71f72af1b2af85bd168f0b0800483f115eeccd9b02adf03bdd4a88eab03e43ce342877af2b61f9d3d85497cd1c6b96674f3d4f07f635bb26add1e36835e321d70263b1c04234e222124dad30ffb9f2a138e3ef453442df1af7e566890aedee568093aa922dd62db188aa8361c55503f8e2c2e6ba93de744b55c15260f15ec8e69bb01048ca1fa7bbbd26975bde80930a5b95054688a0ea73af0353cc84b997626a987cc06a517e18f91e02908829d4f4efc011b9867bd9bfe04c5f94e4b9261d30cc39982eb7b250f12aee2a4cce0484ff34eebba89bc6e35bd48d3968e4ca2d77527212017e202141900152f2fd8af0ac3aa456aae13276a13b9b9492a9a636e18244654b3245f07b20eb76b8e1cea8c55e5427f08a63a16b0a633af67c8e48ef8e53519041c9138176eb14b8782c6c2ee76146b8490b97978ee73cd0104e12f483be5a4af414404618e9f6633c55dda6f22252cb793d3d16fae4f0e1431434e7acc8fa2c009d4f6e345ade172313d558a4e61b4377e31b8ed4e28f7cd13a7fe3f72a409bc3bdabfe0ba47a6d861e21f64d2fac706dab18b3e546df4
attribution data for node 0: 84986c936d26bfd3bb2d34d3ec62cfdb63e0032fdb3d9d75f3e5d456f73dffa7e35aab1db4f1bd3b98ff585caf004f656c51037a3f4e810d275f3f6aea0c8e3a125ebee5f374b6440bcb9bb2955ebf706f42be9999a62ed49c7a81fc73c0b4a16419fd6d334532f40bf179dd19afec21bd8519d5e6ebc3802501ef373bc378eee1f14a6fc5fab5b697c91ce31d5922199d1b0ad5ee12176aacafc7c81d54bc5b8fb7e63f3bfd40a3b6e21f985340cbd1c124c7f85f0369d1aa86ebc66def417107a7861131c8bcd73e8946f4fb54bfac87a2dc15bd7af642f32ae583646141e8875ef81ec9083d7e32d5f135131eab7a43803360434100ff67087762bbe3d6afe2034f5746b8c50e0c3c20dd62a4c174c38b1df7365dccebc7f24f19406649fbf48981448abe5c858bbd4bef6eb983ae7a23e9309fb33b5e7c0522554e88ca04b1d65fc190947dead8c0ccd32932976537d869b5ca53ed4945bccafab2a014ea4cbdc6b0250b25be66ba0afff2ff19c0058c68344fd1b9c472567147525b13b1bc27563e61310110935cf89fda0e34d0575e2389d57bdf2869398ca2965f64a6f04e1d1c2edf2082b97054264a47824dd1a9691c27902b39d57ae4a94dd6481954a9bd1b5cff4ab29ca221fa2bf9b28a362c9661206f896fc7cec563fb80aa5eaccb26c09fa4ef7a981e63028a9c4dac12f82ccb5bea090d56bbb1a4c431e315d9a169299224a8dbd099fb67ea61dfc604edf8a18ee742550b636836bb552dabb28820221bf8546331f32b0c143c1c89310c4fa2e1e0e895ce1a1eb0f43278fdb528131a3e32bfffe0c6de9006418f5309cba773ca38b6ad8507cc59445ccc0257506ebc16a4c01d4cd97e03fcf7a2049fea0db28447858f73b8e9fe98b391b136c9dc510288630a1f0af93b26a8891b857bfe4b818af99a1e011e6dbaa53982d29cf74ae7dffef45545279f19931708ed3eede5e82280eab908e8eb80abff3f1f023ab66869297b40da8496861dc455ac3abe1efa8a6f9e2c4eda48025d43a486a3f26f269743eaa30d6f0e1f48db6287751358a41f5b07aee0f098862e3493731fe2697acce734f004907c6f11eef189424fee52cd30ad708707eaf2e441f52bcf3d0c5440c1742458653c0c8a27b5ade784d9e09c8b47f1671901a29360e7e5e94946b9c75752a1a8d599d2a3e14ac81b84d42115cd688c8383a64fc6e7e1dc5568bb4837358ebe63207a4067af66b2027ad2ce8fb7ae3a452d40723a51fdf9f9c9913e8029a222cf81d12ad41e58860d75deb6de30ad
Returning success
A successful payment without a fulfillment_payload
using the parameters above would result in the following
attribution data values:
attribution data for node 4: d77d0711b5f71d1d1be56bd88b3bb7ebc1792bb739ea7ebc1bc3b031b8bc2df3a50e25aeb99f47d7f7ab39e24187d3f4df9c4333463b053832ee9ac07274a5261b8b2a01fc09ce9ea7cd04d7b585dfb83299fb6570d71f793c1fcac0ef498766952c8c6840efa02a567d558a3cf6822b12476324b9b9efa03e5f8f26f81fa93daac46cbf00c98e69b6747cf69caaa2a71b025bd18830c4c54cd08f598cfde6197b3f2a951aba907c964c0f5d19a44e6d1d7279637321fa598adde927b3087d238f8b426ecde500d318617cdb7a56e6ce3520fc95be41a549973764e4dc483853ecc313947709f1b5199cb077d46e701fa633e11d3e13b03e9212c115ca6fa004b2f3dd912814693b705a561a06da54cdf603677a3abecdc22c7358c2de3cef771b366a568150aeecc86ad1990bb0f4e2865933b03ea0df87901bff467908273dc6cea31cbab0e2b8d398d10b001058c259ed221b7b55762f4c7e49c8c11a45a107b7a2c605c26dc5b0b10d719b1c844670102b2b6a36c43fe4753a78a483fc39166ae28420f112d50c10ee64ca69569a2f690712905236b7c2cb7ac8954f02922d2d918c56d42649261593c47b14b324a65038c3c5be8d3c403ce0c8f19299b1664bf077d7cf1636c4fb9685a8e58b7029fd0939fa07925a60bed339b23f973293598f595e75c8f9d455d7cebe4b5e23357c8bd47d66d6628b39427e37e0aecbabf46c11be6771f7136e108a143ae9bafba0fc47a51b6c7deef4cba54bae906398ee3162a41f2191ca386b628bde7e1dd63d1611aa01a95c456df337c763cb8c3a81a6013aa633739d8cd554c688102211725e6adad165adc1bcd429d020c51b4b25d2117e8bb27eb0cc7020f9070d4ad19ac31a76ebdf5f9246646aeadbfb9a3f1d75bd8237961e786302516a1a781780e8b73f58dc06f307e58bd0eb1d8f5c9111f01312974c1dc777a6a2d3834d8a2a40014e9818d0685cb3919f6b3b788ddc640b0ff9b1854d7098c7dd6f35196e902b26709640bc87935a3914869a807e8339281e9cedaaca99474c3e7bdd35050bb998ab4546f9900904e0e39135e861ff7862049269701081ebce32e4cca992c6967ff0fd239e38233eaf614af31e186635e9439ec5884d798f9174da6ff569d68ed5c092b78bd3f880f5e88a7a8ab36789e1b57b035fb6c32a6358f51f83e4e5f46220bcad072943df8bd9541a61b7dae8f30fa3dd5fb39b1fd9a0b8e802552b78d4ec306ecee15bfe6da14b29ba6d19ce5be4dd478bca74a52429cd5309d404655c3dec85c252
attribution data for node 3: 1571e10db7f8aa9f8e7e99caaf9c892e106c817df1d8e3b7b0e39d1c48f631e473e17e205489dd7b3c634cac3be0825cbf01418cd46e83c24b8d9c207742db9a0f0e5bcd888086498159f08080ba7bf3ea029c0b493227c4e75a90f70340d9e21f00979fc7e4fb2078477c1a457ba242ed54b313e590b13a2a13bfeed753dab133c78059f460075b2594b4c31c50f31076f8f1a0f7ad0530d0fadaf2d86e505ff9755940ec0665f9e5bc58cad6e523091f94d0bcd3c6c65ca1a5d401128dcc5e14f9108b32e660017c13de598bcf9d403710857cccb0fb9c2a81bfd66bc4552e1132afa3119203a4aaa1e8839c1dab8cbdcde7b527aca3f54bde651aa9f3f2178829cee3f1c0b9292758a40cc63bd998fcd0d3ed4bdcaf1023267b8f8e44130a63ad15f76145936552381eabb6d684c0a3af6ba8efcf207cebaea5b7acdbb63f8e7221102409d10c23f0514dc9f4d0efb2264161a193a999a23e992632710580a0d320f676d367b9190721194514457761af05207cdab2b6328b1b3767eacb36a7ef4f7bd2e16762d13df188e0898b7410f62459458712a44bf594ae662fd89eb300abb6952ff8ad40164f2bcd7f86db5c7650b654b79046de55d51aa8061ce35f867a3e8f5bf98ad920be827101c64fb871d86e53a4b3c0455bfac5784168218aa72cbee86d9c750a9fa63c363a8b43d7bf4b2762516706a306f0aa3be1ec788b5e13f8b24837e53ac414f211e11c7a093cd9653dfa5fba4e377c79adfa5e841e2ddb6afc054fc715c05ddc6c8fc3e1ee3406e1ffceb2df77dc2f02652614d1bfcfaddebaa53ba919c7051034e2c7b7cfaabdf89f26e7f8e3f956d205dfab747ad0cb505b85b54a68439621b25832cbc2898919d0cd7c0a64cfd235388982dd4dd68240cb668f57e1d2619a656ed326f8c92357ee0d9acead3c20008bc5f04ca8059b55d77861c6d04dfc57cfba57315075acbe1451c96cf28e1e328e142890248d18f53b5d3513ce574dea7156cf596fdb3d909095ec287651f9cf1bcdc791c5938a5dd9b47e84c004d24ab3ae74492c7e8dcc1da15f65324be2672947ec82074cac8ce2b925bc555facbbf1b55d63ea6fbea6a785c97d4caf2e1dad9551b7f66c31caae5ebc7c0047e892f201308fcf452c588be0e63d89152113d87bf0dbd01603b4cdc7f0b724b0714a9851887a01f709408882e18230fe810b9fafa58a666654576d8eba3005f07221f55a6193815a672e5db56204053bc4286fa3db38250396309fd28011b5708a26a2d76c4a333b69b6bfd272fb
attribution data for node 2: 34e34397b8621ec2f2b54dbe6c14073e267324cd60b152bce76aec8729a6ddefb61bc263be4b57bd592aae604a32bea69afe6ef4a6b573c26b17d69381ec1fc9b5aa769d148f2f1f8b5377a73840bb6dffc324ded0d1c00dc0c99e3dbc13273b2f89510af6410b525dd8836208abbbaae12753ae2276fa0ca49950374f94e187bf65cefcdd9dd9142074edc4bd0052d0eb027cb1ab6182497f9a10f9fe800b3228e3c088dab60081c807b30a67313667ca8c9e77b38b161a037cae8e973038d0fc4a97ea215914c6c4e23baf6ac4f0fb1e7fcc8aac3f6303658dae1f91588b535eb678e2200f45383c2590a55dc181a09f2209da72f79ae6745992c803310d39f960e8ecf327aed706e4b3e2704eeb9b304dc0e0685f5dcd0389ec377bdba37610ad556a0e957a413a56339dd3c40817214bced5802beee2ee545bdd713208751added5fc0eb2bc89a5aa2decb18ee37dac39f22a33b60cc1a369d24de9f3d2d8b63c039e248806de4e36a47c7a0aed30edd30c3d62debdf1ad82bf7aedd7edec413850d91c261e12beec7ad1586a9ad25b2db62c58ca17119d61dcc4f3e5c4520c42a8e384a45d8659b338b3a08f9e123a1d3781f5fc97564ccff2c1d97f06fa0150cfa1e20eacabefb0c339ec109336d207cc63d9170752fc58314c43e6d4a528fd0975afa85f3aa186ff1b6b8cb12c97ed4ace295b0ef5f075f0217665b8bb180246b87982d10f43c9866b22878106f5214e99188781180478b07764a5e12876ddcb709e0a0a8dd42cf004c695c6fc1669a6fd0e4a1ca54b024d0d80eac492a9e5036501f36fb25b72a054189294955830e43c18e55668337c8c6733abb09fc2d4ade18d5a853a2b82f7b4d77151a64985004f1d9218f2945b63c56fdebd1e96a2a7e49fa70acb4c39873947b83c191c10e9a8f40f60f3ad5a2be47145c22ea59ed3f5f4e61cb069e875fb67142d281d784bf925cc286eacc2c43e94d08da4924b83e58dbf2e43fa625bdd620eba6d9ce960ff17d14ed1f2dbee7d08eceb540fdc75ff06dabc767267658fad8ce99e2a3236e46d2deedcb51c3c6f81589357edebac9772a70b3d910d83cd1b9ce6534a011e9fa557b891a23b5d88afcc0d9856c6dabeab25eea55e9a248182229e4927f268fe5431672fcce52f434ca3d27d1a2136bae5770bb36920df12fbc01d0e8165610efa04794f414c1417f1d4059435c5385bfe2de83ce0e238d6fd2dbd3c0487c69843298577bfa480fe2a16ab2a0e4bc712cd8b5a14871cda61c993b6835303d9043d7689a
attribution data for node 1: 74a4ea61339463642a2182758871b2ea724f31f531aa98d80f1c3043febca41d5ee52e8b1e127e61719a0d078db8909748d57839e58424b91f063c4fbc8a221bef261140e66a9b596ca6d420a973ad5431adfa8280a7355462fe50d4cac15cdfbd7a535c4b72a0b6d7d8a64cff3f719ff9b8be28036826342dc3bf3781efc70063d1e6fc79dff86334ae0564a5ab87bd61f8446465ef6713f8c4ef9d0200ebb375f90ee115216b469af42de554622df222858d30d733af1c9223e327ae09d9126be8baee6dd59a112d83a57cc6e0252104c11bc11705d384220eedd72f1a29a0597d97967e28b2ad13ba28b3d8a53c3613c1bb49fe9700739969ef1f795034ef9e2e983af2d3bbd6c637fb12f2f7dfc3aee85e08711e9b604106e95d7a4974e5b047674a6015792dae5d913681d84f71edd415910582e5d86590df2ecfd561dc6e1cdb08d3e10901312326a45fb0498a177319389809c6ba07a76cfad621e07b9af097730e94df92fbd311b2cb5da32c80ab5f14971b6d40f8e2ab202ac98bd8439790764a40bf309ea2205c1632610956495720030a25dc7118e0c868fdfa78c3e9ecce58215579a0581b3bafdb7dbbe53be9e904567fdc0ce1236aab5d22f1ebc18997e3ea83d362d891e04c5785fd5238326f767bce499209f8db211a50e1402160486e98e7235cf397dbb9ae19fd9b79ef589c821c6f99f28be33452405a003b33f4540fe0a41dfcc286f4d7cc10b70552ba7850869abadcd4bb7f256823face853633d6e2a999ac9fcd259c71d08e266db5d744e1909a62c0db673745ad9585949d108ab96640d2bc27fb4acac7fa8b170a30055a5ede90e004df9a44bdc29aeb4a6bec1e85dde1de6aaf01c6a5d12405d0bec22f49026cb23264f8c04b8401d3c2ab6f2e109948b6193b3bec27adfe19fb8afb8a92364d6fc5b219e8737d583e7ff3a4bcb75d53edda3bf3f52896ac36d8a877ad9f296ea6c045603fc62ac4ae41272bde85ef7c3b3fd3538aacfd5b025fefbe277c2906821ecb20e6f75ea479fa3280f9100fb0089203455c56b6bc775e5c2f0f58c63edd63fa3eec0b40da4b276d0d41da2ec0ead865a98d12bc694e23d8eaadd2b4d0ee88e9570c88fb878930f492e036d27998d593e47763927ff7eb80b188864a3846dd2238f7f95f4090ed399ae95deaeb37abca1cf37c397cc12189affb42dca46b4ff6988eb8c060691d155302d448f50ff70a794d97c0408f8cee9385d6a71fa412e36edcb22dbf433db9db4779f27b682ee17fc05e70c8e794b9f7f6d1
attribution data for node 0: 84986c936d26bfd3bb2d34d3ec62cfdb63e0032fdb3d9d75f3e5d456f73dffa7e35aab1db4f1bd3b98ff585caf004f656c51037a3f4e810d275f3f6aea0c8e3a125ebee5f374b6440bcb9bb2955ebf70c06d64090f9f6cf098200305f7f4305ba9e1350a0c3f7dab4ccf35b8399b9650d8e363bf83d3a0a09706433f0adae6562eb338b21ea6f21329b3775905e59187c325c9cbf589f5da5e915d9e5ad1d21aa1431f9bdc587185ed8b5d4928e697e67cc96bee6d5354e3764cede3f385588fa665310356b2b1e68f8bd30c75d395405614a40a587031ebd6ace60dfb7c6dd188b572bd8e3e9a47b06c2187b528c5ed35c32da5130a21cd881138a5fcac806858ce6c596d810a7492eb261bcc91cead1dae75075b950c2e81cecf7e5fdb2b51df005d285803201ce914dfbf3218383829a0caa8f15486dd801133f1ed7edec436730b0ec98f48732547927229ac80269fcdc5e4f4db264274e940178732b429f9f0e582c559f994a7cdfb76c93ffc39de91ff936316726cc561a6520d47b2cd487299a96322dadc463ef06127fc63902ff9cc4f265e2fbd9de3fa5e48b7b51aa0850580ef9f3b5ebb60c6c3216c5a75a93e82936113d9cad57ae4a94dd6481954a9bd1b5cff4ab29ca221fa2bf9b28a362c9661206f896fc7cec563fb80aa5eaccb26c09fa4ef7a981e63028a9c4dac12f82ccb5bea090d56bbb1a4c431e315d9a169299224a8dbd099fb67ea61dfc604edf8a18ee742550b636836bb552dabb28820221bf8546331f32b0c143c1c89310c4fa2e1e0e895ce1a1eb0f43278fdb528131a3e32bfffe0c6de9006418f5309cba773ca38b6ad8507cc59445ccc0257506ebc16a4c01d4cd97e03fcf7a2049fea0db28447858f73b8e9fe98b391b136c9dc510288630a1f0af93b26a8891b857bfe4b818af99a1e011e6dbaa53982d29cf74ae7dffef45545279f19931708ed3eede5e82280eab908e8eb80abff3f1f023ab66869297b40da8496861dc455ac3abe1efa8a6f9e2c4eda48025d43a486a3f26f269743eaa30d6f0e1f48db6287751358a41f5b07aee0f098862e3493731fe2697acce734f004907c6f11eef189424fee52cd30ad708707eaf2e441f52bcf3d0c5440c1742458653c0c8a27b5ade784d9e09c8b47f1671901a29360e7e5e94946b9c75752a1a8d599d2a3e14ac81b84d42115cd688c8383a64fc6e7e1dc5568bb4837358ebe63207a4067af66b2027ad2ce8fb7ae3a452d40723a51fdf9f9c9913e8029a222cf81d12ad41e58860d75deb6de30ad
A successful payment with a fulfillment_payload
using the same route parameters contains the following
fulfillment_payload_tlvs records:
type = 1 (`padding`)
value = 245 zero bytes
type = 65537
value = 070809
These two records serialize to 256 bytes: 247 bytes for the
padding record and 9 bytes for the type
65537 record. With the 16-byte Poly1305 tag, this
results in a 272-byte fulfillment_payload.
The following are the fulfillment_payload and
attribution data values at each hop:
fulfillment payload for node 4: b5b1fed711469adc0da510494818ce54624b537e7a8aba4b190403d90439798a694bdca0d0d53c18487d9940664a8416eb855290621e186081b2222e279bfa6dcb1645a39c2cbc569ed66f8f9ed0c10d4dcbc61abe6685d558d5fb0ec104bf1d14ab1e42a4cf41f1950c3fd06574a8278f553382a78b2725f36559d6db7aeccd41569f88b3722c3535358915648bd2e82c53cbaaa14c34487a77799cc4650d5c2e2edece013cf4095ee99bc96e1a850fa3373538448bd6d5a1771f50ca39b2a4e85c7201be5bedd5fae801e5e99491e6fb1e76457c48094f347205d1170df06e2fa7128d0dfe7d24716fb621632b948f9ad9edba24fba9293906e193a7ca3c234cce42ca9470c08952be1dbd3dcc8452 attribution data for node 4: d77d0711b5f71d1d1be56bd88b3bb7ebc1792bb739ea7ebc1bc3b031b8bc2df3a50e25aeb99f47d7f7ab39e24187d3f4df9c4333463b053832ee9ac07274a5261b8b2a01fc09ce9ea7cd04d7b585dfb83299fb6570d71f793c1fcac0ef498766952c8c6840efa02a567d558a3cf6822b12476324b9b9efa03e5f8f26f81fa93daac46cbf00c98e69b6747cf69caaa2a71b025bd18830c4c54cd08f598cfde6197b3f2a951aba907c964c0f5d19a44e6d1d7279637321fa598adde927b3087d238f8b426ecde500d318617cdb7a56e6ce3520fc95be41a549973764e4dc483853ecc313947709f1b5199cb077d46e701fa633e11d3e13b03e9212c115ca6fa004b2f3dd912814693b705a561a06da54cdf603677a3abecdc22c7358c2de3cef771b366a568150aeecc86ad1990bb0f4e2865933b03ea0df87901bff467908273dc6cea31cbab0e2b8d398d10b001058c259ed221b7b55762f4c7e49c8c11a45a107b7a2c605c26dc5b0b10d719b1c844670102b2b6a36c43fe4753a78a483fc39166ae28420f112d50c10ee64ca69569a2f690712905236b7c2cb7ac8954f02922d2d918c56d42649261593c47b14b324a65038c3c5be8d3c403ce0c8f19299b1664bf077d7cf1636c4fb9685a8e58b7029fd0939fa07925a60bed339b23f973293598f595e75c8f9d455d7cebe4b5e23357c8bd47d66d6628b39427e37e0aecbabf46c11be6771f7136e108a143ae9bafba0fc47a51b6c7deef4cba54bae906398ee3162a41f2191ca386b628bde7e1dd63d1611aa01a95c456df337c763cb8c3a81a6013aa633739d8cd554c688102211725e6adad165adc1bcd429d020c51b4b25d2117e8bb27eb0cc7020f9070d4ad19ac31a76ebdf5f9246646aeadbfb9a3f1d75bd8237961e786302516a1a781780e8b73f58dc06f307e58bd0eb1d8f5c9111f01312974c1dc777a6a2d3834d8a2a40014e9818d0685cb3919f6b3b788ddc640b0ff9b1854d7098c7dd6f35196e902b26709640bc87935a3914869a807e8339281e9cedaaca99474c3e7bdd35050bb998ab4546f9900904e0e39135e861ff7862049269701081ebce32e4cca992c6967ff0fd239e38233eaf614af31e186635e9439ec5884d798f9174da6ff569d68ed5c092b78bd3f880f5e88a7a8ab36789e1b57b035fb6c32a6358f51f83e4e5f46220bcad072943df8bd9541a61b7dae8f30fa3dd5fb39b1fd9a0b8e802552b78d4ec306ecee15bfe6da14b29ba6d19ce5be4dd478bca74a52429cd5309d404655c3dec85c252
fulfillment payload for node 3: d4cd5f33730d592c4249f3e31233af0572bf729218ca375ddd8aa518b3fa466d6101f77904b013dd4ef3c912d9278edc09923288c1c6df3fb636053cb6a2fa4bf7e9d7500310a4fc819d4f26a0a03d4fd73c74ab281a2dcf2ec8bb56ecabb1a9884478a172348bf38ddf3dfd579d3c9393dd79a5650da2caedd41fd531fa4ec9f3a46bfc05df7244f30d115687eacc568395e83a165bfe1bc91073af0172e27488771c9fd7744b45c883d538e90bbbc627bcc428c5ebb71fee5877b7a6d23a198a544565dee2fb2ed736b69f8c7c696dd56fd48e88a24017306f74106a0898622abb24fbf6f3b534ff32ceda7d07d05800f9c32730fcb47a5a774cd464503936d2432e8b450ade0cdd14b2ea1bef2e71 attribution data for node 3: 1571e10db7f8aa9f8e7e99caaf9c892e106c817df1d8e3b7b0e39d1c48f631e473e17e205489dd7b3c634cac3be0825cbf01418cd46e83c24b8d9c207742db9a0f0e5bcd888086498159f08080ba7bf3bc5cfe92707ca5d3bc81720c889a034b89cf2d376a67c5d63651e3af267efb768a38f488eac2940cf5525e959599984c3cf56c1daaa92476de574582eba16f90b9a6a74f4aa5f1cdad2115c994a09565f9755940ec0665f9e5bc58cad6e523091f94d0bcd3c6c65ca1a5d401128dcc5e14f9108b32e660017c13de598bcf9d403710857cccb0fb9c2a81bfd66bc4552e1132afa3119203a4aaa1e8839c1dab8cbdcde7b527aca3f54bde651aa9f3f2178829cee3f1c0b9292758a40cc63bd998fcd0d3ed4bdcaf1023267b8f8e44130a63ad15f76145936552381eabb6d684c0a3af6ba8efcf207cebaea5b7acdbb63f8e7221102409d10c23f0514dc9f4d0efb2264161a193a999a23e992632710580a0d320f676d367b9190721194514457761af05207cdab2b6328b1b3767eacb36a7ef4f7bd2e16762d13df188e0898b7410f62459458712a44bf594ae662fd89eb300abb6952ff8ad40164f2bcd7f86db5c7650b654b79046de55d51aa8061ce35f867a3e8f5bf98ad920be827101c64fb871d86e53a4b3c0455bfac5784168218aa72cbee86d9c750a9fa63c363a8b43d7bf4b2762516706a306f0aa3be1ec788b5e13f8b24837e53ac414f211e11c7a093cd9653dfa5fba4e377c79adfa5e841e2ddb6afc054fc715c05ddc6c8fc3e1ee3406e1ffceb2df77dc2f02652614d1bfcfaddebaa53ba919c7051034e2c7b7cfaabdf89f26e7f8e3f956d205dfab747ad0cb505b85b54a68439621b25832cbc2898919d0cd7c0a64cfd235388982dd4dd68240cb668f57e1d2619a656ed326f8c92357ee0d9acead3c20008bc5f04ca8059b55d77861c6d04dfc57cfba57315075acbe1451c96cf28e1e328e142890248d18f53b5d3513ce574dea7156cf596fdb3d909095ec287651f9cf1bcdc791c5938a5dd9b47e84c004d24ab3ae74492c7e8dcc1da15f65324be2672947ec82074cac8ce2b925bc555facbbf1b55d63ea6fbea6a785c97d4caf2e1dad9551b7f66c31caae5ebc7c0047e892f201308fcf452c588be0e63d89152113d87bf0dbd01603b4cdc7f0b724b0714a9851887a01f709408882e18230fe810b9fafa58a666654576d8eba3005f07221f55a6193815a672e5db56204053bc4286fa3db38250396309fd28011b5708a26a2d76c4a333b69b6bfd272fb
fulfillment payload for node 2: b584abb82973d6112d1474e8685a21253e4936c0b27e7f122c5443694d99bb263e1a8f9724f7cc7b50ce9e79cdbc63738a97bd0d31acee4d15143fea72d1d7dd44c0828a7e3f4fbdc178c2a05caf13fa0eedf325479052aa855aa955e22520fcfbafc5de47d52fc304d4da1b2ba2882861038fc79f6ff6eb0a600e17af44cf25941318a95cb47788e65a4430c9b30d38a2d4e291f3657e5b83712cebeac1f942d4d066f146505d227aefb995cdf098e2e8d82c9118859bf9b1477e3b5bccce02288082bb2e1ded74d94a3278d500298e0a91435a9f6304436a614cfe59e33283067be5bda617e6e094ce861a2c48e51f73ba9dcfab879c6a3a19fbe60697432bb5b04dbc401d53757c133ed01a5ad4ad attribution data for node 2: 34e34397b8621ec2f2b54dbe6c14073e267324cd60b152bce76aec8729a6ddefb61bc263be4b57bd592aae604a32bea69afe6ef4a6b573c26b17d69381ec1fc9b5aa769d148f2f1f8b5377a73840bb6d40734019bf9dcbb731aeac3b1052e6703e8ffa550f2f3b6b40df0faa5bd67271a99a81e81265b567522733358a1c8a3b770d207ba8a22ba238abf056af11042474f4fd44bbb21e3ea8d978058a8cc67a11ad429f816de27a43dd69a3f1fe8ccf670fa081fd9d89af6079f7baf05c7f4bf318b2dcfe18f5bd8628795265f61cbf40b6efa757fc9242927c329f5e06ddbce3be8c1f5dd48a0370eb559f5dc181a09f2209da72f79ae6745992c803310d39f960e8ecf327aed706e4b3e2704eeb9b304dc0e0685f5dcd0389ec377bdba37610ad556a0e957a413a56339dd3c40817214bced5802beee2ee545bdd713208751added5fc0eb2bc89a5aa2decb18ee37dac39f22a33b60cc1a369d24de9f3d2d8b63c039e248806de4e36a47c7a0aed30edd30c3d62debdf1ad82bf7aedd7edec413850d91c261e12beec7ad1586a9ad25b2db62c58ca17119d61dcc4f3e5c4520c42a8e384a45d8659b338b3a08f9e123a1d3781f5fc97564ccff2c1d97f06fa0150cfa1e20eacabefb0c339ec109336d207cc63d9170752fc58314c43e6d4a528fd0975afa85f3aa186ff1b6b8cb12c97ed4ace295b0ef5f075f0217665b8bb180246b87982d10f43c9866b22878106f5214e99188781180478b07764a5e12876ddcb709e0a0a8dd42cf004c695c6fc1669a6fd0e4a1ca54b024d0d80eac492a9e5036501f36fb25b72a054189294955830e43c18e55668337c8c6733abb09fc2d4ade18d5a853a2b82f7b4d77151a64985004f1d9218f2945b63c56fdebd1e96a2a7e49fa70acb4c39873947b83c191c10e9a8f40f60f3ad5a2be47145c22ea59ed3f5f4e61cb069e875fb67142d281d784bf925cc286eacc2c43e94d08da4924b83e58dbf2e43fa625bdd620eba6d9ce960ff17d14ed1f2dbee7d08eceb540fdc75ff06dabc767267658fad8ce99e2a3236e46d2deedcb51c3c6f81589357edebac9772a70b3d910d83cd1b9ce6534a011e9fa557b891a23b5d88afcc0d9856c6dabeab25eea55e9a248182229e4927f268fe5431672fcce52f434ca3d27d1a2136bae5770bb36920df12fbc01d0e8165610efa04794f414c1417f1d4059435c5385bfe2de83ce0e238d6fd2dbd3c0487c69843298577bfa480fe2a16ab2a0e4bc712cd8b5a14871cda61c993b6835303d9043d7689a
fulfillment payload for node 1: ba9463d72ce55bc83c9ccd70861ffdf8c5b1a9291be4d9257016ae3c6d3becc6765fe07333369e629ef7475898e535dda560281a4dcf2654362b0421e95aff38e8aeb1298787331bec87815490e534af8de7c85bdf537418fdb81464168cb7c2123ee4186fa6da7cb60583c8ff2ed07982b0ce3e690cb9ba99f186d416bb8adb7f020ea2ef2894bbc732fcd78d1a2c3f7983b85f8b039ae370e1dd062e6d2e6439c003a4d65a55102db383ef1ceb291cd057dfba81396959613104b894e5f4202218b86b3ac9e9cb7b4a10a06669d788fd7d8a9dd832d8996592d17593978d1a500fbe1943c57f004e41eeb3da28e114997aa3b6f183fa2af59b8ad67c1c2753beb5c5fe6f4733980225e8d40d0cfd95 attribution data for node 1: 74a4ea61339463642a2182758871b2ea724f31f531aa98d80f1c3043febca41d5ee52e8b1e127e61719a0d078db8909748d57839e58424b91f063c4fbc8a221bef261140e66a9b596ca6d420a973ad54651be4bf8728ba81adcb9a1d3ce3820cea24f2c6bfdde427edb7706dfd1e8e50c0ab544022275fd457fbd57555cfc85bbfbed6eb0f7a8ea04ebc1b40fc8d3f67402a01d169ed1448ed2e708e16a0fe2c1ab5055be446594036b5ecae456486addbebbd09ca3423d4c15e2afce6b40b545bfbf5859b6bf913e80bcec00e88cba671fee9770fdace16301fbb23b0eca85549ae0be1a96bda5167b6e5fb837edecd981b61e06858badb34ead1e93746ab5afd2bc10e95bffc4dc965de242db63eb8ec221cf57e2c77241fcfca70818a85a447b6fbcaaf4b2fc2135565cbfc03804aa11ad0ab0582e5d86590df2ecfd561dc6e1cdb08d3e10901312326a45fb0498a177319389809c6ba07a76cfad621e07b9af097730e94df92fbd311b2cb5da32c80ab5f14971b6d40f8e2ab202ac98bd8439790764a40bf309ea2205c1632610956495720030a25dc7118e0c868fdfa78c3e9ecce58215579a0581b3bafdb7dbbe53be9e904567fdc0ce1236aab5d22f1ebc18997e3ea83d362d891e04c5785fd5238326f767bce499209f8db211a50e1402160486e98e7235cf397dbb9ae19fd9b79ef589c821c6f99f28be33452405a003b33f4540fe0a41dfcc286f4d7cc10b70552ba7850869abadcd4bb7f256823face853633d6e2a999ac9fcd259c71d08e266db5d744e1909a62c0db673745ad9585949d108ab96640d2bc27fb4acac7fa8b170a30055a5ede90e004df9a44bdc29aeb4a6bec1e85dde1de6aaf01c6a5d12405d0bec22f49026cb23264f8c04b8401d3c2ab6f2e109948b6193b3bec27adfe19fb8afb8a92364d6fc5b219e8737d583e7ff3a4bcb75d53edda3bf3f52896ac36d8a877ad9f296ea6c045603fc62ac4ae41272bde85ef7c3b3fd3538aacfd5b025fefbe277c2906821ecb20e6f75ea479fa3280f9100fb0089203455c56b6bc775e5c2f0f58c63edd63fa3eec0b40da4b276d0d41da2ec0ead865a98d12bc694e23d8eaadd2b4d0ee88e9570c88fb878930f492e036d27998d593e47763927ff7eb80b188864a3846dd2238f7f95f4090ed399ae95deaeb37abca1cf37c397cc12189affb42dca46b4ff6988eb8c060691d155302d448f50ff70a794d97c0408f8cee9385d6a71fa412e36edcb22dbf433db9db4779f27b682ee17fc05e70c8e794b9f7f6d1
fulfillment payload for node 0: 8c0d9ee20671d1cdca98bb4c8dd5d490105b63021afcb90b22f33f1d9d6b7faafb86ec57ec4b56ad11e122bb0289403447a0b814ef8aefb90d2b0c3567501eb3570011ee96514db6050747a1d5cba50fe6e0c3e639d8208c549d61a502eab8772eceafeee940a586fc0ad92ce57773e307a5055604b9ea68c780617d6a797467d357d185fe9eb4279719d35faaab1105ab77299bd10f3504c439058720ed738a1c16756a44ba348bb193ec7d3dd9f11ac3d0cc1277ace098ed0ed8e25a01e83216a9c6a183a2659ddf2d971bc4a9b5ce776e1b07242a89a15026a3d208bbb8e3f91086f2785be68b5e4122f9d79583b883266ba6dfb4cf0c22737915dda898e1461651818c17f811f51f496f0842223c attribution data for node 0: 84986c936d26bfd3bb2d34d3ec62cfdb63e0032fdb3d9d75f3e5d456f73dffa7e35aab1db4f1bd3b98ff585caf004f656c51037a3f4e810d275f3f6aea0c8e3a125ebee5f374b6440bcb9bb2955ebf706a8fd90a3bef40add4106d8c215290aafbc30881b17d68b6a7aac1b6ab52261df2fceef75d3a490862d4bab3aa510cfb8ca695b38c640b58bb8685db8bb57f93db49657ddda39d21d6074d9ecaa1ea0da6cc904e136dbb4c1ba9839a7fb8367c88662f7f573c82c2746d122cca96b2e7872a48e32c8adba45babdc57a9bca55720b1d2c922622fcf8f8a5ed7daae286484b701e69bd40554a4cc3418444ff7eb9982ecee020c8a92717f089ce1ab0ca00bb3a582253cd832a2f869703a2fadafd8261ebb93fde2a9f4f13dc8470436c3cd110bdcc7f5a1e9f9c743c8e55b50c45dac07e07a8e5c7416de895940fde032786594bbaa8a1147422bd5e926fea510408c249fb61164bf7bdbac53d9fb9704023314c332a865146893ad99743708c4a34a30a82fd8b756c561a6520d47b2cd487299a96322dadc463ef06127fc63902ff9cc4f265e2fbd9de3fa5e48b7b51aa0850580ef9f3b5ebb60c6c3216c5a75a93e82936113d9cad57ae4a94dd6481954a9bd1b5cff4ab29ca221fa2bf9b28a362c9661206f896fc7cec563fb80aa5eaccb26c09fa4ef7a981e63028a9c4dac12f82ccb5bea090d56bbb1a4c431e315d9a169299224a8dbd099fb67ea61dfc604edf8a18ee742550b636836bb552dabb28820221bf8546331f32b0c143c1c89310c4fa2e1e0e895ce1a1eb0f43278fdb528131a3e32bfffe0c6de9006418f5309cba773ca38b6ad8507cc59445ccc0257506ebc16a4c01d4cd97e03fcf7a2049fea0db28447858f73b8e9fe98b391b136c9dc510288630a1f0af93b26a8891b857bfe4b818af99a1e011e6dbaa53982d29cf74ae7dffef45545279f19931708ed3eede5e82280eab908e8eb80abff3f1f023ab66869297b40da8496861dc455ac3abe1efa8a6f9e2c4eda48025d43a486a3f26f269743eaa30d6f0e1f48db6287751358a41f5b07aee0f098862e3493731fe2697acce734f004907c6f11eef189424fee52cd30ad708707eaf2e441f52bcf3d0c5440c1742458653c0c8a27b5ade784d9e09c8b47f1671901a29360e7e5e94946b9c75752a1a8d599d2a3e14ac81b84d42115cd688c8383a64fc6e7e1dc5568bb4837358ebe63207a4067af66b2027ad2ce8fb7ae3a452d40723a51fdf9f9c9913e8029a222cf81d12ad41e58860d75deb6de30ad
References
Authors
[ FIXME: ]
This
work is licensed under a Creative
Commons Attribution 4.0 International License.