Identity Proof of Concept
Here’s a brief rundown of the architecture and setup behind our identity proof of concept that we just launched
Check out the app here: https://safe.fission.name/
And the code here: https://github.com/fission-suite/zerowallet-poc
The goal of this application to to equip a user with a private key while providing UX similar to a traditional web app.
In the demo application, a user stores a private note in IPFS that is encrypted/decrypted with their private key.
For the first iteration of our identity system, we decided to use the ZeroWallet scheme.
ZeroWallet is a simple scheme where a user generates a private key with two passwords, and unlocks their account on login using just a username and password.
ZeroWallet uses 2 passwords and 3 shards. Any 2 shards can reconstruct the
As a brief overview of the components:
account password: this is the password that a user generally uses to login to their account. Imagine a normal username/password signin
recovery password: this is the password that a user uses to recover their private key
shard1: this shard is just a hash of the account password (
shard1 = sha256(accountPassword))
shard2: this is the fancy part of the scheme that makes use of zero-knowledge proofs. You can read more about the nitty gritty details Here. For the purpose here, think of it as
shard2 = serverTransform(sha256(recoveryPassword)). What actually happens is similar to Diffie-Hellman key exchange. The important part of this is that the server gets no information about the user’s share (
sha256(recoveryPassword)), and a malicious hacker gets no information about the server’s share by sending spoof requests.
shard3: this shard is derived from the first two using Shamir’s Secret Sharing (SSS). SSS can come up with an essentially endless number of shards for a given private key. So
shard3is actually unique per-device
Signup flow (I’m totally new here)
recoveryPasswordis hashed and “randomized” into a value we’ll call
alpha, then sent to the server
the server generates an arbitrary 256-bit key
zk_keyis combined with
betawhich is sent back to the user
betais “derandomized” to produce
shard1 = sha256(accountPassword)
privateKey = SSS.combine(shard1, shard2)
shard3 = SSS.newShard(privateKey)
localStorageand logs into the safe
Login flow (I’ve already logged onto this device before)
shard1 = sha256(accountPassword)
privateKey = SSS.combine(shard1, shard3)and loogs into the safe
Recovery flow (I want to login on a new device)
- This is the exact same flow as Signup except that the server uses the
zk_keythat’s already in the database
If a user is only encrypting data for themselves, they can just encrypt/decrypt it with their
privateKey. However, we wanted to build this in such a way that a “sharing” or “social” component could easily be added.
To do this, you don’t want to have to re-encrypt your note for every friend that you want to share it with. This leads to a lot of data replication, and also puts a big load on the user since everytime they edit the note, it must be re-encrypted for every one of their friends.
Instead, we encrypt the note with a symmetric key (
cipherKey). Add the cipher text to IPFS. And then encrypt the
cipherKey with the user’s
privateKey. Now, we have a simple setup that can be easily expanded to shared notes. If I want to share a note with you, I don’t have to re-encrypt the entire note for your
publicKey. I just have to encrypt and send you the
I separated all “key” functionality into it’s own module:
keystore. Any code that touches private keys is always susceptible to attack (malicious packages, etc). We’ve discussed writing this module using WASM which essentially gives us a secure “black box” that other parts of our code can’t acess, keeping these keys safe.
For the time being, we store just 4 things in the database:
The first two are for ZeroWallet.
username is self-explanatory,
zk_key is the server’s “share” of the second shard of the user’s
privateKey. By itself, it reveals absolutely nothing about the second shard, but it can be used to transform the user’s recovery password in such a manner that they can recover the second shard without revealing any information to the server.
safe_cid is the current CID of the encrypted safe, and
safe_key is an encrypted
cipherKey for the safe.
safe_key are currently stored in our database for convenience sake, but would eventually be moved to some form of decentralized storage (OrbitDB spike coming as we speak!)