mirror of
https://github.com/aljazceru/breez-lnd.git
synced 2025-12-17 22:24:21 +01:00
routing: update Sphinx API to include r-hash and per-hop-payload
This commit modifies both the Sphinx packet generation and processing for recent updates to the API. With the version 1 Sphinx specification, the payment hash is now included in the MACs in order to thwart any potential replay attacks. As a result, any attempts to replay previous HTLC packets MUST re-use the same payment hash, meaning that the first-hop node can simply settle the HTLC immediately, thwarting the attacker. Additionally, within the Sphinx packet, each hop now gets a per-hop payload which contains the necessary details (CTLV value, fee, etc) for the node to successfully forward the payment. This per-hop payload is protected by a packet-wide MAC.
This commit is contained in:
70
rpcserver.go
70
rpcserver.go
@@ -564,16 +564,6 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
||||
}
|
||||
rpcsLog.Tracef("[sendpayment] selected route: %v", path)
|
||||
|
||||
// Generate the raw encoded sphinx packet to be
|
||||
// included along with the HTLC add message.
|
||||
// We snip off the first hop from the path as within
|
||||
// the routing table's star graph, we're always the
|
||||
// first hop.
|
||||
sphinxPacket, err := generateSphinxPacket(path[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're in debug HTLC mode, then all outgoing
|
||||
// HTLC's will pay to the same debug rHash. Otherwise,
|
||||
// we pay to the rHash specified within the RPC
|
||||
@@ -585,6 +575,16 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
||||
copy(rHash[:], nextPayment.PaymentHash)
|
||||
}
|
||||
|
||||
// Generate the raw encoded sphinx packet to be
|
||||
// included along with the HTLC add message. We snip
|
||||
// off the first hop from the path as within the
|
||||
// routing table's star graph, we're always the first
|
||||
// hop.
|
||||
sphinxPacket, err := generateSphinxPacket(path[1:], rHash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Craft an HTLC packet to send to the routing
|
||||
// sub-system. The meta-data within this packet will be
|
||||
// used to route the payment through the network.
|
||||
@@ -606,10 +606,11 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
||||
// TODO(roasbeef): semaphore to limit num outstanding
|
||||
// goroutines.
|
||||
go func() {
|
||||
// Finally, send this next packet to the routing layer in order
|
||||
// to complete the next payment.
|
||||
// TODO(roasbeef): this should go through the L3 router once
|
||||
// multi-hop is in place.
|
||||
// Finally, send this next packet to the
|
||||
// routing layer in order to complete the next
|
||||
// payment.
|
||||
// TODO(roasbeef): this should go through the
|
||||
// L3 router once multi-hop is in place.
|
||||
if err := r.server.htlcSwitch.SendHTLC(htlcPkt); err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
@@ -632,10 +633,11 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
||||
// the onion route specified by the passed list of graph vertexes. The blob
|
||||
// returned from this function can immediately be included within an HTLC add
|
||||
// packet to be sent to the first hop within the route.
|
||||
func generateSphinxPacket(vertexes []graph.ID) ([]byte, error) {
|
||||
var dest sphinx.LightningAddress
|
||||
e2eMessage := []byte("test")
|
||||
|
||||
func generateSphinxPacket(vertexes []graph.ID, paymentHash []byte) ([]byte, error) {
|
||||
// First convert all the vertexs from the routing table to in-memory
|
||||
// public key objects. These objects are necessary in order to perform
|
||||
// the series of ECDH operations required to construct the Sphinx
|
||||
// packet below.
|
||||
route := make([]*btcec.PublicKey, len(vertexes))
|
||||
for i, vertex := range vertexes {
|
||||
vertexBytes, err := hex.DecodeString(vertex.String())
|
||||
@@ -651,15 +653,35 @@ func generateSphinxPacket(vertexes []graph.ID) ([]byte, error) {
|
||||
route[i] = pub
|
||||
}
|
||||
|
||||
// Next generate the onion routing packet which allows
|
||||
// us to perform privacy preserving source routing
|
||||
// across the network.
|
||||
var onionBlob bytes.Buffer
|
||||
sphinxPacket, err := sphinx.NewOnionPacket(route, dest,
|
||||
e2eMessage)
|
||||
// Next we generate the per-hop payload which gives each node within
|
||||
// the route the necessary information (fees, CLTV value, etc) to
|
||||
// properly forward the payment.
|
||||
// TODO(roasbeef): properly set CLTV value, payment amount, and chain
|
||||
// within hop paylods.
|
||||
var hopPayloads [][]byte
|
||||
for i := 0; i < len(route); i++ {
|
||||
payload := bytes.Repeat([]byte{byte('A' + i)},
|
||||
sphinx.HopPayloadSize)
|
||||
hopPayloads = append(hopPayloads, payload)
|
||||
}
|
||||
|
||||
sessionKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Next generate the onion routing packet which allows
|
||||
// us to perform privacy preserving source routing
|
||||
// across the network.
|
||||
sphinxPacket, err := sphinx.NewOnionPacket(route, sessionKey,
|
||||
hopPayloads, paymentHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Finally, encode Sphinx packet using it's wire represenation to be
|
||||
// included within the HTLC add packet.
|
||||
var onionBlob bytes.Buffer
|
||||
if err := sphinxPacket.Encode(&onionBlob); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user