ECDSAの点からEthereumのアドレス


いつも忘れるのでメモ

やり方

点の32バイトのx座標と、32バイトのy座標を並べたものを、keccak256でハッシュして、最後の20バイトを取る。

Pubkeyから作る場合

Pubkeyからシリアライズしたデータの先頭1バイトは、header byteなので取り除く

// Pseudo code
let hdr_x_y = Pubkey::serialize();
let x_y = &hdr_x_y[1..];

説明
x 座標 4b4ece7218b90931a2d16d053b579461fab70a5d6d2137143f1026b865f45937
y 座標 b287fe8c37d4615cb9ab23868e012991acf24be87146a9740e02001e549aaed8
アドレス 0x9debb5ff7c3183d441d6e6d0836cbc2df4f36b97

サンプルコード

use crypto::sha3::Sha3;
use secp256k1::PublicKey;
use crypto::digest::Digest;

/*
hex = "0.4"
rust-crypto = "^0.2"
*/

fn hash(buf: &[u8]) -> String {
  let mut hasher = Sha3::keccak256();
  hasher.input(buf);
  hasher.result_str()
}

pub fn calc_addr(x: &str, y: &str) -> String {
  let hex = x.to_owned() + y;
  let raw_pk = hex::decode(hex).unwrap();
  let pk_hash = hash(&raw_pk);
  let addr = &pk_hash[24..];  // last 20 bytes of 32-byte pk_hash
  format!("0x{}", addr)
}

#[test]
fn ecdsa_point_to_addr() {
  let exp = "0x9debb5ff7c3183d441d6e6d0836cbc2df4f36b97";

  let x = "4b4ece7218b90931a2d16d053b579461fab70a5d6d2137143f1026b865f45937";
  let y = "b287fe8c37d4615cb9ab23868e012991acf24be87146a9740e02001e549aaed8";
  let act = calc_addr(x, y);

  assert_eq!(act, exp);
}