冪剰余のソースを表示
←
冪剰余
ナビゲーションに移動
検索に移動
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループに属する利用者のみが実行できます:
登録利用者
。
このページのソースの閲覧やコピーができます。
{{脚注の不足|date=2022年12月}} '''冪剰余'''(べきじょうよ、[[英語|英]]: modular exponentiation)とは、[[冪乗]]の[[剰余]]のことである。[[数論]]的に重要な概念であるとともに、[[計算機科学]]、特に[[暗号理論]]の分野での応用が重要である。'''冪乗剰余'''とも呼ばれる。 正の整数 {{mvar|''b''}}(底)の整数 {{mvar|''e''}} 乗([[冪指数]])を正の整数 {{mvar|''m''}}([[除法#整数の除法|法]])で割った余りを、「{{mvar|''m''}} を法とする {{mvar|''b''}} の {{mvar|''e''}}-冪剰余」と呼ぶ。つまり、冪剰余を求めるとは、次の {{mvar|''c''}} を計算することにほかならない。 : <math>c := b^e \bmod m</math> 例えば、{{math|''b'' {{=}} 5、''e'' {{=}} 3、''m'' {{=}} 13}} の場合、{{mvar|''c''}} は {{math|5{{sup|3}}}} を {{math|13}} で割った余りであり、冪剰余は {{math|8}} となる。 冪指数 {{math|''e'' {{=}} 2, 3}} に対する {{mvar|''e''}}-冪剰余は、通常それぞれ[[平方剰余]]、立方剰余と呼ばれる。 冪剰余 {{mvar|''c''}} を求める計算は、たとえ巨大な数であっても難しくはない。一方、{{math|''b'', ''c'', ''m''}} が与えられたとき指数 {{mvar|''e''}} を求めることを考えると、これは {{math|'''Z'''/''m'''''Z'''}} の[[乗法群]]における[[離散対数|離散対数問題]]と同値であり、一般に難しい。このような[[一方向性関数]]的性質から、冪剰余の暗号での利用についての研究が進んでいる。 == 定義 == 整数 {{math|''b'', ''e''}} と {{math|''m'' (''m'' > 0)}} について、{{mvar|''m''}} を法とする {{mvar|''b''}} の {{mvar|''e''}}-冪剰余とは、剰余群 {{math|'''Z'''/''m'''''Z'''}}における剰余類 {{math|[''b'']}} の {{mvar|''e''}}-冪、つまり :<math>[b]^e \in \mathbb Z / m \mathbb Z </math> である。しばしば、剰余類の代わりに[[同値関係#同値類|代表元]] {{math|''c'' ∈ [''b'']<sup>''e''</sup>}} をとって、整数として扱う。そのようなとき、特に {{math|0 ≤ ''c'' < ''m''}} であるような {{mvar|''c''}} を代表元として選ぶことが多い。 また、変数 {{mvar|''x''}} に関する {{mvar|''m''}} を法とする合同式 : <math>c = x^e \bmod m</math> が解をもつような {{mvar|''c''}} を総称して法 {{mvar|''m''}} に対する {{mvar|''e''}}-'''冪剰余''' (residue of {{mvar|''e''}}-th power modulo {{mvar|''m''}}) と呼び、解をもたないような {{mvar|''c''}} は総じて法 {{mvar|''m''}} に関して {{mvar|''e''}}-'''冪非剰余''' (non-residue of {{mvar|''e''}}-th power modulo {{mvar|''m''}}) であるという。 冪剰余は、指数 {{mvar|''e''}} が負の場合にも定義できる。その場合、{{mvar|''m''}} を法として {{mvar|''b''}} の[[逆数]]([[モジュラ逆数]])となる ''d'' によって、 : <math>b^{e} \bmod m := d^{|e|} \bmod m</math> と定義する。 == 計算方法 == === 素朴な手法 === 冪剰余を求める最も素朴な手法は、まず{{math|''b''<sup>''e''</sup>}} を計算し、その結果を {{mvar|''m''}} で割って余りを求める方法である。 [[冪乗#効率的な演算法]]にあるように、冪乗の演算には、{{math|O(log(''e''))}} 回の乗算が必要であり、それに加えて1回の剰余演算を施すことによって冪剰余を求めることができる。 例として、{{math|''b'' {{=}} 4, ''e'' {{=}} 13, ''m'' {{=}} 497}} の場合、{{mvar|''c''}} を計算することを考える。 : <math>c := 4^{13} \bmod{497}</math> {{math|4<sup>13</sup>}} は {{math|67,108,864}} であり、これを {{math|497}} で割ると、剰余の {{mvar|''c''}} は {{math|445}} であることがわかる。 {{mvar|''b''}} は1桁、{{mvar|''e''}} は2桁の数値だが、{{math|''b''<sup>''e''</sup>}} は8桁にもなる。 強い暗号では、{{mvar|''b''}} は最低でも256桁の2進数(10進数では77桁)である。典型的な例として {{math|''b'' {{=}} 5 × 10<sup>76</sup>}} と {{math|''e'' {{=}} 17}} の場合を考えてみる。この場合、{{mvar|''b''}} は77桁であり、{{mvar|''e''}} は2桁だが、{{math|''b''<sup>''e''</sup>}} は(10進で)1304桁にもなる。コンピュータにそのような計算をさせることはもちろん可能だが、性能は期待できない。{{mvar|''b''}} や {{mvar|''e''}} の桁数が増えるほど、{{math|''b''<sup>''e''</sup>}} は扱いにくくなる。 === 途中で剰余をとる === 次の計算方法は、手順を増やすことになるが、結果としてはこのアルゴリズムのほうが能率が良い。 2つの整数式 {{mvar|''a''}} と {{mvar|''b''}} があるとき、 : <math>(a \times b) \bmod{m} = ((a\ \mbox{mod}\ m) \times (b\ \mbox{mod}\ m)) \bmod{m}</math> である。したがって、最後に剰余演算を1回行うのではなく、前の演算結果 {{mvar|''a''}} と {{mvar|''b''}} のそれぞれについて {{mvar|''m''}} を法とする剰余をとってから乗算をしても、計算結果は変わらない。 たとえば、5<sup>3</sup> mod 13 を計算するときに、(5<sup>3</sup> = 5<sup>2</sup> × 5 であるから)次のように計算できる。 * まず、5<sup>2</sup> mod 13 = 25 mod 13 = 12 を計算する。 * 次に、(12 × 5) mod 13 = 60 mod 13 = 8 として、結果が得られる。 これによって、剰余算の回数が1回から {{math|O(log(''e''))}} 回に増えるが、乗算および剰余算の計算コストは被演算数の桁数によるので、結果としてはこのアルゴリズムのほうが能率が良い。また一般に、{{mvar|''m''}} がその計算機環境における1語の桁数の半分以下に収まる場合 {{math|(''a'' mod ''m'') × (''b'' mod ''m'')}} の結果が必ず1語に収まるので、[[多倍長整数|Bignum]] を一切使わない能率の良い計算が可能である。 次の例は、基本としてこの手法を利用し、さらに指数法則の {{math|''b''<sup>2''x''</sup> {{=}} (''b''<sup>2</sup>)<sup>''x''</sup>}} を活用したコードであり、ほぼ [[C Sharp|C#]] または [[C++]] のコードとなっている。クラス Bignum は任意の巨大な整数を表現できるものとする。引数 ''b'' は底、''e'' は指数、''m'' は法である。記号 "%" は、[[除法の原理#剰余演算|剰余演算]] (mod) を示す。 <syntaxhighlight lang="cpp"> Bignum modpow(Bignum b, Bignum e, Bignum m) { Bignum result = 1; while (e > 0) { if ((e & 1) == 1) result = (result * b) % m; e >>= 1; b = (b * b) % m; } return result; } </syntaxhighlight> このコードは、{{Harvtxt|Schneier|1995|p=244}}にあるものに基づいており、一つの while ループで冪剰余の計算に必要な全ての作業を行っている。 例として、b = 4, e = 13, m = 497 をこの手法で計算する。e を[[2進数]]で表記すると 1101 になる。e が2進数では4桁なので、ループは4回しか回らない。 * ループに最初に入ったとき、各変数の値は b = 4, e = 1101(2進数), result = 1 である。e の右端のビットは 1 なので、result は (1 × 4) % 497 つまり '''4''' となる。e は右にシフトされて 110(2進数)となり、b は (4 × 4) % 497 すなわち 16 になる。 * 繰返しの2回目では、e の右端ビットは 0 なので result は '''4''' のままとなる。e は右にシフトされて 11(2進数)となり、b は (16 × 16) % 497 つまり 256 となる。 * 繰返しの3回目では、e の右端ビットは 1 なので result は (4 × 256) % 497 すなわち '''30''' となる。e は右にシフトされて 1(2進数)となり、b は (256 × 256) % 497 つまり 429 となる。 * 繰返しの4回目では、e の右端ビットは 1 なので result は (30 × 429) % 497 すなわち '''445''' となる。e は右にシフトされて 0 となり、b は (429 × 429) % 497 つまり 151 となる。 e が 0 になるとループは終了し、結果として '''445''' が得られる。これは前述のアルゴリズムの結果とも一致する。 === さらなる最適化 === [[Python]]で右向き[[冪乗#効率的な演算法|バイナリ法]](指数の左端ビットから順に見ていく方法)を使った例である。 <syntaxhighlight lang="python"> import math def bits(integer): # Gets number of bits in integer result = 0 while integer: integer >>= 1 result += 1 return result def power(base, exponent, modulo=None): # Allows fast exponentation with and without moduli result = 1 if not modulo: iteration = bits(exponent) while iteration >= 0: result *= result if (exponent >> iteration) & 1: result *= base iteration -= 1 else: firstModulus = base % modulo iteration = bits(exponent) while iteration >= 0: result = (result * result) % modulo if (exponent >> iteration) & 1: result = (result * firstModulus) % modulo iteration -= 1 return result </syntaxhighlight> この方法では、初期化後は変数 result(とループ変数の iteration)だけが変化していき、他の変数は変化しないという利点がある。このことからハードウェアによる暗号処理の実装を高速かつ安価に実装できる。 {{math|firstModulus {{=}} base % modulo}} という行は、ちょっとした最適化であり、前の手法にも適用可能である。 これらのバイナリ法では、指数の2進数表現の各ビットごとに自乗の計算が必要であり、そのビットが1であるときだけ乗算も行う。 右向きバイナリ法では、乗算回数をさらに減らす bit windowing optimization や sliding window optimization がある。 また、剰余を求める計算(%)の高速化として、[[モンゴメリ乗算]]がある。 == 公開鍵暗号における応用 == 上述のように、{{mvar|''m''}} を法とした {{mvar|''b''}} の {{mvar|''e''}}-冪剰余を求めるには、高々 {{math|O(log(''e''))}} 回の加算、乗算、剰余算が必要である。 加算、乗算、剰余算はそれぞれ被演算数の桁数の多項式時間で計算できる。特に、上述のように乗算を行うたびに剰余演算を行えば、被演算数を常に {{mvar|''m''}} 未満に保つことができる。よって、{{mvar|''m''}} を法とした {{mvar|''b''}} の {{mvar|''e''}}-冪剰余は、入力サイズ {{math|log(''b'') + log(''e'') + log(''m'')}} の多項式時間で計算できる。 一方、{{math|''m'', ''b'', ''c''}} から {{math|''c'' {{=}} ''b''<sup>''e''</sup> mod ''m''}} なる {{mvar|''e''}} を求める問題は[[離散対数問題]]といわれ、効率的な、つまり入力サイズの多項式時間のアルゴリズムは発見されていない。[[公開鍵暗号]]のうちある種のものは、この一方向性を利用して設計されている。 == 参考文献 == *{{Citation |last=Schneier |first=Bruce |author-link=ブルース・シュナイアー |date=1995-10-18 |title=Applied Cryptography: Protocols, Algorithms and Source Code in C |publisher=Wiley |edition=2nd |isbn=0-471-11709-9 }} *:{{Cite book |和書 |last=シュナイアー |first=ブルース |others=[[山形浩生]] 監訳 |translator=[[安達眞弓]] ほか |date=2003-06 |title=暗号技術大全 |publisher=ソフトバンクパブリッシング |isbn=4-7973-1911-9 }} == 関連項目 == {{Div col}} *[[原始根]] *[[指数 (初等整数論)]] *[[平方剰余の相互法則]] *[[冪剰余の相互法則]] {{Div col end}} == 外部リンク == *[http://www.math.umn.edu/~garrett/crypto/a01/FastPow.html Fast Modular Exponentiation Java Applet] - [[ミネソタ大学ツインシティー校]]数学科 *[http://www.mtl.t.u-tokyo.ac.jp/publications/paper/2004/J04-thesis-sakurai-2c.pdf 親子剰余乗算器を用いた左向きアレイ法の実装方式]{{リンク切れ|date=2023-04}} 櫻井隆雄(東京大学) {{DEFAULTSORT:へきしようよ}} [[Category:合同算術]] [[Category:数論アルゴリズム]] [[Category:暗号アルゴリズム]] [[Category:数学に関する記事]]
このページで使用されているテンプレート:
テンプレート:Citation
(
ソースを閲覧
)
テンプレート:Cite book
(
ソースを閲覧
)
テンプレート:Div col
(
ソースを閲覧
)
テンプレート:Div col end
(
ソースを閲覧
)
テンプレート:Harvtxt
(
ソースを閲覧
)
テンプレート:Math
(
ソースを閲覧
)
テンプレート:Mvar
(
ソースを閲覧
)
テンプレート:リンク切れ
(
ソースを閲覧
)
テンプレート:脚注の不足
(
ソースを閲覧
)
冪剰余
に戻る。
ナビゲーション メニュー
個人用ツール
ログイン
名前空間
ページ
議論
日本語
表示
閲覧
ソースを閲覧
履歴表示
その他
検索
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
特別ページ
ツール
リンク元
関連ページの更新状況
ページ情報