lnd/aezeed
2022-05-12 12:47:06 +02:00
..
bench_test.go aezeed: add a set of benchmarks 2018-03-01 17:10:54 -08:00
cipherseed_rpctest.go multi: add golang 1.17 compatible build tags 2021-09-29 17:31:37 -07:00
cipherseed_test.go aezeed: fix typos and formatting 2022-05-12 12:47:06 +02:00
cipherseed.go aezeed: fix typos and formatting 2022-05-12 12:47:06 +02:00
errors.go aezeed: fix typos and formatting 2022-05-12 12:47:06 +02:00
README.md multi: unify code blocks in READMEs 2021-01-22 09:14:11 +01:00
wordlist.go aezeed: export wordlist and properties 2021-06-30 14:20:32 +02:00

aezeed

In this PR we added a new package implementing the aezeed cipher seed scheme (based on aez).

This new scheme aims to address two major features lacking in BIP39: versioning, and a wallet birthday. The lack a version means that wallets may not necessarily know how to re-derive addresses during the recovery process. A lack of a birthday means that wallets dont know how far back to look in the chain to ensure that they derive all the proper user addresses. Additionally, BIP39 use a very weak KDF. We use scrypt with modern parameters (n=32768, r=8, p=1). A set of benchmarks has been added, on my laptop I get about 100ms per attempt):

⛰  go test -run=XXX -bench=.

goos: linux
goarch: amd64
pkg: github.com/lightningnetwork/lnd/aezeed
BenchmarkTomnemonic-4                 20          93280730 ns/op        33559670 B/op         36 allocs/op
BenchmarkToCipherSeed-4               10         102323892 ns/op        36915684 B/op         41 allocs/op
PASS
ok      github.com/lightningnetwork/lnd/aezeed  4.168s

Aside from addressing the shortcomings of BIP 39, an aezeed cipher seed can both be upgraded, and have its password changed.

Sample seed:

ability dance scatter raw fly dentist bar nominee exhaust wine snap super cost case coconut ticket spread funny grain chimney aspect business quiz ginger

Plaintext aezeed encoding

The aezeed scheme addresses these two drawbacks and adds a number of desirable features. First, we start with the following plaintext seed:

1 byte internal version || 2 byte timestamp || 16 bytes of entropy

The version field is for wallets to be able to know how to re-derive the keys of the wallet.

The 2 byte timestamp is expressed in Bitcoin Days Genesis, meaning that the number of days since the timestamp in Bitcoins genesis block. This allow us to save space, and also avoid using a wasteful level of granularity. This can currently express time up until 2188.

Finally, the entropy is raw entropy that should be used to derive the wallets HD root.

aezeed enciphering/deciperhing

Next, well take the plaintext seed described above and encipher it to procure a final cipher text. Well then take this cipher text (the CipherSeed) and encode that using a 24-word mnemonic. The enciphering process takes a user-defined passphrase. If no passphrase is provided, then the string “aezeed” will be used.

To encipher a plaintext seed (19 bytes) to arrive at an enciphered cipher seed (33 bytes), we apply the following operations:

  • First we take the external version and append it to our buffer. The external version describes how we encipher. For the first version (version 0), well use scrypt(n=32768, r=8, p=1) and aezeed.
  • Next, well use scrypt (with the version 9 params) to generate a strong key for encryption. Well generate a 32-byte key using 5 bytes as a salt. The usage of the salt is meant to make the creation of rainbow tables infeasible.
  • Next, the enciphering process. We use aez, modern AEAD with nonce-misuse resistance properties. The important trait we exploit is that its an arbitrary input length block cipher. Additionally, it has whats essentially a configurable MAC size. In our scheme well use a value of 8, which acts as a 64-bit checksum. Well encrypt with our generated seed, and use an AD of (version || salt).
  • Finally, well encode this 33-byte cipher text using the default word list of BIP 39 to produce 24 English words.

Properties of the aezeed cipher seed

The aezeed cipher seed scheme has a few cool properties, notably:

  • The mnemonic itself is a cipher text, meaning leaving it in plaintext is advisable if the user also sets a passphrase. This is in contrast to BIP 39 where the mnemonic alone (without a passphrase) may be sufficient to steal funds.
  • A cipherseed can be modified to change the passphrase. This means that if the users wants a stronger passphrase, they can decipher (with the old passphrase), then encipher (with a new passphrase). Compared to BIP 39, where if the users used a passphrase, since the mapping is one way, they cant change the passphrase of their existing HD key chain.
  • A cipher seed can be upgraded. Since we have an external version, offline tools can be provided to decipher using the old params, and encipher using the new params. In the future if we change ciphers, change scrypt, or just the parameters of scrypt, then users can easily upgrade their seed with an offline tool.