Merge secp256k1-ethereum-derivation with conflict resolution in service.rs tests

This commit is contained in:
2026-06-10 07:30:20 +00:00
4 changed files with 328 additions and 19 deletions

View File

@@ -76,6 +76,8 @@ pub enum SecretServiceError {
Encryption(String),
#[error("invalid path: {0}")]
InvalidPath(String),
#[error("unsupported key type")]
UnsupportedKeyType,
}
impl From<crate::mnemonic::MnemonicError> for SecretServiceError {
@@ -203,22 +205,35 @@ impl SecretServiceHandle {
}
/// Derive a secp256k1 (Ethereum) keypair at the given path.
///
/// Uses BIP-0032 derivation (HMAC-SHA512 with "Bitcoin seed") when the
/// `secp256k1` feature is enabled. Returns `UnsupportedKeyType` when the
/// feature is disabled.
pub fn derive_ethereum_key(&self, path: &str) -> Result<DerivedKey, SecretServiceError> {
let inner = self.inner.read().unwrap();
if !inner.unlocked {
return Err(SecretServiceError::ServiceLocked);
}
let seed = inner
.seed
.as_ref()
.ok_or(SecretServiceError::ServiceLocked)?;
#[cfg(feature = "secp256k1")]
{
let inner = self.inner.read().unwrap();
if !inner.unlocked {
return Err(SecretServiceError::ServiceLocked);
}
let seed = inner
.seed
.as_ref()
.ok_or(SecretServiceError::ServiceLocked)?;
let key = derivation::derive_path_from_seed(seed.as_bytes(), path)?;
Ok(DerivedKey {
key_type: KeyType::Secp256k1,
private_key: key.private_key().to_vec(),
public_key: key.public_key().to_vec(),
})
let key = crate::ethereum::derive_secp256k1_path(seed.as_bytes(), path)?;
Ok(DerivedKey {
key_type: KeyType::Secp256k1,
private_key: key.private_key().to_vec(),
public_key: key.public_key().to_vec(),
})
}
#[cfg(not(feature = "secp256k1"))]
{
let _ = path;
Err(SecretServiceError::UnsupportedKeyType)
}
}
pub fn derive_password(
@@ -504,4 +519,41 @@ mod tests {
let decoded = URL_SAFE_NO_PAD.decode(&encoded).unwrap();
assert_eq!(raw_bytes, decoded);
}
#[cfg(feature = "secp256k1")]
#[test]
fn test_derive_ethereum_key_bip32() {
let service = SecretServiceHandle::new();
service.unlock_new(24).unwrap();
let key = service.derive_ethereum_key(PATHS::ETHEREUM).unwrap();
assert_eq!(key.key_type, KeyType::Secp256k1);
assert_eq!(key.private_key.len(), 32);
assert_eq!(key.public_key.len(), 33);
}
#[cfg(feature = "secp256k1")]
#[test]
fn test_ethereum_key_differs_from_ed25519() {
let service = SecretServiceHandle::new();
service.unlock_new(24).unwrap();
let eth_key = service.derive_ethereum_key(PATHS::ETHEREUM).unwrap();
let ed_key = service.derive_ed25519(PATHS::IDENTITY).unwrap();
assert_ne!(eth_key.private_key, ed_key.private_key);
}
#[cfg(not(feature = "secp256k1"))]
#[test]
fn test_derive_ethereum_key_unsupported_without_feature() {
let service = SecretServiceHandle::new();
service.unlock_new(24).unwrap();
let result = service.derive_ethereum_key(PATHS::ETHEREUM);
assert!(matches!(
result,
Err(SecretServiceError::UnsupportedKeyType)
));
}
}