TEPs icon indicating copy to clipboard operation
TEPs copied to clipboard

TEP: Deterministic subaccounts

Open ProgramCrafter opened this issue 2 years ago • 15 comments

This proposal introduces a standard way to create privacy-preserving subaccounts for a given wallet seed (aka mnemonic).

ProgramCrafter avatar Nov 27 '22 16:11 ProgramCrafter

There are already HD Keys supported by hardware wallets, and alternatives are not required.

ex3ndr avatar Dec 20 '22 10:12 ex3ndr

@ex3ndr Could you provide link to specification of those? As well, what about software wallets?

ProgramCrafter avatar Dec 20 '22 16:12 ProgramCrafter

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.

ex3ndr avatar Dec 20 '22 16:12 ex3ndr

Well, so I think this deserves a discussion.

  • Deterministic subaccounts in my implementation

    • Profits
      1. minimal difference from TON-standard keys derivation procedure
      2. easier procedure means there is less risk of backdoor in keys generation scheme
      3. additional data size is unlimited
    • Drawbacks
      1. makes use of int-to-str conversion, which may produce unexpected float results in certain languages
      2. subwallet ID is equivalent to an additional word in mnemonic just not restricted to be in predefined set
  • Hierarhical deterministic (HD) keys

    • Profits
      1. (probably) consistent with other blockchains' keys derivation
      2. supported in hardware wallets
      3. chain code is big enough (and may hold hash of subwallet ID, for example)
    • Drawbacks
      1. needs careful consideration when dealing with extended keys to not share parent private key accidentally
      2. a good implementation would also have to define wrappers for extended public/private keys

ProgramCrafter avatar Dec 21 '22 12:12 ProgramCrafter

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);
}

PolyProgrammist avatar Dec 23 '22 12:12 PolyProgrammist

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 avatar Dec 23 '22 12:12 PolyProgrammist

@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

ProgramCrafter avatar Dec 24 '22 02:12 ProgramCrafter

@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 avatar Dec 24 '22 04:12 PolyProgrammist

@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?

ProgramCrafter avatar Dec 30 '22 16:12 ProgramCrafter

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.

ProgramCrafter avatar Dec 30 '22 16:12 ProgramCrafter

@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.

PolyProgrammist avatar Dec 30 '22 16:12 PolyProgrammist

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.

ex3ndr avatar Dec 30 '22 16:12 ex3ndr

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).

SlavikBaranov avatar Dec 30 '22 22:12 SlavikBaranov

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.

ex3ndr avatar Dec 30 '22 22:12 ex3ndr

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.

ProgramCrafter avatar Dec 31 '22 07:12 ProgramCrafter