From 72f0dd085257f6f92f160c5539ecc019051751b0 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 26 May 2020 17:32:20 +0800 Subject: [PATCH] Fix key path --- eth2deposit/credentials.py | 14 +++++++++++--- .../key_handling/key_derivation/mnemonic.py | 16 +++++++++------- eth2deposit/key_handling/key_derivation/path.py | 2 +- eth2deposit/utils/crypto.py | 1 + 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/eth2deposit/credentials.py b/eth2deposit/credentials.py index e25d3c5..bb1f09d 100644 --- a/eth2deposit/credentials.py +++ b/eth2deposit/credentials.py @@ -21,9 +21,17 @@ from eth2deposit.utils.ssz import ( class ValidatorCredentials: def __init__(self, *, mnemonic: str, index: int, amount: int): - self.signing_key_path = 'm/12381/3600/%s/0' % index - self.signing_sk = mnemonic_and_path_to_key(mnemonic=mnemonic, path=self.signing_key_path) - self.withdrawal_sk = mnemonic_and_path_to_key(mnemonic=mnemonic, path=self.signing_key_path + '/0') + # Set path as EIP-2334 format + # https://eips.ethereum.org/EIPS/eip-2334 + purpose = '12381' + coin_type = '3600' + account = str(index) + withdrawal_key_path = f'm/{purpose}/{coin_type}/{account}/0' + self.signing_key_path = f'{withdrawal_key_path}/0' + + # Do NOT use password for seed generation. + self.withdrawal_sk = mnemonic_and_path_to_key(mnemonic=mnemonic, path=withdrawal_key_path, password='') + self.signing_sk = mnemonic_and_path_to_key(mnemonic=mnemonic, path=self.signing_key_path, password='') self.amount = amount @property diff --git a/eth2deposit/key_handling/key_derivation/mnemonic.py b/eth2deposit/key_handling/key_derivation/mnemonic.py index ef8e93c..e9f32c5 100644 --- a/eth2deposit/key_handling/key_derivation/mnemonic.py +++ b/eth2deposit/key_handling/key_derivation/mnemonic.py @@ -2,9 +2,9 @@ import os from unicodedata import normalize from secrets import randbits from typing import ( - List, Optional, Sequence, + Tuple, ) from eth2deposit.utils.crypto import ( @@ -22,27 +22,29 @@ def _get_word(*, word_list: Sequence[str], index: int) -> str: return word_list[index][:-1] -def get_seed(*, mnemonic: str, password: str='') -> bytes: +def get_seed(*, mnemonic: str, password: str) -> bytes: """ - Derives the seed for the pre-image root of the tree. + Derive the seed for the pre-image root of the tree. + + Ref: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#from-mnemonic-to-seed """ mnemonic = normalize('NFKD', mnemonic) salt = normalize('NFKD', 'mnemonic' + password).encode('utf-8') return PBKDF2(password=mnemonic, salt=salt, dklen=64, c=2048, prf='sha512') -def get_languages(path: str) -> List[str]: +def get_languages(path: str) -> Tuple[str, ...]: """ Walk the `path` and list all the languages with word-lists available. """ (_, _, filenames) = next(os.walk(path)) - filenames = [name[:-4] for name in filenames] - return filenames + languages = tuple([name[:-4] for name in filenames]) + return languages def get_mnemonic(*, language: str, words_path: str, entropy: Optional[bytes]=None) -> str: """ - Returns a mnemonic string in a given `language` based on `entropy`. + Return a mnemonic string in a given `language` based on `entropy`. """ if entropy is None: entropy = randbits(256).to_bytes(32, 'big') diff --git a/eth2deposit/key_handling/key_derivation/path.py b/eth2deposit/key_handling/key_derivation/path.py index 101b6d6..3a7e713 100644 --- a/eth2deposit/key_handling/key_derivation/path.py +++ b/eth2deposit/key_handling/key_derivation/path.py @@ -18,7 +18,7 @@ def path_to_nodes(path: str) -> List[int]: return [int(index) for index in indices] -def mnemonic_and_path_to_key(*, mnemonic: str, path: str, password: str='') -> int: +def mnemonic_and_path_to_key(*, mnemonic: str, path: str, password: str) -> int: """ Returns the SK at position `path` secures with `password` derived from `mnemonic`. """ diff --git a/eth2deposit/utils/crypto.py b/eth2deposit/utils/crypto.py index b66befb..7dda986 100644 --- a/eth2deposit/utils/crypto.py +++ b/eth2deposit/utils/crypto.py @@ -38,4 +38,5 @@ def HKDF(*, salt: bytes, IKM: bytes, L: int) -> bytes: def AES_128_CTR(*, key: bytes, iv: bytes) -> Any: + assert len(key) == 16 return _AES.new(key=key, mode=_AES.MODE_CTR, initial_value=iv, nonce=b'')