18 comments

[ 3.3 ms ] story [ 48.0 ms ] thread
> Does nobody make apps for fun anymore?

I feel like the fact that you need to pay $100/year to publish an app to the app store and keep it there kind of kills off fun apps that don't have some plan for monetization.

Is it really $100/app/year? I thought it was $100/dev/year.
$100 / company so get 99 friends to go in on an account and it’s only $1 / year!
Getting 99 actual friends in 2024 sounds almost infinitely harder than just putting in 7 extra hours at WageMart to cover the expense.
Per dev yeah, though this does sort of disincentivise keeping stuff online if you're not shipping regularly.
I've once got 000000. If you do the math it takes about 1 year to cycle through all million of them, assuming no duplicates.

Which makes me wonder, what's the expected repeated distribution?

This is the birthday paradox. The rough approximation is you need sqrt(n) values to get to a 50% chance of having a duplicate. Sqrt of a million is a thousand, and if they're every 30 seconds, that's ~8 hours or so. So you probably get a duplicate or 2 every day.

There's _much_ better approximations than the sqrt one, but I don't know them and the actual math is too hard.

Correct, the article actually mentions the birthday problem somewhere. Even with 10k codes (2 days) you get dozens of duplicates, so I'd say it's potentially even more common.

Sextuples are 1 in 100,000, so something like every 50 days (per account).

> Even with 10k codes (2 days) you get dozens of duplicates, so I'd say it's potentially even more common.

Yeah I screwed up here, at the end:

> Sqrt of a million is a thousand, and if they're every 30 seconds, that's ~8 hours or so. So you probably get a duplicate or 2 every day.

You'd get 1 or 2 every day (approx.) if you're only, at any point, looking at the collection of codes generated in the past 8 hours. But of course that wasn't the question, and the odds go way up once the period we're looking at goes larger and larger over time.

I shouldn't have tried to go beyond "ballpark if you wait 8 hours you have a coinflip of having at least one duplicate", anything more than that requires different math.

Genius!

If you add a switch to control iCloud Keychain syncability and backupability this will unironically blow Google Authenticator out of the water in terms of functionality as well.

That's an extremely easy change as well, I'll pop a TODO in
I love that you built this and wrote about it. We need more whimsy in our lives. Thank you.
Whimsy is what I aim for. Really appreciate the praise! :)
This was a fun read. Don't miss the follow-up article on performance optimizations: https://jacobbartlett.substack.com/p/high-performance-swift-...
Why the string searching? One million bits is 125KB. That would fit in L2 cache. Just build a bitmap of interesting results (small enough to ship with the app), do modulo 1000000, then do a lookup in the bit map. Could even be a byte map where the byte value indicates type of interesting number and would still fit in cache.

For sextuplets, you can just check whether the value is zero modulo 111111...

I actually mentioned this in the article! That's a nice catch on the L2 cache reasoning and modulo idea, that saves on spenny heap allocations everywhere.

I did the first sweep of optimisations to kill the super-slow regex and turn the slowest operations into a set matching operation.

I considered pre-processing all the potential interesting codes, reducing everything to a simple dict/set matching, but by that point the actual operation to generate OTPs was orders of magnitude slower than everything else, so there would be negligible user-facing benefit to doing so.

Are you caching a keyed HMAC context? Given the data sizes, it ought to be at least one call of the SHA transform function to set the key, and one to produce the hash. They keying operation isn't dependant on the data and its result can therefore be reused.