長さと文字種を選ぶと、衝突までの年数まで一緒に出します
NanoID の既定は「URL に置ける64種類の文字」を21個並べる形です。64 の21乗は 2 の126乗、約 8.5 x 10 の37乗です。UUID v4 のランダム部分は122ビット、約 5.3 x 10 の36乗なので、既定の NanoID はそれより少し大きい規模になります。つまり21という長さは、UUID と同等以上の強さを36文字ではなく21文字で得るために選ばれた値です。短くしたぶんだけ弱くなるので、長さを変えるときは組み合わせの数がどう動くかを見てから決める必要があります。このツールが年数を一緒に出しているのはそのためです。
使う文字を減らしても同じことが起きます。たとえば数字だけの10種類にすると、1文字あたりの情報量は約6ビットから約3.32ビットへ落ちます。同じ強さを保つには長さを倍近くにしなければなりません。「短くしたい」と「文字種を絞りたい」は、どちらも同じ予算を削る操作です。
乱数のバイトから文字を選ぶとき、単純に「文字数で割った余り」を使うと、割り切れないぶんだけ先頭側の文字が出やすくなります。256 を 62 で割ると 4 余り 8 なので、最初の8文字だけ 5 回、残りの54文字は 4 回の割り当てになる、という偏りです。このツールは NanoID 本家と同じく、文字数を覆う最小のビットマスクで切り出し、範囲外の値は捨てる方式にしています。捨てるぶん乱数を余分に読みますが、どの文字も同じ確率になります。
| 設定 | 1文字あたり | 21文字での組み合わせ | 近いもの |
|---|---|---|---|
| 64種類(既定) | 6ビット | 約 8.5 x 10^37(2^126) | UUID v4 のランダム部分(約 5.3 x 10^36)より少し大きい |
| 62種類(英数字) | 約5.95ビット | 約 4.4 x 10^37 | 記号を使えない場所向け。ほぼ同じ規模 |
| 36種類(小文字と数字) | 約5.17ビット | 約 4.8 x 10^32 | 大文字を使えない場所向け |
| 16種類(16進) | 4ビット | 約 1.9 x 10^25(2^84) | ハッシュの一部を切ったもの |
| 10種類(数字) | 約3.32ビット | 10^21 | 短縮コード。長さを増やして補う |
乱数はブラウザの crypto.getRandomValues から取っています。安全な乱数を取れない環境では、その旨を表示して生成しません(推測できる乱数へ黙って切り替えません)。
64種類の文字を21個並べると、組み合わせは 64 の 21 乗で、2 の 126 乗、約 8.5 x 10 の 37 乗になります。UUID v4 のランダム部分は122ビット、約 5.3 x 10 の 36 乗なので、既定の NanoID はそれより少し大きい規模です。UUID と同等以上の強さを、36文字ではなく21文字で得るための長さです。
決められた形式が要る場面、たとえばデータベースの UUID 型や外部仕様が指定している場合は UUID を使います。自分のアプリのURLやファイル名に置くだけなら、短くて記号が2種類しか入らない NanoID のほうが扱いやすくなります。
誕生日問題の近似式 k = ルート(2 x N x ln(1 / (1 - p))) を使い、N を「文字種の数の長さ乗」、p を1パーセントとしています。得られた k を1時間あたりの生成数で割って年に直しています。桁が大きいので対数で計算しています。
いいえ。乱数はブラウザの crypto.getRandomValues から取り、生成もこのページの中だけで行っています。安全な乱数を取れない環境ではその旨を表示し、推測できる乱数へ黙って切り替えることはしません。