TEPs
TEPs copied to clipboard
TEP: Deterministic subaccounts
This proposal introduces a standard way to create privacy-preserving subaccounts for a given wallet seed (aka mnemonic).
There are already HD Keys supported by hardware wallets, and alternatives are not required.
@ex3ndr Could you provide link to specification of those? As well, what about software wallets?
I am not sure about the specification, it is just normal HD Keys that are used everywhere. TON even has it's own assigned ID.
Well, so I think this deserves a discussion.
-
Deterministic subaccounts in my implementation
-
Profits
- minimal difference from TON-standard keys derivation procedure
- easier procedure means there is less risk of backdoor in keys generation scheme
- additional data size is unlimited
-
Drawbacks
- makes use of int-to-str conversion, which may produce unexpected float results in certain languages
- subwallet ID is equivalent to an additional word in mnemonic just not restricted to be in predefined set
-
Profits
-
Hierarhical deterministic (HD) keys
-
Profits
- (probably) consistent with other blockchains' keys derivation
- supported in hardware wallets
- chain code is big enough (and may hold hash of subwallet ID, for example)
-
Drawbacks
- needs careful consideration when dealing with extended keys to not share parent private key accidentally
- a good implementation would also have to define wrappers for extended public/private keys
-
Profits
So current implementation is:
export async function mnemonicToSeed(mnemonicArray, password) {
const entropy = await mnemonicToEntropy(mnemonicArray, password);
const seed = await pbkdf2Sha512(entropy, 'TON default seed', PBKDF_ITERATIONS);
return seed.slice(0, 32);
}
You are suggesting next one:
async function subwalletMnemonicToSeed(mnemonicArray, password, subwallet) {
const entropy = await mnemonicToEntropy(mnemonicArray, password);
const seed_level0 = await hmacSha512(entropy, 'Subwallet #' + subwallet);
const seed = await pbkdf2Sha512(seed_level0, 'TON default seed', PBKDF_ITERATIONS);
return seed.slice(0, 32);
}
Please note that you are offering one another possible seed from the same mnemonic. So I suggest it to be more compatible with the first one. Something like
async function subwalletMnemonicToSeed(mnemonicArray, password, subwallet) {
const entropy = await mnemonicToEntropy(mnemonicArray, password);
let Uint8Array seed = [];
if (subwallet > 0) {
const seed_level0 = await hmacSha512(entropy, 'Subwallet #' + subwallet);
seed = await pbkdf2Sha512(seed_level0, 'TON default seed', PBKDF_ITERATIONS);
} else {
seed = await pbkdf2Sha512(entrypy, 'TON default seed', PBKDF_ITERATIONS);
}
return seed.slice(0, 32);
}
As we discussed, there are BIP39 and BIP44 standards which can make TON compatible to other wallets. Derivation there is different. For example in Trust Wallet we agreed to use this default derivation path m/44'/607'/0' according to BIP44 standard. It would be great to include it in this or another TEP. I will write down the example code in next message
@PolyProgrammist Do you suggest putting both ways of generating mnemonic for subaccounts into libraries like tonweb?
It would be great to include it in this or another TEP
@PolyProgrammist Do you suggest putting both ways of generating mnemonic for subaccounts into libraries like tonweb?
It would be great to include it in this or another TEP
Yeah, this will enable native wallets to easy integration of mnemonic from trust wallet and other bip compatible wallets. But maybe it's for another TEP
@PolyProgrammist but won't two methods for generating subwallet seeds (and thus far more ways to generate different wallets, as new contracts have an additional field for subwallet ID) force people to do more mistakes or spend more time discovering why generated mnemonics are different?
Though, I think compromise option would look so:
async function subwalletMnemonicToSeed(mnemonicArray, password, subwallet) {
const entropy = await mnemonicToEntropy(mnemonicArray, password);
let Uint8Array seed = [];
if (subwallet < 0) {
// equivalent to hardened keys (they have top bit set; if subwallet ID is interpreted as int32, it's negative)
const seed_level0 = await hmacSha512(entropy, 'Subwallet #' + subwallet);
seed = await pbkdf2Sha512(seed_level0, 'TON default seed', PBKDF_ITERATIONS);
} else {
if (subwallet == 0) {
seed = await pbkdf2Sha512(entropy, 'TON default seed', PBKDF_ITERATIONS);
} else {
// ... HD keys derivation procedure
}
}
return seed.slice(0, 32);
}
@ex3ndr please, take a look on this.
@PolyProgrammist but won't two methods for generating subwallet seeds (and thus far more ways to generate different wallets, as new contracts have an additional field for subwallet ID) force people to do more mistakes or spend more time discovering why generated mnemonics are different?
There are a lot of bip39 compatible wallets https://getcoinplate.com/blog/bip39-compatible-wallets-list-2022-updated/ As soon as ton mnemonic is not compatible with bip39, it will be really hard to integrate ton in those wallets.
Sorry, what's the point? If you want deterministic accounts, you use classical BIP44, if you are a casual user, you use default TON mnemonics.
In my opinion it worths to use some existing standard for several reasons, especially in cryptography area:
- Existing standards have been reviewed and analysed for vulnerabilities.
- Reuse of existing code simplifies the support of various programming languages.
- Lack of support for specific programming language will force adopters to use in-house implementation of the standard and in-house implementations are likely to have security vulnerabilities or critical bugs that might lead to permanent loss of access to user's wallet.
It this specific case I'd suggest to use BIP32-Ed25519 standard (https://input-output-hk.github.io/adrestia/static/Ed25519_BIP.pdf) that's widely used in Solana blockchain. It's not only thoroughly analysed, implemented in multiple programming languages, but also can offer important features that are missing in current proposal (specifically, non-hardened derivation).
Everything already implemented in ledger and other hardware wallets, I don't understand what we are discussing here and why it is that important to support non-hardened derivation, this paper is far from well tested.
I also don't understand the discussion well.
Now I think integrating HD keys of BIP32-Ed25519 into libraries would be the best solution. If you also think so, please react with 👍 emoji on this comment. Then I'll edit my PR.
this paper is far from well tested
However, how is "classic" BIP32 meant to work with ed25519? This curve requires certain bits of private key to be fixed.