-
Notifications
You must be signed in to change notification settings - Fork 1
SMIP: Spacemesh Reference Wallets - File Format and Accounts Derivation #17
Comments
@IlyaVi - we may want to move the contacts to inside ciphertext for increased privacy. The contacts is linking an address to a potential personally identifiable information. |
Hardware Wallet SupportA spacemesh wallet can be backed by a hardware wallet (e.g. Ledger wallet) or be a hot wallet where the mnemonic is stored in the wallet file. Meta field
We add the The wallet's ciphertext syntax for a hardware wallet doesn't include the mnemonic field as it is only stored in the hardware wallet and we don't store specific accounts secret keys. e.g:
So we have an entry for each account created by the user which is backed by the hardware wallet, as well the public key of that account (obtained from the wallet). The path field specifies what account to use for signing when user the hardware wallet's api. |
Can we have a reference wallet with expected accounts for testing purposes? |
I think we can use smapp as the reference wallet as it implements support for this file format. In go-spacemesh we have 2 hard-coded accounts with balances for tests which are not used in public testnet. We can create a reference wallet file with these account - good idea. @IlyaVi |
@IlyaVi - we need to update this spec with the contacts now in cyphertext instead of cleartext in the current smapp implementation. Also - please review that this spec accurately describes the smapp implementation.. |
@IlyaVi - please see my last comment - this becomes a priority as we would like to have CLIWallet compatibility with smapp for release 0.2 |
So for clarity : cipherText now contains
|
And the Minimum Wallet Example is
|
I've updated the main smip to consider the hardware-wallet related fields - this info was only in a comment. |
Regarding spacemeshos/smapp#781 and discussion with @avive I have to update the wallet structure presented in this SMIP. Added:
Since it is a newly added property we had to assume that this property may not persist in the wallet file, so the developers should default it to the empty string for the local node or "host:port" (E.G. "192.168.1.1:30310") for the wallet only mode. |
Due to the brand-new transactions and accounts, we need to tweak the wallet file structure. So in the new version (v0.3), we will have keypairs (that were stored under the "accounts" key, but let's name them keypairs to avoid misunderstanding since these keypairs will be used only for signing/verifying instead of having their own balances), which may be used in accounts ("standard" ones: singlesig / multisig / vesting / vault, and 3rd-party ones in post genesis). So I propose to rename the current
keys with the question mark are optional Meanwhile, In addition to it, spawn arguments can be retrieved from the network only in the case the account represents a standard type (uses a built-in template, and this is valid for genesis, but we'd like to have custom templates in the future). As a consequence, it might be impossible to decode spawn arguments retrieved from the network without additional User interaction or other services. In other words, the user will need to provide a codec for the template, or the Template developer should register it in some public registry. @dshulyak @countvonzero @pigmej @lrettig @noamnelke, please check out my proposal and tell me if I miss or overcomplicate something :) In case it seems good — please let me know as well (thumbs up emoji will be enough) ;) |
So, to clarify: Do you think we could remove the "display name" from either the keychain or the accounts? This JSON structure won't be read by humans anyways because it should always be encrypted at rest. |
Yes, that's right.
I'd like to get rid of all redundant data there, but I'm not sure it will be handy for Users if we will get rid of one of
That's correct. But this JSON structure is also used in the client apps (which decrypts it), and the client app shows such metadata to the User ;) |
Btw, I don't how the hardware wallet keypairs will be integrated there. |
In relation to these two points, I think the best thing to do for now, would be to define a "core wallet file" which contains only the required data to successfully use the wallet. (I'll take some time today to define what might look like)
Can be stored in a separate data structure or even in separate files. This way, the core data required for every wallet (light clients, full nodes, archival nodes, anything else...) is standardized, and then the format of the "other stuff" can be suggested to, and interpreted by, the wallet/client developer. |
I had a conversation today with @pigmej about it. And I miss one important thing — all account types except SingleSig are scheduled for post genesis. In this case, current wallet file structure is enough. |
Motivation
We'd like to formalize how the reference Spacemesh wallets create accounts, sign transactions, manage wallets and accounts and persist wallet and accounts data to wallet file. This will allow different wallets such as CLIWallet and Smapp to use wallets created by any of these apps. Currently, the CLIWallet file format is different than Smapp's plus we don't encrypt the data at rest in CLIWallet. This spec will also allow the community to write their own Spacemesh wallets. It is also important for building hardware wallets support for Spacemesh coins.
Implementation Notes
Smapp already implements this SMIP.
Spacemesh app wallet structure
Wallet File Name
Wallet file name pattern is:
my_wallet__<creation_timestamp>.json
.:
chars replaced with-
.Example file name:
my_wallet_2020-05-26T09-53-06.105Z.json
.Wallet File Contents - Json Syntax
displayName
- Wallet's display name, up to 50 chars.created
- Creation timestamp - same format as the timestamp in the wallet's file name.netId
- Network id that this wallet is designated to work with. Currently unused. It will be used later to match a wallet file to a specific Spacemesh network. Legal values are 0-255.hd_id
- 0: a hot wallet. 1: a ledger wallet. 2: tezos wallet. When field is excluded, assume value is 0 - a whot wallet.cipher
- The name of the encryption algorithm used to encrypt and to decrypt the secret part of the wallet (cipher text). Currently onlyAES-128-CTR
is supported.cipherText
- Encrypted wallet's data. Hex string.contacts
- array of contact objects. Contact object syntax:nickname
- Contact friendly name. String up to 50 characters.address
- 40 hex chars representing contact's 20 bytes address.A decrypted
cipherText
data has the following json syntax:mnemonic
- 12 words concatenated in single string with single space between each word. This field should be excluded or value set to the empty string when wallet is a hardware wallet. e.g. "hd_id" != 0.accounts
- array of account objects. Each object consists of:displayName
- account name up to 50 chars.created
- creation timestamp in the same format as in file name and the wallet'screated
timestamp field.path
- string in the form0/0/<account number>
, whereaccount number
is integer representing serial number of accounts created in this wallet.publicKey
- hex string of the account's public key byte array.secretKey
- hex string of the account's secret key byte array. This field should be excluded or value set to the empty string when wallet is a hardware wallet. e.g. "hd_id" != 0 as the secretKey is only available in the hardware wallet.Minimal Wallet Json Example
TODO: add example of decrypted cipher text with 2 accounts here...
Mnemonic and accounts key-pair generation
bip39.generateMnemonic
. Result is 12 words string separated by white spaces.bip39.validateMnemonic
to validate a mnemonic.Account Generation
Call
bip39.mnemonicToSeedSync
with a mnemonic to generate a seed.The signature scheme used to generate signing keys and to derive new pairs from the seed is ed25519. Note that this is a custom ed25519 signature scheme developed by Spacemesh and not the standard ed25519 signature scheme.
To create user accounts in the wallet, use
ed25519.NewDerivedKeyFromSeed
to create a new key pair, with the following params:seed
- From callingbip39.mnemonicToSeedSync
.index
- Account's serial number. e.g 0, 1, 2...salt
- String "Spacemesh blockmesh" encoding using UTF-8 to a byte array.The first wallet's account should be the derived account index 0, the second at 1, etc... Do not use the a master key-pair generated from the seed directly for user accounts. User accounts should always be used using ed25519.NewDerivedKeyFromSeed.
Spacemesh BIP32 paths
m / 44' / coin_type
/ [account] / 0 / [address_index]`1
for a Spacemesh Testnet and540
for Spacemesh mainent.m / 44' / 540' / 0' / 0 / 0'
.m / 44' / 540' / 0' / 0 / 1'
.address_index
is int32 so there can be up to 2^32 addresses per wallet.Wallet Creation Flows
Obtain Encryption / Decryption Key from User's Password
This key is used to encrypt and decrypt the wallet's file cipher-text binary data.
Encrypt and Decrypt Wallet data
Only AES is currently supported and we use aes-js in the following way:
Encryption
aes.utils.utf8.toBytes
on stringified json data to be encrypted to get the byte array representation of the data.where
key` is the encryption key we have created.aes.encrypt()
with byte array from step 1.aes.utils.hex.fromBytes
on the encrypted data result to get hex string representation to be saved in the wallet's file.Decryption
where
key` is the encryption key we created before.aes.utils.hex.toBytes
on the encrypted hex string to get bytes array representation of the encrypted data.aes.decrypt
to decrypt the bytes array.aes.utils.utf8.fromBytes
to get a json stringified representation of decrypted wallet data.The text was updated successfully, but these errors were encountered: