pull down to refresh

Can someone familiar with bolt11 explain to me how the timestamp is encoded here?
I get the same bech32 encoding, so I must be doing something right, but I don't understand this intermediate value. I'm starting to think it's wrong.
6c6e6263 is lnbc, the invoice has no amount, so the next 7 bytes (35 bits) should be the timestamp, right? It's 0b25fe64500d04, but I have 010c121f1c1902.
My timestamp is encoded in base32, and when decoded it's exactly the timestamp it should be:
0x01 << 30 | 0x0c << 25 | 0x12 << 20 | 0x1f << 15 | 0x1c << 10 | 0x19 << 5 | 0x02 = 1496314658
So excuse me, but wtf is 0b25fe64500d04 in the test vector?? 😅
also asked this in #lightning-101 of the LDK Discord server
1022 sats \ 1 reply \ @tonyaldon 5h
Hey @ek, I made a series of live streams in 2024 explaining how BOLT 11 is implemented in Core Lightning. I'm no longer working on LN, but I guess the implementation has not changed much, and neither has the protocol, at least for BOLT 11.
I think you may find part 4 interesting.
Today we are going to look at the transformation of the information of an invoice from its representation with bytes of 8 bits to bytes of 5 bits. Specifically, we'll try to understand why the description foo bar of an invoice is represented in a BOLT #11 string by vehk7grzv9eq.
I hope this helps.
reply
100 sats \ 0 replies \ @ek OP 4h
Ohh, this looks great, thank you!!
reply
7 bytes (35 bits)
7 bytes * 8 bits = 56 bits
reply
0 sats \ 11 replies \ @ek OP 8h
It’s base32, not base256
reply
So, does that mean each byte is 5 bits?
reply
21 sats \ 9 replies \ @ek OP 8h
Yes
reply
5142 sats \ 8 replies \ @0xbitcoiner 7h
0x01 = 00001 0x0c = 01100 0x12 = 10010 0x1f = 11111 0x1c = 11100 0x19 = 11001 0x02 = 00010
00001 01100 10010 11111 11100 11001 00010
5bit byte to 8bit byte
00001011 = 0x0b 00100101 = 0x25 11111110 = 0xfe 01100101 = 0x65 00001101 = 0x0d 00000100 = 0x04
0b25fe650d04!
reply
100 sats \ 2 replies \ @optimism 6h
This is such a good skill to have.
reply
100 sats \ 1 reply \ @ek OP 6h
Yes, I’m embarrassed it didn’t occur to me to interpret my 5-bit bytes as 8-bit bytes, haha
reply
121 sats \ 0 replies \ @optimism 6h
Don't be. This is exactly why teamwork is important.
33 sats \ 3 replies \ @ek OP 6h
Nice, thank you so much!! I literally spent multiple days on this hahaha
But you've made a mistake, it should have been:
01100100 = 0x64
instead of
01100101 = 0x65
Then it's 0b25fe64500d04, but 0x0d != 0x50, 0x04 != 0x0d.
Probably some encoding / endianess thing.
Edit: I think I just copied too many timestamp bytes, so 0x50, 0x0d and 0x04 aren't actually part of the timestamp.
reply
Must've been a copy/paste screw-up. Did you figure out the conversion yet? I tried it again and fail at hex 0x02.
0x01 = 00001 0x0c = 01100 0x12 = 10010 0x1f = 11111 0x1c = 11100 0x19 = 11001 0x02 = 00010
00001011001001011111111001100100010 -> 1496314658 ✔️ 00001011 00100101 11111110 01100100 010 0x0b 0x25 0xfe 0x64 0x02
Those 3 bits (0x02) might already be part of the next byte. Makes sense 'cause 0x50 is 01010000.
reply
33 sats \ 1 reply \ @ek OP 1h
I think what's going on here is that to go from 010c121f1c1902 in base32 to 0b25fe64 in base256, we group the bits into 8 bits from the left and pad at the right after 35 bits:
00001 01100 10010 11111 11100 11001 00010
 0x01  0x0c  0x12  0x1f  0x1c  0x19  0x02

00001011 00100101 11111110 01100100 010ppppp
    0x0b     0x25     0xfe     0x64     0x40
                                          ??
This is what you've shown in #1342878.
But to interpret the bytes in base32 as bytes in base256 that can then be interpreted as the timestamp, we actually need to group the bits into 8 bits from the right and pad at the left after 35 bits:
00001 01100 10010 11111 11100 11001 00010
 0x01  0x0c  0x12  0x1f  0x1c  0x19  0x02

ppppp000 01011001 00101111 11110011 00100010
     0x0     0x59     0x2f     0xf3     0x22
and 0x592ff322 in base256 is indeed 1496314658.
Or you can just shift 0x0b25fe64 5 bits to the right to remove the padding on the right, and you get 0x592ff322!
deleted by author