bolt4

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

IMPL1.md (4131B)


      1 # IMPL1: Cryptographic Primitives
      2 
      3 **Module**: `Lightning.Protocol.BOLT4.Prim`
      4 
      5 **Dependencies**: ppad-secp256k1, ppad-sha256, ppad-hmac-sha256, ppad-chacha
      6 
      7 **Can run in parallel with**: IMPL2 (Types/Codec)
      8 
      9 ## Overview
     10 
     11 Implement the low-level cryptographic operations used throughout BOLT4.
     12 
     13 ## Types
     14 
     15 ```haskell
     16 -- | 32-byte shared secret derived from ECDH.
     17 newtype SharedSecret = SharedSecret BS.ByteString
     18 
     19 -- | 32-byte derived key (rho, mu, um, pad, ammag).
     20 newtype DerivedKey = DerivedKey BS.ByteString
     21 
     22 -- | 32-byte blinding factor for ephemeral key updates.
     23 newtype BlindingFactor = BlindingFactor BS.ByteString
     24 ```
     25 
     26 ## Functions to Implement
     27 
     28 ### Key Derivation
     29 
     30 Derive keys from shared secret using HMAC-SHA256 with key-type prefix:
     31 
     32 ```haskell
     33 -- | Derive rho key for obfuscation stream generation.
     34 -- rho = HMAC-SHA256(key="rho" (0x72686f), data=shared_secret)
     35 deriveRho :: SharedSecret -> DerivedKey
     36 
     37 -- | Derive mu key for HMAC computation.
     38 -- mu = HMAC-SHA256(key="mu" (0x6d75), data=shared_secret)
     39 deriveMu :: SharedSecret -> DerivedKey
     40 
     41 -- | Derive um key for return error HMAC.
     42 -- um = HMAC-SHA256(key="um" (0x756d), data=shared_secret)
     43 deriveUm :: SharedSecret -> DerivedKey
     44 
     45 -- | Derive pad key for filler generation.
     46 -- pad = HMAC-SHA256(key="pad" (0x706164), data=shared_secret)
     47 derivePad :: SharedSecret -> DerivedKey
     48 
     49 -- | Derive ammag key for error obfuscation.
     50 -- ammag = HMAC-SHA256(key="ammag" (0x616d6d6167), data=shared_secret)
     51 deriveAmmag :: SharedSecret -> DerivedKey
     52 ```
     53 
     54 ### Shared Secret Computation
     55 
     56 ```haskell
     57 -- | Compute shared secret from ECDH.
     58 -- shared_secret = SHA256(ECDH(priv, pub))
     59 -- where ECDH result is serialized as compressed point (33 bytes).
     60 computeSharedSecret
     61   :: Secp256k1.SecKey  -- ^ private key
     62   -> Secp256k1.PubKey  -- ^ public key
     63   -> SharedSecret
     64 ```
     65 
     66 ### Blinding Factor
     67 
     68 ```haskell
     69 -- | Compute blinding factor for ephemeral key updates.
     70 -- blinding_factor = SHA256(ephemeral_pubkey || shared_secret)
     71 computeBlindingFactor
     72   :: Secp256k1.PubKey  -- ^ ephemeral public key (33 bytes compressed)
     73   -> SharedSecret
     74   -> BlindingFactor
     75 ```
     76 
     77 ### Ephemeral Key Blinding
     78 
     79 ```haskell
     80 -- | Blind a public key by multiplying with blinding factor.
     81 -- new_pubkey = pubkey * blinding_factor
     82 blindPubKey
     83   :: Secp256k1.PubKey
     84   -> BlindingFactor
     85   -> Maybe Secp256k1.PubKey
     86 
     87 -- | Blind a private key by multiplying with blinding factor.
     88 -- new_seckey = seckey * blinding_factor
     89 blindSecKey
     90   :: Secp256k1.SecKey
     91   -> BlindingFactor
     92   -> Maybe Secp256k1.SecKey
     93 ```
     94 
     95 ### Pseudo-Random Stream
     96 
     97 ```haskell
     98 -- | Generate pseudo-random byte stream using ChaCha20.
     99 -- Uses derived key as ChaCha20 key, 96-bit zero nonce, counter=0.
    100 -- Encrypts zeros to produce keystream.
    101 generateStream
    102   :: DerivedKey  -- ^ rho or ammag key
    103   -> Int         -- ^ desired length
    104   -> BS.ByteString
    105 ```
    106 
    107 ### HMAC Operations
    108 
    109 ```haskell
    110 -- | Compute HMAC-SHA256 for packet integrity.
    111 computeHmac
    112   :: DerivedKey      -- ^ mu key
    113   -> BS.ByteString   -- ^ hop_payloads
    114   -> BS.ByteString   -- ^ associated_data
    115   -> BS.ByteString   -- ^ 32-byte HMAC
    116 
    117 -- | Constant-time HMAC comparison.
    118 verifyHmac
    119   :: BS.ByteString  -- ^ expected
    120   -> BS.ByteString  -- ^ computed
    121   -> Bool
    122 ```
    123 
    124 ## Implementation Notes
    125 
    126 1. The key-type strings are ASCII: "rho", "mu", "um", "pad", "ammag".
    127    These become the HMAC key, shared secret is the message.
    128 
    129 2. For ECDH, use `Secp256k1.ecdh` if available, otherwise multiply
    130    the public key by the private key and serialize compressed.
    131 
    132 3. Blinding factor is used as a scalar for EC multiplication. Parse it
    133    as a secret key (mod curve order) then use tweak operations.
    134 
    135 4. ChaCha20 zero nonce: `BS.replicate 12 0`.
    136 
    137 5. All operations should be strict to avoid space leaks.
    138 
    139 ## Test Vectors
    140 
    141 From BOLT4 spec, using session key 0x4141...41 (32 bytes of 0x41):
    142 
    143 ```
    144 hop 0 pubkey: 02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619
    145 hop 0 shared secret: 53eb63ea8a3fec3b3cd433b85cd62a4b145e1dda09391b348c4e1cd36a03ea66
    146 hop 0 blinding factor: 2ec2e5da605776054187180343287683aa6a51b4...
    147 ```
    148 
    149 Verify shared secret and blinding factor computations match spec.