I think the misunderstanding here is that I meant one salt for all users at a time, instead of one salt for each hash.
And as long as stored hashes can be recomputed (by active users), the 'global salt' can be rotated over time.
We can pre-compute hashes with future salts in case apps are not constantly online. Then we could rotate salts, say, once every 2 hours.
The point being to make rainbow tables more expensive.
> You can hash the contact pair instead of one side of it, but even then an attacker can rent X instances of some hardware that is Y times faster than your phone, so if you target a difficulty of ~1 second per contact on your phone, you get a difficulty of 2700 hours / XY for the attacker to recover all of your contacts
> So if Y is 10 times faster than your phone, you only need X=10 to recover the contacts for a given number in a day. If the attacker is willing to set X=1000, Y isn't even relevant.
I think this should be (10^10/3600 ~ 2.7 million hours) / XY. Also, let's say we can make it Y seconds (perhaps the hash is memory hard, etc). Then to compute a single table (per salt) we need 2.7e6 hours, at say $0.01 per hour, so $27k per table.
Taken together that would mean to reveal the contacts of signups happening within a 2 hour window, would cost quite a sum.
It's not secure, of course - but it does give some measure of privacy.
If you think users are willing to wait more than an hour, you could 10x the cost too. But that's probably not practical anymore!
Edit: Oh. I see I made a mistake here! If the server computes a single rainbow table it will be able to retroactively de-anonymize all users that are already active at that time! :( Sorry.