packages feed

ppad-bolt4-0.1.0: lib/Lightning/Protocol/BOLT4.hs

{-# OPTIONS_HADDOCK prune #-}

-- |
-- Module: Lightning.Protocol.BOLT4
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Onion routing for the Lightning Network, per BOLT #4
-- (<https://github.com/lightning/bolts/blob/master/04-onion-routing.md>):
-- onion construction and processing, returning errors, and route
-- blinding.
--
-- The examples below assume:
--
-- >>> :set -XOverloadedStrings
-- >>> import qualified Data.ByteString as BS
-- >>> import qualified Lightning.Protocol.BOLT1 as BOLT1
-- >>> import Lightning.Protocol.BOLT4
--
-- Construct a two-hop onion:
--
-- >>> let Just session = secret_key (BS.replicate 32 0x41)
-- >>> let Just alice = secret_key (BS.replicate 32 0x42)
-- >>> let Just bob = secret_key (BS.replicate 32 0x43)
-- >>> let Just scid = BOLT1.short_channel_id 800000 1 0
-- >>> let Just amt = BOLT1.milli_satoshi 100000
-- >>> :{
-- let alice_payload = empty_hop_payload {
--         hp_amt_to_forward      = Just amt
--       , hp_outgoing_cltv_value = Just 800040
--       , hp_short_channel_id    = Just scid
--       }
--     bob_payload = empty_hop_payload {
--         hp_amt_to_forward      = Just amt
--       , hp_outgoing_cltv_value = Just 800000
--       }
--     route = [ Hop (public_key alice) alice_payload
--             , Hop (public_key bob) bob_payload ]
--     payment_hash = BS.replicate 32 0xff
-- :}
-- >>> let Right (onion, secrets) = construct session route payment_hash
--
-- Process it at each hop:
--
-- >>> let Right (Forward fwd) = process alice onion payment_hash Nothing
-- >>> hp_short_channel_id (fwd_payload fwd) == Just scid
-- True
-- >>> let next = fwd_next_packet fwd
-- >>> let Right (Receive rcv) = process bob next payment_hash Nothing
-- >>> hp_outgoing_cltv_value (rcv_payload rcv)
-- Just 800000
--
-- Fail at the final hop, wrap the error at the first, and attribute it
-- at the origin:
--
-- >>> let tlvs = BOLT1.empty_tlv_stream
-- >>> let failure = FailureMessage TemporaryNodeFailure tlvs
-- >>> let Right err = construct_error (rcv_shared_secret rcv) failure
-- >>> let returned = wrap_error (fwd_shared_secret fwd) err
-- >>> unwrap_error secrets returned == Attributed 1 failure
-- True

module Lightning.Protocol.BOLT4 (
  -- * Keys
    SecretKey
  , secret_key
  , public_key
  , SharedSecret
  , shared_secret
  , un_shared_secret

  -- * Onion packets
  , OnionPacket(..)
  , HopPayloads
  , hop_payloads
  , un_hop_payloads
  , Hmac32
  , hmac32
  , un_hmac32
  , encode_onion_packet
  , decode_onion_packet

  -- * Hop payloads
  , HopPayload(..)
  , empty_hop_payload
  , PaymentData(..)
  , PaymentSecret
  , payment_secret
  , un_payment_secret
  , encode_hop_payload
  , decode_hop_payload

  -- * Constructing onions
  , Hop(..)
  , construct
  , ConstructError(..)

  -- * Processing onions
  , process
  , ProcessResult(..)
  , ForwardInfo(..)
  , ReceiveInfo(..)
  , BlindedInfo(..)
  , ProcessError(..)

  -- * Route blinding
  , BlindedPath(..)
  , BlindedHop(..)
  , create_blinded_path
  , BlindingError(..)
  , decrypt_recipient_data
  , BlindedHopData(..)
  , empty_blinded_hop_data
  , PaymentRelay(..)
  , PaymentConstraints(..)
  , encode_blinded_hop_data
  , decode_blinded_hop_data

  -- * Failure messages
  , FailureMessage(..)
  , Failure(..)
  , OnionHash
  , onion_hash
  , un_onion_hash
  , failure_code
  , is_badonion
  , is_perm
  , is_node
  , is_update
  , encode_failure_message
  , decode_failure_message

  -- * Returning errors
  , ErrorPacket(..)
  , construct_error
  , wrap_error
  , unwrap_error
  , Attribution(..)

  -- * Encoding errors
  , DecodeError(..)
  , EncodeError(..)
  ) where

import Lightning.Protocol.BOLT4.Blinding
import Lightning.Protocol.BOLT4.Codec
import Lightning.Protocol.BOLT4.Construct
import Lightning.Protocol.BOLT4.Error
import Lightning.Protocol.BOLT4.Prim
import Lightning.Protocol.BOLT4.Process
import Lightning.Protocol.BOLT4.Types