Take the 2-minute tour ×
Mathematics Stack Exchange is a question and answer site for people studying math at any level and professionals in related fields. It's 100% free, no registration required.

I'm not a mathematician, so please forgive any ignorance.

I have a small business - I'm generating invoices incrementally. I'm currently on about invoice number 4000.

I guess I don't want my customers knowing how much business I'm doing (i.e. if they get an invoice for 4500, they know I've been doing a lot of business lately. However, if they get an invoice for 4010, they know things are slow).

So, my question is: how can I map say, 4500, to a guaranteed-to-be unique, human-readable/human-rememberable sequence?

e.g.

4500 -> a48b82w

4501 -> b802aq2

4502 -> qi289a1

etc.

Is there a quick mathematical function that can do this? I have no idea...

share|improve this question
3  
I'm guessing this is more appropriate for security.stackexchange.com instead of here. –  Ryan Jul 25 at 15:13
1  
You are looking for something like a hash function but as it is not a security issue but just has to hide the information for the average customer. It is not that difficult to find a function for this use - if you could provide the ranges you need (ranges of invoice numbers and those of the numbers you want to show) we can perhaps find you something. Another idea would be encoding the date in the number (e.g. using the unix timestamp) or adding a random number to your 'counter' every few days or so. –  flawr Jul 25 at 15:22
8  
An alternative solution would be to include the customer ID in the invoice number - for example, customer 123 would get invoices 123-1, 123-2 and so on. –  Mark Pattison Jul 25 at 17:18
    
Use the current date and append a random x-digit number, keeping track of the used numbers each day to not reuse them? –  Paŭlo Ebermann Jul 25 at 18:29
2  
@flawr A hash function is not particularly secure here. If the user knows that it's to hide incremental numbers, they can just enumerate the incremental numbers and hash them until they get a match. This is very feasible. It may seem like nobody is going to guess or try this, but if you ask the people security stackexchange you'll hear them say "Security by obscurity, is not security at all". –  Cruncher Jul 25 at 18:54

6 Answers 6

up vote 5 down vote accepted

One option would be a bit relocation (for 32-bit n):

hash(n)=((0x0000FFFF & n)<<16) + ((0xFFFF0000 & n)>>16)

which is reversible, i.e. n=hash(hash(n)).

Example:

n       hash(n)     base-36
4000    262144000   4C2NLS
4001    262209536   4C4268
4002    262275072   4C5GQO
4003    262340608   4C6VB4
4004    262406144   4C89VK
4005    262471680   4C9OG0
4006    262537216   4CB30G
4007    262602752   4CCHKW
4008    262668288   4CDW5C
4009    262733824   4CFAPS
4010    262799360   4CGPA8
share|improve this answer
2  
Mmm. So a bit shift and conversion from base 10 to base 26+10 (i.e. [a-z0-9])? That might just be what I'm looking for... But would that be unique? –  Eamorr Jul 25 at 15:24
    
@Eamorr: Yes, its just shuffling bits around. –  Charles Jul 25 at 15:26
    
Even after the conversion to base 36? –  Eamorr Jul 25 at 15:27
    
@Eamorr No, apply the bit relocation and then convert to base 36. Then at the other end you will convert back to base 10 and apply the same bit relocation operation. –  lemon Jul 25 at 15:30
3  
@Eamorr, For what it's worth, Microsoft omits the characters A E I O U L S N 0 1 5 from Xbox redemption codes (which are 25 characters long). Not sure on the L or N, but stripping vowels prevents accidentally spelling just about any English word and many foreign-language words (you obviously don't want a code that spells a curse word!), S and 5 can be confused, l and 1 can be confused, and 0 and O can be confused. –  Brian S Jul 25 at 19:48

I think using a hash function for this misses the forest for the trees.

Just give an identifier to each customer, then increment an invoice counter for each customer. For example, customer 7634 gets invoices 7634.1, 7634.2, 7634.3, and so on.

This makes it easier on your customers since your invoices will still be sequential, but it doesn't disclose anything about your other customers.

share|improve this answer
    
I like this idea. It helps the customer's own records, and provides a sanity check when voicing the invoice numbers over the phone. –  Brian S Jul 25 at 19:56

It depends on how much hiding you want to do. You could just use a substitution cypher: $0 \to J, 1 \to Q,$ etc. It wouldn't be hard to crack, but maybe nobody will try. Similarly, you pick a prime $p$-something with six or eight digits, and two numbers $a,b$. Then $n \to an+b \pmod p$. You can calculate $a^{-1} \pmod p$ for recovery. An astute customer will note the difference between two numbers is always a multiple of $a$. You can just generate a random number for each invoice and store them in a lookup table. You can just encrypt them with your favorite algorithm, say AES.

The multiply and add modulo a prime might be the best. If $a$ is a large fraction of $p$ it won't be obvious and the resulting numbers will have no more digits than $p$. For example, take $p=104729, a=34567, b=12345$, then $a^{-1} \pmod p=26386$ which you can get from Alpha. Then $4500 \to 4500\cdot 34567 + 12345 \pmod {104729}=41280$ and to reverse it you do $(41280-12345)26386 \pmod {104729} = 4500$ as in this Alpha calc. You will have trouble after your $p^{\text{th}}$ sale.

share|improve this answer
    
AES would give me a rather garbled looking number though? I'm on the phone a lot and that would complicate my life considerably... –  Eamorr Jul 25 at 15:33
1  
That is true. The multiply and add modulo a prime might be the best. If $a$ is a large fraction of $p$ it won't be obvious and the resulting numbers will have no more digits than $p$. –  Ross Millikan Jul 25 at 15:40

If you use any deterministic algorithm(operating on the global invoice ID) to do this, then you're susceptible to the user finding out the numbers.

Since we generally reject Security by Obscurity, you have to assume the user knows how you're generating the invoice number.

Let's call your algorithm $H$. If you give to the user $H(n)$, they can simply enumerate through the natural numbers and apply $H$ to them.

That is $$A=H(n)$$ $$H(1) = A?$$ $$H(2) = A?$$ $$...$$ $$H(n) = A?$$

Yes! it does. Therefore the invoice number is $n$. This even has the advantage that once you find out the number for one of your invoices, you just start the next one from your last invoice number. Unless you get many millions of invoices, this is going to be a feasible solution.

This means that the number has to be generated non-deterministically. I.E using randomness. You could just generate a unique random number for each invoice, and give that to the user. Or, since generating a unique number gets slow as you get more invoices (have to check all the previous numbers) for each user or each day or both you can have a prefix on the number, then put your randomly-generated number after it. This way you'll generally have to only check a few invoices. You can also number the invoices incrementally, starting from 1 with each user (with a prefix)

share|improve this answer

A simple route is to generate the invoice number from the date and time. EG on 26 July 2014, 00:25:23 AM, you would generate invoice 2014072600252301.

This way:

  • All your invoice numbers are in order
  • You can readily retrieve the date from the invoice number
  • You can use the invoice date to check for a valid invoice number
  • Your customers will learn, if they try very hard, only that you are not issuing more than one invoice per second (see trailing '01' on invoice number); occasionally you can frighten them by issuing one ending in 07.
share|improve this answer

Why make such a simple problem so complex?

Most e-commerce and invoice software supports starting numbers and increments, so just pick a large number and increment by another odd number. So something like:

1034578 = first invoice number 32876 = increment amount

So your invoices would follow 1034578 + 32876X like so:

  1. 1067454
  2. 1100330
  3. 1133206
  4. etc.

For any person to know your invoice total they would need to determine the initial invoice number (improbable), and determine your increment (fairly easy).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.