From BOLT 08 we can see that every message is sent in the following way:

2 byte: length
16 byte: MAC 
[length] byte: Encrypted message
16 byte: MAC 

In reality these messages will be send over TCP/IP on the internet. The ip header specifies the length of the data package that is being sent. If we extract the length and subtract 34 byte for the header plus the two MACs we would know how long the message is.

Is the idea to always send a 2^16 byte ip package and fill the rest with junk data? If yes why isn't that specified in the BOLTs? If no: why encrypting the length anyway?

I assume that an attacker would be able track all tcp/ip packages on the lightning port and would at least be able to deduct which messages are being sent even though the messages themselves are safe.

Assume the message length can indeed be deduced can't that be used together with the MAC to reconstruct the session key for that message?

1 Answer 1


TCP and other stream based protocols do not have a 1-to-1 correlation of application level messages and IP packets. If you call send() 3 times, it might result in sending a single IP packet over the wire (eg, due to Nagle's algorithm which is enabled by default), it might get sent individually as 3 packets, as you would expect from a packet oriented protocol like UDP, or the messages might end up being split into several packets each because the IP layer has an MTU.

It is generally out of your control at the application layer. You therefore, cannot rely on reading the length from the IP header to tell you about the length of messages. You need to encode the lengths into the data stream and reconstruct the data coming in from the stream into the individual messages as understood by your protocol.

The reason to encode the length separately in the BOLT#8 specification is that each message must be decrypted as a single operation, because each decryption must increase the counter used in the ChaChaPoly cipher. You need to know the exact length of the message before calling the decrypt function on the encrypted payload.

In the BOLT#8 protocol, you send the exact lengths of the encrypted message+MAC, with no padding added. The receiver should first explicitly call recv(buffer, 18, ...), decrypt the result to get msg_len, then call recv(buffer, msg_len, ...) to retrieve the encrypted message, which can then be decrypted in full. recv may also return fewer bytes than requested, so in both cases, the result of recv must be checked and if less than the expected length is read, recv should be called again with the remaining expected length.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.