Пау функция и длинные инт вызывает проблемы
Я пытаюсь реализовать схему шифрования RSA. Это выглядит примерно так:
encrypted data = ((message)^e) % n
а также decrypted data = ((encrypted data)^d) % n
Я пытался реализовать это в с. Вот код:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
long int num = 3255859;
long int encrypt =(int)pow((double) num,3) % 33;
printf("%ld\n",encrypt);
return 0;
}
Я скомпилировал это используя gcc -Werror -g -o encrypt encrypt.c -lm
Это вывод, который я получаю = -2
что, очевидно, неправильно. Когда я пробую этот код для меньших чисел, я получаю правильный результат. Например:
когда я установил num = 2
Я получаю правильный результат, который 8
Я знаю, что я либо неправильно набрал тип, либо у меня где-то заканчиваются границы. Мне нужно использовать этот код для шифрования больших чисел, как в приведенном выше коде.
Не могли бы вы указать, где я иду не так.
Спасибо
РЕДАКТИРОВАТЬ:
Хорошо, согласно предложению от @Micael Oliver, вот модифицированный код:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
unsigned long long num = 3255859;
long long encrypt =(long long)pow((double) num,3) % 33;
printf("%llu\n",encrypt);
long long decrypt =(long long)pow((double) encrypt,7) % 33;
printf("%llu\n",decrypt);
return 0;
}
Вот вывод этого кода:
Notra:Desktop Sukhvir$ gcc -Werror -g -o encrypt encrypt.c -lm
Notra:Desktop Sukhvir$ ./encrypt
18446744073709551608
18446744073709551614
что, очевидно, неправильно, так как 2-й выход должен был быть 3255859
3 ответа
В вашем коде есть немного не подписанных и подписанных чисел - вы должны стараться избегать этого, когда это возможно. Также вы пытаетесь использовать %llu
на подписанный длинный длинный - вы должны использовать %lld
в этом случае.
Но здесь есть более тонкая проблема. В этой строке:
long long encrypt =(long long)pow((double) num,3) % 33;
pow
возвращает double
, который не гарантирует всю точность, которую вы ищете. В результате вы потеряете несколько цифр long long
, К сожалению, C не обеспечивает хорошую альтернативу для вычисления экспонент, поэтому вам нужно что-то реализовать самостоятельно или использовать библиотеку (некоторые другие ответы предлагают некоторые).
Если вы хотите реализовать его самостоятельно, в Википедии можно найти отличную статью о быстром возведении в квадрат с помощью возведения в квадрат: Возведение в квадрат при возведении в квадрат
Они предоставляют некоторый псевдокод, который должен быть очевиден для кодирования на C.
Но, наконец, в целом ваш код будет ограничен размером long long
или любой другой тип по вашему выбору. В конечном счете, для больших чисел вы должны использовать какую-то другую библиотеку или найти лучший алгоритм. В этом случае вы вычисляете мощность, а затем берете модуль - это именно то, чего могут достичь алгоритмы модульного экспонирования, не имея дело с этими библиотеками. Вы можете найти статью в Википедии здесь: Модульное экспонирование
Одним из предложений было использовать другой тип данных, например long long:
3255859^3 == 34514116960466804779
ULLONG_MAX == 18446744073709551615 // this is the minimum guaranteed
Таким образом, unsigned long long может не работать. В целом изменение типов данных имеет свои ограничения. Другой более надежный подход, который вы можете рассмотреть, - это использование GMP-free. gmp manual -
Вы можете скачать gmp на этом сайте.
фрагмент кода:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gmp.h>
int main()
{
mpz_t rop, base, exp, mod;
mpz_init2(rop,128);
mpz_init2(base,128);
mpz_init2(exp,128);
mpz_init2(mod,128);
mpz_set_ui(base, 3255859);
mpz_set_ui(exp, 3);
mpz_set_ui(mod, 33);
mpz_powm_sec (rop, base, exp, mod);
gmp_printf ("result %Zd\n", rop);
return 0;
}
Пока ваши числа не превышают половины размера, с которым вы работаете, вы можете сделать что-то вроде этого:
(((num * num) % 33) * num) % 33
В общем, для чего-то практического в криптографических целях вам понадобятся гораздо большие значения и вычислительная среда для работы с 1024+ битными числами. Для этого вы можете использовать существующий код (я бы порекомендовал libtommath
от libtomcrypt
, безусловно, не GMP) или написать свой.