Identity & Authentication Services


Hedgehog is a package that lives in your front end application to create and manage a user’s entropy (from which a private key is derived). Hedgehog relies on a username and password to create encrypted auth artifacts, so it’s able to simulate a familiar authentication system that allows users to sign up or login from multiple browsers or devices and retrieve their entropy. Those artifacts, through hedgehog, are persisted to a backend of your choosing.

A private key is only computed and available client side and is never transmitted or stored anywhere besides the user’s browser.


Ethereum Universal Logins


  • this is basically the private-key=hash(username, password) but made high-entropy
  • passwords are low entropy so can be easily bruteforced
  • instead, generate auth artifacts client-side, encrypt with password, and send to the serve


  • recognizable flow for users
  • more secure than brain wallets


  • no recovery options (if you forget password, you’re screwed)
  • can be brute-forced by server
  • not censorship resistant
  • not offline-first


  • every password is 3 shards (shamir secret sharding)
    • shard1: hash(pw1)
    • shard2: hash(pw2) transformed by server key
    • shard3: local shard derived from the prev 2
  • when user needs key, use pw1 to derive w/ shard1 & shard2
  • if the user loses their local shard3, use shard1 & shard2 to derive key & get a new local shard
    • fancy zk-proof stuff in here to make this piece secure


  • censorship resistant
  • offline-first
  • only have to interact w server for recovery
  • no key stored locally (any time you need your pk, calculate it w/ shard + hash(pw1))


  • kinda awkward login flow (2 passwords)
  • need to remember 2 passwords (one for daily use, one for recovery)
  • can be brute-forced by server

Universal Logins

  • multisig wallets
  • different private key for every app on every device
    • Action Keys (app specific keys)
    • Management Keys (device/recovery keys that can add/rm keys from wallet)
    • This distinction is in the docs, but I’m not seeing it reflected in the code??
  • when you log in from a new device, you have to verify it from your previous one
  • txs are sent with a relay network
  • every wallet is tied to an ENS record


  • very extensible/flexible
  • flexible recovery options (ie we can hold a recovery key & then void it if the user decides to upgrade)
  • can abstract txs away from users by using relay network + having an app pay for gas
  • upgradable security
  • easy to add/remove keys


  • not as familiar as username/password
  • tied to ethereum
  • login through ENS names
    • run our own ENS registry so we can avoid auctions/collisions? Abstract away ENS so it just looks like usernames?

Could we do that for them? Just take the first and second half of a string?

Username: nmyawesomeusername
Password: helloworldthisisapassword

Share 1: helloworldthi
Share 3: sisapassword

This of course means that people need to have long passwords, which is unlikley in the general case

Yeah that would work, but:

  • I think most people might hate that even more than 2 passwords (you’d need like 16chars to be decent, 20chars to be good)
  • every time a user has to use their key, they put their entire password in while they only need the 1st half
  • you also lose a recovery vector:
    • user forgets 1st password
    • recover key w/ 2nd password & local shard
    • Note: This is a “last defense”, it can only be done once, and screws up the whole ZeroWallet setup so the user would probably want to migrate their identity after doing so

DID info

Universal Resolver

Created by Decentralized Identity Foundation
Resolves DID URIs (ie did:sov:WRfXPg8dantKVubE3HX8pw) to a DID doc

Creating your own DID driver

All you need is a docker container with a /resolve endpoint (can literally be a server + db, doesn’t actually need to be decentralized). I don’t think we’ll want to do this ourselves

More reading:

Sketched out a draft of what this could look like:

This is basically a combo of hedgehog & Universal logins and is similar to what Brooke described when we were riffing on identity in Vancouver: a multisig wallet where keys can be added/voided for different devices. But with optional added ux for users that just want a normal username/password login & easy steps for upgrading security.

Note: we could do this without Universal Logins (ie make our own multisig contract), but I think we’d be duplicating a lot of effort.
_Also note: we can switch out hedgehog js for a scheme similar to the second shard of a ZeroWallet. Really we just need {user’s password + something from server = private key}

For the user, this looks like a classic Username & Password signup/login. No keys, no hashes, no ENS names etc.

Offer a few options for key management:

  • most secure
  • generate a BIP-39 mnemonic & add to wallet. Prompt user to write down somewhere
  • offer social recovery (shamir secret sharding) (do services exist for this?)
  • (default) use hedgehog.js to generate auth artifacts, encrypt with password & add to wallet as a MANAGEMENT_KEY (this is used as a backup/for logging)
    • at this level, signup/login looks exactly as users are used to. account recovery requires a backup key or another device to be logged in
  • ask the user if they want us to store a recovery key (pretty major hit to security here, but maybe some users prefer it). Use something like AWS cloudHSM to store it
    • at this level, signup/login/recovery looks exactly as users are used to.
  • least secure

Normal Universal Login flow:

  • (currently logged in on computer)
  • Log in on phone for the first time (only username)
  • generate key car on phone
  • send public key to computer
  • sign public key with computer’s private key
  • send to relay network to add to wallet contract
  • unfamiliar flow
  • kinda like 2fa but even more involved (which most users don’t use, and don’t want to use for non-sensitive applications)
  • need another machine that’s already logged in
  • in really shitty circiumstances (house burns down, major theft), you could lose all your devices and be locked out of account

With hedgehog

  • Log in on phone (username & password)
  • use password w/ auth artifacts from server to get already-registered private key client-side
  • generate keypair for phone
  • use sign generated pubkey w/ privkey from hedgehog
  • send to relay network to add to wallet contract
    Familiar log in flow! No second machine needed

Universal Logins is Ethereum-first and makes use of ENS. Personally don’t think this is a big deal. We can easily link into other DIDs & abstract over ENS
Optional: Run our own ENS registry so user’s ENS name can be {username}.fission.eth (or similar)

  • can avoid auction process + less collisions this way
  • users can still easily alias with non-fission ens names & still have full access to their wallet
  • using our login, they won’t even be exposed to ENS, just looks like a normal username to them

Do we want to run our own relay network?? Outside of scope?

This was a GREAT write up! just awesome. At a glance I feel very onboard with the hedgehog flow and like that we would abstract away most of the pain points.

I also think (as a naive person) that running our own ENS registry is a good idea, especially because if we dont we’d have to take development time to deal with the auction process.

Filling in my gaps

generate keypair for phone

What do you mean by this? Is this list of steps all in the context of mobile device or that you generate a second key pair for your other device?

Other notes

Hedgehog mentions its not great for apps with higher security needs (anything finance related for example). If we did use hedgehog in v1 would we be able to give users a “super secure” option for certain apps they wish to login to?

For example every “login with fission” has username and password however you also have an increase security button which would allow a user to set the backing wallet? or some other method that would increase security?

Hedgehog mentions its not great for apps with higher security needs (anything finance related for example). If we did use hedgehog in v1 would we be able to give users a “super secure” option for certain apps they wish to login to?

Yeah, I think this is the equivalent to 2FA – which could be either done in a Web3 / Ethereum way, or actually be an integration with eg Authy / OTP.

This is both “for the user” and for developers, so developers might restrict certain actions until / unless users upgrade to more secure accounts.

At a start – user + pass is the same level of “security” as the vast majority of apps out there today.


Uses Merkle trees and zero knowledge proofs for off chain identity creation and claims, and relayers “batch” on to the chain


Yup think @boris nailed it in terms of the hedgehog flow being equivalent to normal username/password on the web. The way this whole setup differs from normal apps is that your identity is tied to your wallet which. So you have the same login for every app. So if you use an app that requires more security (equivalent of 2fa basically), then you need to upgrade your entire identity to that level of security. It isn’t on a per-app basis.

Yeah that whole list of steps is in the context of a mobile device (for illustrative purposes, it could be in the context of any device). Replace “phone” with “laptop” and it’s the same flow

I did not follow the saga of these ERCs so I’m piecing this together posthoc.

The relevant ERCs seem to be: 725, 734, and 735

725v1 was a key holder contract but it’s now substantially different. v2 is a proxy contract.
734 is a key holder contract. I believe an expanded version of 725v1
735 is an identity claims contract

It looks like Universal Logins did implement 725v1, but stripped that out and is doing their own implementation now. But they also lost key purpose with that (ie, management, action, etc). So every key is treated exactly the same. It seems like it would be good to reimplement this functionality following the 734 spec.

Meanwhile, the current wallet seems to implement a modified version of 725v2.

Meanwhile 735 is the spec for adding claims to an identity. I don’t think that we need to do this part of the implementation. I think it would be good enough to have a key purpose be IDENTITY, and that way we can link back multiple identity implementations to a user’s wallet (say they have an Ethereum native identity, and a Sovrin identity and want to link them both to their wallet)

1 Like


Schema for encrypting filetrees such that if you have access to a directory, you have access to every file underneath it.
Take this file structure with directories A, B, and C and files f1, f2, f3

               /   \
             B      C
            /     /   \
          f1    f2     f3
  • Directory A is encrypted with symmetric key kA
  • Directory B is encrypted with kB = hash(kA, “B”)
  • Directory C is encrypted with kC = hash(kA, “C”)
  • File f1 is encrypted with kf1 = hash(kB, “f1”)
  • File f2 is encrypted with kf2 = hash(kC, “f2”)
  • File f3 is encrypted with kf3 = hash(kC, “f3”)

Since hashes are one-way functions, you can:

  • derive {kB, kC, kf1, kf2, kf3} by knowing kA
  • derive {kf2, kf3} by knowing kC
  • derive no other keys by knowing kf3

In other words: knowing a key gives you access to every child dir & file without giving any information about the parents.

Paper on the subject:

Peergos, where I first came across the idea and pretty similar in some ways to what we’re doing:


Discourse doesn’t want me to make more than 3 consecutive replies :roll_eyes: so editing here

Spent awhile investigating Torus. Very interesting idea: key management through some type of OAuth social service (Google, Github, Twitter, etc).

After some research, I don’t think this is going to work out as one of our initial identity offerings.

Decentralization concerns

Found it pretty difficult to determine what exactly was happening under the hood.

My best read is that it’s a permissioned network of nodes that hold shards of your key. There are “incentive structures” (staking where if you commit fraud, your stake gets slashed) in place to prevent them from leaking shards or colluding to reconstruct your privkey. OAuth is just used as a method for you to display to a node in the network that you are who you say you are.

I’m uncomfortable with this setup because it’s not terribly decentralized. It seems very easy for nodes to collude, and reconstruct your privkey. I’m not convinced that the incentive structures are any stronger than just trusting your privkey with a centralized entity.

Also this scheme is only as secure as OAuth is. So if your token leaks, your screwed. And if the OAuth provider turns out to be a bad actor, they can capture the private keys of everyone using their service.

I might have some of this wrong, as I said, I had a pretty hard time gathering info from their documentation. As Brooke suggested, I’m planning on reaching out to them to get some clarity.

Can’t get privkey from web3 wallet

This is the big clincher. They act as a provider that you pass to an instance of web3.js, similar to Metamask. For security reasons, you can’t just get the privkey out of web3. So Torus won’t work at all for us in the beginning when we’re more concerned about privkey encryption than we are about eth txs. This would really only come in down the line as a key recovery option