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  }