ブログに戻る
arweavecryptographyweb3walletsdeterminism
決定論的Arweaveウォレットの構築:既存ライブラリを超えた理由
node-forgeを使用して堅牢な決定論的Arweaveウォレット生成器をゼロから構築し、既存の人気ライブラリが実現できなかったことを達成した方法を解説します。
Miguel Treviño•

Zelfのマルチチェーンウォレットインフラを構築する際、重要な課題に直面しました:単一のBIP39ニーモニックフレーズから決定論的なArweaveウォレットを生成すること。要件はシンプルですが妥協できないものでした:同じ12語のフレーズが常に同じArweaveアドレスと秘密鍵を生成する必要があります。
簡単そうに聞こえますよね?そうではありませんでした。
要約:
- 問題: 既存のArweaveライブラリは決定論的なウォレットの生成に失敗しました(同じフレーズ = 異なる鍵)。これはウォレット復元にとって致命的です。
- 解決策: PRNGを明示的に制御するために
node-forgeを使用したカスタム実装を構築し、100%の決定論性を確保しました。 - パフォーマンス: 2048ビットRSA鍵を、セキュリティを犠牲にすることなく約2〜3秒(60秒以上と比較して)で生成するよう最適化しました。
- 成果: 厳密に検証されたオープンソースソリューションで、信頼性の高いセルフカストディを保証し、現在Zelf Walletでライブ稼働中です。
既存ライブラリの問題
最初に
arweave-mnemonic-keysという、まさにこの目的のために設計された人気ライブラリを検討しました。約束は完璧でした:ニーモニックを渡せば、決定論的なArweave JWK(JSON Web Key)が返される。しかし最も基本的なテストに失敗しました。
同じニーモニックをライブラリに連続して2回実行すると、異なるアドレスが得られました。わずかに異なるのではなく—完全に異なります。これはウォレット復元機能にとって致命的です。ユーザーに「あなたのシードフレーズでウォレットを復元できます...たぶん。時々。幸運を。」と言うようなものです。
// 期待していたもの
const wallet1 = await getKeyFromMnemonic(mnemonic);
const wallet2 = await getKeyFromMnemonic(mnemonic);
console.log(wallet1.address === wallet2.address); // trueであるべき
// 得られたもの
// false 😱
これは受け入れられませんでした。確率的な希望ではなく、暗号学的確実性が必要でした。
独自ソリューションの構築
壊れたライブラリにパッチを当てたり修正を待ったりする代わりに、
node-forgeを使用してゼロから独自の実装を構築しました。私たちのアプローチが機能する理由は以下の通りです:1. 明示的なPRNG制御
ほとんどのライブラリの核心的な問題は、設計上非決定論的なシステムランダムネス(
crypto.randomBytes)に依存していることです。シードされていても、多くのライブラリは乱数生成器を適切に分離しません。私たちの解決策:疑似乱数生成器(PRNG)の完全な制御。
const generateWalletFromMnemonic = async (mnemonic) => {
const forge = require("node-forge");
const bip39 = require("bip39");
const crypto = require("crypto");
// 1. ニーモニックからシードを導出
const seed = await bip39.mnemonicToSeed(mnemonic);
// 2. SHA-256ハッシュチェーンを使用した決定論的PRNGの作成
let state = seed;
const customPrng = {
getBytesSync: (size) => {
let res = "";
while (res.length < size) {
const hasher = crypto.createHash("sha256");
hasher.update(state);
state = hasher.digest();
res += state.toString("binary");
}
return res.substring(0, size);
},
};
// 3. PRNGでRSA鍵を生成
const keyPair = forge.pki.rsa.generateKeyPair({
bits: 2048,
prng: customPrng,
workers: -1, // メインスレッドを強制
});
// 4. Arweave JWK形式に変換
// ...(変換ロジック)
};
2. パフォーマンス最適化
Arweaveは通常4096ビットのRSA鍵を使用しており、非常に安全ですがピュアJavaScriptでの生成は非常に遅い(約60秒以上)。ウォレットのインポート/復元フローとしては、これは受け入れられないUXです。
2048ビット鍵に最適化しました:
- Arweaveのプロトコルに完全準拠
- 約2〜3秒で生成(20倍高速)
- ウォレットのユースケースに対する暗号学的セキュリティを維持
- 完全な決定論性を保持
3. 厳密な検証
アドレスが一致するだけのテストではありませんでした。生成された鍵の暗号機能全体を検証しました:
// 鍵が機能的であることを検証
const data = new TextEncoder().encode("Hello Arweave");
const signature = await arweave.crypto.sign(jwk, data);
const isValid = await arweave.crypto.verify(jwk.n, data, signature);
expect(isValid).toBe(true); // ✅ PASS
これは鍵が構造的に正しいだけでなく—トランザクションに署名可能な完全に機能するArweave秘密鍵であることを証明しています。
結果
私たちの実装が提供するもの:
✅ 100%決定論性:同じニーモニック = 同じアドレス、毎回
✅ 高速生成:約2〜3秒 vs 60秒以上
✅ 暗号学的に検証済み:鍵はメッセージの署名と検証が可能
✅ 外部依存関係なし:スタック全体を制御
✅ 本番環境対応:Zelfのウォレットインフラに統合済み
Web3にとっての重要性
決定論的鍵生成は単なる技術的な良さではなく—セルフカストディの基盤です。ユーザーがシードフレーズを書き留めるとき、デジタルアイデンティティ全体のバックアップを作成しています。そのバックアップがウォレットを確実に復元できなければ、「自分自身の銀行になる」という約束全体が崩壊します。
これは永続的なデータストレージのために設計されたArweaveにとって特に重要です。Arweave上に重要な文書やNFTを保存している場合、何年後でもシードフレーズだけでアクセスできるという絶対的な確信が必要です。
より広い教訓
この経験は重要な原則を強化しました:信頼するな、検証せよ。
人気のあるライブラリが常に正しいとは限りません。GitHubのスターは正確さを保証しません。ウォレットのような重要なインフラを構築する際は:
- 厳密にテストする(決定論性テストを何百回も実行しました)
- 暗号技術を理解する(コードのコピペだけでなく)
- 既存のソリューションが失敗した場合にゼロから構築する覚悟を持つ
Zelfでは、自己主権的アイデンティティの未来を構築しています。つまり、決定論的鍵生成のような基本に妥協することはできません。ツールが存在しない場合は自分たちで構築し—そして正しく構築します。
自分で試してみる
これを実際に見たいですか?私たちの実装はZelf Walletでライブ稼働中です:
- zelf.worldでZelfをダウンロード
- 任意の12語のニーモニックをインポート(または新しいものを作成)
- Arweaveアドレスを即座に取得—毎回同じであることを確認
開発者の方は、オープンソースの実装をチェックして、より良いWeb3インフラの構築に貢献してください。
技術ノート:私たちの実装はBIP39ニーモニックでシードされたカスタムSHA-256ベースのPRNGを使用した
node-forgeによるRSA生成を使用しています。完全なソースは監査と貢献のために利用可能です。暗号ライブラリで同様の問題に遭遇したことはありますか?下のコメントであなたの経験を共有してください。