シャミアの秘密分散法(SSS)は、グループ内で秘密情報(「秘密」)を効率的に分散させるためのアルゴリズムであり、1979年にアディ・シャミアによって初めて開発されました。秘密は、グループのメンバーのうち最低限の人数が協力して知識を共有しない限り、漏洩することはありません。これを実現するために、秘密は数学的に複数の部分(「シェア」)に分割され、十分な数のシェアが組み合わされた場合にのみ、秘密を復元することができます。SSSは情報理論的安全性という特性を持ち、攻撃者が一部のシェアを盗んだとしても、十分な数のシェアを盗まない限り、秘密を復元することは不可能です。
シャミアの秘密分散法は、マスターシークレットへのアクセスキーを共有するために、一部のアプリケーションで使用されています。
SSSは、秘密情報を分散型で保護するために使用され、最も一般的には暗号鍵の保護に用いられます。秘密情報は複数の共有部分に分割され、それぞれの共有部分は個別に秘密情報に関する情報を一切含みません。
SSSで保護された秘密を復元するには、しきい値と呼ばれる一定数のシェアが必要です。しきい値以下のシェア数からは秘密に関する情報は一切得られません(完全秘匿性と呼ばれる特性)。この意味で、SSSはワンタイムパッドの一般化です(ワンタイムパッドは、しきい値が2シェアで合計2シェアのSSSと見なすことができます)。[ 1 ]
企業は金庫のセキュリティを確保する必要があります。金庫の暗証番号を知っているのが1人だけの場合、金庫を開ける必要が生じた際に暗証番号が紛失したり、利用できなくなったりする可能性があります。また、暗証番号を知っている人が複数いる場合、互いに常に誠実に行動するとは限らないため、信頼関係が崩れる可能性があります。
SSSは、このような状況において、保管庫のコードの共有部分を生成し、社内の承認された個人に配布するために使用できます。各個人に付与される共有部分の最小値と数を設定することで、保管庫へのアクセスを許可された個人(またはグループ)のみに限定できます。提示された共有部分が最小値に満たない場合は、保管庫を開くことはできません。
偶発的な事故、強制、あるいは反抗的な行為として、一部の個人が保有株式に関する誤った情報を提供する可能性があります。正しい株式の合計数が最低基準を満たさない場合、金庫はロックされたままとなります。
シャミアの秘密共有は、
SSSには有用な特性があるが、弱点もある[ 5 ]ため、一部の用途には適さない。
有用な特性には以下が含まれます。
弱点としては以下が挙げられる。
アディ・シャミールは1979年にこの計画を初めて提唱した。[ 6 ]
この手法はラグランジュ補間定理、具体的には以下の定理を利用している。多項式上の点は、次数が以下の多項式を一意に決定します。例えば、直線を定義するには2点あれば十分であり、放物線を定義するには3点あれば十分であり、3次曲線を定義するには4点あれば十分である、といった具合です。
シャミールの秘密共有は理想的で完璧です-有限体上の多項式補間に基づく閾値方式。このような方式では、秘密を分割することが目的です。(例えば、金庫の暗証番号)データの一部(株式と呼ばれる)以下の方法で:
もし秘密を復元するには、すべてのシェアが必要になります。

秘密は要素として表現できる有限体の(どこ数より大きい(生成される株式のうち)ランダムに選択要素、、 からそして多項式を構築する任意の計算例えば曲線上の点を設定するポイントを見つける。参加者全員に点(多項式への非ゼロ入力と対応する出力)が与えられる。[ 7 ]任意のサブセットが与えられた場合、これらのペアのうち、は補間によって得ることができ、そのための可能な式の一つは次のようになる。ここで、多項式上の点のリストは次のように与えられます。形式のペア。 ご了承ください多項式の最初の係数に等しい。
より一般的には、どんな値でも、 どこの代わりに秘密として使用できます主係数同様に、価値として解釈される可能性がある射影線上にあり、秘密としても使用できます。これらはまさに、100未満のあらゆる連合から完全に隠されたままの多項式から導出された量です。参加者。対照的に、中間係数を含む多項式係数の他の線形結合、は、より少ない連合によって決定される可能性がある。参加者。[ 8 ]
以下の例は、基本的な考え方を示しています。ただし、この例では、考え方を理解しやすくするために、有限体演算ではなく整数演算を用いて計算を行っています。したがって、以下の例は完全な秘匿性を保証するものではなく、シャミアのスキームの適切な例ではありません。次の例で、その問題点を説明します。
共有する秘密が1234だと仮定します。。
この例では、秘密は6つのシェアに分割されます。3つの株式の任意の部分集合秘密を復元するにはそれで十分だ。数字はランダムに選ばれます。仮に166と94としましょう。
したがって、秘密のシェア(ポイント)を生成する多項式は次のようになります。
6ポイント多項式は次のように構成されます。
この制度の各参加者は異なるポイント(そして)。 なぜならの代わりにポイントはそしてそうではないこれは、それが秘密です。
秘密を復元するには、3つのポイントがあれば十分です。
以下の3つのポイントの使用を検討してください。
ラグランジュ基底多項式の計算:
多項式補間の公式を用いて、は:
秘密は自由係数であることを思い出してください。つまり、そして、秘密は解明された。
多項式補間を使用してソース多項式の係数を求めるラグランジュ多項式を用いる方法は、使用されない定数まで計算されてしまうため、効率的ではありません。
これを考慮すると、ラグランジュ多項式を使用して見つけるための最適化された式は次のようになります。は次のように定義されます。
上記で示した方法の簡略版(有限体演算ではなく整数演算を使用)は機能するものの、セキュリティ上の問題がある。イブは、あらゆる彼女が見つけたもの。
彼女がポイントを見つけたと仮定します彼女はまだ持っていないポイントなので、理論的には彼女はこれ以上情報を得るべきではなかったしかし彼女は、その地点からの情報と公開情報を組み合わせることができた。そうすることで、イブは以下の代数計算を実行できる。
それによって彼女はSが偶数であるという情報にたどり着く。

上記の攻撃は、多項式が構築された方法によって多項式が取り得る値に課せられた制約を利用します。多項式の係数は整数でなければならず、スキームで使用される各座標で評価されたときに多項式は整数値をとらなければなりません。これにより、結果として得られる秘密を含む未知の点での可能な値が、より少ない値で減少します。株。
この問題は有限体演算を用いることで解決できます。有限体は常にサイズが一定です。、 どこは素数であり、は正の整数です。サイズ当該分野の要件を満たす必要があるそして、は秘密の値の可能な数よりも大きいが、後者の条件は秘密をより小さな秘密の値に分割し、それぞれの値にこの方式を適用することで回避できる。以下の例では、素体(つまりr = 1)を使用する。図は有限体上の多項式曲線を示す。
実際には、これは小さな変更にすぎません。フィールドのオーダーq(つまり、フィールドが持つ値の数)は、参加者の数と秘密の値の数よりも大きく選択する必要があります。時間がかかる場合があります。多項式を含むすべての計算は、体 (mod pの例では、(は素数とみなされる)を整数ではなく体として扱う。体の選択と、秘密をこの体の値にマッピングする方法は、どちらも公に知られているものとみなされる。
この例では、多項式は次のようになるこれにより、以下のポイントが得られます。
今回はイヴは(彼女がポイント)。
イブが再び発見したと仮定しますそして公開情報は以下のとおりです。前述の攻撃を試みる場合、イブは以下のことが可能です。
がある可能な値彼女はそれを知っている常に 3 ずつ減少するので、で割り切れる彼女は結論づけることができた。 しかし、は素数なので、彼女はこの結論を下すことはできません。したがって、有限体を使用することで、このような攻撃を回避できます。
また、イブはこれは、上記の整数演算の例とは異なり、モジュラー演算の「ラップアラウンド」動作によって「Sは偶数である」という情報が漏洩するのを防ぐため、追加情報を提供しません。
コードの可読性を高めるため、ここでは素体を使用しています。実際には、利便性のために、より小さな二進体を使用して構築されたスキームを、秘密情報のビットの小さな部分文字列に個別に適用することができます(例えば、バイト単位の適用にはGF(256)を使用。ここでGFはガロア体です)。この場合もセキュリティは損なわれません。ただし、体のサイズが共有数よりも大きくなければならないという厳密な条件は依然として遵守する必要があります(例えば、共有数が255を超える可能性がある場合、体GF(256)はGF(65536)などに置き換えられる可能性があります)。
「」シャミアの秘密分散法の以下のPython実装は、CC0およびOWFaの条件に基づいてパブリックドメインに公開されています。https: //creativecommons.org/publicdomain/zero/1.0/ http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0使用方法については、下数行をご覧ください。Python 2および3でテスト済み。from __future__ import division from __future__ import print_functionimport random import functools#12位 メルセンヌプライム_PRIME = 2 ** 127 - 1_RINT =関数ツール。部分的(ランダム. SystemRandom () . randint , 0 )def _eval_at ( Poly , x , prime ): """ 以下の make_random_shares でシャミール プールを生成するために使用される、x での多項式 (係数タプル) を評価します。 """ accum = 0 for coeff in reversed ( poly ): accum *= x accum += coeff accum %= prime return accumdef make_random_shares ( secret , minimum , shares , prime = _PRIME ): """ 指定されたシークレットに対してランダムなシャミアプールを生成し、シェアポイントを返します。 """ if minimum > shares : raise ValueError ( "プールシークレットは回復不能になります。" ) poly = [ secret ] + [ _RINT ( prime - 1 ) for i in range ( minimum - 1 )] points = [( i , _eval_at ( poly , i , prime )) for i in range ( 1 , shares + 1 )] return pointsdef _extended_gcd ( a , b ): """ p を法とする整数の除算とは 、分母の p を法とする逆数を求め、その逆数を分子に掛けることを意味します (注: A の逆数は、A*B % p == 1 となる B です)。これは、 拡張ユークリッドアルゴリズムを使用して計算できます 。http://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Computation """ x = 0 last_x = 1 y = 1 last_y = 0 while b ! = 0 : quot = a // b a , b = b , a % b x , last_x = last_x - quot * x , x y , last_y = last_y - quot * y , y return last_x , last_ydef _divmod ( num , den , p ): """素数 p の num / den を計算します。 これを説明すると、結果は次のようになります。 den * _divmod(num, den, p) % p == num """ inv , _ = _extended_gcd ( den , p ) return num * invdef _lagrange_interpolate ( x , x_s , y_s , p ): """ n 個の (x, y) 点が与えられたとき、与えられた x の y 値を求めます。k 個の点は、k 次までの多項式を定義します。 """ k = len ( x_s ) assert k == len ( set ( x_s )), "点は異なる必要があります" def PI ( vals ): # 大文字の PI -- 入力の積accum = 1 for v in vals : accum *= v return accum nums = [] # 不正確な除算を避けるdens = [] for i in range ( k ): others = list ( x_s ) cur = others . pop ( i ) nums . append ( PI ( x - o for o in others )) dens . append ( PI ( cur - o for o in others )) den = PI ( dens ) num = sum ([ _divmod ( nums [ i ] * den * y_s [ i ] % p , dens [ i ], p ) for i in range ( k )]) return ( _divmod ( num , den , p ) + p ) % pdef recover_secret ( shares , prime = _PRIME ): """ シェアポイント (多項式上の点 (x,y)) から秘密情報を復元します。 """ if len ( shares ) < 3 : raise ValueError ( "少なくとも 3 つのシェアが必要です" ) x_s , y_s = zip ( * shares ) return _lagrange_interpolate ( 0 , x_s , y_s , prime )def main (): """メイン関数""" secret = 1234 shares = make_random_shares ( secret , minimum = 3 , shares = 6 )print ( '秘密: ' , secret ) print ( '共有:' ) if shares : for share in shares : print ( ' ' , share )print ( '共有の最小サブセットから復元された秘密情報:' , recover_secret ( shares [: 3 ])) print ( '別の共有の最小サブセットから復元された秘密情報:' , recover_secret ( shares [ -3 : ]))if __name__ == '__main__' : main ()この SLIP は、Shamir's secret-sharing (SSS) の標準的で相互運用可能な実装と、BIP-0032 で説明されている階層的決定論的ウォレットのバックアップにおけるその使用仕様について説明しています。
暗号通貨分野では、Shamir's Secret Sharing (SSS) のバリエーションが何度か実装されてきたが、開発者は後に、追加された複雑さがシステムのセキュリティを低下させる結果になったことに気づいた。