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.