zpay32/invoice: consolidate 32-byte array parsing and encoding logic

This commit also consolidates the existing code duplication in parsing
payment hashes and description hashes into a single, combined method for
parsing 32-byte values. A similar change is made for encoding 32-byte
values.

zpay32/invoice: consolidate 32-byte encoding logic
This commit is contained in:
Conner Fromknecht
2019-12-05 07:58:55 -08:00
parent 91d716be1f
commit 2bf94fa409
2 changed files with 25 additions and 105 deletions

View File

@@ -642,7 +642,7 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
continue
}
invoice.PaymentHash, err = parsePaymentHash(base32Data)
invoice.PaymentHash, err = parse32Bytes(base32Data)
case fieldTypeD:
if invoice.Description != nil {
// We skip the field if we have already seen a
@@ -666,7 +666,7 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
continue
}
invoice.DescriptionHash, err = parseDescriptionHash(base32Data)
invoice.DescriptionHash, err = parse32Bytes(base32Data)
case fieldTypeX:
if invoice.expiry != nil {
// We skip the field if we have already seen a
@@ -733,12 +733,12 @@ func parseFieldDataLength(data []byte) (uint16, error) {
return uint16(data[0])<<5 | uint16(data[1]), nil
}
// parsePaymentHash converts a 256-bit payment hash (encoded in base32)
// to *[32]byte.
func parsePaymentHash(data []byte) (*[32]byte, error) {
// parse32Bytes converts a 256-bit value (encoded in base32) to *[32]byte. This
// can be used for payment hashes, description hashes, payment addresses, etc.
func parse32Bytes(data []byte) (*[32]byte, error) {
var paymentHash [32]byte
// As BOLT-11 states, a reader must skip over the payment hash field if
// As BOLT-11 states, a reader must skip over the 32-byte fields if
// it does not have a length of 52, so avoid returning an error.
if len(data) != hashBase32Len {
return nil, nil
@@ -784,27 +784,6 @@ func parseDestination(data []byte) (*btcec.PublicKey, error) {
return btcec.ParsePubKey(base256Data, btcec.S256())
}
// parseDescriptionHash converts a 256-bit description hash (encoded in base32)
// to *[32]byte.
func parseDescriptionHash(data []byte) (*[32]byte, error) {
var descriptionHash [32]byte
// As BOLT-11 states, a reader must skip over the description hash field
// if it does not have a length of 52, so avoid returning an error.
if len(data) != hashBase32Len {
return nil, nil
}
hash, err := bech32.ConvertBits(data, 5, 8, false)
if err != nil {
return nil, err
}
copy(descriptionHash[:], hash[:])
return &descriptionHash, nil
}
// parseExpiry converts the data (encoded in base32) into the expiry time.
func parseExpiry(data []byte) (*time.Duration, error) {
expiry, err := base32ToUint64(data)
@@ -944,18 +923,7 @@ func parseFeatures(data []byte) (*lnwire.FeatureVector, error) {
// base32 buffer.
func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
if invoice.PaymentHash != nil {
// Convert 32 byte hash to 52 5-bit groups.
base32, err := bech32.ConvertBits(invoice.PaymentHash[:], 8, 5,
true)
if err != nil {
return err
}
if len(base32) != hashBase32Len {
return fmt.Errorf("invalid payment hash length: %d",
len(invoice.PaymentHash))
}
err = writeTaggedField(bufferBase32, fieldTypeP, base32)
err := writeBytes32(bufferBase32, fieldTypeP, *invoice.PaymentHash)
if err != nil {
return err
}
@@ -974,19 +942,9 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
}
if invoice.DescriptionHash != nil {
// Convert 32 byte hash to 52 5-bit groups.
descBase32, err := bech32.ConvertBits(
invoice.DescriptionHash[:], 8, 5, true)
if err != nil {
return err
}
if len(descBase32) != hashBase32Len {
return fmt.Errorf("invalid description hash length: %d",
len(invoice.DescriptionHash))
}
err = writeTaggedField(bufferBase32, fieldTypeH, descBase32)
err := writeBytes32(
bufferBase32, fieldTypeH, *invoice.DescriptionHash,
)
if err != nil {
return err
}
@@ -1106,6 +1064,18 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
return nil
}
// writeBytes32 encodes a 32-byte array as base32 and writes it to bufferBase32
// under the passed fieldType.
func writeBytes32(bufferBase32 *bytes.Buffer, fieldType byte, b [32]byte) error {
// Convert 32 byte hash to 52 5-bit groups.
base32, err := bech32.ConvertBits(b[:], 8, 5, true)
if err != nil {
return err
}
return writeTaggedField(bufferBase32, fieldType, base32)
}
// writeTaggedField takes the type of a tagged data field, and the data of
// the tagged field (encoded in base32), and writes the type, length and data
// to the buffer.