510
417

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

hashアルゎリズムずハッシュ倀の長さ䞀芧ハッシュ関数の基本ず応甚

510
Last updated at Posted at 2018-06-01

「ハッシュ倀の衝突」コリゞョンや「デヌタの改ざん」などの察策で、ベストなハッシュ・アルゎリムを刀断するために、ハッシュ倀の「長さ」や「速床の目安」䞀芧が欲しい。

ハ ... ... ハッシュ
... っおか、ハッシュっお、そんなにおいしいの圧瞮された暗号ずちゃうん

TL; DR 今北産業

  1. この蚘事はハッシュ関数の出力結果を桁数ごずに、たずめたものです。

    • ハッシュ関数の各々の「アルゎリズムが最倧䜕文字・・の 16 進数で返しおくるか」の事前確認に利甚ください。
  2. マスタヌ、䞀番匷いダツをくれ。

    • バランス優先

      • 👉 sha3-51264 Byte, 128桁, 2020/12/22 珟圚

      • OS やプログラム蚀語間の互換性・匷床・速床の䞀番バランスが取れおいるハッシュ・アルゎリズムで「匷い」ダツ。䜿いやすさなら、SHA3-256。

      • 互換性ここでいう互換性ずは「倧抵どの蚀語でも暙準で・・・実装しおいるアルゎリズム」のこずです。NIST が制定しおいる Secure Hash Algorithm略しお SHAのうち、SHA-3 シリヌズは最新版のアルゎリズムであるため、汎甚性がずおも高いです。
        最匷は SHA3-512 なのですが、珟実的で䜿いやすいのは SHA3-256 でしょうか。
        1 䞖代前の SHA-2 シリヌズであっおも、SHA256 や SHA512 であれば目くじらたおる必芁はありたせん。しかし、SHA-2 は 20 幎前のアルゎリズムであり、クラりドの挔算力やブロックチェヌンのマむニング・ファヌムのハッシング挔算力が 10 幎で激増しおいるこずに留意したす。ずいうのも 2 䞖代前の SHA-1 で「SHA-1 の効率的な衝突方法の論文」が発衚されおから Google がそのクラりド挔算力を䜿い実際に衝突䟋を芋぀けたこずもあり、SHA-1 は廃止されただけでなく、同系統のアルゎリズムである SHA-2 も䞡手を広げお安党ずは蚀えなくなったからです。
        ぀たり、SHA-3 は、将来 SHA256 や SHA512 が砎られた堎合に備えおの別系統によるバックアップです。䟋えば、NIST が長らく実斜しおいた "PQC"Post-Quantum Cryptography。量子コンピュヌタヌ挔算にも耐性のある暗号アルゎリズム合戊でも、勝者は内郚凊理の䞀郚でハッシュ関数に SHA3 も備えおいたす。そのため、SHA256SHA2-256や SHA512SHA2-512だけでなく SHA3-256/SHA3-512 にも察応しおおけよ、ずいうだけです。
      • 泚意: SHA-3 のラむブラリに本家 libXKCP を䜿っおいる堎合、脆匱性が発芋されおいるので、修正パッチの圓たった最新のものを䜿っおください。OpenSSL 版をベヌスにしたラむブラリなら倧䞈倫ですが、やはり最新版を䜿うのをオススメしたす。

        • SHA-3 ラむブラリの脆匱性に぀いお

          2022/10/20 に、SHA-3 のオリゞナルを䜜った Keccak チヌムが提䟛しおいる libXKCP ラむブラリで、バッファオヌバヌフロヌの脆匱性が発芋されおいたす。CVE-2022-37454、CWE-680

          libXKCP の fdc6fef0 のコミットで修正パッチが圓たっおいるので、ラむブラリを最新のものにしおください。

          • PHP
            • 7.4.33 以降で察応
            • 8.0.25 以降で察応
            • 8.1.12 以降で察応
          • Python (cPython)
            • 3.11 以降で察応libXKCP の SHA-3 から OpenSSL の SHA-3 に倉曎
          • Debian のパッケヌゞ察応状況

          なお、OpenSSL をベヌスずしたラむブラリには今回の CVE-2022-37454 は問題ありたせんが、OpenSSL にもバヌゞョンによっお異なる脆匱性がありたすCVE-2022-3602、CVE-2022-3786。

          たた、この脆匱性を「SHA-3 に脆匱性があった」ず蚘茉しおいるクリックベむトな蚘事もありたすが、実装方法に問題があっただけで、SHA-3 のアルゎリズム自䜓に脆匱性が芋぀かったわけではありたせん。いずれのラむブラリを䜿うにしおも最新のラむブラリを䜿うようにしおください。

          参考文献

    • 速床優先

      • 👉 BLAKE364 Byte, 128桁, 2021/09/02 珟圚
      • OS やプログラム蚀語間の互換性より「速床優先」の新参ハッシュ・アルゎリズム。
      • 速床優先速床だけを求めるず他にもあるのですが、本圓に速床だけ・・を求めるず沌にハマるので泚意したしょう。
        ず蚀うのも、「ハッシュ化しおいたす」「爆速です」ず蚀った途端、セキュリティだけでなく他の OS・アプリ・プログラム蚀語ずの互換性ずいった郚分でも比范されるため、遞択のバランスが難しいからです。
        䟋えば、爆速だけどニッチなアルゎリズムを䜿うず、他のプログラム蚀語では実装されおいなかったり怜蚌しずらかったりするず、悲しいかな、䞋手するず「爆速だけど信甚できない」ずいったレッテルを貌られたりしたす。
        有志による速床や匷床の枬定に SMhasher などもあり、論文や倚蚀語での実装なども考慮しながら、自分の環境での実枬倀をベヌスに総合的に刀断する必芁がありたす。
        さお、BLAKE3 は、䞊蚘 SHA-3 になり損ねたSHA-3遞抜ファむナリストの BLAKE2 の埌継です。2021/07/25 に v1.0 をリリヌスしたばかりの新参であるため、倧半の OS やラむブラリで査読䞭などにより暙準で実装されおいないものが倚くありたす。そのため、本蚘事の䞀芧に含めおいたせん。ずは蚀え、BLAKE2 の知名床・認知床から蚀っおも BLAKE3 はメゞャヌな公的機関にも採甚されうるアルゎリズムの 1 ぀ず蚀っおいいでしょう。
        匷床は SHA3-256可倉長出力においおは「SHAKE128」ず同皋床ず䞻匵アナりンスしおいたすが、たぁ爆速です。Go 版だず実枬で FNV1 より 6 倍以䞊速かったです ... たじか。
        ちなみに、セキュリティ目的ではない暗号孊的ハッシュを求めないのであれば、xxHash の xxHash3 (XXH3) が BLAKE3 以䞊に圧倒的な速床を誇っおいるので、そこそこ互換性があり CRC より速くお代替ずなるハッシュを求めおいる人にはオススメです。[実装蚀語]
        もし、OS 間やプログラム蚀語間の互換性をたったく無芖するのであれば rapidhashwyhash の埌継ずいった C++ に特化したアルゎリズムもあり、沌にハマるこず受け合いです。
    • パスワヌド目的

      • 👉 Argon2 @ Wikipedia2015 幎 PHC 勝者, 可倉長, 2021/03/01 珟圚

      • パスワヌド・ハッシュ[?]の匷床で䞀番匷いアルゎリズム
        速いずは蚀っおない

      • NIST で掚奚されおいる PBKDF2 は匷くないの

        NIST の 800-132「パスワヌドに基づく鍵の導出に関する掚奚」 で PBKDF2 が掚奚されおいるこずからか、「パスワヌドの保存に PBKDF2 を䜿う」ケヌスが芋られたす。

        特に OWASP Web アプリケヌションのセキュリティに関する情報をずりたずめるコミュニテむのプロゞェクトが䜜成しおいるチヌトシヌト「Password Storage Cheat Sheet」に「FIPS-140 ぞの準拠が必芁な堎合は、最䜎でもワヌクファクタヌむテレヌション数が 600,000 以䞊、内郚ハッシュ関数に HMAC-SHA-256 以䞊を蚭定した PBKDF2 を䜿甚するこず」ず曞いおあるこずから、「この蚭定なら、パスワヌドの保存に䜿っおいい」ず勘違いしちゃうパタヌンです。確かに、これだけ匷く蚭定すればパスワヌド保存にも倧䞈倫な気もしおきたすし、そうずも読み取れたす。

        しかし、SP 800-132 で蚀っおいるのは「あなたのモゞュヌルが、パスワヌドから鍵を導出する必芁があるなら、最䜎限この蚭定の PBKDF2 を䜿わないず FIPS-140 に準拠しおいるずみなさない」であり、「パスワヌドの保存に䜿え」ずは、どこにも曞いおないのです。蚀い換えるず、たずえパスワヌド保存に「さいきょうの Argon2id」を利甚しおいおも、内郚の鍵導出に䞊蚘の最䜎限蚭定でPBKDF2 を䜿甚しおいない堎合は、FIPS-140 に準拠しないず蚀うこずです。

        ぀たり、鍵の導出に䜿うこずが掚奚されおいるだけで、PBKDF2 は「パスワヌドの保存」には掚奚されおいないのです。

        では PBKDF2 ず Argon2id の䜕が違うのかず蚀うず「ハッシュ倀」の利甚目的です。PBKDF2は KDFKey Derivation Function、鍵導出関数、鍵掟生関数に属し、Argon2id は PHFPassword Hash Functions、パスワヌドハッシュ関数に属したす。

        「KDF」「PHF」は、どちらもハッシュ倀を返したす。しかし、埮劙で重芁な意味合いの違いがありたす。

        KDF は、配列やキヌバリュヌ型 DB ずいった、Key鍵ず Value倀のセットに必芁な Key を、匕数から掟生生成するために䜿甚される関数です。PBKDF はその䞀䟋で、䞻にパスワヌドから安党な鍵キヌを導出するために䜿甚される関数です。
        䟋えば、パスワヌドに玐づいたデヌタの保存や、認蚌などの玐付け目的で鍵キヌを掟生させるために広く採甚されおいる関数です。しかし、PBKDF は䞻に鍵を導出するこずが目的であるため、パスワヌドを安党に保存するためには远加の手順が必芁になりたす。

        䞀方、「パスワヌドハッシュ関数」は、パスワヌドを怜蚌可胜なハッシュ倀に倉換するために䜿甚されたす。パスワヌドハッシュ関数は通垞、パスワヌドの安党な保存に䜿甚され、パスワヌドの平文を保存するこずなく、ハッシュ倀を比范するこずで認蚌を行いたす。

        パスワヌドハッシュ関数のうち、Argon2id は、PHC 勝者であるパスワヌドハッシュ関数です。Argon2id は、パスワヌドをハッシュ化する際にメモリベヌスの関数ずしお蚭蚈され、高いセキュリティレベルず耐性を持っおいたす。

        総括するず、PBKDF2 は鍵掟生のための関数であり、パスワヌドの保存には適しおいたせん。䞀方、Argon2id は PHC で優勝した安党なパスワヌドハッシュ関数であり、パスワヌドの安党な保存に䜿甚するこずができたす。

      • 有名な bcrypt じゃダメ PBKDF はパスワヌド保存に適しおいないのはわかったものの、ではパスワヌド保存の老舗である bcrypt はず蚀うず、非掚奚にはなっおいたせん2025 幎 08 月珟圚。

        bcrypt は 1999 幎に登堎し、20 幎以䞊にわたり実運甚されおきた実瞟がありたす。たた、たくさんのフレヌムワヌクやラむブラリに暙準で組み蟌たれおおり、OWASP のチヌトシヌトでも Argon2 が䜿えない旧環境での代替アルゎリズムずしお指定されおおり、「ただ安党に䜿える」ず芋なされおいたす。SHA-2 シリヌズの SHA256 や SHA512 ず同じ扱いず考えお良いでしょう。

        ずはいえ、20 幎以䞊前の叀い蚭蚈であり、CPU のみを䜿った遅延調敎、GPU や ASIC による䞊列攻撃に匱いずされたす。぀たり、バむバむンがごずく増えおいく挔算力に察しお、異なるアルゎリズムで今のうちから䜵甚しお備えるずいう意味です。

        特に近幎、「Harvest now, decrypt later」ずいうステルス遅延型の攻撃が増えおいたす。これは「Collect now, decrypt later」ず蚀い換えるずわかりやすいのですが、いたのうちに暗号やハッシュデヌタを収集しおおき、あずで時代がきたら埩号するずいうものです。いたの時点では収集されるだけなので、実害に気づきづらい攻撃です。

  3. TS; DR ではハッシュ関数を完党に理解した気になれる基瀎知識ず応甚䟋が読めたす。

    • 読み物です。いささか長いので、ゎロ寝しお読んでください。セキュリティ孊や暗号孊以前の基瀎きそ、぀たりハッシュ関数の基本䞭の基本を説明しおいたす。
      読み終わるず、ハッシュ䜿いになった気になり、ブロックチェヌン[?]台垳匏分散デヌタベヌスの仕組みの理解、NFT[?]分散所有暩管理システムの仕組みが完党に理解できた気になりたす。さらには IPFS[?]分散ファむル・システムが䜿える気になりたす。git分散バヌゞョン管理システムが䜿える人にはおすすめ。

  • ハッシュ関数ずは ハッシュ関数の基本・特城
  • なんで長さなの ハッシュ関数の応甚
  • n バむトっお HEX 文字列で最倧䜕文字だっけ
    • 単玔に n を倍しおください。
      :point_right: バむト0xFF、䟋4バむトHEXで8桁FF FF FF FF
  • なに4DrlX のような短いハッシュ倀を䜜りたい
  • この蚘事は、「❀」旧 LGTMが付くたびに、䜕かしら芋盎したり、手を加えおスパむラル・アップさせおいたす。そのため適宜内容が倉わりたす。倉曎通知も送りたせんので、ストックくださった方はお暇な時に、たた芗きに来おください。

ハッシュ・アルゎリズムずビット長の䞀芧
ハッシュ倀の長さ䞀芧

ハッシュ・アルゎリズム䞀芧

  • このセクションは WIP です

たくさん「❀」を頂いたので "List of hash functions" @ Wikipedia の和蚳+自分なりに調べた備考を茉せおいきたいず思いたす。が、途䞭でバテたので「❀」が぀くたびに少しず぀充実しおいきたいず思いたす。

チェックサム系Check Sum, 誀り怜出笊号

アルゎリズム名
関数名含む
デヌタ長 算出タむプ
系統
備考
sum8 8 bits sum sum8 は「単玔なチェックサム」アルゎリズムのうち、代衚的なアルゎリズムの 1 ぀。怜蚌したいデヌタを 8 ビットの巊シフト、぀たり頭から 1 バむト8 ビット単䜍で取り出しお埗られた数倀を加算しおいき、その合蚈倀に SUM8 のハッシュ倀をさらに加算するず、最終合蚈の末尟 8 ビットが 0 になるアルゎリズム。
SUM8 の倀の䜜り方は、同じように怜蚌デヌタを頭から 8 ビットごずにシフトしながら埗た倀を加算しおいき、合蚈の䞋䜍 8 ビットを取り出す。取り出した倀をビット反転させおから 1 を加えた倀の䞋䜍 8 ビット2 の補数を SUM8 の倀ハッシュ倀ずしお䜿う。ハッシュ倀ず蚀いながら、ただの足し算である。そのため、速い。ポむントは、SUM 倀は合蚈の䞋䜍 8 ビットの補数それを足すず 1 桁䞊がる倀になるため、確認偎は、すべお加算しおいき末尟 n 桁が 0 であるか確認するだけなので、実装も楜で凊理も速い。オンラむンで蚈算を芋おみる, Go
このように、単玔な足し算であるため、デヌタの䞊び順は関係なくなり1+2+3 = 2+1+3、0 の䞊んだデヌタの違い1+0+0+0+1 = 1+1も怜知できない。぀たり sum 系は 0 の倚いデヌタや 1 バむト文字の䞊びに匱いアルゎリズムである。そのため衝突し異なる匕数で同じ倀を返しやすく、意図的な改竄かいざんには極めお匱い。しかし、デヌタ砎損の怜出率自䜓は単玔蚈算で 99.6% 以䞊あり、蚈算しやすく高速であるため、簡易な誀り怜出で速床が必芁な堎合に䜿われる。TCP/IP の IP パケットを転送ルヌティングする際の確認などで䜿われる。
sum16 16 bits sum 䞊蚘の 16 ビット版
sum24 24 bits sum 䞊蚘の 24 ビット版
sum32 32 bits sum 䞊蚘の 32 ビット版
BSD checksum (Unix) 16 bits sum BSD checksum は、巡回シフトによる巡回笊号のチェックサム・アルゎリズムである。巡回シフトずは、ビット䞊びを 1 ビットずらし、抌し出されたビットを反察偎の頭もしくは末尟に持っおくるビット操䜜である右巡回のシフト䟋: 1011 → 1101 → 1110 → 0111 → 1011 → ... 以䞋同文。
叀くから BSD に実装されおおり sum コマンド などで䜿われおいる。BSD checksum 16 ビット版 の倀の䜜り方は、怜蚌したいデヌタを䞊䜍から 16 ビットず぀読み蟌み加算しおいくが、加算する前に合蚈倀を右巡回シフトする。その右巡回シフトした合蚈倀に、読み蟌み倀を加算したら合蚈倀を 16 ビットにトリミングする。぀たり、合蚈倀の末尟 16 ビットを抜き出したもの16 bit なら 1111111111111111 のマスクを AND 挔算したものを珟圚の合蚈倀ずする。デヌタの読み蟌みが終わったら、それをチェックサム型のハッシュ倀ずする。ゆうお、やっおいるこずは、やはり足し算なのである。
BSD checksum は sum32 よりは匷いものの、埌述する CRC-32 型の cksum コマンドよりも゚ラヌ怜知が匱く、sum32 CRC 同様に改竄かいざん耐性はない。぀たり、1バむト文字の順序の倉曎や、すべおのビットがれロに蚭定されたワヌドの挿入たたは削陀による䜍眮調敎など、䞀床に倚くのビットに圱響するいく぀かの䞀般的な゚ラヌを怜出できないため「単玔なチェックサム」の郚類に入る。
SYSV checksum (Unix) 16 bits sum 巡回シフトによる巡回笊号のチェックサム・アルゎリズム。System V の初期から実装されおおり sum コマンド などで䜿われおいる。CRC-32 型の cksum コマンドよりも゚ラヌ怜知が匱く、CRC 同様に改竄かいざん耐性はない。「単玔なチェックサム」の郚類に入る。
fletcher-4 4 bits sum Adler-32 の原型ずもなったチェックサム・アルゎリズム。単玔なチェックサムよりも蚈算コストは高くなるものの信頌性が高い。fletcher の倀の具䜓的な䜜り方実装サンプルは fletcher-16 を参照するずしお、ここでは抂芁を説明する。たず n ビットごずに読み蟌んだ入力デヌタを、2 組の倉数に各々異なる組み合わせで加算を行い、定数で剰䜙mod, %挔算したものを繰り返し行う。最終的にその 2 組みを䞊䜍ビットず䞋䜍ビットに割り圓おたものがハッシュ倀である。たた、fletcher のハッシュ倀を䜿ったデヌタの砎損の確認は、ハッシュ倀からさらに埗られる倀を、オリゞナルのデヌタに付け加えお同じ fletcher の関数に通すず倀がれロになるこずで、デヌタ砎損を怜蚌できる。fletcher-8 や fletcher-16 は TCP のチェックサムのオプションの 1 ぀にも採甚されおいる1。Solaris 系のファむルシステムのチェックサムずしおも採甚されおいる。䜿われる定数には、玠数の積合成数を利甚したバリ゚ヌションがある。
fletcher-8 8 bits sum
fletcher-16 16 bits sum Go 蚀語による実装サンプルを芋る
fletcher-32 32 bits sum
Adler-32 32 bits sum zlib の圧瞮ラむブラリの圧瞮や展開解凍のチェックのために fletcher-16 を改善しお開発された。信頌性ず匕き換えに高速性を远求しおいるタむプ。同じ長さの CRC よりも速い。信頌性は fletcher-16 ず fletcher-32 の䞭間くらい。IETF の RFC1950 で定矩されおおり、玠数の剰䜙mod)を利甚しおいる。
xor8 8 bits sum LRCLongitudinal Redundancy Check、氎平冗長怜査ずも呌ばれ、蚈算方法は ISO 1155 で定矩されおいる。sum8 に䌌おいるものの、加算時に 8 ビット0xFFのマスクを合蚈倀にかけるこずで合蚈倀がオヌバヌフロヌしないこずず、チェックサムを算出する際の 2 の補数の算出時に XOR を䜿っおいるのが特城。具䜓的には合蚈にマスク倀0xFFを XOR 埌 +1 し、䞋䜍 8 ビットをチェックサムずする。XOR8 も sum8 同様に 8 ビットごずの加算倀に、さらにチェックサム倀を加えるず末尟 8 ビットが 0 になる。オンラむンで蚈算を芋おみる, Go
ISO 7816 に準拠した IC カヌドの読み取りや、むンタヌネットの PPP 接続時のシリアル信号RFC1134のチェックに䜿われおいる。
Luhn algorithm 1 decimal digit sum
Verhoeff algorithm 1 decimal digit sum
Damm algorithm 1 decimal digit Quasigroup operation

CRC 系Cyclic Redundancy Check, 巡回冗長怜査

アルゎリズム名
関数名含む
デヌタ長 算出タむプ
系統
備考
cksum (Unix) 4 Byte (32 bit) CRC 名残で checksum ず付いおいるが、POSIX:2008 (IEEE Std 1003.1-2008) に準拠した CRC-32 アルゎリズムを䜿ったコマンドであるため CRC に分類される。改竄かいざん耐性はなく、簡単に衝突こずなる倀で同じ出力にさせるこずができる。
CRC-8 1 Byte (8 bit) CRC いわゆる CRCCyclic Redundancy Check、巡回冗長怜査系の兞型的なアルゎリズムの 1 ぀。CRC の Cyclic巡回は、CRC-n の堎合、デヌタを䞊䜍から n ビットぶんを 1 ビットず぀ズラしながら参照しお挔算しおいくため「巡回」ず呌ばれる。前述のチェックサム系アルゎリズムが足し算加算をベヌスにしおいるのに察し、割り算陀算をベヌスにしおいるアルゎリズムで、䜙りをハッシュ倀ずする特殊な剰䜙算である。
CRC の挔算のポむントは 2 ぀あり、その「割る方の倀」以䞋「陀数」、divisorの算出方法ず、実際の CRC の蚈算方法である。
陀数の倀は定数が䜿われるが、耇数のバリ゚ヌションタむプがあり、いずれも倚項匏を甚いお算出された定数である。いずれのタむプの陀数でも、長さは n ビット + 1 の長さである。CRC-8 の堎合は 9 ビット
CRC の蚈算方法は「割り算の筆算」乗陀法に近い方法を䜿う。぀たり、察象の倀の巊から陀数ず同じ桁数ぶんを割り、その結果を反映させお 1 桁ずらしおを繰り返す方法に近く、割る代わりに XOR する。XOR で割り算できるのは、割り算は匕き算の連続であるこずに加え、筆算䞭 0 ず 1 だけで蚈算するため「借り」が発生しないので GF(2) のガロア䜓ずいうテクニック䜓系が䜿えるためである。
具䜓的には CRC-8 の堎合、たずデヌタの䞊䜍 8 ビットを参照し、その倀の巊端の 1 ビットが 1 の堎合は陀数ず XOR した倀ず入れ替える。0 の堎合は䜕もしない次に進む。次に参照先を右に 1 ビットずらしお同様に 8 ビットぶんを参照するこずを䞀番右に蟿り付くたで繰り返す。぀たり、進めるごずに倀の巊端がどんどん 0 になっおいく具䜓䟋。そしお、最終結果の䞋䜍 8 ビットが CRC-8 の倀ずしお䜿われる。
CRC 系は隣り合わせのデヌタを参照しおいくため、sum 系に比べるずデヌタの䞊び順に匷いものの、離れた䜍眮の違いは怜知しにくい同じ答えになるこずがある。そのため、改竄かいざん耐性はないが、バヌスト突発的な匷いノむズなどによる䞀郚のビット䞊びが倉わった堎合の怜知には匷いため、シリアル通信のチェックサム倀ずしおも䜿われる。
CRC-16 2 Byte (16 bit) CRC CRC の 16 ビット版。シリアル通信系プロトコルのデヌタチェックによく䜿われる。陀数ずしお䜿う定数の算出に䜿われる倚項匏には、やはりバリ゚ヌションがあり、CRC-16 は 22 個が知られおいる。有名なバリ゚ヌションずしお、CRC-16-IBM の X16+X15+X2+1 は USB や PLCのチェックに䜿われ、CRC-16-CCITT の X16+X12+X5+1 は Bluetooth や SD カヌドなどのチェックで䜿われる。オンラむンでCRC-16-IBMの蚈算を芋おみる, Go
CRC-32 4 Byte (32 bit) CRC
CRC-32 MPEG-2 4 Byte (32 bit) CRC
CRC-64 8 Byte (64 bits) CRC
  • Adler-32 は CRC であるず思われおいたすが、実質的にはチェックサムの郚類に分類されたす。

Universal hash function families

アルゎリズム名
関数名含む
デヌタ長 算出タむプ
系統
備考
Rabin fingerprint variable multiply
tabulation hashing variable XOR
universal one-way hash function
Zobrist hashing variable XOR

Non-cryptographic hash functions

アルゎリズム名
関数名含む
デヌタ長 算出タむプ
系統
備考
Pearson hashing 8 bits (or more) XOR/table
Paul Hsieh's SuperFastHash[1] 32 bits
Buzhash variable XOR/table
Fowler–Noll–Vo hash function (FNV Hash) 32, 64, 128, 256, 512, or 1024 bits xor/product or product/XOR
Jenkins hash function 32 or 64 bits XOR/addition
Bernstein's hash djb2 32 or 64 bits shift/add or mult/add or shift/add/xor or mult/xor
PJW hash / Elf Hash 32 or 64 bits add,shift,xor
MurmurHash 32, 64, or 128 bits product/rotation
Fast-Hash 32, 64 bits xorshift operations
SpookyHash 32, 64, or 128 bits see Jenkins hash function
CityHash 32, 64, 128, or 256 bits
FarmHash 32, 64 or 128 bits
MetroHash 64 or 128 bits
numeric hash (nhash) variable division/modulo
xxHash 32, 64, 128 bits product/rotation
t1ha (Fast Positive Hash) 64 and 128 bits product/rotation/XOR/add
pHash fixed or variable see Perceptual hashing
dhash 128 bits see Perceptual hashing
SDBM 32 or 64 bits mult/add or shift/add also used in GNU AWK

Keyed Cryptographic Hash Functions

アルゎリズム名
関数名含む
デヌタ長 算出タむプ
系統
備考
BLAKE2 arbitrary keyed hash function (prefix-MAC)
BLAKE3 arbitrary keyed hash function (supplied IV)
HMAC
KMAC arbitrary based on Keccak
MD6 512 bits Merkle tree NLFSR
One-key MAC (OMAC; CMAC)
PMAC (cryptography)
Poly1305-AES 128 bits nonce-based
SipHash 32, 64 or 128 bits non-collision-resistant PRF
HighwayHash 64, 128 or 256 bits non-collision-resistant PRF
UMAC
VMAC

Unkeyed cryptographic hash functions

アルゎリズム名
関数名含む
デヌタ長 算出タむプ
系統
備考
BLAKE-256 256 bits HAIFA structure[14]
BLAKE-512 512 bits HAIFA structure[14]
BLAKE2s up to 256 bits HAIFA structure[14]
BLAKE2b up to 512 bits HAIFA structure[14]
BLAKE2X arbitrary HAIFA structure,[14] extensible-output functions (XOFs) design[15]
BLAKE3 arbitrary Merkle tree
ECOH 224 to 512 bits hash
FSB 160 to 512 bits hash
GOST 256 bits hash
GrÞstl up to 512 bits hash
HAS-160 160 bits hash
HAVAL 128 to 256 bits hash
JH 224 to 512 bits hash
LSH 256 to 512 bits wide-pipe Merkle–Damgård construction
MD2 128 bits hash
MD4 128 bits hash
MD5 128 bits Merkle–Damgård construction
MD6 up to 512 bits Merkle tree NLFSR (it is also a keyed hash function)
RadioGatún arbitrary ideal mangling function
RIPEMD 128 bits hash
RIPEMD-128 128 bits hash
RIPEMD-160 160 bits hash
RIPEMD-320 320 bits hash
SHA-1 160 bits Merkle–Damgård construction
SHA-224 224 bits Merkle–Damgård construction
SHA-256 256 bits Merkle–Damgård construction
SHA-384 384 bits Merkle–Damgård construction
SHA-512 512 bits Merkle–Damgård construction
SHA-3 (subset of Keccak) arbitrary sponge function
Skein arbitrary Unique Block Iteration
Snefru 128 or 256 bits hash
Spectral Hash 512 bits wide-pipe Merkle–Damgård construction
Streebog 256 or 512 bits Merkle–Damgård construction
SWIFFT 512 bits hash
Tiger 192 bits Merkle–Damgård construction
Whirlpool 512 bits hash

ハッシュ倀の長さ䞀芧ず速床の目安

すべお同じメッセヌゞをハッシュ化したもの「Hello Qiita!」のハッシュ倀なのに、ハッシュ倀の長さ、぀たりビット長が同じでも倀がたったく異なるこずに泚目ください。

🐒   各アルゎリズムの PHP 7.2.6 での蚈算速床も蚘茉しおいたすが、環境だけでなく PHP のバヌゞョンによっおかなり速床が異なりたす。速床は目安皋床にご利甚ください。たずは匷いアルゎリズムで組んでから、「掚枬するな、枬定せよ」の粟神でご自分の環境に最適化するこずをお勧めしたす。
なお、SHA-3 に含たれる SHAKE256 などの可倉長のアルゎリズム、および SHA-3 の最終遞考たで残った BLAKE2 や、その埌続で爆速ず噂の BLAKE3 は、ただラむブラリが枯れおOS やプログラム蚀語で浞透しおいないため含めおいたせん。

仕様

  • 怜蚌環境macOS HighSierraOSX 10.13.6, PHP 7.2.6cli, MacBookPro Early 2015, 2.7GHz Corei5, Mem 8GB 1867MHz DDR3
  • ハッシュするメッセヌゞ「Hello Qiita!」
  • ルヌプ回数1,000,000 回100 䞇回
  • 速床䞊蚘ルヌプの 10 回ぶんの平均倀
  • 䞊び順桁数の少ない順 → 速い順
  • メッセヌゞダむゞェストは暪スクロヌルをさけるため 8 桁4バむトごずのブロックに分けおいたす。
  • 枬定の゜ヌスコヌド @ Paiza.IO

8 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
fnv132 4 Byte 0.157887 sec b04649f6
fnv1a32 4 Byte 0.157962 sec 129b42dc
adler32 4 Byte 0.165301 sec 1bf5042e
crc32 4 Byte 0.169681 sec dd54ff69
crc32b
(IEEE)
4 Byte 0.172050 sec ad6adc0d
joaat 4 Byte 0.173369 sec 2cbbf315

16 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
fnv164 8 Byte 0.168120 sec 97bfaffd 885daad6
fnv1a64 8 Byte 0.176964 sec 07c72cc2 7b5f8b5c

32 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
md4 16 Byte 0.284748 sec e2500f3f 1eb028a4 563ca3d4 35028996
md5 16 Byte 0.337097 sec 7c414ef7 535afff2 1e05a36b 1cfc9000
tiger128,3 16 Byte 0.341727 sec 60bd4df9 e039716f 07c9ecd4 4c203d34
tiger128,4 16 Byte 0.397596 sec 7c20d9b5 d9e79da7 b5241a08 a353018a
ripemd128 16 Byte 0.553369 sec 0ff7eaf1 38540680 8e92e642 28a79243
haval128,3 16 Byte 0.954699 sec a8fe5c62 4c856077 d07db6bc 9a7f1275
haval128,4 16 Byte 1.027350 sec b5ee64c0 6a003d55 65108356 08c6a34c
haval128,5 16 Byte 1.197690 sec ad189ff3 183c9cfe cf5a39e3 45ba95f8
md2 16 Byte 4.762099 sec 8cd3c9c1 f1079b15 639ddab1 2227d400

40 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
sha1 20 Byte 0.348829 sec 5d8793ae d96d808a b6af8e47 5ce244e8
a604e478
tiger160,3 20 Byte 0.367638 sec 60bd4df9 e039716f 07c9ecd4 4c203d34
6f07e46a
tiger160,4 20 Byte 0.399170 sec 7c20d9b5 d9e79da7 b5241a08 a353018a
bf178a02
ripemd160 20 Byte 0.694799 sec 99a6c172 52ae4e64 e8d22853 c54ee2ad
44089160
haval160,3 20 Byte 0.900242 sec aba140dc e20ac7a2 615053de 4336e343
37a49b46
haval160,4 20 Byte 1.033398 sec 6bc4fecd c33d5d21 14c695ff f449d333
58f3030d
haval160,5 20 Byte 1.197252 sec d87a41cb 73469426 42faf2ae 7d62e81a
eba5dcc6

48 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
tiger192,3 24 Byte 0.394713 sec 60bd4df9 e039716f 07c9ecd4 4c203d34
6f07e46a 9c308ef7
tiger192,4 24 Byte 0.410200 sec 7c20d9b5 d9e79da7 b5241a08 a353018a
bf178a02 0a74f3fb
haval192,3 24 Byte 0.874294 sec e2b0c018 6b1cc119 0eebe1be 9d61953d
2dd78ba4 8136086c
haval192,4 24 Byte 1.031765 sec 7540fa22 a5714124 cf942e1b 31a890b9
bb59d58c e5a61157
haval192,5 24 Byte 1.211350 sec e4a6b10a d8286eaf 8cb3f225 950c2f93
b6fdab8c 601626c8

56 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
sha224 28 Byte 0.713225 sec d72d6ef7 0a788b3e 7f720b5d 88f20a13
bf161c31 b260fd34 6573094d
sha3-224 28 Byte 0.817025 sec e833eab3 4fbefbe8 9e44dcf1 d4ea9990
10981761 22f51708 df9cd9d0
sha512/224 28 Byte 0.825188 sec e205b15d 16eda0ce e195d210 73edca14
a69198e9 0070b9b0 09f7cb16
haval224,3 28 Byte 0.842655 sec a69049ca 88565098 a6f5e2bc adb22980
e59da983 9a779b63 c214e019
haval224,4 28 Byte 1.045480 sec 090b25d0 e8a0f5ef ecf6b683 5be72fe5
6913b34e 2d086922 3b1ac5d1
haval224,5 28 Byte 1.209415 sec 5343b4b1 a16119c5 dcd7726e 53128841
fecb7607 88e9008f 6c6f2cb6

64 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
ripemd256 32 Byte 0.574046 sec e0fe9c49 b1a59fae 47096909 83e62829
4887b161 5722a62c 2c4187be 816b058d
sha256 32 Byte 0.668654 sec e863d36c 24ada694 fa77454b 33e8f9b9
545d372a ae251e87 79fc25df 16943fed
sha3-256 32 Byte 0.824698 sec cedaea23 33478d77 bc9ed3e3 3303f455
85af1917 4a451ce9 3029fedc dd4d1ecb
sha512/256 32 Byte 0.833001 sec aaa2e875 112de9b6 1744d4a0 ae757e40
cd12008a 0f3948fb 7c42a8cd 48c361b8
haval256,3 32 Byte 0.845439 sec 5f788c8a 5359387b acf7bf60 ff4dd08d
e7176205 a0aae1ce 4f485b40 126c0d2f
haval256,4 32 Byte 1.048196 sec 4ebb9e6f a6c045b0 cbba419e f06ac973
b2fd4914 f746e142 bb6b840f bd836158
haval256,5 32 Byte 1.218753 sec c99614ae a2985f43 f480d029 bcb7974b
f5aface5 8730c9d6 f3141a67 58270431
gost 32 Byte 1.828385 sec 667f4328 0ff9e0a5 9c15de57 022becf3
cd1a48f8 d37a165c 87576b6f 814fa482
gost-crypto 32 Byte 1.849877 sec 7ebf0f97 0f1246b6 aea110d7 32cbcdfd
b0169cf1 7336bae7 814e99f1 8abfbd21
snefru 32 Byte 2.841073 sec ad081810 0ab15234 b13b8d09 ad0c519a
35469221 adbf8c5f a71594ca f7dfddc2
snefru256 32 Byte 2.850217 sec ad081810 0ab15234 b13b8d09 ad0c519a
35469221 adbf8c5f a71594ca f7dfddc2

80 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
ripemd320 40 Byte 0.725499 sec 6d152e32 fee2b979 024b8cff e416c898
16032680 779f7c3a 93c9aa26 35441245
8d4a9010 ad8fdfa5

96 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
sha384 48 Byte 0.831855 sec b10497cf 49601678 4d8413a4 662983a8
dc4ac470 039ea755 d5ec985f 1aab04ee
26dc3d67 71bbe404 75ea7d13 5a97ba58
sha3-384 48 Byte 0.835068 sec e83e54ee 323dafb5 ca2d800f d479e1cc
94502362 93d5ad74 36228519 aa657ea3
d1da8bb6 2d07035d ec1ece2f 428ec8dc

128 桁のハッシュ倀

アルゎリズム バむト長 速床 ハッシュ倀
sha3-512 64 Byte 0.851400 sec 9d1aaed0 79bac194 6a5fbafb 4285ec5b
dcf0053a 9e005590 46884a14 8f28fcb9
02441b49 cb3a8277 5834a244 4dd183ed
a36cee90 0f5662f8 2353fae7 e7111740
sha512 64 Byte 0.860255 sec cac9036c 1dd3652f c550e99a 4ec2b066
d69d6a40 a369bc85 e3078960 e6f26012
4138f5d0 f4e9a6e0 47dfb833 c9dd9b33
76d02d49 be37de26 dd6234d4 e79cc09e
whirlpool 64 Byte 1.041927 sec 488c6cd6 eccb5348 8a7c7617 8c89d514
16b8eb2b 88a30b79 71f1f176 70e27659
fc477cd9 6ade86e4 b6176c5e f2f67068
89606786 4ce15443 eff90733 fd4fcf4c

TS; DR 最速のDBキヌ怜玢を求めお with SQLite3

ハッシュ倀の衝突は別のアルゎリズムでは衝突しない 限りなく

衝突のむメヌゞ
// 倀が埮劙に異なる $a ず $b
$a = 'xxxxxxxxx..1..xxxxxxxxx'; // 長ったらしい文字列 a
$b = 'xxxxxxxxx..0..xxxxxxxxx'; // 長ったらしい文字列 b

$result_sha1 = ( hash('sha1', $a) === hash('sha1', $b) );
$result_md5  = ( hash('md5',  $a) === hash('md5',  $b) );

// $result_sha1 --> true, 偶然にも衝突が発生
// $result_md5  --> false, アルゎリズムが異なるず衝突しない可胜性が高い

叀くからダりンロヌド・ペヌゞなどでファむルの改ざんや砎損がないかを比べるのに䜿われおいる「ハッシュ関数」。

身近なずころでは、い぀もお䞖話になっおいるパッケヌゞマネヌゞャヌのパッケヌゞ管理、アクセス・トヌクンの䜜成や、みんな倧奜き Git のコミットID が有名ですが、デヌタベヌス以䞋 DBのクラスタリングや負荷分散などにも䜿われおいたす。

Linux のニッチで老舗のパッケヌゞマネヌゞャヌである Nix では、ハッシュ倀を党面的に䜿うこずで䟝存関係を培底的に管理しおいたす。最近、頭角を珟しおいる Linux の異端児 NixOS は、その仕組みを OS レベルで䜿うカヌネル含む党おのシステム・ファむルをハッシュ倀ベヌスで管理し、シンボリック・リンクを貌り替えるこずで、異なるバヌゞョンのテストやトラむ゚ラヌをしやすくしおいたす。

たた、埌述する IPFS、ブロックチェヌンや、そのマッシュアップで新型コロナの頃に話題になった NFT などでは芁かなめの関数ずも蚀えるなど、ハッシュ関数は、今埌もさたざたな堎面で掻躍が期埅される関数です。

この蚘事では、「ハッシュ関数の基本ず基瀎知識」、そしお「ハッシュ関数を掻甚した SQLite3 の 1 ぀のアむデア」をシェアしたいず思いたす。

🐒   2021/02/19 远蚘: Qiita の Markdown の仕様倉曎により、今たで <details> タグで「必芁な人だけみれる」ように隠しおいた基本的な情報も衚に衚瀺されおいたす。そのため、やたら長い蚘事になっおいたす。

🐒   2021/03/05 远蚘: Qiita の Markdown で、<details> タグの仕様倉曎は β 版の䞀時的なものだったらしいのですが、たた再々線成するのも面倒なので、そのたた衚瀺した状態にしたす。
ず蚀うのも、Qiita は線集時に数文字打぀たびにプレビュヌを曎新するので、これだけ長文の蚘事になるず秒単䜍で動䜜が重くなりたす。そのため、重耇する説明も倚く、やたら長い蚘事のたたになっおいたす近々 git でオヌプン゜ヌスにしようか考えおいたす。
目次を芋お、ハッシュ関数の基本や掻甚方法は「完党に理解した」ず感じた方は、本題の「長さを知ったずころで䜕」たで、スキップしおください。答えを先に蚀っちゃうず「デヌタのハッシュ倀 n 桁を SQLite3 の rowid に䜿う」っお暡玢した時の話しです。それでも読んでみようずいう方は、ゎロ寝でもしながら読んでください。よく寝れるず思いたす。私も曞いおいお寝ちゃいたす。

ハッシュ関数を完党に理解した気になるコマケヌこず

ハッシュ倀ずは、デヌタそのものから識別子ずしお䜿える倀を取埗したい堎合に䜿われる倀です。

連番などの䞀意の倀を識別子ずしおデヌタに玐付けるのではなく、デヌタから識別子を取り出す算出する関数がハッシュ関数です。

ずは蚀え、ハッシュ関数は異なるデヌタでも同じ識別子を返す堎合がありたす。なるべく䞀意の識別子が欲しい堎合には、「本圓に䞀意であるか」ずいう難しい問題ずなり、暗号孊的芁玠が加味されるため「暗号孊的ハッシュ関数」を利甚する必芁がありたす。

ハッシュ関数の基本ず特城

先に、䞀蚀で恐れずに蚀うなら「ハッシュ倀・はデヌタの指王」です。

぀たり「デヌタのハッシュ化」ず蚀うのは「デヌタから情報の指王を採取するこず」みたいなもので、「ハッシュ倀」ずは採取した指王情報のこずであり、デヌタの暗号化でも圧瞮でもないのです。

もちろん、デヌタなので指を持ちたせん。そのため「指王」よりは、ハッシュ倀はデヌタの「情報王」ず蚀っおもいいかもしれたせん。

人間の指王が、特定の個人を識別するために䜿えるように、デヌタの指王ハッシュ倀も特定のデヌタ識別に䜿えたす。

笊号化された情報、぀たりコンピュヌタヌが認識できるデヌタ0 ず 1 のビットで衚珟できる情報であればテキストであろうが、画像であろうが、プログラムであろうが、そのデヌタからハッシュ倀を埗るこずができたす。

人間の指王は、それ自䜓からは盎接本人を特定できたせんし、個人情報を持ちたせん。しかし、本人の指王ず「比范」したり「察応衚」さえあれば、誰の指王であるか特定できたす。そしお、そこから DB で個人情報ず玐づけるこずができたす。ずは蚀え、本人を特定できたずしおも指王からは本人を埩元クロヌンを䜜成できたせん。

ハッシュ倀も䌌おいたす。ハッシュ倀だけでは元の倀はわかりたせんが、ハッシュ倀を比范したり、察応衚さえあれば元の倀を特定できたす。たた、それをもずにキヌずしおDB に玐づけるこずもできたす。さらに、ハッシュ倀を知っおいおも、ハッシュ倀そのものからは元の倀を埩元できたせん。

「埩元できない」ずいうのは、逆算できない・蚈算で割り出せないずいうこずです。䟋えば「割り算の䜙り」剰䜙からは、元の倀がわからないのず䌌おいたす。

固定長のIDを䜜る䟋
$max = 100;     // IDの長さ最倧倀は99。∎ 2桁衚瀺で 00 〜 99 の固定長
$message = 123; // メッセヌゞを数倀化したもの文字コヌドなど
$hash = $message % $max; // 123 を 100 で割った䜙り必ず 0 〜 99 の範囲
printf("%02s", $hash);   // 23 <-- 䜙りが 23 になる組み合わせは無限にあるため
                         //        message を芋぀けるには行動孊的なアプロヌチ
                         //        が必芁になる

そしお、同じ指王を持぀ 2 人は必ず 1 ペア以䞊いる0 %ではないように、異なるデヌタなのに同じ指王ハッシュ倀を持぀デヌタは必ず䜜れたす。簡単ずは蚀っおない

先の䟋で蚀うず、メッセヌゞが異なっおも同じ䜙りになるようなむメヌゞです。

䜙りが衝突する䟋
$secret = 100;

$message = 123;
print_r($message % $secret); // 123 mod 100 = 23

$message = 323;
print_r($message % $secret); // 323 mod 100 = 23

もちろん、実際には、こんな簡単な匏は䜿われたせん。

しかし、ずお぀もなく匱いながらも関数化すれば立掟な「ハッシュ関数」です。ただ、実甚には耐えない「アルゎリズム」ず「ハッシュ倀の長さ」の、なんちゃっおハッシュ関数である、ずいうだけです。

぀たり、異なるデヌタが同じ「デヌタの指王」を持぀確率識別の粟床が、内郚のアルゎリズムやハッシュ倀の長さに䟝存する、この「謎の箱」がハッシュ関数です。

では、ハッシュ関数の基本を「正しく」知ろうず Wikipedia を開くも、䜕を蚀っおいるのかわかりたせん。

これは法埋や音楜理論や機械孊習などのドキュメントず同じように、「同じプロトコルの人蚀っおいるこずがわかる人向けのドキュメント」だからです。

䟋えば、「倉数」や「配列」ず蚀う甚語がわからないのに゜ヌト・アルゎリズムの説明を芗きに行ったり、メモリアドレスやポむンタが理解できおいないのに高速化ドキュメントを読んだり、ビットや XOR がわからないのに TCP や JPEG の仕様曞を芗くようなものです。

もしくは「デスクトップを右クリックしおプロパティを開いおください」ず説明したら、「日本語でおk」ず盞手がブチキレたこずはないでしょうか。同じようなものです。

぀たり、ハッシュ関数を正しく知ろうずするずプログラミングの基瀎だけでなく「数孊」や「暗号孊」の基瀎知識も必芁なのです。そしお端的に䌝えようずするず、ある皋床の基瀎知識を盞手に求めるこずになるものなのです。

この蚘事は、ゎロ寝読みでもいいので、䞀通り読んでから、再床 Wikipedia の蚘事を読み盎しおみおるず「読める ... 読めるぞ」ずなるこずを期埅しおいたす。

孊問こわい暗号孊・数孊こわい

さお「数孊や暗号孊の基瀎知識も必芁」ずは蚀ったものの、暗号孊の䞖界は調べれば調べるほど「暗号化・埩号」ずいった䞖間䞀般が思うこずを超え、いたや「暗号セキュリティ」ず同矩なんだなず痛感したす。

そしお数孊含む基瀎知識がない人からの「本圓に安党なのか」「なぜ安党ず蚀えるのだ」ず蚀った質問には、数匏で蚌明しお芋せるしかありたせん。蚀葉で説明するず、今床は蚀葉が独りひずり歩きするずいった機械孊習の゚ンゞニアの方ず話しおいる時ず䌌たゞレンマを垣間芋たす。

蚀葉の独り歩きず蚀えば、機械孊習のディヌプラヌニング系の話題で「研究者も、なぜそうなるのかわからない」ず報道されるのを目にしたこずがあるず思いたす。そのため「䜜っおる本人たちすら理解できない謎の技術」的に思われがちです。

しかし、「わからない」ずいうのは「仕組みはわかっおいるが、キチガむじみたず蚀うより、倩文孊的な組み合わせのパタヌンを機械にさせおいるため、なぜその組み合わせにたどり着いたのかがわからない」ずいう略なのです。理解しおいないわけではないのです。

組み合わせの怖さを知らないずいう方は、「フカシギおねえさん」「組み合わせ爆発」「巡回セヌルスマン問題」「䞉䜓問題ず二重振り子」ず蚀ったキヌワヌドで調べおみおください。

そしお「では、仕組みを玠人にもわかるように説明せよ。䞉行で。」みたいな、仕組み理論や理屈を理解する気もない、結果だけが欲しいせっかちさんが蚀うものだから、「なんかわからんけど、すごい」ずいう認知ず、AI ずいう蚀葉が䞀人歩きしお、䞖間ずの甚語の乖離かいりに悩んでいるそうです。

「AI が〜 AI が〜」ず隒ぐのは、機械孊習の孊者からするず「『なんか知らんけど、時代らしい』ずいうだけで付けた、電気ブランやデゞタル・パヌマみたいなもんが溢れかえっおいる」らしいです。

たぁ、確かに時代ではあるのですが、ぶっちゃけ 👌資金 がないず、たずもな研究やモデル䜜成はできたせん。そのため流行っおくれないず予算も出ないし、説明した正したずころで「動くものだけで、仕組みに興味がない盞手」に誀解を解くための時間を割くのも無駄ず蚀うのが珟状らしいです。

我々プログラマヌの䞖界で蚀えば、「デゞタル化」は「笊号化であっお、電子化のこずではない」ず思い぀぀も「デゞタル化電子化」ずいう䞖間の認知に流されないずいけない歯痒さに䌌おいたす。もしくは「えぇぇ。それはクラりドずチャうダろ」ずいった感じでしょうか。

䞊蚘 「デゞタル化」は「笊号化であっお、電子化のこずではない」 に぀いお、思いのほかカチンずきた人が倚いみたいで、SNS で「トランゞスタも電子制埡なんだから電子化ず蚀っおも間違いじゃない」ずいう感じのツッコミを数件いただきたした。

補足したすが、ここで蚀う「デゞタル化」ずはディゞット、぀たり数えられるくらいたで情報量を萜ずすこずを蚀いたす。

アナログ・デヌタの内容が「0b1011」ず衚珟できるなら、囲碁の石やオセロのコマを「●◯●●」ず䞊べお眮いたり、「/-//」ず壁に傷を぀けおも、その数情報は過䞍足なく盞手に正確に䌝え、残すこずができるずいう意味です。同様に、波の幅を「広い・狭い・広い・広い」ず送信すれば、アナログ信号であっおもデゞタル情報を䌝えられたすいわゆる地デゞ。

アナログを「坂」だずするず、デゞタルは「階段」のようなもので、「なんずか山の䞭間で埅っおる」より「なんずか山の●段目で埅っおる」の方が正確に䌝わるむメヌゞでしょうか。

぀たり、必ずしも電気もしくは電子機噚でないずデゞタル化できないずいうわけではないのです。それらを䜿った方が、䜕かず楜だし、速いずいうだけなのです。

たた、「数えられる」ずいう点で「デゞタル化」を「量子化」ずも蚀ったりしたす。アナログ無限に連続したデヌタの枬定倀を䞞めたものを量子化ず蚀い、笊号化したものがビットなのですが、ハッシュ関数における説明においおは「量子化」ずいう蚀葉を䜿うのは奜きではありたせん。埌述したすが、ある皮のハッシュ関数特に暗号がらみでは倩敵ずも蚀える量子コンピュヌタヌの話で、わけわかめになるからです。同じ「量子」ですが、「䜐野量子」くらい違いがあるのに、勝手に玐づける人が倚いからです。

この蚘事では、䟋えば画像をスキャンしただけのものは「電子化」、画像からデヌタを抜き出し解釈できるもの䟋えば OCR デヌタを「デゞタル化」ず呌びたす。これは埌述する「電子眲名」ず「デゞタル眲名」の違いで重芁だからです。

さお、暗号孊の䞖界も我々のようなパンピヌが解釈した内容が埮劙に間違ったたた広たっおいるため、動くものだけで仕組みには興味がない盞手に、基瀎から教えたり間違いを正す時間を割くのも無駄ず感じるようです。

偉そうにゆうお、筆者も数孊や暗号孊に匷いわけではありたせん。

しかも、゚ンゞニアず蚀うよりは猿人に近いのえんじんにnearなので、1 ぀の公匏より 500 文字の゜ヌスコヌドを芋せおもらった方が理解できるのです。

そこで、bash などを觊ったり、自分で䜕かしらのプログラム蚀語で俺様関数を䜜ったこずがあればわかるプログラマヌ的な衚珟方法で「知っおおいた方が良いハッシュの基瀎知識」を説明したいず思いたす。

なお、この蚘事にはサンプル・プログラムはあるものの、蚈算匏やアルゎリズムの詳现はありたせん。たた、セキュリティヌの蚘事でもありたせん。むしろ暗号孊やセキュリティヌ以前・・の基瀎知識レベルです。「割り算の䜙り」や「倉数」が理解できおいれば十分です。

あくたでも筆者が考える、実動䜜するものを通しお理解する「ハッシュ関数の基瀎きそ抂論がいろん」的なものです。そのため、䞁寧に説明しおいる぀もりですが、いささかくどい・・・郚分がありたす。

ゞャンクフヌド的な蚘事ですが、自分なりに「ハッシュ関数が奜きになる話題や実䟋」を、おんこ盛りにしおいたすので、ゎロ寝でもしながらスマホでお読みください。

この蚘事では、さたざたな甚語ず、その抂芁を説明しおいたす。そしお、それらの甚語が぀ながっお点ず点が線になっお行くさた・・を楜しんでいただければず思いたす。

たた、興味のあるキヌワヌドが出お来たら自分なりに掘り䞋げお、より正確なものに堀り䞋げお欲しいず思いたす。キヌワヌドの抂芁を理解した䞊で各皮文献をご芧になるず、より理解床が高たった、そんな蚘事になるずいいなず思いたす。

そしお間違いを芋぀けたら、戻っおきお、こっそりコメント欄に曞いおいただけるず嬉しいです。

たた、この蚘事は「❀旧 LGTM」が付くたび、その時折で埗おいる知識や間違いを敎理する぀もりで曎新・修正しおいたす。曞き出さないず理解できないサガなので、1 ぀の情報ずしお気軜にお読みください。

「ハッシュ」の意味ず「ハッシュ関数」の定矩

さお、ハッシュ関数の説明の前に「ハッシュ」の意味ず、この蚘事における「ハッシュ関数」の定矩をしないずいけたせん。

ずいうのも、埌述したすが䞀般的に「ハッシュ関数」ずいう蚀葉は「暗号孊的ハッシュ関数」を暗あんに指しおいるこずが倚いからです。

そのため「ハッシュ関数のアルゎリズムずしお CRC を含めるのは違うんゞャマむカ🔈」ず蚀う方もいるず思いたす。

鋭い。

確かに、CRC はチェック・サムの芪戚みたいなものだし、正しくは「ゞャメむカ🔈」です。

しかし、それに固執しすぎるずセキュリティにばかり目が行っおしたい、「ハッシュ」の甚語の理解だけでなく、「ハッシュ関数」の利甚方法を狭めおしたいたす。

特に、「デヌタの類䌌性」をハッシュ倀にする「知芚ハッシュ」Perceptual Hashの理解の劚げや、機械孊習においお「ハッシュ化しおトヌクンを䜜成する」ず蚀われ「機械孊習に暗号が䜿われおいる」ずいった誀解にも繋がりかねたせん。

「ハッシュ」ずは䜕か

myArray["foo"] = "bar"; などの連想配列の「ハッシュ・テヌブル」や、JSON オブゞェクトなどの「ハッシュ」添字配列ず聞いお、「ハッシュっお䜕だろう」ず調べたら、やたら暗号や数孊の話しが出おきお、そっ閉じされた方も倚いず思いたす。

それでは「ハッシュ」ずは䜕でしょう。

ハッシュ関数の「ハッシュ」は「hash」ず曞き、単玔に日本語に蚳すず「ごた混ぜ」「现コマ切れ」「台無しにする」などの意味がありたす。

しかし、その語源を蟿るず面癜いルヌツがわかりたす。

矎術の叀兞技法で「hatch」ずいう平行線で描画する技法があり、フランス語の「hach🔈」から来おいたす。日本の挫画などでもペン画の基本ずなっおいる技法ですね。

ハッチング技法の䟋Wikipedia 「ハッチング」より

そこから英囜むギリス英語では平行線で構成された「井いの字」や「二にの字」のような状態のものを hatch もしくは hash ず呌ぶようになりたした。朜氎艊や宇宙船の「ハッチを開ける」などのハッチも「井いの字型の出入り口」であったこずから来おいたす。

他にも、肉やゞャガむモなどを、瞊暪に井いの字カットしおいき、现切れになったものを「hashed 〜ハッシュドなんずか」ず呌ぶのも同様の語源です。

そしお英囜では電話の「」キヌを「ハッシュ・キヌ」ず呌ぶようになりたした。これが珟圚の「ハッシュ・タグ」ハッシュ蚘号  によるタグ付けの語源です。

ちなみに、"#" の蚘号自䜓はラテン語の "libra"平等やバランスを象城する倩秀。転じお「重さ」の略字が厩れたものです。

ロヌマの商人などが、libra pondo「重さの量」を手曞きする際に "lb" に暪線を入れお略した "℔" が厩れたものが "#" です。のちにこれが量や数を瀺す蚘号ずなりたす。

"#" を米囜アメリカ英語ではポンドpoundず呌んだり、ポンドの略が "lb" や “£”libra の Lだったりするのも libra がルヌツです。

蚀語孊的には「平等」libraず「自由」liberは関係がないのですが、ラテン語圏では「独裁政治・封建制・奎隷制などからの解攟」系で、よくセットで䜿われるため、「䞍平等からの解攟ず自己責任 = 自立」ずし、䞍平等からの解攟を "libre" なんずか自由な、なんずかず奜んで衚珟されたす。

Libre Office などの libre が「無料ずいう意味ではなく、自由䞍平等からの解攟ず自己責任である」ず蚀われるゆえんでもありたす。

ハッシュ・タグ"#"の蚘号にも、こんな深い意味があったんですね。知らんけど

さお、閑話䌑題。

転じお デヌタをコマ切れにしお、それ単䜓では党䜓がわからないものをコンピュヌタの䞖界では「ハッシュ」ず呌びたす。

先に、「ハッシュ化しおトヌクンを䜜成する」ずいう機械孊習の衚珟があるこずに觊れたした。具䜓的には、デヌタ䟋えばテキスト文をコマ切れにしお、各々をトヌクンず呌び、トヌクンには ID が振られたすトヌクンずは、そこでしか利甚できない発行物を指し、ここでは、このデヌタでしか意味をなさない ID です。

このコマ切れにするこずを機械孊習でハッシュ化ず蚀いたす。

元デヌタ This is a data to be hashed and tokenized.
トヌクンず ID
6文字ごずにハッシュ
This i1, s a da2, ta to 3, be has4, hed an5, d toke6, nized.7

他にも、Javascript などの Hash map や、Redis などの hash ずいった、どうみおも連想配列か JSON のオブゞェクトにしか芋えないものを「ハッシュ」ず呌んでいるのも、デヌタ党䜓を现分化したものだからです。

ID Name Age
001 Alice 32
002 Bob 33
003 Charlie 16

䞊蚘デヌタの Redis におけるハッシュ1 件のデヌタ。行のこず。

Key Value
ID 001
Name Alice
Age 32

しかし、この皋床の现分化では個々のデヌタを寄せ集めれば元の圢に戻っおしたいたす。角切りステヌキのようなむメヌゞです。ハンバヌグのミンチ肉のように、埩元ができないレベルたで分割しお郜合のいいサむズで䜿いたい堎合に䜿われるのが「ハッシュ関数」です。

【たずめ】
コンピュヌタヌ業界における「ハッシュ化」ずは、情報を凊理しやすい䜿いやすいように断片化するこず。断片化された情報ハッシュ倀単䜓では党䜓が芋えないのが特城。

🐒  ちなみに「ミンチ肉」などの「ミンチ」は、ラテン語の「小ささ」の意である「minutia」が、フランスで「mincier」になり、英囜の「mince」になったものです。「分ふん」の minute や「小さい」の mini がミンチ肉ず同じ語源なのも面癜いですね。

「ハッシュ関数」の定矩

デヌタをコマ切れにするなど、「それ単䜓では党䜓がわからないデヌタにするこずをハッシュず呌ぶ」こずはわかりたした。

そしお、ハッシュ・マップなどは寄せ集めれば党䜓が芋えおしたうので、そもそも元の圢に埩元ができないレベルたで现分化ミンチ状態にしお、郜合のいいサむズにしたい時に䜿うのがハッシュ関数ずいうこずもわかりたした。

以䞊を螏たえお、この蚘事における「ハッシュ関数」の甚語の定矩をしたいず思いたす。

A hash function is any function that can be used to map data of arbitrary size to fixed-size values.

Hash Function @ Wikipedia より

【筆者蚳】
ハッシュ関数ずは、任意のサむズのデヌタを固定サむズの倀にマッピングするために䜿甚できる関数党般のこずを蚀いたす。

぀たり、どのような内郚凊理の考え方アルゎリズムの関数であっおも「その関数を通すず固定長のデヌタで返っおくる関数」を、この蚘事ではハッシュ関数ず呌びたす。広矩広い意味でのハッシュ関数ですね。

「ハッシュ関数」ずは䜕か

䜕はずもあれハッシュ関数は「任意のデヌタを枡すず『ハッシュ倀』ず呌ばれる倀が返っおくる関数のこず」です。

... ... ... たぁ、そうですよね。

でも「ただの関数である」ずいう認識は意倖に重芁なのです。

機械孊習などで「ニュヌラル・ネットワヌク」ずか芋聞きする際、「○」がたくさんの線で぀ながっおいる図を芋お、怖いず感じた方もいるず思いたす。

実は、あの「○」っお関数やメ゜ッドクラス関数のこずなんです。

そしお関数の出力を、別の関数の匕数に「配列で枡しおいる」のが「線」なんです。

しかも「○」の関数は「匕数に重みを付けお足し算しおフィルタヌにかけるだけ」ずいった「単现胞かよっ」ず蚀いたくなるような単玔な凊理をするだけだったりしたす。

そう考えながら芋るず単玔です簡単ずは蚀っおない。

「ハッシュ関数」も、なんだかんだ蚀っおも結局のずころ「ただの関数」なのです。

「凜数」぀たり「匕数が同じなら期埅する倀が出おくる謎の凜はこ」です。そしお「ハッシュ倀なる謎の倀」が戻り倀であるず蚀うだけです。「ハッシュ倀」に぀いおは埌述したす

ほずんどのプログラム蚀語で「ハッシュ関数」は実装されおいたすが、䜿甚できるアルゎリズム凜の䞭身は環境によっお異なりたす。暙準ラむブラリ最初から同梱されおいるモゞュヌルなどに含たれおいるかに䟝存するからです。

「ハッシュ倀」ずは䜕か

さお、ハッシュ関数の戻り倀である「ハッシュ倀ずは䜕か」の前に、以䞋の "beef" および "beef1" ずいう文字列をハッシュ倀にした䟋をご芧ください䞀芋、ランダム関数のようにも思えたすが違いは埌述したす。

本蚘事で䜿甚する蚀語は、bash ず PHP です。コマンドが 1 行でおさたるず蚀うだけで遞びたした。どちらの蚀語も知らなくおも、やっおいるこずは同じなので気楜に構えおください。文字列を関数に枡しお出力しおいるだけです。プログラムの文法などは深く考えずに「単玔に䜕をしおいるか」に気付けば十分です。

bash は openssl コマンド、PHP では hash() 関数を䜿っおハッシュ化しおいたす。たた、利甚するアルゎリズムは md5 ず sha512 です。

ポむントは、bash php に限らず、どのプログラム蚀語を䜿っおも以䞋の 3 ぀は同じこずに泚目です。

  1. 数倀16 進数の文字列で返っおくる。
  2. アルゎリズムず匕数が同じ堎合は結果も倉わらない。
  3. 塩を 1 足すだけで結果が倧きく倉わる。
ハッシュド・ビヌフの䟋
匕数が同じなら結果も毎回同じミンチ肉
$ # 粗挜き牛ミンチ
$ echo -n 'beef' | openssl md5
34902903de8d4fee8e6afe868982f0dd

$ # 粗挜き牛ミンチ
$ echo -n 'beef' | openssl md5
34902903de8d4fee8e6afe868982f0dd
蚀語が違っおも同じアルゎリズムず匕数なら同じミンチ肉
$ # 粗挜き牛ミンチBash
$ echo -n 'beef' | openssl md5
34902903de8d4fee8e6afe868982f0dd

$ # 粗挜き牛ミンチPHP
$ php --run 'echo hash("md5", "beef");'
34902903de8d4fee8e6afe868982f0dd
具材を倉えおみる
$ # ハッシュド・ポテト
$ echo -n 'poteto' | openssl md5
147f31c730caa77f8a3440e549264a2e

$ # 角切りトマト
$ echo -n 'tomato' | openssl md5
006f87892f47ef9aa60fa5ed01a440fb
匕数を少し倉化させる味付けしおみる
$ # 粗挜き牛ミンチ  1g の塩入りbeef1
$ salt=1; echo -n 'beef'$salt | openssl md5
30017279d6a5bac241e764eeed261dd8

$ # 粗挜き牛ミンチ  1g の塩入りコックが違っおも同じレシピなら同じ味
$ php -r '$salt=1; echo hash("md5", "beef" . $salt);'
30017279d6a5bac241e764eeed261dd8
より现かいアルゎリズムに倉えおみる
$ # 絹ごし牛ミンチ
$ echo -n 'beef' | openssl sha512
8cd8bb0cef938ef9cd054c2c2cb965e83310ab5c197cb5fc8f35892a44c1a028bac9e1bcd6248580fa2739cc96074885ea3ee116ef35c2d8f6124270aeff50b7

$ # 絹ごし牛ミンチコマンドの蚀語が違っおも同じアルゎリズムず匕数なら同じミンチ肉
$ php -r 'echo hash("sha512", "beef");'
8cd8bb0cef938ef9cd054c2c2cb965e83310ab5c197cb5fc8f35892a44c1a028bac9e1bcd6248580fa2739cc96074885ea3ee116ef35c2d8f6124270aeff50b7

$ # 絹ごし牛ミンチ  1g の塩入り
$ salt=1; echo -n 'beef'$salt | openssl sha512
a528829f370819123ad3fb04d8066b77ec79ce6eddad07e5b2c925bbd9b2e699e73428d23315875c29b45500b8c767262cf5546e33974e4f7a6102abd1bb045e

$ # 絹ごし牛ミンチ  1g の塩入りコックが違っおも同じレシピなら同じ味
$ php -r '$salt=1; echo hash("sha512", "beef" . $salt);'
a528829f370819123ad3fb04d8066b77ec79ce6eddad07e5b2c925bbd9b2e699e73428d23315875c29b45500b8c767262cf5546e33974e4f7a6102abd1bb045e
Windows の PowerShell でも詊しおみる

Windows 11 の暙準コマンドでハッシュ倀を確認するには certutil ず Get-FileHash コマンドがありたす。

certutil は倚機胜である蚌明曞の無効化操䜜ずいったクリティカルな機胜も含むため、単玔にファむルのハッシュ倀を確認するだけなら Get-FileHash を䜿うこずが掚奚されおいたす。

Get-FileHashの構文
Get-FileHash [オプション] <ファむルのパス>

# 䜿甚䟋
Get-FileHash -Algorithm SHA512 foo.pdf

問題は Get-FileHash は「ファむル」のハッシュ倀に特化しおいるこずです。そのため、「文字列」のハッシュ倀を知りたい堎合は盎接䜿えないので、工倫が必芁になりたす。

文字列を䞀旊ファむルに曞き出しおから実行
PS C:\Users\KEINOS\OneDrive\Desktop> # 改行なしで "beef" のテキストを䜜成
PS C:\Users\KEINOS\OneDrive\Desktop> "beef" | Out-File beef.txt
PS C:\Users\KEINOS\OneDrive\Desktop> Get-FileHash -Algorithm MD5 ./beef.txt

Algorithm      Hash                                 Path
---------      ----                                 ----
MD5            34902903DE8D4FEE8E6AFE868982F0DD     C:\Users\KEINOS\OneDrive\Desktop

スクリプト内で文字列をハッシュ化したい堎合は、䞀旊ストリヌムに文字列を曞き蟌み、ストリヌム経由で読み蟌たせる必芁がありたす。

beef.ps1
PS C:\Users\KEINOS\OneDrive\Desktop> # スクリプトの䞭身
PS C:\Users\KEINOS\OneDrive\Desktop> get-content ./beef.ps1
$stringAsStream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter]::new($stringAsStream)
$writer.write("beef")
$writer.Flush()
$stringAsStream.Position = 0
Get-FileHash -InputStream $stringAsStream -Algorithm MD5 | Select-Object Hash

PS C:\Users\KEINOS\OneDrive\Desktop> # スクリプトの実行
PS C:\Users\KEINOS\OneDrive\Desktop> . ./beef.ps1

Hash
----
34902903DE8D4FEE8E6AFE868982F0DD
PowerShell 怜蚌バヌゞョン
PS C:\Users\KEINOS\OneDrive\Desktop> $PSVersion::PSVersion

Major  Minor  Patch  PreReleaseLavel  BuildLabel
-----  -----  -----  ---------------  ----------
7      4      1

さお、䞊蚘を芋るず beef の原型はありたせんが、ハッシュ倀の察応衚があれば、元は beef もしくは beef1 であるこずは確認できそうです。

ハッシュしたおのビヌフはミミズにしか芋えたせんが、成分衚䞊は同じでも「原型を留めおいない状態を数倀の文字列にした倀」がハッシュ倀です。

非可逆な感じは、「芆氎盆に返らず」でも「氎である」こずはわかるようなむメヌゞでしょうか。

ずは蚀え、ハッシュ倀は「倀」ずあるように数倀です。しかし、10 進数の倀のたただず人間゚ンゞニアが扱いづらいので短くするため、䞀般的に 16 進数の「数倀の文字列」で返しおきたす。ハッシュ関数のオプションによっおは文字列型でなく、バむナリバむトデヌタ型のたた取埗できるものもありたすが、いずれにしおも「数倀ずしお認識できる倀」で返っおきたす。

そしお、どのようにミンチハッシュにするかが「アルゎリズム」になりたす。

カヌドをシャッフルするかのように䜕床も XOR をする物もあれば、デヌタを 1 バむトず぀読み蟌みながらゎニョゎニョしたりず、どのアルゎリズムも䜿甚目的や思想によっお蚭蚈が異なりたす。

暗号孊的ハッシュ関数ずチェックサム的ハッシュ関数

ハッシュ関数の戻り倀である「ハッシュ倀」を生成するには、本蚘事の䞀芧で玹介しおいるように、色々なアルゎリズムがありたす。

各々異なった思想や目的で蚭蚈されおいたすが、いずれのアルゎリズムでも「匕数が同じであれば戻り倀も同じ」「どんな長さのデヌタでも固定長のデヌタにする関数」ずいう点は倉わりたせん䟋え挔算結果が 1 ず短くおも、最倧倀は決たっおいるため「パディング」ず蚀っお、頭をれロで埋めお固定長にしたす。それに茪を掛けお、SHA-3 の SHAKE256 のように任意の長さで取埗できるアルゎリズム、぀たり可倉長のアルゎリズムもありたすが、匕数が同じであれば同じ倀が返っおきたす。

「ハッシュ関数」の皮類

ハッシュ関数には倧きく 2 ぀の皮類がありたす。

暗号孊的ハッシュ関数ず、それ以倖です。

ハッシュ関数によっおは、暗号化にも䜿われおいる考え方アルゎリズムを利甚したものがありたす。これを「暗号孊的ハッシュ関数」ず呌びたす。恐れずに蚀うず「セキュリティヌ目的で䜿われるハッシュ関数のこず」です。

先述したしたが、ハッシュ関数には以䞋の 2 ぀の特城がありたす。

同じ結果になる
アルゎリズムず匕数が同じ堎合は、同じハッシュ倀が返っおくる。
同じ長さの倀になる
ハッシュ倀は固定長の数倀で返っおくる䞀般的に n 桁の HEX 文字列※1

そしお「暗号孊的ハッシュ関数」の堎合は、これに茪をかけおさらに倧きな 3 ぀の特城が加わりたす。

同じハッシュ倀にならない
異なる匕数を、同じハッシュ倀にするのは限りなく難しい。
逆算ができない
ハッシュ倀から元の倀匕数の倀は蚈算匏による算出ができない。※2
予枬が困難である
入力の芏則性に察しお出力に芏則性があっおはならず、ハッシュ倀から元の倀の予枬は難しい。※2
  • ※1 本蚘事未掲茉である SHAKE256 などの䞀郚のアルゎリズムでは「任意の長さの戻り倀が埗られる」可倉長で返すものがありたす。しかし「匕数が同じ堎合は、戻り倀も同じ」ず蚀う点で、同じ匕数であれば毎回同じ倀、぀たり同じ長さで返っおくるのは倉わりたせん。ちなみに SHAKE256 の 256 は出力のビット長ではなく、内郚で䜿われる匷床です。
  • ※2 無限ルヌプ総圓たり攻撃による算出や蟞曞攻撃による予枬の堎合陀く。逆に蚀えば「暗号孊的ハッシュを利甚しない」アルゎリズムは、暗号孊的ハッシュず比べ、より予枬・衝突可胜になりたす。衝突や暗号孊的ハッシュに関しおは埌述したす。

異なる倀なのに、ハッシュ化するず同じ倀になるこずを「衝突」コリゞョンず蚀いたす。

しかし、同じ衝突でも「あるハッシュ倀ず同じハッシュ倀になる倀を探す」のず「同じハッシュ倀になる異なる 2 ぀の倀を探す」のでは皮類が違いたす。

「自分ず同じ指王の人を探す」のず「同じ指王を持぀ 2 人を探す」のでは確認する数が違うのず同じです。研究する䞊で、これらの違いは重芁なため、専門家同士が迅速に疎通できるように各々に専門甚語が付いおいるので Wikipedia や専門蚘事を読んでも難しく感じるのです。

暗号孊的ハッシュ関数に぀いお、セキュリティ暗号孊専門の方の説明を聞いおも、わかるようでわからない説明に感じたす。「... ... 矎孊」ず説明されるような小難しさです。

「なぜ小難しい蚀い方をするのだろう」ず思い、備忘録ずしお、この蚘事を曞き始めたわけですが、単玔に「その業界の勉匷䞍足」ずいう語圙力のなさなのでした。ずほほ。

【たずめ】
ナヌザヌ目線だず「暗号孊的ハッシュ関数」は、デヌタの改竄かいざん怜知に匷い「デヌタの同䞀性」が重芖されたハッシュ関数であるのが特城です。

぀たり、異なるデヌタが同じハッシュ倀になりづらいアルゎリズムず蚀えたす。暗号孊的ハッシュ関数以倖のハッシュ関数に関しおは埌述したす。

ランダム関数ずハッシュ関数

さお、ハッシュ関数に觊れ始めるずランダム関数ずの違いが気になっおきたす。

ハッシュ関数ずランダム関数は、どちらも戻り倀の予枬が難しいゎタ混ぜな数倀を返したす。しかも、ランダム関数擬䌌乱数も、シヌド倀が同じ堎合は「毎回同じ結果になる」のです。

ランダム関数は、同じ倀になる戻り倀を「均等にランダムに返そうずする」こずが目的です。぀たり、出力結果に偏りかたよりがないようにランダムに倀を出力しようずしたす。そのため、ランダム性の性胜は、OS やラむブラリやハヌドりェアに䟝存するため、シヌド倀が同じでも、すべおの環境で同じ倀が返っおくる保蚌がないのです。

反面、ハッシュ関数の堎合は「アルゎリズムず匕数が同じなら、どの環境でも毎回同じ結果になる」ずいう点がランダム関数ず異なりたす。

さらに、ハッシュ関数の堎合特に暗号孊的ハッシュ関数は、「入力倀が異なるなら、なるべく同じ倀の戻り倀にならないように返そうずする」点も異なりたす。

暗号化ずハッシュ化

さお、「暗号孊的ハッシュ関数」ず蚀われお「暗号孊・的暗号的でなく」ず思った方も倚いず思いたす。

これは、暗号孊の考え方を取り入れた、セキュリティ甚途に䜿われるハッシュ関数だからです。

「暗号孊的ハッシュ関数」は埌から出おきたのですが、珟圚は他を凌駕りょうがし、ハッシュ関数ず蚀えば暗号孊的ハッシュ関数を暗黙的に指すこずも倚くありたす。

ハッシュ関数は「暗号の䞖界」でも、ずおもよく䜿われる関数で、暗号化する際にも内郚でよく䜿われたす。

そのためか、ハッシュ関数を「デヌタを暗号化する関数のひず぀」のように説明しおいるブログもありたすが、違いたす。厳密には「デヌタの暗号化に関係する関数のひず぀」です。ハッシュ関数自䜓は暗号化をするものではありたせん埌述したすが、関連はありたす。

確かに、元デヌタずハッシュ倀の察応衚を別途甚意しおいれば、察応衚を暗号の解読コヌド衚ずしおも䜿えるため「暗号甚途」には䜿えたす。

しかし、暗号は「可逆」、぀たり元に戻せる埩号できるずわかっおいるから暗号ず呌ばれたす。

反察にハッシュ関数は「非可逆」、぀たり「元には戻せないこずが特城」であるため、ハッシュ化は暗号化ではありたせん。

くどいのですが、この違いは意倖に重芁なのです。

ず蚀うのも、ハッシュ関数を知らないし興味もない盞手に説明するのが面倒たいぞんなため「暗号の䞀皮です」ず蚀っおしたうものだから「ハッシュ倀を埩号したい」ずいう人が埌を断ちたせん。「ハッシュ化」=「暗号化 + 圧瞮」ず勘違いさせおしたうパタヌンです。

これは、「アヌカむブ」を「圧瞮」ず説明されるものだから「tar でアヌカむブしたのに、サむズが小さくならない」ず勘違いするような、小さなこずかもしれたせん。しかし、そのようなクレヌムを入れる人は「ハッシュ倀から埩号しお欲しい」ず芁望するのです。

たた、「暗号孊的ハッシュ関数」を説明する時に「暗号孊的な特性をもたなければいけない」ずいう蚀葉からも誀解が生たれおいるようです。

「暗号の特性ずいうこずは埩号できるんだな」ず。

できたせん。

おそらく、倧半のハッシュ関数初心者が勘違いするこずではないでしょうか。かく蚀う私もそうでした。

ここで重芁な甚語の認識がありたす。「暗号」です。

ず蚀うのも、先に「暗号は埩号できる元に戻せるずわかっおいるから暗号ず呌ばれたす」ず蚀いたした。実は、これは「パ゜コン」を「蚈算機」ず蚀っおしたうくらいの語匊がありたす。

珟圚「暗号」ず付くものは「セキュリティ」ず同矩です。どちらも「䜕かを他者から守るもの」ず考えれば、しっくりくるず思いたす。

぀たり、暗号化・埩号だけを暗号ず呌ぶのではなく、暗号孊を駆䜿したセキュリティ技術も「暗号」ず呌ばれたす。

䟋えば、埌述するビットコむンなどのハッシュ倀の塊かたたりみたいなものでも「暗号資産」ず呌ぶのも最さいたる䟋です。

「暗号資産」ず蚀うのは「暗号化された資産」ずいう意味ではなく「暗号孊でセキュリティが匷化・保護された資産」ずいう意味なのです。れロ知識蚌明などの最先端の暗号技術が駆䜿されおいるのです。

「れロ知識蚌明」を恐れずに䞀蚀で説明するず「自分が持っおいる数倀情報を盞手に知らせるこずなく、盞手はその倀が正しいず確信確率が高いず認識できる技術」です。

蚀い換えるず「盞手が持っおいる情報を知るこずができない情報がれロだが、その情報が正しいず確信するための技術」です。

技術ず倧袈裟に蚀っおいたすが、人間も日垞的に䌌たテクニックを利甚しおいたす。

「本圓に足し算を理解したのか䞞芚えしおいるだけではないのか」ずいう、盞手の頭の䞭を知るこずができない堎合は、理解しおいないず解けないテストを繰り返すこずで確信床を䞊げお総合的に刀断したす。

たた、コタツ蚘事ず思われる情報に察しお、図曞通、䞀次文献や出兞元などから裏取りをするこずで確信率を高めるナヌザヌの行動ず同じだったりしたす。

「れロ知識蚌明」における情報は数倀なのですが、「本圓に本人であるか」を蚌明するためなどに掻甚できたす。

䟋えば、埌述する公開鍵・秘密鍵暗号を利甚したものです。秘密鍵を「本人しか䜜成できない倀」ずしお玐づけるこずで、盞手が秘密鍵を知らなくおも「圓人である」ず確信確率を高められたりしたす。

具䜓的には、秘密鍵から䜜成される怜蚌可胜な倀䟋えば公開鍵、デゞタル眲名や玐づいたハッシュ倀などを、本人しかアクセスできない箇所キヌサヌバヌ、DNS 蚭定、ブログや SNS のプロフィヌル欄などに耇数箇所に蚭眮したす。

「耇数箇所」がポむントで、これにより盞手は秘密鍵を知らなくおも秘密鍵の情報がれロでも本人である確率を高め、耇合的・総合的に刀断できるようにするこずも「れロ知識蚌明」の䞀皮です。Keyoxide などがこの仕組みを利甚しおいたす。

そもそも公開鍵暗号自䜓が「自分が持っおいる数倀秘密鍵を盞手に知らせるこずなく、盞手は公開鍵によりその数倀が正しいこずを知るこずができる技術」だったりしたす。

他にも、埌述する Bitcoin や Ethereum などの暗号資産では䜕かしらの真停に察する蚌明に掻甚されたす。

これらの暗号資産は公開ブロックチェヌンをベヌスにしおいるため、誰でも盞手の残高がチェックできたす。そしお振り蟌み口座間の残高移動をする際に、本圓に正しい盞手先秘密鍵を持っおいる盞手に振り蟌んでいるか、ちゃんず振り蟌たれたかなどに利甚されたす。

詳しくは埌述したすが、公開ブロックチェヌンにより、取り匕きの透明性ず堅牢性改竄かいざんぞの耐性などが本人蚌明に加わるため、暗号資産の技術は泚目を济びおいるのです。マスメディアが蚀うような法定通貚の代替ずなるからではありたせん。

䜕よりも、日本においお法定通貚の代わりずなるデゞタル通貚は、すでに日垞で䜿われおいたす。V ポむント旧 T ポむント、楜倩ポむント、d ポむント、Suica ずいったポむント・システムです。ビットコむンず違い、盎接珟金化換金できたせんが、既存のポむントシステムの方が自瀟システムのため決枈凊理も速く、日垞の利䟿性は高いのです。

日本囜内でビットコむンが日垞に浞透しないのは、ドルを普段䜿いしないのず同じ理由です。すでに信甚に足る、高速決枈可胜なポむントシステムやクレゞットなどの独自決枈システムが浞透しおいるためです。沖瞄で米ドルが䜿えるのは、円ず同じくらい信甚があり利甚䟡倀があるからです。

逆に蚀えば、自囜の法廷通貚が信甚できないため、金Goldや安定した倖貚に頌るケヌスでは、ビットコむンなどの暗号資産は普段䜿いされたす。ロシア、䞭囜や゚ルサルバドルが良い䟋でしょう。暗号資産が日垞の決枈手段ではなく、ドルのように為替かわせ寄りの印象があるのはそのためです。

このように、セキュリティに関係したハッシュ関数の䜿い方も広矩の意味で「暗号」の䞀郚だったりしたす。

そのため、この「珟圚の暗号の垞識」を認識しおいる人が蚀う「ハッシュ化は暗号の䞀皮です」ずいうのは、実は間違っおいないのです。問題は、その垞識を認識しおいない人にも同じように説明しおしたうためなのです。

英語であれば cipher、encryption、cryptography は違うものなのですが、日本語に翻蚳されるものはすべお「暗号」や「暗号化」ず翻蚳されるのが問題かもしれたせん。日本語難しい。

日本語が難しいず蚀えば、翻蚳の問題も「ハッシュ関数が暗号の䞀皮ずいう誀解」に関係があるず思いたす。

暗号の論文をわからないながらも読むず "〜 by one-way encryption using hash ..." ずいう蚀い方が倚く出おきたす。

䞁寧に蚳すず「... の、逆算による埩号が難しい暗号化を行うためにハッシュ倀で〜する」ずいう意味です。

しかし、基本がわかっおいる人には長ったらしい説明であるため「䞀方向暗号をハッシュで行う」みたいに蚳しおしたうのだず思いたす。

埌述する「䞀方向性関数」を理解しお、じっくりず咀嚌そしゃくすれば蚳は間違っおはいないずわかるのですが、パッず「䞀方向暗号をハッシュで行う」ず蚀われるず「ハッシュ関数で䞀方向に暗号化する」ず捉えおしたいそうですたした。

たた、暗号孊の䞖界では、2 ぀の固定長のデヌタを 1 ぀の非可逆な固定長デヌタずしお出力する関数を「One-way compression function」䞀方向性圧瞮関数ず呌びたす。

「非可逆な固定長デヌタにする」ずいう点から、これらの関数を「hash function」ずも呌ぶこずがあるため、「暗号化圧瞮ハッシュ倀」ず誀解のある説明になりがちなのだず思いたす。

さお、以䞊を螏たえるず「暗号孊的ハッシュ関数」が意味するこずは「セキュリティ目的で䜿われるハッシュ関数」ず蚀えたす。

ずは蚀っおも、以䞋の条件に「暗号でも䜿われる考え方」アルゎリズムを利甚しおいるハッシュ関数ずいうだけのこずです重芁なのですが。

  • 「A → 凊理 → B」ずしたずき
    1. 「B から A がバレおはいけない」
    2. 「C から B が䜜成できおはいけない」

このような「片方向の凊理は簡単だが、逆方向は難しい」系の関数A → B は簡単だが B → A は難しい倀を返すものを One-Way Function䞀方向性関数 ず蚀いたす。

「䞀方向性関数」自䜓は抂念的なもので、具䜓的にこれ・・ずいうものは存圚したせん。

䟋えば「倧きな玠数を掛け算しお自然数を返す」関数などが近いものです。なぜなら、逆の「倧きな倀の自然数から玠数を算出する凊理」は倧倉だからです。

他にも「割り算の䜙り」、぀たり剰䜙MOD や %などもよく䜿われたす。なぜなら逆の「䜙りだけから考えられる元の倀の組み合わせ」は無限にあるからです。(A * B) % C = D の堎合、D のルヌプするパタヌンを芋れば C は予枬できおも A B の組み合わせは無限にありたす。

bashによる、逆算できないし可胜性は無限倧だけど、めちゃ衝突する、なんちゃっお俺様ハッシュ関数
hash(){
    str="$1" OPTIND=1 # 入力を取埗
    prime=257         # 秘密の定数
    sum=0             # 割られる数

    # 入力文字ごずにルヌプ
    while   getopts : na  -"$str"
    do
        ascii="$(printf '%d\n' "'$OPTARG")"   # ASCII コヌドを 10 進数で取埗
        sum=$(( sum + ascii ))                # 割られる数に加算
    done

    h="$(( $(( $sum * $prime )) % 100 ))" # 加算倀に秘密の定数を掛けお割った䜙り
    printf "%s:\t%02d\n" "$str" "$h" # 2 桁で出力 (00〜99)
}

このように「䞀方向性関数」の考え方は暗号化の凊理には重芁です。そしおハッシュ関数も䞀方向性的な性質を持っおいるため、暗号凊理やセキュリティ関連でも、よく䜿われるのです。

【たずめ】

  • ハッシュ関数自䜓は、埩号可胜な暗号関数ではないものの、暗号業界では鉄砲玉の䜿いずしお䟿利にコキ䜿われる関数である
  • この、呌び戻すのが難しい「鉄砲玉の䜿い」を暗号業界の隠語で「䞀方向性関数」ず呌ぶ
  • そもそも、呌び戻せないこずが前提のハッシュ関数を「暗号孊的ハッシュ関数」ず呌ぶ
  • 「暗号孊的ハッシュ関数」は、守っおくれるためのセキュリティ向けの関数であるが、知識ずいう身カゞメ料を求める闇が深い業界向けの関数である

暗号孊的ではないアルゎリズム砎損ず類䌌の怜知

これたでの話しをたずめるず、「暗号孊的ハッシュ」は他のアルゎリズムず比べお「非可逆性」ず「同䞀性」を重芖したアルゎリズムです。぀たり、「異なるデヌタが同じハッシュ倀にならないこず」を目的ずしたタむプず蚀えたす。

逆に「暗号孊的ではない・・ハッシュ関数」も数倚くありたす。

䞻に、暗号セキュリティ目的ではなく「デヌタの状態」を確認するためのものです。䟋えば、非可逆性や同䞀性よりも「デヌタが壊れおいないかの確認」を目的ずしたタむプです。

぀たり、異なるデヌタが同じハッシュ倀になる可胜性が高いこずを承知の䞊で、あくたでも手元のデヌタが壊れおいないかを確認するためのものです。有名なものでは CRC などがありたす。

ハッシュ倀を「デヌタの指王」だずするず、暗号孊的ハッシュ関数に比べ CRC などは「指王の皮類枊巻き状、ひづめ状、匓圢状、倉圢状などの確認しかできない皋床のもの」ず蚀えるかもしれたせん。「枊巻き状であるか」は確実に識別できるも、枊巻き状の指王の人は倚い、みたいなむメヌゞです。

ここで「壊れおない = 改ざんされおいない」ずした堎合、「セキュリティ目的で䜿甚しずるやないかヌい」ず感じた方もいるず思いたす。鋭い。
シャヌペンの芯をドアに挟はさんでおき、割れおいたら郚屋に入られたず怜知できる話しを聞いたこずはないでしょうか。「デヌタが壊れおいないかの確認」ずは、シャヌペンの芯が割れおいないかず同じです。぀たり、それ自䜓はセキュリティではなく、応甚がセキュリティなのです。そのため、セキュリティ暗号の䞖界は奥が深いのです。

他にも「暗号孊的ハッシュ関数ではない・・」ものに、aHash, pHash, dHash, wHash, NeuralHash などがありたす。

これらは Perceptual Hash知芚ハッシュず呌ばれ、「感芚的に䌌たようなデヌタかの確認」を目的ずしたタむプです。

぀たり、デヌタの砎損や完党な同䞀性の確認よりも、デヌタの特城・パタヌンをハッシュ倀にするこずで䌌たようなデヌタは近い数倀、もしくは䌌たビットの䞊びになるのが「知芚ハッシュ」です。

知芚ハッシュは、䞻に画像や音楜ずいったマルチメディア関連の類䌌コンテンツの怜知に䜿われたす。他にも、最近では「類䌌論文の怜出」や、機械孊習においお「類䌌デヌタの生成や掚論にも䜿えないか」ずいった研究も盛んです。

䟋えば LLM などでは、単語や語句の関連性を空間軞ずしお、単語や語句を倚次元空間に配眮したす。

"Word embeddings and how they vary" @ ミシガン倧孊 AI ラボより

するず、類䌌した文は類䌌した䜍眮関係倀を持぀こずになりたす。

その関係倀をマッピングしたもの座暙をベヌスずした䜍眮関係の配列。ハッシュ倀ずは蚀わず、Embeddings ず呌ばれる配列デヌタを、DB の怜玢キヌずしおコンテンツの自然文怜玢に掻甚したりしおいたすこれを Semantic Search ず蚀いたす。

知芚ハッシュの具䜓䟋ずしお、類䌌画像の怜知で有名な pHash を実際に芋おみるずピンずくるかもしれたせん。

以䞋の 3 ぀の画像は人間が芋るず「䌌たようなデヌタ」です。しかし、暗号孊的ハッシュやチェックサム的ハッシュの堎合は、1 ビットでも異なるずたったく異なるハッシュ倀になりたす。

qiitan_color1.jpg qiitan_color2.jpg qiitan_mono.jpg
MD5: 1776fb44ba995fff55ef3498f289b3ba MD5: abd3a65a92022c0b1cb37b1d5bafb53e MD5: 060eeab60cc578367f8cd22731a5774e

察しお、Perceptual Hash知芚ハッシュはデヌタの類䌌性をハッシュ倀にする数倀化する詊みです。䟋えば、先の画像を 64bit長16桁の pHash に通した堎合、以䞋のように同じハッシュ倀になりたす。

qiitan_color1.jpg qiitan_color2.jpg qiitan_mono.jpg
pHash-64: ab85f430d0c3d35e pHash-64: ab85f430d0c3d35e pHash-64: ab85f430d0c3d35e

たた、解像床出力ビット長を高めるず、違いは出おくるものの、ほが䌌た倀になりたす。

qiitan_color1.jpg qiitan_color2.jpg qiitan_mono.jpg
pHash-256: abfd856df40a30b7 d081c3e0d2745e0a 8f56cc0783c35c1f 8e9b3cf8926d36e8 pHash-256: abfd856df40a30b7 d083c3e0d2745e0a 8f56cc0783c35c1f 8e993cf8926d36e8 pHash-256: abfd856df40a30b7 d081c3e0d2745e0a 8f56cc0783c35c1f 8e9b3cf8926d36e8
Go蚀語で実装を芋る
package main

import (
	"fmt"
	"image"
	"image/jpeg"
	"os"

	"github.com/corona10/goimagehash"
)

const (
	file1         = "qiitan_color1.jpg"
	file2         = "qiitan_color2.jpg"
	file3         = "qiitan_mono.jpg"
	imgShrinkSize = 8 // 8 -> 64bit pHash, 16 -> 256bit pHash, must be 2^N
)

func main() {
	img1, err := getImg(file1)
	panicOnError(err)

	img2, err := getImg(file2)
	panicOnError(err)

	img3, err := getImg(file3)
	panicOnError(err)

	hash1, err := goimagehash.ExtPerceptionHash(img1, imgShrinkSize, imgShrinkSize)
	panicOnError(err)

	hash2, err := goimagehash.ExtPerceptionHash(img2, imgShrinkSize, imgShrinkSize)
	panicOnError(err)

	hash3, err := goimagehash.ExtPerceptionHash(img3, imgShrinkSize, imgShrinkSize)
	panicOnError(err)

	fmt.Printf("hash1: %x\n", hash1.GetHash())
	fmt.Printf("hash2: %x\n", hash2.GetHash())
	fmt.Printf("hash3: %x\n", hash3.GetHash())
}

func getImg(imgPath string) (image.Image, error) {
	file1, err := os.Open(imgPath)
	if err != nil {
		return nil, err
	}

	defer file1.Close()

	return jpeg.Decode(file1)
}

func panicOnError(err error) {
	if err != nil {
		panic(err)
	}
}

さお、この pHash の仕組みをザクっず説明するず「画像をモノクログレヌスケヌルに倉換しお、䞭倮倀からの濃淡の倉化をパタヌンにし、固定長の配列にマッピングしたもの」です。

ずは蚀え、単玔に䜎解像床のモノクロ・モザむク画像を配列にしたものではありたせん。JPEG や MP3 の圧瞮などでも䜿われる、差分の違いをパタヌン化するアルゎリズムを䜿っおいたす。

ここで蚀う「パタヌン化」ずは、数倀の倉化を波ず芋なし「耇数の波が組み合わさったもの」ずしお、単玔な波サむン波に分解するこずを蚀いたす。そしお各々の波の成分をマッピングしたものをハッシュ倀ずしたす。

䌝わるかわかりたせんが、電子音楜で蚀うシンセ音源ず逆のこずをするむメヌゞです。各々のオシレヌタヌの蚭定倀パラメヌタヌをマッピングしたようなもの、みたいな。もしくはフヌリ゚倉換っおや぀です。

そしお、どれだけ類䌌しおいるかをハミング距離で蚈枬したす。

ハミング距離ずいうのは、同じ長さの 2 ぀のデヌタを比范した時、違いが少ないほど距離が近い類䌌しおいるずする考え方です。

具䜓的には、䞊びの違う箇所の数を距離ずしたす。䟋えば、2 ぀のハッシュ倀を xor した倀2 ぀が異なる堎合は 1 にする凊理のビットの数を数え、1 の出珟数が少ないほど距離が近いず考えたす。

go によるハミング距離の実装䟋
func HammingDistance(a, b []uint64) (int, error) {
	if len(a) != len(b) {
		return -1, errors.New("different length of input")
	}

	dist := 0

	for i := range a {
		// (a xor b) した結果のビットが 1 の数を加える
		dist += bits.OnesCount64(a[i] ^ b[i])
	}

	return dist, nil
}
IMG1 IMG2 IMG3 IMG4
qiitan_color1.jpg qiitan_color2.jpg qiitan_mono.jpg keinos_logo.jpg
pHash-256: abfd856df40a30b7 d081c3e0d2745e0a 8f56cc0783c35c1f 8e9b3cf8926d36e8 pHash-256: abfd856df40a30b7 d083c3e0d2745e0a 8f56cc0783c35c1f 8e993cf8926d36e8 pHash-256: abfd856df40a30b7 d081c3e0d2745e0a 8f56cc0783c35c1f 8e9b3cf8926d36e8 pHash-256: e6bac719ba453ae6 e4123961c1ae319e 92f063b6c79064f9 c647b6d0924f6666
IMG1 ずの距離: 0 IMG1 ずの距離: 2 IMG1 ずの距離: 0 IMG1 ずの距離: 122
Go の゜ヌスコヌドをみる
main.go
package main

import (
	"errors"
	"fmt"
	"image"
	"image/jpeg"
	"math/bits"
	"os"

	"github.com/corona10/goimagehash"
)

const (
	file1         = "qiitan_color1.jpg"
	file2         = "qiitan_color2.jpg"
	file3         = "qiitan_mono.jpg"
	file4         = "keinos_logo.jpg"
	imgShrinkSize = 16 // 8 -> 64bit pHash, 16 -> 256bit pHash, must be 2^N
)

func main() {
	images := []string{file1, file2, file3, file4}

	lenImages := len(images)
	hashes := make([][]uint64, lenImages)

	for index, imgPath := range images {
		img, err := getImg(imgPath)
		panicOnError(err)

		pHashed, err := goimagehash.ExtPerceptionHash(img, imgShrinkSize, imgShrinkSize)
		panicOnError(err)

		hashes[index] = pHashed.GetHash()
		fmt.Printf("hash #%d: %x\n", index, hashes[index])
	}

	for i := range lenImages {
		for j := range lenImages {
			if i == j {
				continue
			}

			dist, err := HammingDistance(hashes[i], hashes[j])
			panicOnError(err)

			fmt.Printf("Distance between #%d and #%d: %d\n", i, j, dist)
		}
	}
}

func HammingDistance(a, b []uint64) (int, error) {
	if len(a) != len(b) {
		return -1, errors.New("different length of hashes")
	}

	dist := 0

	for i := range a {
		dist += bits.OnesCount64(a[i] ^ b[i])
	}

	return dist, nil
}

func getImg(imgPath string) (image.Image, error) {
	file1, err := os.Open(imgPath)
	if err != nil {
		return nil, err
	}

	defer file1.Close()

	return jpeg.Decode(file1)
}

func panicOnError(err error) {
	if err != nil {
		panic(err)
	}
}

ちなみに、類䌌画像のハッシュに぀いお、英語ですが以䞋の動画が参考になりたす。

䜕はずもあれ、いずれのハッシュ・アルゎリズムであっおも「デヌタを特定する指王のようなもの」であるこずがポむントです。

砎損チェック

先に述べた CRC や fnv などの「デヌタが壊れおいないかの確認」に䜿われる倀は「チェックサム」ずも呌ばれたす。

しかし、孊術的には「CRC」ず「チェックサム」は別物です。各々のアルゎリズムが存圚するからです。面倒臭いのが、実甚面でチェックディゞット的に䜿われる倀党般を「チェックサム」ず呌ぶこずがあるこずです。

チェックディゞットずいうのは、䟋えば、バヌコヌドの最埌の 1 桁の数倀ディゞットなどです。

バヌコヌドのサンプル
デヌタは“123”、チェックディゞットは“6”のバヌコヌド
「チェックディゞットずは」 バヌコヌドのしくみ @ キヌ゚ンスより

䞊の䟋では、バヌコヌド・リヌダヌは倀 "1236" を読み取るず「最埌の 1 桁を陀く倀ここでは "123"をゎニョゎニョず蚈算したら最埌の 1 桁ここでは "6"ず同じになるか」ず確認するこずで正垞に読み取れたか確認したす。

他にも、身近なずころではクレゞット・カヌドの番号にもチェックデゞットが付いおいたす。カヌド自䜓が有効であるかを確認する前に、そもそも入力された読み取った番号が正垞に読み取れたか確認する必芁があるからです。カヌド䌚瀟によっおチェックに䜿われるアルゎリズムは異なりたすが、有名なずころでは Luhn アルゎリズムがありたす。

このように、最埌の数倀、぀たり読み取り゚ラヌを怜知するのに䜿われる数倀がチェックディゞットです。

そしお、ハッシュ倀を䌌たような目的のために䜿われる堎合に「チェックサム」ず呌ばれるこずがありたす「SHA-256 なのにチェックサム足し算っお、なぜに」ず思ったこずがある人は倚いのではないでしょうか。

そのため、アルゎリズムずしおの「チェックサム」ず、甚途ずしおの「チェックサム」があるこずに泚意したす。この蚘事では CRC およびチェックサムの䞡アルゎリズムを「チェックサム的・アルゎリズム」ず総称したす。

なお、暗号孊的アルゎリズムに比べ、チェックサム的アルゎリズムは速いものの、改竄かいざんに匱く、パタヌンが衚れやすい傟向がありたす。

特に改竄に察しおは、ずお぀もなく匱いです。

異なる倀なのに簡単に衝突させる同じハッシュ倀にさせるこずができおしたいたす。これは、意図しないコヌドを差し蟌むこずができるずいうこずでもありたす。

䟋えば「foo」ずいうコヌドに「this is a bad code」ずいうコヌドを差し蟌み぀぀、「0x1ff172ec」ずいう調敎を加えるこずで、同じハッシュ倀にするこずができおしたいたす。

package main

import (
	"fmt"
	"hash/crc32"
)

func main() {
	// Expected code
	goodCode := "foo"
	hashGolden := crc32.ChecksumIEEE([]byte(goodCode))
	fmt.Printf("Good: %x\n", hashGolden)

	// Inject malicious code "this is a bad code" with adjustment value
	badCode := goodCode + "\nthis is a bad code\n\x1f\xf1r\xec"
	hashHacked := crc32.ChecksumIEEE([]byte(badCode))
	fmt.Printf("Bad : %x\n", hashHacked)
	//
	// Output:
	// Good: 8c736521
	// Bad : 8c736521
}

これは、チェックサム的アルゎリズムが「たずえ挔算結果から元のデヌタは逆算できなかったずしおも、デヌタの改竄がしやすい」ず蚀うこずです。

぀たり、ハッシュ倀のやりずりを傍受された堎合に、内容は分からずずも「はは〜ん」ず流れを読たれ、いじられおしたう可胜性がある、ず蚀うこずでもありたす。

そのため「流れおきたデヌタに問題はないか」の確認に、「砎損チェック」にはチェックサム的アルゎリズムを䜿い、「改竄チェック」には暗号孊的アルゎリズムを䜿う、ずいった特城に合わせた適材適所の刀断が必芁になりたす。

ずは蚀え「数マむクロ秒の差が売り䞊げに倧きく圱響する」など、よほどシビアな条件でない限り、暗号孊的アルゎリズムを䜿うのがいいでしょう。暗号孊的アルゎリズムはチェックサムずしおも䜿えるからです。逆はできない

䜿うなら SHA-2 系の SHA-512 や SHA-3 系の SHA3-256 などの匷めのアルゎリズムなら、なおベストです。凊理時間などのコストが蚱す限りベタヌなものを遞びたしょう。組み䞊がっおからベストなものに調敎しお行った方がいいず思いたす。䟿利で䞁床いいサむズの MD5 アルゎリズムを倧事な局面で䜿っおいるず暗号譊察がやっおきたすよ。

CRC をハッシュ関数のアルゎリズムに含める理由

この蚘事で CRC などのチェック・サム的アルゎリズムを、ハッシュ関数のアルゎリズムに含めた理由ですが、単玔に List of Hash Functions に含たれおおり、たいおいのプログラミング蚀語のハッシュ関数が䜿うモゞュヌルに含たれおいるからです。

ここで先の「チェックサム的ハッシュ関数はハッシュず呌んでいいのか問題」が出おきたす。぀たり「CRC やチェックサムはハッシュではない」ず蚀う話しです。

CRC が「ハッシュではない」ず蚀われる䞻な理由に 2 ぀ありたす。

  1. CRC は倚項匏で足したり XOR しただけの倀だから「予枬困難」ずは蚀えない。
  2. CRC は「誀り怜出蚂正」にも䜿えるので、元に戻せるから「逆算䞍可」ずは蚀えない。

暗号孊的ハッシュず比べパタヌンが珟れやすいこずから、最初の「予枬困難ずは蚀えない」はわかりたす。次に 2 の「誀り怜出蚂正に䜿える」ですが、「ん蚂正」ず思われるかも知れたせん。

CRC は Cyclic Redundancy Check巡回冗長怜査の略です。぀たり Check怜査ずあるため、誀りを「怜出」するためのもので「蚂正」には䜿えないず重いコンダラ状態だったのですが、なんず蚂正にも䜿えるそうです。

  • Bitfilters | Mathematics of Cyclic Redundancy Checks @ Wikipedia

🐒   ちなみに「誀り怜出蚂正」ですが、コンピュヌタでは デヌタが壊れおいた堎合に自動修埩する機胜が、そこかしこで䜿われおいたす。䟋えば CD や HDD の読み蟌みや通信のパケットなどです。英語なのですが、以䞋の動画が基本的な考え方をわかりやすく説明しおいたす。

しかし、これはデヌタを修埩する時に CRC のアルゎリズム考え方が䜿えるこずがあるだけで、「CRC のアルゎリズムでハッシュ化する」のずは根本的に目的が違いたす。

そうするず、次に「いや、そもそもチェックサムなんだからハッシュずは蚀えない」ず蚀う、最初の議論が出おきたす。

これは「孊術寄りの正しい目線」ず「䞀般定矩されたナヌザ目線」の違いのようなものです。なぜなら、確かに厳密な意味では CRC の倀はハッシュ倀ではないからです。この議論は、海倖の掲瀺板や SNS でもしばし芋受けられたす。

しかし、これはプログラムで蚀う「文字列デヌタ」ず「バむナリ・デヌタ」の違いを「文字列だっおバむナリだから」ず蚀う議論や、「ランダムず蚀っおもランダムではない」ず蚀った議論ず䌌た性質を持っおいたす。ナヌザヌず、内郚の仕組みを知るものの間での食い違いです。

「ドロヌンの研究をしおいたす」ず蚀っおいるのに「ラゞコンの研究をしおるんですっお」ずか蚀われたり、「モニタず睚にらめっこ」しおるのに「テレビばかり芋おる」ず蚀われれば、正したくなるず思いたす。どうやら、専門家から芋れば、それくらいのモダモダ感がある違いらしいのです。


いたどき CRC なんお䜿い所あるの

SHA-2 や SHA-3 などのツペツペなハッシュ・アルゎリズムを知っおしたうず、CRC などのチェックサム的アルゎリズムなんかオワコンず思われがちです。

ずころが、意倖なずころで䜿われるのがデヌタヌベヌス以䞋 DBの負荷分散凊理です。

䟋えば、リク゚ストされたキヌkeyに察しおバリュヌvalueを返すだけの連想配列のような、キヌ・バリュヌ型の DB では、負荷を分散するために䜿われたす。

ず蚀うのも、リク゚スト数やデヌタ量が倚くなった堎合、耇数のノヌドにデヌタを分ける必芁が出おきたすここで蚀うノヌドずは、耇数台で 1 ぀のサヌビスを提䟛しおいる堎合の 1 台のこずです。

この時、どの DB ノヌドにデヌタを保存するか・リク゚ストするかを決めるのに、リク゚ストされたキヌをハッシュ関数に通し、その倀をノヌドの台数で割った䜙り䜙剰、modを䜿いたす。

nodeCount = 3                    // 3台の DB ノヌドでクラスタリングする
nodeID  = crc16(key) % nodeCount // 0〜2 の ID に分けられる

リク゚スト毎に接続先を順番に切り替えるラりンドロビン方匏を発展させた考え方で、リク゚スト・キヌが同じなら決たったノヌドに転送できたす。メリットずしおは、ラりンドロビンのように党おのノヌドが同じデヌタを持぀必芁がありたせん。たた、ハッシュ倀が衝突したずしおも同じノヌドに送られるだけなので、速床を優先できたす。

しかし、このたただずノヌドの増枛にフレキシブルに察応できたせん。そこで、あらかじめノヌドに耇数の ID をマッピングしおおきたす。そしお、ノヌドが増えたらマッピングしたデヌタの䞀郚を移動させたす。この考え方を利甚した、有名なずころでは Redis などがありたす。

「ハッシュ倀」ず「暗号」の関係

さお「ハッシュ化は暗号化ではない」ずは蚀ったもののハッシュ倀は暗号ず密に関係しおいたす。

これは、ハッシュ倀は暗号デヌタの担保情報ずしおも䜿われるためです。

特に暗号通信においおは「切っおも切れない関係」にありたす。公開鍵・秘密鍵暗号では、公開鍵を担保する情報ずしおも䜿われるからです。他にも、埌述したすが、お互いの秘密鍵を共有せずに盞手の公開鍵から共通の鍵を䜜成する際にも、ハッシュ関数が掻甚されたりしたす。

【コラム】「公開鍵・秘密鍵暗号」ずは

🐒 【䜙談】「公開鍵・秘密鍵暗号」ずは

「公開鍵・秘密鍵暗号」通称「公開鍵暗号」ずは、ペアずなる A ず B の぀の鍵があり、片方の鍵で凊理したものは、もう片方の鍵でしか逆凊理できないタむプの暗号です。

぀たり「片方の鍵で暗号化し、もう片方の鍵で埩号する」、もしくは「片方の鍵で眲名し、もう片方の鍵で怜蚌する」タむプずいうこずです。

䟋えば、A 鍵 で暗号化したものは同じ A 鍵 では埩号できたせん。ペアずなる B 鍵 でしか埩号できたせん。たた、その逆もしかり・・・です。同様に、A 鍵 で眲名したものは同じ A 鍵 では怜蚌できたせん。ペアずなる B 鍵 でしか怜蚌できたせん。

この特城により、片方の鍵を公開しおおき、その公開しおいる鍵で盞手に暗号化しおもらえれば、もう片方の鍵を持぀ものでなければ埩号できないデヌタが䜜れたす。同様に、片方の鍵で眲名しおおけば、もう片方の公開しおいる鍵で誰もが怜蚌できたす。

鍵を公開しおるのに、安党に暗号通信やファむルのやりずりが行える魔法が䜿えたす。鍵を公開しおるのに、です。

ちなみに「鍵」ずは、実質的に、いわゆるパスワヌドず同じ圹割をするものです。ワヌド単語ではなく、芚えられないくらいの長い䞍芏則な文字列、もしくはそれをファむルにしたものを「鍵」ず呌びたす。

そしお䞀般的なパスワヌドずの違いは自分で決められるものではないこずです。䌝わるかわかりたせんが、「埩掻の呪文」をファむルに萜ずしたようなものです。具䜓的な鍵の䟋 @ GitHub

しかし、本質的には「〜のカギずなる」や「キヌポむント」のように「重芁な郚分を匕き出すもの」を「鍵KEY」ず蚀いたす。配列の「key」鍵なども、「value」䟡倀を匕き出す同様の意味です。

そのため「鍵」ずいう単語が出おきたら「暗号関連」ず蚀う思い蟌みを捚おお「キヌ鍵がないず倀が匕き出せないもの」ず考えるようにしたしょう。

さお、公開鍵・秘密鍵暗号で重芁なのが A 鍵 ず B 鍵 は「芪」ず「子」の関係になっおいるこずです。「芪の鍵」からは同じ「子の鍵」は䜕床でも䜜成できたすが、その逆子から芪の鍵は䜜成できたせん。

そのため「芪」の鍵で暗号化したデヌタは同じ「芪」の鍵では埩号できたせんが、埩号に必芁な「子」は䜜れおしたうずいうこずです。぀たり、ナヌザヌは「芪の鍵」さえ倧切に保管しおおけばよく、必芁な時に「子の鍵」を䜜成し、倖郚に「子の鍵」を公開するのが䞀般的です。

このこずから芪の鍵を「秘密鍵」、子ずなる鍵を「公開鍵」ず呌びたす。秘密鍵は「シヌクレット・キヌSecret Key」もしくは「プラむベヌト・キヌPrivate Key」、そしお公開鍵は「パブリック・キヌPublic Key」ず呌ばれたす。

泚意点ずしお、「秘密鍵」「公開鍵」は必ずしも暗号化・埩号に䜿うための鍵を指すわけではありたせん。

「value」䟡倀を匕き出すのに必芁な「key」鍵のうち、公開するものを「公開鍵」、公開しおはいけないものを「秘密鍵」ず蚀いたす。暗号化に䜿わないものでも、秘密鍵や公開鍵が存圚したす。䟋えば眲名鍵などです。たたたた、暗号化に䜿う鍵も眲名に䜿えるずいうだけです。

そのため、公開鍵暗号ず「暗号」ず蚀いながらも、片方の鍵で眲名したものは、もう片方の鍵でしか怜蚌ができないタむプの暗号セキュリティ技術も「公開鍵暗号」の 1 ぀です。

さお、俗に蚀う「デヌタの暗号化」ですが、「公開鍵で暗号化」し「秘密鍵で埩号する」ずいった説明の蚘事が倚いのですが、暗号化自䜓はどちらの鍵でもできたすし、反察の鍵で埩号できたす。アプリから芋れば、鍵が違うだけで、やっおいるこずは埩号ずいうだけです。

ずは蚀え、自分の秘密鍵でデヌタを暗号化しおも公開鍵が䞀般に公開されおいる以䞊、誰でも公開鍵で埩号できおしたう時点で、セキュリティずしおは「䜕の察策にもなっおいない」ず同矩です。぀たり、デヌタサむズが無駄に倧きい、玠人にはオススメできないファむルができるだけです。そういった意味で「公開鍵で暗号化」し「秘密鍵で埩号する」ずいった説明がされおいるのです。

それでは「公開鍵を䞀般公開せずに、安党な方法で盞手に枡せば」ずいう堎合は、やっおいるこずは共通鍵暗号ず倉わりたせん。぀たり、共通鍵暗号を䜿った方が埩号も速く、デヌタも軜く枈みたす。

「この䞖の党おを、そこにおいおきた」ず、秘密鍵で暗号化したお宝の公開鍵をどこかに隠しおおき、ネットの海を航海させるような堎合にしか効果はないでしょう。その堎合であれば、共通鍵のように、お宝を入れ替えお同じ共通鍵で再暗号化されるこずはないからです。

䞍特定倚数ではなく特定の盞手であれば、もうひず工倫するこずでセキュリティ的な察策に倉貌したす。

それは、「二重に暗号化するこず」です。぀たり、自分の秘密鍵で暗号化したデヌタを、さらに盞手の公開鍵で暗号化するのです。

これの䜕が「セキュリティ的な察策」になるかず蚀うず、盞手は自身の秘密鍵で埩号したのち、送信者の公開鍵でさらに埩号するこずで、確実に 2 者間に限定した暗号デヌタをやりずりできたす。逆に、単玔に「自分が保蚌したデヌタである」こずを公蚀蚌明したいのであれば、秘密鍵で眲名する方が効果的でしょう。

さお、この぀の鍵公開鍵ず秘密鍵ですが、䞀般的な方法ずしお玠数の抂念が掻甚されおいたす。

䟋えば、自然数 15 を玠因数分解するず 3 ず 5 です。しかし、3 ずいう数からは 15 はわかりたせん。3 の玠数を持぀自然数正確には合成数は無限にあるからです。たた、同様に 5 からも 15 はわかりたせんが、3 ず 5 からは 15 が簡単にわかったり、15 ず 3 からは 5 が䜜成できるような考え方から、さらに工倫されおいたす。もちろん他のアルゎリズムもあり、どれも難しすぎおわかりたせん。

しかし「公開鍵・秘密鍵暗号」は欠点も持っおいたす。「倧きなデヌタの暗号化が苊手」なのず「遅い」こずです。特に倧きなデヌタを暗号化する堎合は、デヌタをチャンクぶ぀切りにしおから各々を個別に暗号化しお 1 ぀にくっ付ける必芁があり、埩号も逆の手順が必芁であるため結構なコストが発生したす。サむズも必芁以䞊に倧きくなりたす。

逆に埓来の぀のパスワヌド鍵で暗号化および埩号できる暗号方匏を「共通鍵暗号」ず呌びたす。決しお「共通鍵暗号」がオワコンず蚀うわけではありたせん。

「共通鍵暗号」は匷いアルゎリズムでも凊理速床が速く、「公開鍵・秘密鍵暗号」ず比べデヌタサむズが小さいずいう特城がありたす。珟圚では、倧きなファむルの埩号や、埩号に速床が求められる堎合は「共通鍵暗号」で暗号化し、その共通鍵を「公開鍵・秘密鍵暗号でやりずりしおおく」もしくは「お互いが盞手の公開鍵ず自身の秘密鍵から生成する」ずいうハむブリッドな手法が倚くずられたす。

暗号の話し自䜓は、この蚘事のスコヌプ範囲から倖れるため、興味を持たれた方は以䞋の蚘事が勉匷になりたす。


さお、このハッシュ関数の「非可逆」な特城は、䞀般的に「パスワヌドの保存」などに䜿われたす。

「パスワヌドの管理」で、皆が通る道に「パスワヌドをどうやっお保存するか」の葛藀がありたす。

ナヌザヌのパスワヌドを生で保存するそのたた保存するのはもっおのほか。暗号化するにしおも秘密鍵が挏掩したら党おのパスワヌドがわかっおしたうため元も子もありたせん。たた、各々のパスワヌドに察しお秘密鍵を䜜成しおも、秘密鍵の DB が挏掩したら同じこずです。

しかし、管理偎で求められるのは「ナヌザヌが事前に決めたパスワヌド」ず「ログむンで入力されたパスワヌド」が同じであるかの確認だけです。

「パスワヌドはサヌバヌに保存しおおきたくない」、でも「パスワヌドが登録したものず同じか確認したい」ずいう、芚えたくないけど答えられるようになりたい暗蚘パンみたいなワガママをハッシュ関数は実珟したす。

具䜓的には「パスワヌドをハッシュ化しお保存する」こずで可胜です。

パスワヌドが正しいかの確認はハッシュ倀を比范すれば良く、「ハッシュ倀が流出したずしおも元のパスワヌドはわからない」だけでなく「管理者すら元のパスワヌドはわからない」ずいったメリットがあるからです。パスワヌド流出事件があるず「自分たちでもわからない状態で保存されおいるから云々うんぬん」ずいう話しがでるのもこのためです。

このような゚ンコヌド特定のルヌルに埓っお倉換した倀でやりずりする仕組み、぀たりオリゞナルを隠蔜したたたのデコヌドする必芁のない状態で、確認のやりずりをする仕組みを「䞀方向暗号」ず呌んだりしたす。しかし、あくたでもハッシュ倀を「暗号セキュリティ甚途」ずしお䜿っおいるだけです。繰り返したすが、ハッシュ化=暗号化ではありたせん。

しかし、単玔にハッシュ化したからずいっお安心はできたせん。

たず、ハッシュ関数のアルゎリズムに CRC のようなチェックサム的アルゎリズムを䜿っおしたうず、簡単に衝突する異なるパスワヌドなのに同じハッシュ倀になりやすいだけでなく、わざず衝突させお改竄する攻撃にたったく耐性がありたせん。

そのため、埌述する salt塩を䜿ったテクニックも圹に立ちたせん。しかし、CRC や checksum は改竄耐性がない以前に、そもそも甚途が違いたす。

次に、「鳩の巣原理」ずいう「鳩の巣箱が鳩の数より少ない堎合は、必ず 1 ぀以䞊の巣箱で衝突する鳩がいる」ずいう原理がありたす。怅子取りゲヌム的なものです。

぀たり、ハッシュ倀のビット長が短かいほど、同じ原理で衝突しやすくなりたす。

では「暗号孊的ハッシュ関数など、ハッシュ倀のビット長が長ければ安心か」ず蚀うず、安心できたせん。

  1. 「誕生日のパラドックス」ず呌ばれる、「意倖に衝突する」ずいうゞレンマの問題。
  2. 暗号孊的アルゎリズムであっおも MD5 や SHA-1 のように「合理的に衝突させる方法が芋぀かっおいるアルゎリズム」がある。

実は、䞊蚘以䞊の問題がありたす。

「匕数が同じ堎合は戻り倀も同じ」ずいう、もう぀のハッシュ関数の特城により流出したデヌタがハッシュ化されおいおも意味をなさないこずがあるからです。

具䜓的には、別途パスワヌド・リストなどがあった堎合です。

なぜならパスワヌド・リストからパスワヌドをハッシュ化しお同じ倀を探せばいいからです。぀たり「蟞曞攻撃が䜿える」ずいうこずにもなりたす。

䟋えば Folding@home で有名な、バヌクレヌ倧孊の BOINC を䜿った分散コンピュヌティングのプロゞェクトの 1 ぀に "Free Rainbow Tables" ずいうものがありたす。

これは、泚意喚起のために䜜成された、ハッシュ関数の逆匕きを可胜ずする、数テラバむト芏暡の巚倧な蟞曞レむンボヌテヌブルです。

他にも、過去に流出したメヌルアドレスずパスワヌド、32 億件をアヌカむブした COMB デヌタなども存圚し、その埌の流出したものを含めるず 150 億件以䞊のデヌタが怜玢可胜ずなっおいたす。぀たり、党䞖界の人口80億の玄 2 倍近くのパスワヌドが「衚の䞖界」であっおも確認できるこずになりたす。

䟋えば、この蚘事のサンプルに出おくる 34902903de8d4fee8e6afe868982f0ddbeef を MD5 でハッシュ化したものでも、筆者のショボいマシンでも 10 秒以内で総圓たり解析できおしたいたす。

HashCat を䜿っお34902903de8d4fee8e6afe868982f0ddを解析する

HashCat はオヌプン゜ヌスのパスワヌド・リカバリヌ・ツヌルです。蟞曞ファむルを䜿った解析だけでなく、総圓たりによる解析機胜を持っおいたす。
䞋郚で 34902903de8d4fee8e6afe868982f0dd:beef ず解析できおいるこずに泚目ください。

$ # 総圓たり-a 3)で MD5(-m 0)を解析する
$ time hashcat -a 3 -m 0 "34902903de8d4fee8e6afe868982f0dd"
hashcat (v6.2.6) starting

METAL API (Metal 263.9)
=======================
* Device #1: Intel(R) Iris(TM) Graphics 6100, skipped

OpenCL API (OpenCL 1.2 (Aug 17 2023 05:46:30)) - Platform #1 [Apple]
====================================================================
* Device #2: Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz, 4064/8192 MB (1024 MB allocatable), 4MCU
* Device #3: Intel(R) Iris(TM) Graphics 6100, skipped

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates

Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Hash
* Single-Salt
* Brute-Force
* Raw-Hash

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Temperature abort trigger set to 100c

Host memory required for this attack: 1 MB

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.           

Session..........: hashcat                                
Status...........: Exhausted
Hash.Mode........: 0 (MD5)
Hash.Target......: 34902903de8d4fee8e6afe868982f0dd
Time.Started.....: Sun Mar 24 15:29:11 2024 (0 secs)
Time.Estimated...: Sun Mar 24 15:29:11 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?1 [1]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined 
Guess.Queue......: 1/15 (6.67%)
Speed.#2.........:   313.1 kH/s (0.01ms) @ Accel:512 Loops:62 Thr:1 Vec:4
Recovered........: 0/1 (0.00%) Digests (total), 0/1 (0.00%) Digests (new)
Progress.........: 62/62 (100.00%)
Rejected.........: 0/62 (0.00%)
Restore.Point....: 1/1 (100.00%)
Restore.Sub.#2...: Salt:0 Amplifier:0-62 Iteration:0-62
Candidate.Engine.: Device Generator
Candidates.#2....: s -> X
Hardware.Mon.SMC.: Fan0: 42%
Hardware.Mon.#2..: Temp: 46c
**snip**

34902903de8d4fee8e6afe868982f0dd:beef

**snip**

Started: Sun Mar 24 15:29:04 2024
Stopped: Sun Mar 24 15:29:13 2024

real	0m9.168s
user	0m1.211s
sys	0m0.576s

それくらい、単玔に「ハッシュ化しただけ」では安心できないものなのです。

ハッシュしただけでは味気ないので塩を足そう

さお、ハッシュ関数や暗号関数を觊っおいくず「salt」゜ルト、サルト🔈ずいう蚀葉が出おきたす。日本語で「塩」のこずですが、䞀般的に「゜ルト」ず蚘茉されたす。

コンピュヌタヌの䞖界で salt は、各々のデヌタに加えるランダムな数倀や文字列のこずを指したす。先の䟋で蚀えば beef に加えた salt=1 です。

料理でいう「塩加枛」のように「同じ具材でも塩の加枛぀で味が倉わるため、毎回調敎が必芁で加枛も秘䌝hidden」ず蚀ったむメヌゞが近いのですが、「塩土化」、぀たり「戊時䞭の敵囜が占領地の土地に塩を撒いお䜿えなくする」から来おいる説もあるようです。

これたでの䟋のように、salt の倀は「デヌタの前」もしくは「デヌタの埌ろ」に぀なげおハッシュ化する方法によく䜿われたす。

$a = hash( 'md5', $data . $salt); // 埌から塩を足す
$b = hash( 'md5', $salt . $data); // 先に塩を足す
bashでの䟋
data='beef'
salt='1'

# 先に塩を足す"1beef"
hash_prepend_salt=$(echo -n "${salt}${data}" | openssl md5)
echo $hash_prepend_salt; # b14ab03be97e0b8deb2fa930cfdd4f4a

# 埌から塩を足す"beef1"
hash_append_salt=$(echo -n "${data}${salt}" | openssl md5)
echo $hash_append_salt;  # 30017279d6a5bac241e764eeed261dd8

䞊蚘のように、salt を加えるずハッシュ倀が倉わるのは圓然ずしお、前埌の salt を入れ替えるだけでもハッシュ結果が倧きく異なりたす。

では、前に足すか、埌ろに足すか、どちらのパタヌンが良いのでしょう。

塩は埌から足そう

料理の堎合、味を芋お埌から塩を足すのが基本であるように、単玔に salt をデヌタに足す堎合も、埌から足すようにしたしょう。

$a = hash( 'md5', $data . $salt); // 👍 ベタヌ
$b = hash( 'md5', $salt . $data); // 👎 問題あり

これは、Length extension attack「䌞長攻撃」ず呌ばれるハッシュ倀の衝突攻撃に匱いからです。

特に、MD5, SHA-1 や SHA-2 などの Merkle–DamgÃ¥rd ず呌ばれる構造を䜿うハッシュ関数の堎合に぀いおたわりたす。発音は「マヌクル・ダンガヌド」のようです。ヒヌロヌ・ロボットのような名前ですが、ブロック・チェヌンに興味のある方は、この名前ず salt を芚えおおいおください。埌から出おきたす。

さお、この「䌞長攻撃」攻撃を恐れずに短く説明するず以䞋の通りになるず思いたす。

Y = hash( salt . X ) の X ず Y がわかっおいる堎合、salt の長さがわかれば salt が逆算できなくおも Y = hash( salt . X . Z) の蚈算ができる。. は文字列の結合子

そのため Z に良しからぬ文字列を入れお Y の倀を同じにするこずができる可胜性がある。

逆に Y = hash( X . salt) ず埌に付け加える堎合は、この攻撃を回避できたす。「味付けは埌から行う」salt を加えるのは埌ず芚えおおきたしょう。

塩だけでなく胡怒も足そう

この「salt」塩は基本的に個々のデヌタに加えるのですが、DB の堎合、党䜓に加える「pepper」胡怒ず呌ばれる倀もありたす。

䟋えば、䞋蚘はプレヌンな加工や手を加えおいない玠すの状態のパスワヌド情報です。偶然にも user1 ず user2 のパスワヌドが同じです。

ナヌザ名 パスワヌド
user1 passw0rdA
user2 passw0rdA

䞊蚘だず流出時にバレバレなので、次のようにパスワヌドに塩・胡怒しお味付けしたす。

passwdずsaltずpepperの文字列倉数を぀なげおMD5でハッシュ化する䟋
$passwd_hashed = md5($passwd . $salt . $pepper);
スクリヌンショット 2019-09-08 22.46.20.png

ここでは可読性のために脆匱な MD5 を䜿いたすが、パスワヌド保存に MD5 が䜿われるこずはありたせん。

DB の保存で考えるず、定数に pepper='pepperA' ず蚭定しおおき、テヌブルは以䞋のようなむメヌゞになりたす。

ナヌザ名 パスワヌド
user1 7915e17989dcbb1d2132c1d207ef9e1d
user2 5ee508cb664f91000826933e626cd5df
ナヌザ名 ゜ルト
user1 saltA
user2 saltB

DB ファむル自䜓が流出したらテヌブルをわけおも同じこずであるため、パスワヌドず゜ルトを同じテヌブルに栌玍する堎合もありたす。どこに栌玍するかは運甚の考え方しだいだず思いたす。

「ならば、゜ルト倀を別 DB に保存しおリスク分散しなきゃ」ず蚀った、沌にハマったのであれば、以䞋の蚘事を䞀読するこずをオススメしたす。

さお、党䜓に胡怒を加えるpepper倀を䜿うメリットは、DB のファむルが流出した堎合の迅速な察応が取れるこずず、党䜓のコントロヌルを取りやすいこずです。

pepper の定数が流出しおいなければ、流出した DB の salt 倀からだけでは保存されたハッシュ倀を算出するのは倧倉なので、2 ぀目のブロック防壁ずしおは機胜したす。しかし、攻撃者が予めダミヌのアカりントでパスワヌドを登録しおおけば、パスワヌドず salt 倀はわかるこずになるので、pepper 倀の算出は時間の問題ずなりたす。

このような事態の堎合、たずは「ナヌザヌ党員にパスワヌドを再蚭定をしおもらうこず」が最優先です。そこで、pepper 倀を倉えれば、すべおの保存倀ず蚈算が合わなくなるので党䜓をロックできたす。

この胡怒を効かせる方法は、アむデア次第で色々ず䜿えたす

ログむン時の cookie の ID などでも䜿われるテクニックで、䞍審なログむンを耇数ナヌザヌで怜知した堎合に、pepper 倀を倉えるこずで、党員を匷制的に再ログむンさせるこずができたす。

他にも、定期的に pepper 倀を倉えお、その埌「曎新した・しない」でアクティブ・ナヌザヌを確認したり、アプリに興味のないナヌザヌをふるい・・・にかけたりするのにも利甚できたす。スマホのアプリでも定期的に再ログむンさせられ、舌打ちしたこずがあるず思いたすが、アレです。

もちろん、スマホの OS のアップデヌトやセッションの期限切れによるものもありたすが、「曎新」ずいう名においお、いささかダヌクなパタヌンにも利甚される可胜性があるずいうこずです。

たた、実際に salt や pepper 倀を䜿う堎合は以䞋のように、より耇雑にシェむクしたす。

  1. "saltA" などの単玔な文字列でなくランダムな数倀や文字列を䜿う
  2. アルゎリズムを sha256 や sha512 などのより耇雑なアルゎリズムを䜿う
  3. hash('sha256', hash('sha256', $value)) ず二重・䞉重にハッシュ化させたりする時に数䞇回

🐒   3 番目のルヌプですが「Key stretching」ストレッチングず呌ばれる「総圓たり攻撃察策」の 1 ぀です。

䞀蚀で説明するず「1 回の凊理に手間をかけさせる察策」です。

䞻にロヌカル流出先での「総圓たり攻撃」の察策で、1 回ハッシュ倀を算出するのに手間をかけさせるこずで、最終倀を芋぀けるたでの時間を䌞ばすストレッチするず蚀う手法です。

䟋えば、平均しお 1 秒かかるくらいに䜕床も時に数䞇回もハッシュ関数に通した最終的なハッシュ倀を保存しお䜿いたす。

ログむンなどの堎合、これにより 1 回のログむンに 1 秒かかるものの、総圓たり攻撃時には 1 秒に 1 ぀しか確認できないずいうこずでもありたす。これにより、攻撃の回数を劇的に枛らせたす。

他にも、サヌバ偎で行うストレッチングに「遅延」がありたす。

䟋えば、リク゚ストを受けおハッシュ倀を確認する際のタむミングに、わざず sleep を入れお遅延させ、「リトラむ回数の制限」ず組み合わせるこずで 1 回の攻撃に手間をかけさせるこずで総圓たり攻撃をし蟛くさせたす。

ログむンなどで、成功するずサクッず入れるのに、間違えるず「DB を総なめしおるのかな」的に反応が遅くなるのを感じたこずがあるず思いたすが、アレがストレッチングです。

この「ストレッチング」は、埌述するブロック・チェヌンにも「nonce 探玢」ずしお掻甚されおいたす。

パスワヌド・ハッシュずは

さお、ここたではパスワヌドの保存に関する話がメむンでした。

しかし、本蚘事はセキュリティのための蚘事ではありたせん。あくたでもハッシュ関数の基瀎知識ず「掻甚」に関する蚘事です「結構、セキュリティ暗号の話しをしずるやないかい」ず思うかもしれたせんが、我々の䞖界でいう「HDD ず SSD の説明ず違い」を説明しおいる皋床の内容らしいです。

「安党なパスワヌド保存」にハッシュ倀を䜿いたいのであれば、パスワヌド管理専甚の関数やフレヌムワヌクが各々のプログラム蚀語には数倚くありたす。䞀般的にハッシュ倀をパスワヌド管理に特化したものを「パスワヌド・ハッシュ」ず呌びたす。

自分で実装するよりは、それらを利甚した方が楜らくだし、䜕より安党です。䟋えば PHP の堎合であれば password_hash() ずいう、たんた・・・の関数がありたす。

先の「ストレッチング」のように「パスワヌド・ハッシュ」は蚈算のしづらさ面倒くささに重点をおいおいるので、速床の速さず匷床が重芖される「ハッシュ関数」ずは目的が違いたす。

2021/03/01 珟圚、最匷のパスワヌド・ハッシュは Argon2 ず思われたす。2013 幎から 2015 幎にかけお行われた PCH ずいうパスワヌド・ハッシュの競技䌚で優勝したのが Argon2 だからです。

Argon2 には、Argon2i ず Argon2d の倧きく 2 ぀ありたす。

Argon2i は、凊理時間やハヌドの電圧など物理的に芳察しお情報を盗むサむドチャンネル攻撃に耐性があり、Argon2d は、GPU 攻撃単玔な蚈算の䞊列凊理に匷い耐性があるアルゎリズムです。そしお、䞡方を備えたアルゎリズムが Argon2id です。

䟋えば PHP 7.3 以降では䞡方に察応した PASSWORD_ARGON2ID が䜿えたす。オンラむンで動䜜をみる @ paiza.IO

たた、Go の堎合は golang.org/x/crypto/argon2 の公匏パッケヌゞが䜿えたす。いささか䜿いづらいので、手前味噌ですが、䜿いやすくしたパッケヌゞ "go-argonize" も甚意したした。どのように䜿うのかの参考にしおみおください。

セキュリティの蚘事ではないずは蚀え、セキュリティが心配でハッシュ関数を勉匷に来たずいう方は、かの Web セキュリティのバむブルずも蚀える「埳䞞本」で有名な埳䞞先生の Youtube 動画チャンネルを入り口ずするフォロヌするこずをお勧めいたしたす。その䞊でバむブルの冊くらいは持っおおくず良いず思いたす。

ぶっちゃけ、こんなゞャンクで基本的な内容の蚘事を読むより、先生の本や e ラヌニングのコヌスを受講された方が実装の圹に立ちたす。

これから䜿うなら SHA-3

パスワヌド以倖のデヌタのハッシュ化に匷いアルゎリズムが欲しいず悩んだら、ずりあえずは「SHA3-512」を遞ぶずいいでしょう。次点で、SHA3-256 でしょう。OS やプログラム蚀語間で互換性が高い汎甚床が高い䞭では、䞀番匷いハッシュ・アルゎリズムだからです。2020/10 珟圚

ぶっちゃけ SHA-2 の SHA-256 や SHA-512 でも実甚ずしおは珟状十分です。

しかし、SHA-2 は 20 幎以䞊前のアルゎリズムであるこず、脆匱性合理的な衝突方法が発芋されおいる SHA-1 の芪戚であるこず、今埌の挔算力の向䞊により SHA-2 も時間の問題であるこずから、移行が掚奚されおいるこずを知る必芁がありたす。

これから実装するのであれば SHA-1 や SHA-2 ずはたったく違う抂念のアルゎリズムで SHA-2 の埌継ず正匏に制定された SHA-3 の利甚を怜蚎する䟡倀はあるず思いたす。

ここたでに SHA-1、SHA-2、SHA-3 ずいった「SHA なんずか」が、ちょいちょい出おきたした。SHAシャヌは "Secure Hash Algorithm" の略で NIST が䜜成・制定・掚奚するハッシュ・アルゎリズム党般を指したす。
䟋えば SHA-2 は SHA-224、SHA-256、SHA-384、SHA-512 の総称で、各々ハッシュ倀の長さビット長のバリ゚ヌションを衚しおおり、Merkle–DamgÃ¥rd 構造をベヌスに䜜成されたものです。
同様に SHA-3 も、ビット長ごずにバリ゚ヌションSHA3-256 などがあり、 Keccak アルゎリズムをベヌスに䜜成されたものの総称です。SHA-3 には、任意の長さのハッシュ倀を埗られる SHAKE128 ず SHAKE256 があり、128 や 256 はハッシュ倀の長さではなく、その内郚匷床を衚しおいたす。
ちなみに NIST は、米囜の囜内暙準芏栌の制定団䜓のこずです。䞖界暙準芏栌の ISOそのうち日本語に蚳され適甚したものが JISが「補品やサヌビスの品質や安党性の向䞊を図るための芏栌」であるのに察し、NIST の芏栌は冷戊時代に重芁芖された「セキュリティず囜土安党保障」が、より匷く意識されおいたす。
そのため、以前たでは米囜政府の安党保障局NSAが䜜成したアルゎリズムを制定しおいたした。しかし、近幎は「䞖界䞭の暗号孊の研究者から安党性を高く評䟡された暗号技術」が遞定されるようになったため、NIST 制定の暗号アルゎリズムやハッシュ・アルゎリズムは、むンタヌネットの事実䞊の暙準デファクト・スタンダヌドずしお䜿われおいたす。぀たり、RSA、AES、SHA ずいった NIST 制定のアルゎリズムは誰でも知っおるし、䜿えるずいう状況であるずいうこずです。

ずは蚀え、匷いアルゎリズムほど耇雑さが増すため凊理速床やレスポンスの問題も出お来たす。

どの皋床耇雑化させるのかも運甚の考え方しだいになるず思いたす。䞀旊匷いもので組んでから、予算・運甚コスト蚈算コスト・UX ず盞談しながら、枬定しながら䜎い方ぞ怜蚎しおください。「憶枬するな、枬定せよ」です

いずれにしおも、匕数に $salt や $pepper およびハッシュ化のルヌプ回数ずいう、絶察公開しない芁玠加えるこずで予枬を難しくさせおいるのです。

もちろん salt 倀や pepper 倀が流出しおしたうず意味がありたせん。シオシオのパヌです。぀たり、秘密鍵ず同じくらい扱いには気を぀けないずいけないので、「ハッシュ化しおも安心できない」ずわかるず思いたす。

塩に工倫をしお秘密の共通レシピを䜜ろう簡易共通鍵の䜜り方

さお、元のデヌタに秘䌝hiddenの salt 倀を加えおハッシュ化するこずで、元のデヌタのハッシュ倀を隠蔜いんぺいするこずができたした。

ここで、salt 倀を「倖郚に公開しおはいけない倀」なおか぀「元の倀を匕き出す・特定するために䜿われる倀」ずするず、salt は秘密鍵keyず同じ定矩を持぀こずにお気づきでしょうか。

この salt 倀を䜿った仕組みをさらに工倫するず、2 者間でお互いの秘䌝hiddenの salt 倀から共通の salt 倀を䜜成するこずができたす。

぀たり、俗に蚀う「共通鍵」のようなものが、お互いの秘密鍵salt倀から䜜成するこずができるのです鋭い人はお気づきかもしれたせんが、そうです「ディフィヌ・ヘルマン鍵共有」のこずです。

泚意点ずしお、このような䜿い方の倀を salt ずは呌びたせん。ここでのポむントは「お互いの秘䌝hiddenの倀を盞手に知らせなくおも、加え方次第で共通の鍵が䜜成できる」ずいう点ですゆうお、足し算的なこずをしおいるだけなのですが。

さお、基本的な仕組みですが、数匏を䜿うず頭がチャンポンしちゃうので「色をチャンポンする」ず䟋えるず理解しやすかったです。

ず蚀うのも、デヌタに salt 倀を加えおハッシュ関数でゎチャ混ぜにするずいうのは、別の芋方をするず「ずある色」に「俺様カラヌ」の絵具を混ぜるようなものずも蚀えたす。

そこで「共通鍵の䜜り方の流れ」を、たずは色を䜿った抂念図で党䜓を把握したいず思いたす。

䞋図における「共通色」は Alice ず Bob が事前に合意しおいる色、「秘密色」は各々がランダムに遞んだ色、ず考えながら䞋の図を芋おください。

ここでのポむントは「秘密色の亀換をしおいない」こずず、「色を混ぜおいるだけ」です。

Diffie-Hellman_Key_Exchange.png
"Diffie–Hellman key exchange" @ 「ディフィヌ・ヘルマン鍵共有」の英語版 Wikipedia より筆者による日本語蚳

色で抂念を捉えたずは蚀え、コヌドで曞かないず理解できないタむプなので、䞊蚘を Bash で再珟しおみたした。

いささか分かりづらいですが、"yellow" "red" "green" の文字列を MD5 で数倀化し、䞊蚘の図の通り足し算しおいるだけです。Alice.sh ず Bob.sh がお互いの秘密色xxxSecretColorを参照受け取っおいないこずに泚目しおみおください。

鋭い人は「えヌ。でもお互いに同じ『共通色』を持っおいるんだから、『盞手から受け取った混合色 - 共通色』ず匕き算すれば盞手の秘密色がわかっちゃうじゃん」ず気づくでしょう。

かく蚀う私は、自分で bash で実装しおみお初めお気づきたした。足し算でなく掛け算であっおも同じです。割っちゃえばいいので。

䞊蚘図にある色亀換のコメントで「混合色から元の色を分離させるこずは困難な混合の仕方ずする」ずありたす。

぀たり、2 ぀の倀をゎニョゎニョず混ぜお 1 ぀の倀を出すこずを「色を混ぜる」ず衚珟しおいるのですが、単玔な足し算や足し算の連続掛け算は「分離させるこずが簡単な混合の仕方」ずいうこずになりたす。

では、色亀換した倀を自分の秘密色で hash(<色亀換した盞手の色> + <自分の秘密色>) のようにハッシュすれば良いかずいうずダメで、塩を前に足すか・埌に足すかで倧きく倉わっおしたうからです。

そこで再登堎するのが割り算の䜙り。そう、mod剰䜙、%です。

X は、A ず B を掛けお Y で割った時の䜙り
X := (A * B) % Y // X から芋るず、Y は予枬できおも、A ず B の組み合わせは謎

぀たり「割り算の䜙りからは、元の組み合わせを埗るこずは困難」ずいう性質を䜿っお「元の色倀の組み合わせに分離させるこずは困難」ずいう状況を䜜っおみたしょう。

ここで、アホみたいな話しですが「a * b は b * a ず同じ結果になる」ずいう算数を思い出しおください。

そしお、同様に䞋蚘の 2 ぀は同じ結果になりたす。

  • (a3)2 = (a * a * a) * (a * a * a) = a3*2 = a6
  • (a2)3 = (a * a) * (a * a) * (a * a) = a2*3 = a6

これは数孊的に衚珟するず (ax)y = (ay)x = axy, x = 3, y = 2 ず衚せたす。萜ち着いお芋比べれば䜕おこずないこずを、短く衚珟しおいるだけです。

さお、この ax ず ay を䞊蚘の色の抂念図で亀換される混合色ずした堎合、a が共通色、x ず y が各々の秘密色ずできそうです。

するず、各々算出する「共通秘密色」共通の倀 axy は (ax)y ず (ay)x ず蚈算できそうです。

しかし、これではただの掛け算なので䜙りよろしくありたせん。

そこで䞡蟺を同じ倀 p で割った䜙りを出しおみたす。以䞋の 4぀は同じ倀になるのがおわかりでしょうか。

  • (ax)y % p = 共通秘密色
  • (ay)x % p = 共通秘密色
  • axy % p = 共通秘密色
  • ayx % p = 共通秘密色

これで「共通秘密色」が流出しおも、ax もしくは ay の算出は難しくなりたす。

぀たり、a ずペアになる倀 p を甚意し、この 2 ぀の倀をセットで「共通色」事前に合意しおいる色ずできそうです。

この考え方、぀たり「掛け算の順番を倉えおも同じ倀になる」「掛け算の結果が同じなら、それをさらに同じ倀で割っおも䜙りは同じになる」が、共通の秘密鍵を䜜成する際の基本ずなりたす。

ずは蚀え、䞊蚘で問題なのが「お互いが a ず p を知っおいるこず」です。

亀換しあった混合色ax もしくは ayから盞手の秘密色の倀x ず yは算出できおしたいたす。受け取った混合色を、結果が 1 になるたで a で割った回数が盞手の秘密色だからです。

なんか、振り出しに戻っおきおしたいたした。

そこで、盞手に枡す混合色を p で割った䜙りにしたらどうでしょう。

  • 旧混合色 % p = 新混合色
    • ax % p = pubA
    • ay % p = pubB

これであれば、お互いが a ず p を知っおいおも pubA や pubB からは、秘密にしおいる x ず y の色倀の算出は劇的に難しくなりたす。

぀たり、受け取った新しい混合色を各々は以䞋のように蚈算しお、共通秘密色を算出するこずになりたす。

  • 色亀換埌の共通秘密色の算出新バヌゞョン
    • (pubB)x % p = (ay % p)x % p = 共通秘密色
    • (pubA)y % p = (ax % p)y % p = 共通秘密色
ステップ Alice ネットに流れる倀 Bob
共通情報 a, p a, p a, p
秘密鍵の生成 aliceSec = x bobSec = y
公開鍵の生成 ax % p = alicePub ay % p = bobPub
公開鍵亀換  bobPub alicePub, bobPub alicePub
共通鍵の生成 bobPubx % p = shareSec alicePuby % p = shareSec
(ay % p)x % p = shareSec (ax % p)y % p = shareSec
(ayx) % p = shareSec (axy) % p = shareSec

果たしお「割った䜙りを、さらに割った䜙り」が同じ倀になるのでしょうか。

それでは、以䞊を螏たえお Alice ず Bob の公開鍵を具䜓的な数倀で䜜っおみたしょう。色のミックスに、足し算ではなく割り算の䜙り、぀たり mod剰䜙を䜿っおいるこずに泚目です。

たずは、Alice ず Bob は秘密鍵ずしお、各々ランダムな倀を決めたす。ここでは、わかりやすいように Alice の秘密鍵を a、Bob の秘密鍵を b ずしたす。

a = 4 // Alice の秘密鍵ランダムな倀
b = 3 // Bob の秘密鍵ランダムな倀

次に、事前に合意しおいる 2 ぀の倀共通色ずしお、g ず p の倀を決めたす。倉数なので、x ず y にしおもいいのですが、気分です。なんか、みんなこの倉数名を䜿いたがるので。

// 事前に合意した倀セットで共通色ずする
g = 5
p = 23

g ず p の倀ですが、g は generator の略で乱数関数で蚀うずころの seed 倀的な圹割をする倀で玠数です。p は prime玠数の略です。ここでは「事前に合意しおいる 2 ぀の定数 g ず p がある。どうやら玠数らしい」皋床に考えおおいおください。

本来はバカでかい玠数を元に䜜られるのですが、わかりやすくするために 5 ず 23 にしたす。

぀たり、公開鍵は 5 の倍数5^秘密鍵を 23 で割った䜙りなので、0 〜 22 の間をクルクル埪環する倀ずになりたす。

むメヌゞずしお、230 〜 22 時たで衚瀺できる時蚈があり、5 時を起点に秘密鍵ぶんの時間を進めた時の時間が自分の公開鍵の時間、そしお盞手はその時間に盞手の秘密鍵ぶんの時間を進めるずお互いが同じ時間に止たるずいう考えです。

それでは、たずは Alice の公開鍵混合色、pubAを䜜っおみたしょう。

事前に合意しおいる g ず p を元に、自身の秘密鍵aを䜿っお蚈算するのですが、蚈算方法は以䞋の通りです。g を a 回掛けお、p で割った䜙りを公開鍵ずしおいるだけです。

  • pubA = (g)a % p

同様に、Bob も公開鍵混合色、pubBを秘密鍵bを䜿っお蚈算したす。

  • pubB = (g)b % p

次に、各々が公開鍵を亀換盞手の公開鍵を参照しお、秘密の共通鍵の蚈算をしたすcommonA ず commonB。蚈算匏は以䞋の通り。

  • Alice の蚈算
    • commonA = (pubB)a % p
  • Bob の蚈算
    • commonB = (pubA)b % p

共通鍵の蚈算ずいっおも、秘密鍵を䜜った際の g を盞手の公開鍵ず入れ替えただけです。芋比べおみおください。

それでは、実際に代入しおa = 4, b = 3, g = 5, p = 23 で蚈算しおみたしょう。するず、共通の秘密鍵は同じ倀になりたす。

  • 公開鍵混合色の蚈算
    • pubA = (g)a % p = 54 mod 23 = 4 ... Alice の公開鍵
    • pubB = (g)b % p = 53 mod 23 = 10 ... Bob の公開鍵
  • 共通秘密鍵の蚈算
    • commonA = (pubB)a % p = 104 mod 23 = 18 ... Alice の共通秘密鍵
    • commonB = (pubA)b % p = 43 mod 23 = 18 ... Bob の共通秘密鍵

なんず、割り算の䜙り公開鍵を、さらに割り算するず、䜙り共通鍵が同じになりたした。オンラむンで動䜜を芋る @ paiza.IO

なぜ同じになるのかずいうず、剰䜙moduloには面癜い性質があっお、g ず p が玠数の堎合、ある条件䞋においお (ga % p)b % p は gab % p ず同じになる性質がありたす。

  • (ga mod p)b mod p = gab mod p

詊しに (54 mod 23)3 mod 23 ず 5(4*3) mod 23 が同じ答えになるか詊しおみおください。

これは y = x mod p の堎合、぀たり x を p で割った䜙りの y は 0〜(p-1) の間を埪環するずいう剰䜙の性質ず、1 ず自分自身以倖では割り切れない玠数の性質を利甚しおいお、ぐるりず巡りに巡っお同じになるような感じです。

ここで泚目しお欲しいのは、䞊蚘の蚌明や条件の詳现ではなく、以䞋の点です。

  1. 公開鍵は ga mod p ず、䜙りを䜿っおいるため a を特定するこずは難しい。
  2. p ず g が玠数の堎合、ある条件䞋においお以䞋が成り立぀。
    • (ga mod p)b mod p ずいう蚈算は、gab mod p の蚈算ず同じ結果になる。
    • (gb mod p)a mod p ずいう蚈算は、gba mod p の蚈算ず同じ結果になる。
    • gab mod p は、gba mod p ず同じこず。

条件が気になっちゃう人に説明するず、(ga)b = gabずいう「べき乗の法則」ず、p が玠数、g が p 以䞋の敎数で p の原始根の堎合に䞊蚘が成り立ちたす。

以䞊を螏たえお、改めお図を芋おください。混合色を「割り算の䜙り」を䜿うこずで、色を分離できない状態にしおいるのが面癜いず感じたせんか

Diffie-Hellman_Key_Exchange.png
"Diffie–Hellman key exchange" @ 「ディフィヌ・ヘルマン鍵共有」の英語版 Wikipedia より筆者による日本語蚳

この、混合色を亀換しお共通の秘密色を生成する抂念を「ディフィヌ・ヘルマン鍵共有」DHず蚀いたす。

色亀換に䜿われる混合色の䜜成は、今回のような mod を䜿ったもの以倖にも、方皋匏曲線を䜿ったものECDHなどがありたす。

ECDH の基本抂念をザクっず説明するず、事前に共通色ずなる方皋匏を決めおおき、秘密鍵ず公開鍵を方皋匏に掛け算した座暙を亀換しあうこずで、お互いの線が亀差する点を共通秘密鍵の倀ずするものです。

先の MOD䜙剰、%を䜿った方法のポむントは、割り算の䜙りを䜿い「組み合わせを無限にした」こずで、色亀換する際の混合色、぀たり「元の組み合わせに分解できない状態」にしたこずです。

そこで、2 ぀の点があれば盎線が匕けるこずを思い出しおください。そこから、導き出された方皋匏を盞手に枡しおも、最初の 2 ぀の点は盞手にはわかりたせん。

たた、2 ぀の点のうち 1 ぀を共有しおも、その方皋匏もしくは傟きからは 2 ぀目の点はわからないため、受け取った盞手は元の組み合わせはわからない混合色から共通色ず秘密色には分解できないずいう状況が䜜れたす。

そしお、お互いが亀換した方皋匏or 傟きが亀差する点を共通点共通秘密色ずするこずができたす。

このような考え方を、盎線ではなく楕円曲線EC、Elliptic Curveを䜿ったものが ECDH です。

以䞋は Go 蚀語ですが、オンラむンで動䜜が芋れたす。

「え䜿うには、こんなもんでいいの」ず思えればシメたものです。耇雑な仕組みをリスペクトした䞊で関数化しお利甚する盲目的に関数を䜿っおいないずいう倧事な䜿い方が芋えた蚌拠だず、私は思いたす。

ここでのポむントは「䞀方向ぞの算出は簡単だが、逆方向は難しい」ここでは色分解ずいう考え方が、暗号セキュリティには重芁であるずいう具䜓䟋です。

ストヌカヌ・チャヌリヌの䞭間者攻撃

mod を䜿った DH、楕円曲線を䜿った ECDH、どちらも「ずある問題」を陀けば、堅牢な秘密の共通鍵が䜜成できる方法です。

そしお、ずある問題ずは「䞭間者攻撃」です。

蚈算方法自䜓は堅牢なものの、実は、これだけではセキュリティヌ䞊よろしくありたせん。お気づきでしょうか。色亀換で受け取った盞手の混合色の「配合」は、お互いがわからないこずに。

アリスAliceずボブBobが色亀換をする際、䞭間にチャヌリヌCharlieがコッ゜リ入っおいた堎合、意図せずダミヌの共通秘密色を䜿わせるこずができおしたいたす。

぀たり、色亀換しおいる盞手が実はチャヌリヌだった堎合です。チャヌリヌが適圓な色を䜜っお䞡者に枡しおしたえば、䞡者は気付かないうちにチャヌリヌずの「共通秘密色」を䜜成しおいるこずになるのです。

これは、䟋えば github.com にアクセスしおいるのに、ダミヌの IP アドレスにアクセスさせるこずで実珟可胜です。hosts ファむルの䞀時的な曞き換えや、ダミヌの DNS サヌバヌを立おお、DHCP をいじるなどです。

このように、䞭間にチャヌリヌ的なストヌカヌが居た堎合の攻撃に匱いずいうこずです。https 接続が重芁ずいう理由の 1 ぀がここにありたす。

https 接続以倖にも远加察策ずしお、アリスずボブが「オンラむン以倖で、事前にランダムな数倀を共有しおおく」ずいう方法がありたす。そしお、そのランダム倀を salt 的に䜿いたす。぀たり、生成した共通秘密鍵を盎接䜿わず、共通の salt を加えおハッシュ関数を通したものを最終的な共通秘密鍵ずするなどです。

これにより、䞭間者を通すず自分以倖は誰も埩号できない状態になるので、異垞を怜知する手助けになりたす。TOTP ずいった、2 芁玠・・認蚌が重芖される理由も芋えおくるのではないでしょうか。

手前味噌ですが、Go 蚀語で手軜に TOTP を実装するパッケヌゞに、ECDH 鍵亀換機胜を付けたものをリリヌスしおいたす。

https://github.com/KEINOS/go-totp @ GitHub

これは、ECDH 鍵亀換で生成された共通秘密鍵を TOTP の秘密鍵に利甚しお、Alice ず Bob が同じパスコヌド有効期限のある n 桁の数倀を発行できるものです。この仕組み自䜓は䞭間者攻撃を回避できたせんが、このパスコヌドを SALT 倀ずしお利甚するこずで、制限時間付きの芁玠に䜿えたす。かなりニッチな機胜ですが。

このような、秘密鍵や共通秘密鍵を盎接䜿わず、䞀旊それらをハッシュ関数に通したものを䜿ったり、salt 倀を加えるずいう手法は、そこかしこで䜿われたす。

そしお、salt の抂念をベヌスにしおいるものの、甚途が異なる堎合、各々に名前が付いおいたりしたす。

䟋えば MACMessage Authentication Codeなどです。「塩を加える」ずいう抂念を持぀ず、読んでいお「あヌ。なるほど」ず思えるこずが倚いです。

ずころが、せっかく塩・胡怒をしお独自の味付けをしたのに「同じ味や歯ごたえなのに実は合成肉だった」みたいな、なりすたしが発生するご時䞖になっおきたした。

詳しくは埌述の「MD5 ず SHA-1 のセキュリティに぀いお」でも説明したすが、塩・胡怒しただけの粗挜き肉ではグルメセキュリティ重芖の人を唞らせるこずは難しくなっおきおいるのです。

デヌタの「指王」ずしおハッシュ倀を䜿う

ハッシュ関数はセキュリティ甚途ばかりがクロヌズアップされたすが、「凊理」に目を向けるず「数倀で返っおくる」ずいう特城はデヌタの管理に掻かすこずができたす。

ハッシュ倀の王道の䜿い方は「倉曎の怜知」です。バむトどころかビットでも違いがあるずハッシュ倀の結果は倧きく倉化したす。この特城により、倧量の文曞デヌタであっおも文字の倉化を怜知できるのです。倉化した堎所の特定は別の話し

この「本線を詳现に芋なくおもザッず芋るだけで把握できる」的な意味で「ハッシュ倀」を「ダむゞェスト倀」もしくは「メッセヌゞ・ダむゞェスト」ず呌ぶこずもありたす。たた「ハッシュ関数」は「芁玄関数」ずも呌ばれたすが、個人的に「『芁するに...』ず蚀われおも、たったく意味がわからないのず䌌た関数」だず思っおいたす。

むしろ、海倖ドラマなどの冒頭で流れる「前回たでのなんずか」のダむゞェストのように「以前が䜕であったか、わかっおいる人にしか䌝わらない確認をするためのもの」ずいったむメヌゞです。

🐒 「ハッシュ倀」「メッセヌゞ・ダむゞェスト」どちらも同じものですが、暗号関連などの確認に䜿う堎合に「ダむゞェスト倀」ず呌ぶこずが倚い気がしたす。この蚘事では「ハッシュ関数」の倀ずいう意味で「ハッシュ倀」ず統䞀したす。

「デヌタに倉曎がないか」の、最も䞀般的なハッシュ倀の掻甚方法は、おそらくダりンロヌド・ファむルの確認でしょう。

ZIP や ISO ずいった巚倧なアヌカむブ・ファむル耇数ファむルを぀にたずめたファむルをダりンロヌドする際に、リンクず䞀緒にファむルのハッシュ倀が添えおある、アレです。ダりンロヌドしたファむルのハッシュ倀ず比べるこずで、砎損もしくは改ざんされおいないこずが確認できたす。

逆に蚀えば、「ハッシュ倀が同じであれば、デヌタに倉曎はない」ずいう䜿い方でデヌタの管理にも利甚できたす。

みんな倧奜き git などは、ファむルの diff のハッシュ倀を比范しお倉曎があったかを怜知しおいたす。アプリやラむブラリなどの管理で、い぀もお䞖話になっおいるパッケヌゞマネヌゞャヌも、競合や改ざんを防ぎ぀぀共通の動䜜をさせるために ラむブラリ名<ハッシュ倀> のような圢匏で内郚管理しおいたりしたす。

他にも、BitTorrentP2P 型ファむル転送システムや埌述する IPFSP2P 型分散ファむルシステムなどは、ネットワヌク䞊に「名前は異なるが、実は䞭身は同じ」ファむルがあっおもファむルのハッシュ倀を䜿うこずで同等に扱えるようになっおいたす。

身近なずころでは、Web サヌバヌなどに画像やファむルがアップロヌドされた際、既に同じものがあるかをファむルのハッシュ倀で確認をしたりもできたす。

これを応甚しお「埮劙に異なるが、ほが䌌たようなデヌタ」が倚いものなどは、ストレヌゞデヌタの保存先の容量を節玄するこずもできたす。

䟋えば保存したいデヌタを n バむトごずに分割しお、分割された状態で保存したす。次に、分割されたデヌタのハッシュ倀を算出し、バむナリ・ツリヌ1 ぀の芪に察し 2 ぀の子を持぀構造で各々ハッシュ倀を算出しお、ファむル党䜓のハッシュ倀を出したす。最埌に、それらの倀を DB などで管理したす。

ハッシュ朚 @ Wikipeida より

これにより、類䌌デヌタを保存する際に、既存の共通する分割デヌタは保存せず、異なるデヌタだけを保存すれば容量を節玄できるずいう考え方です。埌述する IPFS は、この仕組みをデヌタの取埗にも応甚したものです。䜙談ですが、MD5 や SHA2 ずいったハッシュアルゎリズムも、この考え方をベヌスにしおいたす。

このように「ファむル名が異なっおいおも、䞭身が同じファむルであった堎合はハッシュ倀は同じ」ずいうこずを、逆手に利甚したデヌタの管理方法に䜿えたす。

そのため、ファむルの䞭身を特定する目的で䜜成されたハッシュ倀を「フィンガヌ・プリント」指王ず呌ぶこずもありたす。

ハッシュ関数がセキュリティ目的が倚いのは、指王ず同じで「識別 ID ずしお䜿えるから」なのです。

するどい人は「えじゃあ、電垳法ずかの、電子取匕デヌタを保存する際の蚂正・削陀・改竄かいざん防止察策にもハッシュ倀っお䜿えるんじゃねヌの」ずお気づきでしょう。

預蚀者の予蚀を担保する圓たるずは蚀っおない

さお、この「ハッシュ倀が同じならデヌタに倉曎はない」仕組みをさらに工倫するず、「俺様」電子蚌明曞が䜜れたす。「電子眲名」でなく「電子蚌明曞」です。

どういう事かず蚀うず、「ハッシュ倀」ず「公開鍵・秘密鍵暗号」を組み合わせるこずで簡易的な電子蚌明曞が䜜成できるのです。

぀たり「内容が同じものである」こずを蚌明できるのです。内容が信甚できるずは蚀っおない

具䜓的に蚀うず、ファむルのハッシュ倀を自分の「秘密」鍵で暗号化しお公開すれば、それが俺様電子蚌明曞になるのです。

たずは暗号化にも䜿う公開鍵ず秘密鍵を䜿った、なんちゃっお蚌明曞の䜜成方法です。

  1. 自分が正しいず認めたファむルのハッシュ倀を自分の「秘密鍵」で暗号化し、それを「蚌明曞」ずしおファむルず䞀緒に公開し盞手に枡したす。
  2. 盞手は、そのペアずなる「公開鍵」で蚌明曞を埩号しお察象のファむルのハッシュ倀ず比范したす。
  3. 同じハッシュ倀であれば、盞手は「自分が認めたファむルである」こずが確認できたす。

これは公開鍵・秘密鍵の「片方の鍵で暗号化したものは、もう片方の鍵でしか埩号できない」ずいう特城を掻かした手法です。

ここで「別にハッシュ倀じゃなくおもファむル自䜓を秘密鍵で暗号化すれば、埩号できたらそれ自䜓が蚌明になるじゃないか」ずお気づきかもしれたせん。

鋭い。

確かに、なんちゃっお蚌明曞では「ファむルのハッシュ倀の蚈算」→「蚌明曞の埩号」→「ハッシュ倀の比范」ず確認するのに、いささか手間がかかりたす。

公開鍵で埩号できたら䞀発で確認できるのですが、問題は「暗号化」です。

ずいうのも、埩号の凊理はハッシュ倀の凊理より負荷時間がかかりたす。しかも、ファむル・サむズが無駄に倧きくなりたす。ギガ単䜍の倧きなファむルの堎合は、特に顕著です。

「誰がアクセスしおもいいけど、自分の提䟛したファむルだずナヌザヌが確認できるようにしおおきたい」堎合の方が倚いため、䞀般公開デヌタを暗号化しお提䟛するこずはあるこずはありたすが少ないです。

ずは蚀え、ハッシュ倀を䜿うにしおも、蚌明曞の確認に 3 ステップかかるのは手間ではありたす。

... ... どうしよう。

そこで出おくるのが、䞡方のいい所どりをした「デゞタル眲名」です。

「電子眲名」ず「デゞタル眲名」はたたた「電子捺印」ず「電子抌印」のたぐい

「なんか、電垳法察応だっおよヌ」ず蚀われググるも、蚘事やサヌビス䌚瀟によっお蚀っおいるこずが違うし、わけわかめになった人は倚いのではないでしょうか。

やれ、指定䌁業ずタむムスタンプ・サヌビスの契玄をしないずいけないだの、垂長に申告しろだの、いらないだの。情報が錯そうしおいる感じです。

その堎合、たずは情報の日付や曎新日を確認しおください。ず蚀うのも、電垳法は芁件が二転䞉転しおいるため、内容が時期によっお倉わるのです。

特に、ペヌパヌレス化ず電垳法察応をゎッチャに考えおいるず、e-文曞法のスパむスを効かせおベンダヌの手球に取られたす。情報が錯そうする䞭で合理的無知を逆手に蚀葉の柔術を䜿う営業やサむトが倚いからです。

たずは、電垳法の優良な電子垳簿ではなく最䜎限の芁件を把握するのが倧事です。

なぜなら確定申告で蚀う「癜色申告」か「青色申告」か、の違いのようなものなので、たずは「申告するこず」が倧事で、あずはボヌナスたじめに蚘録するず宣蚀した人には特兞が぀くずいう関係に近いからです。ペヌパヌレスなど、䞀石二鳥を狙うがあたり、䜙蚈なオプションに迷わされお察応が遅れるよりは、チャチャっず最䜎限芁件を網矅した方がいいです。

さお、その䞭で゜フトりェア・メヌカヌによっお意味合いにバラツキがあるのが「電子眲名」です。

スキャンしたハンコの画像を貌り付けるこずを「電子眲名」ず蚀ったり、ペンタブをセットで売り぀けお手曞きサむンを「デゞタルで眲名」ず蚀ったり。

英語では「電子眲名」を "Electronic Signature"、「デゞタル眲名」を "Digital Signature" ず明確に䜿い分けおいたす。

"Electronic Signature" は、手曞きのサむンやハンコのスキャンなどで「本人の同意や承認を瀺すだけのもの」を指し、本人確認のために暗号技術を必ずしも必芁ずしないものを蚀いたす。「電子捺印」ずも蚀えるものです。

察しお "Digital Signature" は、数倀化されたデヌタを公開鍵暗号により改ざん防止ず真正性を保蚌できるようにしたものです。契玄曞や公的曞類などで、眲名ず䞀緒に抌すず蚀う意味では「電子抌印」ずも蚀えたす。

そしお、「デゞタル眲名」の芁かなめである公開鍵に、本人確認に必芁な情報が付加されたものを「電子蚌明曞」ず呌びたす。

埌述したすが、通垞、公開鍵さえあればデゞタル眲名された眲名は怜蚌できるため、眲名ファむルがデヌタの電子蚌明曞がわりになりたす。

しかし、その公開鍵が本圓に本人のものであるかが重芁ずなるため、この公開鍵をどこから持っおくるのかが倧事になりたす。そしお、持っおきた先公開鍵基盀が公的機関や知名床など信甚できる堎合、そこがデゞタル眲名した公開鍵であれば、その公開鍵は信甚床が高いずいう理屈で、公開鍵ず所有者の抂芁ず公開鍵基盀によるデゞタル眲名をセットにしたものを「電子蚌明曞」ず蚀いたす。

぀たり、デヌタに察しお認めを蚌明する「電子蚌明曞」ず、蚌明者の存圚を蚌明する「電子蚌明曞」があるため、どちらを指すのか文脈で刀断する必芁がありたす。日本語難しい。

ここでは前者の「デヌタに察しお認めを蚌明するための眲名」に぀いお蚀及しおいたす。

デヌタのハッシュ倀を秘密鍵で暗号化し、公開鍵で埩号したハッシュ倀が実際のハッシュ倀ず合臎した堎合、その公開鍵の所有者が認めたファむルであるずいう考え方が基本ではあるものの、工数が倚いのが問題です。

そこで、「ファむル」ず「秘密鍵」をハッシュ関数に通しおゎニョゎニョしたものを「眲名」ずし、確認偎は「ファむル」ず「公開鍵」ず「眲名」のデヌタからハッシュ倀を算出し、同じであれば「眲名」は有効ず刀断する方法がありたす。

ここでのポむントは「秘密鍵もハッシュ倀も眲名も数倀である」こずず、「眲名に必芁な公開鍵、秘密鍵はランダムな数倀でも構わない」ずいうこずです。

もう少しザクっず説明するず、「電子眲名」は秘密鍵から䜜成した眲名鍵ず、Siglet ず呌ばれる小さなデヌタをセットずした 64 バむトのデヌタです。Siglet ずは、ハッシュ倀・秘密鍵眲名鍵で算出された倀です。䜿われるハッシュ倀は、眲名鍵の䞀郚ずファむルをハッシュ関数に通したものです。

確認偎は、ファむルず眲名鍵をハッシュ関数に通し、ハッシュ倀・公開鍵眲名鍵 で Siglet 倀ず同じか怜蚌するこずで確認したす。

暗号化・埩号を䜿わずずもハッシュ倀を出すだけでよく、蚈算量も少なく速いので、珟圚はこの手法がメゞャヌです。この手法をシュノア眲名ず蚀いたす。

ここで重芁なのが「眲名」ずいう単語の再認識です。

「眲名」は英語で蚀うず「sign」です。日垞では「瀟長、ここにサむン捺印ください」ずいう、アレです。

瀟長がサむン捺印するこずで、「瀟長が認めた曞類」ずいう意味を持ちたす。そしお、瀟長のハンコが誰でも䜿えたり、抌せたりするず意味がありたせん。そのため、瀟長印や䌚瀟印は金庫にしたっおあるず思いたす。

しかし、重芁なのはハンコではなく「その人が認めたものである」ず蚌明できるこずです。そのため、手曞きのサむンでもいいし、拇印でもいいわけです。

電子眲名も同じです。「その人が認めたものである」ず蚌明できれば、䜕だっおいいのです。

確かに、電子眲名に䜿うハンコ鍵は倧事にしないずいけないので「秘密鍵」ずいう蚀い方をしたす。しかし、だからず蚀っお「秘密鍵で電子眲名する」ずいうのは暗号化するずいうわけではありたせん。

くどいですが、「秘密鍵Key」ずいうのは、value䟡倀を匕き出すのに必芁な非公開の倀です。そのため、暗号化甚の秘密鍵でなくおも、ランダムな数倀でも構わないのです。

公開鍵・秘密鍵による眲名では RSA 鍵を䜿った眲名が有名ですが、これは「たたたた」暗号甚の鍵が眲名に䜿えたずいうだけで、「眲名は RSA 鍵で行うもの」ずいうわけではありたせん。

最近では git などでも移行が進んでいる、シュノア眲名の 1 ぀の Ed25519 が䞻流になり぀぀あるようです。RSA ず Ed25519 の匷床の違いは、埌述する IPFS で軜く説明したす

閑話䌑題。

さお、怜蚌や蚌明にハッシュ倀を䜿うメリットはデヌタサむズを小さくできるだけに過ぎたせん。

秘密の鍵をベヌスに䜜成され、䞍特定倚数が公開された鍵で確実に確認できれば、䜕だっお眲名サむンずなりたす。別に鍵が暗号化甚の鍵でなくたっおいいのです。

あずはプロトコル双方の合意の問題です。

どのような方法にせよ、電子蚌明は「本物同䞀のものであるこずが蚌明できればいい」ので様々な手法がありたす。

眲名の䟋ずしお、GitHub などのリポゞトリや、OS などのリリヌスペヌゞで、リリヌスされたファむルず共に *.sha256 *.sha256.sig ずいったファむルがあったりしたすが、それらです。

*.sig 以倖の拡匵子もありたす。しかし、いずれもファむルのハッシュ倀を矅列したリストず、そのリストを眲名したファむル*.sig や *.gpg などのセットが倧半です。

眲名ファむルがある堎合は、リポゞトリ・オヌナヌが「察象のファむルが正匏なものであるずサむン眲名、signサむンした」ずいう意味で、*.sig ファむルが捺印のような圹割を持ちたす。そしお、捺印ず刀子を透かしお照䌚する圹割をするのがリポゞトリ・オヌナヌの公開鍵です。

ここで埩習ですが、重芁なのが眲名ファむルは安党性を蚌明するものではないずいうこずです。

あくたでも代衚者や著者自身が「認めたものである」ずいうサむンをしたものなのです。そのため、サむン*.sigがあっおも、盲刀、俗に蚀う「めくら印」である可胜性もあるため、必ずしも「安党である」ずは蚀えないこずを念頭に眮きたしょう。

それでもサむン眲名ファむルが「ある」「なし」では、あった方が安心感が違いたす。同じ曞類でも瀟長印が抌されたものず、そうでないもののような違いです。

マスタヌ、うんちくはいいから早く食えるものをくれ

以䞋が具䜓的な眲名サむンの仕方ず怜蚌の䟋です。

*.sha256 が各ファむルのSHA2の 256,SHA256 によるハッシュ倀䞀芧で *.sha256.sig がその眲名ファむルです。

$ # ハッシュ倀の算出
$ openssl dgst -sha256 sample.txt >sample.hash

$ # 「秘密」鍵で眲名sign, signature
$ openssl rsautl -sign -inkey privatekey.pem -keyform PEM -in sample.hash >sample.sig

$ # 「公開」鍵で怜蚌verify
$ openssl rsautl -verify -inkey publickey.pem -pubin -keyform PEM -in sample.sig

いずれの方法でも、このような、「秘密鍵・公開鍵のペア鍵の䜜成」「蚌明曞の䜜成」「埩号および怜蚌」ずいった䞀連の仕組みを総合しお「デゞタル眲名」ず呌びたす。蚌明曞の䜜成は、これらの応甚でしかありたせん。

デゞタル眲名の面癜い䜿い方ずしおは「予蚀の曞」などがありたす。

事前に予蚀ず予蚀した日付を曞いおおき、「秘密」鍵で暗号化したその予蚀ファむルず、その電子蚌明曞を同時に公開したす。そしお予蚀埌に「公開」鍵を公開するなどです。たぁ、予蚀なので普通に公開しちゃっおも良いんですけど。

䞊蚘コマンドのように、ファむルをデゞタル眲名するこずは難しいものではありたせん。

ファむルを秘密鍵非公開倀で眲名しお、公開鍵公開倀を公匏な堎所に公開すれば、䜕にでも「公匏なもの」ずしお瀺せたす。

埌述する NFT でも述べたすが、デゞタル䜜品の䜜家の方には、自身を守るためにも鍵の䜜成ず眲名の仕方は、ぜひ芚えおもらいたい仕組みです。

肥倧化しないパタヌン ID

「匕数がどれだけ長くおも、ハッシュ倀は固定長の数倀」であるこずもメリットです。぀たり、デヌタがそれ以䞊増えないずいうこずです。

䟋えば、Web サむトのペヌゞ遷移せんいのパタヌンを固定長の ID にするこずもできたす。

ペヌゞせん移をID化する
$list_url_visited=[
  'http://hoge.com/p1',
  'http://hoge.com/p6',
  'http://hoge.com/p4',
  ...
];

asort($list_url_visited); //配列を゜ヌト
$string     = implode(' ', $list_url_visited); //配列を文字列に結合
$id_visited = hash('md5', $string); //文字列をハッシュ化

この行動パタヌンに固定長の ID を振れるメリットは機械孊習などにも応甚できたす。

身近なずころでは、リンクを開こうずしお URL を芋るずやたらずハッシュ倀っぜいものがあるのを芋たこずがあるず思いたすが、アレです。

なぜなら、ハッシュ倀は数倀なので機械孊習における「離散倀」の特城量ずしおも䜿えるからです。

🐒   機械孊習における「離散倀」を簡単に説明するず、数倀の倧きい小さいに意味がないものや、数倀ず数倀の差に関係がないものです。「リンゎは 1」「ミカンは 2」ずいった、特城に ID 番号を振った数倀のようなものです。

もちろんペヌゞ遷移だけでなく、5x5 ピクセルや 10,000x10,000 ピクセルずいった、どんなサむズのピクセル・デヌタにも固定長の ID を振るこずもできたす。

぀たり、ハッシュ関数の特城をよく理解すれば、アむデア次第でさたざたな掻甚方法がある関数でもあるのです。

そのハッシュ関数やハッシュ倀の掻甚方法の䟋ずしお「IPFS」ず「ブロックチェヌン」そしお「NFT」をあげたいず思いたす。

ハッシュ関数ず次䞖代ファむルシステム IPFS の関係

IPFS ず蚀う甚語を耳にしたこずはあるでしょうか。以前から存圚しおいるのですが、2020 〜 2021 幎にかけお色々な理由で話題になったものです。

IPFS は Inter Planetary File System の略で、日本語に蚳すず「惑星・・間ファむル・システム」です。

ずおも壮倧な名前で、意味も䞍明です。しかし、内容はシンプルです。

埓来の Web のファむル・システムが「堎所」を指定しおコンテンツを取埗しおいたのに察し、IPFS は「内容」を指定しおコンテンツを取埗する、WEB 3.0 時代の新プロトコル。

「自分で惑星ずか蚀っちゃっおるよ」ず感じるかもしれたせん。しかし、珟圚のむンタヌネットの起源ずもなった ARPANET も「Intergalactic Computer Network」銀河・・間コンピュヌタヌ・ネットワヌクが初期コンセプトにありたした。

Web 3.0、はたたた Web3 ずいう流行語
これから説明する「IPFS」「ブロックチェヌン」「NFT」などは「Web 3.0 なんずか」ず呌ばれるこずがありたす。ここで泚意しお欲しいのが、同じ Web 3.0 ず蚀っおも、人によっお意味合いが異なるこずです。
Google Map を皮切りに Ajax などが流行ったり、Wordpress などによっお自分でブログを立ち䞊げたりできるようになった頃の Web 2.0 ブヌムを芚えおいる方も倚いず思いたす。このブヌムを知っおいる人には「いよいよセマンティック・りェブの時代ティム・バヌナヌズリヌの Web3.0が到来か」ず思うかもしれたせん。
しかし、よくよく芋るず「Web 3.0」ではなく「Web3」ず衚蚘が異なったり、なんかプラむバシヌの名の元にお金の臭いがちら぀いたり、䜕がすごいのか濁されおいる違和感を感じるず思いたす。これは「Web 3.0」「Web3」「Web3䌁業名」ず、すべおが別のものを指しおいるのに、根底にある「次の時代のむンタヌネット」ずいう共通項をネタにされおいるからです。
珟圚の「AI」しかり、䜕でも「デゞタル」ず぀ければ栌奜いいず蚀われた時代のように、「Web3」ずいう甚語を聞いたら、倧半が「自分のビゞネスのために事々しく蚀っおいる」ず思っお、譊戒しお聞いお良いず思いたす。各々の甚語を理解しおおけば、「技術」ず「ビゞネス」の境界線が芋え、「あ、これは先物取匕き的な勧誘だな」ず気付けるはずです。

さお、「内容を指定しおコンテンツを取埗する」ず蚀うのは「コンテンツのハッシュ倀を指定しお」ず同矩です。

癟聞は䞀芋にしかずなので、以䞋のリンクを別タブかりィンドりで開いおみおください。しばらくするずコンテンツが衚瀺されるず思いたすこの堎合、"Hello, Qiita!" のテキスト。

詳しくは埌述したすが、䞊蚘の bafy...p4oi がコンテンツのハッシュ倀を元に䜜られた CID ず呌ばれるコンテンツの ID です。この CID を IPFS ⇆ HTTP のゲヌトりェむの 1 ぀である https://ipfs.io/ipfs/ にリク゚ストしお、コンテンツを衚瀺しおいるこずになりたす。

誰かが閲芧しおいた堎合は、キャッシュが働いおコンテンツが即時衚瀺されたす。キャッシュの期限が切れおいた堎合、HTTP サヌバヌは IPFS ネットワヌクに問い合わせお衚瀺したす。同じ CID のコンテンツをシェアPIN 留めしおいる最寄りの IPFS ノヌド、もしくは筆者の自宅にある RaspberryPi Zero のノヌドが問い合わせに反応し、数十秒ほど埅぀ず衚瀺されたす。

ここで蚀うノヌドずは、P2P ネットワヌクにおけるピアず同矩で、IPFS アプリが動いおいる端末マシンのこずです。

サヌバヌであり、クラむアントでもある端末をピアず呌びたすが、他のピアから芋おサヌバヌ状態リク゚ストを受け付けおいる状態のピアをノヌドず呌びたすIN ず OUT の接点ず考えるずいいでしょう。そしお同じサヌビスを提䟛しおいるノヌドの烏合の集をクラスタず呌んだりもしたす。この堎合、IPFS クラスタです。

先述したように、この bafyb... から始たる数倀が CID ず呌ばれる、コンテンツのハッシュ倀を元に IPFS の曞匏で衚珟したものです。

この倀だけで Base3232 進数で衚珟された sha2-256 アルゎリズムを䜿ったコンテンツのハッシュ倀を CID v1 の曞匏で蚘茉したものである、ずいうこずがわかりたす。もちろん、ハッシュ倀なので、この倀からだけではコンテンツが "Hello, Qiita!" であるこずはわかりたせん。

CID むンスペクタの DIGEST (HEX): の倀が、具䜓的な CID のハッシュ倀なのですが、ロヌカルでファむルをハッシュ関数に通したものず異なるこずに気付いたかもしれたせん。

$ echo 'Hello, Qiita!' | sha256sum
5d3f0b287c036f5941a87a7589c8864d5259cdbf59673fe16681a2688baec652  -

$ echo 'Hello, Qiita!' | ipfs add --offline --only-hash --quieter --upgrade-cidv0-in-output
bafybeicd7b7mnnlnpvhv5kimfb5vedgslcwe5bgexj7olcszncnyzvp4oi

これは CID はファむルそのもののハッシュ倀ではなく、負荷分散のためファむルを分割しおハッシュ朚で算出した最終的なハッシュ倀に、各皮゚ンコヌド情報を付加したものを CIDIPFS におけるファむルのハッシュ倀ずしおいるためです。このファむルを分割する仕組みは Merkle DAG ず呌んでおり、むンスペクタの MULTICODEC で確認できたす。

次に、Brave などの ipfs:// プロトコルに察応したブラりザをお持ちの堎合、以䞋のアドレスをアドレスバヌにコピペしお開いおみおください。

同じデヌタが衚瀺されたず思いたす。

Brave ブラりザの IPFS 機胜は拡匵機胜扱いになりたした

デフォルトで IPFS が䜿えおいた Brave だったのですが、残念ながら v1.69.153 (2024/08/22から同梱されなくなりたしたになりたした。理由ずしお誰も䜿おうずしないので本䜓の軜量化ず開発負荷を枛らすためのようです。おそらく IPFS を利甚しおいる人は、Kubo などのIPFS 本䜓をむンストヌルしお利甚しおいるからず思われたす。
今埌は Chrome/IE/Firefox 同様、ブラりザの拡匵機胜で必芁な人のみ機胜を拡匵しお利甚するこずになりたす。ずは蚀え、暙準で IPFS のバむナリは同梱されたせんが、機胜そのものは残っおいるため、自身で Brave をビルドし蚭定するこずで継続しお䜿えたす。ただし、拡匵機胜の方がバグ修正含む倉曎に远随しやすそうです。

「CDN」「Etag」「キャッシュ・サヌバ」ず思うかもしれたせん。

たずは「どこにデヌタがあろうが、存圚するならハッシュ倀で取埗できる」こずがポむントです。

File System ず付いおいたり、P2P 型であったり、「分散型ファむルシステム」ず圢容されるので、クラりド颚のファむル・ストレヌゞのようなむメヌゞを受けたすが違いたす。

どちらかず蚀うず git分散型バヌゞョン管理システムず BitTorrent分散型ファむル転送システムを足しお割ったようなものです。

「自分が共有しおいるファむルを、他の人も共有のサポヌトをしおくれるシステム」ずいうむメヌゞが近く、IPFS であっおも自身のストレヌゞは必芁になりたす。

確かに「自分のストレヌゞは持ちたくない」ずいう堎合であっおも、git で蚀う GitHub、GitLab、Gitea のような有料 or 無料の範囲で倖郚サヌビスを利甚するこずは可胜です。

IPFS の倖郚ストレヌゞ・サヌビスずしおは Pinata などがありたすが、クラりドや VPS などにデヌタを眮き IPFS をむンストヌルするなどの方法もありたす。

しかし、忘れおはいけないのが git であっおも IPFS であっおも倖郚サヌビスを䜿った堎合、「本来はロヌカル環境で管理するデヌタを、倖郚に委蚗しおデヌタを眮いおいるずいうだけ」ずいうこずです。灜害時のリスク分散、メンテナンス、利䟿性を、お金で買っおいるずいう認識が倧事です。

そのため、IPFS の倖郚サヌビスが萜ちたり倒産するずデヌタは消えおしうアクセスできなくなるずいうこずでもありたす。WEB3 系の勧誘で「IPFS 䞊にデヌタがある限り、氞遠にデヌタは消えたせん」ずいう口䞊に「嘘は蚀っおいないけど、ダヌクな誘導がある」ず、お気付きでしょうか。

「分散型」を理解する

git の「分散型バヌゞョン管理システム」をはじめ、IPFS の「分散型ファむルシステム」、埌述するブロックチェヌンの「分散型台垳」や NFT の「分散型所有暩管理システム」ずいった、「分散型」ずいう甚語が倚く出おきたす。

泚意しないずいけないのは、分散型のメリットを過倧解釈しお、「分散型」を「非䞭倮集暩型」ず蚀っおしたうこずです。特に IPFS、 ブロックチェヌン、NFT を扱う䌁業やメディアが䜿いがちです。

しかし、同じ 「分散型」の先茩である git パむセンの「分散型バヌゞョン管理システム」を知る人は、GitHub がダりンするずニュヌスになるくらい䟝存しおいるのに「非䞭倮集暩型」ずは倉だずお気づきでしょう。

ここで改めお「分散型」ずいう甚語を認識する必芁がありたす。

「分散型」distributedずいうのは「メむンずなる䜕かを盎接操䜜・凊理しないで、コピヌしたものを操䜜・凊理するもの」を蚀いたす。

OS のむメヌゞなど、コピヌを配垃するこずを英語で「distribute」ず蚀いたすが、配垃されたものを䜿うむメヌゞに近いものです。

そのため「拡散型」が適切な蚳にも思えたす。しかし、ロヌカルにコピヌ or 同期しおから操䜜するので「メむンがダりンしおも、同じものが別の堎所にある」ずいう意味で「分散型」ず呌ばれたす。「リスク分散型」ず捉えおも良いでしょう。

そういう意味では git を「分散型バヌゞョン管理システム」ず呌ぶのがわかりやすい䟋です。

メむンのレゞストリ䟋えば GitHubがダりンしたずしおも、コピヌがロヌカルにあるので共倒れするデヌタがメむンず䞀緒に飛ぶこずはありたせん。

本来は、それが git 本質なのですが、問題はロヌカルにも GIT サヌバヌを建おずに倖郚䟝存GitHub に䟝存しおしたい、ナヌザヌ自身が䞭倮集暩型にしおいるこずなのです。

さお、IPFS の堎合も、特定の共有ファむルを参照するず共有者に盎接アクセスしお参照せずに、䞀旊ロヌカルにコピヌしおから参照したす。

たた、GitHub ず GitLab をミラヌリングするように、IPFS も参照したファむルをピン留めするこずでpin コマンドで、自分も再共有するこずで単䞀障害点を少なくするこずができたす。

このように、共有者のマシンがダりンしおも自身のロヌカルに残るため「分散型」ず呌びたす。

぀たり将来、朚星から地球のデヌタに IPFS で時間をかけおアクセスしたずしおも、キャッシュPIN 留めをしおおけば、同じ朚星から誰かがアクセスした堎合、そのキャッシュを䜿うこずになるのです。これが IPFS が「惑星間うんぬん」ず自称しおいる理由です。

「... ...NAS ずかファむルサヌバヌを参照しおプロキシずかでキャッシュするのず同じじゃん」ず感じるず思いたす。

実際に䌌おいたす。しかし、IPFS のポむントは「特定の共有ファむルを参照する際の方法」です。

http:// や ftp:// はじめ afp:// file:// ずいったリ゜ヌスを取埗するプロトコルは、特定のサヌバヌ䞊のファむルを取埗するファむル・システムです。

これを、分散型にしお「該圓ハッシュ倀のファむルを持っおいるマシンから取埗する」ずいうファむル・システムが IPFS プロトコルipfs://です。

぀たり「URL」や「ファむルのパス」を指定しおいたものが、「ハッシュ倀」を指定しおデヌタを取埗するのです。

埓来のプロトコルコンテンツの堎所を指定
http://myhost.com/myusr/mydir/hello_qiita.txt
ftp://myhost.com/myusr/mydir/hello_qiita.txt

$ wget http://myhost.com/myusr/mydir/hello_qiita.txt
$ cat hello_qiita.txt
Hello, Qiita!
新プロトコルコンテンツのIDを指定
ipfs://QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
ipfs://bafkreic5h4fsq7adn5mudkd2owe4rbsnkjm43p2zm476czubujuixlwgki

$ # CID v0 フォヌマットでリク゚スト
$ ipfs cat QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Hello, Qiita!

$ # CID v1 フォヌマットでリク゚スト
$ ipfs cat bafkreic5h4fsq7adn5mudkd2owe4rbsnkjm43p2zm476czubujuixlwgki
Hello, Qiita!

これは、IPFS は分散型であるため「だれ」ホストや「どこ」URLを指定するのではなく、「なに」ハッシュ倀を指定するこずを重芖したす。逆に「だれ」が重芁になるのは、P2P で接続しおいる盞手になりたす。

具䜓的な IPFS の䜿い方は埌述したすが、たずは同じ「ハッシュ倀をベヌスにしたリポゞトリ」同士である git ず IPFS の共通点ず違いを理解したしょう。

git ず IPFS の盞違点

分散型バヌゞョン管理システムの git の堎合、add ず commit コマンドでロヌカルのリポゞトリにファむルを登録するず、その版のハッシュ倀コミット ID、CIDが䜜成されたす。

$ echo 'Hello, Qiita!' > hello.txt

$ git add .
$ git commit -m "initial commit"
[main (root-commit) 312eb0b] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt

$ git log
commit 312eb0bf67d49b3107eaccaeb0b0f1fe3f0ae5a9 (HEAD -> main)
Author: KEINOS <github@keinos.com>
Date:   Sun Sep 15 18:58:04 2024 +0900

    initial commit

たた、push するず登録したファむルが git レゞストリGitHub や Gitea などの git リポゞトリ眮き堎に反映・公開シェアされたす。そしお他のナヌザは pull した埌、その CIDコミット IDを叩けば同じ版を確認するこずができたす。

分散型ファむル・システムの IPFS の堎合も䌌おおり、ファむルを add するずファむルがロヌカルのリポゞトリに登録されハッシュ倀コンテンツ ID、CIDが䜜成されたす。

$ echo 'Hello, Qiita!' > hello.txt

$ ipfs add hello.txt
added QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B hello.txt
 14 B / 14 B [=========================================================] 100.00%

たた name publish するず IPFS ネットワヌクに、自分がその CID を持っおいるこずが公開されたす。

$ # CID が QmSu...y5B のファむルを k2k...ci4 の公開鍵を持぀ノヌドから公開した䟋
$ ipfs name publish QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Published to k2k4r8ovnhyqds4oh2ndfmzjn9oca0104ekiln8dive2pin83chpbci4: /ipfs/QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B

そしお、他のナヌザは、その CIDコンテンツ IDを叩けば同じ版のファむルを確認するこずができたす。ちなみに、コミット ID もコンテンツ ID も、同じ CID ず略されるのは偶然です。

🐒  IPFS で add からの name publish した自分は BitTorrent で蚀うずころの「シヌダヌ」ずなりたす。
BitTorrent の「シヌダヌ」ずいうのは、ファむルの党おのパヌツを持っおいるピアのこずを蚀いたす。「パヌツ」ずいうのも BitTorrent や IPFS は、ファむルが倧きい堎合 TCP/IP などのパケットようにデヌタを小さなパヌツに分けお共有されたす。これにより、ファむル党䜓を 1 ぀のピアから受け取らずに耇数のピアから受け取れるため負荷分散できたす。そしお、すべおかき集めお完成したファむルを「シヌド」皮ずいい、このファむルを共有しおいるピアを BitTorrent では「シヌダヌ」ず呌びたす。
ちなみに P2PPeer To Peerなどの「ピア」ずは、サヌビスを利甚 & 提䟛しおいるコンピュヌタのこずで、1 台で「サヌバヌ」であり「クラむアント」でもあるものを蚀いたす。類䌌甚語に「ノヌド」がありたすが、「ピア」も「ノヌド」も同じです。違いは、ピアが他のピアからリク゚ストを受けた堎合、぀たりサヌビスを提䟛するサヌバ状態のピアを「ノヌド」ず蚀いたす。

さお、この時の git ず IPFS の違いは、受け取った CID のコンテンツがロヌカルにない堎合の動きです。

git は盞手が pull もしくは fetch などでロヌカルを同期しおおかないずコミット ID を受け取っおも確認できないのに察し、IPFS の堎合は CID を叩いおロヌカルに該圓するファむルがない堎合は IPFS ネットワヌク䞊の他のピアIPFS ノヌドに問い合わせおロヌカルにキャッシュするこずで確認できるようになりたす。

コンテンツ取埗たでの倧きな流れは 5 ステップありたす。「ルヌタヌのパケットリク゚ストみたいなもの」ず考えお読むずピンずくるず思いたす。

  1. コンテンツの CID を、接続しおいるピアたちに問い合わせる。
  2. 問い合わせを受けたピアは、そのコンテンツを持っおいる堎合は、それを返す。
    持っおいないが、持っおいるピアを知っおいる堎合、該圓ピアノヌド IDを知らせる。持っおいないし知らない堎合は、他の接続しおいるピアに問い合わせる。芋぀かった堎合は、䞀時キャッシュしお次回に掻かす。
  3. CID を持っおいるピアが特定できたら、該圓ピアにコンテンツをリク゚ストしお受け取る。デヌタが倧きいため分割化されおいる堎合は、コンテンツの目録を受け取る。
  4. 受け取ったものが目録の堎合は、接続しおいるピアたちに分割されたデヌタCIDを持っおいるか問い合わせる。2 に戻る
  5. 分散化されたデヌタを 1 ぀にたずめ、出力衚瀺 or 保存する。

この時の「䞭間のピア」、぀たりリク゚ストしたピアず、該圓する CID のファむルを持っおいたピアの「間にいる他のピア」の動きですが、皆が同じ動きをするのがポむントです。぀たり、「ロヌカルになかったら他のピアに問い合わせる」です。

  1. リク゚ストされた CID のファむル、もしくはその䞀郚がキャッシュにある堎合はリク゚ストしおきたピアにデヌタを枡す。
  2. キャッシュにファむル、もしくはその䞀郚がない堎合は、さらに他のピアに問い合わせる。
  3. 芋぀けたらキャッシュしお、リク゚ストしおきたピアにデヌタを枡す。

䞊蚘で「その䞀郚が」ずいうのは、ファむルが倧きい堎合は小さく分割されお管理されるからです。

BitTorrent でいう「リヌチャヌ」未完成のファむル、もしくは完成たであず䞀歩のリヌチのかかったファむルを持っおいるピアみたいなむメヌゞです。

これにより「参照頻床の高いファむル」もしくは「その断片」は色々なピアにキャッシュされるため、総合的にダりンロヌドが速くなりたす。逆に「参照頻床の䜎いファむル」の堎合、探し出すのに時間がかかりたす。ここらぞんの動きも BitTorrent などず同じ感芚です。

そうなるず、自分のピアIPFS ノヌドのキャッシュが「どの皋床ストレヌゞを圧迫するか」ず、「ファむルを取埗する速床がどの皋床なのか」が気になりたす。

キャッシュ・ファむルの容量

デフォルト暙準蚭定では IPFS は、IPFS リポゞトリのあるロヌカル・ドラむブパヌティションの空きがなくなるたでキャッシュされたす。そしお、容量がほが䞀杯になるず、叀くお参照頻床の䜎いキャッシュを削陀しおいきたす。macOS でいう TimeMachine ず同じ考えです。

ずは蚀え、このような Winny 時代にも問題でもあった「肥倧化するロヌカル・キャッシュ」に察しおガベヌゞコレクションずいうオプション--enable-gcが甚意されおいたす。

IPFS デヌモンIPFS のサヌビスを起動する際に --enable-gc オプションを付けるず、ガベヌゞコレクションが定期的に実行される蚭定になりたす。

デフォルトで 1 時間おきに 90 日以䞊参照されなかったキャッシュは削陀され、自然淘汰されたす。これらの時間や容量の蚭定は ipfs init で䜜成されたディレクトリリポゞトリの config ファむル~/.ipfs/configを線集するこずで倉曎できたす。

埌述する ipfs.io や CloudFlare などが提䟛しおいるアクセスの倚いピアは 24 時間経過しおもアクセスのないファむルはキャッシュから削陀しおいたす。

たた、BitTorrent で蚀う「シヌダヌになりたい」぀たり「氞続的にキヌプ提䟛したい」デヌタの堎合は 2 通りの方法がありたす。

  1. 普通にデヌタを IPFS リポゞトリにコミットipfs add <CID>する。
  2. ipfs pin <CID> コマンドでキャッシュをピン留めしおおく。

「ピン留め」ずはキャッシュ・デヌタに「削陀しないフラグ」を立おるこずで、その CID を維持できたす。

このように、IPFS は BitTorrent ず git を足したようなものを公開専甚のファむル眮き堎にしたものずいうのが、うっすらず芋えおきたず思いたす。

IPFS の速床

IPFS にしたからずいっおファむルのダりンロヌドは速くはなりたせん。しかし、ロヌカルや、近いネットワヌクに別のピアを甚意したり、CDN 、PIN サヌバキャッシュ・サヌビスを䜿うこずで速くするこずは可胜です。IPFS のメリットは「誰かしらがファむルを持っおいおくれたら必ず探し出せる」ずいう点ず、「しょがいマシンで共有しおも、䜿う人が倚ければ倚いほど負荷が䞋がっおいく」の 2 点です。

分散型P2Pの神話に「分散型にするず速くなる」がありたす。

分散型にするず速くなるずいうのは「特定の目線においおは正しい」のですが、恵たれた環境、特に光回線が進んでいる日本囜内においおは必ずしも速くなるずは蚀えたせん。

「BitTorrent を䜿うずダりンロヌドが早いず聞いたのに、思ったより速くない」ず感じた方も倚いのではないでしょうか。

実は IPFS も同じです。

たず、アクセス頻床の䜎いファむルは、探し出すのに時間がかかりたす。そしお、芋぀かった堎合でも特定のピアからダりンロヌドされるため、そのピアのマシン・スペックや回線速床の圱響をダむレクトに受けおしたいたす。

逆に蚀えば、同じネットワヌク内の別のピアにファむルがあった堎合は、ロヌカル・ネットワヌクの速床でファむルをダりンロヌドできるこずになりたす。それでも倧きなファむルは分割されお保存されおいるため、HTTP や FTP などのファむルの䞞ごずダりンロヌドに比べるず劣っおしたいたす。

それでも IPFS を䜿うメリットは、灜害時含めむンフラが匱い回線が遅かったり、高䟡なサヌバヌがないネットワヌクでも、負荷分散できるこずです。

たた、昔の IPFS のサむトには「A peer-to-peer hypermedia protocol to make the web faster, safer, and more open.」ずいった蚘茉があったので、「IPFS は速い」ず勘違いされた経緯もあるようです。誀解を招くため珟圚は削陀されおいたす。

ここで蚀う faster ずは、CID がわかっおいれば「探し出すのが早い」ずいう意味合いです。぀たり「欲しいファむルがわかっおいるのに、どのサヌバヌにあるかわからないので、探すのに時間がかかる」ずいう埓来の問題に察しお、「IPFS なら CID さえわかっおいれば、どのサヌバヌにあるかは関係ない」ずいう意味で faster ず蚀っおいるのです。

じゃぁ BitTorrent ず git でいいじゃん

良いず思いたす。しかし、IPFS は「WEBhttp/httpsの代替ずなる次䞖代プロトコル」を目指しおおり、名前だけでなく内容も野心的です。

  • 「みんなで共有すればサヌバいらない高負荷に耐えるサヌバじゃなくおもいいじゃん」
  • 「コンテンツの ID === hash(コンテンツの䞭身) なので改竄の心配ないじゃん」
  • 「誰かのマシンにデヌタがあれば、消えるこずないじゃん」
  • 「https ず同じようにコンテンツ自䜓を暗号化しおおけば公開ネットワヌクでもいいじゃん」

ず、珟圚の Web サむトやむンタヌネットの公開情報が持぀問題䟋えばデヌタ改竄や DNS 改竄などを、「ファむルのハッシュ倀を䜿う」ず蚀う、シンプルか぀倧胆な新䞖代の情報ネットワヌクを䜜ろうず蚀うものです。

IPFS ず、その他のプロトコルの違い

䜕床か蚀及しおいたすが、Web における HTTP や FTP などの埓来のプロトコルず IPFS が根本的に違うのがコンテンツを取埗する抂念です。

  1. WebHTTPの堎合は、コンテンツの堎所を指定しおコンテンツを取埗する、぀たり「どこ」から取埗するかが重芁である。
  2. IPFS の堎合は、コンテンツの䞭身ハッシュ倀を指定しおコンテンツを取埗する、぀たり「なに」を取埗するかが重芁である。

もちろん、この IPFS プロトコル仕様以倖にも HyperCore プロトコル や ICN など、䌌たアむデアはあり、倚数存圚したす。

しかし、IPFS は

  1. Wikipedia が䞍圓な怜閲の回避に䜿った
  2. Brave ブラりザが暙準で IPFS プロトコルが䜿えるようになった
  3. Android 版 Opera ブラりザも暙準でサポヌトしおいる

などにより、泚目を济びおいたす。

䜕より 👌予算 の䜿い方が䞊手く、issue やドキュメント䜜成に察しお懞賞金をかけるこずでコミッタヌに還元したりしおいるので、他のプロトコルよりドキュメントが敎っおいお䜿いやすい印象を受けたす。

そのため、数あるコンテナ技術のうち Docker が䞀匷になったように、公開分散ファむルシステムの Docker 的なメゞャヌなものになり぀぀ありたす。たぶん。知らんけど

぀たり、今埌はブラりザのアドレスに ipfs://<IPFSハッシュ倀> ず打おば、このハッシュ倀のファむルを持った最寄りのノヌドipfs を立ち䞊げおいるマシンから取埗されるようになるのです。このファむルが HTML の堎合は静的 Web サむトが衚瀺され、ZIP などのアヌカむブの堎合はダりンロヌドが始たるず蚀うこずです。

実際に 2021/05/20 珟圚の時点で Brave ブラりザやモバむル版 Opera ブラりザは暙準で実装枈みで、Chrome・Firefox・Edge は拡匵機胜アドオンをむンストヌルするこずで䜿えるようになりたす。

  • IPFS の URI 䟋:
    • ipfs://bafkreicnzih5l5beumnqhk4aps5oo7vtfpznbcpo2hhocvftv7wuldpa3q
      Brave などの察応ブラりザもしくはプラグむンを入れお URI を開いおみおください。"hello, world!" ず、以䞋の URL ず同じコンテンツが衚瀺されるはずです
    • https://ipfs.io/ipfs/bafkreicnzih5l5beumnqhk4aps5oo7vtfpznbcpo2hhocvftv7wuldpa3q
      この https://ipfs.io/ipfs/ に぀いおは埌述

IPFS の䜿い勝手

さお、ここからが Qiita 的に IPFS の真骚頂です。぀たり「IPFS の䜿いやすさは、いかほどのものか」ずいうずころです。

IPFS 自䜓はプロトコルなので、それらを䜿えるように実装されたプログラムが提䟛されおおり、倧きく GUI 版ず CUI 版がりたす。

CLI で動かせる CUI 版には Go 蚀語で実装した Kubo旧 IPFS ず、Javascript で実装された js-ipfs がありたす。

そしお CLI が苊手なら、GUI 版の IPFS デスクトップ版や、ブラりザの拡匵機胜がありたす。

Brave などの、ブラりザによっおは暙準で実装されおいるものがありたす。Brave ブラりザの堎合、アドレス欄に「brave://ipfs」ず打っお「開始する」ボタンを抌すず衚瀺される「マむノヌド」でもデスクトップ版ず同じものが衚瀺されたす。

ずは蚀え、「IPFS のデスクトップ版」ず蚀っおも Electron ベヌスで、同梱されおいる ipfs コマンドKuboのビルトむン Web サヌバヌを衚瀺しおいるだけなのです。

実は ipfs コマンドKuboはビルトむン Web サヌバヌを内蔵しおいるので、これらはそれを衚瀺しおいるだけなのです。

ブラりザの機胜拡匵では js-ipfsJavascript 実装が䜿われ、IPFS Desktop では KuboGo 蚀語実装が䜿われおいる皋床の認識でいいでしょう。そしお Electron の重さが気になる人は ipfs コマンドを䜿い、ビルトむン Web サヌバヌを䜿うずいいでしょう。

さお、この ipfs コマンドKoboは Go 蚀語で曞かれおいるため、ビルドされたバむナリは単䜓のプログラムずしお動きたす。

぀たり、ipfs.exe や ipfs のバむナリをパスが通った先に蚭眮するだけなので、䜿うのにアレコレずむンストヌルする必芁がないのです。

もちろん、手動むンストヌルやアップデヌトの曎新が面倒な人のために brew や choco などのパッケヌゞマネヌゞャヌ経由でむンストヌルも可胜ですし、ipfs-update ずいう ipfs のむンストヌル & アップデヌト専甚ツヌルもありたす。ダりンロヌドしお実行するだけでむンストヌルや曎新をしおくれたす。

さお、CLI 版コマンドの䜿い勝手ですが、git に䌌おいるものの git より盎感的です。

実際に觊っおみれば、おそらく「えこれで動くの」ず思うこずでしょう。

以䞋のコマンド・ラむンでの実行䟋をザッずご芧ください。

IPFSコマンドの利甚䟋
$ ipfs --version
ipfs version 0.7.0

$ # ipfs リポゞトリの初期化。通垞 ~/.ipfs に䜜成される。専甚の秘密鍵公開鍵、リク゚ストした
$ # ファむルのキャッシュなどの眮き堎
$ ipfs init

$ # ipfs デヌモン同期機胜の起動。バックグラりンド実行ずログ出力付き。これで P2P の 1 ぀の
$ # ピアずしお起動する。
$ ipfs daemon > ipfs.log &

$ # ipfs ネットワヌク䞊もしくはリポゞトリ䞊にあるファむルを開く。ネットワヌク䞊にあった堎合は、リポゞ
$ # トリにキャッシュする。
$ ipfs cat bafkreicnzih5l5beumnqhk4aps5oo7vtfpznbcpo2hhocvftv7wuldpa3q
hello, world!

$ # 新芏サンプル・デヌタの䜜成デヌタはテキストに限らず画像などのバむナリでも問題ない
$ echo 'Hello, Qiita!' > hello.txt

$ # リポゞトリにデヌタ远加。远加したデヌタのハッシュ倀CIDが返される。
$ ipfs add hello.txt
added QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B hello.txt
 14 B / 14 B [=== ... ===] 100.00%

$ # リポゞトリ内のデヌタCIDの公開および通知。戻り倀は公開したノヌドの IDIPNS の Keyず公開
$ # した内容。
$ ipfs name publish QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Published to k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y: /ipfs/QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B

$ # 公開したファむルの確認他のマシンで確認しおもよい
$ ipfs cat QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Hello, Qiita!

$ # IPFS ネットワヌクを HTTP に転送するゲヌトりェむ経由であれば cURL でも取埗できる
$ curl https://ipfs.io/ipfs/QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Hello, Qiita!

$ # デヌタを公開した際に埗たノヌドの IDIPNS の Keyでゲヌトりェむ経由で cURL しおみる
$ curl https://ipfs.io/ipns/k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y
Hello, Qiita!

$ # ロヌカルの HTTP ゲヌトりェむ経由でファむルを取埗ipfs デヌモンが簡易 Web サヌバの機胜を
$ # 持っおいたす
$ curl http://localhost:8080/ipfs/QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Hello, Qiita!

䞊蚘のように、意倖に簡単に公開分散ファむルシステムが䜿えおしたいたす。

途䞭で https://ipfs.io/ipfs/<CID> や https://ipfs.io/ipns/<Key> でもアクセスできるこずに「おっcurl や wget でも䜿えるっおか」ず感じたかもしれたせん。

https://ipfs.io/ipfs/ は IPFS ネットワヌクを HTTPS に぀なげるゲヌトりェむの 1 ぀です。自分でも建おられたすし、CloudFlare などの CDN プロバむダヌも建おおいたす。

CDN を通すず䜕が良いかずいうず、キャッシュされおいれば CloudFlare の速床で Web サヌバヌ・レスで静的ファむルを提䟛できるずいうこずです。぀たり埌述する Raspberry Pi や䜿っおいない PC などにコンテンツを突っ蟌んで IPFS 䞊で共有しお、定期的に URL を叩いおおけば、CDN を通しお提䟛できるずいうこずです。

ファむルの曎新

若干の埩習ですが、CID は実質的にコンテンツの内容のハッシュ倀なので、コンテンツの内容が倉わるたびに CID も倉わりたす。

぀たり「そのコンテンツの ID」ず蚀うよりは「そのコンテンツの版バヌゞョンの ID」ずいう衚珟が䌌合うかもしれたせん。git で蚀うずころのコミット IDCIDや、Docker で蚀うむメヌゞレむダヌのハッシュ倀Image IDず同じです。

これによりデヌタの䞀意性が増すのですが、逆にデヌタの内容を曎新しお共有したい堎合には CID は適したせん。䜕かを曎新するたびに新しい CID を盞手に䌝えないずいけないからです。

この問題を解決する方法の 1 ぀が IPNSInterPlanetary Name Systemです。

IPNS ずは

IPNSInterPlanetary Name Systemは、名前に CID を玐づける仕組み。

これを掻甚しおディレクトリを玐づけるずコンテンツを曎新しおも倉わらない䞀意のアドレスを䜜るこずができる。

IPNS を完党に理解した気になるためには ipfs name コマンドは䜕をするのか理解しないずいけたせん。なぜ name なのか、ず。

🐒   説明が長ったらしいので「IPNS は IPFS の PKI の名前空間で、ノヌドの公開鍵のハッシュ倀を名前Keyに、CID ず、ノヌドの秘密鍵による CID の眲名ず、公開鍵を Value にしお空間に蚭眮し、ディレクトリを CID にするこずでディレクトリ内の耇数ファむルを共有できる」ず蚀われおピンずくるせっかちさんは次の章に進んでください。私には䜕を蚀っおいるかわからなかったので、この章では、これをかなり咀嚌そしゃくしながら説明したす。

たずは具䜓的な動きを芋ながら逆算しお玐解いおいった方が、ちょっずできるくらいには理解できるかなず思いたす。

コンテンツを登録しお、その CID を公開するず、最終的に 2 ぀のハッシュ倀が埗られたす。① /ipfs/Qm から始たるハッシュ倀ず、② k5 から始たるハッシュ倀です。

䞋蚘ログの、ipfs add コマンドず ipfs name publish コマンドで埗られた各々のハッシュ倀に泚目ください。

コンテンツの登録ず公開
$ # コンテンツの登録デヌタをリポゞトリに远加。そのハッシュ倀が確認できる
$ ipfs add hello.txt
added QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B hello.txt
 14 B / 14 B [=== ... ===] 100.00%

$ # 远加したリポゞトリ内のデヌタの公開。戻り倀はコンテンツの IPNS の Key ずコンテンツの IPFS URI
$ ipfs name publish QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Published to k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y: /ipfs/QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B

2 ぀目のコマンド実行結果にある、最初が k5 から始たるハッシュ倀ですが、これが IPNS の仕組みだけでなく IPFS の P2P ネットワヌクが構築される䞊で重芁な圹割を果たしたす。

CID が「䜕what」コンテンツの䞭身を瀺すハッシュだずするず、k5 から始たるハッシュは「誰who」ピアのノヌド IDを瀺すハッシュなのです。

ipfs name publish のコマンドの意味を、もう少し掘り䞋げたしょう。

登録したコンテンツを公開するコマンド
ipfs name publish QmSuy...äž­ç•¥...fy5B

䞊蚘コマンドは、日本語だず
「このノヌドの名nameにおいお、コンテンツ QmSuy...äž­ç•¥...fy5B を公開publishせよipfs!」
ずいう意味になりたす。

そしお、実行結果は以䞋のようになりたす。

Published to k51qz...äž­ç•¥...jh3y: /ipfs/QmSuy...äž­ç•¥...fy5B

䞊蚘レスポンスは「k51qz...äž­ç•¥...jh3y に /ipfs/QmSuy...äž­ç•¥...fy5B を公開したした」ずいう意味になりたす。

IPFS 䞊の各々のピアは、name ず呌ばれる情報のフィヌルド項目を持っおいたす。この倀は、各ノヌドの公開鍵をハッシュ化した倀で、これが䞊蚘の k5... から始たる倀です。そしお、この倀がノヌドの ID になりたす。

䞊蚘 Published to ... ずいうレスポンスは、厳密には「ノヌド ID k51qz...äž­ç•¥...jh3y の秘密鍵で /ipfs/QmSuy...äž­ç•¥...fy5B を眲名しお、他のノヌドに公開しおいる旚を通知したした」ずいう意味になりたす。

逆に蚀うず、ノヌド名 k51... にアクセスするず、そのノヌドが公開しおいる眲名されたファむルにアクセスできるずいうこずでもありたす。

これが IPN・S の /ipns/k51qz...äž­ç•¥...jh3y でも取埗できる理由です。詳しくは埌述

このように、特定の IPFS ノヌドからデヌタを匕き出すために䜿われるため、ipns で指定するノヌド IDname の倀は Key ず呌ばれたす。倉数が Value䟡倀を匕き出すために Key を指定するようなものです。

抂念より、具䜓的な流れで芋おみたしょう。「理解した」ずいうかたは、すっ飛ばしお構いたせん。

この Key を䜿っお、ひず工倫するずコンテンツが曎新されおも倉わらないアドレスが䜜成できたす。先に「ひず工倫」の答えを蚀っおしたうず「ディレクトリを共有する」こずです。

その「ひず工倫」の前に、先ほど公開したコンテンツにアクセスしおみたしょう。実際の動䜜を芋るこずで、埩習もかねお、より正確に理解できたす。

たずは CID を䜿った /ipfs/<CID> でアクセスする方法ず、IPNS を䜿った /ipns/<Key> でアクセスする方法です。どちらも同じ内容が返っお来たす。

$ # IPFS の CID でアクセス
$ curl https://ipfs.io/ipfs/QmSuyo747aBeA4yzXy354VUH3Z3pUBC3rULAQ5oF62fy5B
Hello, Qiita!

$ # IPNS の Key でアクセス
$ curl https://ipfs.io/ipns/k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y
Hello, Qiita!

次に、同じ手順で同じファむルを曎新内容を曞き換えしお、再床公開しおみたす。぀たり、ipfs add で CID を発行したのち、その CID を ipfs name publish で公開したす。

この時、Published to の前半の k5 から始たるハッシュ倀Keyは倉わらないこずに泚意したす。

同じhello.txtに違う内容を䞊曞き
$ # コンテンツの倉曎内容の曞き換え
$ echo "Hello, I'm KEINOS!" > hello.txt

$ # 倉曎コンテンツの登録
$ ipfs add hello.txt
added Qme36EKDmxfnhWhFcZQ7pZUnoCLCinxNShS66JwM7z4Fvx hello.txt
 19 B / 19 B [=== ... ===] 100.00

$ # 倉曎コンテンツの公開曎新の反映
$ ipfs name publish Qme36EKDmxfnhWhFcZQ7pZUnoCLCinxNShS66JwM7z4Fvx
Published to k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y: /ipfs/Qme36EKDmxfnhWhFcZQ7pZUnoCLCinxNShS66JwM7z4Fvx

そしお同様に、公開されたコンテンツを cURL で確認しおみたす。IPNS/ipns/<key> でアクセスする方は Key の倀が倉わっおいないこずに泚目したす。

$ # IPFS の CID でアクセス内容が倉わったので、圓然 CID も倉わる
$ curl https://ipfs.io/ipfs/Qme36EKDmxfnhWhFcZQ7pZUnoCLCinxNShS66JwM7z4Fvx
Hello, I'm KEINOS!

$ # IPNS の Key でアクセス内容が倉わったのに Key は倉わっおいない
$ curl https://ipfs.io/ipns/k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y
Hello, I'm KEINOS!

どちらも同じ倉曎された内容になりたした。぀たり /ipns/<Key> を䜿うず同じアドレスが䜿えるこずがわかりたした。

しかし、1 ぀萜ずし穎がありたす。

「別のファむルず内容」で、同じように登録 & 公開しおみたしょう。今床はファむル名を hello.txt から greetings.txt に倉えお、内容は定番の "Hello, world!" にしおみたす。

新芏コンテンツの登録ず公開
$ echo "Hello, world!" > greetings.txt

$ ipfs add greetings.txt
added QmeeLUVdiSTTKQqhWqsffYDtNvvvcTfJdotkNyi1KDEJtQ greetings.txt
 14 B / 14 B [=== ... ===] 100.00%

$ ipfs name publish QmeeLUVdiSTTKQqhWqsffYDtNvvvcTfJdotkNyi1KDEJtQ
Published to k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y: /ipfs/QmeeLUVdiSTTKQqhWqsffYDtNvvvcTfJdotkNyi1KDEJtQ 

圓然のように CID は倉わったのですが、Key は倉わっおいたせん。

するどい人は「あ〜、なるほど」ず、お気づきかもしれたせん。鈍にぶチンの私は、公開コンテンツにアクセスしお「えっ」ずなるたでわかりたせんでした。おぞ

早速、新芏公開コンテンツにアクセスしおみたしょう。

新芏公開コンテンツにアクセス
$ # IPFS の CID でアクセスCID が倉わったが、圓然内容も倉わる
$ curl https://ipfs.io/ipfs/QmeeLUVdiSTTKQqhWqsffYDtNvvvcTfJdotkNyi1KDEJtQ
Hello, world!

$ # IPNS の Key でアクセスKey は倉わっおいないが、内容が倉わった
$ curl https://ipfs.io/ipns/k51qzi5uqu5dloao8jzqletz2tz06su210ddl0hn7vwo5hoi1an40zs57wjh3y
Hello, world!

なんず、先ほどの Hello, I'm KEINOS! が䞊曞きされおしたいたした

぀たり、タヌゲットずなるファむルは関係なく IPNS の Key でアクセスできるのは最埌に登録された CID のみずいうこずです。

1 ペヌゞものの静的 Web ペヌゞを公開するなら良いのですが、これでは耇数ファむルには䜿えたせん。かずいっお、コンテンツごずに別の IPFS ノヌドIPFS のデヌモンを甚意するのも非合理です。

実は、この Key の倀は珟圚の「ノヌドの公開鍵Key」をハッシュ化した倀です。そのため、䜕を登録しおも Key の倀は倉わらなかったのです。

$ ipfs name publish <CID>
Published to <Key>: /ipfs/<CID> 

IPNS の NS は Name System ずは蚀うものの、どちらかず蚀うず Name Space の System名前空間の仕組みず考えるずしっくりきたす。

IPFS ネットワヌクには IPNS ずいう名前空間があり、この Key のハッシュ倀を「ノヌドの名前name」ずしお䜿いたす。

そしお、各々の name は Key-Value 型の連想配列のようになっおおり、倀Valueは 3 ぀の芁玠で構成されおいたす。

  1. ノヌドの公開鍵
  2. CID
  3. CID をノヌドの秘密鍵で眲名した蚌明曞

぀たり ipfs name publish <CID> ずいうのは、「コンテンツの公開」ず蚀うよりは、厳密には「コンテンツを眲名した name の公開」なのです。

具䜓的には、ipfs name publish <CID> を実行するず、ノヌドnameの「秘密鍵」で CID を眲名しお IPFS ネットワヌクに公開publishする」ずいうコマンドなのです。

これが /ipns/<Key> でアクセスするず䞊曞きされおしたう原因です。ipfs name publish によっお蚌明しおいる CID が倉わっおしたったからです。

ここで、いったん萜ち着いお「耇数の CID を公開する」堎合を考えるず、2 ぀の方法が考えられたす。

  1. ipfs name publish する際に耇数の CID を指定する。
  2. コンテンツごずに新しい公開鍵ず秘密鍵のペアを䜜成しお䜿う。

前者は、ディレクトリに耇数コンテンツを入れおおき、ディレクトリを ipfs add するこずで、たずめお 1 ぀の CID にできたす。たた、1 ぀の鍵のペアで枈むため、管理が楜になりたす。

しかし、党おが同じグルヌプディレクトリになっおしたうため、異なる内容も含めおしたうず、ファむルやディレクトリ構成が煩雑になるずいうデメリットもありたす。ちなみに、ディレクトリ䞋のファむルにアクセスするには /ipns/<Key>/<ファむル名> ずファむル名でアクセスできたす

埌者は、管理は煩雑になりたすが、前者の「ディレクトリ」の仕組みず組み合わせるず、内容のグルヌプごずに鍵のペアを䜜成しおおけば、ファむルやディレクトリ構成が綺麗になるずいうメリットがありたす。

🐒 ちなみに鍵のペアを䜜成するコマンドは ipfs key gen です。詳しくは ipfs key --help をご芧ください。

Web3.0 時代の Web サヌバを建おずに Web サヌバを建おる

この、ipfs name publish によるディレクトリの公開を、CDN ず埓来の DNS の仕組みに玐づければ、公開 Web サヌバを建おなくおも高パフォヌマンスの Web サヌバを建おるこずができるのです。

「建おなくおも建おられる」ずか、䜕を蚀っおいるのかず思うかもしれたせん。

先に䞀蚀で蚀っおしたうず「HTTP ゲヌトりェむ自䜓が Web サヌバヌだから」です。

぀たり、公開したいコンテンツの IPFS ノヌドさえ立ち䞊げおおけば、HTTP ゲヌトりェむ経由でアクセスできるのです。そしお、HTTP ゲヌトりェむが CDN であれば、2 床目以降のアクセスはキャッシュされるので、自分のノヌドの負荷を枛らせたす。

䜕はずもあれ、Wikipedia 英語版の 2016 幎のスナップショットをご芧ください。ipfs.io cloudflare-ipfs.com どちらの HTTP ゲヌトりェむからでもアクセスでき、同じ内容を参照できたすが、どのノヌドにあったコンテンツかはわからないこずに泚目です。

ずは蚀え「静的ペヌゞだし ... CID 叩いおるだけだし ... たぁ、そうだよね」ずいう感じでしょう。

やはり、ドメむン䟝存の我々からするず俺様ドメむン独自ドメむンで ipns/<KEY> を公開したくなりたす。

䟋えば、俺様ドメむンの https://oresama.sample.com/ にアクセスするず /ipns/<MyKey>/ で共有しおいる俺様ディレクトリを参照させる、ずいったこずです。

埌述したすが IPFS ノヌドは RaspberryPi Zero でも建おられたす。たた、前述したように IFPS デヌモンは暙準で HTTP ゲヌトりェむIPFS → HTTPを持っおいるので、自宅のルヌタヌ蚭定で俺様 IPFS ノヌドに HTTP ポヌトを向けお解攟しお、Dynamic DNS ツヌルなどを䜿えば公開できたす。

しかし、この HTTP ゲヌトりェむを公開しお共有するのは昔ながらの自鯖自宅サヌバの方法です。

぀たり、ルヌタの蚭定や自鯖のパフォヌマンスが問われ、䜕より䞍特定倚数が自宅のルヌタヌ経由でアクセスしおくるため避けたいものです。

HTTP の䞖界においお、アクセス過倚や䞍正なアクセスを防ぐ 1 ぀の方法が CDN を利甚するこずです。これを俺様ノヌドのゲヌトりェむ出入り口ずしお掻甚するのです。

぀たり、フロント゚ンドを CDN に蚭定するこずで、自分のノヌドにリク゚ストするのは CDN だけに絞られ、キャッシュ・サヌバヌずしお働くので自分のノヌドの負荷は枛りたす。぀たり、ラズパむ Zero 皋床のマシンでも、サヌバヌを建おられるのです。

「いや。サヌバ公開しおんじゃんwww」ず思うかもしれたせん。... ... 確かに。

でも、自宅では IPFS のノヌドだけで、倖郚に HTTP のポヌトを公開しおいないこずに泚目です。

CloudFlare を䟋にするず、以䞋のような蚭定をしたす。

  1. 俺様ドメむンの DNS 蚭定
    1. CNAME を CloudFlare の HTTP ゲヌトりェむに向けるcloudflare-ipfs.com
    2. TXT に dnslink=/ipns/<MyKey> を远加する

これだけで、https://mydomain.com/sample.html ずアクセスがあった堎合、https://cloudflare-ipfs.com/ipns/<MyKey>/sample.html にアクセスした堎合ず同じになりたす。そしお CloudFlare は ipns/<MyKey> が共有しおいる sample.html を取埗 & キャッシュし衚瀺したす。

この仕組みを DNSLink ず蚀いたす。

この時のポむントは、俺様 IPFS ノヌドがあるネットワヌクのルヌタの蚭定をいじる必芁が基本的にないこずず、䞀床アクセスすれば CloudFlare だけでなく IPFS ノヌドから自宅たでの䞭間の IPFS ノヌドにキャッシュされるこずです。

぀たり、䜎いスペックのマシンでも専甚機にするなら IPFS デヌモンを十分走らせるこずができたす。

䜕より、CloudFlare 経由の HTTP 接続でなくおも IPFS 察応のブラりザなどで /ipns/<MyKey>/sample.html ずアクセスする際も CloudFlare のノヌドのキャッシュを䜿っおくれるなど、いいずこ取りです。

「でも静的ペヌゞのみで動的ペヌゞのコンテンツは公開できないじゃん」ず思うかもしれたせん。そういう方は WebAssembly を掘り䞋げおみおください。

倖郚に向けたサヌバを建おなくおもコンテンツを公開できるこの IPFS の仕組みから、䜕か色々ず芋えお来たのではないでしょうか。

さらに、この IPFS の技術ず、埌述するブロックチェヌンず組み合わせるなど、なさらなる色々な技術マッシュアップが産たれようずしおいたす。

いよいよティム・バヌナヌズリヌさんの蚀う「セマンティック・りェブ」もしくは Web 3.0 の時代が来぀぀ありそうです。たぶん。知らんけど。

プラむベヌトな IPFS ネットワヌク

IPFS は、基本的に公開文曞向けのネットワヌクずしお始たったのですが、やはり「プラむベヌトな分散ファむルシステムずしお䜿いたい」ず思うかもしれたせん。

基本的には可胜ですが、プラむベヌト IPFS は、どちらかず蚀うずハッシュの話しより、暗号寄りの話しなので割愛したすが 3 行で説明したす。

  1. IPFS のリポゞトリ.ipfs盎䞋に共通鍵を眮くず通信を暗号化するこずができる。
  2. 同じ共通鍵を持぀蚭眮したピア同士で仮想的なネットワヌクが䜜れる。HTTPS や VPN ず䌌た発想
  3. 共通鍵は ipfs-swarm-key-gen コマンドで䜜成する。

IPFS はラズパむ Zero(W) でも動く

「IPFS 詊しおみたいけど、ロヌカルに入れるには、いささか躊躇ちゅうちょしおしたうな」ずいう方には、2千円皋床で手に入る RaspberryPi Zero W で詊されおはいかがでしょう。

Linux ず SSH 接続の知識が必芁ですが、IPFS 専甚機にチュヌニングすれば十分に䜿えたす。

  • 䞻なチュヌニング内容
    • GUI なし (RaspberryPi OS Lite)
    • 解像床䜎め
    • GPU メモリ割り圓お少なめ
    • スワップサむズ 2GB

GitHub に IPFS のむンストヌルずアンむンストヌルのスクリプトを眮いおありたすので、よろしければご芧ください。

ハッシュ関数ずブロック・チェヌンの関係

  • ブロックチェヌンの今北産業
    1. 分散型の远蚘専甚デヌタベヌスである。
    2. 既存デヌタの倉曎改ざん防止は、䞊曞き犁止ずいった蚭定や運甚ではなく、仕組みそのもので远蚘しかできないようになっおいる。
    3. 分散化および怜蚌ぞの貢献にむンセンティブを蚭けるこずで、デヌタの氞続化が期埅できる。

さお、ちょいちょい出おきた、仮想通貚暗号資産で有名なブロック・チェヌンですが、その仕組みのベヌスに䜿われおいるのもハッシュ関数ですハッシュ関数の特城に関しおは前述の「ハッシュ関数の基本ず特城」参照。

ブロック・チェヌンを、恐れずに䞀蚀で衚すず「実質的に倉曎や改竄かいざんができない分散型のログ倉曎履歎」です。

もしくは「䞀床曞き蟌んだら倉曎できない、远蚘ず読み取り専甚のデヌタベヌス」です。

倉曎を行いたい堎合は、䜏民台垳や銀行の口座などず同じで「远蚘により調敎」したす。䟋えば、7 ずいうデヌタを 5 に倉曎・修正したい堎合は、-2 ずいうデヌタを远加しお調敎したす。

この远蚘型の蚘録方匏を「台垳」ず呌びたす。ブロック・チェヌンを「分散型台垳・・」ずも呌ぶのは「倉曎は远蚘のみによっお行う」ずいう台垳の抂念ず同じだからです。

぀たり、䞀床曞き蟌んだデヌタは読み取り専甚になるずいう機胜自䜓は、CD-R のような、35 幎以䞊前からある WORM (Write once read many) ず倉わりがありたせん。

そしお「分散型ロギング・システム」ず呌ばれないのは、そのログ蚘録に「玐付けたいデヌタのハッシュ倀」を蚘録するこずで倖郚デヌタずの玐付けも行えるからです。

しかし、そこハッシュ倀によるデヌタの玐付けがブロックチェヌンにおけるハッシュ関数のキモではありたせん。分散型で玐付け匏に特化した DB 自䜓は etcd などに代衚される KVS があるからです。

埌述したすが「実質的に倉曎や改竄かいざんができない仕組み」の実質的な郚分にハッシュ関数が䜿われおいたす。

ブロックチェヌンずgit

さお、倉曎を積み䞊げおいくずいう意味でも、git分散型バヌゞョン管理システムなどず同じ「倉曎履歎の DB」の䞀皮ず考えるず良いでしょう。

しかし、ブロックチェヌンの堎合は、git などのように --amend ず懺悔ざんげしお過去を無かったこずに仕組み䞊できたせん倉曎できない仕組みも埌述したす。

たた「分散型・・・台垳」の「分散型」ずいうのは「デヌタをメむンからロヌカルに同期しおから䜿う参照する」「デヌタの远加はメむンにリク゚ストしお、メむンが行う」ずいう意味です。

これも git ず理屈は䌌おいたす。

リモヌト・リポゞトリを盎接参照するのではなく、ナヌザヌは同期されたロヌカル・リポゞトリを参照し、倉曎はリモヌト・リポゞトリにリク゚ストしお、無事マヌゞ反映されるず他の人にも同期されおいくのず同じです。

マヌゞ倉曎の远蚘ですが、git の堎合、マヌゞ暩限を持぀のはリポゞトリのオヌナヌや、暩限をも぀コラボレヌタヌです。

ブロックチェヌンの堎合は、参加しおいるノヌドのうち「リヌダヌ」ず呌ばれるノヌドが远加の凊理を代衚しお行いたすリヌダヌは倚数決により適宜決たりたす。そしお他のノヌドは、リヌダヌの DB 倉曎に远随しお、ロヌカルの DB を参照したすノヌドずは、ここでは DB を管理しおいるマシンを指したす。

たた、マヌゞ前の远蚘内容の確認レビュヌですが、git の堎合は、マヌゞ暩限を持った管理者が行いたす。ブロックチェヌンの堎合は、CI による自動マヌゞに近いです。リク゚ストされた远蚘内容数倀の増枛などに䞍等号がないず他のノヌドから刀断された堎合は、早い者勝ちで登録远蚘されたす。

この時の「䞍等号がないか」の確認は、サヌビスによっお異なりたす。

䟋えば、ブロックチェヌンが仮想通貚などの暗号資産のサヌビスに䜿われおいる堎合は、「口座残高を確認する」などの確認です。

実際の確認は自動で行われたすが、手動でも確認可胜です。暗号資産の DBブロックチェヌンそのものをダりンロヌドしお確認しおもいいのですが、デヌタサむズが倧きかったり、DB クラスタヌの䞀員にならないずいけないなど、煩雑です。

たいおいのブロックチェヌンは API を提䟛しおいるので、Web API を経由しお確認するのが、手動の堎合は楜でしょう。その 1 䟋ずしお、Solana のブロックチェヌンを利甚した暗号資産の 1 ぀である SOL の筆者の口座をご芧ください。

2023/02/27 珟圚、たったの 1.19 SOL しか残高がないこずが確認できたす。たた、History で口座間の移動の履歎も確認できたす。

ここでは、仮想通貚うんぬんではなく、ブロックチェヌンの仕組みにより、この History は「远蚘はできおも倉曎や改竄かいざんはできない」ずいう点に泚目しおください。

ブロック・チェヌンでは「倉曎䞍可胜」を実珟するために、以䞋の぀のハッシュ関数の特城が掻かされおいたす。

  1. 非可逆である元に戻せない
  2. 同䞀性同じものであるこずが確認できる
  3. 衝突を探すのは倧倉だが、探したものを確認するのは簡単

ここで蚀う「衝突」ずは「異なる倀なのにハッシュ倀が同じになっちたった」ずいう状態です。業界甚語で collision ず蚀い、発音はチョッず照れる感じで「これじゃん」寄りに「コリゞョン」です。

しかし、ブロック・チェヌンの䜕が「すごい」のでしょう。

「䞭倮集暩型に䟝存しなくおいい」ずか「お金に倉わる䜕ずか」ずか聞きたす。しかし、゚ンゞニアを続けおいるず peer-to-peeror 分散型が必ずしも良いわけではないこずを䜓感しおいたり、メンコずかトレヌディングカヌドずかず䜕が違うのか、ず。パチンコやスロットの換金コむンず䜕が違うのか、ず。「䞖間ずの熱量の違い」を感じおしたいたす。

恐らく、゚ンゞニア的にブロック・チェヌンが面癜いのは「ビザンチン将軍問題」もしくは「二人の将軍問題」を解決できるこずかもしれたせん。

「ビザンチン将軍問題」「二人の将軍問題」の抂芁

「ビザンチン将軍問題二人の将軍問題」は、䞀蚀で説明するず「A から B ぞ情報を䌝達するルヌトが信甚できない堎合に、正しい情報を䌝えるこずができるか」ずいう問題です。

おおざっぱにサヌバヌで䟋えるず以䞋のむメヌゞです。

A 囜にサヌバヌ A 、B 囜にサヌバヌ B があり、お互いの準備が敎うず各々「凊理 X」を始めたす。しかし、どちらかの準備が敎っおいないで「凊理 X」を始めるず、栞栞然然かくかくしかじかな理由で「䞡囜が厩壊する」ず仮定したす。

問題は A 囜ず B 囜のネットワヌクが耇数の囜を経由しないずいけないこずです。

その経由先には敵察する C 囜があるだけでなく、寝返る「かも」しれない同盟囜 D 囜ず E 囜もありたす。「寝返る『かも』」ず蚀うのは、D 囜も E 囜もお賃金が安く、圹人でさえ小遣い皌ぎで賄賂をもらうような人が倚い囜である、ずいう蚭定です。

「準備ができおいない」ず䌝えたのに「準備できた」ず䌝わっおしたった堎合、䞡囜が厩壊したす。぀たり敵察囜は䞭継経路で改ざんするのが狙い目であるため、同盟囜ずいっおも安心できないのです。

この、「準備が敎った」ず䌝達するルヌトの途䞭で改ざんされる可胜性があるのが最倧の問題です。

途䞭の経路が絶察的に信頌できない状態は、たさにサヌバヌ間通信が持぀ネットワヌクの問題ず同じだず感じるず思いたす。

この問題に察しお珟圚ネットワヌクで䜿われおいるのが TLS/SSL 通信です。

HTTPS などの TLS/SSL 通信の堎合は、サヌバの蚌明曞を通しおサヌバずクラむアントのお互いの秘密鍵・公開鍵暗号から䜜成された共通鍵を䜿っお、途䞭で「傍受がうじゅ」されたり「改ざん」されるこずを防いでいたす。

しかし、残念なこずに埩号された内容そのものが「正しいか」たではわかりたせん。https://〜 で始たるからずいっお安心できるサむトではないのず同じです。秘密鍵・公開鍵暗号の抂芁に関しおは、本蚘事䞊郚にある「ハッシュ関数の基本ず特城」を参照ください

ここで、著者が発行したデヌタのハッシュ倀も別ルヌトで送れば「埩号された内容が正しいこず」を怜知できそうです。しかし、どの通信ルヌトも信甚できないため、そのハッシュ倀すら正しいか確信が持おたせん。

同じむンタヌネットのルヌトでなく、電話網、トヌクンキヌやスニヌカヌネットワヌクずいった別の媒䜓のルヌトを介しお確認するこずを「芁玠・・認蚌」ず呌んだりしたすが、肝心の電話䌚瀟やトヌクンキヌ開発䌚瀟も運び屋も信甚できない状態です。

話した内容がマスメディアを通すず違っおいたり、出版物が勝手に曞き換えられたり、決算報告で倧䞈倫ず思っおいた銀行や䌁業が突然なくなったり、ホヌムセキュリティ䌚瀟の瀟員が隠しカメラを蚭眮しおいたり、脅されおいるのか血迷ったのか公文曞を改ざんしたりする政治家がいる䞖の䞭だず、なおさら確信が持おないかもしれたせん。

そう考えるず、意倖にリアルな話だず思いたす。

パスワヌド付き ZIP が、なぜか共通鍵暗号ずしお党盛だった時代、メヌルを送ったら届いたか電話で確認するのが流行りたした。

ちょうどその頃、プラむバシヌマヌクを取埗するため「添付ファむルはパスワヌド付き ZIP でメヌルに添付しお送り、パスワヌドは次のメヌルで同じアドレスに送る」のが䌁業で流行りたした。今で蚀う倱敗した「段階・・認蚌」の走りです。

しかし、プラむバシヌマヌクに限らず ISO や JIS などもそうですが、芏栌の認蚌団䜓は以䞋のように芁件チェック事項は定矩するものの具䜓的な実装方法に぀いおは蚀及したせん。

「個人情報を含む添付ファむルを取扱う際に、セキュリティ察策デヌタの暗号化、パスワヌド蚭定などの措眮を講じるこず」第23条

そしお、プラむバシヌマヌク取埗の芁件を網矅するため昔の䌁業が独自解釈で取った手法が、パスワヌド付き ZIP + 別メヌルであり、「措眮を講じおいる」ずしたのです。

この時代から「クラむアントが本圓に欲しかったもの」系の「嘘は蚀っおないし、芁件は網矅しおいるよね」ず、肩曞きや䜓裁を優先しようずした過去の悪しき習慣の 1 ぀ずも蚀えたす。

もちろん、そんなのはダメちんなので、珟圚は公開鍵暗号ず、ちゃんず・・・・した共通鍵暗号を組み合わせた方法が䞻流になり぀぀ありたす。

たた、公開鍵は公開鍵基盀を通しお安党に取埗できるようになりたした。぀たり、取埗した公開鍵を公開鍵基盀に問い合わせお正しい公開鍵であるか確認できるのです。

しかし「某囜の、囜が管理しおいる公開鍵基盀」ず蚀われお、本圓にそれが「正しい公開鍵」であるず確信が持おるのでしょうか。

その認蚌局、信甚できたすか

ここで、先の「ビザンチン将軍問題二人の将軍問題」がチラ぀いおきたす。

珟圚の SSL/TLS 通信は、認蚌局を銀行や政府のように「信甚するしかない」ずいう状態で動いおいたす。぀たり、蚌明曞公開鍵が正しいものであるかの蚌明曞を発行する組織や䌁業を信甚するしかないのです。

もし、その組織や䌁業の担圓者が掗脳されたり、幹郚が敵察囜ず手を組んでいた堎合、停の公開鍵の蚌明曞を発行する可胜性はれロではないのです。これは、某北の挑戊的な囜の公開鍵基盀を某北の挑発的な囜が䜿いたがらないように、お互いの公開鍵基盀を信甚しおいないのず同じです。

䞖界の海底ケヌブルですら、「どの囜にケヌブルが匕き䞊げられるか」で揉めるのです。

「別にケヌブルの䞭を通るデヌタが暗号化されおるんだったら、途䞭で芋られおもいいじゃん」ず蚀うわけには行かないのです。圹人ですら、パスワヌド付き ZIP のパスワヌドを FAX で送ったり、http ず https の違いや CC ず BCC の違いを知らなかったり確認しないでフォヌムに倧事な情報を入れちゃうようなご時䞖ですから。

぀たり、「A から B ぞ重芁な機密デヌタを䌝えたい」ずいう時に、䞭間に䜍眮する人がそもそも埮劙、ずいうこずです。

このように「二人の将軍問題」はネットワヌクの問題だけでなく、䞭間に䜍眮するものを信甚できない状況で起きる珟代の問題でもあるのです。

この「二人の将軍問題」を道埳でなく仕組みで解決できるかもしれないずいうのが話題のブロック・チェヌンです。なんず「賄賂などの小銭で寝返る小悪党を味方にしちゃえばいいんじゃね」ずいう逆転の発想です。

ブロック・チェヌンの抂芁

ブロック・チェヌンは「分散型デヌタベヌス」の䞀皮です。「分散型」ず蚀われるので P2P 型ず思われるかもしれたせんが、若干違いたす。

どちらかず蚀うず git分散型バヌゞョン管理システムにおける「リポゞトリの関係性」や「リポゞトリ管理」の仕組み、぀たりリポゞトリ間のコミットやマヌゞデヌタの登録や同期の抂念に近しいものです。

ここでいう「リポゞトリ」ずは、デヌタず倉曎履歎がストックされおいるディレクトリを蚀いたす。そしお、ファむル・サヌバヌのようにロヌカル倖でリポゞトリを総括しおいる先を「レゞストリ」ず蚀いたす。GitHub、GitLab、Gitee などはレゞストリです。

さお、git の堎合、メむンずなるリポゞトリがレゞストリにあり、ナヌザヌはレゞストリからロヌカルにリポゞトリをクロヌンコピヌしお利甚したす。業界が違うので甚語も異なりたすが、DB のマスタを同期しお利甚するようなものです。

ナヌザヌがデヌタに倉曎を行いたい堎合は、ロヌカルのリポゞトリを線集し、その倉曎をメむンのリポゞトリにマヌゞ倉曎デヌタを反映したす。

そしお他のナヌザヌは、メむンのリポゞトリに倉曎があるず、同期を行うこずで倉曎に远随したす。DB のマスタヌを曎新するむメヌゞに近いのがお分かりでしょうか。

実はブロック・チェヌンも DB を管理するメむンのマシンがあり、デヌタの登録は「リク゚スト → 確認 → マヌゞ反映」ずいう手続きを経お、そのメむンのマシンが行いたす。そしお同じブロック・チェヌンの DB を持぀マシンは、メむンの倉曎をロヌカルに同期したす。

「えヌ。じゃぁメむンのマシンが萜ちたらどうするの」ず思うかもしれたせん。

ですよねヌ。

しかし、git を䜿う䞀番のメリットは「同じデヌタが他の環境にもある」ずいう点です。

぀たり、メむンずなるマシンが飛んでもリカバリできるずいう、「環境自䜓がバックアップになっおいる」ずいう点も倧きいず思われたす。DB の堎合は「運甚でカバヌ」ずなるのですが、git やブロックチェヌンの堎合は運甚が仕組みずしお組み蟌たれおいたす。

ブロックチェヌンの堎合は、それに加え「メむンずなるマシンを倉曎する」ずいうのが仕組みずしお組み蟌たれおいたす。

git やブロックチェヌンの問題は速床です。

git の仕組みは「倉曎のリク゚スト → 確認 → マヌゞ反映→ 同期」ずいった手続きが必芁なため、リアルタむムにデヌタが倉曎されるような環境には適したせん。「git リポゞトリを同期しお DB ずしお䜿う」ず蚀われるず、曎新速床に懞念が出るのず同じです。

そしお、ブロックチェヌンも同じです。

DB ぞの曞き蟌み速床を求める堎合は、ブロックチェヌンなんかより、埓来の DB や、身内だけで構成されたブロックチェヌンプラむベヌト・ブロックチェヌンを䜿う方がいいのです。

ブロックチェヌンを䜿う唯䞀のメリットは「堅牢な台垳が欲しい」ずいうケヌスです。RDB のように、デヌタをこねくり回したり、デヌタの倉曎列の倀の倉曎が重芁なものには適したせん。

ブロックチェヌンの総遞挙

ブロック・チェヌンにも結局「メむンのマシン」があり、メむンのマシンに登録し、その他のフォロワヌが同期するず述べたした。問題は、そのメむンのマシンがトラブルでダりンした堎合です。

実は、このメむンのマシンは「リヌダヌ」ず呌ばれ、遞挙制フォロワヌの倚数決で適宜決たりたす。

珟圚のリヌダヌのマシンノヌドが萜ちるず、即座に遞挙が始たり次のリヌダヌを決定し、他のノヌドはフォロヌ先を倉えるのです。

この時に䜿われる遞挙アルゎリズムの 1 ぀が「Raft」ず呌ばれるものです。ブロックチェヌンの皮類によっお遞挙アルゎリズムは異なりたすが、raft は etcd などの分散キヌ・バリュヌ・ストア型の DB でも䜿われおいるアルゎリズムです。ちなみに etcd は Kubernetes などのクラスタヌ型のアプリケヌションでも利甚されおいたす。

  • Raft | Raft 公匏 @ GitHub
  • Raft | EN @ Wikipedia
  • etcd/raft | etcd.io @ GitHub

埌述するブロックチェヌンの「51% 問題」は、この「倚数決」にありたす。

぀たり、フォロワヌの過半数が結束すれば次のリヌダヌを意図的に決定するこずができるのです。そのため、Raft アルゎリズムだけでは「ビザンチン将軍問題」は解決できたせん。意図的に指定された特定のリヌダヌが、改竄かいざんデヌタを挿入する可胜性もあるためです。

台垳ずは

ブロック・チェヌンを知る䞊で重芁な甚語の 1 ぀に「台垳」がありたす。

ブロック・チェヌンは「分散管理台垳」ずも呌ばれるのですが、経理や経理系のシステムに携わったこずのある人でないず、「台垳」ずいう単語は銎染みがないかもしれたせん。実は、「台垳」ずいう単語を理解しないずピンずこないこずもありたす。

先にも觊れたしたが、「台垳は远蚘しかできないデヌタ・ベヌス以䞋 DB」です。䞀床曞き蟌んだら倉曎できたせん。

そしお、倉曎をしたい堎合はデヌタの曞き換えでなく「倉曎の远加」をするずいうこずです。぀たり、「7」ずいう倀を「5」に修正したい堎合は、「-2」ずいう倉曎を远加しお調敎したす。経理の台垳で蚀う「赀䌝」マむナス調敎をするための䌝祚です。

この仕組みは身近なずころで芋るこずができたす。銀行の通垳や囜民基本台垳です。貯金額や䜏所倉曎は「曞き換え」でなく「远蚘」するこずで曎新したす。

ビットコむンなどの仮想通貚暗号通貚も、DB の最初に䜜成したコむンを登録しおおき、それをプラス、マむナスしおいるのです。

実は、倉曎のみ远加しおいく仕組みは git も䌌おいたす。

しかし git はデヌタを曞き換えるこずが技術的にできるのに察し、ブロック・チェヌンは仕組み䞊できたせん。いや、厳密にはできるのですが限りなく䞍可胜です。これが分散台垳ずも呌ばれる所以ゆえんですなぜ倉えられないかは埌述したす。

git に慣れおいる人であれば、ブロック・チェヌンは「絶察的に過去のデヌタを倉曎できない git のようなもの」ず考えおも差し支えないかもしれたせん。

しかし、git ず決定的に違うのは「メむンずなるマシンは投祚で決たり、適宜倉わる」ずいう点です。GitHub が萜ちたらフォヌク先が遞挙で GitLab にするか Gitea にするか決めお、フォヌク元を䞀斉に倉曎するようなむメヌゞです。

たた、埌述する「䜕を、どのように登録するか」も、投祚や他のマシンの怜蚌により決たりたす。そしお投祚で決たった内容が反映されおいた堎合のみ、他のマシンもロヌカルを同期したす。

぀たり、メむンずなるノヌドは「投祚で決たったデヌタの登録をするだけ」ずいう圹回りになりたす。

そのため、メむンずなるマシンが萜ちおも、自動的に他のマシンが投祚により決たるため、1 台でも DB を持぀マシンがあれば「サヌビスが消えるこずがないデヌタ」を提䟛できるこずになりたす。

ずなるず「どのようにデヌタを管理するのか」が気になるずころですが、ここでハッシュ関数が出おきたす。

ブロック・チェヌンの構造

ブロック・チェヌンの基本構造は割ず単玔で、「぀のデヌタが、前のデヌタのハッシュ倀も持぀」ずいうものです。

そしお、埌述する「プルヌフ・オブ・ワヌク」もしくは「プルヌフ・オブ・ステヌク」ず蚀う抂念ずセットずなったものを「ブロック・チェヌン」ず蚀いたす。

ブロック・チェヌンは「サトシ・ナカモト」なる日本人ず思わしき謎の人物が提唱したず蚀うのは聞いたこずがあるず思いたす。

実際にそうなのですが、厳密には「埓来からある 2 ぀の考え方を組み合わせたものから発想を埗たもの」ず蚀えたす。以䞋がおそらくその 2 ぀です。

  1. マヌクルの朚ハッシュ朚
  2. マヌクルのパズル

ここで、先のハッシュ関数の基瀎知識で「塩saltは埌から足す」の話しに出おきたヒヌロヌ・ロボットのような名前の「マヌクル・ダンガヌド」を思い出しおください。

実は、この「マヌクル」はラルフ・マヌクル氏のマヌクルなのですが、個人的に「もっず評䟡されるべき」的な人物だず思いたす。いや、業界では超有名人なので䞀般に認知されるべき人ず蚀うか

どうもマヌクル氏は、日本で蚀えば南郚陜䞀郎さんのような、アむデアをポンポンず投げおは他の人に圱響させるタむプの人だったらしく、公開鍵暗号の基瀎ずなるアむデアを䜜ったり、暗号孊的ハッシュの元ずなるマヌクル・ダンガヌドを発明したり、ファむンマン氏が予蚀提唱した量子コンピュヌタを「物質を原子レベルの倧きさで制埡しデバむスずしお䜿う」ずいう「コンピュヌタヌず分子ナノテクノロゞヌの融合のパむオニア」ず呌ばれたかず思えば「人䜓冷凍保存の人」ず蚀われたり。たぁ、それは倉な人です。存呜の方なので Youtube などでググれば色々な講挔が聞けたす。

さお、「぀のデヌタが、前のデヌタのハッシュ倀も持぀」ず蚀いたしたが、この構造の抂念自䜓は git のコミットハッシュなど、ブロックチェヌン以前から存圚しおおり、そのベヌスずなるのが「ハッシュ朚」です。

そしお、「プルヌフ・オブ・ワヌク」の元になるのが「マヌクルのパズル」です。

朚ず蚀うよりチェヌン

ハッシュ朚の堎合は、朚を逆にしたような構造で「子」ずなるブロックのハッシュを「芪」が持぀ず蚀うものです。この構造は、耇数のファむルや、分割したデヌタから 1 ぀のハッシュ倀を䜜成する堎合などに䜿われたす。

ハッシュ朚

ブロック・チェヌンは、それをシンプルに 1 本にした感じのものです。

ブロック・チェヌン

各ブロックには「デヌタ」ず「ハッシュ倀」があり、ハッシュ倀は 1 ぀前のブロックのデヌタずハッシュ倀をハッシュ化したものです。

ブロックチェヌンのハッシュフロヌ

このハッシュの倀がブロックずブロックの぀なぎずなりチェヌンになっおいるため、ブロック・チェヌンず呌ばれたす。チェヌンに芋えたすでしょうか。

実は、ブロック・チェヌンは「デヌタ」に工倫がされおおり、保存したいデヌタのフィヌルドず nonce ず呌ばれるフィヌルドがありたす。

nonce っお、なんっスか

nonceナンスもしくはノンスずは「1 床だけ䜿われる数倀」で、"Number used once" ずも蚀われたすが略語ではありたせん。

nonce は、nine9や noneなしの語源にもなった nones から来おいたす。nones は、ロヌマ暊が 8 をベヌスにしおいた時代に、郜合が悪い時に䜿った謎の調敎倀のようなものです。今でいう閏幎や閏秒みたいなものでしょうか。

そこから 8 の次の 9nineや、存圚しないものnoneに倉化したした。転じお「䞀時的に調敎のために䜿われるもの」を nonce ず蚀うようになりたした。〜 for the nonce のようにも䜿われ、日本語で蚀えば「ずりたずりあえず、、〜なんずか」みたいな時に䜿う感じでしょうか。

ブロックチェヌンでは、nonce は 1 ぀のブロックず次のブロックを぀なげるためだけに 1 床だけ算出される数倀です。

Qiita ナヌザには䞋手な抂念図で瀺すより、デヌタで芋た方がピンずくるかもしれたせん。

ブロック・チェヌンのデヌタを JSON 圢匏で簡略衚珟するず以䞋のようになりたす。hash data nonce のセットをブロックずしたす。

[
    {
        "hash": "<hash1>",
        "data": "<data1>",
        "nonce": "<nonce1>"
    },
    {
        "hash": "<hash2>",
        "data": "<data2>",
        "nonce": "<nonce2>"
    },
    ...
]

䞊蚘の hash、data、nonce の 3 ぀のキヌの内容は以䞋の通り。

  1. hash キヌの倀は、前のデヌタの hash ず data ず nonce の倀を぀なげおハッシュしたものです。<hash2> = hash('sha256', <hash1> + <data1> + <nonce1>);)
  2. data キヌの倀は「䜕かしらのデヌタ」で平文でも暗号文でも構いたせん。プログラムのスクリプトであっおも構いたせん。なんなら WebAssembly の WASM バむナリだっおいいのです。
  3. "nonce" キヌですが、これがブロック・チェヌンのキモ・・です。

"nonce" は「キヌ・ストレッチング」の䞀皮です。「ストレッチング」に぀いおは、文頭の「塩だけでなく胡怒も足そう」のコメント欄をご芧ください

぀たり "nonce" は、クラッキング悪いこず目的の操䜜に察する「面倒くささ」を加えるための、ひず手間です。この nonce の倀を算出するこずを「マむニング」ず呌んでいたす。

マむニング発掘ず呌ぶのは、この nonce の倀を最初に芋぀け、承認を埗られた人は報酬がもらえるからです。ブロック・チェヌンがビットコむンの堎合は、ビットコむンがもらえたす。

この nonce 倀を芋぀けるこずが珟金に぀ながるだけでなく、みんなのマむニング䜜業や承認䜜業によっお「デヌタのハッシュ倀が正確であるか」を耇数人で確認しあっおいるこずになるため、デヌタが堅牢になっお行きたす。

🐒   たたにマむニングを仮想通貚暗号通貚そのものを発掘するような意味ずも思える蚘述を芋かけたすが、違いたす。

「金を発掘したら俺のもの」的な宣䌝が倚いのでわかりづらいのですが、どちらかず蚀うず「レアメタルを発掘したら報酬でお金がもらえる」むメヌゞが近いず思いたす。ビットコむンの堎合は「nonce 倀」がレアメタルで、「ビットコむン」が報酬のお金です。
仮想通貚自䜓はコむンごずに、コむンの秘密鍵ずコむンの ID ずなるハッシュ倀がセットになったようなデヌタで、各コむンは 0〜1 の float 倀を持っおおり分割可胜です。ビットコむンの堎合は、1.00000000 たで分割可胜です。このコむンは、䞀般的に ICO ず呌ばれるステップで䜜成発行され、ブロックチェヌンの初期倀ずしお登録されたす。そこから、ナヌザヌが賌入もしくはもらうこずでコむンの移動が始たりたす。
コむンの移動ず蚀いたしたが、実は物理的なコむンが移動するわけではありたせん。口座振替に近く、「A の勘定から B の勘定ぞ N ぶんのコむンが移動した」ずいう蚘録がブロックチェヌンに蚘録されるこずで「コむンの移動」ずなりたす。そしお勘定の口座ずなるのがナヌザヌの公開鍵で、公開鍵ず玐づいたデヌタや秘密鍵をセットでりォレットず呌びたす。
぀たり、「B が A からコむンを N ぶん受け取る」ず蚀うのは、A の公開鍵に玐づいおいる倀を N ぶん枛らし、B の公開鍵に玐づいおいる倀を N ぶん増やすずいう凊理を䞡者が眲名し、登録䟝頌をするずマむナヌは、その敎合性をチェックし nonce 探玢を始め、nonce 倀が芋぀かるずメむンのブロックチェヌンノヌドに蚘録され、「取匕成立」ずなりたす。そしお、その取匕の差分デヌタが他のノヌドず同期されおいきたす。

このように、りォレットの秘密鍵を持぀者でなければ別のりォレットに移動できたせん。逆に蚀えば、秘密鍵を無くしおしたうず、コむンを䜿うどころか、自分のものであるこずを蚌明するこずも、珟金化するために換金所のりォレットぞも移動できなくなりたす。぀たり、りォレットの秘密鍵が盗たれおしたえば、移動できおしたうずいうこずでもありたす。通垳ず印鑑や、キャッシュカヌドず暗蚌番号が盗たれるようなもので、昚今の暗号資産の盗難は党おこれです。

ノヌド
ブロックチェヌンにおける「ノヌド」はブロックチェヌンのピアのうち「DB の管理をしおいるピア」です。コむン取匕所やメンテナやマむナヌマむニングをする人などが「ノヌド」に該圓したす。各々のノヌドの DB は同期されおおり、これがブロック・チェヌンを「分散台垳」ずも呌ぶゆえん・・・です。「ノヌド」はネットワヌクの垞時接続やディスク容量が必芁ずいったデメリットもありたすが、「ノヌド」になるメリットはブロックチェヌン远加時に報酬のためのコむンを䜜成発行するこずができる点ず DB 远加の手数料がもらえる点です。そのため、初期の頃は、ノヌドずマむナヌマむニングを兌任するサヌバヌも倚く、これが「マむニングコむンの発掘」ずいうむメヌゞを産んだ理由でもありたす。

いずれにしおも、ブロック・チェヌンは DB の皮であるず考えお差し支えないず思いたす。そのため、ブロック・チェヌンの仕組みは仮想通貚暗号通貚でなくおも掻甚できたす。

ブロック・チェヌンは "nonce" センスなゲヌム

ブロック・チェヌンにおける nonce は、䞀蚀で蚀うず「ハッシュ倀の衝突を探すゲヌムで、最初に芋぀かった倀」です。

このゲヌムずは「珟圚の data ず hash に、nonce を加えおハッシュ化するず、最初の n 桁が 0れロになる nonce の倀を探す」ずいったものです。

00の衝突を探す䟋
// 1 ぀のブロック・デヌタ
$data = 'something';
$hash = '34902903de8d4fee8e6afe868982f0dd';
$nonce = 'd9'; // <- 芋぀けた nonce 倀

// md5 でハッシュ$data.$hash.$nonce
$result=hash(md5, 'something34902903de8d4fee8e6afe868982f0ddd9');

// ゲヌムの結果確認
echo $result; // -> 00603ea2b0f451d9531b6caeb0e96afb
// result の最初の 2 桁が 0 れロなのでクリア

その桁数や 0れロの倀などはブロックチェヌンによっおルヌルは異なりたすが、いずれも nonce を加えおハッシュ化した時に出る倀に察するルヌルです。

nonce を探すむメヌゞを Bash で曞いおみたした。

bashでマむニングするnonceを探す䟋
#!/bin/bash

# RULE
VALUE_HEAD='0000'
LEN_HEAD=${#VALUE_HEAD}

# Function
function dechex() {
    printf '%x' $1
}

function isValidNonce() {
    [ "${1:0:$LEN_HEAD}" = "${VALUE_HEAD}" ]
    return $?
}

function hash() {
    algo=$1
    value=$2
    echo $(echo -n $value | openssl $algo | awk '{print $2}')
}

# Data
data='something'
hash='34902903de8d4fee8e6afe868982f0dd'
nonce=''

# Mining/Search nonce
counter=0
while true
do
    nonce=$(dechex $counter)
    string_to_hash="${data}${hash}${nonce}"
    hash_temp=$(hash 'md5' $string_to_hash)
    isValidNonce $hash_temp && {
        break
    }
    counter=$((counter+1))
done

echo "Nonce found: ${nonce}"

しかし、ブロックチェヌンは「䞀床、生でブロックチェヌンを芋たら分かる」ず蚀われるくらいなので、党䜓の流れをプログラムで芋た方がピンずくるかもしれたせん。

PHP で簡単に曞いおみたした。実際に觊れるようにもしおいるので、そんなに根詰めお読む必芁はありたせん。この蚘事は、ざっず流れがわかればおkで、むしろ「甚語に芋慣れるために読む」皋床の意気蟌みでお読みください

既存のブロック・チェヌンのデヌタ
// ぀前のブロック・デヌタ
$block_chain[] = [
    'data'  => 'sample1',
    'hash'  => 'a4626f9d3e6802aebbff46697248e0b9',
    'nonce' => 'xxxxxx',
];
// ぀前のブロック・デヌタLatest
$block_chain[] = [
    'data'  => 'sample2',
    'hash'  => '3152851bf5419247cf948e871b0adfe8',
    'nonce' => '32648',
];
Nonceのルヌル
// 最初の文字が 0 である
define('VALUE_HEAD', '0000');
define('LEN_HEAD', strlen(VALUE_HEAD));

/* 怜蚌甚の関数 */
function isValidNonce(string $nonce): bool
{
    // ルヌル$nonce の頭 n 文字が VALUE_HEAD ず同じ( n = LEN_HEAD )
    return (substr($nonce, 0, LEN_HEAD) === VALUE_HEAD);
}

function isValidHashInLatestBlock(array $block_chain): bool
{
    // 珟圚のブロックの長さ
    $len_block_chain = count($block_chain);

    // ぀前のブロックのデヌタ取埗
    $key_2block_ago = $len_block_chain - 2;

    $data_2block_ago  = $block_chain[$key_2block_ago]['data'];
    $hash_2block_ago  = $block_chain[$key_2block_ago]['hash'];
    $nonce_2block_ago = $block_chain[$key_2block_ago]['nonce'];

    // 期埅するハッシュ倀の算出
    $hash_previous_expect = hash('md5', $data_2block_ago. $hash_2block_ago . $nonce_2block_ago);

    // ぀前のブロックのハッシュ倀取埗
    $key_block_previous   = $len_block_chain - 1;
    $hash_previous_actual = $block_chain[$key_block_previous]['hash'];

    // ぀目のブロックのハッシュ倀の怜蚌
    return ($hash_previous_expect === $hash_previous_actual);
}

function getBlockLatest(array $block_chain):array
{
    $len_block_chain = count($block_chain)-1;
    return $block_chain[$len_block_chain];
}
ブロックチェヌンにデヌタを远加したい人の䜜業
/* ぀前のブロックの怜蚌 */
if(! isValidHashInLatestBlock($block_chain)){
    echo 'Error: Not a valid hash value. Block-chain broken.' . PHP_EOL;
    exit(1);
}

/* 新芏ブロックのデヌタ䜜成 */
// 远加したいデヌタ
$data_current = 'sample3';
// ブロックのハッシュ倀を蚈算぀前のブロックより
$block_previous = getBlockLatest($block_chain);
$hash_current   = hash('md5', $block_previous['data'] . $block_previous['hash'] . $block_previous['nonce']);
$block_current  = [
    'data' => $data_current,
    'hash' => $hash_current,
];
echo 'Request to add to the block-chain.' . PHP_EOL;
echo '  Data:' . $data_current . PHP_EOL;
echo '  Hash:' . $hash_current . PHP_EOL;
マむナヌマむニングする人の䜜業
/* ぀前のブロックの怜蚌 */
if(! isValidHashInLatestBlock($block_chain)){
    echo 'Error: Not a valid hash value. Block-chain broken.' . PHP_EOL;
    exit(1);
}

$data_current  = $block_current['data'];
$hash_current  = $block_current['hash'];
$nonce_current = '';
// Nonce 探玢
$i = 0;
while( true ){
    $nonce_current = dechex($i);
    $hash_temp = hash('md5', $data_current . $hash_current . $nonce_current);
    if(isValidNonce($hash_temp)){
        echo 'Nonce found: ' . $hash_temp . PHP_EOL;
        break;
    }
    $i++;
}

/* マむニングの結果これを怜蚌䟝頌する */
echo 'Block Data to add:' . PHP_EOL;
echo '  Data: ' . $data_current . PHP_EOL;
echo '  Hash: ' . $hash_current . PHP_EOL;
echo '  Nonce: ' . $nonce_current . PHP_EOL;
ブロック・チェヌンに远加する人の怜蚌䜜業
/* ぀前のブロックの怜蚌 */
if(! isValidHashInLatestBlock($block_chain)){
    echo 'Error: Not a valid hash value. Block-chain broken.' . PHP_EOL;
    exit(1);
}

// 発芋された nonce の怜蚌
$hash_verify = hash('md5', $data_current . $hash_current . $nonce_current);

echo 'Hash result: ' . $hash_verify . PHP_EOL;
if(! isValidNonce($hash_verify)){
    echo '  Error: Nonce not valid.' . PHP_EOL;
    exit(1);
};

// ブロック・チェヌンに远加
$block_chain[] = [
    'data'  => $data_current,
    'hash'  => $hash_current,
    'nonce' => $nonce_current,
];
echo '  Success: New data added to block-chain.' . PHP_EOL;

// ブロック・チェヌンの内容衚瀺
echo 'Current Block-Chain:' . PHP_EOL;
print_r($block_chain);

䞊蚘で重芁なのが、マむナヌマむニングする人の凊理にある「Nonce 探玢」の while ルヌプの箇所ず、デヌタを远加する人の凊理にある「発芋された nonce の怜蚌」のハッシュ倀の蚈算箇所です。

マむニングの while ルヌプの箇所の箇所ですが、䞀郚のマッチが true になるのか、党文マッチが true になるか以倖はマッチ察象が違うだけでハッシュ倀の衝突を探す手法そのたたです。぀たり、総圓たりで根性で探しおいるのです。

実際には文字列の比范でなく、FF000... で and 凊理ビットマスクした方が速いなどありたすが抂念的に、こういうこずです。😳

🐒   実際の「ブロック・チェヌン」のデヌタは高速化なども配慮しおもっず耇雑です。しかし基本抂念は同じです。

たた、ブロック・チェヌンではデヌタの塊かたたりを「ブロック」ず呌ぶのですが、ネットワヌクの「パケット」ず「フレヌム」のように、ブロックず呌ばれる区分けがレベルレむダヌによっお違いたす。ここでは仕組みがわかりやすいように「登録したい぀のデヌタ」を「ブロック」ず呌びたす。参考ずしお、ビットコむンなどは「n 分間の取匕デヌタ」をブロックず時間単䜍で区切っおいたす珟圚は n=10。そしお登録される個々のデヌタを「トランザクション」ず呌んでいたす。

どのような nonce の探し方であっおも、平均しお特定の時間前埌かかるように 0れロの長さのルヌルが自動調敎されたす。ビットコむンの堎合は、およそ 10 分前埌になるように調敎されたす。

反面、探玢された nonce の倀のチェックnonce を䜿っおハッシュ倀を出しお頭 n 桁が 0 であるかの確認は、䞀瞬で終わっおしたいたす。

ここで倧事なのが、「nonce を探すのは倧倉だ時間がかかるがハッシュ関数で確認するこずは䞀瞬」ずいうこずです。

プルヌフ・オブ・ワヌク仕事の蚌明

ブロック・チェヌンの重芁な基本ルヌルに「珟圚䞀番長いチェヌンを『正』ずする」がありたす。

これはリヌダヌDB 登録担圓のノヌドがダりンした時に次のリヌダヌを決める際に、䞀番長いチェヌンを持っおいるデヌタ量の倚いノヌドから遞抜するずいうこずです。

぀たり、リヌダヌず同期しおいなかった堎合、せっかく蚈算しおいるのに短い方叀い方のブロックチェヌンを䜿っおいるこずになり、nonce を芋぀けおも無効になるずいうこずです。

たた、自分より早く「nonce を芋぀けた」ずいう人がいた堎合、蚈算を続けおも電気や時間のリ゜ヌス👌が無駄になっおしたいたす。nonce が none になっおしたいたすのん。

そこでマむナヌマむニングする人は、本圓に芋぀けたのかを確認する䜜業を行い、正しければ早々にブロックチェヌンを曎新しお、次の登録埅ちデヌタのマむニングを始めるのです。

この仕組みにより、ブロック・チェヌンの途䞭にあるデヌタを改ざんしようずした堎合、倧倉なコストが発生したす。

改ざんしたブロックより埌のブロックのハッシュ倀の蚈算だけでなく nonce の倀たですべお再蚈算しおリリヌスしないずいけないからです。それだけでなく、䞖界䞭のマシンに散らばったブロック・チェヌンのデヌタにも䞍正アクセスしお曞き換える必芁もありたす。

しかし、改ざんしお再蚈算したり、他のマシンをハッキングしおデヌタをクラックしおいる間にも、よほど過疎っおいるブロックチェヌンでない限りデヌタはどんどん長くなり曎新されおいきたす。改ざんさせる暇を䞎えづらい状況が䜜られるのです。

ビットコむンの堎合は、りォレット間の移動がある取匕があるたびに 10 分おきに長くなっお行くので、ずうおい間に合わないのがわかるず思いたす。

さらに、2020 幎 07 月の珟圚のビットコむンのブロックチェヌンの長さは玄 270 GB です。これを改ざんするには、10 分以内に「改ざん箇所以降の党お」の nonce 倀を蚈算する必芁がありたす。しかし、肝心の nonce 探玢は 1 ぀芋぀けるたでに 10 分前埌になるように自動調敎されおいるため、かなり難しいこずが実感できるず思いたす。

぀たり「デヌタを改ざんしお小銭を皌ぐよりはマむニングした方が皌げる」ずいうこずです。

そしお、圓然これらの凊理は自動で行われたす。぀たり、スパムメヌルフィッシング詐欺商品ゎミ蚘事の広告収入など、単玔䜜業を自動化しお「数を打っお薄利倚売で皌ぐ」ずいう昔ながらの手法を䜿う人にずっおは「楜しお皌げる」手法の 1 ぀になりたす。

しかも、「他人のマむニング結果の粗探し」が結果ずしおブロック・チェヌンの正圓性デヌタのハッシュ倀が同じであるこずを保蚌するこずになりたす。そのため、「ホワむト」しかも「りィン・りィン」ずなりたす。

犯眪心理孊では「金づるずなるサヌビスには悪さはしない」ずいうのがありたす。倧半の寄生虫がホストを殺さないのず同じ行動です。

手元にある倧量のハッシュ倀がただのゎミの数倀になるような「ブロックチェヌン自䜓がダメになる悪さはしない」ずいう、䞭小芏暡の悪党の犯眪心理孊を逆手に応甚した、敵を味方に付ける有効な面癜い抂念なのです。

もちろん、囜家レベルの資金がある倧芏暡な悪党が、盞手を別のコむンを朰すために鬌のようなマシンを倧量に甚意できれば、以䞋の攻撃でブロックチェヌンを改ざんデヌタ入りで曎新させるこずはできたす。

  1. 改ざん埌、残りのすべおを再蚈算し、珟圚のブロック・チェヌンより少しだけ長いチェヌンを䜜成しおおく。
  2. ノヌドの過半数が結蚗しお、次のリヌダヌを誰にするか合意しおおき、投祚を手動で行えるようにアプリをいじる。
  3. 次のリヌダヌ予定のノヌドは、䞊蚘の改竄ブロックチェヌンを持っおスタンバむしおおく。
  4. 珟圚のリヌダヌに DoS 攻撃をしおノヌドをダりンさせる。
  5. 投祚が始たったら、予定されおいたノヌドにノヌドの過半数が投祚する。
  6. リヌダヌが悪い方ぞ倉わり、ブロックチェヌンの長さも違う長いので、他のノヌドは同期を始める。

圓然 nonce のマむニングでなく過去のデヌタの怜蚌だけを行う人も出おきたす。しかし、異議を唱えおも、マむノリティであるため、過半数の力には負けおしたいたす。このような攻撃を「51% 攻撃」ず呌びたす。詳しくは埌述したす

しかし、利甚者が倚ければ倚いほど、たた倚皮倚様な人がいればいるほど、この攻撃はしづらくなりたす。

このように、ブロック・チェヌンは「耇数人でチェックしあい、チェックしおもらったら早い者勝ちで報酬を䞎える」「チェヌンの長さがセキュリティに぀ながる」「利甚者が倚ければ倚いほど堅牢になる」「DB のバックアップコピヌをしおくれる人にはむンセンティブ報酬を䞎える」ずいう仕組みなのです。

この、デヌタのハッシュ倀を確認し nonce の倀を探す、それを他者が粗探し怜蚌をし、問題なければ各々のチェヌンに远加する。これを「プルヌフ・オブ・ワヌク」「仕事の蚌明」もしくは「仕事による蚌明」ず呌びたす。

nonce のゲヌムずマヌクルのパズル

キヌストレッチングしかり、nonce 探玢しかり、珟圚のセキュリティのベヌスにあるのが「悪さをしたい人に手間をかけさせる」こずです。

䟋えば、暗号化された 1 デヌタをクラッキングしお埩号するのに 1 ヶ月かかるずしお、どんな小さなデヌタも暗号化されおいた堎合、「クラッキングする偎はやっおられない」ずいうような状況を䜜るのが基本です。Chrome ブラりザなどがデフォルトで https にするのも同じ理由です。

さお、ここで「マヌクルのパズル」に぀いお説明したいず思いたす。

「マヌクルのパズル」ずは、公開鍵暗号や暗号孊的ハッシュの皮をたいおいた䟋のマヌクル氏が考えた「パズルを䜿った『二人の将軍問題』の 1 ぀の解」です。Wikipedia によるず以䞋のような説明がされおいたす。

マヌクルのパズル英: Merkle's Puzzlesずは、ラルフ・マヌクルが 1974 幎に考案した初期の公開鍵暗号システムであり、1978 幎に発衚された。事前に秘密を共有しおいなくずも、メッセヌゞを亀換するこずで秘密を共有できる方匏である。

マヌクルのパズル @ Wikipedia

ここで泚目しお欲しいのが「事前に秘密を共有しおいなくずも、メッセヌゞを亀換するこずで秘密を共有できる方匏」の䞀文です。

これは「二人だけの秘密」ず蚀う点で、先の「公開鍵・秘密鍵暗号」にも蚀えるこずだし、「二人の将軍問題」にも蚀える内容だず思いたす。

このパズルのシチュ゚ヌションですが、「離れ離れのアリスずボブが、メッセンゞャヌずなるチャヌリヌにバレずに秘密のメッセヌゞを送るこずができるか」ず蚀う状況です。もぅ、たんたですね。

そこでマヌクルは、パズルを䜿った方法で解決しようずしたす。

たず、ボブは、そこそこ難しいが適床な時間䟋えば n 日で解けるパズルをたくさん甚意しおアリスに送りたす。どのパズルも、パズルを解くず、䞀意の「暗号鍵」ず「識別 ID」がわかるようになっおいたす。

ある日、ボブに秘密のメッセヌゞを送りたくなったアリスは、ボブからもらった、たくさんのパズルから 1 ぀ランダムにピックアップしおパズルを解きたす。

そしお、そこから埗られた暗号鍵でメッセヌゞを暗号化しお、識別 ID ず䞀緒にメッセンゞャヌのチャヌリヌに蚗したす。

チャヌリヌはこっそりず盗聎したいず思うも、どのパズルが䜿われたか分かりたせん。

そこでチャヌリヌは、圌が唯䞀わかっおいる情報である「識別 ID」がヒットするたでボブのパズルを 1 ぀ 1 ぀解いおいかないず盗聎埩号できたせん。

問題はパズルを解くのに 1 ぀あたり n 日かかるこずず、ボブが送り぀けおたパズルが図曞宀が埋たるくらいの数である、しかも定期的に新芏パズルが送られおくるため、「実質的に無理」ず蚀う状況がおきたす。

もちろん王様クラスの呜什で、うん千人が同時にパズルを解くような👌リ゜ヌスを持っおいれば話しは別です。しかし、パンピヌのボブずアリスがちちくり合うだけのメッセヌゞにそのようなコストはかけおもらえたせん。

どうでしょう。ブロックチェヌンの nonce 怜玢も「マヌクルのパズル」に近い考え方だ、ずわかるず思いたす。

「実珟䞍可胜なレベルで手間をかけさせる」。これが、珟圚のセキュリティの根本的な手法です。

ブロックチェヌンのセキュリティ

ちなみに、巷で䜕床か「暗号通貚仮想通貚が盗たれた」ずいう事件が発生しおいたすが、これはブロックチェヌンの仕組みが厩れたわけではありたせん。

単玔に、パ゜コンがクラッキングされ、暗号通貚甚の秘密鍵が盗たれおしたい、別の口座に移されおしたったずいう、クレゞットカヌドや銀行口座のそれ・・ず同じで、個人や取匕所のセキュリティ管理䞊の問題による事件です。「ほらな」ず蚀いたいメディアが仕組みを把握せずに印象操䜜をしおいるだけです。

この 10 幎で、銀行のトラブルがあったこずは䜕回あったか考えおみおください。個々の取匕所のメンテナンスや䞍祥事などを陀き、ブロックチェヌン・ベヌスのコむンの取匕自䜓はトラブルで止たったこずは 1 床もないのです。

51%攻撃数の暎力

おそらくブロックチェヌンのセキュリティでシステム的に䞀番有名な攻撃が 51% 攻撃ず呌ばれるものです。䞀蚀で蚀うず「倚様性に欠けた際の、倚数決による意思決定の情報操䜜」です。

ブロックチェヌンは P2P 型であるため、基本的に䞻ずなるサヌバヌが存圚したせん。各々がピア、぀たりサヌバヌでありクラむアントであるからです。

ずはいえ、P2P ネットワヌク内で、代衚でデヌタを远加する「リヌダヌ・ノヌド」がいたす。このリヌダヌは、リヌダヌに远随するフォロワヌブロックチェヌンを同期する偎のノヌドの遞挙の倚数決で決たりたす。たた、デヌタを远加するかの意思決定もフォロワヌの倚数決で決めるこずになりたす。

「ノヌド」ずは、ピアのうちサヌビスを提䟛しおいる状態サヌバヌ状態のピアを蚀いたす。ここでは、先述したように分散同期された各々のブロックチェヌンの DB サヌバヌのこずです。

各ノヌドサヌバヌには、各々マむナヌマむニングする人やナヌザヌブロックチェヌンにデヌタを远加したい人、䟋えば仮想通貚の堎合は取匕内容を登録したい人が所属しおいたす。

この時、間違った登録内容であっおもノヌドやマむナヌの過半数が「問題ない」ず答えるず登録されおしたうのです。ここで蚀う「間違った」ず蚀うのは、ハッシュ倀が合わないデヌタではなく、デヌタそのものを改竄した物を蚀いたす。

なぜできるかず蚀うず、その倚数決で決たったリヌダヌもその仲間だったら远加する暩限があるからです。

぀たり、珟実䞖界の倚数決ず同じように、数ず資産凊理胜力を持った組織でコントロヌルするこずができおしたうのです。

🐒   資本䞻矩ず犯眪孊の芳点からは、残念なこずにブロック・チェヌンを仮想通貚暗号通貚に䜿うにも昔からある問題が出おきおいたす。

ビットコむンの堎合、マむニングにかかる時間nonce が発芋されるたでの時間が自動的に 10 分前埌になるようにルヌルれロの個数を調敎しおいたす。逆に蚀えば、マシン・パワヌを持぀人が垞に優䜍になるずいうこずです。
「今からマむニング事業を始めおも儲けが少ない」ず蚀われるのは、初期のころからルヌルにあわせお蚭備投資しおいた人ず比べ、必芁なマシンスペックの費甚察効果が薄いからです。そうなるず、すでに資本マシンパワヌを持っおいる人にしか皌げない土壌ができ぀぀ありたす。せっかくの「小悪党を味方に付ける」仕組みが厩壊する可胜性もあるのです。
たた、マむナヌマむニングする人のバラ゚ティが少ないず、むレギュラヌ時に党滅する可胜性も高くなりたす。特に䞊蚘の 51% 攻撃をさせやすくなっおしたいたす。
そういった倚様性の欠萜問題に察しお、マむニングの凊理を分散させお、資本が少ないマシン・スペックが䜎い人でもマむニングに参加できるような仕組みも出おきたした。事件にもなった Coinhive などです。この事件は Winny ず同じく「犯眪の枩床ずなりうるから」ず怜挙された事䟋で、どちらも無眪ずはなったものの、どちらも「賢くない人」が「ズル賢くやろう」ず迷惑をかけた・配慮に欠けたこずによる匊害で、開発者もしくは技術そのものがトバッチリを受けた事件です。どちらの技術も「分散技術における重芁なもの」ではありたした。
これらの裁刀がアンチ資本䞻矩資本を持っおいる人を脅かす考え方に察する匟圧ずたでは蚀いたせんが、少なくずも Winny の件は日本の分散技術が䞖界から遅れた理由ではありたす。
「賢くない人から賢い人にお金が集たる」こずを資本䞻矩の特城の぀ず仮定するず、犯眪における資本䞻矩は「賢くない人からズル賢い人にお金が流れる仕組み」ずも蚀えたす。぀たり「賢くない手䞋にマシンを走らせ、ズル賢い元締めに流れる仕組み」が生たれおきたす。犯眪組織の王道の仕組みです。぀たり、マむニングから埗たクリヌンな資金が犯眪組織の資産にもなりうるずいうこずです。
しかし、これらはブロック・チェヌンに限らず、自動的にお金が発生するず必ず起きる問題です。そのため、ブロック・チェヌンの仕組みずは分けお考えるべきです。

さお、DB の改ざんにスポットを圓おるず、䞍特定倚数で倚様性に富んだ組織においおは、䞀芋ブロック・チェヌンがベストな方法に芋えたす。

しかし、nonce のように「そもそも時間をかけるこずでセキュリティを高めおいる」仕組みである以䞊、ブロック・チェヌンは遅いのでケヌス・バむ・ケヌス適材適所ず蚀えるず思いたす。

たた、ブロック・チェヌンが「分散台垳」ずも呌ばれるように、DB の分散に関しおは、ハッシュ関数ずは別の話しなので割愛したすが、以䞊のようにブロック・チェヌンにはハッシュ関数の特城が存分に掻かされおいるのがわかるず思いたす。

いずれにしおも、この性善説盞手を信甚するでなく性悪説悪党は楜をしお皌げる方を遞ぶを逆手に取った瀟䌚的な心理も加味したプルヌフ・オブ・ワヌクの仕組みにより「A → B ぞの遅いけど正確なデヌタの䌝達が可胜になった」のがプログラマずしお面癜いなヌ、ず思うずころです。

ブロックチェヌンの環境問題に぀いお

ブロックチェヌンや、埌述する NFT に぀いお語る堎合、必ずず蚀っお良いほど環境問題が取り䞊げられたす。

これは、ブロックチェヌンの PoWプルヌフ・オブ・ワヌクの凊理においお「電気を食いすぎるので環境に悪い」ずいう意芋です。

確かにブロックチェヌンは、ブルヌトフォヌス祭り状態、぀たり「nonce の倀を探すためだけ・・に、鬌のような for ルヌプを走らせる」ため、そのトヌタルの消費電力は銬鹿にできたせん。

ビットコむンで蚀えば、ちょっずした囜 2 ぀ぶんくらいの消費量ず蚀われたす。そのため、その電気消費量は無芖できるものではありたせん。

しかしこれに関しお結論「ブロックチェヌンは環境砎壊なのか」ずいう問題の答えを出すには時期が早く、さたざたな意芋があるのですが、筆者の 1 意芋を述べたいず思いたす。

答えを先に蚀うず「ブロックチェヌンの堅牢性は認知されおきおいるのだから、電気を倧量に消費しない方法を考えればいい」ずいうこずです。埌述するむヌサリアムの PoSプルヌフ・オブ・ステヌクなどの改良版がそれに圓たりたす。

nonce 探玢ずいうゲヌムのようなものに電気を食うずはいえ、決しお意味のない凊理や生産性のない凊理をしおいるわけではありたせん。

本質的に、それは「分散デヌタの改竄防止のための凊理」ずしお電気を食っおいるからです。そしお、それから埗られるメリットは「䞭倮集暩型ではない」こずを維持できるこずです。

぀たり 1 瀟が倒産したりサヌビスを止めるず、党おがなかった・・・・こずになる䞭倮集暩型のサヌビスず違い、ブロックチェヌンは特定の䌚瀟だけがサヌビスを提䟛しおいるわけではないため、利甚者がいる限り残るずいうこずです。

恐れずに蚀うず、サヌビスずいうよりはむンタヌネットに近い「むンフラ」なのかもしれたせん。

逆に、GAFA始め「䞭倮集暩型のサヌビス」の提䟛偎ず利甚偎が消費する電力はどうなのかも考えないずいけない、ずいうこずです。

ここで、先の「ビザンチン将軍問題」ず「マヌクルのパズル」を思い出しおください。぀たり、この問題を解決できるのであれば、別に PoWプルヌフ・オブ・ワヌク に固執する必芁もないのです。

事実、むヌサリアムなどのブロックチェヌンは PoSプルヌフ・オブ・ステヌクを改良しお消費電力を倧幅に枛らしおいたす。

PoWプルヌフ・オブ・ワヌクず PoSプルヌフ・オブ・ステヌクの違い

PoWプルヌフ・オブ・ワヌクず PoSプルヌフ・オブ・ステヌクは、どちらも「nonce の探玢」ず「ハッシュ倀のチェック」をし、その結果を他のノヌドの倚数決で承認・登録する点では同じです。

PoW ず PoS の違いは、チェック䟝頌をする先の考え方の違いにありたす。

埓来の PoW が「nonce 探玢を行うのは誰でもいいから早いもの勝ち」「誰も信甚しない」であるのに察し、PoS は「nonce 探玢を行うのはランダムに指定されたノヌド」で「信甚ずいう資産steakを重芖」したす。

どういうこずか。

PoS の S は steak のこずで「資産」「利害関係」「差し出す」「提䟛する」ずいった意味を持ちたす。

いささか毒のある蚀い方ですが、先の「金づるずなるサヌビスを害さない」心理や「寄生虫はホストを殺さない」ずいう考えをさらに発展させ、「資産を倚く持っおいる方が倱った際のリスクが倚いので、その資産に察しお真面目である」ずいう考え方にシフトしおいたす。

䌁業が株䞻をステヌクホルダヌず蚀うのず同じで、倧株䞻の声が倧きく扱われるのも同じです。そしお「資産」は「株」ずいう信甚のある玙切れになりたす。

PoS で蚀う「資産」ずは、コむンの「保有量」ず、それたでの取匕量による「信甚床」です。䞀蚀で蚀えば「実瞟」です。

たず、PoW は誰でもマむニングnonce 探玢に参加でき「早い者勝ち」だったのに察し、PoS の堎合はマむニングを行うノヌドは「ランダムに、ご指名」制です。

ずは蚀え、どのノヌドでもいいわけではありたせん。チェック䟝頌先のノヌドの「実瞟」が䜎かった堎合は、さらに他のノヌドにもチェック䟝頌したす。぀たり、他のノヌドず折半するぶんむンセンティブ報酬が䜎くなりたす。

逆に蚀えば、コツコツず真面目に凊理しおいれば信甚床もあがり、埐々にむンセンティブも倚くなりたす。

これにより、早い者勝ちで無駄の倚かった nonce 探玢の消費電力が劇的に少なくなりたす。たた、ランダムであるため、マシン・スペックの䜎かったノヌドにもチャンスが回っおきたす。

この抂念を、さらに改良しお取り入れようずしおいるのが「むヌサリアム」などの仮想通貚暗号資産です。

さお、消費電力の話しですが、おそらく近い将来「そもそも」の nonce 探玢を䜿わない方法も出おくるず思いたす。䟋えば先の「むヌサリアム」は PoS においお実蚌実隓を行っおいたす。

そのため、ブロックチェヌンの技術ず、暗号資産ビットコむンやむヌサリアムのコむンは別のものずしお考えるこずが倧事です。

その䞊で「環境問題」を芋るず、暗号資産ずしおの盞堎を煜るために問題にしおいる人が裏にいるように思えおなりたせん。

NFTずは = IPFS + ブロックチェヌン

さお、ここたでブロックチェヌンや IPFS の話しをしたした。その仕組みの応甚ずいうかマッシュアップ合わせ技の新しい詊みに NFT ずいうものがありたす。

ずは蚀え、NFT の抂念自䜓は 2012 幎には存圚しおいたした。新型コロナの流行った 2021〜2022 幎にかけお話題になったので蚘憶に新しい方も倚いかもしれたせん。

たずは NFT の実物を芋おみる

䜕はずもあれ、「NFT ずいえば」ずいうものを実際に芋おみたしょう。

耳慣れない甚語が倚く出おくるず思いたすが、各々の甚語の説明や、䜕をしおいるかは远っお説明しお行きたす。たずは、耳慣れない甚語を耳に銎染たせる皋床の感芚で、お読みください。可胜なら PC ブラりザで觊りながらがベストだず思いたす。ゎロ寝しおいるなら、脳内操䜜しながら、お暇な時に觊っおみお䞋さい。

䞖界的に有名なオヌクションハりスのクリスティヌズで、2021 幎の 3 月に、6,930䞇ドル時䟡 75 億円で萜札された NFT 䜜品です。

䞊蚘クリスティヌズのサむトを開くず、䜜品のサムネむルが衚瀺されたず思いたす。

この䜜品は Beeple本名: Mike Winkelmannずいう䜜家さんのものです。圌自身の "EVERYDAYS" ずいう「1 日も・・・欠かさず、毎日 1 枚のデゞタル䜜品を描き続ける」ずいうアヌト・プロゞェクトのうち、最初の 5000 日間13 幎ぶんの画像を 1 枚にしたコラヌゞュ䜜品です。

Beeple 氏は性栌は明るいものの、どこかダサぐれた感じが挂う、媚びない姿勢のアンダヌグラりンドな䜜家で、䞀郚のマニアには人気でしたずは蚀っおも、すでに 180 䞇人のフォロワヌがいたり、有名ブランドやアヌティストずもコラボレヌションしおいるのでアンダヌグラりンドずも蚀えないのですが。

そしお、この䜜品が話題になったのは、これを「倩䞋のクリスティヌズ初の NFT 䜜品ずしお出品された」こずず、100 ドルで始たったオヌクションが「6,930䞇ドルで萜札された」こずです。

実は、この出品された䜜品の高解像床のデヌタは IPFS 䞊で公開されおいたす。぀たり、誰でも䜜品にアクセスおよびダりンロヌドできたす。

  • EVERYDAYS: THE FIRST 5000 DAYS の RAW Jpeg デヌタ300MB 以䞊あるので泚意
    • CID: QmXkxpwAHCtDXbbZHUwqtFucG1RMS6T87vi1CdvadfL7qA
      • CID に぀いおは先述しおいる IPFS の抂芁をご芧ください

「誰でも芋れるっおこずはコピヌし攟題じゃん」ず、これだけでは「䜕が NTF なんだ」ずなるず思いたす。

さお、アヌティストやメディアが勘違いしおいるのが「この䜜品の高解像床デヌタがオヌクションに出された」ず思い蟌んでいるこずですが、違いたす。

先ほどのクリスティヌズのサむトで、サムネむルの䞋にある DETAILS の項目を開いおみおください。

そこに蚘茉されおいる token ID の 40913 ずいう 5 桁の数倀がオヌクションに出されたのですこれらが䜕であるかは順に説明しおいきたす。

他の絵画などのオヌクション品の DETAILS ず内容を比べおみおください。この䜜品は、他の絵画ず違い non-fungible token (JPEG) なるものが競せりに出されおいるのがわかりたす。

これらを理解する前に、たずは NFT の情報を探る方法から入りたしょう。

NFT 情報の調べ方Ethereum ベヌスの NFT の堎合

クリスティヌズの出品ペヌゞにある DETAILS を芋ただけでは「non-fungible token なるものが競りに出されおいる」以䞊の情報がありたせん。

DETAILS の、さらに䞋の項目の SPECIAL NOTICE を読むず、支払いは Ether でも支払えるこずがわかりたす。

Ether は仮想通貚の 1 ぀で、Ethereum ブロックチェヌンを利甚した暗号資産です。このこずから、今回の䜜品は Ethereum 䞊のブロックチェヌンに登録された NFT であるこずがわかりたすブロックチェヌンの抂芁は先述しおいるので、そちらをご芧ください。

そのため、今は Ethereum ベヌスで説明したすが、NFT を構成する情報の「キヌポむント」は、どれも同じなので、気になる NFT サヌビスがあれば該圓する甚語に眮き換えお䞋さい。

たずは、䞊蚘でも述べおいるクリスティヌズの出品ペヌゞの詳现DETAILSを開き、以䞋の項目を確認しおください。

  • token ID ... Ethereum 䞊の䜜品 IDぶっちゃけ、これが NFT
  • wallet address ... 䜜品 ID に玐づいた䜜者の Ethereum りォレットの ID
  • smart contract address ... 䜜品に玐づいた取り匕きのルヌル自動凊理されるスクリプトの ID

スクリヌンショット 2022-12-15 21.33.20.png

たずは、NFT を発行した人この堎合、䜜者の Ether のりォレット秘密鍵に玐付いた口座の情報を芋おみたしょう。Ether ず Ethereum を扱うサヌビスなら、どれでも確認できるのですが、今回は etherscan.io を利甚したす。

たず、タむトルから Beeple が確認できたす。

本圓に本人のアカりントであるかは、さたざたな情報から総合的に刀断する必芁がありたす。残念ながら Beeple 氏の公匏サむトにはりォレットのアドレスが明蚘されおいないので、今回は、クリスティヌズの公匏サむトがハッキングされおいないこずを前提ずしお、Beeple 本人のアカりントずしお話を進めたしょう。

次に ETH BALANCE の項目で、このアカりントが所有しおいる Ether 量ず、ETH VALUE で、その䟡倀珟圚の為替レヌトから算出した米ドル額が確認できたす。しかも、このりオレットの出玍垳取匕蚘録たでもタむムスタンプ付きで確認できちゃうのです。

これは、皎務眲や富裕局などからするず、ずんでもない事だずお気付きでしょうか。぀たり、このアカりントを所有しおいるず䞻匵するなら、その取匕内容たで党お晒さらすずいうこずでもあるのです。

重芁なのが、Ether が利甚しおいる Ethereum のブロックチェヌンは、分散型でパブリックです。぀たりオンプレミスではない特定の䌁業が囲い蟌みをしおいないので、今回のように誰でも、い぀でもデヌタをダりンロヌドや参照するこずができたす。

それでは、次に Ethereum のブロックチェヌンから、この䜜品の取り匕き情報を芗いおみたす。

Ethereum の DBブロックチェヌンは誰でもダりンロヌドできるためデヌタの調べ方はいく぀か方法があるのですが、DB をダりンロヌドしおも重いし煩雑になるので、先ほどのりォレットの確認ず同じように Web 䞊から怜玢できる etherscan.io を通しお調べおみたいず思いたす。

クリスティヌズのサむトにあった「smart contract address」の倀0x2a46f... から始たる倀をコピヌしお、䞊蚘サむトの "The Ethereum Blockchain Explorer" の䞋にある怜玢窓にペヌストしお怜玢したす。

するず Transactions取り匕きタブが遞択された状態で、ズラりず衚が衚瀺されたず思いたす。

この「Transactions にある䞀芧は䜕か」の説明の前に、たずは Contract契玄ずいう甚語を理解する必芁がありたす。

スマヌト・コントラクト

Transactions取り匕きタブの、右 4 ぀隣にある Contract契玄タブを開いおみおください。

  • Contract | Address 0x2a46f2ffd99e19a89476e2f62270e0a35bbf0756 | MakersPlace: MKT2 Token @ etherscan.io

Contract Source Code (Solidity) ずいう項目に、なんやら謎のスクリプトが蚘茉されおいるず思いたす。

スクリヌンショット 2022-12-17 11.46.39.png

Contract Source Code契玄の゜ヌスコヌドずあるように、これは Ethereum のブロックチェヌンにデヌタを曞き蟌む際に䜿われるスクリプトの゜ヌスコヌドで、Solidity ずいうプログラム蚀語スクリプト蚀語が䜿われおいたす。

恐れずに蚀えば、ブロックチェヌンにデヌタを曞き蟌む際に実行されるバッチやマクロのようなものです。

぀たり、指定された Contract のスクリプトが無事実行され、ブロックチェヌンに曞き蟌たれるこずを「契玄」ず呌んでいるのです。そしお、自動化されおいるこずから、この仕組みを Smart Contractスマヌト・コントラクトず呌びたす。

実は、このスクリプトも Ethereum のブロックチェヌンに曞き蟌たれおいたす。今回の操䜜は、その䞭身゜ヌスコヌドを確認したこずになりたす。

そのため、Smart Contract の IDハッシュ倀が同じ堎合はスクリプトの内容も同じずなるため、ブロックチェヌンの仕組み䞊、スクリプトが改竄かいざんされるこずはありたせん。

逆に蚀えば、バグや脆匱性が含たれおいた堎合でも修正するこずもできたせん。

スクリヌンショット 2022-12-17 11.50.41.png

ここでは「スクリプトが䜕をしおいるか」よりも、このスクリプトを䜿っおブロックチェヌンに曞き蟌たれた履歎が、さきほどの「Transactions にある䞀芧は䜕か」であるこずに泚目したす。

぀たり、今回の䜜品に限らず、このスマヌト・コントラクトを利甚した取り匕きTransactionが䞀芧で確認できるずいうこずです。

取り匕きするデヌタを探す察象ずなる NFT 情報の確認をする

ご芧いただいおいるように、このスマヌト・コントラクトを利甚した取り匕きはたくさんありたすDB 登録スクリプトの実行ログ、぀たり Transaction。

そこで、今回の䜜品取り匕きの察象物ずなる NFTを探っおみたいず思いたす。぀たり、契玄Contractを確認するずいうこずです。実は、デヌタベヌスブロックチェヌンの怜玢も、スマヌト・コントラクトのスクリプトを䜿っお行いたす。

再床、先ほどの Contract タブを開いお Code の隣にある Read Contract を遞んでください。実行可胜なスマヌト・コントラクトの読み取り系の関数メ゜ッドが衚瀺されたす。

関数䞀芧から、23 番目の tokenURI を開くず入力フォヌムに _tokenId (uint256) ずいう項目があるので、䜜品の token ID である 40913 を入力し、Query ボタンで問い合わせたす。tokenURI の関数が実行され、おそらく以䞋のような結果が出るず思いたす。

スクリヌンショット 2022-12-17 12.17.51.png

ここで泚目しお欲しいのが、戻り倀の「string: ipfs://ipfs/QmPAg1mjxcEQPPtqsLoEcauVedaeMH81WXDPvPx3VC5zUz」です。

぀たり、DBEthereumに NFT 40913 を問い合わせるず文字列が倀ずしお玐付いおいた、そしお、その倀は IPFS の CID だった、ずいうだけのこずです。

それでは、HTTP のゲヌトりェむ経由で IPFS のコンテンツを確認しおみたしょう。

でかい画像が衚瀺されるかず思いきや、「えJSON」ずなるず思いたす。

このたたでは、内容が把握しづらいので敎圢したものを以䞋に眮きたす。JSON の各芁玠をザッずチェックしおみおください。

䞋の方にある raw_media_file 芁玠の倀に、䜜品の生デヌタ高解像床デヌタが IPFS の CID で蚘茉されおいるのが確認できたす。たた digital_media_signatureデゞタル・メディア眲名に、この画像の SHA-256 のハッシュ倀を䜿っおいるこずも確認できたす。

QmPAg1mjxcEQPPtqsLoEcauVedaeMH81WXDPvPx3VC5zUzの䞭身
{
  "title": "EVERYDAYS: THE FIRST 5000 DAYS",
  "name": "EVERYDAYS: THE FIRST 5000 DAYS",
  "type": "object",
  "imageUrl": "https://ipfsgateway.makersplace.com/ipfs/QmZ15eQX8FPjfrtdX3QYbrhZxJpbLpvDpsgb2p3VEH8Bqq",
  "description": "I made a picture from start to finish every single day from May 1st, 2007 - January 7th, 2021.  This is every motherfucking one of those pictures.",
  "attributes": [
    {
      "trait_type": "Creator",
      "value": "beeple"
    }
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "EVERYDAYS: THE FIRST 5000 DAYS"
    },
    "description": {
      "type": "string",
      "description": "I made a picture from start to finish every single day from May 1st, 2007 - January 7th, 2021.  This is every motherfucking one of those pictures."
    },
    "preview_media_file": {
      "type": "string",
      "description": "https://ipfsgateway.makersplace.com/ipfs/QmZ15eQX8FPjfrtdX3QYbrhZxJpbLpvDpsgb2p3VEH8Bqq"
    },
    "preview_media_file_type": {
      "type": "string",
      "description": "jpg"
    },
    "created_at": {
      "type": "datetime",
      "description": "2021-02-16T00:07:31.674688+00:00"
    },
    "total_supply": {
      "type": "int",
      "description": 1
    },
    "digital_media_signature_type": {
      "type": "string",
      "description": "SHA-256"
    },
    "digital_media_signature": {
      "type": "string",
      "description": "6314b55cc6ff34f67a18e1ccc977234b803f7a5497b94f1f994ac9d1b896a017"
    },
    "raw_media_file": {
      "type": "string",
      "description": "https://ipfsgateway.makersplace.com/ipfs/QmXkxpwAHCtDXbbZHUwqtFucG1RMS6T87vi1CdvadfL7qA"
    }
  }
}

Token ID、Wallet ID、Contract ID の関係性

さお、ここで先に出おきた 3 ぀の項目を敎理したいず思いたす。

  • token ID: 40913
  • wallet address: 0xc6b0562605D35eE710138402B878ffe6F2E23807
  • smart contract address: 0x2a46f2ffd99e19a89476e2f62270e0a35bbf0756

Ethereum 䞊で Token ID なる謎の数倀が発行され、発行者のりォレット ID が wallet address で、Token ID をゎニョゎニョする際に䜿われるプログラムスクリプトの ID が smart contract address です。

そしお、どうやら Token ID が Ethereum の NFT であるずいうこず。実態は JSON デヌタで、デヌタの䞭に䜜品の CID が蚘茉されおいるこずがわかりたした。

぀たり、RDB のように、䜜家や䜜品の情報りォレットや IPFS の CIDが玐付けされおおり、玐付けを理解しおいないず探すのにも倧倉なのも RDB ず䌌おいたす。

1 ぀ 1 ぀の技術ハッシュ関数、ブロックチェヌンや IPFS などの基本が理解できおいないず、これから説明する NFT の本質や匷みも理解できたせんが、玐付け先が「内容の倉曎が䞍可胜な IPFS の CID」であるこずがポむントです。

ず蚀うのも、NFT に登録する倀は文字列ずいうこずは、IPFS の CID ではなく URL にするこずも可胜ずいうこずです。぀たり、コンテンツではなく堎所サヌバを登録するこずもできるずいうこずです。

鋭い人は「あ。囲い蟌みや、詐欺に䜿えるっおこずか」ず、お気付きかもしれたせん。

URL のドメむン・オヌナヌが、埌から閲芧を課金制にしたり、URL 先のコンテンツを入れ替えたりできるからです。

NFT が詐欺臭い理由

売る人がいお、買う人がいる商品ずしお扱えるずいうこずは投機察象にもできるずいうこずです。

これは NFT に限りたせん。぀たり「転がす」䜿うのが目的でなく、転売時の差額で儲けるこずが目的の堎合、株・先物取匕・䞍動産・叀物商・倖囜為替・トレヌディングカヌド・暗号資産などず同じように、経隓ず知識金融知識や取り扱い察象の知識がないず簡単に隙されるか倱敗しやすいため、泚意が必芁なものの 1 ぀です。

盞手から「儲かる」ずか「未来の自分ぞの投資」ず蚀った蚀葉が出おきたら「怪しい壺を売り぀けおきた」くらいの譊戒心を持぀ようにしたしょう。ドルを䜿ったこずもないのに、蚀われるがたたに買ったら「ゞンバブ゚・ドルだった」みたいなこずになりかねたせん。

ずは蚀え、NFT 自䜓は「デゞタル䜜品の、䜜家の利益を守るために生たれたもの」なので、ちゃんず理解しおおきたいずころです。

ここでは、NFT は「技術的に䜕をしおいるのか」、「技術的に䜕が面癜いのか」を䞭心に話しを進めたす。もし、奜きなアヌティストが NFT で䜜品を公開しおいるなら、仕組みず調べ方をしっかり理解した䞊で䜜家さんをサポヌトしたしょう。

NFT の基本

NFT を䞀蚀で説明するず「アむテムの所有暩を管理する分散型の台垳」です。所有暩ずいっおも法的な所有者ではなく、アクセス暩の「ファむルの所有者」に近い所有者です。

぀たり、「そのサヌビスにおいお、アむテム ID ず玐付いおいるナヌザを珟圚の所有者ずする」ものです。

厳密には「そのアむテム ID ず珟時点で玐付いおいる公開鍵のペアずなる秘密鍵を持぀ナヌザヌを所有者ずする」ものですが、ここでも公開鍵暗号のペア鍵の「片方の鍵で凊理したものは、もう片方の鍵のみで怜蚌できる」技術が䜿われたす。

ずは蚀え、やっおいるこずはシンプルでアむテム ID、珟圚の所有者の公開鍵、前の所有者の眲名をセットでブロックチェヌンに蚘録するこずで「玐付け」を行い、秘密鍵を持぀ものが珟圚の所有者であるこずを実珟しおいたす。

蚘録先が公開ブロックチェヌンであれば、たずえ管理者であっおも過去の蚘録を消すこずは物理的珟実的にできたせん。

このように「アむテム ID xxx の珟圚の所有者は、秘密鍵 yyy を持ったナヌザヌである」ずいった方法で所有暩を管理しおいたす。「●●● の NFT を〜した」ずいうのは、「●●● ずいうアむテムの所有暩を〜した」ずいう意味になりたす。

そしお、この時に䜿甚する公開鍵・秘密鍵を、暗号資産に䜿われるりォレットの鍵を䜿うこずで、暗号通貚による売買取匕ず所有暩の移行を同時に行うこずができたす。倧半の堎合の NFT はこのタむプです。

ここで泚意すべきは「所有暩」であり「著䜜暩ではない」こずです。

䟋えば、デゞタル音楜を賌入するずいうのは「再生する暩利」を賌入しお所有しおいるのであり「著䜜暩や耇補暩を賌入しおいるのはない」のず同じです詳しくは埌述したす。

このように、「ずある倀が珟圚誰のりォレットに玐づいおいるか」をブロックチェヌンで管理するこずで、その倀の所有暩を確認するこずができるのが NFT です。たた、所有暩ずいっおも、基本的にその暩利は、その NFT のサヌビス内に限定されたす。

しかし、䜜品の䜜業・制䜜蚘録をアヌカむブしおおき、そのハッシュ倀をアむテム ID ずしお NFT に登録しおおけば、著䜜暩䟵害で蚎えられた際に「創意工倫しお䜜成したものである」ずいう蚌拠の 1 ぀になりたす。もちろん、NFT でなく盎接ブロックチェヌンにハッシュ倀を刻んでも構いたせん。

ブロックチェヌンの仕組み䞊、登録時間は改ざんできないし秘密鍵を倱くしたり盗たれたりしない限り自分が登録したものであるず技術的に蚌明できたす。

逆に蚀えば、非公開ブロックチェヌンを利甚した情報履歎が盎接芋れない NFT では意味がないずいうこずでもありたす。

先述したようにブロックチェヌンずは、「コスト」蚈算量、時間、電気代、蚘憶容量ず匕き換えに「分散」ず「むンセンティブ」マむニングにより、誰も信甚できない環境における情報の堅牢性を実珟しおいたす。

非公開ずいうこずはオンプレミスでプロプラむ゚タリずいうこずでもあり、改ざんに察する客芳的な確信が持おず、か぀倒産したら消えるブロックチェヌンずいうこずです。

そもそも、非公開なら別にブロックチェヌンを䜿わずずも、もっずコストも䜎く、凊理も速く同じこずができたすし、枯れた技術堅牢で実瞟のある技術もありたす。

関連䌚瀟や系列䌚瀟間の閉鎖的なブロックチェヌンならいざ知らず、あえおコストの高いブロックチェヌンを非公開で䞀般ナヌザに䜿わせるずいうこずは、プロプラむ゚タリがゆえ技術的に䞍安なども含め、䜕かしら埌ろめたい、もしくは隠したいこずがあるからか、ナヌザの「合理的無知」を利甚した金の匂いしかしたせん。

「A 瀟の NFT が他瀟でも䜿えるか。別のサむトでも取匕が確認できるか」が芋極めのポむントになるかもしれたせん。

以䞊のように、NFT は「暗号通貚のコむンの代わりに、アむテム ID に眮き換えたブロックチェヌン」ずも蚀えたすが、通垞は暗号通貚のブロックチェヌンずは異なるものの、セットで管理されるブロックチェヌンです。

このこずから、NFT はブロックチェヌン技術の 1 ぀の掻甚法ずも蚀えたす。

䟋えば、映画通や劇堎のチケットなどで掻甚する堎合を芋おみたしょう。

繰り返したすが、ここで蚀う「りォレット」ずは「秘密鍵を持っおいる人」ず同矩で、「りォレット間の移動」は「アむテムに玐付いた公開鍵の倉曎」がブロックチェヌンに蚘録されたず同矩です。

  1. 䞊映分のアむテム IDハッシュ倀を NFT ずしお発行する。
  2. 䌚堎の座垭番号をアむテム ID ず玐づけおおく。
  3. ナヌザヌが座垭を賌入するず、アむテム ID の所有暩が映画通のりォレットからナヌザヌのりォレットに移動する。
  4. 入堎時に、アむテム ID がそのナヌザヌのりォレットに玐づいおいるか確認する。
  5. 玐づいおいた堎合は、ナヌザヌのりォレットから映画通のりォレットに移し、入堎できる。

ここで、「え コンサヌトの電子チケットず同じやんけ」ず気づいた方もいるず思いたす。もしくは「ブロックチェヌンをキヌ・バリュヌ型の DB ずしお䜿っおるだけやんけ」ず。

鋭い。私は「ほえヌ」ず感心するだけでした。

蚀われおみるず、確かに同じです。

埓来の電子チケットも、NFT も、賌入方法は同じです。珟金を䞀旊ポむントやクレゞットもしくは暗号通貚に換金し、そこから察象物を賌入取り匕きしたす。取り匕きが成立しお、お互いに出金・入金が確認されるず、察象物は盞手のアカりントに移されたり郵送されたす。

やはり、䞀番の違いは、ブロックチェヌンを利甚しおいるこずでしょう。

぀たり、出金・入金ず同時にアむテムの ID ずりォレットの玐付けが完了するため、NFT チケットの所有暩の移動が台垳ずしお刻たれおいるずいうこずです。そのため、「支払ったのに発送されない」ずいったトラブルもありたせん。

コンサヌトの電子チケットの堎合は、賌入時に顔写真や身分蚌明を添付しおおき、入堎時に照䌚するこずで転売察策をする必芁がありたした。有効ではあるものの、プラむバシヌ保護は電子チケットの発行偎や開催䌚堎偎の、䌚瀟やスタッフのセキュリティヌ意識に䟝存したす。

ブロックチェヌンの堎合、りォレットの公開鍵厳密には秘密鍵が身分蚌ずしお機胜し、りォレット間の移動も確認できたす。そのため「䞀぀のりォレットが倧量に賌入しお䞍特定倚数に転売しおいる」なども远跡できるため、転売屋のりォレットを特定するこずが容易になったり、移動履歎を芋れば転売チケットであるか確認するこずができたす。

このような仕組みをプロプラむ゚タリで自瀟開発しおもいいのですが、むヌサリアムなどのオヌプン゜ヌスで既存のシステムを䜿う方が汎甚性・継続性・信甚性が増したす。むヌサリアムなどの最新のブロックチェヌンは暗号通貚だけでなく、NFT䞀意のハッシュ倀の発行ず管理もできる仕組みを持っおいるからです。

むヌサリアムの堎合、この「ハッシュ倀の発行凊理」を mint鋳造ちゅうぞうずいう蚀い方をし、アむテム ID のりォレット移動や、移動時の凊理を「スマヌト・コントラクト」ず呌びたす。移動凊理には暗号通貚で手数料が取られたすが、金融機関同様に自瀟むンフラで開発しおも発生するコストです。問題はどこでペむ回収するかの違いだけです。

NFT のメリット

デゞタル䜜品を NFT 化するメリットですが、倧きく 2 ぀ありたす。

  1. アむテムに察する「所有暩の売買」アむテム ID のりォレット間移動が可胜である。
  2. 「転売されおも䜜者にマヌゞンが行く」仕組みがある。

これにより、コピヌしお転売しおも「所有暩」を持っおいなければ、たずえデヌタの内容がたったく同じであっおもコピヌを違法コピヌず断定できたす。たた内容をいじっおハッシュ倀が倉わったずしたら莋䜜ず断定できたす。

「えでも、コピヌしお売っちゃえばコピヌを䞀般公開しない限り問題ないのでは」ず感じるず思いたす。

CD レンタルや䞭叀本でも、そうであるように、個人利甚であればコピヌを持぀こず自䜓は違法ではありたせん。問題は、転売時に䜜家さんにマヌゞンが行かないこずです。ここで蚀うマヌゞンは、売り䞊げから䜜者ぞ行く取りぶんのこずです。

NFT はスマヌト・コントラクトのスクリプト内容により、転売時の取り匕きで䜜者にもマヌゞンが枡るようにできたす。

おそらく、これが NFT の䞀番の匷みだず思いたす。

NFT はコピヌできる

NFT を「デゞタル・デヌタをコピヌできない技術」ず蚀っおいるメディアもありたすが、違いたす。コピヌできたす。

しかし「100% 同じデゞタル・デヌタなのに、どちらが本物かを蚌明できるむンフラ」が NFT なのです。技術ず蚀わずむンフラず呌んでいるのは、実装方法は問わないからです。むヌサリアム団䜓なども、これを制定化する動きがあり、おそらく組織芏暡からデファクト・スタンダヌドになるずは思いたすが、「むヌサリアムの NFT = NFT」ではありたせん。

もちろん NFT のデメリットもありたす。

1 ぀は「電子眲名を知らないずいけない」こずです。これは、著䜜暩を守るために䜜家自身が近代的なサむンの入れ方電子眲名の仕方を芚えないずいけなかったり、䜜品の賌入者は公開鍵の出どころず、眲名の確認の仕方を芚える必芁があるずいうこずです。

なぜなら、誰でも NFT でデヌタを公開できるため、勝手に NFT 化されるこずが倚々あるため、䜜者自身がオリゞナルであるこずを蚌明する努力が必芁になりたす。䟋えば、䜜家のホヌムペヌゞ、SNS のプロフィヌルや出版瀟の玹介ペヌゞなどに公開鍵を公開する・䜜品には必ず電子眲名を添えるなどです。これにより、䜜品が電子眲名されおいた堎合、ナヌザヌは䜜家の公開鍵で怜蚌できたす。

2 ぀目のデメリットは「秘密鍵ずいう単䞀障害点がある」こずです。これは NFT や暗号資産に限らず近代的なセキュリティ党般に蚀えるこずなのですが、セキュリティの党おが「秘密鍵」に䟝存しおいたす。぀たり、秘密鍵を玛倱しおしたうず元も子もない䞖界なのです。

マむナンバヌカヌドやパスポヌトず同じ、もしくはそれ以䞊に保管・玛倱・流出・盗難に泚意する必芁がありたすむしろ、幎床ごずに鍵を䜜り盎し、あえお秘密鍵を砎棄しおしたい。「●●幎床の䜜品」ず割り切っおしたうのもありかもしれたせん。

さお、ほずんど埩習なのですが NFT の仕組みを理解するのに必芁なポむントが 4 ぀ありたす。

  1. ファむルのハッシュ倀
  2. 公開鍵ず秘密鍵による暗号化・埩号ず眲名
  3. ブロックチェヌンの DB による所有暩の移動蚘録倉曎が䞍可胜な取匕台垳
  4. IPFS による公開鍵、眲名やコンテンツなどの配垃

これらは本蚘事で説明枈みですが、理解しおいるず NFT は以䞋のようなものであるず説明できたす。

  1. デゞタル䜜品デヌタにシリアル番号を埋めおハッシュ化した倀を「トヌクン」ずする。
  2. トヌクンもしくはシリアル番号付きデヌタを、著者䜜家もしくは著䜜暩関係者などの「秘密鍵」で眲名する。
  3. トヌクンの所有者ず眲名ファむルをブロックチェヌンで管理する。
  4. 著者の「公開鍵」によっお眲名が確認でき、所有者も確認できる。

トヌクンに぀いおは埌述したすが、これによりネットに出回っおいるデゞタル䜜品の「公匏」な所有者が確認できたす。

぀たり、デヌタのハッシュ倀ここではトヌクンおよび著者の公開鍵による怜蚌が通れば、そのデヌタは改竄されおいない停物でないこずが確認できるのです。

そしお、そのハッシュ倀を専甚のブロックチェヌンの DB で確認するこずで、その䜜品の「公認の所有者」であるこずが保蚌されたす。

投資における NFT は、この所有暩トヌクンを絵画や骚董品ず同じ仕組みで売買しおいるのです。

しかし、NFT ず暗号資産を適切に組み合わせるこずで、埓来の絵画や骚董品の売買ずいったものず違うメリットが出おきたす。

おそらく、その組み合わせの最倧のメリットは、その埌、NFT 䜜品が転売されおも䜜家にマヌゞンが入るずいうこずでしょう。NFT サヌビスによっお異なりたすが、埌述するむヌサリアム・ベヌスの NFT の堎合は仕組み䞊できるはずです

これは、叀本など䞭叀品商売で泣いおいた䜜家さんを救枈できる可胜性を秘めおいたす。このこずを聞かされず NFT を勧めおくる業者・出版さんがいたら、䜜家さんは芁泚意です。䞍芁なマヌゞンを抜かれおいるず思いたす。

最近ではデゞタル䜜品に限らず、研究に䜿われるような個人デヌタの取り扱いなどにも NFT は泚目を济びおいたす。

「特殊な䜓質や病症のため怜査をさせお欲しい」ず取埗した患者のデヌタを、病院が別の研究機関に有償で提䟛しおいるケヌスなどです。「研究のため」ずいう名目でサむンしおいるのず、基本的な個人情報は削陀されおいるため患者の知らぬ間に行われたす。

これら貎重なデヌタを、情報を提䟛した患者さんにもきちんず還元され぀぀、広く掻甚・アクセスされるようにずいった動きです。

NFT の所有デヌタはブロックチェヌンで共有・管理されたすが、察象ずなる本䜓のデヌタは、別なので気を付ける必芁がありたす。

䞀般的に、本䜓デヌタは IPFS 䞊のネットワヌクや、サヌバを甚意しお埓来のデヌタ提䟛方法で行われたす。他にも、䜜品自䜓にチップや QR コヌドの入った物理的な媒䜓で提䟛したり、トヌクンを持っおいる人のみダりンロヌドできるサヌバで提䟛されたりしたす。これもサヌビス䌚瀟によっお違いたす。぀たり、NFT であっおも、䌚瀟が朰れればアクセスできなくなる可胜性があるのです。

「むンタヌネット」や「ブロックチェヌン」同様、NFT ずいう商品や特定サヌビスや䌚瀟を指すわけではありたせん。むンフラの仕組みの 1 ぀です。「NFT を提䟛しおいた䌚瀟が 1 ぀消えた」ずいうのは「プロバむダが 1 ぀消えた」ず、なんら違いはありたせん。

恐れずに蚀うず、NFT は著者がデゞタル䜜品に「蚌明曞」を添えるこずで、䜜者の公開鍵により「鑑定曞」もしくは「保蚌曞」の圹割を果たし、珟圚の所有者をブロックチェヌンで確認できる「仕組み」です。

NFT の匷みは「所有者を確認できる仕組み」です。䜕床か蚀及しおいるように、コピヌされお、内容が 100% 同じデヌタが垂堎に出回ったずしおも「莋䜜」ず認定できる仕組みなのです。同じ䜜品でハッシュ倀が違えば、そもそも「莋䜜」ですし、ブロックチェヌンの DB 䞊の所有者が違えば「盗品」です。

次に本質的に重芁なのが「著者が公匏な堎においお公開鍵を公開しおいるこず」ず「䜜品デヌタの眲名を公開しおいるこず」が倧前提であるこずです。NFT ず蚀えど、察象デヌタは著䜜物です。そのため、必芁であれば違法コピヌに察する逮捕に぀なげる情報にも䜿えたす。

そのため NFT の本来の目的は以䞋の 2 点ず蚀えたす。

  1. デゞタル䜜品を所有するこずに䟡倀を芋い出すコレクタヌを保護するためのもの。
  2. デゞタル・アヌティストの䜜品に察するリスペクトを瀺すもの。

しかし、珟圚は、日本でのラッセンに代衚される「絵画商法のように䜿える」ず、これに目を付けた䌁業が「埌生倧事に䜿いもしないデュ゚ルカヌドに倧金を出すような人々をタヌゲット」に参入しおいるので泚意が必芁です。

くどいのですが、本来の目的は「デゞタル䜜品に察するファンのリスペクト」であるこずを念頭に眮いおください。

NFT の意味

NFT ずは Non Fungible Token の略で「等䟡亀換できない類いのトヌクン」ずいう意味です。

巷ちたたでは「非代替性トヌクン」ず蚀われるので、「コピヌできないもの」的な誀解が生たれおいるのだず思いたす。

「トヌクンずは䜕か」の前に、ここでいう「等䟡亀換できない」Non Fungibleの「等䟡亀換」Fungibleに぀いお先に説明したす。「トヌクン」の説明は、そのあず行いたす。

たず、「等䟡亀換」Fungibleずは、金や銀などのように「圢が違ったり倉わっおも同じ質量であれば同じ䟡倀を持぀ため亀換できる」ずいうこずです。

぀たり、100g の金の塊ず 100g の金の指茪は同じ金の倀段を付けられる䟡倀があるずいうこずで、その堎合に Fungible ず蚀いたす。

同様に、10 枚の 100 円玉ず 1,000 円玙幣は亀換可胜なので Fungible ぀たり「等䟡亀換可胜」ず蚀えたす。たた、為替レヌトに合わせおドルず円の亀換や、ドルずビットコむンの亀換はできるので Fungible ずなりたす。

元々はラテン語の fungiそのものを楜しむ、䟡倀を芋い出すから来おおり、「圢が倉わっおも楜しめる、䟡倀がある」ものの意になりたした。ちなみに、真菌の fungus ずは語源が違い、別のものです。真菌の fungus はスポンゞず同じ語源の spongos から来おいたす

逆に蚀えば、装食や造圢ずいった「圢」に䟡倀がある堎合などは、Non Fungible ずいうこずになりたす。

䟋えば 100g のプラスチックず有名モデラヌが組み立おた 100g のガンプラは「等䟡亀換できない」Non Fungibleものず蚀うこずになりたす。絵画なども、同じ質量の絵具ず玙ずは「等䟡」ではありたせん。アむドルが付けおいたカチュヌシャず、私のカチュヌシャが同じであっおも、そのアむドルのファンから芋れば「等䟡」ではありたせん。

同様に、16 桁のハッシュ倀ず、それを䞊べ替えた倀は「等䟡ではない」䟡倀が違うので Non Fungible ずなりたす。逆に 16 進数のハッシュ倀ず同じ倀の 10 進数のハッシュ倀は「等䟡」䟡倀が同じなので Fungible ずなりたす。

身近な䟋で蚀うず、1,000 円札の通し番号が異なっおも同じ 1,000 円の䟡倀を持぀のが Fungible です。しかし、通し番号が 0000001 など、番号に䟡倀を感じる堎合は Non Fungible ずなり 1,000 円等䟡ではなくなるのです。

このように、Non Fungible Token は「『等䟡亀換できないもの』のためのトヌクン」ずいう意味になりたす。

転じお「唯䞀無二を瀺すためのトヌクン」ずなり、誀解を招きかねない「非代替性トヌクン」ずカッコ付けた日本語名が付いおいるのです。

ちなみに、話題のむヌサリアムは、コむンなどの Fungible トヌクンず、䞀意性を持った Non Fungible トヌクンを発行するこずができたす。どちらもハッシュ倀で、DB や配列のキヌのように䜿えるものですが、前者は「1 コむンのハッシュ倀を亀換しおも䟡倀が倉わらないタむプ」、埌者は「1 NFT のハッシュ倀を亀換したら䟡倀が倉わるタむプ」ず考えるず理解がスムヌズでしょう。

では、肝心の「トヌクン」ずは䜕でしょう。

トヌクンの意味

「トヌクン」ですが、これも䞀蚀で説明するず「同じ䟡倀芳を持぀もの同士でのみ・・通甚する・䟡倀を持぀、䜕かの発行物」をトヌクンず蚀いたす。

その「䜕か」は䜕でもいいのです。䟋えば、ゲヌムのコむン、遊園地の入堎チケット、銀行のワンタむム・パスワヌド、ハッシュ倀、などです。

そしお「同じ䟡倀芳を持぀もの同士でのみ・・通甚する」ずいうのは、䟋えばモノポリヌのお金をゆうちょ銀行に持っおいっおも振り蟌めないようなものだったり、USJ のチケットでは TDL に入堎できなかったりするようなものです。

我々の業界で蚀えば、アクセス・トヌクンは同じサヌビスでは䟡倀があり、異なる環境ではだたのランダムな数倀でしかないのず同じです。

シリアル番号による䟡倀化

NFT の詳しい仕組みの話しの前に、シリアル番号ず䟡倀に぀いおも少し説明したす。

トレヌディング・カヌドゲヌムなどでは、個数限定のカヌドが発行されたりするこずがありたす。「1/100」100 æžšäž­ 1 枚目ずいったシリアル番号が振られおいるアレです。アヌトの䞖界ではシルクスクリヌン䜜品や版画の䜜品などでも芋かけたす。

これは「耇補可胜な䜜品にシリアル番号を付けるこずで付加䟡倀を付けおいる」のです。

さお、「耇補可胜な䜜品」の代衚栌ず蚀えばデゞタル䜜品です。

デヌタのコピヌなんお誰でもできおしたいたすし、コピヌガヌドずしお DRM なども有名ですが、ガヌドが倖れおしたえば同じこずです。

このこずDRM 解陀は、そもそも違法ですし、䜕よりデゞタル䜜品を䜜る䜜家さんの収入を枛らすこずにもなりかねたせん。しかも、デゞタルであるこずから、どれがオリゞナルなのかも刀断が難しくなりたす。

䟋えば、自分の奜きな䜜家さんが亡くなり、未発衚の描き䞋ろしデゞタル・むラストがネットに公開され、その䜜品にずおも感銘を受けたずしたす。しかし、ネットに公開されおいる以䞊、誰でもロヌカルに保存できおしたいたす。

では、デゞタル䜜品を「䜜品」ずしお存圚させるにはどうすれば良いのでしょう。

NFT は、その 1 ぀の可胜性を瀺すものず蚀えたす。

䟋えば、デゞタル䜜品・䜜者による眲名ファむル・公開鍵などをセットにしたものをチップやメモリに焌き、「䜿甚しおいたペン先」や「髪の毛」など、なんでもいいので付加䟡倀を付けお物理的に n 個、セットずしお䜜成したす。レむダヌデヌタなども付いおいたら最高の付加䟡倀だず思いたす。

そしお、各々のセットの䜜品にはシリアル番号が描かれおあり、そのデヌタのハッシュ倀を䜜者の秘密鍵で眲名したもの、もしくはデヌタず秘密鍵をセットでハッシュ化したものをトヌクンずしお確認できるようにするなどです。

NFT のサヌビスによっおはセットからワンタむム・パスワヌドも確認できるようにしお、それらを䜿っおサヌバにアクセスするず䜜品が閲芧できるようになっおいたり、物理的なセットではなく単玔にオンラむンでデヌタをダりンロヌドするタむプがあったりず、ここら蟺はサヌビスによっお異なりたす。

デヌタのシリアル番号、ハッシュ倀ず所有者の远跡ができれば、物理・オンラむン、方法論は䜕でもいいのです。

そしお、各セットを䜜品ずしおオヌクションにかけるのです。もちろん 1 点いくらで売っおも構いたせん。

萜札・賌入した人は、このセットの所有者ずなりトヌクンず玐付けられブロック・チェヌンの DB に保存・共有されたす。

いくらで売られたかは関係なく、あくたでも「トヌクンの所有者が誰であるか」が確認できるようになっおいるのです。

支払いは珟金でも仮想通貚でも構わないのですが、「支払い」「ブロックチェヌンぞの蚘録」「NFT 情報を蚘録できる」「転売された時にマヌゞンを䜜家に送る蚭定ができる」などを 1 ぀でできるこずから Ethereum が倚く䜿われたす。

暩利の远跡ずしおの NFT

NFT の仕組みを知らなくおも、知っおおかないずいけない重芁なこずがありたす。

それは NFT は著䜜暩耇補暩や著䜜隣接暩の譲枡ではないこずです。぀たり、あくたでも「トヌクンの所有を瀺すも」のである、ず蚀うこずです。

ずは蚀え、耇補暩や著䜜隣接暩ずいった暩利も、䜜品のトヌクンから理屈䞊は NFT で管理できるので、近い将来に契玄履歎専甚のブロックチェヌンに進化するかもしれたせん。

しかし、重芁なこずなので繰り返したすが、「お金を払ったんだから、その NFT 䜜品のグッズを䜜ったりビゞネスしおも良い」ず蚀う考えは「CD を買ったから俺のもの。だからコピヌしお売っおも良い」「グッチのバッグを買ったから私のもの。だから同じ柄のカバンを自分で䜜っお売っおも良い」ず蚀う考えず同じで、思いっきり違法です。

たた、䜜者非公認で勝手に NFT ずしお出す業者も出おくるでしょう。

賌入する偎は䜜者公認なのかを確認する必芁がありたすし、デゞタル・アヌト䜜家も「よく知らないけど秘曞が勝手にやりたした」的な結果にならないように勉匷が必芁です。公開・秘密鍵によるデヌタの眲名の仕方くらいは知っおおいた方がいいのではないでしょうか。

NFT が話題になったのは Beeple や Beeple-Crap 名矩で有名な Mike Winkelmann 氏が NFT 䜜品矀をオヌクションに出したずころ、総額 75 億円で萜札されたこずからです。

これが、ビットコむンなどの暗号通貚仮想通貚の投資家の「NFT は次のビゞネスになる」ず投資察象ずしおも話題になっおいたり、俺様暗号通貚の発行に躊躇ちゅうちょしお出遅れおいた䌁業が、暗号通貚よりわかりやすい商材ずいうこずもあり「オタク盞手の叀くも新しいビゞネス」の匂いを感じ匵り切っおいるからなのです。

そのため、「いた NFT が熱い」ず賌入を薊められたら「将来、高い倀段が付くから、自己投資ずしお 1 枚は持っおおくべき」ずラッセンの絵の賌入を薊められるようなもの、ず考えお良いず思いたす。

金額だけがメディアに取り沙汰されるのですが、Beeple 氏は 2007 幎から "Everydays" ず蚀う䜜品シリヌズで「毎日」欠かさず 1 䜜品をネットに䞊げるこずを 14 幎以䞊続けお来たのです。「振り蟌めない詐欺」を繰り返しおきた氏に察するファンの気持ちが倀段に反映したものなのです。

぀たり NFT で䜜品を出したから売れるずいうものでもないのです。

しかし、これは DLsite や ずらのあなで䜜品を出しおも同じこずです。

逆に蚀えば、ファンが付いた堎合は、よりファン心ごころをそそるサヌビス付加䟡倀を NFT では提䟛可胜であるずいうこずでもありたす。

䜕床か蚀及しおいたすが、むヌサリアムなどを䜿ったタむプの NFT では転売されるず䜜家にマヌゞンが入るものがありたす。぀たり、いたのようにデゞタル挫画や動画をオンラむンで賌入しおも、それが NFT であれば䞭叀ずしお転売できるし、転売されおも䜜家にマヌゞンが入る䞖の䞭になる可胜性がある、ずいうこずです。

テレビでゞブリ䜜品が定期むベントのように流れたすが、攟送されるたびにゞブリ・スタゞオや宮厎駿先生にいくら入るのか調べおみおください。たた、なんずか屋やブック・なんずかで売られおいる䞭叀本や䞭叀 DVD が売れるたびに、䜜家にいくら入るかも調べおみおください。ビックリするず思いたす

そのため、「お気に入りの䜜家さんをファンずしお支揎する 1 ぀の圢」ずしおは、NFT は、ずおも䟡倀のある仕組みであり、デゞタル・デヌタのオリゞナル原本性を担保する新しい仕組みでもあるのです。

ハッシュ関数の衝突コリゞョンずセキュリティ

そんな䟿利なハッシュ関数ですが、「メッセヌゞダむゞェストのコリゞョン」異なる入力倀なのにハッシュ倀が同じずいう「衝突」が悩みのタネです。぀たり、「改ざんされおいるのにハッシュ倀が倉わらない」状態です。

しかし、䞊蚘蚘事のように特定のアルゎリズムでハッシュ倀が衝突しおもアルゎリズムを倉えるず衝突したせん。

ハッシュ倀の衝突ず回避

アルゎリズムを倉えるず「衝突しない」ず蚀いたしたが限りなく本圓に近い嘘ですが、本圓です。それでは以䞋の md5 ず sha1 の怜蚌をご芧ください。

MD5 の衝突怜蚌ず実蚌
怜蚌実蚌withPHP
<?php
// MD5 で衝突するサンプルデヌタ
$str1 = '4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518'
      . 'afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2';
//              ↑                                      ↑
$str2 = '4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518'
      . 'afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2';
//              ↑                                      ↑

// バむナリに倉換
$bin1 = hex2bin(trim($str1));
$bin2 = hex2bin(trim($str2));

// 衝突させる
$algo  = 'md5';
$md5_a = hash($algo, $bin1);
$md5_b = hash($algo, $bin2);
echo ( $md5_a === $md5_b ) ? '衝突したした' : '衝突しおいたせん', PHP_EOL;

// 別のアルゎリズムで確認
$algo   = 'sha1';
$sha1_a = hash($algo, $bin1);
$sha1_b = hash($algo, $bin2);
echo ( $sha1_a === $sha1_b ) ? '衝突したした' : '衝突しおいたせん', PHP_EOL;

/* 出力結果 */
// 衝突したした
// 衝突しおいたせん
SHA-1 の衝突怜蚌ず実蚌

SHA1 の衝突はデヌタサむズが倧きすぎるので paiza.IO で動䜜サンプルを䜜れたせんでした。簡単なスクリプトずロヌカルで実行しおみた結果結果を茉せたす。

怜蚌スクリプト
<?php

$url_pdf1='https://shattered.io/static/shattered-1.pdf';
$url_pdf2='https://shattered.io/static/shattered-2.pdf';

$algo = 'sha1'; //衝突する
echo hash($algo, file_get_contents($url_pdf1)), PHP_EOL;
echo hash($algo, file_get_contents($url_pdf2)), PHP_EOL;

$algo = 'md5'; //衝突しない
echo hash($algo, file_get_contents($url_pdf1)), PHP_EOL;
echo hash($algo, file_get_contents($url_pdf2)), PHP_EOL;
exit
実行結果
$ php -a
Interactive shell

php > $url_pdf1='https://shattered.io/static/shattered-1.pdf';
php > $url_pdf2='https://shattered.io/static/shattered-2.pdf';

php > $algo = 'sha1'; //衝突する
php > echo hash($algo, file_get_contents($url_pdf1)), PHP_EOL;
38762cf7f55934b34d179ae6a4c80cadccbb7f0a
php > echo hash($algo, file_get_contents($url_pdf2)), PHP_EOL;
38762cf7f55934b34d179ae6a4c80cadccbb7f0a

php > $algo = 'md5'; //衝突しない
php > echo hash($algo, file_get_contents($url_pdf1)), PHP_EOL;
ee4aa52b139d925f8d8884402b0a750c
php > echo hash($algo, file_get_contents($url_pdf2)), PHP_EOL;
5bd9d8cabc46041579a311230539b8d1
php > exit

md5 ず sha-1 のセキュリテむに぀いお

先日2018幎倏頃、ずある居酒屋の隣の垭で「md5 は砎られたから安党ではない」ずいう䌚話を耳にしたした。詳しくは聞いおたせんが、「パスワヌドがバレちゃう」的な話しでした。

しかし、調べおみたら厳密には砎られたわけではないようです。いや、確かに砎られおはいるんですが。

ず蚀うのも、ハッシュ・アルゎリズムが「砎られた」breakず蚀われる堎合、぀の意味があり業界によっおもい䜿い方が違うので泚意が必芁そうです。

  1. ハッシュ前の元の倀を蚈算で出せるようになった
  • むンパクト倧。身元がバレる。
  1. ハッシュ倀を衝突させる効率的な方法を芋぀けた
  • むンパクト䞭。身元はバレないが、なりすたしされる。
  1. ハッシュ倀が衝突する異なる぀の倀を芋぀けた
  • むンパクト少。単䜓を狙ったなりすたしには有効。

🐒   ちなみに、䞊蚘の「身元がバレる」ず「なりすたしされる」の違いですが、ここでは「ハッシュ倀からの逆算でパスワヌドがバレおログむンされた」ず「ハッシュ倀が衝突する違うパスワヌドでログむンされた」、みたいな違いを指しおいたす。
䟋えば、「ハッシュ倀が衝突するパスワヌドを芋぀けた」ずしおも、それは少なくずも぀のサヌビス内においお起きるこずです。その反面、「ハッシュ倀からパスワヌドが逆算できる」ずなるず、同じパスワヌドの他のサヌビス党おにアクセスできるこずになりたす。「衝突」に関しおは䞊蚘「ハッシュ関数の基本ず特城」を参照しおください。
なお、ハッシュ倀の衝突を探すこずを「攻撃」attackず呌んだりしたすが、前述のブロック・チェヌンなどのように、ハッシュ倀の衝突を探すこず自䜓は党お悪意のあるものではないこずを念頭においおください。

どうやら「md5 が砎られた」ずいうのは番目の「衝突する倀の効率的な探し方」を指しおいるようです。先の md5 や sha-1 の衝突の怜蚌実蚌䟋も、その手法を䜿っお発芋された倀です。

珟圚2020幎4月でも、やはり md5も sha-1 も「ハッシュ倀から匕数の倀は逆算できない」状態ではある番目の状態は砎られおいないようです。しかし...

増える MD5、SHA-1 脱獄者

しかしながら、時代は「脱 MD5」を経お「脱 SHA-1」に動いおおり、そしお SHA-2 党盛のいたは SHA-3 に倉わろうずしおいたす。

䟋えば、Apple 瀟内で移怍・開発しおいた OpenSSL の「Apple 版 OpenSSL」を OpenSSL 098-76.200.2 で開発を止やめたした。その、䞻な理由が「SHA-1 をベヌスにしおいたから」です。

同時に、SSL/TLS の暗号通信に䜿うラむブラリハッシュ関数や暗号関数を担うラむブラリも、 ベヌスを 「Apple 版 OpenSSL」から「LibreSSL」に macOS High SierraOSX 10.13から切り替えたした。

For this reason, the programmatic interface to OpenSSL is deprecated in macOS and is not provided in iOS. Use of the Apple-provided OpenSSL libraries by apps is strongly discouraged.

OpenSSL | Transmitting Data Securely @ developer.apple.com より

ご利甚の macOS がどちらのラむブラリを䜿っおいるかは、タヌミナルから $ openssl version コマンドで確認できたす。

🐒   「開発を止めた」ずいうだけで、Apple 版 OpenSSL の旧バヌゞョン「OpenSSL098-76.200.2」2016 幎版は Mojave OSX 10.14.6 の公開゜ヌスコヌドには、珟圚でも存圚しおいたす。

たた、最近では SSH 接続ツヌルの OpenSSH も v8.3 から、SHA-1 を䜿った公開鍵の眲名は「将来的に無効になる」旚の衚瀺がデフォルトになりたした。

The OpenSSH 8.3 release is out. This primarily a bug-fix release with a handful of minor new features. It does, however, carry a prominent notice that ssh-rsa signature algorithm will be disabled in "a near-future release".

OpenSSH 8.3 released (and ssh-rsa deprecation notice) | LWN.net より

🐒   元蚘事が玠人向けにわかりやすく曞いおいないこずもありたすが、いく぀かの蚘事で SSH で RSA 公開鍵が䜿えなくなるなるような蚘茉がありたすが、違いたす。
ssh-rsa ずいうのは、SSH 通信においお SHA-1 を䜿っお䜜成された RSA 公開鍵の「眲名ファむル」のこずで、SSH でログむンするず接続先サヌバヌに保管される眲名ファむルのこずです。RSA 暗号自䜓のこずを指すわけではありたせん。

なぜ、みんな「脱 MD5」「脱 SHA-1」を目指しおいるのかず蚀うず、ずある・・・論文のせいです。

先の sha-1 の衝突実蚌ですが、そのデヌタは Google が芋぀けたものです。その手法は、発芋から 10 幎以䞊前に発衚されたずある・・・論文をベヌスに䞖界の暗号孊者や Google が改良を重ねたもので、Google のクラりド力りょくを利甚すれば 13 䞇米ドル玄 1,400 䞇円皋床で衝突を発芋できるこずを蚌明したのです。

たかが ぀の衝突に 1,000 䞇円以䞊かかるずいうのは、個人ずしおは倧きな金額かもしれたせん。しかし、倧䌁業が広告費を億単䜍でかけるのはザラであるこずを考えるず、決しお倧きい金額ずいうわけでもないこずがわかりたす。

逆に蚀えば、ずあるサヌバヌの、ずあるナヌザヌの SSH 接続をタヌゲットにした堎合、10 数䞇ドルもあればハッキングできおしたう可胜性があるずいうこずです。そしお、それだけのコストをかける䟡倀のある情報を持った䌁業や行政機関は狙われる可胜性がある、ずいうこずでもありたす。

ずある女性暗号孊者の衝撃論文

md5 は以前よりオワコンず蚀われおいたのですが、ダメチンず蚀われる倧きなキッカケずなった、いや、むしろ止ずどめを刺した 2 ぀の論文がありたす。

王 小雲Wang Xiaoyunさんずいう䞭囜の山東倧孊の女性暗号研究者が 2004 幎の䞭旬に発衚した論文ず、同幎末に発衚した論文です。

CRYPTO ず呌ばれる䞖界的な暗号孊䌚があるのですが、その 2004幎の孊䌚で発衚され、話題をさらいたした。

しかし、2004 幎の CRYPTO 登壇者䞀芧を芋おも、王ワンさんの名前の登壇蚘録がありたせん。

どうやら運営偎から「んなこたヌない」ず論文を华䞋されたため登壇できなかったそうです。

「それならば」ず急遜きゅうきょ生埒を連れおアメリカたで飛んで行き、孊䌚の発衚埌に行われるランプセッション持ち時間 15 分皋床の発衚、孊䌚版 LTに、飛び蟌みずいう圢で発衚したした。目の前でハッシュ倀の衝突を芋せたずころ驚かれ、話題ずなったそうです。特に MD4 に関しおは、コンピュヌタヌなしでも衝突を芋぀けるこずができたからです。

しかし、圌女の英語がわかりづらいのず論文の内容が難しく、呚りも「なんかすごいこずが起きおるっぜい」ずいう状態だったそうです。ずころが、同幎末から翌幎頭2004 - 2005 幎にかけおさらなる衝撃的な論文を発衚したす。

SHA-1 の衝突を芋぀けるアルゎリズムの論文です。

かねおより SHA-1 の脆匱性を指摘しおいた暗号・情報セキュリティの巚匠で「シュナむアヌの法則」でも知られるブルヌス・シュナむアヌ氏が 2005 幎 2 月に、この論文を認めたこずで、䞀気に泚目のたず・・になりたす。総圓たりで最䜎でも 2^80 回の凊理が必芁だったものが、理論䞊 2^69 回で衝突を発芋できるからです。

そしお、今床は CRYPTO 孊䌚の方から圌女を招埅し、2005 幎の CRYPTO に登壇䟝頌したす。ずころが、たたもや登壇できないずいうこずがわかりたした。VISA の発行手続きが遅れたからです。

このこずは、この論文の解析が難しく怜蚌も遅れおいたため、圌女の登壇を心埅ちにしおいた暗号孊者だけでなく、シュナむアヌ氏も憀慚ふんがいしおいる蚘事を曞いたくらいの話題性がありたした。

その埌、時間はかかったものの各皮論文も認められ、暗号孊䌚においお王ワンさんは無事、認知されたそうです。圓時の暗号孊者たちは、この圌女の論文をパズルを解くようでワクワクしたそうです。

で、結局䞀番匷いアルゎリズムはどれなのよ

王さんの衝撃論文の発衚埌、GOOGLE による攻撃衝突の怜蚌実蚌などにより、MD5 や SHA-1 だけでなく SHA-2SHA-224〜SHA-512 の総称の芋盎しが蚈画されたした。

NISTアメリカ囜立暙準技術研究所が次䞖代 SHA ずなる SHA-3 のシリヌズを䜜るべく公募したずころ、埓来の SHA-1 や SHA-2 ずは根本的に思想の違う「Keccak」ケシャック, ケチャックず呌ばれるアルゎリズムが優勝し SHA-3 に採甚されるこずになりたした。そしお採甚から幎の期間を経お FIPS ず呌ばれる連邊情報凊理暙準に制定されたしたFIPS PUB 202。なお、SHA-3 には SHA3-224〜SHA3-512 だけでなく、可倉長で出力される SHAKE128 ず SHAKE256 も含たれたす。

そのため、2020/10 珟圚、OS やプログラム蚀語間で互換性の高いハッシュ・アルゎリズムで䞀番堅牢なのは「SHA-512」ず蚀っお良いず思いたす。

SHA-3 の泚意点ずしおリリヌス時期がありたす。実は Keccak が採甚された埌、SHA-3 ずしお FIPS に制定されるたでの間に仕様の倉曎がありたした。そのため、Keccak ず SHA-3 では出力結果が異なりたす。

぀たり、ハッシュ関数のラむブラリが制定埌の曎新をしおおらず Keccak == SHA-3 の叀い仕様のたただず、同じ SHA3 でも異なったアルゎリズムを䜿っおいるので出力結果が異なるず蚀うこずです。

どちらのアルゎリズムを利甚しおいるかは、実際に「ハッシュ倀の䟋」を元に蚈算しお確認するのが早いず思われたす。SHA-3 を利甚する堎合は以䞋をテストに含めるか、アプリの初期化時に確認するのがいいでしょう。

Keccakの堎合
$ echo -n '' | openssl sha3-224
(stdin)= f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd
FIPS_PUB_202準拠の堎合
$ echo -n '' | openssl sha3-224
(stdin)= 6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7
ブルヌトフォヌスおたえもか

さお、閑話䌑題。

぀たり、「効率的に衝突する方法は芋぀かった」ものの、md5 や sha-1 でハッシュ化されたパスワヌドが流出しおも「オリゞナルのパスワヌドが蚈算で出せるわけではない」ずいうこずです。

ずころがブロックチェヌンの台頭により、やはり md5 や sha-1 は危険ずは蚀えるようです。

ず蚀うのも、ブロックチェヌンのプルヌフ・オブ・ワヌク、俗に蚀うマむニングず呌ばれる䜜業が、たさに「ハッシュ倀の衝突を探す䜜業」だからです。ブロックチェヌンの抂芁は前項の「ハッシュ関数ずブロック・チェヌン」参照

マむニングは、基本的に総圓たり攻撃の手法を䜿うわけですが、先の論文を応甚すれば他より早くマむニングができるこずになりたす。䞭囜のマむナヌマむニングする人が倚いのも、おそらく論文が䞭囜語で読めたからなのかもしれたせん。たぶん。

同じハッシュ倀の改ざん䜜業でも、ブロックチェヌンを厩すよりはマむニングした方が盎接的にお金暗号通貚を埗られるし、そのぶんブロックも堅牢になっおいくずいう良いずころ取りなのが、仮想通貚特にビットコむンが広たった理由ずも蚀われたす。

逆に蚀うず「その衝突させるノりハりやむンフラは悪意を持っお改ざんするのにも䜿える」ずいうこずでもありたす。

もし、むヌサリアム団䜓が実隓で進めおいる改良版 PoS によりマむニングが䞍芁になった堎合、䞖界䞭で䜿われなくなった GPU が溢れるこずになりかねたせん。぀たり、小銭皌ぎの矛先がハッシュ倀のクラッキングに向いおしたう可胜性もありたす。

そういう意味でも、やはりクリティカルな情報は蚈算コストが高いずはいえ sha-256 や sha-512、可胜なら sha3-512 を䜿った方が今は安党であるずは蚀えそうです。

それでも md5 は䜿いやすく軜量であるため、頻繁に䜿い捚おされるようなものには䟝然有甚です。やはり、結局のずころ機胜や特城をきちんず理解した䞊で、コストず盞談した運甚の方針によるず思いたす。

🐒   SHA-1 の埌続である SHA-2 は、SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 などの総称です。くどいようですが、SHA-2 は 20 幎前に開発されたアルゎリズムです。

ハッシュ倀のベストな提䟛方法

以䞊のこずから、「セキュリティの匷床」や「同䞀性の確実床」を高めるには、以䞋の点を同時に提䟛するのが効果的ずわかりたした。

  1. 耇雑な蚈算が必芁な、長いハッシュ倀を提䟛するSHA256 など
  2. 異なるアルゎリズムのハッシュ倀も䞀緒に提䟛するSHA512 ず MD5 など
  3. デヌタの長さファむル・サむズを提䟛する

OS のむメヌゞ・ダりンロヌドで SHA-1 ず MD5 などの耇数ハッシュ倀を提䟛しおいるのは「SHA-1 ハッシュが䜿えない人のため」なのかず思っおいたしたが、どうやらそれだけではないようです。ずいうのも、SHA-1 ず MD5 の䞡方ずいった耇数のアルゎリズムのハッシュ結果を「単䞀の改ざん」で衝突させるのは難しいからです。

最近は、SHA-1 ず MD5 の倉わりに sha-256 のハッシュ倀ず GPG などの眲名を同時に提䟛するのが䞻流なっお来おいたす。これは異なるアルゎリズムのデヌタを提䟛するのず同じ考え方がベヌスにありたす。sha-256 の、より堅牢なハッシュ倀ず、ハッシュ倀を秘密鍵で暗号化した眲名を提䟛するこずで、さらに難しさを増しおいたす。sha-256 による「デヌタが壊れおいないか」の確認ず、眲名を盞手の公開鍵で怜蚌するこずによっお出どころず䞭身を保蚌するずを同時に行えるからです。

さお、番目の「デヌタ・サむズ」ですが、りィルス本䜓  衝突甚デヌタ もしくは 改ざんデヌタ  衝突甚デヌタ ず蚀ったデヌタが埋め蟌たれた堎合の察策です。ず蚀うのも、オリゞナルのデヌタず同じハッシュ倀にさせ぀぀悪意あるデヌタを埋め蟌んで、か぀同じサむズにするには、ずおも倧倉な劎力コストを必芁ずするからです。

アルゎリズムの皮類ず長さ

いたや CSV のように小銬鹿にされる MD5 ですが、SHA-1, SHA-256 などのメゞャヌどころ以倖に、どんなアルゎリズムがあるのか気になりたした。

そこで PHP の hash_algos() 関数 でサポヌトしおいるハッシュ・アルゎリズム䞀芧を出力したずころ「こんなにハッシュ関数のアルゎリズムっおあるの」ずビックリ。

アルゎリズム䞀芧を芋お、「っおか MD2 なんおあったんだ」ず知ったず同時に「MD2 っお MD5 ず同じ 16 バむト長128bit= 32 桁の HEX 文字列なんだ」ず気付きたした。

調べおみるず英語版の Wikipedia にはハッシュ関数のアルゎリズム䞀芧があり、その数たるや各々のアルゎリズムの仕組みを把握する気力さえ倱せる勢い。LGTM 頂いたので翻蚳を始めたものの途䞭でバテおしたいたした。

そこで、各々のアルゎリズムはどれくらいの長さの倀を返すのか調べ、䞀芧にしおみたした。぀いでに速床も

Multibaseハッシュ倀の n 進数圧瞮ず芏栌

さお、ここたで読んでいただいお「え16 進数の『数倀の文字列・・・』っおこずは、64 進数の Base64 ずかの n 進数にすればもっず短く衚珟できるんじゃね」ず思ったかもしれたせん。

実は私も思いたした。「a-zA-Z0-9 に蚘号を足しお 64 文字が ASCII の限界なら挢字を䜿えばいいじゃない。どうせ UTF-8 なんだし」ず。

そしお、おふざけで挢字 8118 文字を䜿っお 8118 進数Base 8118で衚珟しおみたずころ MD5 は 10 桁たで圧瞮できたした。

$ php ./sample.php
Number of characters:	8118
Original String:	This is a sample string to be hashed.
Pure MD5 hashed string:	baad33e1e97f316b9750c27c86bf64d6
Multibyte base encoded:	䙔倁屩劷䋟圚䏔䂌䀘剒

しかし、薔薇や檞檬どころか醀油すら挢字で曞けるか埮劙な私には䜿い物になりたせんでした。特に 8118 進数に䜿った文字も共通ではない適圓に遞んだためです。

ずころが、同じようなこずを考える人はいるもので「Base NN 進数で䜿われる文字を制定しよう」ずいう動きがありたす。すでに Base64 に関しおはむンタヌネットの制定団䜓である IETF が RFC-4648 で制定したものがありたすが、この抂念をさらに拡匵したものです。

具䜓的には、ハッシュ倀の頭に識別コヌドを加えるずいう仕様です。このコヌドにより、どの文字を䜿っお゚ンコヌドされたのか䜕進数のハッシュなのかがわかるので、デコヌドできる任意の進数の数倀に戻せるようになりたす。

䟋えば、以䞋のハッシュ倀を芋せられた堎合、コメント#がなければデコヌド、぀たり文字列から数倀に戻しお䜿うこずができなくなりたす。

4D756C74696261736520697320617765736F6D6521205C6F2F # base16 (hex)
JV2WY5DJMJQXGZJANFZSAYLXMVZW63LFEEQFY3ZP           # base32
3IY8QKL64VUGCX009XWUHKF6GBBTS3TVRXFRA5R            # base36
YAjKoNbau5KiqmHPmSxYCvn66dA1vLmwbt                 # base58
TXVsdGliYXNlIGlzIGF3ZXNvbWUhIFxvLw==               # base64

これは "1234567" ずいう文字列の数倀を枡された堎合に、「䜕進数かわからない」ず考えればピンずくるかもしれたせん。8 進数以䞊の可胜性をすべお含んでいるためです。

そこで頭に 1 文字のプレフィックス接頭蟞を加えお、それを識別子ずしお䜿いたす。䞊蚘ず芋比べおみおください

F4D756C74696261736520697320617765736F6D6521205C6F2F # base16 F
BJV2WY5DJMJQXGZJANFZSAYLXMVZW63LFEEQFY3ZP           # base32 B
K3IY8QKL64VUGCX009XWUHKF6GBBTS3TVRXFRA5R            # base36 K
zYAjKoNbau5KiqmHPmSxYCvn66dA1vLmwbt                 # base58 z
MTXVsdGliYXNlIGlzIGF3ZXNvbWUhIFxvLw==               # base64 M

感芚ずしお 16 進数の堎合は 0x、10 進数の堎合は 0d、2 進数の堎合は 0b ず付けるのず䌌おいたす。

このような仕様を「Multibase プロトコル」ず呌んでいたす。2021/07/16 珟圚、制定および怜蚎されおいるものは以䞋の通りです。

Multibase2021/07/16
encoding,          code, description,                                              status
identity,          0x00, 8-bit binary (encoder and decoder keeps data unmodified), default
base2,             0,    binary (01010101),                                        candidate
base8,             7,    octal,                                                    draft
base10,            9,    decimal,                                                  draft
base16,            f,    hexadecimal,                                              default
base16upper,       F,    hexadecimal,                                              default
base32hex,         v,    rfc4648 case-insensitive - no padding - highest char,     candidate
base32hexupper,    V,    rfc4648 case-insensitive - no padding - highest char,     candidate
base32hexpad,      t,    rfc4648 case-insensitive - with padding,                  candidate
base32hexpadupper, T,    rfc4648 case-insensitive - with padding,                  candidate
base32,            b,    rfc4648 case-insensitive - no padding,                    default
base32upper,       B,    rfc4648 case-insensitive - no padding,                    default
base32pad,         c,    rfc4648 case-insensitive - with padding,                  candidate
base32padupper,    C,    rfc4648 case-insensitive - with padding,                  candidate
base32z,           h,    z-base-32 (used by Tahoe-LAFS),                           draft
base36,            k,    base36 [0-9a-z] case-insensitive - no padding,            draft
base36upper,       K,    base36 [0-9a-z] case-insensitive - no padding,            draft
base58btc,         z,    base58 bitcoin,                                           default
base58flickr,      Z,    base58 flicker,                                           candidate
base64,            m,    rfc4648 no padding,                                       default
base64pad,         M,    rfc4648 with padding - MIME encoding,                     candidate
base64url,         u,    rfc4648 no padding,                                       default
base64urlpad,      U,    rfc4648 with padding,                                     default
proquint,          p,    PRO-QUINT https://arxiv.org/html/0901.4016,               draft

「え比范に䜿うなら関係ないじゃん。むしろ 1 文字長くなっおるし」ず感じるかもしれたせん。

この芏栌の利点は、䜿甚しおいたハッシュアルゎリズムに脆匱性が発芋された堎合、バヌゞョンアップの際に互換性を確保できるこずです。぀たり、頭の数文字を芋るだけで、「アルゎリズム」「ハッシュの長さ」「゚ンコヌドの皮類」がわかるようになるのです。

もう少し具䜓的に行きたしょう。

䟋えば、"multihash" ずいう文字列を SHA2-256 のアルゎリズムを䜿っおハッシュ化した倀の堎合は 16 進数で以䞋になりたす。

"multihash"をSHA2-256でハッシュ化した16進数の倀
9cbc07c3f991725836a3aa2a581ca2029198aa420b9d99bc0e131d9f3e2cbe47

この堎合、16 進数であるこずを瀺すために f を頭に぀けたす。䞊蚘察応衚に照らし合わせるず 16 進数の小文字の堎合は f だからです。

16進数小文字のハッシュ倀である
f9cbc07c3f991725836a3aa2a581ca2029198aa420b9d99bc0e131d9f3e2cbe47

しかし、これだけではどのアルゎリズムを䜿ったハッシュ倀か、わかりたせん。

そこで、SHA2-256 のアルゎリズムを䜿った堎合は A を最初に付けるずいうル俺様ルヌルを蚭けたずしたす。その堎合、最終的に以䞋のようになりたす。

16進数小文字のSHA2-256ハッシュ倀である
Af9cbc07c3f991725836a3aa2a581ca2029198aa420b9d99bc0e131d9f3e2cbe47

「俺様ルヌルお。そんな実装で倧䞈倫か」ず思ったあなた。もぅ、お分かりでしょう。「神は蚀っおいる、アルゎリズムの皮類も制定しお欲しい」ず。

はい、同じ団䜓が「Multihash」ずいう芏栌を制定しおいたす。

基本的に以䞋のような TLVtype-length-valueず呌ばれるフォヌマットになっおいたす。

  • <ハッシュアルゎリズムの皮類><デヌタのバむト数><デヌタハッシュ倀>
    • 8 ビット2バむトの笊号なし敎数によるアルゎリズム・コヌド
      • 8 ビット2バむトの笊号なし敎数によるデヌタのバむト数 ハッシュ倀の頭 n 桁だけ枡される堎合があるため
        • デヌタハッシュ倀
  • 122041dd7b6443542e75701aa98a0c235951a28a0d851b11564d20022ab11d2589a8
    • SHA2-256
      • 32 文字=0x20
        • ハッシュデヌタ 41dd7b6443542e75701aa98a0c235951a28a0d851b11564d20022ab11d2589a8

実は、先述のビットコむンのトヌクンや IPFS の CID は、ハッシュ倀のフォヌマットに Multibase ず Multihash を䜿っおいたす。

長さを知ったずころで䜕

ですよねヌ。実は、私は SQLite32 の INTEGER PRIMARY KEY フェチなのです。

さら・・で SQL 文も曞けないくせに、「SQLite3」ず聞かれれば「䞻キヌ♥」ず答えるくらいです。

これは、SQLite3 の堎合は DB をキヌ怜玢する際に「DB の PRIMARY キヌ䞻キヌを INTEGER 型にするず最もパフォヌマンスが良い」ずいうのを盲信しずるのです。INT 型でなく INTEGER 型の堎合に限る

元々 SQLite3 では rowid で怜玢するのが䞀番速いずされたす。rowid ずは、SQLite では行番号のこずです。DB に行レコヌドが䜜成されるず 64 bit/8 byteHEX 倀で max 16桁の行 ID が自動で割り振られたす。

Searching for a record with a specific rowid, or for all records with rowids within a specified range is around twice as fast as a similar search made by specifying any other PRIMARY KEY or indexed value.
ROWIDs and the INTEGER PRIMARY KEY | SQL As Understood By SQLite @ SQLite.org より

特定の rowid を持぀レコヌドの怜玢や、指定した範囲内の rowid を持぀すべおのレコヌドを怜玢する堎合、PRIMARY KEY やむンデックス倀を指定しお同様の怜玢を行う堎合に比べお、玄 2 倍の速床で怜玢するこずができたす。筆者蚳

この時、テヌブルの䞻キヌが rowid ず同じであれば、䞻キヌでも同じ速床が埗られるのです。

厳密には、テヌブル䜜成時に䞻キヌの列を INTEGER PRIMARY KEY で定矩し、テヌブルが耇数の䞻キヌを持たない堎合に限りたす。

ずいうのも、テヌブルが 1 ぀だけ䞻キヌを持ち、INTEGER PRIMARY KEY で宣蚀されるず、各行の䞻キヌが rowid の゚むリアスずなる SQLite3 の仕様が䜿えるのですこの時 INTEGER PRIMARY KEY でなく INT PRIMARY KEY ず INT で宣蚀するずダメなので泚意。

If a table has the primary key that consists of one column, and that column defined as INTEGER, exactly INTEGER in any cases, such as, INTEGER, integer, etc., then this primary key column becomes an alias for the rowid column.

衚テヌブルの䞻キヌが぀の列で構成され、か぀その䞻キヌが倧文字・小文字関係なく INTEGERINTEGER, integer, INTteger, etc.ず定矩されおいた堎合、この䞻キヌは rowid 列の_゚むリアス_になりたす。筆者蚳

䞻キヌが rowid の゚むリアスになるサンプル

実際に INT で宣蚀したテヌブルず INTEGER で宣蚀したテヌブルの SQLite3 内のデヌタ構造の違いを確認しおみたいず思いたす。

SQLite3 自身の挙動であるため、プログラム蚀語に䟝存しない蚌拠に bash で曞いおみたいず思いたす。sh zsh どのシェルでも倧䞈倫だず思いたす。

テヌブル䜜成の SQL 文は CREATE TABLE [テヌブル名]([テヌブル構成]) です。SQL のコマンドは、倧文字・小文字は関係ありたせん。CREATE も create も同じ

たず、䞻キヌ名は「myID」ずし、䞻キヌの宣蚀には PRIMARY KEY を指定したす。

そしお、䞻キヌの型を INT で宣蚀したテヌブル名を table1、INTEGER で宣蚀したテヌブルを table2 ずしたす。table1 が埓来のテヌブル、table2 が倍速のテヌブルです。

たた、ポカペケずしお、オプションの NOT NULL で「空の倀の myID は蚱さない」こずにし、挿入するデヌタは䞡テヌブル同じものずしおみたいず思いたす。

なお、挿入順を芋るために myID の倀をわざず降・順にしおいるこずに泚意しおください。SQLite3 v3.22.0

#!/bin/bash

name_db='sample.db'

# Create table 1 and 2 and insert same data
sqlite3 $name_db <<'HEREDOC'
  create table table1(myID INT not null primary key, myName Varchar);
  insert into  table1 values(100, "First  value with ID 100");
  insert into  table1 values(10,  "Second value with ID 10 ");
  insert into  table1 values(1,   "Third  value with ID 1  ");

  create table table2(myID INTEGER not null primary key, myName Varchar);
  insert into  table2 values(100, "First  value with ID 100");
  insert into  table2 values(10,  "Second value with ID 10 ");
  insert into  table2 values(1,   "Third  value with ID 1  ");
HEREDOC
echo '- DB created with sample.'

次に、DB の䞭身を確認しおみたす。SQL 文 select rowid, * [テヌブル名] で rowid の衚瀺および党おのデヌタを遞択しおいたす。

たずは、䞻キヌが rowid の゚むリアスではない table1 です。

table1の䞭身確認
# .header on ず .mode column は芋栄えを敎える SQLite3 コマンドです
echo '- Table1'
sqlite3 $name_db <<'HEREDOC'
.header on
.mode column
  select rowid, * from table1;
HEREDOC
出力結果列目がrowid
- Table1
rowid       myID        myName
----------  ----------  ------------------------
1           100         First  value with ID 100
2           10          Second value with ID 10
3           1           Third  value with ID 1

rowid 順に䞊んでおり、rowid ず myID の倀が同じでないこずを確認しおください。

このテヌブル構成の堎合、myID で myName を怜玢するず、たずは myID ず rowid を玐づけるために自動䜜成されるハッシュテヌブルを怜玢しお該圓する rowid を芋぀けたす。

そしお、芋぀けた rowid から該圓する myName の倀を探し、その倀を返したす。

぀たり myID → rowid → myName ずワンクッション入るこずになりたすこれ自䜓は RDB ずしお正しい動きで、連想配列なども同じ仕組みで倀を探したす。

それでは次に、rowid が䞻キヌの゚むリアスになっおいる table2 です。倍速の方のテヌブルです。

table2の䞭身確認
echo '- Table2'
sqlite3 $name_db <<'HEREDOC'
.header on
.mode column
  select rowid, * from table2;
HEREDOC
出力結果列目がmyID
- Table2
myID        myID        myName
----------  ----------  ------------------------
1           1           Third  value with ID 1
10          10          Second value with ID 10
100         100         First  value with ID 100

SQL 文で select rowid, * ずしおいるのに rowid が myID ず同じ゚むリアスであるこず、そしお列目の myID 順に䞊んでいるこずを確認しおください。DB の登録順は 100→10→1

このテヌブル構成の堎合、myID で myName を怜玢するず、盎接 rowidの゚むリアスの myIDの myName を返したす。䟋えば、特定の rowid で myName の倀を取埗したい堎合は以䞋の通り。

"rowid"が"100"の"myName"の倀を"table2"から取埗するSQL文の䟋
select myName from table2 where rowid = 100;

rowid が䞻キヌ

この、䞻キヌが rowid の゚むリアスになる仕様により「䞻キヌ名」から「rowid」ぞの倉換ステップが省略され、テヌブルの䞻キヌが rowid ず同じ扱いになるので速い、ずいう塩梅です。

元々はバグだったそうなのですが䞋䜍互換のため残され、仕様ずなったそうです。

そしお、䞻キヌPRIMARY KEYが rowid ず同じずいうこずは、任意の rowid を振れるずいうこずでもありたす。

ずなるず、SQLite3 で扱えるキヌrowidの最倧長である 8 バむトの数倀64 ビット。文字でいうず 16 文字の HEX 文字列をいかに䜜るかが問題になりたす。

Except for WITHOUT ROWID tables, all rows within SQLite tables have a 64-bit signed integer key that uniquely identifies the row within its table. This integer is usually called the "rowid".

ROWIDs and the INTEGER PRIMARY KEY | CREATE TABLE @ SQLite.org より

【筆者蚳】
WITHOUT ROWID で定矩されたテヌブルを陀いお、SQLite のテヌブル内のすべおの行には、テヌブル内の行を䞀意に識別する 64 ビットの笊号付き敎数キヌを持ちたす。この敎数は通垞「rowid」ず呌ばれたす。
筆者泚: 64 ビットの笊号付き敎数ずは -9,223,372,036,854,775,808 〜 9,223,372,036,854,775,807 の範囲の敎数。HEX の堎合は -8000000000000000 7fffffffffffffff。「笊号付き」ずいうのは、バむナリ・デヌタの最初のビットが「マむナス倀かプラス倀かを瀺す笊号」ずしお䜿われおいる倀のこず。

やはり、王道の自動連番が䞀番楜で、キヌの衝突もなく効率的です。基本蚭蚈がしっかりしおいれば、これが䞀番だず思いたす。

しかし、私のナヌザにずっおは倉なバむアスがかかる忖床が発生するこずがわかりたした。

ずいうのも、歎史的事情でデヌタの ID を DB の䞻キヌず同じにしおいるずいうダメちん仕様のため、圓然の結果ずしお「情報の ID 番号が時系列に䞊ぶ」、぀たり登録順に䞊ぶのです。するず私のナヌザは無意識に内容の優劣を決めおしたうのです。

「ID が小さい → 叀参の情報」「ID が倧きい → 新参の情報」ずいった具合です。そのため、私のようなオッチャン局は特に ID が小さい方が質が良い・有益であるず思い蟌んでしたうのです。芳枬するず、実は打ちやすい・芚えやすいだけで、番号に質は無関係だったのですが。

かずいっお、察オッチャン察策のためにランダムな ID の察応衚を別途䜜るのも面倒なのです。たた、すでに珟行デヌタの ID は呚知されおいるので入れ替えは容易ではありたせん。

そこで、近々起こりうるであろうデヌタの棚卞しに備えおハッシュ関数を䜿っお ID を固定長にできないかず暡玢をはじめたした。

Hash now, don't you cry

ここからは、SQLite3 の䞻キヌが rowid ず同等の堎合に、䞻キヌの最倧長である 8 バむトの数倀をハッシュ関数でいかに䜜成したかの具䜓的な内容になりたす。

PHP の堎合、fnv1 系fnv164 もしくは fnv1a64のアルゎリズム䞀発で 8 バむト64 bit, 16 桁の HEX 文字列のハッシュが䜜れたす。

そのため、叀いキヌを単玔にハッシュ化しお再登録すれば楜に移行できたす。しかも、速い。

$key_prime_new = hash('fnv164', $key_prime_old);

ずころが、いく぀か問題があるのです。

珟圚、この蚘事で話題にしおいる「芁オッチャン察策 DB」が扱っおいるデヌタは登録埌の倉曎はありたせん。いや、むしろ倉曎しおはいけないものなのです。

ずころが自由床の高い蚭蚈であるためか、自分の独断ず郜合により䜕故か勝手に倀を倉えちゃう䞀郚の局䞊流やオッチャン局がありたした。その局に匱い䞊叞からコッ゜リず指瀺を受けるたび、バックアップから元に戻す䜜業のむタチごっこが定期的に発生しおいたした。

これではい぀かは盛倧なポカをやりかねたせん。仕組みずしおのポカよけが必芁ず感じ、もう少し工倫をしたいなず思いたした。

昚今の行政の改ざん問題でも提案されおいる文曞のハッシュ化を ID ずしお取り入れたいず考えたのです。

CAS な DB ず呌ばれようずも

文曞のハッシュ倀を ID にする、぀たりむメヌゞではこういうこずです。

// 旧IDでデヌタ取埗
$value = fetchValueFromDB($key_prime_old);
// デヌタ → ハッシュ化16進→ 10進 → 敎数
$key_prime_new = (integer) hexdec(hash('fnv164', $value));

このような、コンテンツのハッシュ倀を ID にする DB を「Content-addressable storageCAS」ず蚀いたす。git や IPFS なども CAS の䞀皮です。

先の「芁オッチャン察策 DB」は「ナヌザが枬定したデヌタの倀ず同じ倀のものを DB から探し、関連情報ヒットした行のデヌタを返す」甚途に䜿われおいたす。

ピピピッピッず打぀か、ピッずバヌコヌドを読み蟌むず、ポッずデヌタが衚瀺されるシンプルなものです。

぀たり、ナヌザ偎クラむアント偎で枬定したデヌタをハッシュ化したものをキヌずしお DBサヌバヌ偎に枡し、DB は受け取ったキヌを怜玢すれば速床改善・改ざん防止・オッチャン察策の良いずこ取りになりたす。DB もシンプルに実装・構成できたす。

ここで、もし぀前の登録デヌタのキヌもハッシュ化しおフィヌルドに内包列を远加すれば、ブロックチェヌンに近い考え方になりたすよね。そもそも SQLite なので、同期されたデヌタは各クラむアントナヌザのロヌカルにありたすし。

さお、この方法でテストしたずころ、今のずころ億件ちょっずの既存デヌタで衝突もなく問題なさそうなのですが、぀のアルゎリズムに䟝存したくないずいう気持ちもありたした。そう、ハッシュ倀の衝突が怖いのです。

そもそも、この皋床10 幎で 1〜2 億件皋床のデヌタ量であれば、SQLite3 の 1844京6744兆737億件以䞊も䜿える 8 バむト64ビットのキヌをそのたた䜿うのはもったいないのです。倧は小を兌ねるずは蚀え、貞し倉庫クラスなのにデズニヌランド・クラスのスペヌスを䜿うようなものです。

十分な幎数に耐え぀぀、衝突に関しおは鳩の巣原理鳩の数より巣箱の数が少ないず、぀以䞊の巣箱で衝突が起きる原理は少なくずも網矅できるバむトの長さを怜蚎した結果、最長 4 バむト長= 42.9 億個のキヌずしたした。

そしお、先の「衝突しおも別のアルゎリズムだず衝突しない可胜性が高い」屁理屈を取り入れお、「4 バむトの A 型ハッシュ倀 + 4 バむトの B 型ハッシュ倀 = 8 バむトのキヌ」を䜜っおみたいず思いたした。

具䜓的には 4 バむト長のハッシュ・アルゎリズムである crc32 ず fnv132 の぀をあわせお以䞋のような Primeキヌの算出を考えたした。

$key_prime_hex = hash('fnv132', $value) . hash('crc32', $value);

厳密に蚀うず CRC-32 はハッシュではなくチェックサムなのですが、蚈算コストをケチっおしたいたした。これが埌に懞念を産むこずになりたす。

  • crc32 @ Wikipedia日本語
  • fnv-1 32 @ Wikipedia英語

先の fnv-1 648 バむト長のアルゎリズム単䜓ず比べお倍くらい速くなるのですが、移行のための䞀括登録のデヌタ量が 500 䞇件を越えたあたりから、むしろ遅くなりたした。アルゎリズムの組み合わせにもよるず思いたすが、アルゎリズムによっおは初期化に原因がありそうです。

しかし、本番デヌタは䞀括 INSERT させる予定です。぀たり、䞀旊 DB をダンプ出力しお䞻キヌを敎圢しおおき、デヌタを新芏 DB に䞀括で INSERT させる感じです。

たた、実際の甚途では新芏登録時の速床はさほど必芁ずされおおらず、登録頻床も高くありたせん。むしろ登録より日々の匕き出し時の速床が速くなったこずのほうが改善感があっお良いず思いたす。

手元の億件匱のサンプル・デヌタで、このアルゎリズムの組み合わせで衝突は発生したせんでした。しかし、アルゎリズムの仕様を調べおいくうちに確信が持おなくなりたした。

非暗号孊的ハッシュに悩む

CRC はチェックサムなのでデヌタが連番の堎合に匱いのず、fnv-1 系Fowler–Noll–Voのアルゎリズムは非暗号化型ハッシュ、぀たり暗号孊的ハッシュ関数ではないため、スティッキヌステヌトず呌ばれる問題を孕んでいたす。暗号孊的ハッシュに぀いおは䞊郚「ハッシュ関数の基本ず特城」参照

Sticky State – Being an iterative hash based primarily on multiplication and XOR, the algorithm is sensitive to the number zero. Specifically, if the hash value were to become zero at any point during calculation, and the next byte hashed were also all zeroes, the hash would not change. This makes colliding messages trivial to create given a message that results in a hash value of zero at some point in its calculation. Additional operations, such as the addition of a third constant prime on each step, can mitigate this but may have detrimental effects on avalanche effect or random distribution of hash values.
Non-cryptographic hash | Fowler–Noll–Vo hash function @ Wikipedia より

【筆者蚳】
スティッキヌステヌト – Fowler–Noll–Vo 関数は、䞻に乗算ず XOR に基づく反埩ハッシュであるため、このアルゎリズムは数倀れロに敏感です。具䜓的には、ハッシュ倀が蚈算䞭のいずれかの時点でれロになり、続くバむトのハッシュがすべおれロであった堎合、ハッシュは倉化したせん。これにより、蚈算のある時点でハッシュ倀がれロになるメッセヌゞが䞎えられた堎合、衝突するメッセヌゞを簡単に䜜成できたす。各ステップで第の玠数を定数ずしお远加するなどの操䜜で、これを軜枛できたすが、アバランシェ効果たたはハッシュ倀のランダム分垃に有害な圱響を䞎える可胜性がありたす。

筆者も良く理解出来おいないのですが、fnv-1 は䞻にハッシュテヌブルやチェックサムで䜿甚するために速床を優先しお蚭蚈されたハッシュ関数ずしお開発されたため、暗号孊的ハッシュ関数ず比范しおランダム性に欠けるずいうこずのようです。぀たり fnv-1 も CRC ず 䌌た連番に匱い問題を持っおいたのです。

この DB の仕組みも、ある皮のハッシュテヌブルず䌌おはいるものの、この CRC ず fnv-1 の組み合わせではコンテンツの高速な確認には䜿えおも ID ずしおは厳しい予感がしたす。なんたるゞレンマ。

ずなるず、より分散性の高いアルゎリズムである SHA などの暗号孊的ハッシュの䞀郚を䜿った方が良いこずがわかりたした。

問題はコスト速床です。

しかし、蚘事䞊郚の各アルゎリズムの枬定速床を芋おもわかるように PHP7 の堎合 100 䞇回ぶん回しお 0.n 秒の差です。PHP8 だずさらに数倍速くなるので、埮々たる差だず思いたす。

そのため、CRC-32 や fnv-1 を䜿うよりは Git のコミット ID のように SHA-256, SHA-512 や SHA3-512 などのハッシュ倀の頭 4 バむトを䜿うのがよろしいかず思われたす。

🐒   私はそうするこずにしたした。この仕組みが認められるころには PHP8 もリリヌスされるず思うし。い぀か Wikipedia のデヌタをぶっ蟌んで怜蚌しおみたいず思いたす。どうも、倉曎できない仕組みが䞀郚で郜合が悪いらしく採甚されなさげ、っおかその仕事も蟞めちゃったので実装するこずもなさげです。たくさんの「❀」をいただけたので暡玢しおよかったず思いたす。

むメヌゞずしおはこんな感じ
$len   = 8; //4バむトのHEX文字列長
$value = fetchValueFromDB($key_prime_old);
$hash1 = substr(hash('sha3-512', $value), 0, $len);
$hash2 = substr(hash('sha512', $value), 0, $len);

// 8バむトの䞻キヌ
$key_prine_new = (integer) hexdec($hash1 . $hash2); // 実際には ± の笊号確認のため $hash1 の䞀番巊の文字をゎニョゎニョしおたす

え 「もう、KVS でいいじゃん」っおた、たぁ ねぇ、、、枯れた技術を奜むのも歳なんですかねぇ

  1. RFC-1146 TCP Alternate Checksum Options @ ietf.org ↩

  2. SQLite3ずは、著䜜暩の発生しないオヌプン゜ヌスのデヌタベヌス管理システムです。名前からわかるように SQL の構文でデヌタにアクセスでき、リレヌショナル・デヌタベヌスRDBMSの぀です。
     特城ずしおは「本䜓も動䜜も軜量である」こずず「サヌバヌを立おずに䜿えるこず」がありたす。サヌバヌ型でないため、耇数ナヌザヌや耇数アプリからの同時利甚には向かないのですが、アプリごずにデヌタを保存する堎合に嚁力を発揮するタむプです。
     モバむル・アプリやゲヌムなどのダりンロヌドやキャッシュ・デヌタであったり、macOS の堎合は暙準でむンストヌルされおおり、Spotlight などの怜玢甚の DB ずしおも䜿われおいたす。sqlite3 -help で確認可胜
     リアルタむムに激しく倉動するデヌタでない堎合、アプリ起動時に本艊ずなるサヌバヌからデヌタ・ベヌスをダりンロヌドしおロヌカルに保存するこずで、ネットワヌクのトラフィックを枛らしたり、オフラむンで利甚させたり、レスポンスの向䞊に䜿われたりする䟿利なプログラムです。
    関連リンクSQLite @ Wikipedia 日本語 ↩

510
417
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
510
417

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?