Allow import of Prysm keystores (#1535)

## Issue Addressed

- Resolves #1361

## Proposed Changes

Loosens the constraints imposed by EIP-2335 so we can import keys from Prysm.

## Additional Info

NA
This commit is contained in:
Paul Hauner 2020-08-18 06:28:20 +00:00
parent 8311074d68
commit 46dd530476
6 changed files with 78 additions and 13 deletions

View File

@ -310,6 +310,15 @@ fn is_voting_keystore(file_name: &str) -> bool {
return true; return true;
} }
// The format exported by Prysm. I don't have a reference for this, but it was shared via
// Discord to Paul H.
if Regex::new("keystore-[0-9]+.json")
.expect("regex is valid")
.is_match(file_name)
{
return true;
}
false false
} }
@ -318,8 +327,12 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn voting_keystore_filename() { fn voting_keystore_filename_lighthouse() {
assert!(is_voting_keystore(VOTING_KEYSTORE_FILE)); assert!(is_voting_keystore(VOTING_KEYSTORE_FILE));
}
#[test]
fn voting_keystore_filename_launchpad() {
assert!(!is_voting_keystore("cats")); assert!(!is_voting_keystore("cats"));
assert!(!is_voting_keystore(&format!("a{}", VOTING_KEYSTORE_FILE))); assert!(!is_voting_keystore(&format!("a{}", VOTING_KEYSTORE_FILE)));
assert!(!is_voting_keystore(&format!("{}b", VOTING_KEYSTORE_FILE))); assert!(!is_voting_keystore(&format!("{}b", VOTING_KEYSTORE_FILE)));
@ -337,4 +350,14 @@ mod tests {
"keystore-m_12381_3600_1_0-1593476250.json" "keystore-m_12381_3600_1_0-1593476250.json"
)); ));
} }
#[test]
fn voting_keystore_filename_prysm() {
assert!(is_voting_keystore("keystore-0.json"));
assert!(is_voting_keystore("keystore-1.json"));
assert!(is_voting_keystore("keystore-101238259.json"));
assert!(!is_voting_keystore("keystore-.json"));
assert!(!is_voting_keystore("keystore-0a.json"));
assert!(!is_voting_keystore("keystore-cats.json"));
}
} }

View File

@ -24,10 +24,14 @@ use serde_repr::*;
pub struct JsonKeystore { pub struct JsonKeystore {
pub crypto: Crypto, pub crypto: Crypto,
pub uuid: Uuid, pub uuid: Uuid,
pub path: String, /// EIP-2335 does not declare this field as optional, but Prysm is omitting it so we must
/// support it.
pub path: Option<String>,
pub pubkey: String, pub pubkey: String,
pub version: Version, pub version: Version,
pub description: Option<String>, pub description: Option<String>,
/// Not part of EIP-2335, but `ethdo` and Prysm have adopted it anyway so we must support it.
pub name: Option<String>,
} }
/// Version for `JsonKeystore`. /// Version for `JsonKeystore`.

View File

@ -172,10 +172,11 @@ impl Keystore {
}, },
}, },
uuid, uuid,
path, path: Some(path),
pubkey: keypair.pk.to_hex_string()[2..].to_string(), pubkey: keypair.pk.to_hex_string()[2..].to_string(),
version: Version::four(), version: Version::four(),
description: None, description: None,
name: None,
}, },
}) })
} }
@ -218,8 +219,8 @@ impl Keystore {
/// Returns the path for the keystore. /// Returns the path for the keystore.
/// ///
/// Note: the path is not validated, it is simply whatever string the keystore provided. /// Note: the path is not validated, it is simply whatever string the keystore provided.
pub fn path(&self) -> &str { pub fn path(&self) -> Option<String> {
&self.json.path self.json.path.clone()
} }
/// Returns the pubkey for the keystore. /// Returns the pubkey for the keystore.

View File

@ -64,7 +64,7 @@ fn eip2335_test_vector_scrypt() {
Uuid::parse_str("1d85ae20-35c5-4611-98e8-aa14a633906f").unwrap(), Uuid::parse_str("1d85ae20-35c5-4611-98e8-aa14a633906f").unwrap(),
"uuid" "uuid"
); );
assert_eq!(keystore.path(), "", "path"); assert_eq!(keystore.path().unwrap(), "", "path");
} }
#[test] #[test]
@ -108,5 +108,5 @@ fn eip2335_test_vector_pbkdf() {
Uuid::parse_str("64625def-3331-4eea-ab6f-782f3ed16a83").unwrap(), Uuid::parse_str("64625def-3331-4eea-ab6f-782f3ed16a83").unwrap(),
"uuid" "uuid"
); );
assert_eq!(keystore.path(), "m/12381/60/0/0", "path"); assert_eq!(keystore.path().unwrap(), "m/12381/60/0/0", "path");
} }

View File

@ -841,10 +841,7 @@ fn missing_path() {
} }
"#; "#;
match Keystore::from_json_str(&vector) { assert!(Keystore::from_json_str(&vector).is_ok());
Err(Error::InvalidJson(_)) => {}
_ => panic!("expected invalid json error"),
}
} }
#[test] #[test]
@ -1010,3 +1007,43 @@ fn pbkdf2_missing_parameter() {
_ => panic!("expected invalid json error"), _ => panic!("expected invalid json error"),
} }
} }
#[test]
fn name_field() {
let vector = r#"
{
"crypto": {
"kdf": {
"function": "scrypt",
"params": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
},
"message": ""
},
"checksum": {
"function": "sha256",
"params": {},
"message": "149aafa27b041f3523c53d7acba1905fa6b1c90f9fef137568101f44b531a3cb"
},
"cipher": {
"function": "aes-128-ctr",
"params": {
"iv": "264daa3f303d7259501c93d997d84fe6"
},
"message": "54ecc8863c0550351eee5720f3be6a5d4a016025aa91cd6436cfec938d6a8d30"
}
},
"pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07",
"uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f",
"path": "",
"version": 4,
"name": "cats"
}
"#;
assert!(Keystore::from_json_str(&vector).is_ok());
}

View File

@ -225,13 +225,13 @@ fn key_derivation_from_seed() {
.expect("should generate keystores"); .expect("should generate keystores");
assert_eq!( assert_eq!(
keystores.voting.path(), keystores.voting.path().unwrap(),
format!("m/12381/3600/{}/0/0", i), format!("m/12381/3600/{}/0/0", i),
"voting path should match" "voting path should match"
); );
assert_eq!( assert_eq!(
keystores.withdrawal.path(), keystores.withdrawal.path().unwrap(),
format!("m/12381/3600/{}/0", i), format!("m/12381/3600/{}/0", i),
"withdrawal path should match" "withdrawal path should match"
); );