owned this note
                
                
                     
                     owned this note
                
                
                     
                    
                
                
                     
                    
                
                
                     
                    
                        
                            
                            Published
                        
                        
                            
                                
                                Linked with GitHub
                            
                            
                                
                                
                            
                        
                     
                
            
            
                
                    
                    
                
                
                    
                
                
                
                    
                        
                    
                    
                    
                
                
                
                    
                
            
            
         
        
        # Multisigned
Multisigned is an open source digital locker for Ethereum seed phrases.
## Motivation
The self custodial Ethereum wallets' user experience is bad and hasn't notably improved over the last few years. While this is not exactly a problem for crypto currency applications, for decentralized social media apps this is a death sentence as our web2 counter parts are alive and innovating players who keep shipping the best in class user experiences. For essentially all of crypto-related decentralized social media, over the course of the last 2-3 years, this has meant TAM-constraint growth and zero sum customer acquisition.
The fact of the matter is: Crypto-based decentralized social media cannot grow with the Ethereum self custody wallets as a substrate. That is not even a failure of Ethereum wallet providers. The fault rather lies in the fact that building crypto-based decentralized social media and nation-state-secure crypto currency have different goals.
Hence, we think it is urgently necessary for crypto-based decentralized social media to branch out into its own wallet vertical and to solve their problems with bespoke solutions.
In the document below we outline a concept to client-side-encrypt and store Ethereum seed phrases on open source servers to immensely improve the UX of crypto-based decentralized social media applications.
## User Experience
There are a few things to say about the user experience of using passkeys in a crypto-based decentralized social media application versus using a self custodial Ethereum wallet. 
For the sake of this document, it is simply important to note that, for users, interacting with Passkeys doesn't appear as a risk to their funds. While there are a few sites that allow people to transact funds with Passkeys, generally we trust that users are intuitively aware of the domain separation Passkeys implement and hence do not associate a Passkey dialogue with a possibility of endangering their savings.
Passkeys obviously also come pre-installed on all major operating systems now. The PRF extension is now [widely available](https://www.passkeyprf.com/). Meanwhile crypto currency wallets will continue to try to lock down users private keys and seed phrases
## Safety Considerations and Limitations
It's important to highlight that we intend this protocol to be used for crypto-based decentralized social media applications. These usually allow users, for example, to delete prior statements. The potential to do irrevocable damage to a crypto currency account is obviously very high and so wallet providers do their utter most to lock down seed phrases. In our view, this potential to do irrevocable damage is much lower for crypto-based decentralized social media. And in cases where the stakes are high, dapps can always choose to allow users to use self-custodial Ethereum wallets.
## Protocol
### Registration
1. The protocol uses envelope encryption.
2. When the user opens a website, sees and clicks a "Sign up" button, an operating-system-specific Passkey dialog opens asking the user to create a Passkey for the website. The user confirms.
3. With this dialogue, the user is registering a public private key pair with the multisigned server. In return for signing up they receive a 15 minute valid JWT session token. A salted PRF value is generated from the credential creation dialogue too. It's used as an input to generate an AES encryption key (KEK, key encryption key).
4. The user's browser now generates another AES encryption key that we call data encryption key (DEK). The seed value of this DEK is entirely random.
5. An Ethereum seed phrase is generated and wrapped with the DEK. We call this the vault.
6. The DEK itself is wrapped with the Passkey-PRF-derived KEK.
7. Using the JWT session token from step 3, the user's browser now sends the wrapped DEK and the vault to the server.
8. The server stores the vault in one table and the DEK in reference to the vault ID.
9. The Ethereum seed phrase is stored for the time of the browser or app's session in the user browser's local storage. Upon closing the browser tab or app, the Ethereum seed phrase is deleted from the device.
```mermaid
sequenceDiagram
    actor User
    participant Browser
    participant OS as OS/Passkey Provider
    participant Server
    User->>Browser: Click "Sign up"
    Browser->>Server: POST /register/begin
    Note over Server: Generate lockboxId (UUID)<br/>Generate registration challenge
    Server->>Browser: Return registration options<br/>(challenge, rpID, rpName, etc)
    Browser->>OS: navigator.credentials.create()<br/>with PRF extension
    OS->>User: Show Passkey dialog
    User->>OS: Confirm creation
    Note over OS: Generate public/private keypair<br/>Generate PRF salt output
    OS->>Browser: Return credential response<br/>(credentialId, publicKey, PRF output)
    Note over Browser: Derive KEK from PRF output
    Note over Browser: Generate random DEK
    Note over Browser: Generate Ethereum seed phrase
    Note over Browser: Encrypt seed phrase with DEK<br/>(creates vault)
    Note over Browser: Encrypt DEK with KEK<br/>(creates wrapped DEK)
    Browser->>Server: POST /register/complete<br/>(credential response)
    Note over Server: Verify registration response<br/>Create lockbox with lockboxId<br/>Store passkey credential
    Server->>Browser: Return JWT token (15min)
    Browser->>Server: PUT /lockbox<br/>(wrapped DEK + vault, with JWT)
    Note over Server: Store encryptedData in lockbox
    Server->>Browser: 200 OK
    Note over Browser: Store plaintext seed phrase<br/>in session storage<br/>(deleted on close)
```
### Login
1. When the user opens a website and is prompted to sign a login challenge with their Passkey. In return for completing the challenge, the server sends back a 15 minute valid JWT session token. A salted PRF value is also generated during the Passkey challenge dialogue. It's used as an input to generate an AES encryption key (KEK, key encryption key).
2. Using the JWT session token, the user now requests to access the wrapped DEK and the vault. The server sends both.
3. The user's browser unwraps the DEK, the unwrapped DEK is then used to unwrap the vault. The DEK is discarded.
4. The vault's Ethereum seed phrase is stored for the time of the browser or app's session in the user browser's local storage. Upon closing the browser tab or app, the Ethereum seed phrase is deleted from the device.
```mermaid
sequenceDiagram
    actor User
    participant Browser
    participant OS as OS/Passkey Provider
    participant Server
    User->>Browser: Open website, click "Login"
    Browser->>Server: POST /login/begin
    Note over Server: Generate authentication challenge
    Server->>Browser: Return authentication options<br/>(challenge, rpID, etc)
    Browser->>OS: navigator.credentials.get()<br/>with PRF extension
    OS->>User: Show Passkey dialog
    User->>OS: Confirm authentication
    Note over OS: Sign challenge with private key<br/>Generate PRF salt output
    OS->>Browser: Return assertion response<br/>(credentialId, signature, PRF output)
    Browser->>Server: POST /login/complete<br/>(assertion response)
    Note over Server: Verify signature<br/>Lookup passkey by credentialId<br/>Update counter
    Server->>Browser: Return JWT token (15min)
    Note over Browser: Derive KEK from PRF output
    Browser->>Server: GET /lockbox (with JWT)
    Note over Server: Lookup lockbox by lockboxId from JWT
    Server->>Browser: Return encryptedData<br/>(wrapped DEK + vault)
    Note over Browser: Unwrap DEK with KEK
    Note over Browser: Unwrap vault with DEK
    Note over Browser: Discard plaintext DEK
    Note over Browser: Store plaintext seed phrase<br/>in session storage<br/>(deleted on close)
```
### Adding a second Passkey
A user's identity should not permanently bind to a Passkey as they are not easily portable, e.g., across ecosystems.
The user now has two devices: phone1 and phone2. Assume the user has successfully registered and is logged into the app with phone1. Both devices are of different Passkey ecosystems (e.g. Apple and Google). The user now wants to add phone2 as a second device.
1. On phone2, the user navigates to the app and clicks "Add recovery option." The user is presented with a Passkey registration dialogue. Upon completing the registration challenge, phone2 receives a 15 minute valid JWT session token. A PRF value is generated from the Passkey dialogue too and is used as an input to generate an AES encryption key (KEK).
2. An ephemeral ECDH keypair (public + private) is generated on phone2. The ECDH's public key, along with the signing key of phone's Passkey credential are shown as a QR code along with the message "Scan this QR code with phone1"
3. On phone1 (already logged in), the user scans the QR code in the app and deserializes phone2's ECDH public key and its Passkey credential's public key.
4. To get the DEK, phone1 now repeats the Login proceedure but doesn't discard the plaintext DEK in step 3.
5. Phone1 wraps the plaintext DEK using phone2's public ECDH key and sends it along with phone2's Passkey credential public key to an ephemeral storage slot on the server.
6. The server now allows phone2 to store a new DEK in phone1's DEK and vault storage.
6. Using the JWT session key from step 1, phone2 polls the server's ephemeral storage slot, finds the encrypted DEK and downloads it.
7. Phone2 also requests and downloads phone1's encrypted vault.
7. Phone2 unwraps the DEK using the ECDH private key and discards the ECDH keypair.
8. Phone2 now wraps the plaintext DEK with its own KEK.
9. Phone2 unwraps the vault and stores the Ethereum seed phrase in the app's session storage.
9. Phone2 sends the newly wrapped DEK to the server where it is stored along side phone1's vault and DEK.
```mermaid
sequenceDiagram
    actor User
    participant Phone2 as Phone2 Browser
    participant OS2 as Phone2 OS/Passkey
    participant Server
    participant Phone1 as Phone1 Browser (logged in)
    participant OS1 as Phone1 OS/Passkey
    Note over Phone1: Phone1 is already logged in
    User->>Phone2: Click "Add recovery option"
    Phone2->>Server: POST /register/begin
    Server->>Phone2: Return registration options
    Phone2->>OS2: navigator.credentials.create()<br/>with PRF extension
    OS2->>User: Show Passkey dialog
    User->>OS2: Confirm creation
    Note over OS2: Generate keypair<br/>Generate PRF output
    OS2->>Phone2: Return credential response
    Phone2->>Server: POST /register/complete
    Server->>Phone2: Return JWT token (15min)
    Note over Phone2: Derive KEK2 from PRF output<br/>Generate ephemeral ECDH keypair
    Phone2->>Phone2: Display QR code<br/>(ECDH public key + credential public key)
    User->>Phone1: Scan QR code with Phone1
    Phone1->>Phone1: Parse ECDH public key<br/>and credential public key
    Note over Phone1: Repeat login procedure to get DEK
    Phone1->>Server: POST /login/begin
    Server->>Phone1: Return authentication options
    Phone1->>OS1: navigator.credentials.get()<br/>with PRF extension
    OS1->>User: Show Passkey dialog
    User->>OS1: Confirm authentication
    OS1->>Phone1: Return assertion + PRF output
    Phone1->>Server: POST /login/complete
    Server->>Phone1: Return JWT token
    Note over Phone1: Derive KEK1 from PRF output
    Phone1->>Server: GET /lockbox (with JWT)
    Server->>Phone1: Return encryptedData
    Note over Phone1: Unwrap DEK with KEK1<br/>Keep plaintext DEK in memory<br/>(don't discard yet)
    Note over Phone1: Encrypt DEK with Phone2's ECDH public key
    Phone1->>Server: POST /recovery/transfer<br/>(encrypted DEK, Phone2 credential pubkey, with JWT)
    Note over Server: Store in ephemeral slot<br/>Authorize Phone2 credential<br/>to access lockbox
    Server->>Phone1: 200 OK
    Note over Phone1: Now discard plaintext DEK
    Phone2->>Server: GET /recovery/transfer (with JWT, polling)
    Server->>Phone2: Return ECDH-encrypted DEK
    Phone2->>Server: GET /lockbox (with JWT)
    Server->>Phone2: Return vault
    Note over Phone2: Decrypt DEK with ECDH private key<br/>Discard ECDH keypair
    Note over Phone2: Wrap DEK with KEK2
    Phone2->>Server: PUT /lockbox/add-key<br/>(wrapped DEK2, with JWT)
    Note over Server: Store Phone2's wrapped DEK<br/>alongside existing data
    Server->>Phone2: 200 OK
    Note over Phone2: Unwrap vault with DEK<br/>Store seed phrase in session storage
```
#### Considerations
It is important that phone1 learns about phone2's decryption key through a QR code as this then guarantees that the server never gets a chance to steal or see the Ethereum seed phrase.
### Rotating the DEK
[TODO]
  
## Server Architecture
As the encrypted blob storage is for many users the only way to access their application credentials, then it is important to write a few words about how we intend to design the server architecture.
We think that decentralized social mediabuilders have a shared interest in keeping users' identities safe, so we think that them running their own instances of these encrypted blob servers makes sense.
We can also envision dapp-independent providers of this blob storage to emerge. Which is fine, but also not something we intend to design for in this first iteration.
## Feasibility
To understand the feasibility to implement out above outlined scheme we have to understand how widely supported Passkeys with the PRF extension are. This is not exactly an easy task as there are many nuances to consider.
Generally speaking, we believe that Passkeys and PRF will find its way into most operating systems and browsers. So we are optimistic that our scheme will be widely supported over the long term. However, we think it's also important to thoroughly validate some potential pitfalls. A few examples of Passkeys+PRF support being sub-optimal are:
1. Passkeys and PRF are be unavailable on a logged out version of Chrome.
2. Authenticators like iCloud Keychain are shipped along with operating system upgrades, and so while browsers may already support Passkeys and PRF, hence suggesting a large addressable market, an outdated authenticator can still fail the process, shrinking the addressable market.
## Call to Action
We have written this document for it to be circulated among potential stakeholders and investors. 
We think such a system could be built now pretty easily, the technology is ready and it seems no one has built it yet. But we'd like to work on this as a community of interested parties to make this safe, co-owned and successful.
If such a system already exists, we don't want to build it, but reuse and adjust the existing system.
We are most likely not interested in just using Ethereum smart accounts or newly developed Ethereum crypto currency wallets as they tend to favor moving user funds around which is a misaligned goal to what we intend to use Ethereum keys for. This, however, is by no means meant to exclude the Ethereum wallet community of which we consider ourselves a part too.
If you would like to help drive this project forward, please reach out to @freeatnet or @timdaub on Telegram. Please also join our Telegram group: https://t.me/+MT5G5BZUQTU2ODRk
## Conclusion
These days it almost feels as if it was over for crypto-based decentralized social media. 
Not even Ethereum leadership seems to embrace its vision anymore. This can be a curse if we assume their help to prosper. 
Seeking a split in how we design wallets for decentralized social media, we'd like to argue, can maybe also be a blessing. We can finally pave our own path, solve our own problems and we may still benefit from the excellent research pipeline that crypto currencies has generated.