Wednesday, June 25, 2025 at 11:57:11 UTC
On Walmart receipts, there is a barcode, which encodes a TC number:
The barcode itself is Code-39 and encodes the string GCTS6T$OPLN%N02$.
I couldn't find any information on the internet about how to decode that into the TC number, so I figured it out myself, and this blog post will document how to decode these strings.
I also wrote a utility to decode the strings: walmart_receipt_barcode_decoder.zip
First, you need to know that Code-39 supports 43 different characters.
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/%+
Note that Code-39 applications typically order the + before the %. However, I have multiple receipts whose barcodes only decode correctly when % comes before +. I also manually decoded one of them to make sure my barcode scanner wasn't deciding the barcode incorrectly, and the sample barcode above, from an online barcode generator, scans correctly as well. So it appears that Walmart has chosen to swap the order of those last two characters.
The receipt uses these characters to encode a very large number in base 43. You'll need 128-bit variables.
The number in the case of GCTS6T$OPLN%N02$ is 51770704892547446742599859. You start with n=0, then take the first character G and note that, in the sequence 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/%+, if you count forward in the sequence, A=10, B=11, C=12, and G=16. So you then multiply n by 43 and add 16. At this point n=16. The next letter is 'C' which is 12, so you then multiply n by 43 and add 12. At this point n=700. The next letter is T which is 29, so you then multiply n by 43 and add 23. Now n=30129. Repeat for the rest of the characters and at the end you'll have 51770704892547446742599859.
You then need to subtract 10 * 43 ^ 15, which is 31770703657979556619143070. This is equivalent to taking the first character of the barcode string and, whatever index into the Code-39 characters it is, subtracting 10 from it. I don't know why this step is necessary, but my guess is that Walmart was using another encoding scheme in the past, perhaps raw decimal numbers or a hexadecimal representation, and this offset guarantees that the new encoding cannot be confused with the old one, since no matter what number is encoded, it will always contain at least one non-digit, and if the number encoded is at least 20 digits, it will also always contain at least one character that isn't A through F.
Anyway, after that subtraction, we're left with 20000001234567890123456789. This number contains two pieces of data: The TC number and its length.
To separate TC number and its length, divide the number by 10 ^ 24, which is 1000000000000000000000000. The dividend is the number of digits in the TC number, which in this case is 20, and the remainder is almost the TC number itself, which is 1234567890123456789.
Because the leading zeros are required, you must then ensure that you format the TC number with enough leading zeros that its length is correct. In this case, 1234567890123456789 is a 19 digit number, and so it needs one leading zero to become a 20 digit TC number. So the correct TC number is 01234567890123456789.
If that isn't clear enough, check the C source code included in the download: walmart_receipt_barcode_decoder.zip