[Lightning-dev] An Alternative Onion-Routing Proposal

Olaoluwa Osuntokun laolu32 at gmail.com
Mon Dec 14 22:04:01 UTC 2015

Hi y'all!!

So I've been drafting up some schemes for the design of onion routing
within the
Lightning Network myself. Rather than create my own mixing format, and
routing protocol, I've instead turned to some of the existing academic
concerning the subject. I found two schemes, the first building upon the
other, which seem to fit elegantly into our problem domain, directly solving
many problems we've encountered along the way.

The two schemes of interest are first Sphinx[1]: a compact mixing format,
HORNET[2][3], which leverages Sphinx to build a low-latency, high-bandwidth
onion routing protocol.

Alright, let's jump into and overview of both schemes!

(heads up, this post is a bit long as it includes a brain dump of ideas
been been floating around in my head for the past two months or so)

First, I'll give a brief overview of Sphinx. I won't delve into the exact
details of the protocol, instead I'll highlight the key insight that allows
*extremely* small mix-headers. If we assume a maximum diameter of 20 hops,
and a
16-byte MAC, then a full onion blob weighs in at only 705 bytes! This is
considerably smaller (a 4X size reduction) than the 3840 bytes per
onion-blob in
current proposal. I recommend consulting the paper for the proper
Additionally the paper includes a formal proof of security in the Universal
Composability model[4], achieving each of the 4 properties outlined for a
onion routing protocol in [5].

(btw, don't dismiss figures 1 and 2 in the Sphinx paper. They may look
but finally grokking them resulted in a break through allowing me to finish

So, at this point, y'all may be wondering how Sphinx achieves such compact
mix-headers. Well, Rather, than including a group element to perform DH
for *each* hop in the route, mix-headers in Sphinx only contain a single
element. This single group element is then deterministically re-randomized
each hop in the route, preparing the group element for the hop directly
following it.

Here's a brief sketch of the mechanism (covering only the DH aspects):

Say Alice wants to route a payment to Bob (Y_b) over Lightning. Alice
consults her
routing/service table, and finds a route via Carol and Dave. Next, to
create the
mix-header, Alice grabs key-pairs for Carol (Y_c) and Dave (Y_d). She then
an ephemeral DH key-pair (a_0 = g^x) then proceeds to derive a shared
for each hop in the route. Using multiplicative notation, the DH derivation
looks something like this (s = shared key, b = blinding factor):
  * a_0 = g^x,       s_0 = (Y_c)^x,         b_0 = hash(a_0, s_0)
  * a_1 = (a_0)^b_0, s_1 = (Y_d)^x*b_0,     b_1 = hash(a_1, s_1)
  * a_2 = (a_1)^b_1, s_2 = (Y_b)^x*b_0*b_1, b_2 = hash(a_2, s_2)
  ......... continued if more hops were in the route ..........

Alice computes all the blinding factors and shared secrets up front,
her to create the mix-header for each hop using the derived hop shared
to derive subsequent decryption and MAC keys. Each node receives a_{i}, and
prepares a_{i+1} for the next hop by re-randomizing the group element using
blinding factor.

The formula for computing the size of a mix-header for a given hop count,
security parameter is (ignoring the final message size):
  * p + (2r + 2)s
    * p = pub key size (in bytes, for DH each hop)
    * r = max number of hops
    * s = symmetric key size (in bytes)

So, for 20 hops the size is computed as (with a symmetric key size of 16
  * 33 + (2*20 + 2) * 16 = 705 bytes!

445% smaller than the 3840 bytes of the current proposal.

The original version of Sphinx was designed with anonymous mailing in mind.
So the final mix-header to the destination node includes a final
email-address (k-bits), and an Identifier (k-bits) used to generate reply
messages back to the sender. If we remove these from the mix-net, we save
2k-bits arriving at a new formula to compute the mix-header size:
  * p + (2*r*s)

So with 20 hops the size is reduced to:
  * 33 + (2*20*16) = 673 bytes

With this size reduction the, the base64 encoding of a mix-header for two
can fit entirely into a tweet!
  * 33 + (2*2*16) = 97 bytes

However, it occurred to me that the final destination address may be useful
the context of a more hub-and-spoke-y network. In this scheme the payment
be routed to a "shared node", who would then use the destination address to
demultiplexing the payment to one of its connected links in a "host:port"

Finally, Sphinx has built-in protection for replay attacks. Meaning an
is unable to force a node to process a previously processed mix-header. It
achieves this protection by having all nodes remember every derived shard
it has ever come across. However, within the paper, the extent of the past
which a node is to recall is unspecified, leading to potentially large
overhead. However, it's worth noting that the paper recommends frequent key
rotation, during which this table may be safely cleared. Additionally,
nodes may
also employ a decaying bloom-filter/hash-set [6] for use in-between key
rotations to create an upper bound on the storage overhead.

With that said, Sphinx is much more compact than the current proposal,
a formal proof of security, and specifies replay protection.

It was recently brought up in [7], that allowing nodes to use onion routing
Lightning as an end-to-end messaging interface. This is where HORNET comes
One could use Sphinx's Single-Use-Reply-Blocks to allow the recipient to
communicate with the sender after a dummy onion circuit has been set up.
However, this introduces some performance considerations, due to Sphinx
each hop to perform 2 asymmetric crypto operations (shared secret
derivation + group element blinding)
before forwarding. HORNET gets around this performance issue by first using
to set up a duplex onion circuit between sender and receiver, which after
set up,
only requires nodes to compute purely symmetric crypto operations before

Continuing, both Sphinx and the current proposal only provide sender
Meaning that only the source maintains unlinkability, therefore it learns
destination's location. The addition of HORNET allows both side to retain
unlinkability. HORNET has a built-in, an optional rendezvous protocol,
which is
a bit similar to the way Hidden Services in TOR work.

With that said, what follows is a brief high-level overview of the HORNET
protocol (focusing on the initial set up, instead of data transmission).

Unlike Sphinx, which is essentially a "fire-and-forget" onion routing
from the view of the sender, HORNET requires a cumulative circuit
as a set up phase before messaging can begin. Once completed, this set up
creates a duplex onion circuit between the sender and destination, allowing
level of throughput approaching 93 Gb/s as reported experimentation section
the paper.

The primary addition to Sphinx's mix-header format is something they've
dubbed the
Anonymous Header (AHDR). Instead of requiring each node in the mix-net to
per-session state (which would prohibit scale in large networks), all
is instead stored within the onion-packet itself. Therefore, each node only
needs to
maintain a local secret. A full AHDR contains contains a series of
Segments (FSes) for each hop, allowing them to decrypt the per-hop onion,
revealing the next hop in the path. Each FS contains: the next hop in the
a TTL value, and a derived shared secret. A full AHDR has the following
  * (FS, MAC, Onion wrapped FSes)

First, let's go over how a duplex onion circuit is achieved, maintaining
unlinkability (once again, using multiplicative notation):
  * Sender Set Up:
    * The sender obtains the current keys for each hop in the path,
      a forward, and backwards path (the reverse of the forward path).
    * The sender then generates a per-session ephemeral DH key-pair: (x,
    * Using the Sphinx protocol described above, then sender then generates
      Sphinx mix-headers: one for the forwards path, and another for the
      path. At this point, the source has derived shared secrets for each
node along
      both paths.
    * The message payload (SP) of the forward Sphinx mix-header (encrypted
to the
      destination), is the backwards Sphinx mix-header which allows the
      to reply to the sender.
    * The Sphinx mix-header (SHDR) is then extended with two additions:
      * A empty list of FSes (P_fs), which each intermediate node can
        without learning the total path length, nor their position within
      * The Sphinx per-hop MAC is also extended over the HORNET Common
        (CHDR): (packet type, hops, TTL)
    * The sender then sends this set up packet to the first node in the
      (CHDR, SHDR, SP, P_fsf)
  * Intermediate Node Set Up:
    * Upon receipt of the Sphinx packet, each node processes it as normal
      (according to Sphinx): deriving the shared secret, recovering the
next hop's
      ID, and re-blinding the group element.
    * Next, the node verifies the next-hop is correct, and that the packet
      hasn't yet expired according to its TTL.
    * In order to provide forward secrecy for the messaging phase,
      the node then derives a new DH key-pair (y, g^y), and then derives a
      shared secret to be included within the FS: (a_i)^y
    * Using it's local shared secret (SV_i), the node creates a FS that
only it
      can decrypt, adding this to the FS payload. This payload entry
      includes the new ephemeral DH-key pair (y, g^y), allowing the source
to derive
      the shared secret which will be used for the FS's MAC (and also when
transmitting data).
    * Finally the node re-assembles the packet (CHDR', SHDR', SP, P_fsf'),
      forwards it to the next hop.
  * Destination Set Up:
    * The destination initially processes the packet identically to the
      nodes described above.
    * It then decrypts the Sphinx payload, uncovering the backwards SHDR.
The node
      then creates a new payload each of the completed FSes in the payload.
      destined to the source.
    * At this point, the destination has no knowledge of any of the derived
      secrets, other than the one it has derived with the source.
    * Next, it creates a new FS list P_fsb, to collect FSes along the
backwards path.
    * Finally, it creates the backwards set up packet (CHDR, SHDR, SP_b,
P_fsb), and
      sends it to the first node on the backwards path.
    * Each intermediate node then processes the backwards packet just as
  * Data Transfer (brief overview, consult the paper for proper details)
    * The source node then recovers the Sphinx payload SP_b, recovering the
      forwarding segments for the forward (P_fsf) and backwards path (P_fsb)
    * At this point, set up has been completed!
    * The source node then constructs two initial AHDR's, one so it can
      messages to the destination via the circuit, and the other which will
      allow the destination to reply to the source.
    * After the first message from S -> D, D obtains the backwards AHDR,
      allowing it to reply without knowing the actual route.

The, the following modifications are necessary to achieve sender-receiver
unlinkability as described earlier. The modification to allow send-receiver
unlinkability is relatively straight forward. It involves nested AHDRs.
say Alice wants to send a message (or a payment in our case) to Bob while
full unlinkability. Bob will first need to select a rendezvous point (RP),
let's call him Rodriguez. Bob then executes the set up protocol detailed
between himself and Rodriguez. As a result, Bob obtains a AHDR allowing
to route messages (via some specified path) to Bob (R -> B). Bob then
this AHDR_rb to some "public bulletin board", or in the case that Alice has
hidden service set up, directly to Alice. Alice then obtains the AHDR_rb,
routing as normal to Rodriguez, but then includes AHDR_rb, nested within
regular AHDR_ar (Alice -> Bob). Once this mix-header reaches Bob, he
recovers the
nested AHDR, allowing him to complete the route to Bob. Additionally, its
for Bob to specify several rendezvous points, allowing Alice to select the
closest/cheapest route to her. As a side effect, the usage  of this nested
doubles the bandwidth required for each node to forward along the path.

With this duplex onion route set up (with or without the RP), Alice can
send a
message to Bob, asking for R (along with other payment details), then
HTLCs along the full path in order to pay Bob. In order to mitigate the
DoS attacks introduced by adding a message layer for control signals, we
either introduce a payment system (as suggested in [8]), or a required
challenge (avoiding SHA-256, using either SHA-3 or BLAKE2). However, seeing
we'd like to maintain the responsiveness of the network, I'm personally
towards payments (if we do in fact deem in network messaging attractive).

Okay, so that concludes my first post on the mailing list! So at this point
y'all may be wondering where the implementation I mentioned above is?
Well, so far I have a working implementation of Sphinx by itself, not yet
integrating the aspects of HORNET, but, it's not yet publicly released.

We (me+Tadge+Joseph) are planning on publicly releasing our in progress
implementation of Lightning, sometime near the end of this month (December)

1. http://www.cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf
2. http://arxiv.org/pdf/1507.05724v1.pdf (HORNET w/ forward secrecy)
3. http://www.scion-architecture.net/pdf/2015-HORNET.pdf
4. https://eprint.iacr.org/2000/067.pdf
5. http://cs.brown.edu/~anna/papers/cl05-full.pdf
6. https://moderncrypto.org/mail-archive/messaging/2015/001906.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linuxfoundation.org/pipermail/lightning-dev/attachments/20151214/996b3701/attachment-0001.html>

More information about the Lightning-dev mailing list