bolt4

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

IMPL5.md (6656B)


      1 # IMPL5: Error Handling
      2 
      3 **Module**: `Lightning.Protocol.BOLT4.Error`
      4 
      5 **Dependencies**: IMPL1 (Prim), IMPL2 (Types, Codec)
      6 
      7 **Can run in parallel with**: IMPL3, IMPL4 (after IMPL1 and IMPL2 complete)
      8 
      9 ## Overview
     10 
     11 Implement failure message construction (by failing node) and
     12 unwrapping/attribution (by origin node).
     13 
     14 ## Types
     15 
     16 ```haskell
     17 -- | Wrapped error packet ready for return to origin.
     18 newtype ErrorPacket = ErrorPacket BS.ByteString
     19   deriving (Eq, Show)
     20 
     21 -- | Result of error attribution.
     22 data AttributionResult
     23   = Attributed !Int !FailureMessage  -- ^ (hop index, failure)
     24   | UnknownOrigin !BS.ByteString     -- ^ Could not attribute
     25   deriving (Eq, Show)
     26 
     27 -- | Minimum error packet size (256 bytes per spec).
     28 minErrorPacketSize :: Int
     29 minErrorPacketSize = 256
     30 ```
     31 
     32 ## Error Construction (Failing Node)
     33 
     34 ```haskell
     35 -- | Construct an error packet at a failing node.
     36 --
     37 -- Takes the shared secret (from processing), failure message,
     38 -- and wraps it for return to origin.
     39 constructError
     40   :: SharedSecret      -- ^ from packet processing
     41   -> FailureMessage    -- ^ failure details
     42   -> ErrorPacket
     43 
     44 -- | Wrap an existing error packet for forwarding back.
     45 --
     46 -- Each intermediate node wraps the error with its own layer.
     47 wrapError
     48   :: SharedSecret      -- ^ this node's shared secret
     49   -> ErrorPacket       -- ^ error from downstream
     50   -> ErrorPacket
     51 ```
     52 
     53 ## Error Unwrapping (Origin Node)
     54 
     55 ```haskell
     56 -- | Attempt to attribute an error to a specific hop.
     57 --
     58 -- Takes the shared secrets from original packet construction
     59 -- (in order from first hop to final) and the error packet.
     60 --
     61 -- Tries each hop's keys until HMAC verifies, revealing origin.
     62 unwrapError
     63   :: [SharedSecret]    -- ^ secrets from construction, in route order
     64   -> ErrorPacket       -- ^ received error
     65   -> AttributionResult
     66 ```
     67 
     68 ## Internal Functions
     69 
     70 ### Error Packet Construction
     71 
     72 ```haskell
     73 -- | Build the inner error message structure.
     74 --
     75 -- Format: HMAC (32) || len (2) || message || pad_len (2) || padding
     76 -- Total must be >= 256 bytes.
     77 buildErrorMessage
     78   :: DerivedKey        -- ^ um key
     79   -> FailureMessage    -- ^ failure to encode
     80   -> BS.ByteString     -- ^ complete message with HMAC
     81 ```
     82 
     83 Algorithm:
     84 1. Encode failure message to bytes
     85 2. Compute padding needed: max(0, 256 - 32 - 2 - msg_len - 2)
     86 3. Build: len (u16 BE) || message || pad_len (u16 BE) || padding
     87 4. Compute HMAC = HMAC-SHA256(um_key, len || message || pad_len || padding)
     88 5. Return: HMAC || len || message || pad_len || padding
     89 
     90 ### Error Obfuscation
     91 
     92 ```haskell
     93 -- | Obfuscate error packet with ammag stream.
     94 --
     95 -- XORs the entire packet (after HMAC) with pseudo-random stream.
     96 obfuscateError
     97   :: DerivedKey        -- ^ ammag key
     98   -> BS.ByteString     -- ^ error packet
     99   -> BS.ByteString     -- ^ obfuscated packet
    100 ```
    101 
    102 Note: The HMAC is computed over plaintext, then the entire packet
    103 including HMAC is XORed with ammag stream.
    104 
    105 ### Error Deobfuscation
    106 
    107 ```haskell
    108 -- | Remove one layer of obfuscation from error packet.
    109 deobfuscateError
    110   :: DerivedKey        -- ^ ammag key
    111   -> BS.ByteString     -- ^ obfuscated packet
    112   -> BS.ByteString     -- ^ deobfuscated packet
    113 
    114 -- | Verify error HMAC after deobfuscation.
    115 verifyErrorHmac
    116   :: DerivedKey        -- ^ um key
    117   -> BS.ByteString     -- ^ deobfuscated packet (HMAC || rest)
    118   -> Bool
    119 ```
    120 
    121 ### Error Parsing
    122 
    123 ```haskell
    124 -- | Parse error message from deobfuscated packet.
    125 parseErrorMessage
    126   :: BS.ByteString     -- ^ packet after HMAC verification
    127   -> Maybe FailureMessage
    128 ```
    129 
    130 ## Construction Algorithm
    131 
    132 At failing node:
    133 
    134 ```
    135 constructError(shared_secret, failure):
    136   1. um = deriveUm(shared_secret)
    137   2. ammag = deriveAmmag(shared_secret)
    138   3. inner = buildErrorMessage(um, failure)
    139   4. obfuscated = obfuscateError(ammag, inner)
    140   5. return ErrorPacket(obfuscated)
    141 ```
    142 
    143 At forwarding node (wrapping existing error):
    144 
    145 ```
    146 wrapError(shared_secret, error_packet):
    147   1. ammag = deriveAmmag(shared_secret)
    148   2. wrapped = obfuscateError(ammag, error_packet)
    149   3. return ErrorPacket(wrapped)
    150 ```
    151 
    152 ## Unwrapping Algorithm
    153 
    154 At origin node:
    155 
    156 ```
    157 unwrapError(shared_secrets, error_packet):
    158   packet = error_packet.bytes
    159 
    160   for i = 0 to len(shared_secrets) - 1:
    161     ammag = deriveAmmag(shared_secrets[i])
    162     um = deriveUm(shared_secrets[i])
    163 
    164     packet = deobfuscateError(ammag, packet)
    165 
    166     if verifyErrorHmac(um, packet):
    167       failure = parseErrorMessage(packet[32:])
    168       return Attributed(i, failure)
    169 
    170   return UnknownOrigin(packet)
    171 ```
    172 
    173 The first hop whose HMAC verifies is the origin of the error.
    174 
    175 ## Failure Codes
    176 
    177 Common failure codes to handle (define in Types, use here):
    178 
    179 ```haskell
    180 -- Flags
    181 badonion, perm, node, update :: Word16
    182 
    183 -- Codes (incomplete list)
    184 invalid_realm                      = perm .|. 1
    185 temporary_node_failure             = node .|. 2
    186 permanent_node_failure             = perm .|. node .|. 2
    187 required_node_feature_missing      = perm .|. node .|. 3
    188 invalid_onion_version              = badonion .|. perm .|. 4
    189 invalid_onion_hmac                 = badonion .|. perm .|. 5
    190 invalid_onion_key                  = badonion .|. perm .|. 6
    191 temporary_channel_failure          = update .|. 7
    192 permanent_channel_failure          = perm .|. 8
    193 amount_below_minimum               = update .|. 11
    194 fee_insufficient                   = update .|. 12
    195 incorrect_cltv_expiry              = update .|. 13
    196 expiry_too_soon                    = update .|. 14
    197 incorrect_or_unknown_payment_details = perm .|. 15
    198 final_incorrect_cltv_expiry        = 18
    199 final_incorrect_htlc_amount        = 19
    200 channel_disabled                   = update .|. 20
    201 expiry_too_far                     = 21
    202 invalid_onion_payload              = perm .|. 22
    203 mpp_timeout                        = 23
    204 ```
    205 
    206 ## Implementation Notes
    207 
    208 1. Error packets are always at least 256 bytes to prevent length-based
    209    traffic analysis.
    210 
    211 2. Each intermediate node adds a layer of encryption (XOR with ammag
    212    stream). Origin peels layers in route order.
    213 
    214 3. HMAC verification at origin: only the actual failing node's HMAC
    215    will verify after exactly the right number of layers are removed.
    216 
    217 4. The BADONION flag indicates the error relates to the onion itself
    218    (HMAC failure, bad key). These get special treatment.
    219 
    220 5. UPDATE flag means the error includes a channel_update message that
    221    the origin should process.
    222 
    223 ## Test Vectors
    224 
    225 From spec, with failure at node 4:
    226 
    227 ```
    228 failure code: incorrect_or_unknown_payment_details (0x400f)
    229 htlc_msat: 100
    230 height: 800000
    231 ```
    232 
    233 Verify:
    234 - Error packet construction produces correct bytes
    235 - Wrapping at each intermediate node matches spec
    236 - Unwrapping at origin correctly attributes to node 4
    237 - Parsed failure message matches original