計算したいb mod n RSA復号化で使用します。私のコード(下)は間違った答えを返します。何が問題なのですか?
unsigned long int decrypt2(int a,int b,int n)
{
unsigned long int res = 1;
for (int i = 0; i < (b / 2); i++)
{
res *= ((a * a) % n);
res %= n;
}
if (b % n == 1)
res *=a;
res %=n;
return res;
}
このC++コードを試すことができます。 32ビットと64ビットの整数で使用しました。私はこれをSOから得たと確信しています。
template <typename T>
T modpow(T base, T exp, T modulus) {
base %= modulus;
T result = 1;
while (exp > 0) {
if (exp & 1) result = (result * base) % modulus;
base = (base * base) % modulus;
exp >>= 1;
}
return result;
}
このアルゴリズムと関連する議論は、pの文献にあります。 244の
シュナイアー、ブルース(1996)。 Applied Cryptography:Protocols、Algorithms、and Source Code in C、Second Edition(2nd ed。)ワイリー。 ISBN 978-0-471-11709-4。
乗算result * base
およびbase * base
は、この簡易バージョンではオーバーフローする可能性があります。モジュラスがT
の幅の半分より大きい(つまり、最大のT
値の平方根より大きい)場合は、代わりに適切なモジュラー乗算アルゴリズムを使用する必要があります。 プリミティブ型でモジュロ乗算を行う方法。
RSA復号化に使用されるpow(a,b) % n
を計算するために、私が遭遇した最良のアルゴリズムはPrimality Testingです。 1) 次のとおりです。
int modulo(int a, int b, int n){
long long x=1, y=a;
while (b > 0) {
if (b%2 == 1) {
x = (x*y) % n; // multiplying with base
}
y = (y*y) % n; // squaring the base
b /= 2;
}
return x % n;
}
詳細については、以下のリファレンスを参照してください。
通常、これは次のようなものです。
while (b)
{
if (b % 2) { res = (res * a) % n; }
a = (a * a) % n;
b /= 2;
}
return res;
私が見る唯一の実際の論理エラーはこの行です:
if (b % n == 1)
これは次のようになります:
if (b % 2 == 1)
しかし、全体的な設計には問題があります。関数はO(b)乗算とモジュラス演算を実行しますが、b / 2
およびa * a
は、O(log b)操作を実行することを目的としていたことを意味します(通常、モジュラーべき乗を行う方法です)。
生の電力操作は非常にコストがかかるため、次のロジックを適用して復号化を簡素化できます。
here から
メッセージm = 7を暗号化するとします。
c = m ^ e mod n = 7 ^ 3 mod 33 = 343 mod 33 = 13。
したがって、暗号文c = 13。復号化を確認するために計算します
m '= c ^ d mod n = 13 ^ 7 mod 33 = 7。
ここで、13の7乗の完全な値を計算する必要はありません。私たちは、という事実を利用することができます
a = bc mod n =(b mod n)。(c mod n)mod n
したがって、潜在的に大きな数をそのコンポーネントに分解し、より簡単で小さな計算の結果を組み合わせて、最終値を計算できます。M 'を計算する1つの方法は次のとおりです。
任意の数は2の累乗の合計として表現できることに注意してください。
13 ^ 2、13 ^ 4、13 ^ 8、... 33を法とする連続値を繰り返し2乗することにより、13 ^ 2 = 169≡4、13 ^ 4 = 4.4 = 16、13 ^ 8 = 16.16 = 256≡25。
次に、7 = 4 + 2 + 1なので、m '= 13 ^ 7 = 13 ^(4 + 2 + 1)= 13 ^ 4.13 ^ 2.13 ^ 1になります。
≡16 x 4 x 13 = 832≡7 mod 33
_(a^b)%n
_、またはa^(b%n)
を計算しようとしていますか?
最初のコードが必要な場合、コードはbが偶数の場合にのみ機能します。これはb/2のためです。 「_if b%n==1
_」は、ここでは_b%n
_を気にするのではなく、_b%2
_を気にするため間違っています。
2番目のループが必要な場合、ループは(b%n)/ 2回ではなくb/2回ループしているため間違っています。
いずれにせよ、あなたの機能は不必要に複雑です。なぜb/2までループし、毎回2 aを掛けようとするのですか?なぜbになるまでループし、毎回1つずつループしないのですか。これにより、多くの不要な複雑さが排除され、潜在的なエラーが排除されます。ループの回数を半分に減らすことでプログラムを高速化すると考えていますか?率直に言って、それは悪いプログラミングの実践です:マイクロ最適化。それは実際にはあまり役に立ちません:あなたはまだ同じ回数で乗算します、あなたがすることはループをテストする回数を減らすことです。 bが通常小さい場合(1桁または2桁など)、問題はありません。 bが大きい場合(数百万単位になる可能性がある場合)、これでは不十分です。より根本的な最適化が必要です。
また、ループのたびに_%n
_を実行するのはなぜですか?最後に一度だけやってみませんか?
Pow(a、b)mod nの計算
OPのコードに関する重要な問題はa * a
です。 int
が十分に大きい場合、これはa
オーバーフロー(未定義の動作)です。 res
の型は、a * a
の乗算には無関係です。
解決策は、次のいずれかを確認することです。
n
、n*n <= type_MAX + 1
でmodulusの型よりも広い型を返す理由はありません。結果は常にその型で表されるためです。
// unsigned long int decrypt2(int a,int b,int n)
int decrypt2(int a,int b,int n)
nsigned mathを使用することは、OPのRSA目標により確実に適しています。
// (a^b)%n
// n != 0
// Test if unsigned long long at least 2x values bits as unsigned
#if ULLONG_MAX/UINT_MAX - 1 > UINT_MAX
unsigned decrypt2(unsigned a, unsigned b, unsigned n) {
unsigned long long result = 1u % n; // Insure result < n, even when n==1
while (b > 0) {
if (b & 1) result = (result * a) % n;
a = (1ULL * a * a) %n;
b >>= 1;
}
return (unsigned) result;
}
#else
unsigned decrypt2(unsigned a, unsigned b, unsigned n) {
// Detect if UINT_MAX + 1 < n*n
if (UINT_MAX/n < n-1) {
return TBD_code_with_wider_math(a,b,n);
}
a %= n;
unsigned result = 1u % n;
while (b > 0) {
if (b & 1) result = (result * a) % n;
a = (a * a) % n;
b >>= 1;
}
return result;
}
#endif
これ(暗号化)は、プログラミングよりもアルゴリズム設計の問題です。欠けている重要な部分は、現代の代数に精通していることです。群論と数論の巨大な最適化を探すことをお勧めします。 n
が素数の場合、pow(a,n-1)%n==1
(無限桁の整数を想定)。したがって、基本的にpow(a,b%(n-1))%n
;を計算する必要があります。グループ理論によれば、e
は、1つおきの数値がe
を法とするn
のべき乗に等しいことがわかります。したがって、範囲[1..n-1]
は、e
のべき乗の置換として表すことができます。 e
のn
とa
baseの対数e
を見つけるアルゴリズムを考えると、計算を大幅に簡素化できます。暗号化には数学の背景のトーンが必要です。十分なバックグラウンドがなくても、その場から離れたいと思います。
int
は通常、RSAには十分ではありません(簡単な簡単な例を扱っている場合を除く)
最大2つの整数を格納できるデータ型が必要です256 (256ビットRSAキーの場合)または2512 512ビットキーなど
私のコードの場合a ^ k mod n:
function pmod(a, k, n)
{
if (n==1) return 0;
power = 1;
for(i=1; i<=k; $i++)
{
power = (power*a) % n;
}
return power;
}