use k256::elliptic_curve::sec1::ToEncodedPoint;
use k256::PublicKey;
use sha3::{Digest, Keccak256};
pub fn generate_address(pub_key_sec1_string: String) -> Result<String, String> {
let pub_key_sec1_bytes =
hex::decode(&pub_key_sec1_string).map_err(|_| "Invalid hex format.".to_string())?;
let pub_key = match PublicKey::from_sec1_bytes(&pub_key_sec1_bytes) {
Ok(key) => key,
Err(_) => return Err("Invalid SEC1 public key format.".to_string()),
};
let point = pub_key.to_encoded_point(false);
let point_bytes = point.as_bytes();
if point_bytes[0] != 0x04 {
return Err("Invalid uncompressed point format".to_string());
}
let mut hasher = Keccak256::new();
hasher.update(&point_bytes[1..]); let result = hasher.finalize();
let mut eth_address = [0u8; 20];
eth_address.copy_from_slice(&result[12..]);
Ok(format!("0x{}", hex::encode(eth_address)))
}
#[cfg(test)]
mod tests {
use super::*;
const PUB_KEY_UNCOMPRESSED: &str = "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
const PUB_KEY_COMPRESSED: &str =
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
const ETH_ADDRESS: &str = "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf";
#[test]
fn test_generate_address_valid_uncompressed_key() {
let result = generate_address(PUB_KEY_UNCOMPRESSED.to_string());
assert!(result.is_ok());
let address = result.unwrap();
assert_eq!(address, ETH_ADDRESS);
}
#[test]
fn test_generate_address_valid_compressed_key() {
let result = generate_address(PUB_KEY_COMPRESSED.to_string());
assert!(result.is_ok());
let address = result.unwrap();
assert_eq!(address, ETH_ADDRESS);
}
#[test]
fn test_generate_address_invalid_key() {
let invalid_pub_key = "invalid_key".to_string();
let result = generate_address(invalid_pub_key);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Invalid hex format"));
}
}