web-dev-qa-db-fra.com

Calculer pow (a, b) mod n

Je veux calculer unb mod n pour le décryptage RSA. Mon code (ci-dessous) renvoie des réponses incorrectes. Qu'est-ce qui va pas avec ça?

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;
}
18
Moein Hosseini

Vous pouvez essayer ce code C++. Je l'ai utilisé avec des entiers 32 et 64 bits. Je suis sûr que je l'ai eu de 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;
}

Vous pouvez trouver cet algorithme et une discussion connexe dans la littérature à la p. 244 de

Schneier, Bruce (1996). Cryptographie appliquée: protocoles, algorithmes et code source en C, deuxième édition (2e éd.). Wiley. ISBN 978-0-471-11709-4.


Notez que les multiplications result * base et base * base sont sujettes au débordement dans cette version simplifiée. Si le module est plus de la moitié de la largeur de T (c'est-à-dire plus que la racine carrée de la valeur maximale de T), il convient d'utiliser un algorithme de multiplication modulaire approprié - voir les réponses à Façons de faire une multiplication modulo avec des types primitifs.

42
Blastfurnace

Afin de calculer pow(a,b) % n à utiliser pour le déchiffrement RSA, le meilleur algorithme que j'ai rencontré est Primality Testing 1) qui est comme suit:

 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;
}

Voir la référence ci-dessous pour plus de détails.


1) Test de primalité: Algorithmes non déterministes - topcoder

15
Shubham Khatri

Habituellement c'est quelque chose comme ça:

while (b)
{
    if (b % 2) { res = (res * a) % n; }

    a = (a * a) % n;
    b /= 2;
}

return res;
10
Kerrek SB

La seule erreur de logique que je vois est cette ligne:

if (b % n == 1)

qui devrait être ceci:

if (b % 2 == 1)

Mais votre conception globale est problématique: votre fonction effectue O(b) multiplications et opérations de module, mais votre utilisation de b / 2 et a * a implique que vous vouliez effectuer des opérations O (log b) est fait).

6
ruakh

Faire l'opération brute d'alimentation est très coûteux, vous pouvez donc appliquer la logique suivante pour simplifier le déchiffrement.

De ici

Maintenant, disons que nous voulons chiffrer le message m = 7,
c = m ^ e mod n = 7 ^ 3 mod 33 = 343 mod 33 = 13. 
D'où le texte chiffré c = 13.

Pour vérifier le déchiffrement, nous calculons 
m '= c ^ d mod n = 13 ^ 7 mod 33 = 7. 
Remarque que nous n'avons pas à calculer la valeur complète de 13 à la puissance 7 ici. Nous pouvons utiliser le fait que 
a = bc mod n = (b mod n). (c mod n) mod n 
afin que nous puissions décomposer un nombre potentiellement important en son composants et combinez les résultats de calculs plus faciles et plus petits jusqu'à calculer la valeur finale.

Une façon de calculer m 'est la suivante: - 
Notez que n'importe quel nombre peut être exprimé comme une somme de puissances de 2. Donc, calculez d'abord les valeurs de 
13 ^ 2, 13 ^ 4, 13 ^ 8, ... en quadrillant de façon répétée les valeurs successives modulo 33. 13 ^ 2 = 169 ≡ 4, 13 ^ 4 = 4,4 = 16, 13 ^ 8 = 16,16 = 256 25. 
Alors, puisque 7 = 4 + 2 + 1, on a m '= 13 ^ 7 = 13 ^ (4 + 2 + 1) = 13 ^ 4.13 ^ 2.13 ^ 1 
≡ 16 x 4 x 13 = 832 Mod 7 mod 33

3
bragboy

Essayez-vous de calculer (a^b)%n ou a^(b%n)?

Si vous voulez le premier, alors votre code ne fonctionne que lorsque b est un nombre pair, à cause de cela b/2 . Le "if b%n==1" est incorrect car vous ne vous souciez pas de b%n ici, mais plutôt de b%2.

Si vous voulez le second, alors la boucle est fausse car vous utilisez b/2 times au lieu de (b% n)/2 times.

Dans les deux cas, votre fonction est inutilement complexe. Pourquoi faites-vous une boucle jusqu'à b/2 et essayez de vous multiplier par 2 à chaque fois? Pourquoi ne pas simplement boucler jusqu’à b et mulitply en un à chaque fois. Cela éliminerait beaucoup de complexité inutile et donc les erreurs potentielles. Pensez-vous que vous accélérerez le programme en réduisant de moitié le nombre de fois dans la boucle? Franchement, c'est une mauvaise pratique de programmation: la micro-optimisation. Cela n'aide pas beaucoup: vous multipliez toujours par le même nombre de fois, vous ne faites que réduire le nombre de fois que vous testez la boucle. Si b est typiquement petit (comme un ou deux chiffres), cela ne vaut pas la peine. Si b est grand - s'il peut être dans les millions - alors cela est insuffisant, vous avez besoin d'une optimisation beaucoup plus radicale.

Aussi, pourquoi le %n à chaque fois dans la boucle? Pourquoi ne pas le faire une fois à la fin?

1
Jay

Calculer pow (a, b) mod n

  1. Un problème clé avec le code OP est a * a. C'est int overflow (comportement indéfini) lorsque a est suffisamment grand. Le type de res n'est pas pertinent dans la multiplication de a * a

    La solution consiste à assurer soit: 

    • la multiplication est faite avec 2x math large ou 
    • avec modulen, n*n <= type_MAX + 1
  2. Il n'y a aucune raison de renvoyer un type plus large que le type de modulus car le résultat est toujours représenté par ce type.

    // unsigned long int decrypt2(int a,int b,int n)
    int decrypt2(int a,int b,int n)
    
  3. L'utilisation de unsigned math est certainement plus adaptée aux objectifs RSA de l'OP.


// (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
1
chux

Ceci (cryptage) est plus un problème de conception d’algorithme que de programmation. La partie importante qui manque est la connaissance de l'algèbre moderne. Je suggère que vous recherchiez une optimisation énorme dans la théorie des groupes et la théorie des nombres . Si n est un nombre premier, pow(a,n-1)%n==1 (en supposant des nombres entiers infinis). Alors, fondamentalement, vous devez calculer pow(a,b%(n-1))%n; Selon la théorie des groupes, vous pouvez trouver e tel que tout autre nombre équivaut à une puissance de e modulo n. Par conséquent, la plage [1..n-1] peut être représentée comme une permutation sur des puissances de e. Avec l'algorithme pour trouver e pour n et le logarithme de a base e, les calculs peuvent être considérablement simplifiés. La cryptographie a besoin d'un ton d'arrière-plan mathématique; Je préférerais être sur cette terre sans assez de fond.

0
Red.Wave

int's ne suffisent généralement pas pour RSA (à moins que vous ne traitiez avec de petits exemples simplifiés)

vous avez besoin d'un type de données pouvant stocker des entiers allant jusqu'à 2256 (pour les clés RSA 256 bits) ou 2512 pour les clés 512 bits, etc.

0
zed_0xff