bolt4

Onion routing protocol, per BOLT #4 (docs.ppad.tech/bolt4).
git clone git://git.ppad.tech/bolt4.git
Log | Files | Refs | README | LICENSE

IMPL6.md (6567B)


      1 # IMPL6: Route Blinding
      2 
      3 **Module**: `Lightning.Protocol.BOLT4.Blinding`
      4 
      5 **Dependencies**: IMPL1 (Prim), IMPL2 (Types, Codec)
      6 
      7 **Can run in parallel with**: IMPL3, IMPL4, IMPL5 (after IMPL1 and IMPL2 complete)
      8 
      9 **Priority**: Lower - can be deferred. Core functionality works without this.
     10 
     11 ## Overview
     12 
     13 Route blinding allows a recipient to provide a "blinded path" that hides
     14 the identities of nodes in the path. The sender constructs a route to
     15 the introduction point, then the blinded path takes over.
     16 
     17 ## Types
     18 
     19 ```haskell
     20 -- | A blinded route provided by recipient.
     21 data BlindedPath = BlindedPath
     22   { bpIntroductionNode :: !Secp256k1.PubKey  -- first node (unblinded)
     23   , bpBlindingKey      :: !Secp256k1.PubKey  -- E_0, initial ephemeral
     24   , bpBlindedHops      :: ![BlindedHop]
     25   } deriving (Eq, Show)
     26 
     27 -- | A single hop in a blinded path.
     28 data BlindedHop = BlindedHop
     29   { bhBlindedNodeId   :: !BS.ByteString     -- 33 bytes, blinded pubkey
     30   , bhEncryptedData   :: !BS.ByteString     -- encrypted routing data
     31   } deriving (Eq, Show)
     32 
     33 -- | Data encrypted for each blinded hop (before encryption).
     34 data BlindedHopData = BlindedHopData
     35   { bhdPadding          :: !(Maybe BS.ByteString)  -- TLV 1
     36   , bhdShortChannelId   :: !(Maybe ShortChannelId) -- TLV 2
     37   , bhdNextNodeId       :: !(Maybe BS.ByteString)  -- TLV 4, 33-byte pubkey
     38   , bhdPathId           :: !(Maybe BS.ByteString)  -- TLV 6
     39   , bhdNextPathKeyOverride :: !(Maybe BS.ByteString) -- TLV 8
     40   , bhdPaymentRelay     :: !(Maybe PaymentRelay)   -- TLV 10
     41   , bhdPaymentConstraints :: !(Maybe PaymentConstraints) -- TLV 12
     42   , bhdAllowedFeatures  :: !(Maybe BS.ByteString)  -- TLV 14
     43   } deriving (Eq, Show)
     44 
     45 -- | Payment relay parameters (TLV 10).
     46 data PaymentRelay = PaymentRelay
     47   { prCltvExpiryDelta    :: {-# UNPACK #-} !Word16
     48   , prFeeProportional    :: {-# UNPACK #-} !Word32  -- millionths
     49   , prFeeBaseMsat        :: {-# UNPACK #-} !Word32
     50   } deriving (Eq, Show)
     51 
     52 -- | Payment constraints (TLV 12).
     53 data PaymentConstraints = PaymentConstraints
     54   { pcMaxCltvExpiry      :: {-# UNPACK #-} !Word32
     55   , pcHtlcMinimumMsat    :: {-# UNPACK #-} !Word64
     56   } deriving (Eq, Show)
     57 ```
     58 
     59 ## Path Creation (Recipient)
     60 
     61 ```haskell
     62 -- | Create a blinded path from a list of nodes.
     63 --
     64 -- The recipient generates this and shares it (e.g., in an invoice).
     65 createBlindedPath
     66   :: BS.ByteString       -- ^ 32-byte random seed for ephemeral key
     67   -> [(Secp256k1.PubKey, BlindedHopData)]  -- ^ nodes with their data
     68   -> Either Error BlindedPath
     69 
     70 -- | Errors during blinded path creation.
     71 data BlindingError
     72   = InvalidSeed
     73   | EmptyPath
     74   | InvalidNodeKey Int
     75   deriving (Eq, Show)
     76 ```
     77 
     78 ## Path Processing (Blinded Node)
     79 
     80 ```haskell
     81 -- | Process a packet at a blinded node.
     82 --
     83 -- Takes the node's private key, the path key (blinding point), and
     84 -- the encrypted data. Returns decrypted routing data and next path key.
     85 processBlindedHop
     86   :: Secp256k1.SecKey    -- ^ node's private key
     87   , Secp256k1.PubKey     -- ^ E_i, current path key (blinding point)
     88   -> BS.ByteString       -- ^ encrypted_data from onion payload
     89   -> Either Error (BlindedHopData, Secp256k1.PubKey)
     90   -- ^ (decrypted data, E_{i+1} next path key)
     91 ```
     92 
     93 ## Internal Functions
     94 
     95 ### Key Derivation for Blinding
     96 
     97 ```haskell
     98 -- | Derive blinded node ID.
     99 -- B_i = HMAC256("blinded_node_id", ss_i) * N_i
    100 deriveBlindedNodeId
    101   :: SharedSecret        -- ^ ss_i
    102   -> Secp256k1.PubKey    -- ^ N_i, node's real pubkey
    103   -> Maybe BS.ByteString -- ^ blinded pubkey bytes
    104 
    105 -- | Derive rho key for encrypting hop data.
    106 -- Same as regular rho but used with ChaCha20-Poly1305.
    107 deriveBlindingRho :: SharedSecret -> DerivedKey
    108 ```
    109 
    110 ### Ephemeral Key Iteration
    111 
    112 ```haskell
    113 -- | Compute next ephemeral key pair for path creation.
    114 -- e_{i+1} = SHA256(E_i || ss_i) * e_i
    115 -- E_{i+1} = SHA256(E_i || ss_i) * E_i
    116 nextEphemeral
    117   :: Secp256k1.SecKey    -- ^ e_i
    118   -> Secp256k1.PubKey    -- ^ E_i
    119   -> SharedSecret        -- ^ ss_i
    120   -> Maybe (Secp256k1.SecKey, Secp256k1.PubKey)  -- ^ (e_{i+1}, E_{i+1})
    121 ```
    122 
    123 ### Encryption
    124 
    125 ```haskell
    126 -- | Encrypt hop data with ChaCha20-Poly1305.
    127 --
    128 -- Uses rho key and 12-byte zero nonce.
    129 -- NOTE: This requires AEAD, unlike regular packet obfuscation.
    130 encryptHopData
    131   :: DerivedKey          -- ^ rho key
    132   -> BlindedHopData      -- ^ plaintext data
    133   -> BS.ByteString       -- ^ ciphertext with auth tag
    134 
    135 -- | Decrypt hop data with ChaCha20-Poly1305.
    136 decryptHopData
    137   :: DerivedKey          -- ^ rho key
    138   -> BS.ByteString       -- ^ ciphertext with auth tag
    139   -> Maybe BlindedHopData
    140 ```
    141 
    142 ## Path Creation Algorithm
    143 
    144 ```
    145 createBlindedPath(seed, nodes):
    146   1. (e_0, E_0) = keypair from seed
    147   2. introduction_node = nodes[0].pubkey
    148 
    149   3. blinded_hops = []
    150   4. e_i, E_i = e_0, E_0
    151 
    152   For each (N_i, data_i) in nodes:
    153     5. ss_i = SHA256(ECDH(e_i, N_i))
    154     6. rho_i = deriveBlindingRho(ss_i)
    155     7. B_i = deriveBlindedNodeId(ss_i, N_i)
    156     8. encrypted_i = encryptHopData(rho_i, data_i)
    157     9. blinded_hops.append(BlindedHop(B_i, encrypted_i))
    158     10. (e_i, E_i) = nextEphemeral(e_i, E_i, ss_i)
    159 
    160   11. return BlindedPath(introduction_node, E_0, blinded_hops)
    161 ```
    162 
    163 ## Hop Processing Algorithm
    164 
    165 ```
    166 processBlindedHop(node_seckey, path_key, encrypted_data):
    167   1. ss = SHA256(ECDH(node_seckey, path_key))
    168   2. rho = deriveBlindingRho(ss)
    169 
    170   3. hop_data = decryptHopData(rho, encrypted_data)
    171      If decryption fails: return error
    172 
    173   4. Check for next_path_key_override in hop_data
    174      If present: E_next = override value
    175      Else: E_next = SHA256(path_key || ss) * path_key
    176 
    177   5. return (hop_data, E_next)
    178 ```
    179 
    180 ## Integration with Packet Construction
    181 
    182 When constructing a packet with a blinded suffix:
    183 
    184 1. Construct normal hops up to introduction point
    185 2. At introduction point, include `current_path_key` (TLV 12) = E_0
    186 3. For blinded hops, use blinded node IDs as "pubkeys" and include
    187    `encrypted_recipient_data` (TLV 10) from BlindedHop
    188 
    189 The blinded nodes don't know their position or the path structure.
    190 
    191 ## Implementation Notes
    192 
    193 1. Route blinding uses ChaCha20-Poly1305 (AEAD), not plain ChaCha20.
    194    This may require ppad-aead as dependency.
    195 
    196 2. The "blinded node ID" is a tweaked public key. Nodes must be able
    197    to derive the corresponding private key tweak.
    198 
    199 3. path_key_override allows path creators to inject specific keys,
    200    useful for multi-path scenarios.
    201 
    202 4. This is an optional feature. Core BOLT4 works without it.
    203 
    204 ## Test Vectors
    205 
    206 The spec includes blinded path test vectors. Key values to verify:
    207 - Blinded node ID derivation
    208 - Encrypted data for each hop
    209 - Path key iteration
    210 - Decryption at each blinded node