v0.0.14: Ethereum-compatible identity (secp256k1 + Keccak-256)

Protocol (ethereum.rs):
- derive_eth_identity(): HKDF from seed (info="warzone-secp256k1")
- secp256k1 signing key (k256 crate)
- Ethereum address: Keccak-256(uncompressed_pubkey[1..])[-20:]
- EIP-55 checksum address formatting
- eth_sign() / eth_verify() for secp256k1 ECDSA
- EthAddress type with Display, hex parsing, checksum
- 5 tests: deterministic, format, checksum, sign/verify, uniqueness

CLI:
- `warzone eth` — show Ethereum address alongside Warzone fingerprint
- Same seed produces both identities (dual-curve)

Dual identity model:
- Ed25519 + X25519 for Warzone messaging (fast, small signatures)
- secp256k1 for Ethereum compatibility (MetaMask, ENS, Ledger/Trezor)
- Both derived from the same BIP39 seed via different HKDF paths

28/28 protocol tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-27 13:30:25 +04:00
parent 86da52acc4
commit 661de47552
6 changed files with 343 additions and 6 deletions

View File

@@ -31,6 +31,8 @@ enum Commands {
#[arg(short, long, default_value = "http://localhost:7700")]
server: String,
},
/// Show Ethereum-compatible address derived from your seed
Eth,
/// Send an encrypted message
Send {
/// Recipient fingerprint (e.g. a3f8:c912:...) or @alias
@@ -94,6 +96,13 @@ async fn main() -> anyhow::Result<()> {
println!("Signing key: {}", hex::encode(pub_id.signing.as_bytes()));
println!("Encryption key: {}", hex::encode(pub_id.encryption.as_bytes()));
}
Commands::Eth => {
let eth_id = warzone_protocol::ethereum::derive_eth_identity(&seed.0);
let pub_id = identity.public_identity();
println!("Warzone fingerprint: {}", pub_id.fingerprint);
println!("Ethereum address: {}", eth_id.address.to_checksum());
println!("Same seed, dual identity.");
}
Commands::Register { server } => {
cli::init::register_with_server_identity(&server, &identity).await?;
}