Skip to content

Instantly share code, notes, and snippets.

@benjaminion
Last active December 23, 2021 15:15
Show Gist options
  • Save benjaminion/6d24491abe01a40e728c37f0834f5009 to your computer and use it in GitHub Desktop.
Save benjaminion/6d24491abe01a40e728c37f0834f5009 to your computer and use it in GitHub Desktop.
Convert Eth2 EIP-2335 scrypt keystores to pbkdf2 keystores
## Converts Eth2 EIP-2335 scrypt keystores to pbkdf2 keystores
#
# Requires ethdo (https://github.com/wealdtech/ethdo) and jq.
#
# Tested with ethdo v1.7.3 and Teku v0.12.5+508-g03d75b2
#
# Notes:
# - I'd definitely do this off-line and air-gapped.
# - The files in INPUT_DIR and PASS_DIR are not modified.
# - Take care of directory and file permissions. This script assumes it can
# access everything it needs to, and doesn't make any special settings.
# - The following abuses ethdo in various undeserved ways...
### Settings ####
ethdo=~/bin/ethdo
# The existing keystores in Teku's normal ingestion format.
# Individual keystores are named <x>.json
INPUT_DIR=`pwd`/validator_keys_scrypt
# Where the pbkdf2 files will be written to.
# They will end up with the same format as INPUT_DIR.
OUTPUT_DIR=`pwd`/validator_keys_pbkdf2
# Keystore passwords are here. One file named <x>.txt for each <x>.json.
# Passwords are unchanged by the process.
PASS_DIR=`pwd`/passwords
### Processing ###
echo Using ethdo version $($ethdo version)
echo Using output directory $OUTPUT_DIR
if [ "$INPUT_DIR" == "$OUTPUT_DIR" ]; then
echo "ERROR: output directory cannot be the same as input directory" >&2
exit 1;
fi
mkdir -p $OUTPUT_DIR
WALLET1=Wallet1
WALLET2=Wallet2
## Create wallets
if $ethdo wallet list | grep $WALLET1 > /dev/null; then
echo Deleting $WALLET1
$ethdo wallet delete --wallet=$WALLET1
fi
if $ethdo wallet list | grep $WALLET2 > /dev/null; then
echo Deleting $WALLET2
$ethdo wallet delete --wallet=$WALLET2
fi
echo Creating wallet $WALLET1
$ethdo wallet create --wallet=$WALLET1
echo Creating wallet $WALLET2
$ethdo wallet create --wallet=$WALLET2
## Find out where the wallets are stored in the filesystem
wallet1_dir=$($ethdo wallet info --verbose --wallet=$WALLET1 | grep 'Location:' | cut -c 11-)
wallet2_dir=$($ethdo wallet info --verbose --wallet=$WALLET2 | grep 'Location:' | cut -c 11-)
echo Wallet1 directory: $wallet1_dir
echo Wallet2 directory: $wallet2_dir
## Repeatedly populate the wallet with accounts to convert
n=0
for keystore in $INPUT_DIR/*.json
do
echo Processing $keystore
## Extract UUID of the account
uuid=$(cat $keystore | jq '.uuid' | tr -d '"')
## Add account name to the keystore and copy it into Wallet1
account=Account$(printf "%05d" $n)
cat $keystore | jq -c ". * {name: \"$account\"}" > $wallet1_dir/$uuid
cat $wallet1_dir/index | jq -c ". += [{uuid:\"$uuid\",name:\"$account\"}]" > $wallet1_dir/index_tmp && mv $wallet1_dir/index_tmp $wallet1_dir/index
base=$(basename -s '.json' $keystore)
password=$(cat $PASS_DIR/$base.txt)
# Export the private key from the original (scrypt) wallet account and
# immediately import it into a new (pbkdf2) wallet account
$ethdo account import --key=$($ethdo account key --account=$WALLET1/$account --passphrase=$password) --account=$WALLET2/$account --passphrase=$password --allow-weak-passphrases
## Copy the new (pbkdf2) keystore to the output directory
echo Copying new keystore to the output directory
new_uuid=$(cat $wallet2_dir/index | jq '.[0].uuid' | tr -d '"')
cp $wallet2_dir/$new_uuid $OUTPUT_DIR/$base.json
# Ethdo does not helpfully order the accounts in the wallet, and there seems to be
# no clean way to delete an account, so we reset the index by force.
echo -n '[]' > $wallet2_dir/index
((n++))
done
## Tidy up
echo Deleting wallet $WALLET1
$ethdo wallet delete --wallet=$WALLET1
rm -rf $wallet1_dir
echo Deleting wallet $WALLET2
$ethdo wallet delete --wallet=$WALLET2
rm -rf $wallet2_dir
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment