mirror of
https://github.com/lightning/bolts.git
synced 2025-01-18 21:32:31 +01:00
BOLT-4 Re-Edits
Minor edits, clarifications, and standardizations.
This commit is contained in:
parent
46c454cb56
commit
29ae44ec6e
@ -15,18 +15,18 @@ 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
|
||||
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. Knowing each intermediate hop's public key
|
||||
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, including the final recipient node. The shared secret is then
|
||||
used to generate a _pseudo-random stream_ of bytes (used to obfuscate
|
||||
the packet) and a number of _keys_ (used to encrypt the payload and
|
||||
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.
|
||||
|
||||
@ -68,7 +68,7 @@ A node:
|
||||
|
||||
There are a number of conventions adhered to throughout this document:
|
||||
|
||||
- The maximum route length is limited to 20 hops.
|
||||
- Length: the maximum route length is limited to 20 hops.
|
||||
- HMAC: the integrity verification of the packet is based on Keyed-Hash
|
||||
Message Authentication Code, as defined by the
|
||||
[FIPS 198 Standard](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf)/[RFC 2104](https://tools.ietf.org/html/rfc2104),
|
||||
@ -120,6 +120,7 @@ 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 zero-nonce (`0x00000000000000`).
|
||||
|
||||
The use of a fixed nonce is safe, since the keys are never reused.
|
||||
|
||||
# Packet Structure
|
||||
@ -129,11 +130,11 @@ The packet consists of four sections:
|
||||
- a `version` byte
|
||||
- a 33-byte compressed `secp256k1` `public_key`, used during the shared secret
|
||||
generation
|
||||
- a 1300-byte `hops_data` consisting of 20 fixed-size packets, each containing
|
||||
- a 1300-byte `hops_data` consisting of twenty fixed-size packets, each containing
|
||||
information to be used by its associated hop during message forwarding
|
||||
- a 32-byte `HMAC`, used to verify the packet's integrity
|
||||
|
||||
The network format of the packet consists of the individual sections being
|
||||
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.
|
||||
@ -150,7 +151,7 @@ The overall structure of the packet is as follows:
|
||||
For this specification (_version 0_), `version` has a constant value of `0x00`.
|
||||
|
||||
The `hops_data` field is a structure that holds obfuscations of the next hop's
|
||||
address, transfer information, and its associated HMAC. It is 1300 bytes long
|
||||
address, transfer information, and its associated HMAC. It is 1300 bytes (`20x65`) long
|
||||
and has the following structure:
|
||||
|
||||
1. type: `hops_data`
|
||||
@ -161,13 +162,13 @@ and has the following structure:
|
||||
* ...
|
||||
* `filler`
|
||||
|
||||
Where, the `realm`, `HMAC`, and `per_hop` (of which contents depend on `realm`)
|
||||
Where, the `realm`, `per_hop` (with contents dependent on `realm`), and `HMAC`
|
||||
are repeated for each hop; and where, `filler` consists of obfuscated,
|
||||
deterministically-generated padding, as detailed in
|
||||
[Filler Generation](#filler-generation). Additionally, `hops_data` is
|
||||
incrementally obfuscated at each hop.
|
||||
|
||||
The `realm` byte determines the format of the `per_hop`; currently, only `realm`
|
||||
The `realm` byte determines the format of the `per_hop` field; currently, only `realm`
|
||||
0 is defined, for which the `per_hop` format follows:
|
||||
|
||||
1. type: `per_hop` (for `realm` 0)
|
||||
@ -177,15 +178,17 @@ The `realm` byte determines the format of the `per_hop`; currently, only `realm`
|
||||
* [`4`:`outgoing_cltv_value`]
|
||||
* [`12`:`padding`]
|
||||
|
||||
Using the `per_hop`, the origin node is able to precisely specify the path and
|
||||
Using the `per_hop` field, the origin node is able to precisely specify the path and
|
||||
structure of the HTLCs forwarded at each hop. As the `per_hop` 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, in addition to
|
||||
cross-checking the HTLC parameters with the `per_hop`'s specified values, each
|
||||
hop is able to ensure the sending peer hasn't forwarded it an
|
||||
Using this end-to-end authentication,
|
||||
each
|
||||
hop is able to
|
||||
cross-check the HTLC parameters with the `per_hop`'s specified values
|
||||
and to ensure that the sending peer hasn't forwarded an
|
||||
ill-crafted HTLC.
|
||||
|
||||
Field descriptions:
|
||||
@ -197,9 +200,9 @@ Field descriptions:
|
||||
receiving peer specified within the routing information.
|
||||
|
||||
This value amount MUST include the origin node's computed _fee_ for the
|
||||
receiving peer. When processing an incoming Sphinx packet, along with the HTLC
|
||||
receiving peer. When processing an incoming Sphinx packet and the HTLC
|
||||
message that it is encapsulated within, if the following inequality doesn't hold,
|
||||
then the HTLC should be rejected; as this indicates a prior hop has
|
||||
then the HTLC should be rejected as it would indicate that a prior hop has
|
||||
deviated from the specified parameters:
|
||||
|
||||
incoming_htlc_amt - fee >= amt_to_forward
|
||||
@ -217,9 +220,9 @@ Field descriptions:
|
||||
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 there is no next hop, `cltv_expiry_delta` is 0.
|
||||
If the values don't correspond, then the HTLC should be failed and rejected as
|
||||
If the values don't correspond, then the HTLC should be failed and rejected, as
|
||||
this indicates that either a forwarding node has tampered with the intended HTLC
|
||||
values, or the origin node has an obsolete `cltv_expiry_delta` value.
|
||||
values or that the origin node has an obsolete `cltv_expiry_delta` value.
|
||||
The hop MUST be consistent in responding to an unexpected
|
||||
`outgoing_cltv_value`, whether it is the final node or not, to avoid
|
||||
leaking its position in the route.
|
||||
@ -254,7 +257,7 @@ simply discard its payload.
|
||||
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. The nodes `n_i` and
|
||||
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
|
||||
@ -312,7 +315,7 @@ following operations:
|
||||
|
||||
- The _rho_-key and _mu_-key are generated using the hop's shared secret.
|
||||
- The `hops_data` field is right-shifted by 65 bytes, discarding the last 65
|
||||
bytes that exceed its 1300 byte size.
|
||||
bytes that exceed its 1300-byte size.
|
||||
- The `version`, `short_channel_id`, `amt_to_forward`, `outgoing_cltv_value`,
|
||||
`padding`, and `HMAC` are copied into the following 65 bytes.
|
||||
- The _rho_-key is used to generate 1300 bytes of pseudo-random byte stream
|
||||
@ -399,8 +402,9 @@ func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey
|
||||
|
||||
# Packet Forwarding
|
||||
|
||||
This specification is limited to `version` `0` packets; however, the structure
|
||||
This specification is limited to `version` `0` packets; the structure
|
||||
of future versions may change.
|
||||
|
||||
Upon receiving a packet, a processing node compares the version byte of the
|
||||
packet with its own supported versions and aborts the connection if the packet
|
||||
specifies a version number that it doesn't support.
|
||||
@ -443,8 +447,8 @@ processing hop is the intended recipient and that the packet should not be forwa
|
||||
|
||||
If the HMAC does not indicate route termination, and if the next hop is a peer of the
|
||||
processing node; then the new packet is assembled. Packet assembly is accomplished
|
||||
by blinding the ephemeral key with the processing node's public key along with the
|
||||
shared secret and by serializing the `hops_data`.
|
||||
by blinding the ephemeral key with the processing node's public key, along with the
|
||||
shared secret, and by serializing the `hops_data`.
|
||||
The resulting packet is then forwarded to the addressed peer.
|
||||
|
||||
## Requirements
|
||||
@ -474,10 +478,10 @@ The processing node:
|
||||
|
||||
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.
|
||||
The shared secret builder function takes a public key and a 32-byte secret
|
||||
,as inputs, and returns a 32-byte secret, as output.
|
||||
The shared secret builder function takes a public key and a 32-byte secret,
|
||||
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 hop's public key, which is blinded by all previous blinding
|
||||
factors.
|
||||
During the processing phase, the secret is the hop's (processing node's) private
|
||||
@ -485,7 +489,7 @@ key, while the public key is the ephemeral public key from the packet, which has
|
||||
been incrementally blinded by its predecessors.
|
||||
|
||||
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`, and the resulting hash is returned as the shared secret.
|
||||
Notice that this is the ECDH variant implemented in `libsecp256k1`.
|
||||
|
||||
@ -544,7 +548,7 @@ func generateFiller(key string, numHops int, hopSize int, sharedSecrets [][share
|
||||
}
|
||||
```
|
||||
|
||||
Notice that this example implementation is for demonstration purposes only; the
|
||||
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.
|
||||
@ -857,11 +861,11 @@ of packet creation:
|
||||
|
||||
### Parameters
|
||||
|
||||
pubkey[0] 0x02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619
|
||||
pubkey[1] 0x0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c
|
||||
pubkey[2] 0x027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007
|
||||
pubkey[3] 0x032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991
|
||||
pubkey[4] 0x02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145
|
||||
pubkey[0] = 0x02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619
|
||||
pubkey[1] = 0x0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c
|
||||
pubkey[2] = 0x027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007
|
||||
pubkey[3] = 0x032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991
|
||||
pubkey[4] = 0x02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145
|
||||
|
||||
nhops = 5/20
|
||||
sessionkey = 0x4141414141414141414141414141414141414141414141414141414141414141
|
||||
|
Loading…
Reference in New Issue
Block a user