OpenRung
A free, privacy-first relay network that helps you reach the open internet. Open source and nonprofit-run.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Offline Shamir secret sharing for printable paper shares, QR scanning, BIP-39 validation, and verified restoration. Day124.
翻訳待ち
Loading the full README.
Read the full README ↗English · 日本語
Day124 - 生成AIで作るセキュリティツール200
Scatter Seedsは、秘密をシャミアの秘密分散でn枚の紙に分け、k枚から復元するツールです。パスワード、暗号資産のシード、金庫の番号、復旧キーを扱えます。k−1枚から秘密の情報は漏れず、n−k枚を失っても戻せます。共有を作った直後に、すべてのk枚の組が元の秘密を戻すことを検査します。
名前は、共有という「種」を離れた場所へ蒔くことに由来します。暗号資産のシードと、備えのための種の備蓄も重ねています。頭文字SSSはShamir's Secret Sharingとも共通です。Secret Sharing Scheme一般にも使われ、視覚暗号のVSSSにも含まれる略語です。
ダウンロードしたindex.htmlをfile://で開いても使えます。画面は外部へ通信しません。秘密を入れるときは、オフラインの信頼できる端末を使ってください。
以下はライトモードの画面です。画面右上の「◐」ボタンでダークモードに切り替えられます。
分ける
共有の証書
印刷プレビュー
戻す・検査表
保管の指針
英語画面の同じ状態も掲載しています。撮影にはtest/fixtures/vectors.jsonのデモ値だけを使っています。共有の乱数とセットIDは撮影ごとに変わります。
| タブ | 内容 |
|---|---|
| 分ける | テキスト、16進のバイト列、英語BIP-39を2≤k≤n≤16で分ける。全組の復元検査が終わってから共有とQRを表示し、A4で1枚ずつ印刷する。 |
| 戻す | 文字列を1行ずつ貼るか、押したときだけカメラでQRを1枚読む。書式、CRC、セットID、k/n、x、指紋、余分な共有の食い違いを検査する。秘密は最初は隠す。 |
| 保管の指針 | kとnから失ってよい枚数と盗まれてよい枚数を示し、保管例、定期点検、限界を説明する。 |
秘密・共有・ラベルはストレージ、URL、履歴に保存しません。保存するのは言語と明暗だけです。「すべて消す」は画面の値を消しますが、コピー先のクリップボードは消せません。
秘密と乱数からn個の「共有(シェア)」を作り、そのうち異なるk個が集まれば元に戻せる方式です。必要数kを「しきい値」と呼びます。n=3、k=2(2-of-3)なら、共有①+②、①+③、②+③のどの組でも戻せます。1枚を失っても残り2枚で戻せます。同じ共有のコピーは2枚分には数えません。
正しい乱数で作った共有だけなら、k−1枚以下から秘密の値はわかりません。秘密の文字を単純に切り分ける方式ではありません。共有には長さやk・nなどの情報は残ります。n−k枚まで失っても戻せますが、k=nでは1枚の紛失で復元できなくなります。
Day123 ShamirSharing CipherLabでは、座標平面、手計算、バイト表を通して仕組みを学べます。Day123は必要数を先に書く「(k,n)しきい値法」という表記です。学習用のため、実際のパスワードやシードを入力せず、練習用の値を使ってください。
秘密本体のサイズは1〜256バイトです。1バイトは8ビットなので、最大256 × 8 = 2,048ビットになります。共有に加える種別・指紋などの付加データは、この上限に含めません。
テキストは空白・改行も含めたUTF-8のバイト数で判定します。同じ文字だけを繰り返す場合、入る個数は「256 ÷ 1文字のバイト数」の小数点以下を切り捨てた値です。表のfloorは小数点以下の切り捨てを表します。
| 入力例 | 1単位のサイズ | 上限の計算 | 入力できる量 |
|---|---|---|---|
| 半角英数字(ASCII) | 1文字で1バイト | 256 ÷ 1 = 256 | 256文字 |
| 「あ」だけ | 1文字で3バイト | floor(256 ÷ 3) = 85 | 85文字(255バイト) |
| 「😀」だけ | 1個で4バイト | 256 ÷ 4 = 64 | 64個(256バイト) |
| 16進のバイト列 | 2桁で1バイト | 256 × 2 = 512 | 512桁(偶数桁) |
「あ」は85 × 3 = 255バイトまで入り、86 × 3 = 258バイトでは上限を超えます。異なる文字を混ぜる場合は、それぞれのUTF-8バイト数を足します。たとえばAあ😀は1 + 3 + 4 = 8バイトです。日本語には4バイトになる文字もあり、絵文字や結合文字は複数の文字を組み合わせて表示する場合もあるため、見た目の文字数だけではサイズを判断できません。
16進では1桁が4ビット、2桁が8ビット(1バイト)です。そのため、入力する桁数は最大256 × 2 = 512桁になります。
BIP-39では、英単語列から取り出した元の乱数(エントロピー)を分けます。1語は11ビットを表し、語数 ÷ 3ビットのチェックサムを除いてから8で割ると、元の乱数のバイト数が求まります。
| 語数 | チェックサム(ビット) | 元の乱数(バイト) |
|---|---|---|
| 12 | 4 | 16 |
| 15 | 5 | 20 |
| 18 | 6 | 24 |
| 21 | 7 | 28 |
| 24 | 8 | 32 |
12語なら(12 × 11 − 4) ÷ 8 = 16バイト、24語なら(24 × 11 − 8) ÷ 8 = 32バイトです。このサイズは、単語列をUTF-8で保存した場合のサイズとは別です。
画面右上の「?」に、各タブの操作、練習手順、活用例、してはいけないことをまとめています。「保管の指針」で選ぶk・nは、「分ける」の設定には反映されません。初めて使うときは、テキスト「Scatter Seeds」をk=2、n=3で分けて復元を試してください。
kとnを選びます。2-of-3なら1枚を失っても戻せ、1枚を盗まれても秘密の情報は漏れません。k=nなら1枚でも失うと戻せません。BIP-39は12・15・18・21・24語の英語を受け付けます。入力時にNFKD、小文字、空白を整え、語彙とチェックサムを確認します。最初の4文字だけの省略形は受け付けません。チェックサムは4〜8ビットなので、12語では1語を取り違えても約1/16の確率で通ります。元の紙と1語ずつ比べてください。25番目のパスフレーズは扱わないため、別に保管してください。復元結果には番号つきの語と元の乱数の16進を表示します。
入力欄の下に現在のバイト数を表示します。BIP-39では、語とチェックサムの検査が通ると元の乱数のサイズを表示します。入力、種別、枚数、ラベル、日付を変更すると、前の証書は消えます。生成の検査中に変更した場合も処理を中止するため、新しい内容で「分ける」を押し直してください。
各証書の「QRを拡大」で、その1枚を大きく表示できます。共有番号・セットID・必要枚数を確認し、「閉じる」またはEscapeキーで戻ります。QR画像の四辺には4セル分の白余白を含めています。
タブ内の「共有を集める → 文字列またはQRを入力する → 検査結果を確認する」の順に操作します。証書のSSS1文字列は1枚につき1行で入力し、紙の途中の折り返しは1行につなげてください。カメラは1枚を追加するたび自動で検査します。
検査表には入力順と証書の共有番号xを区別して表示し、セットID・k/nも実際の値を示します。「検査表の見方」を開くとCRCなどの意味を確認できます。異常があれば入力順ごとに貼り直し・別の共有の追加などを案内します。追加共有の不一致では先頭k枚の復元値を表示できますが、全体の検査は通っていないと表示します。
復元したテキストは引用符付きのJSON形式で表示します。改行は「\n」、文字としてのバックスラッシュは「\」と区別します。先頭のU+FEFFも保存し、表示では「\uFEFF」と示します。「表示」後の「元のテキストをコピー」は、表示用の引用符やエスケープを含めずにコピーします。バイト単位で保存する場合は、次のPythonの--rawを使ってください。
カメラは開始待ちの間も停止できます。別のタブへ移るか「すべて消す」を押すと、開始待ちを含めて中止します。画面が非表示になった場合も停止します。
入力を変更すると前の検査結果と復元値を消します。手入力の変更後は再び「検査して戻す」を押してください。「すべて消す」は戻すタブ内の入力・結果を消し、カメラを止めます。分けるタブやクリップボードの内容は消しません。
文字列はSSS1-と大文字の16進です。区切りの空白・ハイフンと小文字は読み取り時に許しますが、自動訂正はしません。「戻す」タブとPythonスクリプトでは改行が共有の区切りになるため、1枚の文字列を1行に入力します。1枚のバイト列は次の順です。
| フィールド | 長さ | 内容 |
|---|---|---|
| 版 | 1バイト | 01 |
| セットID | 4バイト | 乱数。共有を同じセットとして扱う目印。 |
| k、n、x | 各1バイト | 2≤k≤n≤16、1≤x≤n。x=0は拒否。 |
| 分散データ | 秘密長+5バイト | 種別 ‖ S ‖ 指紋を1バイトずつ独立の多項式で分けた値。 |
| CRC-32 | 4バイト | それ以前の全バイトのIEEE CRC-32。123456789→CBF43926。 |
種別は01がUTF-8テキスト、02がバイト列、03がBIP-39の元の乱数です。指紋はSHA-256(種別 ‖ S)の先頭4バイトです。種別と指紋も秘密とともに分けます。体はGF(2⁸)、既約多項式は0x11B、加算はXORです。係数とセットIDにはcrypto.getRandomValuesだけを使います。共有の長さは5+2×(秘密のバイト数+17)文字です。
| 秘密の長さ | 共有の文字数 | QRの版(英数字、誤り訂正M) |
|---|---|---|
| 16バイト | 71 | 4 |
| 32バイト | 103 | 5 |
| 64バイト | 167 | 7 |
| 128バイト | 295 | 10 |
| 256バイト | 551 | 15 |
CRCは書き写しの誤りを見つけます。指紋が一致しなければ値を表示しません。k枚より多いときは、最初のk枚から決まる多項式に乗らない共有のxを示します。セットIDは32ビットなので偶然の衝突はあり得ます。CRCと4バイトの指紋は認証タグではありません。k枚を持つ攻撃者による意図的な作り直しを防ぎません。
This is the beginning of the README. Read the rest at the original. Read the full README ↗