github.com/decred/dcrlnd@v0.7.6/zpay32/encode.go (about) 1 package zpay32 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 8 "github.com/decred/dcrd/bech32" 9 "github.com/decred/dcrd/chaincfg/chainhash" 10 "github.com/decred/dcrd/txscript/v4/stdaddr" 11 12 "github.com/decred/dcrlnd/lnwire" 13 ) 14 15 // Encode takes the given MessageSigner and returns a string encoding this 16 // invoice signed by the node key of the signer. 17 func (invoice *Invoice) Encode(signer MessageSigner) (string, error) { 18 // First check that this invoice is valid before starting the encoding. 19 if err := validateInvoice(invoice); err != nil { 20 return "", err 21 } 22 23 // The buffer will encoded the invoice data using 5-bit groups (base32). 24 var bufferBase32 bytes.Buffer 25 26 // The timestamp will be encoded using 35 bits, in base32. 27 timestampBase32 := uint64ToBase32(uint64(invoice.Timestamp.Unix())) 28 29 // The timestamp must be exactly 35 bits, which means 7 groups. If it 30 // can fit into fewer groups we add leading zero groups, if it is too 31 // big we fail early, as there is not possible to encode it. 32 if len(timestampBase32) > timestampBase32Len { 33 return "", fmt.Errorf("timestamp too big: %d", 34 invoice.Timestamp.Unix()) 35 } 36 37 // Add zero bytes to the first timestampBase32Len-len(timestampBase32) 38 // groups, then add the non-zero groups. 39 zeroes := make([]byte, timestampBase32Len-len(timestampBase32)) 40 _, err := bufferBase32.Write(zeroes) 41 if err != nil { 42 return "", fmt.Errorf("unable to write to buffer: %v", err) 43 } 44 _, err = bufferBase32.Write(timestampBase32) 45 if err != nil { 46 return "", fmt.Errorf("unable to write to buffer: %v", err) 47 } 48 49 // We now write the tagged fields to the buffer, which will fill the 50 // rest of the data part before the signature. 51 if err := writeTaggedFields(&bufferBase32, invoice); err != nil { 52 return "", err 53 } 54 55 // The human-readable part (hrp) is "ln" + net hrp + optional amount. 56 hrp := "ln" + decredHRPPrefixes[invoice.Net.Name] 57 if invoice.MilliAt != nil { 58 // Encode the amount using the fewest possible characters. 59 am, err := encodeAmount(*invoice.MilliAt) 60 if err != nil { 61 return "", err 62 } 63 hrp += am 64 } 65 66 // The signature is over the single SHA-256 hash of the hrp + the 67 // tagged fields encoded in base256. 68 taggedFieldsBytes, err := bech32.ConvertBits(bufferBase32.Bytes(), 5, 8, true) 69 if err != nil { 70 return "", err 71 } 72 73 toSign := append([]byte(hrp), taggedFieldsBytes...) 74 75 // We use compact signature format, and also encoded the recovery ID 76 // such that a reader of the invoice can recover our pubkey from the 77 // signature. 78 sign, err := signer.SignCompact(toSign) 79 if err != nil { 80 return "", err 81 } 82 83 // From the header byte we can extract the recovery ID, and the last 64 84 // bytes encode the signature. 85 recoveryID := sign[0] - 27 - 4 86 var sig lnwire.Sig 87 copy(sig[:], sign[1:]) 88 89 // If the pubkey field was explicitly set, it must be set to the pubkey 90 // used to create the signature. 91 if invoice.Destination != nil { 92 signature, err := sig.ToSignature() 93 if err != nil { 94 return "", fmt.Errorf("unable to deserialize "+ 95 "signature: %v", err) 96 } 97 98 hash := chainhash.HashB(toSign) 99 valid := signature.Verify(hash, invoice.Destination) 100 if !valid { 101 return "", fmt.Errorf("signature does not match " + 102 "provided pubkey") 103 } 104 } 105 106 // Convert the signature to base32 before writing it to the buffer. 107 signBase32, err := bech32.ConvertBits(append(sig[:], recoveryID), 8, 5, true) 108 if err != nil { 109 return "", err 110 } 111 bufferBase32.Write(signBase32) 112 113 // Now we can create the bech32 encoded string from the base32 buffer. 114 b32, err := bech32.Encode(hrp, bufferBase32.Bytes()) 115 if err != nil { 116 return "", err 117 } 118 119 // Before returning, check that the bech32 encoded string is not greater 120 // than our largest supported invoice size. 121 if len(b32) > maxInvoiceLength { 122 return "", ErrInvoiceTooLarge 123 } 124 125 return b32, nil 126 } 127 128 // writeTaggedFields writes the non-nil tagged fields of the Invoice to the 129 // base32 buffer. 130 func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error { 131 if invoice.PaymentHash != nil { 132 err := writeBytes32(bufferBase32, fieldTypeP, *invoice.PaymentHash) 133 if err != nil { 134 return err 135 } 136 } 137 138 if invoice.Description != nil { 139 base32, err := bech32.ConvertBits([]byte(*invoice.Description), 140 8, 5, true) 141 if err != nil { 142 return err 143 } 144 err = writeTaggedField(bufferBase32, fieldTypeD, base32) 145 if err != nil { 146 return err 147 } 148 } 149 150 if invoice.DescriptionHash != nil { 151 err := writeBytes32( 152 bufferBase32, fieldTypeH, *invoice.DescriptionHash, 153 ) 154 if err != nil { 155 return err 156 } 157 } 158 159 if invoice.minFinalCLTVExpiry != nil { 160 finalDelta := uint64ToBase32(*invoice.minFinalCLTVExpiry) 161 err := writeTaggedField(bufferBase32, fieldTypeC, finalDelta) 162 if err != nil { 163 return err 164 } 165 } 166 167 if invoice.expiry != nil { 168 seconds := invoice.expiry.Seconds() 169 expiry := uint64ToBase32(uint64(seconds)) 170 err := writeTaggedField(bufferBase32, fieldTypeX, expiry) 171 if err != nil { 172 return err 173 } 174 } 175 176 if invoice.FallbackAddr != nil { 177 var version byte 178 switch invoice.FallbackAddr.(type) { 179 case *stdaddr.AddressPubKeyHashEcdsaSecp256k1V0: 180 version = 17 181 case *stdaddr.AddressScriptHashV0: 182 version = 18 183 default: 184 return fmt.Errorf("unknown fallback address type") 185 } 186 base32Addr, err := bech32.ConvertBits( 187 invoice.FallbackAddr.(stdaddr.Hash160er).Hash160()[:], 8, 5, true) 188 if err != nil { 189 return err 190 } 191 192 err = writeTaggedField(bufferBase32, fieldTypeF, 193 append([]byte{version}, base32Addr...)) 194 if err != nil { 195 return err 196 } 197 } 198 199 for _, routeHint := range invoice.RouteHints { 200 // Each hop hint is encoded using 51 bytes, so we'll make to 201 // sure to allocate enough space for the whole route hint. 202 routeHintBase256 := make([]byte, 0, hopHintLen*len(routeHint)) 203 204 for _, hopHint := range routeHint { 205 hopHintBase256 := make([]byte, hopHintLen) 206 copy(hopHintBase256[:33], hopHint.NodeID.SerializeCompressed()) 207 binary.BigEndian.PutUint64( 208 hopHintBase256[33:41], hopHint.ChannelID, 209 ) 210 binary.BigEndian.PutUint32( 211 hopHintBase256[41:45], hopHint.FeeBaseMAtoms, 212 ) 213 binary.BigEndian.PutUint32( 214 hopHintBase256[45:49], hopHint.FeeProportionalMillionths, 215 ) 216 binary.BigEndian.PutUint16( 217 hopHintBase256[49:51], hopHint.CLTVExpiryDelta, 218 ) 219 routeHintBase256 = append(routeHintBase256, hopHintBase256...) 220 } 221 222 routeHintBase32, err := bech32.ConvertBits( 223 routeHintBase256, 8, 5, true, 224 ) 225 if err != nil { 226 return err 227 } 228 229 err = writeTaggedField(bufferBase32, fieldTypeR, routeHintBase32) 230 if err != nil { 231 return err 232 } 233 } 234 235 if invoice.Destination != nil { 236 // Convert 33 byte pubkey to 53 5-bit groups. 237 pubKeyBase32, err := bech32.ConvertBits( 238 invoice.Destination.SerializeCompressed(), 8, 5, true) 239 if err != nil { 240 return err 241 } 242 243 if len(pubKeyBase32) != pubKeyBase32Len { 244 return fmt.Errorf("invalid pubkey length: %d", 245 len(invoice.Destination.SerializeCompressed())) 246 } 247 248 err = writeTaggedField(bufferBase32, fieldTypeN, pubKeyBase32) 249 if err != nil { 250 return err 251 } 252 } 253 if invoice.PaymentAddr != nil { 254 err := writeBytes32( 255 bufferBase32, fieldTypeS, *invoice.PaymentAddr, 256 ) 257 if err != nil { 258 return err 259 } 260 } 261 if invoice.Features.SerializeSize32() > 0 { 262 var b bytes.Buffer 263 err := invoice.Features.RawFeatureVector.EncodeBase32(&b) 264 if err != nil { 265 return err 266 } 267 268 err = writeTaggedField(bufferBase32, fieldType9, b.Bytes()) 269 if err != nil { 270 return err 271 } 272 } 273 274 return nil 275 } 276 277 // writeBytes32 encodes a 32-byte array as base32 and writes it to bufferBase32 278 // under the passed fieldType. 279 func writeBytes32(bufferBase32 *bytes.Buffer, fieldType byte, b [32]byte) error { 280 // Convert 32 byte hash to 52 5-bit groups. 281 base32, err := bech32.ConvertBits(b[:], 8, 5, true) 282 if err != nil { 283 return err 284 } 285 286 return writeTaggedField(bufferBase32, fieldType, base32) 287 } 288 289 // writeTaggedField takes the type of a tagged data field, and the data of 290 // the tagged field (encoded in base32), and writes the type, length and data 291 // to the buffer. 292 func writeTaggedField(bufferBase32 *bytes.Buffer, dataType byte, data []byte) error { 293 // Length must be exactly 10 bits, so add leading zero groups if 294 // needed. 295 lenBase32 := uint64ToBase32(uint64(len(data))) 296 for len(lenBase32) < 2 { 297 lenBase32 = append([]byte{0}, lenBase32...) 298 } 299 300 if len(lenBase32) != 2 { 301 return fmt.Errorf("data length too big to fit within 10 bits: %d", 302 len(data)) 303 } 304 305 err := bufferBase32.WriteByte(dataType) 306 if err != nil { 307 return fmt.Errorf("unable to write to buffer: %v", err) 308 } 309 _, err = bufferBase32.Write(lenBase32) 310 if err != nil { 311 return fmt.Errorf("unable to write to buffer: %v", err) 312 } 313 _, err = bufferBase32.Write(data) 314 if err != nil { 315 return fmt.Errorf("unable to write to buffer: %v", err) 316 } 317 318 return nil 319 } 320 321 // uint64ToBase32 converts a uint64 to a base32 encoded integer encoded using 322 // as few 5-bit groups as possible. 323 func uint64ToBase32(num uint64) []byte { 324 // Return at least one group. 325 if num == 0 { 326 return []byte{0} 327 } 328 329 // To fit an uint64, we need at most is ceil(64 / 5) = 13 groups. 330 arr := make([]byte, 13) 331 i := 13 332 for num > 0 { 333 i-- 334 arr[i] = byte(num & uint64(31)) // 0b11111 in binary 335 num >>= 5 336 } 337 338 // We only return non-zero leading groups. 339 return arr[i:] 340 }