Filecoin Phase 2 Write Up

Filecoin Phase 2

We’re excited to announce the release of v1 of our Filecoin backup app! This app will allow users to store and send filecoin securely from the browser and make storage deals to back up parts (or all of!) their Webnative Filesystem.

The project itself is divided into 3 parts:

:white_check_mark: Phase 1 - Research: Designing an architecture & cryptographic system to securely send Filecoin from the browser
:white_check_mark: Phase 2 - Co-signatures: Create that :point_up: system which takes the form of a library & backend
:black_square_button: Phase 3 - Storage deals: Use transferred funds to make storage deals and back up arbitrary content, or a part of the user’s filesystem

I’ll give a brief overview of the Filecoin cosigning service that we’ve built.

Building blocks

The three main building blocks of our system are BLS signatures, UCANs, and the Webnative Filesystem.

BLS Signatures

BLS signatures have a unique quality: aggregation. The aggregation of two signatures from two different private keys is a valid signature for the public key resulting from the aggregation of both of their respective public keys.

Put another way:

  • secret_key_alice signs msg to give signature_alice
  • signature_alice is a valid signature for public_key_alice
  • secret_key_bob signs msg to give signature_bob
  • signature_bob is a valid signature for public_key_bob
  • aggregate signatures: signature_agg = aggregate(signature_alice, signature_bob)
  • aggregate public keys: public_key_agg = aggregate(public_key_alice, public_key_bob)
  • signature_agg is a valid signature for public_key_agg

Specifically, in our code we use the Filecoin-compatible curve bls12-381.

UCANs

UCANs (or User Controlled Authorization Networks) are a decentralized auth model. UCANs are tokens (similar to a JWT) that authorize a user (or more accurately a public key) to perform certain actions, as well as delegate some subset of that authorization to another key.

When a user delegates some subset of their rights to another token, they attach the delegating UCAN (or some reference to it, such as a CID) to the new UCAN. Thus a chain of trust is formed back to the root UCAN.

In the Fission ecosystem, a user’s root DID is stored at _did.${username}.fission.name (in a TXT record). The signing key for this account is only available in the auth lobby of the device that a user logged into for the first time. Therefore every UCAN stemming from a given user can be traced back to that same root key.

WNFS (Webnative Filesystem)

WNFS is a distributed filesystem built on top of IPFS. It has both a public and private side, with the private side allowing fine-grain access controls. Files can be accessed from the browser with no extensions using a familiar POSIX-style interface

Securely managing Filecoin from the browser

Private keys in the browser are scary. Keeping keys in memory leaves them susceptible to attacks from malicious javascript packages or extensions.

We make use of BLS signature aggregation so that the signing private key is never held in memory.

For each Filecoin wallet, there are two private keys whose corresponding public keys are aggregated to obtain the wallet address:

  • the first is stored in the user’s WNFS
  • the second is stored by our cosigning server and is authorized for use through a UCAN

When a user creates a Filecoin wallet, they generate a random private key and store it to their WNFS at private/Keychain/fil-cosigner.json. The file contents can only be accessed by applications that have been granted read permission to the Keychain or to that key in particular.

The user then sends the public key to our cosigning service along with their root DID.

The server generates a random private key which it stores along side the related public key from the user.

When a user wishes to send a Filecoin transaction, they:

  • read their private key from WNFS
  • sign the transaction with that private key
  • send the transaction, along with a properly permissioned UCAN to the cosigning server

The UCAN that a user sends along is signed with a non-exportable WebCrypto private key scoped to the current page. It is non-exportable at the browser level, meaning that malicious javascript is unable to access it.

The server then checks the UCAN to ensure that the user has the proper permissions to request a cosignature. If they do, the server will sign the transaction, aggregate the signature with the user’s, and forward the transaction to the Filecoin network.

This approach of aggregated signatures ensures that:

  • malicious javascript is not able to send FIL from a user’s wallet, since, even if they are able to obtain the signing key held client-side, they will be unable to permission a UCAN for the other half of the signature
  • a cosigning server that turns out to be a bad actor is unable to steal a user’s FIL as it only possesses one signing key and not the other that is held client-side

UCAN specifics

Here is a breakdown of an example payload for a UCAN that offers cosigning permissions

payload = {
   // Audience: the cosigning server's DID
  aud: 'did:key:zCosign...',
  // Expiration: the UCAN is set to expire 1 hr after permissioning
  exp: Math.floor(Date.now() / 1000) + 3600,
  // Facts: not necessary
  fct: null,
  // Issuer: the DID for the application sending the cosignature request
  iss: 'did:key:zLocalKey',
  // NotBefore: the UCAN can be used immediately
  nbf: Date.now(),
  // Proof: A valid UCAN from the auth lobby that gives an app permission to request a cosignature
  prf: ParentUCAN,
  // Resource: the aggregated key that the UCAN is permissioning
  rsc: {
    cosign: 'did:key:zAggKey'
  },
  // Potency: describes that this UCAN is only for signing FIL messages
  // and allows the ability to limit the amount that a given UCAN is able to spend
  ptc: {
    fil: {
      max: 1000
    }
  }
}

UCANs are very flexible, and we can set constraints on how a given key can be used. For instance, this token describes that a cosigner should sign data for did:key:zAggKey only if that data is a FIL transaction and it does not exceed a max spend of 1000FIL

Technical Flow

Code

The code is all open source and can be found on Github:

Security & Future Considerations

UCANs

Like most things in crypto, there are some tradeoffs between security and user experience. Fortunately, UCANs are very flexible and app developers can make these tradeoffs as they see fit.

For the purpose of this deliverable, we put (relatively) loose constraints on our cosigning UCANs. They default to an expiration of 1hr & a max spend of 1000 FIL.

For added security, the expiration length could be shortened, or UCANs could be labeled as one-time use and given a max spend of the exact amount of FIL to be spent. As well they could specify the recipient of the tx in the UCAN. All of these restrictions would increase protection against malicious javascript.

However, the more restrictions on the UCAN, the more often a user has to be redirected back to the auth lobby. We felt for the sake of this deliverable, allowing multiple transactions without redirect was preferable. We did include the high FIL limit to demonstrate the capabilities of UCANs in limited what an app is capable of.

Multisig wallet

As discussed earlier, if the cosigning server turns out to be a bad actor, they will be unable to steal a user’s FIL. However, the cosigning server could still refuse to cosign a tx, or they may be negligent and delete the cosigning secret key.

To protect against this, a future improvement would be to use a 1-of-n multisig wallet with the aggregated key as just one possible signer. By doing so, if a cosigning server turns out to be malicious or negligent, another key on the wallet would still be able to recover the funds.

Screencast

This is a walkthrough and narration of the app to show it working end to end. The latest version of the app is always available at https://ancient-round-crab.fission.app/ – please do try it out and give us feedback.

We have a FAQ that we will keep updated as we get questions.

Summary

  • Based on our research of BLS key aggregation and a co-signer model, we’ve built a cosigner implementation and implemented an end-to-end cosigning flow
  • The webnative-filecoin package creates a new Filecoin public address on the fly, in browser for instant onboarding. This works in any web browser, including on mobile, and is all non-custodial
  • The Filecoin Backup App demonstrates the Phase 2 criteria: creating a wallet in browser and sending Filecoin transactions

Now that we have transaction flows and signing working end to end, we will move on to Phase 3, which is completing storage deals on the Filecoin network.

All of this is running on testnet, and we use the testnet faucet to give funds to newly created accounts. This can be configured to run on mainnet.

This same method is applicable to other types of private keys, which enables browser based instant onboarding. Let us know if you’re interested in working on webnative-ethereum or other systems.