Technical Walkthrough

An overview of the background processes enabling Fluidkey.

This walkthrough provides background on Fluidkey's core crypto functions, which are released as an open source kit.

1. Background Reading

To keep the walkthrough concise, we assume the reader has a basic understanding of the following concepts. If you're not familiar with them, you can start with the linked resources.

2. User Keys

When a user signs into Fluidkey, they are asked to sign a key generation message with their existing Ethereum account. The signature of this message is used to derive the user's private key pair.

See generateKeysFromSignature in the kit.

The private key pair never leaves the user's client and is not stored locally. Every time the user re-opens the Fluidkey app and wants to send funds out, they must sign the key generation message again to derive their private keys.

The private key pair is composed of two keys:

  • A private spending key used to control user funds and sign transactions

  • A private viewing key used to retrieve user funds and view transactions

To allow Fluidkey to generate addresses on behalf of the user and retrieve their funds, the user shares a BIP-32 derived node of their private viewing key with Fluidkey.

The shared node is of the form m/5564'/N' where N is the number identifying the specific node shared. 5564 refers to ERC-5564, focused on standardizing the use of stealth addresses. Fluidkey currently uses 0 as the N value for all users. In the future, N may also be used to reference a specific time period (e.g. year, Unix timestamp) or other dimension to be able to give third parties view access to this specific dimension only.

See extractViewingPrivateKeyNode in the kit.

3. Stealth Accounts

Fluidkey currently uses 1/1 Safe smart accounts as stealth accounts. They act as stealth addresses with the added UX benefits of smart accounts, such as gas sponsorship.

By using Safe as the underlying smart account, Fluidkey users also benefit from the security of a battle-tested smart account implementation.

3.a. Stealth Signer Derivation

Each stealth account is controlled by a stealth EOA that acts as the sole signer authorized to approve transactions and control the stealth account.

The stealth EOA is derived pseudo-randomly using the viewing key node shared by the user (see section 2.). Every time a new stealth account is required, the ephemeral private key used to derive the stealth EOA is a new leaf of the shared viewing key node.

Specifically, each new stealth address request increments the viewing key node p/n by one and derives the secret from the obtained leaf m/5564'/N'/c0'/c1'/0'/p'/n', where c0 and c1 represent the coinType of the chain used following ENSIP-11.

We use c0'/c1' and p'/n' to ensure no single number in the derivation path exceeds or equals 0x80000000 (2^31) in line with BIP-32 requirements.

Currently Fluidkey uses a coinType corresponding to chainId 0, which allows us to generate addresses valid across all EVM chains supported in the interface. A Fluidkey derivation path should therefore look like m/5564'/0'/8'/0'/0'/p'/n'.

See generateEphemeralPrivateKey and generateStealthAddresses in the kit.

The pseudo-random derivation of the stealth EOA ensures that the user can independently replay all stealth addresses generated and recover funds without relying on Fluidkey.

3.b. Counterfactual Instantiation

Sending assets to a user's stealth account does not require the deployment of the underlying smart contract. Instead, the stealth account's address is counterfactually predicted and is only deployed at the moment of withdrawal.

See predictStealthSafeAddressWithClient in the kit.

4. ENS Resolution

Fluidkey provides users with a static ENS of the form and username.fkey.eth. This identifier resolves a new stealth address controlled by the recipient on every query. This allows users to send funds to a single human-readable identifier while protecting recipient privacy.

Fluidkey uses an ENS offchain resolver to return stealth addresses.

Last updated