def lnencode(addr: 'LnAddr', privkey) -> str:
    if addr.amount:
        amount = (addr.net.BOLT11_HRP + shorten_amount(addr.amount))
    else:
        amount = (addr.net.BOLT11_HRP if addr.net else '')
    hrp = ('ln' + amount)
    data = bitstring.pack('uint:35', addr.date)
    tags_set = set()
    data += tagged_bytes('p', addr.paymenthash)
    tags_set.add('p')
    if (addr.payment_secret is not None):
        data += tagged_bytes('s', addr.payment_secret)
        tags_set.add('s')
    for (k, v) in addr.tags:
        if (k in ('d', 'h', 'n', 'x', 'p', 's')):
            if (k in tags_set):
                raise LnEncodeException("Duplicate '{}' tag".format(k))
        if (k == 'r'):
            route = bitstring.BitArray()
            for step in v:
                (pubkey, channel, feebase, feerate, cltv) = step
                route.append(((((bitstring.BitArray(pubkey) + bitstring.BitArray(channel)) + bitstring.pack('intbe:32', feebase)) + bitstring.pack('intbe:32', feerate)) + bitstring.pack('intbe:16', cltv)))
            data += tagged('r', route)
        elif (k == 't'):
            (pubkey, feebase, feerate, cltv) = v
            route = (((bitstring.BitArray(pubkey) + bitstring.pack('intbe:32', feebase)) + bitstring.pack('intbe:32', feerate)) + bitstring.pack('intbe:16', cltv))
            data += tagged('t', route)
        elif (k == 'f'):
            data += encode_fallback(v, addr.net)
        elif (k == 'd'):
            data += tagged_bytes('d', v.encode()[0:639])
        elif (k == 'x'):
            expirybits = bitstring.pack('intbe:64', v)
            expirybits = trim_to_min_length(expirybits)
            data += tagged('x', expirybits)
        elif (k == 'h'):
            data += tagged_bytes('h', sha256(v.encode('utf-8')).digest())
        elif (k == 'n'):
            data += tagged_bytes('n', v)
        elif (k == 'c'):
            finalcltvbits = bitstring.pack('intbe:64', v)
            finalcltvbits = trim_to_min_length(finalcltvbits)
            data += tagged('c', finalcltvbits)
        elif (k == '9'):
            if (v == 0):
                continue
            feature_bits = bitstring.BitArray(uint=v, length=v.bit_length())
            feature_bits = trim_to_min_length(feature_bits)
            data += tagged('9', feature_bits)
        else:
            raise LnEncodeException('Unknown tag {}'.format(k))
        tags_set.add(k)
    if (('d' in tags_set) and ('h' in tags_set)):
        raise ValueError("Cannot include both 'd' and 'h'")
    if ((not ('d' in tags_set)) and (not ('h' in tags_set))):
        raise ValueError("Must include either 'd' or 'h'")
    msg = (hrp.encode('ascii') + data.tobytes())
    privkey = ecc.ECPrivkey(privkey)
    sig = privkey.sign_message(msg, is_compressed=False, algo=(lambda x: sha256(x).digest()))
    recovery_flag = bytes([(sig[0] - 27)])
    sig = (bytes(sig[1:]) + recovery_flag)
    data += sig
    return bech32_encode(segwit_addr.Encoding.BECH32, hrp, bitarray_to_u5(data))
def lnencode(addr: 'LnAddr', privkey) -> str:
    if addr.amount:
        amount = (addr.net.BOLT11_HRP + shorten_amount(addr.amount))
    else:
        amount = (addr.net.BOLT11_HRP if addr.net else )
    hrp = ('ln' + amount)
    data = bitstring.pack('uint:35', addr.date)
    tags_set = set()
    data += tagged_bytes('p', addr.paymenthash)
    tags_set.add('p')
    if (addr.payment_secret is not None):
        data += tagged_bytes('s', addr.payment_secret)
        tags_set.add('s')
    for (k, v) in addr.tags:
        if (k in ('d', 'h', 'n', 'x', 'p', 's')):
            if (k in tags_set):
                raise LnEncodeException("Duplicate '{}' tag".format(k))
        if (k == 'r'):
            route = bitstring.BitArray()
            for step in v:
                (pubkey, channel, feebase, feerate, cltv) = step
                route.append(((((bitstring.BitArray(pubkey) + bitstring.BitArray(channel)) + bitstring.pack('intbe:32', feebase)) + bitstring.pack('intbe:32', feerate)) + bitstring.pack('intbe:16', cltv)))
            data += tagged('r', route)
        elif (k == 't'):
            (pubkey, feebase, feerate, cltv) = v
            route = (((bitstring.BitArray(pubkey) + bitstring.pack('intbe:32', feebase)) + bitstring.pack('intbe:32', feerate)) + bitstring.pack('intbe:16', cltv))
            data += tagged('t', route)
        elif (k == 'f'):
            data += encode_fallback(v, addr.net)
        elif (k == 'd'):
            data += tagged_bytes('d', v.encode()[0:639])
        elif (k == 'x'):
            expirybits = bitstring.pack('intbe:64', v)
            expirybits = trim_to_min_length(expirybits)
            data += tagged('x', expirybits)
        elif (k == 'h'):
            data += tagged_bytes('h', sha256(v.encode('utf-8')).digest())
        elif (k == 'n'):
            data += tagged_bytes('n', v)
        elif (k == 'c'):
            finalcltvbits = bitstring.pack('intbe:64', v)
            finalcltvbits = trim_to_min_length(finalcltvbits)
            data += tagged('c', finalcltvbits)
        elif (k == '9'):
            if (v == 0):
                continue
            feature_bits = bitstring.BitArray(uint=v, length=v.bit_length())
            feature_bits = trim_to_min_length(feature_bits)
            data += tagged('9', feature_bits)
        else:
            raise LnEncodeException('Unknown tag {}'.format(k))
        tags_set.add(k)
    if (('d' in tags_set) and ('h' in tags_set)):
        raise ValueError("Cannot include both 'd' and 'h'")
    if ((not ('d' in tags_set)) and (not ('h' in tags_set))):
        raise ValueError("Must include either 'd' or 'h'")
    msg = (hrp.encode('ascii') + data.tobytes())
    privkey = ecc.ECPrivkey(privkey)
    sig = privkey.sign_message(msg, is_compressed=False, algo=(lambda x: sha256(x).digest()))
    recovery_flag = bytes([(sig[0] - 27)])
    sig = (bytes(sig[1:]) + recovery_flag)
    data += sig
    return bech32_encode(segwit_addr.Encoding.BECH32, hrp, bitarray_to_u5(data))