|Author||Vincent Eli, Dan Finlay|
Among others cryptographic applications, scalability and privacy solutions for ethereum blockchain require that an user performs a significant amount of signing operations. It may also require her to watch some state and be ready to sign data automatically (e.g. sign a state or contest a withdraw). The way wallets currently implement accounts poses several obstacles to the development of a complete web3.0 experience both in terms of UX, security and privacy.
This proposal describes a standard and api for a new type of wallet accounts that are derived specifically for a each given application. We propose to call them
app keys. They allow to isolate the accounts used for each application, thus potentially increasing privacy. They also allow to give more control to the applications developers over account management and signing delegation. For these app keys, wallets can have a more permissive level of security (e.g. not requesting user’s confirmation) while keeping main accounts secure. Finally wallets can also implement a different behavior such as allowing to sign transactions without broadcasting them.
This new accounts type can allow to significantly improve UX and permit new designs for applications of the crypto permissionned web.
In a wallet, an user often holds most of her funds in her main accounts. These accounts require a significant level of security and should not be delegated in any way, this significantly impacts the design of cryptographic applications if a user has to manually confirm every action. Also often an user uses the same accounts across apps, which is a privacy and potentially also a security issue.
We introduce here a new account type, app keys, which permits signing delegation and accounts isolation across applications for privacy and security.
In this EIP, we provide a proposal on how to uniquely identify and authenticate each application, how to derive the accounts along an Hierarchical Deterministic (HD) path restricted for the domain and we finally define an API for applications to derive and use these app keys. This ERC aims at finding a standard that will fit the needs of wallets and application developers while also allowing app keys to be used across wallets and yield the same accounts for the user for each application.
Wallets developers have agreed on an HD derivation path for ethereum accounts using BIP32, BIP44, SLIP44, (see the discussion here). Web3 wallets have implemented in a roughly similar way the rpc eth api. EIP1102 introduced privacy through non automatic opt-in of a wallet account into an app increasing privacy.
However several limitations remain in order to allow for proper design and UX for crypto permissioned apps.
Most of GUI based current wallets don’t allow to:
- being able to automatically and effortlessly use different keys / accounts for each apps,
- being able to sign some app’s action without prompting the user with the same level of security as sending funds from their main accounts,
- being able to use throwable keys to improve anonymity,
- effortlessly signing transactions for an app without broadcasting these while still being able to perform other transaction signing as usual from their main accounts,
- All this while being fully restorable using the user’s mnemonic or hardware wallet and the HD Path determined uniquely by the app’s ens name.
We try to overcome these limitations by introducing a new account’s type, app keys, made to be used along side the existing main accounts.
These new app keys can permit to give more power and flexibility to the crypto apps developers. This can allow to improve a lot the UX of crypto dapps and to create new designs that were not possible before leveraging the ability to create and handle many accounts, to presign messages and broadcast them later. These features were not compatible with the level of security we were requesting for main accounts that hold most of an user’s funds.
An app is a website (or other) that would like to request from a wallet to access app keys. It can be any form of cryptography/identity relying application, ethereum but not only.
Once connected to a wallet, an application can request to access a set of accounts derived exclusively for that application using the hierarchical deterministic (HD) paths.
Applications’ HD path
Using the BIP32 and BIP43 standards, we propose to use the following HD path for each app keys:
m / [standardized Path Beginning]' / [persona path]' / [application uniquely assigned path]' / [app's custom subpath]
standardized HD Path Beginning is based on the EIP number that will be assigned to this EIP and we harden it. We use a different path than 44’ since it’s not bip44 compliant. At this point, I’m not sure if there is a list of BIP43 codes of standards following the
purpose field specification of BIP43.
persona path allows to use applications with different and isolated personas (or in other words accounts) that are tracable by the application. They will still be fully restorable from the same mnemonic.
application uniquely assigned path isolate each application along unique branches of the tree through these unique subPath combination.
app's custom subPath give freedom to application to use this BIP32 compliant subPath to manage accounts and other needed parameters.
Note that we suggest that each of these indexes, except those belonging to the app’s custom subpath, must be hardened to fully isolate the public keys across personas and applications.
Standardized HD Path Beginning
For the path header, several alternative are possible depending on what the cryptocommunities agree upon.
The least contentious is the following one (as suggested here in the BIP repository):
43' / 60' / 1775 '
However, there may be benefits to use only one depth instead of 3. We could use the
EIP Number' (ie. 1775) or a ` BIP Number’` if we attain some cross crypto agreement that would avoid collision.
We allow the user to use different personas in combination to her mnemonic to potentially fully isolate her interaction with a given app across personas. One can use this for instance to create a personal and business profile for a given’s domain both backup up from the same mnemonic, using 2 different personnas indexes. The app or domain, will not be aware that it is the same person and mnemonic behind both.
We use a string following BIP32 format (can be hardened) to define personas. The indexes should be hex under 0x80000000, 31 bits.
Applications’ Unique Identifiers
We need a way to uniquely identify each application. We will use a naming and a hashing scheme.
In our favored spec, each application is uniquely defined and authenticated by its name, a domain string. It can be a Domain Name Service DNS name or and Ethereum Name Service ENS name.
There are a few restrictions however on the characters used and normalisation, each name should be passed through the NamePrep Algorithm
In addition there must be a maximum size to the domain string that we need to determine such that the mapping from strings to nodes remains injective, to avoid collision.
We recommend this standard to be following the ENS Specs, reproduced below for convenience and reference.
Normalising and validating names Before a name can be converted to a node hash using Namehash, the name must first be normalised and checked for validity - for instance, converting fOO.eth into foo.eth, and prohibiting names containing forbidden characters such as underscores. It is crucial that all applications follow the same set of rules for normalisation and validation, as otherwise two users entering the same name on different systems may resolve the same human-readable name into two different ENS names.
Hashing and Applications UIDs
The ENS uses an hashing scheme to associate a domain to a unique hash,
node, through the
namehash function. We will use this hashing scheme both for ENS and for DNS names.
This gives an unique identifier (UID) of 32 bytes.
e.g. for foo.bar.eth app's uid 0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3
For reference, here are the specs of ENS:
domain - the complete, human-readable form of a name; eg, ‘vitalik.wallet.eth’. label - a single component of a domain; eg, ‘vitalik’, ‘wallet’, or ‘eth’. A label may not contain a period (‘.’). label hash - the output of the keccak-256 function applied to a label; eg, keccak256(‘eth’) = 0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0. node - the output of the namehash function, used to uniquely identify a name in ENS. Algorithm First, a domain is divided into labels by splitting on periods (‘.’). So, ‘vitalik.wallet.eth’ becomes the list [‘vitalik’, ‘wallet’, ‘eth’]. The namehash function is then defined recursively as follows: namehash() = 0x0000000000000000000000000000000000000000000000000000000000000000 namehash([label, …]) = keccak256(namehash(…), keccak256(label)) keccak256(‘eth’) = 0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0
We thus propose to use the node of each app’s domain as a unique identifier for each app but one can think of other UIDs, we include some alternative specs in the Rationale section below.
If the application is using a DNS name then we simply authenticate the application by using the url of the loaded browser webpage.
For applications using ENS, we can authenticate the application through ENS resolution.
The ENS can also allow to register and resolve metadata for the application such as
url, and other parameters.
If we use for instance this resolver profile defined in EIP634 which permits the lookup of arbitrary key-value text data, we can for instance use the key
url to point to a website.
A new resolver interface is defined, consisting of the following method: function text(bytes32 node, string key) constant returns (string text); The interface ID of this interface is 0x59d1d43c. The text data may be any arbitrary UTF-8 string. If the key is not present, the empty string must be returned.
One can think of other authentication methods and even use some of them alongside the url-resolution method through ENS. We mention other methods in the Rationale section.
We suggest for instance to also add an
authorEthAddress text metadata field that can be used to authenticate messages from the application, with for instance a sign challenge.
Applications UID decomposition to get a BIP32 HD path
Since each child index in an HD path only has 31 bits we will decompose the domain’s hash as several child indexes, first as hex bytes then parsed as integers.
For the applications’s uid we use an
ENS namehash node of 32 bytes, 256 bits (removing the leading
foo.bar.eth which gives the following namehash node:
We can decompose it in several ways, here are 2 potential ways:
- First approach could favor having the least indexes:
This requires to first convert the hex uid to 256 bits then decompose it as 8 * 31 bits + 8 bits
x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7 || x8
x7 are 31 bits and
x8 is 8 bits
then we convert the
x_i to uints.
The derivation sub-path would be:
E.g. foo.bar.eth 0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 converted to binary (256 bits) 6033644d673b 011000000011001101100100010011010110011100111011 47b3bea04e79 010001111011001110111110101000000100111001111001 bbe06d78ce76 101110111110000001101101011110001100111001110110 b8be2fb8704f 101110001011111000101111101110000111000001001111 9c2a80fd139c 100111000010101010000000111111010001001110011100 81d3 1000000111010011 256 bits: 0110000000110011011001000100110101100111001110110100011110110011101111101010000001001110011110011011101111100000011011010111100011001110011101101011100010111110001011111011100001110000010011111001110000101010100000001111110100010011100111001000000111010011 converted to less than or equal to 31 bits indexes: 8 * 31 bits + 1 * 8 bits 0110000000110011011001000100110 1011001110011101101000111101100 1110111110101000000100111001111 0011011101111100000011011010111 1000110011100111011010111000101 1111000101111101110000111000001 0011111001110000101010100000001 1111101000100111001110010000001 11010011 and converted to uints 806990374'/1506726380'/2010384847'/465438423'/1181988293'/2025775553'/523785473'/2098437249'/211'
- Second approach favors an homogeneous decomposition:
Equal length indexes would be 16 * 16 bits or in other words 16 * 2 bytes, cleanest and favored spec:
x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7 || x8 || x9 || x10 || x11 || x12 || x13 || x14 || x15 where || is concatenation
E.g. foo.bar.eth 0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 6033 644d 673b 47b3 bea0 4e79 bbe0 6d78 ce76 b8be 2fb8 704f 9c2a 80fd 139c 81d3 6033'/644d'/673b'/47b3'/bea0'/4e79'/bbe0'/6d78'/ce76'/b8be'/2fb8'/704f'/9c2a'/80fd'/139c'/81d3' 24627'/25677'/26427'/18355'/48800'/20089'/48096'/28024'/52854'/47294'/12216'/28751'/39978'/33021'/5020'/33235'
Between these 2 decomposition approaches, there is a trade-off between computational efficiency (having less depth) and having an homegenous decomposition. We tend to favor the first approach with least indexes.
Application customisable HD sub path
Finally, the last part of the hd path is under the application’s control. This will allow applications developers to use the HD path structure that best fits their needs. Developers can for instance, among any combination of other parameters they like, choose to include a
version field if they would like to use different signing accounts when updating to a new version. They can then also manage the user accounts in the way they would like, for instance including or not an index for
sets of accounts (called
accounts in BIP44), an index for
change and an index for
address_index in BIP44).
We consider that a given child on the HD tree should be called an
account and not an
address since it is composed of a private key, a public key and an address.
Similarly to the persona path, this sub path must follow bip32, with hex under 0x80000000, 31 bits. It can be hardened depending on each application’s needs and can be written as hex or unsigned integers. It can include a large number of indexes.
Q [Should we set a limit on the persona and application customsable hd path number of indexes?]
Example HD paths for app keys:
Dummy data: EIP Number: 1775 personaPath: 0'/712' application's name: foo.bar.eth uid: 0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 app custom path params: app_version, set_of_accounts_index, account_index
We propose to introduce new RPC methods but they should be restricted and wrapped such that some parameters (e.g. domain name) are imposed by the wallet on the caller depending on the caller’s authentication.
[TBD] Specify scope of RPC methods (some params should be forced to the authenticated domain value) and how to integrate them into web3 api.
App keys exposure:
wallet.appkey.enable(options)This method allows to enable app keys (getting user permission to use and allow him to select the persona she would like to use).
[TBD] Could return the account public key from the HD path before
the app's custom subPath. Hence from this app’s root account, one could derive all non hardened children public keys of the app’s keys.
Options could also include a challenge to be signed by the app’s root account (would serve as authentication of the users from the app’s perspective). The signature should then be also returned.
Options should also include a parameter for the application to indicate which name should be used to compute the domain’s HD path. That’s required for applications that are loaded through ENS. They could be authenticated either through ENS or through DNS. These applications may like to use the DNS name even when they are resolved through ENS. (e.g. an application that just upgraded to ENS may like to continue using DNS paths to be retro-compatible for its former users).
Uses the persona selected by the user (not known nor controllable by application).
Uses the domain ens namehash (node) that was resolved to load window (not provided by application itself)
Ethereum accounts methods:
appKey_eth_getPublicKey(hdSubPath) returns publicKey 64 bytes:
hdSubPath string with BIP32 format, “index_i / index_(i+1) ‘”, can use hardening
publicKey returns e.g. 0x80b994e25fb98f69518b1a03e59ddf4494a1a86cc66019131a732ff4a85108fbb86491e2bc423b2cdf6f1f0f4468ec73db0535a1528ca192d975116899289a4b
appKey_eth_getAddress(hdSubPath) returns address 20 bytes:
hdSubPath: string with BIP32 format, “index_i / index_(i+1) ‘”, can use hardening
address e.g. 0x9df77328a2515c6d529bae90edf3d501eaaa268e
appKey_eth_derivePublicKeyFromParent(parentPublicKey, hdSubPath) returns publicKey 64 bytes
hdSubPath: string with BIP32 format, “index_i / index_(i+1) ‘”, should not use hardening here.
appKey_eth_getAddressForPublicKey(publicKey) returns address 20 bytes
publicKey 64 bytes
Ethereum signing methods:
appKey_eth_signTransaction(fromAddress, tx)tx is ethereum-js tx object
Ethereum broadcasting methods:
appKey_eth_broadcastTransaction(tx, signedTx)tx is ethereum-js tx object
Other potential methods:
We defined for now Ethereum accounts and signing methods. However, one could do the same for other cryptocurrencies deriving accounts along their standards. This may open to some very interesting cross-blockchains application designs.
Other cryptographic methods:
Similarly, using entropy provided by the HD Path, one could think of other cryptographic methods such as encryption and also other curve types.
The HD path for each application can also be used as a key to isolate databases for user’s persistent data. We could introduce methods that allow to read and write in a database specific to the application.
Q [Benefit of this compared to using classical browser local storage?]
API permissions and confirmations from users:
Initial permission request and full access afterwards:
Each wallet has freedom in the way they implement their permission system along with this EIP and this API. We tend to favor a design where the applications would request once and for all full access to the applications keys (for their domain) and that the user has to confirm this once. From then on, any account derivation or signing for those applications keys will not prompt a confirmation request on the wallet side. However applications themselves are free to reproduce some confirmation at their own level if they would like the users to double check the transactions or signatures they are making at the application level. This will be of course dependent on trusting the application code.
However, we would like to give users the option to monitor at any point applications keys and how applications user them. We therefore encourage wallets to introduce a
paranoia mode that users can activate (for instance in the wallet advanced settings) to force confirmations request for all the applications keys actions.
Isolated paths but customisable
The proposed specifications permit to have isolation between personas and between applications. Each persona / application combination will yield a unique subtree that can be explored by the application using the structure it would like to use.
Personas are known only by the user and its wallet, application’ UID based path is computable by everyone from the application’s name. And then the application decides and communicates the final levels of the path.
Only the wallet and the user will know the full tree and where we are in the tree (depth, parents). Applications will have knowledge only of the subtree, starting after the persona.
API not exposing private keys
Applications can derive accounts and request signing from them but they will not get access to the private keys of these accounts. So when the user closes her wallet entirely, the application can not continue signing for the user. This is of course in order to keep an user’s ultimate control over its accounts.
If there is a strong demand, we could add a method that exposes the private keys for the application accounts but it would be an optional to request upon app keys initial setup.
We indeed think that writing applications that don’t need to manipulate the user private keys is a better pattern. For instance, if one needs the user to sign data while being offline, one should for instance rather implement a delegation method to an external application’s controlled account rather than storing the user private key on a server that stays online.
Persona isolation across applications for privacy
The persona path is set by the user-wallet interaction and known only by them. There is thus a strict isolation between 2 different persona subpaths as if they were generated by different mnemonics.
Instead of personas, an alternative proposal would be to make the
application UID based path a subset of a user’s ethereum main accounts)
Most wallets use the following derivation path for ethereum accounts:
where a is a set of account number and n is the account index
We could use:
m/44'/60'/a'/0/n / [Application UID based path] / [App controlled HD subPath]
This way, we could use accounts as personas.
However it does not necessarily make sense to anchor an application to a single main account. Some applications may like to interact with several “main accounts” or allow the user to change the main account they are using to deposit while keeping the same signing
app keys accounts. Some applications may even like to use non ethereum accounts.
Also this alternative specification HD path would not be BIP44 compliant but would be using this purpose field.
Also it may add complexity to restore a wallet and the used accounts, one should remember which account is associated with which application and application can not suggest you which account to use because they are not aware of this part of the path.
If we don’t harden the level indexes after the main account index, we could however enumerate all app keys of an user given a list a applications. We would first enumerate over the main accounts (assuming the wallet uses an account gap limit), then over the Applications list and then over the
Application controlled HD subPath if it allows to do so and has an account gap limit.
For the persona specification this may not be possible, unless we impose some structure on the personas such as using a basic index.
Hardened and non-hardened indexes: privacy and functionality
Hardening allows to increase privacy. If the extended public key of a parent level in the HD tree is known, public keys of its children can not be computed if they are hardened. On the contrary if the child indexes are not hardened one can enumerate the child public keys and use that for the application design or to easily restore a wallet and it increases functionality.
For the first parts of the HD tree, we need isolation and privacy. Thus we use hardened indexes for the persona and application paths in case some extended public key leaks at some previous level of the tree, it would protect the sub trees (of course this has no impact if private keys leak).
For instance if we don’t harden the application path, in case a persona public key is known and the application subpath does not use hardening either, one could get all
app keys public keys for every application for this persona.
However the app can use non hardened indexes in their custom path part to be able to benefit from guessing child public keys from parent one (for instance for counterfactual state channel interaction across 2 peers that would like to use new keys every time they counterfactually instantiate a new sub app).
Alternatives for the HD derivation path
m / purpose' / *
It is of course not be BIP44 compliant which uses the following tree level structure:
m / purpose' / coin_type' / account' / change / address_index
One could think of alternative specifications deviating from BIP43 or even BIP32. Or on the contrary, one could try to become BIP44 compliant, although we do not really see the benefit of that for app keys and it would impose serious limitations on how to identify the applications using potentially the
HD derivation path purpose field
If we agree on not using BIP44 but following BIP32 and BIP43, we need to settle on a purpose field. We can either use the 3 depth path proposed here (https://github.com/bitcoin/bips/pull/523) or try to rech agreement on a one depth path. A one depth path should however avoid collision. This can be achieves by either submitting a BIP or by maintening a list of BIP 43 purpose fields.
We did not find a list of BIP43 purpose code so here is what we could gather:
|44||BIP44||Multi-Account Hierarchy for Deterministic Wallets|
|45||BIP45||Structure for Deterministic P2SH Multisignature Wallets|
|48||SLIP48||Deterministic Key Hierarchy for Graphene-based Networks|
|49||BIP49||Derivation scheme for P2WPKH-nested-in-P2SH based accounts|
|80||BIP80||Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets|
|84||BIP84||Derivation scheme for P2WPKH based accounts|
|535348||Ledger app ssh|
|1775||EIP1775||App Keys: application specific wallet accounts|
Favoring a deterministic scheme for application uids
Quoting Vitalik in his post Meta: we should value privacy more, we indeed favor a deterministic scheme for applications specific accounts generation:
It would be nice to keep wallet software stateless, so users can easily export and import their keys between wallets; this implies using some deterministic scheme like privkey_for_dapp = hash(master_key + dapp_id). But then what is the dapp_id? How would that work for multi-contract dapps?
And we proposed to use the ENS domain hash, or node, as the dapp_id and to use a BIP32 structure instead to derive the private keys.
Alternative: using a centraly maintened index of application uids
EIP1581: Non-wallet usage of keys derived from BIP32 trees also discussed here proposes a scheme that relies on a list of indexes where application should register (similar to SLIP44 list for instance).
We think our approach while also being more englobing benefits from not requiring a centrally maintained registry. In our approach every application has already a potential unique identifier assigned to it.
Shortening the Hash node
Our current approach uses identification through an ENS name converted to a hash node and sliced fully but one could potentially keep only the first 16 bytes of the node for instance and slice them similarly. This may increase the chance of app collision but we probably can reduce the length while retaining an injective mapping from strings to hashes.
Alternative application identification specification
For the application unique identifiers, an alternative specification could favor using an
ethereum author address and including a signed message challenge for author for authentication.
It would also need to specify how to decompose this address.
The same reasoning as before would apply, if we use an
eth address of 20 bytes, 160 bits
x = x0 || x1 || x2 || x3 || x4 || x5
x4 are 30 bits and
x5 is 10 bits.
or alternatively equal length
x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7
x7 are 20 bits.
Another alternative could be to use the plain website url and get rid of ens altogether but it would require another way to authenticate applications. See for instance SLIP13 for such a proposal.
For authentication we use DNS and ENS resolution, and browsing to a given url resolved. A few comments on this:
A few comments in case of ENS resolution:
First connection requires the wallet to connect to ethereum mainnet, but once first resolution is done we could use some metadata parameter such as
author addressfor a blockchain less authentication of the application (e.g. application server signs a challenge message with the author address resolved in the ENS metadata).
The url the name resolves to through ENS can change without the user knowing and then a different application/website may be granted access to his app keys. But this means the ENS name owner address was copromised. This would be similar to using a signing challenge authentified by a known public key. If this known public key is compromised we have a similar problem.
Homoglyph attacks are not a bigger problem for
app keysthan it is for ENS since it will not grant access to
app keysfrom the real domain (they would be derived along a different path). However homoglyph applications may lure the user to send funds from her main account to an
app keyof a malicious homoglyphic domain.
Other metadata resolution through ENS that can be used alongside:
author address: already mentioned above
contract address: For app keys that would be designed to interact with a given ethereum contract (for instance app keys for a given token, if one desires to do so), other metadata fields could be used such as contract addresses.
In relation to the SLIP13 proposal mentioned above, one could think of alternative specifications that would use some certificate for authentication similar to https.
An Account gap limit standard for application controlled hd sub-path?
If applications don’t enumerate through their hd sub-path structure, we won’t be able to restore
app keys accounts by enumeration. However it has benefits to give total freedom to applications over the way they create accounts and use their sub-path. Also, it may be safe to assume that the part of the restoring procedure will be carried by the application itself and not by the wallets. The application will need a way to remember what accounts were derived for each user.
Privacy and the funding trail
If all an application needs to do with its keys is to sign messages and it does not require funding, then this EIP allows for privacy through the use of distinct keys for each application with a simple deterministic standard compatible across wallets.
However if these application keys require funding, there can be trail and the use of app keys would not fully solve the privacy problem there.
Mixers or anonymous ways of funding an ethereum address (ring signatures) along with this proposal would guarantee privacy.
Even if privacy is not solved fully without this anonymous funding method, we still need a way to easily create and restore different accounts/addresses for each application
From a wallet point of view, there does not seem to be incompatibities since these are separate accounts from those that were used previously by wallets and they are supposed to be used along-side in synergy.
However, for applications that associated in some way their users to their main accounts ethereum addresses may want to reflect on if and how they would like to leverage the power offered by
app keys to migrate to them and increase their user’s privacy, security and potentially also user-flow.
Provide some examples of accounts derived from a given mnemonic, persona, application and application’s custom subpath.
Example use cases
signing transactions without broadcasting them https://github.com/MetaMask/metamask-extension/issues/3475
token contract https://github.com/ethereum/EIPs/issues/85
default account for dapps https://ethereum-magicians.org/t/default-accounts-for-dapps/904
non wallet/crypto accounts EIP1581: Non-wallet usage of keys derived from BIP32 trees
state channel application
non custodian cross cryptocurrency exchange…
MetaMask team, Christian Lundkvist, Counterfactual team, Liam Horne, Erik Bryn, Richard Moore, Jeff Coleman.
HD and mnemonics
Derivation path for eth
Previous proposals and discussions related to app keys
Copyright and related rights waived via CC0.