Implementation details
We use elliptic curve keys with curve secp521r1. The private key is encrypted with a libargon2i hash of the users' password, stored in a libsodium secret box.
A second copy of the private key is stored encrypted with a libargon2i hash of the users' recovery token, to be used when a user restores their account after they lost their password.