シャミアの秘密分散法
(Shamir’s secret sharing)を、ethers.js
を使用して試してみます。以下は、シャミアの秘密分散法を実装するためのコード例です。
必要なライブラリをインストール
yarn init -y
yarn add ethers@5.7 @stablelib/random secrets.js-grempe
テストコードの実装
const ethers = require("ethers");
const randomBytes = require("@stablelib/random").randomBytes;
const sss = require("secrets.js-grempe");
// 秘密鍵を生成する関数
function generatePrivateKey() {
return ethers.utils.hexlify(randomBytes(32));
}
// シャミアの秘密分散法を使って秘密鍵を分割する関数
function splitSecretKey(secretKey, shares, threshold) {
return sss.split(sss.fromHex(secretKey), { shares, threshold });
}
// シャミアの秘密分散法を使って秘密鍵を再構築する関数
function reconstructSecretKey(shares) {
return sss.toHex(sss.combine(shares));
}
// テスト用の秘密鍵を生成
const privateKey = generatePrivateKey();
console.log("Generated Private Key:", privateKey);
// 秘密鍵をシャミアの秘密分散法を使って分割
const shares = 5;
const threshold = 3;
const secretShares = splitSecretKey(privateKey, shares, threshold);
console.log("Secret Shares:", secretShares);
// 秘密鍵を再構築するために必要なシェアを選択
const requiredShares = secretShares.slice(0, threshold);
// 秘密鍵を再構築
const reconstructedPrivateKey = reconstructSecretKey(requiredShares);
console.log("Reconstructed Private Key:", reconstructedPrivateKey);
// 元の秘密鍵と再構築された秘密鍵が一致するか確認
if (privateKey === reconstructedPrivateKey) {
console.log("Success! The original and reconstructed private keys match.");
} else {
console.log(
"Error! The original and reconstructed private keys do not match."
);
}
このコードは、秘密鍵を生成し、シャミアの秘密分散法を使用して分割し、再構築します。元の秘密鍵と再構築された秘密鍵が一致するかどうかを確認します。 ethers.js は、秘密鍵の生成に使用されています。シャミアの秘密分散法の実装には、secrets.js-grempe ライブラリが使用されています。
実行結果は以下のようになります。
$ node index.js
Generated Private Key: 0xf5b44f49ad549ad7b4a2ba40a60507c7cd2d6b2f163b1edf4a20ba4bc88d257d
Secret Shares: [
'801a5351b5d10b65cb7005e7e863db96e6dc6a40e11f98b2272c19f46380bd6caa2599ae4121145ea3ac564708844097a7af00aead31d4fa2e70b3c216ba32c4a771924f8cf2112000b676df7efd718d96d2c5a943d19f55107aeae84dc8dafdce24fe77285c11b016a9e5b28b84443d37ba26abfd3da76a3a6a14d8888987a4ab3d87b9d24dfc293373686ddc88cbcba69',
'80271eb750ea88af75f3545501b9d101f5aedb878cfd1a30057387735477aa0eb14928c71e2c0c8de20c2348457a9150afde2725bfe67aaf9e7315fc42e683f0837efa7a4ec75ade02dd9663702003132de63962b35ea6792346efebba65cf70b84cecf3cc608147e650342ce9a0a4b6e12a2b1de850f3b262724a9e1a935bb9d1457e30c173b2a3ceba97fedad1962c488',
'803d4de6e53b83cabe8351b2e9ca0cd71002b2976ec284c221df9d0731c71142182cb779592d1bd34280731f4ebed7a70e3121db11c7a875b333a55e574cb754272f6e15c1554dbe014be6fc08ed71eebd04ffbbf38f3a7c303c0663f1bd168d75281494e21c93d7f6e9d2de6404e3fbd0d00ba616fd57985b485806940adf8d7938ffe9107e4dcafbe9fcc300395a67ed1',
'8047af5fbf657c2d20ebe492a119ce715ae2ac07d0347e70d2dd6d6b459591d5e30b9be48e23295fd1ed0aa98eacb0ecbe5a548c4eaa79d551ffe0db7991cc75a3e90cc6c4b367f7aa5f320592cf6462aba2a992e468e8af98d6008e948c914944ddce63ff676b311218e42c3d626a5afb592e36f95bc3ca5b5b9a548f00a3003b861b7b47e2c9364e17c65f2ff424a1b75',
'805dfc0e0ab47748eb9be175496a13a7bf4ec517320be082f671771f20252a994a6e045ac9223e0171615afe8568f61b1fb55272e08bab0f7cbf50796c3bf8d107b898a94b217097a9c9429aea02169f3b406f4ba4b974aa8bace906df5448b489b93604d11b79a102a102deb0c62d17caa30e8d07f667e0626188cc0199273493fb9aa296ef365f7b44ad62f51ce8ea12c'
]
Reconstructed Private Key: 0xf5b44f49ad549ad7b4a2ba40a60507c7cd2d6b2f163b1edf4a20ba4bc88d257d
Success! The original and reconstructed private keys match.
利用するだけなら簡単ですね。
secretShares のバイト数(今回は292バイト)は、生成されたシェアの数とそれぞれのシェアのサイズに依存します。シャミアの秘密分散法では、シェアは通常、元の秘密情報よりも大きなサイズになります。これは、各シェアが元の情報に加えて、シェアの識別子 (x 座標) や他のメタデータを含むためです。
secrets.js-grempe
ライブラリでは、デフォルトのエンコーディングは hex 文字列です。Secret Sharesがすべての80から始まっていますが secrets.js-grempe
は、シェアのインデックスと実際のシェアデータを結合する際、インデックスとシェアデータを8ビット左シフトして結合します。これにより、シェアの最初の2文字が 80 になります。
ちなみに、JavaScriptで実装されたシャミアの秘密分散法ライブラリsecrets.js-grempe
のライブラリ名は、ライブラリの作者である Glenn Rempe さんの名前から取られています。彼が開発し、メンテナンスを行っているため、彼の名前がライブラリ名に含まれているとのことです。