nash-protocol
Implementation of Nash cryptographic routines
This document is very WIP and should be checked for accuracy by someone with more expertise!
Getting started
yarn install
yarn build
yarn test
API
getEntropy = () => { publicKey: Buffer, secretKey: Buffer }
secretKeyToMnemonic = (secretKey: Buffer) => Array<string>
mnemonictoSecretKey = (Array<string>) => Buffer
mnemonicToMasterSeed = (mnemonic: Array<string>) => Buffer
hashPassword = (password: string) => Promise<Buffer>
getHKDFKeysFromPassword = (password: string, salt: string) => Promise<{ authKey: Buffer, encryptionKey: Buffer }>
interface AEAD = {
encryptedSecretKey: Buffer
nonce: Buffer
tag: Buffer
}
encryptSecretKey = (encryptionKey: Buffer, secretKey: Buffer) => AEAD
decryptSecretKey = (encryptionKey: Buffer, aead: AEAD) => Promise<Buffer>
regenerateMnemonic = (aead: AEAD, password: string): Array<String>
Usage Summary
Onboarding
- User signs up for an account with a password (and other stuff).
getEntropy()
generates their keys. - Secret key is used to generate mnemonic with
secretKeyToMnemonic()
. Asynchronously, the master seed is used to generate the master seed with mnemonicToMasterSeed()
. - User confirms they recorded the mnemonic.
- Auth / encryption keys are derived from password with
hashPassword()
and getHKDFKeysFromPassword()
. Auth key is sent to server. - Encryption key is used to encrypt the secret key with
encryptSecretKey()
. Output is sent to server. - Wallets are created with the master seed.
Logging in
- User submits password. Client processes into auth / encryption keys. Auth key is used to login, server responds with
aead
which can be decrypted using the encryption key.
Glossary
- Auth key: Derived from password. Stored on the server side to validate sessions.
- BIP-39: Protocol for generating master seed from private key.
- BIP-44: Protocol for generating wallet addresses from master seed.
- Chain: an ID for each blockchain we want to generate a private key for. Constant. TODO: Should this use the standardized chain IDs described in BIP-44, or should we make our own?
- Encryption key: Derived from password. Used to encrypt the private key for server side storage.
- Entropy: A secure-randomly generated bitstring composed of public and private key.
- Master seed: Hash generated by
PBKDF2(mnemonic, passphrase = "")
Iteration = 2048, uses HMAC-SHA512. Should be 512 bits (64 bytes). Used to generate wallet addresses. - Mnemonic: A n-word phrase generated from the entropy using a wordlist. Can be used along with passphrase to (re)generate the master seed. User needs to memorize this.
- Passphrase: An optional string for use with the
PBKDF2()
encryption function. - Password: User's login credential. Used to generate encryption key and auth key via HKDF.
- PBKDF2: The encryption function used to generate the master seed from the mnemonic and an optional passphrase.
- Private key: Abstracted into the mnemonic for better UX. We use this as the "master key" -- the ultimate password from which everything is derived, that should be protected at all costs. An encrypted version is stored on the server side.
- Public key: Used to verify signatures.
Notes
External wallet keys
We will NOT support the user supplying their own wallet keys. While users will control their own wallets, we will generate the wallets for them. This is partially because we want wallets to be deterministically derivable from the master seed.
Development
Publishing to NPM
Gitlab CI will automatically publish a version if it receives a new Git tag (see also the publish_to_npm
step in .gitlab-ci.yml
).
Here's the specific steps: Start with decide on a new release version, eg. v1.2.3
. Then create a branch and tag and push everything to Gitlab:
git checkout -b release/v1.2.3
yarn prepare-release
git push origin release/v1.2.3
git push origin refs/tags/v1.2.3
References