Scrypt

暗号理論において、scryptは、2009年3月にによって作成されたパスワードベースの鍵導出関数である。このアルゴリズムは特に大規模なの実行時に大量のメモリが必要になるようにし、そのコストが高くなるように設計されている。2016年にscryptアルゴリズムはIETFによってRFC 7914として公開された。scryptの簡素化されたバージョンは多くの暗号通貨でプルーフ・オブ・ワークスキームとして使用されている。最初はArtForzと名乗る匿名のプログラマーによってTenebrixに実装され、その後すぐにFairbrixとライトコインにも実装された。
導入.
パスワードベースの鍵導出関数は一般的に多くの計算資源が必要になるように設計されているので、計算に比較的長い時間がかかる。正しいユーザーは認証などの操作ごとにこれを1回だけ実行するので、必要な時間は僅かである。しかし、総当たり攻撃では操作を何十億回も実行する必要がある可能性が高く、その時点で必要な時間が無視できないほどになり、理想的には途方もない時間が必要となる。
RSAセキュリティによるPBKDF2などの以前のパスワードベースの鍵導出関数は、要求される計算資源が比較的低く、実行に綿密なハードウェアや大量のメモリを必要としない。そのため、ASICやFPGAなどのハードウェアに簡単かつ安価に実装することができる。これによって、十分な計算資源を持つ攻撃者は、数百から数千のハードウェアにアルゴリズムの実装を構築し、それぞれが鍵空間の異なるサブセットを検索することで、大規模な並列攻撃を始めることができる。これは総当たり攻撃を完了するのに必要な時間を利用可能な実装で割ることにより、必要な時間を妥当なものに引き下げる可能性が非常に高い。
scrypt関数はアルゴリズムの計算資源要求を引き上げることによって、このような試みを阻止するように設計されている。具体的には、このアルゴリズムは他のパスワードベースの鍵導出関数と比較して大量のメモリを使用するように設計されており、ハードウェア実装のサイズとコストが遥かに高くなるので、攻撃者が実行可能な並列処理の量が制限される。
概要.
scryptが多くのメモリを必要とすることはアルゴリズムの一部として生成されるビット文字列の大きなベクターに由来する。ベクターが一度生成されると、派生鍵を生成するためにその要素に対して擬似ランダムな順序でアクセスと結合が行われる。単純な実装では、必要に応じてアクセスできるように、ベクター全体をRAMに保持する必要がある。
ベクターの要素はアルゴリズムで生成されるので、必要に応じて各要素をオンザフライで生成でき、一度に1つの要素だけをメモリに格納できるので、メモリ使用量が大幅に削減される。しかし、各要素の生成には多くの計算資源を必要とすることを意図しており、要素は関数の実行中に何度もアクセスされることが予想される。したがって、メモリの使用量を減らすには速度に大きなトレードオフがある。
この種の時間とメモリのトレードオフは、多くのコンピューターアルゴリズムに存在する。速度はより多くのメモリを使用することで上げることができ、メモリ使用量はより多くの操作を実行して長い時間を必要とすることで減らすことができる。scryptの背後にある考え方は、このトレードオフを意図的にどちらも高価なものにすることである。したがって、攻撃者は限られた費用で大規模な並列化が可能な多くの計算資源を必要としない実装を使用する可能性があるが、これの実行速度は非常に遅くなる。または、高速に実行できる実装を使用する場合は、大量のメモリが必要となることから並列化のコストが高価になる。
アルゴリズム.
 Function scrypt
 Inputs: "このアルゴリズムには次のパラメーターが含まれている:"
 Passphrase: Bytes ハッシュ化する文字列
 Salt: Bytes レインボーテーブル攻撃から保護するためにハッシュを変更するランダムな文字列
 CostFactor (N): Integer CPU/メモリコストパラメーター - 2の累乗でなければならない（1024など）
 BlockSizeFactor (r): Integer ブロックサイズパラメーター、シーケンシャルメモリ読み取りサイズと性能を微調整する（8が一般的）
 ParallelizationFactor (p): Integer "並列化パラメーター"。（1 .. 232-1 * hLen/MFlen）
 DesiredKeyLen (dkLen): Integer 必要な鍵の長さ（バイト単位、派生鍵のオクテット単位の意図した出力長、dkLen ≤ (232− 1) * hLenを満たす正の整数。）
 hLen: Integer ハッシュ関数のオクテット単位の長さ（SHA256の場合は32）。
 MFlen: Integer 混合関数（以下の"SMix"）のオクテット単位の出力長。RFC7914でr * 128と定義されている。
 Output:
 DerivedKey: Bytes バイト配列、長さはDesiredKeyLen
 "ステップ1. 高価なソルトを生成する"
 blockSize ← 128*BlockSizeFactor "// バイト単位のSMix混合関数の出力長（例えば128*8 = 1024バイト）"
 PBKDF2を使用して最初の128*BlockSizeFactor*pバイトのデータを生成する（例えば128*8*3 = 3072バイト）
 結果を"p"個の要素を持つ配列として扱う。各エントリーは"blocksize"バイトである（例えば3要素で各エントリーは1024バイト）
 [B0...Bp−1] ← PBKDF2HMAC-SHA256("Passphrase", "Salt", 1, blockSize*ParallelizationFactor)
 ROMix関数を使用して各ブロックをB Costfactor回混合する（各ブロックは並列で混合できる）
 for i ← 0 to p-1 do
 Bi ← ROMix(Bi, CostFactor)
 Bの全要素が新しい「高価な」ソルトである
 expensiveSalt ← B0∥B1∥B2∥ ... ∥Bp-1 "// ∥は連結を意味する
 "ステップ2. PBKDF2を使用して目的のバイト数を生成するが、生成した高価なソルトを使用する"
 return PBKDF2HMAC-SHA256(Passphrase, expensiveSalt, 1, DesiredKeyLen);
"PBKDF2(P, S, c, dkLen)"表記はRFC 2898で定義されており、cは反復回数である。
この表記はc = 1でPBKDF2の使用法を指定するためにRFC 7914で使用されている。
 Function ROMix(Block, Iterations)
 "X"の"Iterations"コピーを作成する
 X ← Block
 for i ← 0 to Iterations−1 do
 Vi ← X
 X ← BlockMix(X)
 for i ← 0 to Iterations−1 do
 j ← Integerify(X) mod Iterations 
 X ← BlockMix(X xor Vj)
 return X
RFC 7914ではをXの最後の64バイトを"リトルエンディアン"整数A1として解釈した結果として定義している。
Iterationsは2のN乗と等しいので、Xの"最後"の64バイトのうち"最初"のCeiling(N / 8)バイトだけが"リトルエンディアン"整数A2として解釈され、codice_1を計算するために実際に必要となる。
 Function BlockMix(B):
 "ブロックBはrの128バイトのチャンクである（これは2rの64バイトのチャンクに相当します）"
 r ← Length(B) / 128;
 "Bを2rの64バイトチャンクの配列として扱う"
 [B0...B2r-1] ← B
 X ← B2r−1
 for i ← 0 to 2r−1 do
 X ← Salsa20/8(X xor Bi) // 64バイトから64バイトのSalsa20/8ハッシュ
 Yi ← X
 return ← Y0∥Y2∥...∥Y2r−2 ∥ Y1∥Y3∥...∥Y2r−1
"Salsa20/8"はSalsa20の8ラウンドバージョンである。
暗号通貨での使用.
Scryptはプルーフ・オブ・ワークアルゴリズムとして多くの暗号通貨で使用されている。最初は2011年9月にTenebrixに実装され、scryptアルゴリズムを採用したライトコインとドージコインの基礎となった。scryptを使用する暗号通貨の採掘は、Graphics Processing Unit（GPU）がCPUと比べて処理能力が大幅に高い傾向があることから、GPUで実行されることが多い。これは2013年の11月と12月にこれらの暗号通貨の価格が上昇した際に、ハイエンドGPUが不足したことにつながった。
2014年5月時点で特別なASIC採掘ハードウェアがscryptベースの暗号通貨で利用することができる。
ユーティリティ.
scryptユーティリティは2009年5月にコリン・パーシバルによってscrypt鍵導出関数のデモンストレーションとして作成された。これは殆どのLinuxディストリビューションとBSDディストリビューションで利用することができる。