[NKP-0020] Upgrade wallet format (v2)

During the security audit, we found a few potential risks of the current wallet format (version 1):

  1. The current KDF is double sha256, making brute force password searching quite low cost if an attacker managed to get wallet.json: only one Ed25519 key gen is needed per password.
  2. Password hash is stored in wallet.json, further reduce brute force cost: just two sha256 are needed to test a password.

To eliminate these potential risks, we are proposing the next wallet format version (version 2), with the following changes to wallet.json:

  1. Use scrypt as KDF instead of double sha256, and store scrypt parameters (salt, n, r, p) in Scrypt field.
  2. Remove the following fields: PasswordHash, ProgramHash, ContractData.
  3. Upgrade the value of Version to 2.

Algorithm change:

  1. The value of passwordKey is changed from sha256(sha256(password)) to scrypt(salt, n, r, p, 32). Salt is a random byte array, encoded in hex format. The recommended (n, r, p) is (32768, 8, 1), and the recommended salt size is 8 bytes.
  2. When verify whether a password is correct or not, one should decrypt the wallet, compute wallet address, and compare it with the Address field of wallet.json. A correct password should give you the correct address, otherwise the password is wrong.

A sample wallet.json with password 123:

{
   "Version":2,
   "IV":"ffa90ac9ea923af95da01500f43875b0",
   "MasterKey":"232f695a7bce7b66855adc6191849c1f687b50341ad3d1aef554c721af22eb44",
   "SeedEncrypted":"cbc6e1eac1d3e17fb3e19e60db70ff9dfca487d93b169bef0355bc306bc3ebbd",
   "Address":"NKNV6H1RDx2Fc1iXMmCJN4hoxDdrfCDTPQPR",
   "Scrypt":{
      "Salt":"6551484dbb1a982a",
      "N":32768,
      "R":8,
      "P":1
   }
}

The SDK should still be able to parse and use v1 wallet format (based on Version field), but newly generated wallet should use v2 format for better security.

This NKP has been implemented in Go/JavaScript SDK.