mirror of
https://github.com/lightning/bolts.git
synced 2025-03-10 17:18:44 +01:00
BOLT 4: complete second-pass copy edit, introduced new terminology 'erring node', require a few clarifications
This commit is contained in:
parent
051f98a75e
commit
54b49c09db
1 changed files with 150 additions and 136 deletions
|
@ -255,7 +255,7 @@ 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`.
|
`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`
|
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. The nodes `n_i` and
|
is the sender itself and `n_r` is the final recipient. The nodes `n_i` and
|
||||||
`n_{i+1}` MUST be peers in the overlay network. The sender then gathers the
|
`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`.
|
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
|
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
|
packet commits to but that is not included in the packet itself. Associated
|
||||||
|
@ -269,32 +269,35 @@ The hop receiving the header will perform ECDH with the ephemeral public key
|
||||||
and its own private key in order to derive the same shared secret.
|
and its own private key in order to derive the same shared secret.
|
||||||
However, when generating the packet, the sending node doesn't have access to the
|
However, when generating the packet, the sending node doesn't have access to the
|
||||||
other nodes' private keys. So instead, it uses the commutative property of
|
other nodes' private keys. So instead, it uses the commutative property of
|
||||||
multiplication to blind each node's public key with all previous blinding
|
multiplication to blind each hop's public key with all previous blinding
|
||||||
factors and performs ECDH using each node's blinded public key and the `sessionkey`.
|
factors and performs ECDH, using each hop's blinded public key and the
|
||||||
|
`sessionkey`.
|
||||||
|
|
||||||
The transformations at hop `k` are given by the following:
|
The transformations at hop `k` are as follows:
|
||||||
|
|
||||||
- The shared secret `ss_k` is computed by first blinding the node's public key
|
- The shared secret `ss_k` is computed by first blinding the hop's public key
|
||||||
`nodepk_k` with all previous blinding factors `{b_1, ..., b_{k-1}}` (if any),
|
`nodepk_k` with all previous blinding factors `{b_1, ..., b_{k-1}}` (if any),
|
||||||
and second executing ECDH with the blinded public key and the `sessionkey`.
|
and second, executing ECDH with the blinded public key and the `sessionkey`.
|
||||||
- The blinding factor is the `SHA256` hash of the concatenation between the
|
- The blinding factor is the `SHA256` hash of the concatenation between the
|
||||||
node's public key `nodepk_k` and the hop's shared secret `ss_k`. Before
|
hop's public key `nodepk_k` and its shared secret `ss_k`. Before
|
||||||
concatenation, the node's public key is serialized in the compressed format.
|
concatenation, the hop's public key is serialized in the compressed format.
|
||||||
- The ephemeral public key `epk_k` is computed by blinding the previous hop's
|
- The ephemeral public key `epk_k` is computed by blinding the hop's sending
|
||||||
ephemeral public key `epk_{k-1}` with the previous hop's blinding factor `b_{k-1}`.
|
peer's ephemeral public key `epk_{k-1}` with the hop's sending peer's blinding
|
||||||
|
factor `b_{k-1}`.
|
||||||
|
|
||||||
This recursive algorithm is initialized by setting the first hop's (`k=1`)
|
This recursive algorithm is initialized by setting the first hop's (`k=1`)
|
||||||
ephemeral public key to the public key corresponding to the `sessionkey`, i.e.
|
ephemeral public key to the public key corresponding to the `sessionkey`, i.e.
|
||||||
`secp256k1` is used to derive a public key for the randomly selected `sessionkey`.
|
`secp256k1` is used to derive a public key for the randomly selected
|
||||||
|
`sessionkey`.
|
||||||
|
|
||||||
The sender then iteratively computes the ephemeral public keys, shared secrets,
|
The origin node then iteratively computes the ephemeral public keys, shared
|
||||||
and blinding factors for nodes `{n_2, ..., n_r}`.
|
secrets, and blinding factors for hops `{n_2, ..., n_r}`.
|
||||||
|
|
||||||
Once the sender has all the required information above, it can construct the packet.
|
Once the sender has all the required information above, it can construct the
|
||||||
Constructing a packet routed over `r` hops requires `r` 32-byte ephemeral
|
packet. Constructing a packet routed over `r` hops requires `r` 32-byte
|
||||||
public keys, `r` 32-byte shared secrets, `r` 32-byte blinding factors, and `r`
|
ephemeral public keys, `r` 32-byte shared secrets, `r` 32-byte blinding factors,
|
||||||
65-byte `per_hop` payloads.
|
and `r` 65-byte `per_hop` payloads. The construction returns a single 1366-byte
|
||||||
The construction returns a single 1366-byte packet along with the first hop's address.
|
packet along with the first receiving peer's address.
|
||||||
|
|
||||||
The packet construction is performed in the reverse order of the route, i.e.
|
The packet construction is performed in the reverse order of the route, i.e.
|
||||||
the last hop's operations are applied first.
|
the last hop's operations are applied first.
|
||||||
|
@ -313,19 +316,20 @@ following operations:
|
||||||
- The `version`, `short_channel_id`, `amt_to_forward`, `outgoing_cltv_value`,
|
- The `version`, `short_channel_id`, `amt_to_forward`, `outgoing_cltv_value`,
|
||||||
`padding`, and `HMAC` are copied into the following 65 bytes.
|
`padding`, and `HMAC` are copied into the following 65 bytes.
|
||||||
- The _rho_-key is used to generate 1300 bytes of pseudo-random byte stream
|
- The _rho_-key is used to generate 1300 bytes of pseudo-random byte stream
|
||||||
and applied, with `XOR`, to the `hops_data` field.
|
which is then applied, with `XOR`, to the `hops_data` field.
|
||||||
- If this is the last hop, i.e. the first iteration, then the tail of the
|
- If this is the last hop, i.e. the first iteration, then the tail of the
|
||||||
`hops_data` field is overwritten with the routing information `filler`.
|
`hops_data` field is overwritten with the routing information `filler`.
|
||||||
- The next HMAC is computed (with the _mu_-key as HMAC-key) over the
|
- The next HMAC is computed (with the _mu_-key as HMAC-key) over the
|
||||||
concatenated `hops_data` and associated data.
|
concatenated `hops_data` and associated data.
|
||||||
|
|
||||||
[FIXME: Please reword, meaning is unclear] The final value for the HMAC is the HMAC as it should be sent to the first hop.
|
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`
|
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
|
byte, the ephemeral pubkey for the first hop, the HMAC for the first hop, and
|
||||||
the obfuscated `hops_data`.
|
the obfuscated `hops_data`.
|
||||||
|
|
||||||
The following code implements the packet construction in Go:
|
The following Go code is an example implementation of the packet construction:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey,
|
func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey,
|
||||||
|
@ -395,12 +399,12 @@ func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey
|
||||||
|
|
||||||
# Packet Forwarding
|
# Packet Forwarding
|
||||||
|
|
||||||
This specification is limited to `version` `0` packets; however, the structure of
|
This specification is limited to `version` `0` packets; however, the structure
|
||||||
future versions may change.
|
of future versions may change.
|
||||||
Upon receiving a packet, a processing node compares the version byte of the
|
Upon receiving a packet, a processing node compares the version byte of the
|
||||||
packet with its supported versions and aborts the connection if the packet
|
packet with its own supported versions and aborts the connection if the packet
|
||||||
specifies a version number it doesn't support.
|
specifies a version number that it doesn't support.
|
||||||
For packets with supported version numbers, the processing node then parses the
|
For packets with supported version numbers, the processing node first parses the
|
||||||
packet into its individual fields.
|
packet into its individual fields.
|
||||||
|
|
||||||
The processing node:
|
The processing node:
|
||||||
|
@ -408,37 +412,38 @@ The processing node:
|
||||||
- MUST abort processing the packet.
|
- MUST abort processing the packet.
|
||||||
- MUST report a route failure to the origin node.
|
- MUST report a route failure to the origin node.
|
||||||
|
|
||||||
The processing node then computes the shared secret, as described below, using the private
|
Next, the processing node computes the shared secret using the private key
|
||||||
key corresponding to its public key and the ephemeral key from the packet.
|
corresponding to its own public key and the ephemeral key from the packet, as
|
||||||
|
described in [Shared Secret](#shared-secret).
|
||||||
|
|
||||||
The processing node:
|
The processing node:
|
||||||
- if the packet has previously been forwarded or locally redeemed, i.e. packet
|
- if the packet has previously been forwarded or locally redeemed, i.e. the
|
||||||
contains duplicated routing information:
|
packet contains duplicate routing information to a previously received packet:
|
||||||
- if preimage is known:
|
- if preimage is known:
|
||||||
- MAY immediately redeem the HTLC using the preimage.
|
- MAY immediately redeem the HTLC using the preimage.
|
||||||
- otherwise:
|
- otherwise:
|
||||||
- MUST abort processing and report a route failure.
|
- MUST abort processing and report a route failure.
|
||||||
|
|
||||||
The above requirements prevent any hop along the route from retrying a payment
|
The above requirements prevent any hop along the route from retrying a payment
|
||||||
multiple times and attempting to track a payment's progress via traffic
|
multiple times, in an attempt to track a payment's progress via traffic
|
||||||
analysis. Note that this could be accomplished using a log of previous shared
|
analysis. Note that such traffic analysis could be accomplished using a log of
|
||||||
secrets or HMACs, which could be forgotten once the HTLC would not be accepted
|
previous shared secrets or HMACs, which could be forgotten once the HTLC would
|
||||||
anyway (i.e. after `outgoing_cltv_value` has passed). Such a log may use a
|
not be accepted anyway (i.e. after `outgoing_cltv_value` has passed). Such a log
|
||||||
probabilistic data structure, but it MUST rate-limit commitments, as necessary,
|
may use a probabilistic data structure, but it MUST rate-limit commitments as
|
||||||
in order to constrain the worst-case storage requirements or false positives of
|
necessary, in order to constrain the worst-case storage requirements or false
|
||||||
this log.
|
positives of this log.
|
||||||
|
|
||||||
The shared secret is used to compute a _mu_-key. The processing node then
|
Next, the processing node uses the shared secret to compute a _mu_-key, which it
|
||||||
computes the HMAC of the `hops_data` using the _mu_-key. The resulting HMAC is
|
in turn uses to compute the HMAC of the `hops_data`. The resulting HMAC is then
|
||||||
compared with the HMAC from the packet.
|
compared against the packet's HMAC.
|
||||||
|
|
||||||
The processing node:
|
The processing node:
|
||||||
- if the computed HMAC and the HMAC from the packet differ:
|
- if the computed HMAC and the packet's HMAC differ:
|
||||||
- MUST abort processing.
|
- MUST abort processing.
|
||||||
- MUST report a route failure.
|
- MUST report a route failure.
|
||||||
|
|
||||||
Comparison of the computed HMAC and the HMAC from the packet MUST be
|
Comparison of the computed HMAC and the packet's HMAC MUST be
|
||||||
time-constant to avoid leaking information.
|
time-constant to avoid information leaks.
|
||||||
|
|
||||||
At this point, the processing node can generate a _rho_-key and a _gamma_-key.
|
At this point, the processing node can generate a _rho_-key and a _gamma_-key.
|
||||||
|
|
||||||
|
@ -471,24 +476,25 @@ The processing node:
|
||||||
- MUST drop the packet.
|
- MUST drop the packet.
|
||||||
- MUST signal a route failure.
|
- MUST signal a route failure.
|
||||||
|
|
||||||
|
[FIXME: separate processing node requirements into `Requirements` section, or is more it important to integrate them into the sequence of events?]
|
||||||
|
|
||||||
# Shared Secret
|
# Shared Secret
|
||||||
|
|
||||||
The origin node performs ECDH with each hop of the route, in order to establish a secret.
|
The origin node performs ECDH with each hop of the route, in order to establish a secret.
|
||||||
A new _sessionkey_, a 32-byte EC private key, is generated for each message.
|
A new _sessionkey_, a 32-byte EC private key, is generated for each message.
|
||||||
The shared secret builder function takes a public key and a 32-byte secret
|
The shared secret builder function takes a public key and a 32-byte secret
|
||||||
as input and returns a 32-byte secret as output.
|
,as inputs, and returns a 32-byte secret, as output.
|
||||||
|
|
||||||
During the packet generation phase, the secret is the `sessionkey`, and the
|
During the packet generation phase, the secret is the `sessionkey`, and the
|
||||||
public key is the processing node's public key, which is
|
public key is the hop's public key, which is blinded by all previous blinding
|
||||||
blinded by all previous blinding factors.
|
factors.
|
||||||
During the processing phase, the secret is the processing node's private key,
|
During the processing phase, the secret is the hop's (processing node's) private
|
||||||
while the public key is the ephemeral public key from the packet, which has been
|
key, while the public key is the ephemeral public key from the packet, which has
|
||||||
incrementally blinded by its predecessors.
|
been incrementally blinded by its predecessors.
|
||||||
|
|
||||||
The public key is multiplied by the secret, using the `secp256k1` curve.
|
The public key is multiplied by the secret, using the `secp256k1` curve.
|
||||||
The DER compressed representation of the multiplication result is serialized and
|
The DER compressed representation of the multiplication result is serialized and
|
||||||
hashed using `SHA256`.
|
hashed using `SHA256`, and the resulting hash is returned as the shared secret.
|
||||||
The resulting hash is returned as the shared secret.
|
|
||||||
Notice that this is the ECDH variant implemented in `libsecp256k1`.
|
Notice that this is the ECDH variant implemented in `libsecp256k1`.
|
||||||
|
|
||||||
# Filler Generation
|
# Filler Generation
|
||||||
|
@ -496,12 +502,12 @@ Notice that this is the ECDH variant implemented in `libsecp256k1`.
|
||||||
Upon receiving a packet, the processing node extracts the information destined
|
Upon receiving a packet, the processing node extracts the information destined
|
||||||
for it from the route information and the per-hop payload.
|
for it from the route information and the per-hop payload.
|
||||||
The extraction is done by deobfuscating and left-shifting the field.
|
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.
|
This would make the field shorter at each hop, allowing an attacker to deduce the
|
||||||
For this reason, the field is padded before forwarding.
|
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 generate an
|
Since the padding is part of the HMAC, the origin node will have to generate an
|
||||||
identical padding in order to compute the HMACs correctly for each hop.
|
identical [FIXME: identical to what?] padding 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
|
The filler is also used to pad the field-length, in the case that the selected
|
||||||
route is shorter than the maximum allowed route length.
|
route is shorter than the maximum allowed route length of 20.
|
||||||
|
|
||||||
Before deobfuscating the `hops_data`, the processing node pads it with 65
|
Before deobfuscating the `hops_data`, the processing node pads it with 65
|
||||||
`0x00`-bytes, such that the total length is `(20 + 1) * 65`.
|
`0x00`-bytes, such that the total length is `(20 + 1) * 65`.
|
||||||
|
@ -510,11 +516,12 @@ it with `XOR` to the `hops_data`.
|
||||||
This deobfuscates the information destined for it, while simultaneously
|
This deobfuscates the information destined for it, while simultaneously
|
||||||
obfuscating the added `0x00`-bytes at the end.
|
obfuscating the added `0x00`-bytes at the end.
|
||||||
|
|
||||||
In order to compute the correct HMAC, the origin node has to generate the `hops_data`
|
In order to compute the correct HMAC, the origin node has to pre-generate the
|
||||||
for each hop, which includes the incrementally obfuscated padding added by each hop.
|
`hops_data` for each hop, including the incrementally obfuscated padding added
|
||||||
The incrementally obfuscated padding is called the `filler`.
|
by each hop. This incrementally obfuscated padding is referred to as the
|
||||||
|
`filler`.
|
||||||
|
|
||||||
The following code shows how the filler is generated in Go:
|
The following example code shows how the filler is generated in Go:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
func generateFiller(key string, numHops int, hopSize int, sharedSecrets [][sharedSecretSize]byte) []byte {
|
func generateFiller(key string, numHops int, hopSize int, sharedSecrets [][sharedSecretSize]byte) []byte {
|
||||||
|
@ -544,30 +551,31 @@ func generateFiller(key string, numHops int, hopSize int, sharedSecrets [][share
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that this implementation is for demonstration purposes only; the filler
|
Notice that this example implementation is for demonstration purposes only; the
|
||||||
can be generated much more efficiently.
|
`filler` can be generated much more efficiently.
|
||||||
The last hop does not obfuscate the filler, since it will not forward the packet
|
The last hop need not obfuscate the `filler`, since it won't forward the packet
|
||||||
and will not extract an HMAC for any further hops.
|
any further and thus need not extract an HMAC either.
|
||||||
|
|
||||||
# Blinding EC Points
|
# Blinding EC Points
|
||||||
|
|
||||||
In order to vary the ephemeral public key (the EC point) between hops, it is
|
In order to vary the ephemeral public key (the EC point) between hops, it's
|
||||||
blinded at each hop.
|
blinded at each hop.
|
||||||
The inputs for the blinding process are the EC point to be blinded, the hop's
|
The inputs for the blinding process are the EC point to be blinded, the hop's
|
||||||
public key, and a 32-byte shared secret. The output is a single EC point,
|
public key, and a 32-byte shared secret. The output is a single EC point, which
|
||||||
representing the blinded element.
|
represents the blinded element.
|
||||||
|
|
||||||
Blinding is accomplished by computing a blinding factor from the hop's public
|
Blinding is accomplished by computing a blinding factor from the hop's public
|
||||||
key and the shared secret for that hop.
|
key and the shared secret for that hop.
|
||||||
The blinding factor is the result of serializing the hop's public key into its
|
The blinding factor is the computed `SHA256` hash value of the result of
|
||||||
compressed format, appending the shared secret, and computing the `SHA256` hash.
|
serializing the hop's public key into its compressed format and appending the
|
||||||
The blinded EC point then is the result of the scalar multiplication between the
|
shared secret.
|
||||||
|
The blinded EC point, in turn, is the result of the scalar multiplication of the
|
||||||
EC point and the blinding factor.
|
EC point and the blinding factor.
|
||||||
|
|
||||||
# Returning Errors
|
# Returning Errors
|
||||||
|
|
||||||
The protocol includes a simple mechanism for returning encrypted error messages
|
The onion routing protocol includes a simple mechanism for returning encrypted
|
||||||
to the origin node.
|
error messages to the origin node.
|
||||||
The returned error messages may be failures reported by any hop, including the
|
The returned error messages may be failures reported by any hop, including the
|
||||||
final node.
|
final node.
|
||||||
The format of the forward packet is not usable for the return path, since no hop
|
The format of the forward packet is not usable for the return path, since no hop
|
||||||
|
@ -576,11 +584,11 @@ Note that these error messages are not reliable, as they are not placed on-chain
|
||||||
due to the possibility of hop failure.
|
due to the possibility of hop failure.
|
||||||
|
|
||||||
Intermediate hops store the shared secret from the forward path and reuse it to
|
Intermediate hops store the shared secret from the forward path and reuse it to
|
||||||
obfuscate the error packet on each hop.
|
obfuscate any corresponding return packet during each hop.
|
||||||
In addition, each node locally stores data regarding its sending peer in the
|
In addition, each node locally stores data regarding its own sending peer in the
|
||||||
route, so it knows where to back-send an eventual return packet.
|
route, so it knows where to return-forward any eventual return packets.
|
||||||
The node returning the message builds a return packet consisting of the
|
The node generating the error message (_erring node_) builds a return packet
|
||||||
following fields:
|
consisting of the following fields:
|
||||||
|
|
||||||
1. data:
|
1. data:
|
||||||
* [`32`:`hmac`]
|
* [`32`:`hmac`]
|
||||||
|
@ -593,56 +601,59 @@ 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
|
generated using the above process, with key type `um`, `failuremsg` as defined
|
||||||
below, and `pad` as the extra bytes used to conceal length.
|
below, and `pad` as the extra bytes used to conceal length.
|
||||||
|
|
||||||
The node:
|
The erring node:
|
||||||
- SHOULD set `pad` such that the `failure_len` plus `pad_len` is equal to 256.
|
- SHOULD set `pad` such that the `failure_len` plus `pad_len` is equal to 256.
|
||||||
- Note: this value is 118 bytes longer than the longest currently-defined
|
- Note: this value is 118 bytes longer than the longest currently-defined
|
||||||
message.
|
message.
|
||||||
|
|
||||||
The node then generates a new key, using the key type `ammag`.
|
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 then applied
|
This key is then used to generate a pseudo-random stream, which is in turn
|
||||||
to the packet using `XOR`.
|
applied to the packet using `XOR`.
|
||||||
|
|
||||||
The obfuscation step is repeated by every hop on the return path.
|
The obfuscation step is repeated by every hop along the return path.
|
||||||
Upon receiving a packet, the hop will generate its `ammag`, generate the
|
Upon receiving a return packet, each hop generates its `ammag`, generates the
|
||||||
pseudo-random byte stream, and apply it to the packet before forwarding.
|
pseudo-random byte stream, and applies the result to the return packet before
|
||||||
|
return-forwarding it.
|
||||||
|
|
||||||
The origin node detects that it is the last hop of the return message, since it
|
The origin node is able to detect that it's the intended final recipient of the
|
||||||
was the origin of the corresponding forward packet.
|
return message, because of course, it was the originator of the corresponding
|
||||||
|
forward packet.
|
||||||
When an origin node receives an error message matching a transfer it initiated
|
When an origin node receives an error message matching a transfer it initiated
|
||||||
(i.e. it cannot forward the error any further) it then generates the
|
(i.e. it cannot return-forward the error any further) it generates the `ammag`
|
||||||
`ammag` and `um` keys for each hop in the route.
|
and `um` keys for each hop in the route.
|
||||||
The origin node then iteratively decrypts the error message using each of the `ammag`
|
It then iteratively decrypts the error message, using each hop's `ammag`
|
||||||
keys and computes the HMAC using the `um` keys.
|
key, and computes the HMAC, using each hop's `um` key.
|
||||||
The origin node can detect the sender of the error message by matching the
|
The origin node can detect the sender of the error message by matching the
|
||||||
`hmac` field with the computed HMAC.
|
`hmac` field with the computed HMAC.
|
||||||
|
|
||||||
The origin node:
|
The origin node:
|
||||||
- once the original message has been decrypted:
|
- once the return message has been decrypted:
|
||||||
- SHOULD store a copy of the message.
|
- SHOULD store a copy of the message.
|
||||||
- SHOULD continue decrypting, until the loop has been repeated 20 times.
|
- SHOULD continue decrypting, until the loop has been repeated 20 times.
|
||||||
- SHOULD use constant `ammag` and `um` keys to obfuscate the route length.
|
- SHOULD use constant `ammag` and `um` keys to de-obfuscate the route length.
|
||||||
|
|
||||||
The association between the forward and return packets is handled outside of
|
The association between the forward and return packets is handled outside of
|
||||||
this protocol, e.g. via association with an HTLC in a payment channel.
|
this onion routing protocol, e.g. via association with an HTLC in a payment
|
||||||
|
channel.
|
||||||
|
|
||||||
## Failure Messages
|
## Failure Messages
|
||||||
|
|
||||||
The failure message encapsulated in `failuremsg` has an identical format as
|
The failure message encapsulated in `failuremsg` has an identical format as
|
||||||
a normal message: a 2-byte type `failure_code` followed by data applicable
|
a normal message: a 2-byte type `failure_code` followed by data applicable
|
||||||
to that type. Following is a list of `failure_code` values currently supported
|
to that type. Following is a list of the currently supported `failure_code`
|
||||||
along with their intended use cases.
|
values and their associated use cases.
|
||||||
|
|
||||||
Notice that the `failure_code`s are not of the same type as other message types
|
Notice that the `failure_code`s are not of the same type as other message types,
|
||||||
(defined in other BOLTs), as they are not sent directly on the transport layer
|
defined in other BOLTs, as they are not sent directly on the transport layer
|
||||||
but are instead wrapped inside return packets.
|
but are instead wrapped inside return packets.
|
||||||
The numeric values for the `failure_code` may therefore reuse values that are
|
The numeric values for the `failure_code` may therefore reuse values, that are
|
||||||
also assigned as message types, without any danger of causing collisions.
|
also assigned to other message types, without any danger of causing collisions.
|
||||||
|
|
||||||
A node:
|
An erring node:
|
||||||
- MUST select one of these codes when creating an error message.
|
- MUST select one of these codes when creating an error message.
|
||||||
- MUST include the appropriate data for that particular error type.
|
- MUST include the appropriate data for that particular error type.
|
||||||
- if there is more than one error:
|
- if there is more than one error:
|
||||||
- SHOULD select the first error listed below.
|
- SHOULD select the first error it encounters from the list below.
|
||||||
|
|
||||||
The top byte of `failure_code` can be read as a set of flags:
|
The top byte of `failure_code` can be read as a set of flags:
|
||||||
* 0x8000 (BADONION): unparsable onion encrypted by sending peer
|
* 0x8000 (BADONION): unparsable onion encrypted by sending peer
|
||||||
|
@ -650,18 +661,18 @@ The top byte of `failure_code` can be read as a set of flags:
|
||||||
* 0x2000 (NODE): node failure (otherwise channel)
|
* 0x2000 (NODE): node failure (otherwise channel)
|
||||||
* 0x1000 (UPDATE): new channel update enclosed
|
* 0x1000 (UPDATE): new channel update enclosed
|
||||||
|
|
||||||
Any node MAY return one of the following errors:
|
Any erring node MAY return one of the following errors:
|
||||||
- if the `realm` byte is unknown:
|
- if the `realm` byte is unknown:
|
||||||
1. type: PERM|1 (`invalid_realm`)
|
1. type: PERM|1 (`invalid_realm`)
|
||||||
- if an otherwise unspecified transient error occurs for the entire node:
|
- if an otherwise unspecified transient error occurs for the entire node:
|
||||||
1. type: NODE|2 (`temporary_node_failure`)
|
1. type: NODE|2 (`temporary_node_failure`)
|
||||||
- if an otherwise unspecified permanent error occurs for the entire node:
|
- if an otherwise unspecified permanent error occurs for the entire node:
|
||||||
1. type: PERM|NODE|2 (`permanent_node_failure`)
|
1. type: PERM|NODE|2 (`permanent_node_failure`)
|
||||||
- if a node has requirement advertised in its `node_announcement` `features`
|
- if a node has requirements advertised in its `node_announcement` `features`
|
||||||
which were not present in the onion:
|
which were NOT included in the onion:
|
||||||
1. type: PERM|NODE|3 (`required_node_feature_missing`)
|
1. type: PERM|NODE|3 (`required_node_feature_missing`)
|
||||||
|
|
||||||
A _forwarding node_ MAY, but the _final node_ MUST NOT, return one of the following
|
A _return-forwarding node_ MAY, but a _final node_ MUST NOT, return one of the following
|
||||||
errors:
|
errors:
|
||||||
- if the onion `version` byte is unknown:
|
- if the onion `version` byte is unknown:
|
||||||
1. type: BADONION|PERM|4 (`invalid_onion_version`)
|
1. type: BADONION|PERM|4 (`invalid_onion_version`)
|
||||||
|
@ -675,36 +686,36 @@ errors:
|
||||||
1. type: BADONION|PERM|6 (`invalid_onion_key`)
|
1. type: BADONION|PERM|6 (`invalid_onion_key`)
|
||||||
2. data:
|
2. data:
|
||||||
* [`32`:`sha256_of_onion`]
|
* [`32`:`sha256_of_onion`]
|
||||||
- if an otherwise unspecified transient error occurs for the outgoing
|
- if an otherwise unspecified, transient error occurs for the outgoing
|
||||||
channel (e.g. channel capacity reached, too many in-flight HTLCs):
|
channel [FIXME: what is exact definition of 'outgoing' channel?] (e.g. channel capacity reached, too many in-flight HTLCs, etc.):
|
||||||
1. type: UPDATE|7 (`temporary_channel_failure`)
|
1. type: UPDATE|7 (`temporary_channel_failure`)
|
||||||
2. data:
|
2. data:
|
||||||
* [`2`:`len`]
|
* [`2`:`len`]
|
||||||
* [`len`:`channel_update`]
|
* [`len`:`channel_update`]
|
||||||
- if an otherwise unspecified, permanent error occurs for the outgoing channel
|
- if an otherwise unspecified, permanent error occurs for the outgoing channel
|
||||||
(e.g. channel (recently) closed):
|
(e.g. channel recently closed):
|
||||||
1. type: PERM|8 (`permanent_channel_failure`)
|
1. type: PERM|8 (`permanent_channel_failure`)
|
||||||
- if the outgoing channel has a requirement advertised in its
|
- if the outgoing channel has requirements advertised in its
|
||||||
`channel_announcement` `features` which was not present in the onion:
|
`channel_announcement` `features` which were NOT included in the onion:
|
||||||
1. type: PERM|9 (`required_channel_feature_missing`)
|
1. type: PERM|9 (`required_channel_feature_missing`)
|
||||||
- if the receiving peer specified by the onion is not known:
|
- if the receiving peer specified by the onion is NOT known:
|
||||||
1. type: PERM|10 (`unknown_next_peer`)
|
1. type: PERM|10 (`unknown_next_peer`)
|
||||||
- if the HTLC does not reach the current minimum amount, the amount of the
|
- if the HTLC amount is less than the currently specified minimum amount, the
|
||||||
incoming HTLC and the current channel setting for the outgoing channel are
|
amount of the incoming HTLC and the current channel setting for the outgoing
|
||||||
reported:
|
channel [FIXME: is there a more concise way to say this?] are reported:
|
||||||
1. type: UPDATE|11 (`amount_below_minimum`)
|
1. type: UPDATE|11 (`amount_below_minimum`)
|
||||||
2. data:
|
2. data:
|
||||||
* [`8`:`htlc_msat`]
|
* [`8`:`htlc_msat`]
|
||||||
* [`2`:`len`]
|
* [`2`:`len`]
|
||||||
* [`len`:`channel_update`]
|
* [`len`:`channel_update`]
|
||||||
- if the HTLC does not pay a sufficient fee, the amount of the incoming HTLC
|
- if the HTLC does NOT pay a sufficient fee, the amount of the incoming HTLC
|
||||||
and the current channel setting for the outgoing channel are reported:
|
and the current channel setting for the outgoing channel are reported:
|
||||||
1. type: UPDATE|12 (`fee_insufficient`)
|
1. type: UPDATE|12 (`fee_insufficient`)
|
||||||
2. data:
|
2. data:
|
||||||
* [`8`:`htlc_msat`]
|
* [`8`:`htlc_msat`]
|
||||||
* [`2`:`len`]
|
* [`2`:`len`]
|
||||||
* [`len`:`channel_update`]
|
* [`len`:`channel_update`]
|
||||||
- if the `outgoing_cltv_value` does not match the `update_add_htlc`'s
|
- if the `outgoing_cltv_value` does NOT match the `update_add_htlc`'s
|
||||||
`cltv_expiry` minus the `cltv_expiry_delta` for the outgoing channel, the
|
`cltv_expiry` minus the `cltv_expiry_delta` for the outgoing channel, the
|
||||||
`cltv_expiry` and the current channel setting for the outgoing channel are
|
`cltv_expiry` and the current channel setting for the outgoing channel are
|
||||||
reported:
|
reported:
|
||||||
|
@ -719,7 +730,8 @@ errors:
|
||||||
2. data:
|
2. data:
|
||||||
* [`2`:`len`]
|
* [`2`:`len`]
|
||||||
* [`len`:`channel_update`]
|
* [`len`:`channel_update`]
|
||||||
- if the `cltv_expiry` is unreasonably far, its also possible report an error:
|
- if the `cltv_expiry` is unreasonably far in the future, its also possible to
|
||||||
|
report an error:
|
||||||
1. type: 21 (`expiry_too_far`)
|
1. type: 21 (`expiry_too_far`)
|
||||||
- if the channel is disabled, the current channel setting for the outgoing
|
- if the channel is disabled, the current channel setting for the outgoing
|
||||||
channel are reported:
|
channel are reported:
|
||||||
|
@ -729,37 +741,38 @@ errors:
|
||||||
* [`2`:`len`]
|
* [`2`:`len`]
|
||||||
* [`len`:`channel_update`]
|
* [`len`:`channel_update`]
|
||||||
|
|
||||||
The _final node_ MAY, but _intermediate hops_ MUST NOT, return one of the
|
The _final node_ MAY, but an _intermediate hop_ MUST NOT, return one of the
|
||||||
following errors:
|
following errors:
|
||||||
- if the payment hash has already been paid:
|
- if the payment hash has already been paid:
|
||||||
- MAY treat the payment hash as unknown.
|
- MAY treat the payment hash as unknown.
|
||||||
- MAY succeed in accepting the HTLC.
|
- MAY succeed in accepting the HTLC [FIXME: is this correct?].
|
||||||
- if the payment hash is unknown:
|
- if the payment hash is unknown:
|
||||||
- MUST fail the HTLC:
|
- MUST fail the HTLC:
|
||||||
1. type: PERM|15 (`unknown_payment_hash`)
|
1. type: PERM|15 (`unknown_payment_hash`)
|
||||||
- if the amount paid is less than the amount expected:
|
- if the amount paid is less than the amount expected:
|
||||||
- MUST fail the HTLC.
|
- MUST fail the HTLC.
|
||||||
- if the amount paid is more than twice the amount expected:
|
- if the amount paid is more than twice the amount expected:
|
||||||
- SHOULD fail the HTLC. This allows the origin node to reduce information leakage
|
- SHOULD [FIXME: MUST?] fail the HTLC. Note: this allows the origin node to reduce
|
||||||
by altering the amount while not allowing for accidental gross overpayment:
|
information leakage by altering the amount while not allowing for accidental
|
||||||
|
gross overpayment:
|
||||||
1. type: PERM|16 (`incorrect_payment_amount`)
|
1. type: PERM|16 (`incorrect_payment_amount`)
|
||||||
- if the `cltv_expiry` is too low:
|
- if the `cltv_expiry` value is too near the present:
|
||||||
- MUST fail the HTLC:
|
- MUST fail the HTLC:
|
||||||
1. type: 17 (`final_expiry_too_soon`)
|
1. type: 17 (`final_expiry_too_soon`)
|
||||||
- if the `outgoing_cltv_value` does not match the `cltv_expiry` of the HTLC at
|
- if the `outgoing_cltv_value` does NOT correspond with the `cltv_expiry` from
|
||||||
the final node:
|
the final node's HTLC:
|
||||||
1. type: 18 (`final_incorrect_cltv_expiry`)
|
1. type: 18 (`final_incorrect_cltv_expiry`)
|
||||||
2. data:
|
2. data:
|
||||||
* [`4`:`cltv_expiry`]
|
* [`4`:`cltv_expiry`]
|
||||||
- if the `amt_to_forward` is greater than the `incoming_htlc_amt` of the HTLC
|
- if the `amt_to_forward` is greater than the `incoming_htlc_amt` from the
|
||||||
at the final node:
|
final node's HTLC:
|
||||||
1. type: 19 (`final_incorrect_htlc_amount`)
|
1. type: 19 (`final_incorrect_htlc_amount`)
|
||||||
2. data:
|
2. data:
|
||||||
* [`4`:`incoming_htlc_amt`]
|
* [`4`:`incoming_htlc_amt`]
|
||||||
|
|
||||||
## Receiving Failure Codes
|
## Receiving Failure Codes
|
||||||
|
|
||||||
A node:
|
A node [FIXME: 'origin', 'return-forwarding', or 'any' node?]:
|
||||||
- MUST ignore any extra bytes in `failuremsg`.
|
- MUST ignore any extra bytes in `failuremsg`.
|
||||||
|
|
||||||
The _origin node_:
|
The _origin node_:
|
||||||
|
@ -768,9 +781,9 @@ The _origin node_:
|
||||||
- SHOULD fail the payment.
|
- SHOULD fail the payment.
|
||||||
- otherwise:
|
- otherwise:
|
||||||
- if the error code is understood and valid:
|
- if the error code is understood and valid:
|
||||||
- MAY retry the payment. (In particular, `final_expiry_too_soon` can
|
- MAY retry the payment. In particular, `final_expiry_too_soon` can
|
||||||
occur if the block height has changed since sending,
|
occur if the block height has changed since sending, and in this case
|
||||||
`temporary_node_failure` could resolve within a few seconds).
|
`temporary_node_failure` could resolve within a few seconds.
|
||||||
- otherwise, an _intermediate hop_ is returning the error:
|
- otherwise, an _intermediate hop_ is returning the error:
|
||||||
- if the NODE bit is set:
|
- if the NODE bit is set:
|
||||||
- SHOULD remove all channels connected with the erring node from
|
- SHOULD remove all channels connected with the erring node from
|
||||||
|
@ -780,7 +793,7 @@ The _origin node_:
|
||||||
- otherwise:
|
- otherwise:
|
||||||
- if UPDATE is set, AND the `channel_update` is valid and more recent
|
- if UPDATE is set, AND the `channel_update` is valid and more recent
|
||||||
than the `channel_update` used to send the payment:
|
than the `channel_update` used to send the payment:
|
||||||
- if this [FIXME: what does 'this' refer to?] should not have caused the failure:
|
- if this [FIXME: what does 'this' refer to?] should NOT have caused the failure:
|
||||||
- MAY treat the `channel_update` as invalid.
|
- MAY treat the `channel_update` as invalid.
|
||||||
- otherwise:
|
- otherwise:
|
||||||
- SHOULD apply the `channel_update`.
|
- SHOULD apply the `channel_update`.
|
||||||
|
@ -788,17 +801,18 @@ The _origin node_:
|
||||||
- otherwise:
|
- otherwise:
|
||||||
- SHOULD eliminate the channel outgoing from the erring node from
|
- SHOULD eliminate the channel outgoing from the erring node from
|
||||||
consideration.
|
consideration.
|
||||||
- if the PERM bit is not set:
|
- if the PERM bit is NOT set:
|
||||||
- SHOULD restore the channel as it receives new `channel_update`s.
|
- SHOULD restore the channel as it receives new `channel_update`s.
|
||||||
- SHOULD then retry routing and sending the payment.
|
- SHOULD then retry routing and sending the payment.
|
||||||
- MAY use the data specified in the various types of failure for debugging
|
- MAY use the data specified in the various failure types for debugging
|
||||||
purposes.
|
purposes.
|
||||||
|
|
||||||
# Test Vector
|
# Test Vector
|
||||||
|
|
||||||
## Packet Creation
|
## Packet Creation
|
||||||
|
|
||||||
The following is an in-depth trace of the packet creation, including intermediate data.
|
The following is an in-depth trace (including intermediate data) of an example
|
||||||
|
of packet creation:
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
|
@ -816,8 +830,8 @@ The HMAC is omitted in the following `hop_data`, since it's likely to be filled
|
||||||
by the onion construction. Hence, the values below are the `realm`, the
|
by the onion construction. Hence, the values below are the `realm`, the
|
||||||
`short_channel_id`, the `amt_to_forward`, the `outgoing_cltv`, and the 16-byte
|
`short_channel_id`, the `amt_to_forward`, the `outgoing_cltv`, and the 16-byte
|
||||||
`padding`. They were initialized by byte-filling the `short_channel_id` to the
|
`padding`. They were initialized by byte-filling the `short_channel_id` to the
|
||||||
respective position in the route and then (starting at 0) setting
|
each hop's respective position in the route and then, starting at 0, setting
|
||||||
`amt_to_forward` and `outgoing_cltv` to the appropriate position in the route.
|
`amt_to_forward` and `outgoing_cltv` to same route position.
|
||||||
|
|
||||||
hop_payload[0] = 0x000000000000000000000000000000000000000000000000000000000000000000
|
hop_payload[0] = 0x000000000000000000000000000000000000000000000000000000000000000000
|
||||||
hop_payload[1] = 0x000101010101010101000000010000000100000000000000000000000000000000
|
hop_payload[1] = 0x000101010101010101000000010000000100000000000000000000000000000000
|
||||||
|
@ -894,7 +908,7 @@ respective position in the route and then (starting at 0) setting
|
||||||
|
|
||||||
## Returning Errors
|
## Returning Errors
|
||||||
|
|
||||||
The same parameters (node IDs, shared secrets, ...) as above are used.
|
The same parameters (node IDs, shared secrets, etc.) as above are used.
|
||||||
|
|
||||||
# node 4 is returning an error
|
# node 4 is returning an error
|
||||||
failure_message = 2002
|
failure_message = 2002
|
||||||
|
|
Loading…
Add table
Reference in a new issue