電卓をあまり使わずに5 ^ 55モジュラス221のモジュラスを計算する方法は?
そのようなことを計算するための暗号学の数論には、いくつかの簡単な原理があると思います。
さて、あなたはa^b mod m
を計算したいと思います。まず、素朴なアプローチを取り、それをどのように改良できるかを見ていきます。
まず、a mod m
を減らします。つまり、a1
と0 <= a1 < m
になるように、番号a = a1 mod m
を見つけます。次に、ループ内で繰り返しa1
を掛け、再びmod m
を減らします。したがって、擬似コードでは:
a1 = a reduced mod m
p = 1
for(int i = 1; i <= b; i++) {
p *= a1
p = p reduced mod m
}
これを行うことで、m^2
より大きい数値を避けます。これが鍵です。 m^2
より大きい数を避ける理由は、すべてのステップで0 <= p < m
および0 <= a1 < m
であるためです。
例として、5^55 mod 221
を計算しましょう。まず、5
はすでにmod 221
に削減されています。
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
したがって、5^55 = 112 mod 221
。
これで、 二乗によるべき乗 ;を使用してこれを改善できます。これは、b
の代わりにlog b
乗算のみを必要とするべき乗を減らす有名なトリックです。上記で説明したアルゴリズム、2乗の改善による累乗法では、 右から左へのバイナリ方式 になることに注意してください。
a1 = a reduced mod m
p = 1
while (b > 0) {
if (b is odd) {
p *= a1
p = p reduced mod m
}
b /= 2
a1 = (a1 * a1) reduced mod m
}
したがって、55 = 110111のバイナリ
1 * (5^1 mod 221) = 5 mod 221
5 * (5^2 mod 221) = 125 mod 221
125 * (5^4 mod 221) = 112 mod 221
112 * (5^16 mod 221) = 112 mod 221
112 * (5^32 mod 221) = 112 mod 221
したがって、答えは5^55 = 112 mod 221
です。これが機能する理由は
55 = 1 + 2 + 4 + 16 + 32
そのため
5^55 = 5^(1 + 2 + 4 + 16 + 32) mod 221
= 5^1 * 5^2 * 5^4 * 5^16 * 5^32 mod 221
= 5 * 25 * 183 * 1 * 1 mod 221
= 22875 mod 221
= 112 mod 221
5^1 mod 221
、5^2 mod 221
などを計算するステップでは、5^(2^k)
= 5^(2^(k-1)) * 5^(2^(k-1))
であることに注意してください。これは2^k = 2^(k-1) + 2^(k-1)
であるため、最初に5^1
を計算し、mod 221
を減らし、次にこれを2乗してmod 221
を減らして5^2 mod 221
などを取得します.
上記のアルゴリズムはこのアイデアを形式化します。
ジェイソンの答えに追加するには:
指数のバイナリ展開を使用して、プロセスを高速化できます(非常に大きな指数の場合に役立つ可能性があります)。最初に5、5 ^ 2、5 ^ 4、5 ^ 8 mod 221を計算します。これは、二乗を繰り返して行います。
5^1 = 5(mod 221)
5^2 = 5^2 (mod 221) = 25(mod 221)
5^4 = (5^2)^2 = 25^2(mod 221) = 625 (mod 221) = 183(mod221)
5^8 = (5^4)^2 = 183^2(mod 221) = 33489 (mod 221) = 118(mod 221)
5^16 = (5^8)^2 = 118^2(mod 221) = 13924 (mod 221) = 1(mod 221)
5^32 = (5^16)^2 = 1^2(mod 221) = 1(mod 221)
今、私たちは書くことができます
55 = 1 + 2 + 4 + 16 + 32
so 5^55 = 5^1 * 5^2 * 5^4 * 5^16 * 5^32
= 5 * 25 * 625 * 1 * 1 (mod 221)
= 125 * 625 (mod 221)
= 125 * 183 (mod 183) - because 625 = 183 (mod 221)
= 22875 ( mod 221)
= 112 (mod 221)
指数が非常に大きい場合、これがはるかに高速になることがわかります(bの線形とは対照的に対数であると確信していますが、確実ではありません)。
/* The algorithm is from the book "Discrete Mathematics and Its
Applications 5th Edition" by Kenneth H. Rosen.
(base^exp)%mod
*/
int modular(int base, unsigned int exp, unsigned int mod)
{
int x = 1;
int power = base % mod;
for (int i = 0; i < sizeof(int) * 8; i++) {
int least_sig_bit = 0x00000001 & (exp >> i);
if (least_sig_bit)
x = (x * power) % mod;
power = (power * power) % mod;
}
return x;
}
5^55 mod221
= ( 5^10 * 5^10 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( ( 5^10) mod221 * 5^10 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( 77 * 5^10 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( ( 77 * 5^10) mod221 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( 183 * 5^10 * 5^10 * 5^10 * 5^5) mod221
= ( ( 183 * 5^10) mod221 * 5^10 * 5^10 * 5^5) mod221
= ( 168 * 5^10 * 5^10 * 5^5) mod221
= ( ( 168 * 5^10) mod 221 * 5^10 * 5^5) mod221
= ( 118 * 5^10 * 5^5) mod221
= ( ( 118 * 5^10) mod 221 * 5^5) mod221
= ( 25 * 5^5) mod221
= 112
Java(注i < exp
)。
private static void testModulus() {
int bse = 5, exp = 55, mod = 221;
int a1 = bse % mod;
int p = 1;
System.out.println("1. " + (p % mod) + " * " + bse + " = " + (p % mod) * bse + " mod " + mod);
for (int i = 1; i < exp; i++) {
p *= a1;
System.out.println((i + 1) + ". " + (p % mod) + " * " + bse + " = " + ((p % mod) * bse) % mod + " mod " + mod);
p = (p % mod);
}
}
これは、IBAN検証用に作成したコードの一部です。気軽に使用してください。
static void Main(string[] args)
{
int modulo = 97;
string input = Reverse("100020778788920323232343433");
int result = 0;
int lastRowValue = 1;
for (int i = 0; i < input.Length; i++)
{
// Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number
if (i > 0)
{
lastRowValue = ModuloByDigits(lastRowValue, modulo);
}
result += lastRowValue * int.Parse(input[i].ToString());
}
result = result % modulo;
Console.WriteLine(string.Format("Result: {0}", result));
}
public static int ModuloByDigits(int previousValue, int modulo)
{
// Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number
return ((previousValue * 10) % modulo);
}
public static string Reverse(string input)
{
char[] arr = input.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
中国の剰余定理 は、221 = 13 * 17の初期点として頭に浮かぶので、これを最終的に結合される2つの部分に分割します。1つはmod 13、もう1つはmod 17です。 、すべての非ゼロaに対してa ^(p-1)= 1 mod pの何らかの証拠があると信じています。これは、13 * 4 = 52のmod 13の場合に5 ^ 55が5 ^ 3になるため、問題の軽減にも役立ちます。 「Finite Fields」のテーマを見ると、これを解決する方法についていくつかの良い結果が見つかるかもしれません。
編集:私が要因に言及する理由は、13 ^ 2 * 17 ^ 4 mod 221のようなものを試したかのようにゼロを非ゼロ要素に因数分解する方法を作成するためです。答えは13 * 17 = 221以来ゼロです。多くの大きな数は素数にはなりませんが、暗号学や数学の他の分野で多く使用されているため、大きな素数を見つける方法があります。
探しているのは、モジュラーべき乗、特にモジュラー2進べき乗です。この wikipediaリンク には擬似コードがあります。
これはモジュラーべき乗法と呼ばれます( https://en.wikipedia.org/wiki/Modular_exponentiation )。
次の式があると仮定しましょう。
19 ^ 3 mod 7
19に直接電力を供給する代わりに、次のことができます。
(((19 mod 7) * 19) mod 7) * 19) mod 7
しかし、これは多くの連続的な乗算のために時間がかかる可能性があるため、2乗値で乗算することができます:
x mod N -> x ^ 2 mod N -> x ^ 4 mod -> ... x ^ 2 |log y| mod N
モジュラーべき乗アルゴリズムは、次のことを前提としています。
x ^ y == (x ^ |y/2|) ^ 2 if y is even
x ^ y == x * ((x ^ |y/2|) ^ 2) if y is odd
そして、再帰的なモジュラーべき乗アルゴリズムは、Javaでは次のようになります。
/**
* Modular exponentiation algorithm
* @param x Assumption: x >= 0
* @param y Assumption: y >= 0
* @param N Assumption: N > 0
* @return x ^ y mod N
*/
public static long modExp(long x, long y, long N) {
if(y == 0)
return 1 % N;
long z = modExp(x, Math.abs(y/2), N);
if(y % 2 == 0)
return (long) ((Math.pow(z, 2)) % N);
return (long) ((x * Math.pow(z, 2)) % N);
}
@ chux に特に感謝します。yと0の比較の場合に誤った戻り値を使用して見つかった間違いに対して。
CによるJasonの答えの別の実装を提供するだけです。
Jasonの説明に基づいてクラスメートと話し合った後、パフォーマンスをあまり気にしないのであれば、再帰バージョンの方が好きです。
例えば:
#include<stdio.h>
int mypow( int base, int pow, int mod ){
if( pow == 0 ) return 1;
if( pow % 2 == 0 ){
int tmp = mypow( base, pow >> 1, mod );
return tmp * tmp % mod;
}
else{
return base * mypow( base, pow - 1, mod ) % mod;
}
}
int main(){
printf("%d", mypow(5,55,221));
return 0;
}