[Dev] Bun.shで公開鍵復元してみる
こんにちは、@yasuです。
Keychainの使い方を勉強している。
Keychainが出力したメッセージと署名から公開鍵を復元する方法。
sha256関連の処理は、bun環境ではdsteemが使用できなかった。
しかたなく、dsteemを使用せずに、公開鍵復元の方法を探した。
しかし、@noble/secp256k1はバージョン2やバージョン3はうまく動かず、
結局、古いが@noble/secp256k1はバージョン1で実現できた。
完全なソースコード
import * as secp from "@noble/secp256k1";
import { createHash } from "crypto";
import bs58 from "bs58";
function ripemd160(data: Uint8Array): Uint8Array { return new Uint8Array(createHash("ripemd160").update(data).digest()); }
function pubkeyToSteem(pubkey: Uint8Array): string {
const checksum = ripemd160(pubkey).slice(0, 4);// compressed pubkey → RIPEMD160 ハッシュ
const full = new Uint8Array(pubkey.length + 4);// pubkey + checksum
full.set(pubkey, 0);
full.set(checksum, pubkey.length);
return "STM" + bs58.encode(full);// Base58 エンコード
}
try {
const signature = "20356757cb7d303ece5852aa84dc1d4e1ca27099ee99023a216e3b2e43f13ead677f69be476b6004a027b77a743ab113ec3ba168a6d758e2c13ce6cc80ac2d0406";
const message = "Login to mysite with nonce: 14a31bde6b422d0f3a1bfe47758cc7f0";
// SHA256
const digest = Bun.SHA256.hash(new TextEncoder().encode(message));
// Steem署名解析
const sigBytes = Buffer.from(signature, "hex");
const recovery = (sigBytes[0] - 27) & 3;
const compactSig = sigBytes.slice(1, 65);
// 公開鍵復元
const pubkey = secp.recoverPublicKey(digest, compactSig, recovery, true);
// Steem形式に変換
const steemPubkey = pubkeyToSteem(pubkey);
console.log("Steem PubKey:", steemPubkey);
// 署名検証
const isValid = secp.verify(compactSig, digest, pubkey);
console.log("Signature valid:", isValid);
} catch (err) {
console.error(err);
}

Konnichiwa, @yasu! This is a fantastic, practical breakdown of recovering a public key from a Keychain signature. The detail about troubleshooting the
@noble/secp256k1library versions is super valuable – I'm sure many developers will appreciate that insight and the working version 1 solution.The inclusion of the complete source code is a huge plus, making it easy for others to learn from and implement this solution. Thanks for sharing your journey and providing such a clear, concise explanation.
I'm curious, @yasu, have you considered wrapping this into a reusable function or library for easier integration? Anyone else working with Keychain and public key recovery, please share your experiences and any alternative approaches you might have! Let's learn together!
■修正前(Node.js 標準 crypto)
function sha256(data: Uint8Array): Uint8Array { return new Uint8Array(createHash("sha256").update(data).digest()); }
const digest = sha256(new TextEncoder().encode(message));
■修正後(Bun 独自 Bun.SHA256.hash)
const digest = Bun.SHA256.hash(new TextEncoder().encode(message));