数学やコンピュータプログラミングにおいて、二乗によるべき乗は、数の大きな正の整数べき乗、あるいはより一般的には多項式や正方行列などの半群の要素のべき乗を高速に計算するための一般的な方法です。いくつかの変種は、一般的に二乗乗法または二進べき乗法と呼ばれています。これらは、例えばモジュラー演算や行列のべき乗など、非常に汎用的に使用できます。暗号で使用される楕円曲線のように、加法表記が一般的に使用される半群の場合、この方法は倍加算法とも呼ばれます。
この方法は、任意の整数に対して1つは
指数nがゼロの場合、答えは 1 です。指数が負の場合は、値を正の指数で書き換えることで前の式を再利用できます。つまり、
これらを組み合わせると、以下の再帰アルゴリズムとして直接実装できます。
入力:実数x、整数n出力:x n関数exp_by_squaring( x , n )は、 n < 0 の場合、 exp_by_squaring(1 / x , − n ) を返します。それ以外の場合、 n = 0 の場合、 1 を 返します。それ以外の場合、nが偶数の場合、 exp_by_squaring( x × x , n / 2) を返します。それ以外の場合、 nが奇数の場合、x × exp_by_squaring( x × x , ( n − 1) / 2) を返します。
各再帰呼び出しでは、 nのバイナリ表現の最下位桁が削除されます。したがって、再帰呼び出しの回数はnの二進数表現のビット数。したがって、このアルゴリズムでは、この数の平方と、nの二進数表現の 1 の数に等しいより少ない数の乗算を計算します。この対数的な演算回数は、 n − 1 回の乗算を必要とする自明なアルゴリズムと比較されます。
このアルゴリズムは末尾再帰ではありません。つまり、必要な補助メモリの量は、再帰呼び出しの回数にほぼ比例するか、反復ごとのデータ量が増加する場合はさらに多くなる可能性があります。
次のセクションのアルゴリズムは異なるアプローチを採用しており、結果として得られるアルゴリズムは同数の演算を必要としますが、結果を格納するために必要なメモリとほぼ同じ補助メモリを使用します。
このセクションで説明するバリアントは、次の式に基づいています。
この式を再帰的に適用し、 y = 1から始めると、最終的に指数が0になり、その結果が左側の因数となります。
これは末尾再帰関数として実装できます。
関数exp_by_squaring ( x , n )はexp_by_squaring2 ( 1 , x , n )を返します関数exp_by_squaring2 ( y , x , n ) n < 0の場合、exp_by_squaring2 ( y , 1 / x , - n )を返します。それ以外の場合、n = 0の場合、yを返します。それ以外の場合、nが偶数の場合、exp_by_squaring2 ( y , x * x , n / 2 )を返します。それ以外の場合、nが奇数の場合、 exp_by_squaring2 ( x * y , x * x , ( n - 1 ) / 2 )を返します。アルゴリズムの反復バージョンも有界補助空間を使用し、次のように表される。
関数exp_by_squaring_iterative ( x , n ) n < 0の場合、x := 1 / x ; n := - n ; n = 0の場合、1 を返すy := 1 ; n > 1の間、nが奇数の場合、y := x * y ; n := n - 1 ; x := x * x ; n := n / 2 ; x * yを返すアルゴリズムの正しさは、以下の事実から生じる。は計算中不変です。最初は、そしてそれは最後に。
これらのアルゴリズムは、前のセクションのアルゴリズムと全く同じ数の演算を使用しますが、乗算の順序が異なります。
簡単な分析によると、このようなアルゴリズムは平方数と最大乗算、は床関数を表します。より正確には、乗算の回数は、nの二進展開に含まれる 1 の数より 1 少ない数です。n が約 4 より大きい場合、これは単純に基数を自身で繰り返し乗算するよりも計算効率が高くなります。
各二乗の結果、桁数は前の桁数の約2倍になるため、2つのd桁の数の乗算が固定されたkに対してO( dk )演算で実装される場合、 xnを計算する複雑さは次のように与えられる。
このアルゴリズムは、指数を底 2 kで展開した後、 x nの値を計算します。これは1939 年にBrauerによって最初に提案されました。以下のアルゴリズムでは、次の関数f (0) = ( k , 0) およびf ( m ) = ( s , u )を使用します。ここで、 m = u ·2 sであり、 u は奇数です。
アルゴリズム:
y := 1; i := l - 1 while i ≥ 0 do (s, u) := f(n i ) for j := 1 to k - s do y := y 2 y := y * x u for j := 1 to s do y := y 2 i := i - 1 yを返す
最適な効率を得るには、k は[ 1 ]を満たす最小の整数である必要がある。
この方法は、 2k進法の効率的な変種です。例えば、2進展開が(110 001 110) 2である指数398を計算するには、 2k進法アルゴリズムを使用して長さ3のウィンドウを取り、1、 x3、x6 、 x12 、 x24、x48 、 x49 、 x98 、x99、x198、x199 、x398を計算します。しかし、1、x3、x6、x12、x24、x48、x96、x192、x199、x398を計算することもでき、これは1回の乗算を節約し、( 110 001 110 ) 2を評価することに相当します。
一般的なアルゴリズムは以下のとおりです。
アルゴリズム:
アルゴリズム:
y := 1; i := l - 1 while i > -1 do if n i = 0 then y := y 2 i := i - 1 それ以外 s := max{i - k + 1, 0} n s = 0の間 、s := s + 1を実行します[注 1 ] h := 1からi - s + 1まで 、y := y 2を実行します 。u := (n i , n i-1 , ..., n s ) 2 を実行します 。y := y * x u を実行します。 i := s - 1 yを返すべき乗計算のための多くのアルゴリズムは、サイドチャネル攻撃に対する防御を提供していません。つまり、攻撃者は、2乗と乗算のシーケンスを観察することで、計算に関係する指数を(部分的に)復元できます。これは、多くの公開鍵暗号システムのように、指数を秘密にしておく必要がある場合に問題となります。「モンゴメリーのはしご」[ 2 ]と呼ばれる技術は、この懸念に対処します。
正の非ゼロ整数n = ( n k −1 ... n 0 ) 2の二進展開( n k−1 = 1)が与えられた場合、 x n は次のように計算できます。
x 1 = x; x 2 = x 2 for i = k - 2 to 0 do if n i = 0 then x 2 = x 1 * x 2 ; x 1 = x 1 2 else x 1 = x 1 * x 2 ; x 2 = x 2 2 return x 1
このアルゴリズムは、( log nまで)固定された一連の演算を実行します。指数部の各ビットに対して、そのビットの具体的な値に関係なく、乗算と二乗演算が行われます。乗算による倍数演算についても同様のアルゴリズムが存在します。
このモンゴメリーラダーの特定の実装は、キャッシュタイミング攻撃に対してまだ保護されていません。秘密指数のビットの値に応じて異なる変数にアクセスするため、メモリアクセスの遅延が攻撃者に観測される可能性があります。最新の暗号化実装では、「スキャッター」技術を使用して、プロセッサが常に高速キャッシュをミスするようにしています。[ 3 ]
底が固定され指数が変化する場合にx nを計算する方法はいくつか存在する。ご覧のとおり、これらのアルゴリズムでは事前計算が重要な役割を果たす。
Yao の方法は、指数が基数b = 2 kで展開され、上記のアルゴリズムで実行される計算が行われる2 k進法と直交しています。n 、n i、b、b iを整数とします。
指数nを次のように表す。
どこすべての人々のために。
x i = x b iとする。
次に、アルゴリズムは等式を使用します
Gの要素xと、上記の形式で記述された指数n、および事前に計算された値x b 0 ... x b w −1が与えられた場合、要素x nは以下のアルゴリズムを使用して計算されます。
y = 1、u = 1、j = h - 1 j > 0の間、 i = 0からw - 1まで繰り返す。もしn i = jならば、 u = u × x b iとする。 y = y × u j = j - 1 yを返す
h = 2 kおよびb i = h iと設定すると、n i の値は単純にn をh基数で表した数字になります。Yao の方法では、まずuに最高次数で現れるx iを収集します。次のラウンドでは権力を持つ者たちがはuにも収集されます。変数yは乗算されます。先頭のuで始まる回数、次に高いべき乗で何回も、といった具合に。このアルゴリズムは、乗算、そしてx nを計算するには要素を保存する必要があります。 [ 1 ]
ユークリッド法は、PD Rooij による「事前計算とベクトル加算チェーンを用いた効率的なべき乗法」で初めて紹介されました。
この計算方法はグループGにおいて、nは自然整数であり、そのアルゴリズムは以下に示すとおりで、次の等式を再帰的に使用します。
どこつまり、指数n 1をn 0で割ったユークリッド除算を使用して、商qと剰余n 1 mod n 0を返します。
グループGの基底要素xと指数が与えられています。姚の方法のように書かれた要素は以下を使用して計算されます。事前計算された値そして、以下のアルゴリズムです。
ループ開始検索、したがって。探す、したがってループを中断する。させてそして再帰的に計算するそして ループ 終了;戻る。
このアルゴリズムは、まずn iの中で最大の値を見つけ、次に{ n i \ i ≠ M }の集合の中で上限値を見つけます。次に、x Mを q乗し、この値をx Nと掛け合わせ、この計算結果をx Nに、 n Mをn Nで割った値をn Mに代入します。
このアプローチは、特性がゼロでない半群にも適用でき、例えば、ある数を法とする大きな指数を高速に計算できます。特に暗号学では、整数環のべき乗を法qで計算することが有用です。例えば、
13789 722341を計算し、それを2345 で割った余りを求めるという単純な方法を用いると、非常に長い時間と多くのストレージ容量が必要になります。より効率的な方法(13789 を二乗し、2345 で割った余りを求め、その結果に 13789 を掛ける、といった方法)を使っても、やはり時間がかかります。
上記の指数二乗アルゴリズムを、「*」をx * y = xy mod 2345 (つまり、乗算の後に剰余付き除算が続く) と解釈して適用すると、整数の乗算と除算はわずか 27 回で済み、これらはすべて単一のマシン ワードに格納できます。一般に、これらのアプローチのいずれも、2log 2 (722340) ≤ 40未満のモジュラ乗算で済みます。
この手法は、以下のいずれかの規則を用いて、グループ内の整数乗を計算するためにも使用できます。
この手法は非可換半群でも有効であり、行列のべき乗を計算する際によく用いられる。
特定の計算では、負の係数を許容し、基数の逆数を使用する方が効率的な場合があります。ただし、Gの逆数の計算が「高速」であるか、事前に計算済みであることが前提となります。たとえば、x 2 k −1を計算する場合、バイナリ法ではk −1 回の乗算とk −1回の二乗が必要になります。しかし、 k 回の二乗を実行してx 2 kを取得し、それにx −1を掛けてx 2 k −1を取得することもできます。
この目的のために、基数bにおける整数nの符号付き桁表現を次のように定義します。
符号付きバイナリ表現は、特定の選択b = 2および。それは次のように表されます。この表現を計算する方法はいくつかあります。表現は一意ではありません。たとえば、n = 478の場合、2 つの異なる符号付きバイナリ表現が与えられます。そして、 どこ−1を表すために が使用されます。バイナリ法では、 nの 2 進数表現の非ゼロ要素ごとに乗算を計算するため、非ゼロ要素の数が最小の符号付きバイナリ表現、つまりハミング重みが最小の表現を見つけることに興味があります。これを行う 1 つの方法は、非隣接形式、略して NAFでの表現を計算することです。これは、次の条件を満たすものです。そして、例えば、478のNAF表現は次のようになります。この表現は常に最小のハミング重みを持ちます。与えられた整数のNAF表現を計算する簡単なアルゴリズムと以下のとおりです。
i = 0からl − 1まで繰り返す 戻る
小山と鶴岡による別のアルゴリズムでは、; それでもハミング重みは最小化される。
二乗によるべき乗は、最適とは言えない加算連鎖べき乗アルゴリズムと見なすことができます。これは、指数を2倍にする(二乗する)操作を繰り返したり、指数を1ずつ増やす(xを乗じる)操作のみを行う加算連鎖によって指数を計算します。より一般的には、以前に計算した指数を合計する(xのべき乗を乗じる)ことを許可すれば、乗算回数を減らす(ただし、通常はより多くのメモリを使用する)ことができる場合があります。これが起こる最小のべき乗はn = 15の場合です。
一般的に、与えられた指数に対する最適な加算チェーンを見つけることは困難な問題であり、効率的なアルゴリズムは知られていないため、最適なチェーンは通常、小さな指数に対してのみ使用されます(例えば、小さなべき乗のチェーンが事前に表にまとめられているコンパイラなど)。しかし、最適ではないものの、追加の管理作業とメモリ使用量を犠牲にして、2乗によるべき乗計算よりも乗算回数が少ないヒューリスティックアルゴリズムがいくつか存在します。いずれにせよ、乗算回数はΘ(log n )よりも遅く増加することはないため、これらのアルゴリズムは、2乗によるべき乗計算に対して漸近的にせいぜい定数倍しか改善しません。