中国剩余定理加速实现RSA解密

input

第一行:1个正整数n,表示问题的个数,3个大整数p,q,e,其中,p,q均不超过1024比特,整数间用空格分开

接下来n行,每一行一个大整数 c

output

共n行,每行输出对应的c^d(mod pq)

sample input

2 101 103 19
25
73

sample output

6724
8380

相关

  • mpz_t类型不能作为返回值,需要返回时可以在函数中用mpz_set(a,result)达到返回值的效果
  • mpz_tstbit(mpz_t para,index):返回para中第index位的比特值(最右侧的是第0位
  • mpz_div_2exp(rop,op1,op2):令rop = op1/(2op2),类似向右移位操作
  • 为了加快速度需要尽量减少模重复平方中的循环次数

如何减少循环次数,以2579 mod 100为例,设置窗口大小为5

  • 我们首先预处理,pre[i]存放25i mod 100(i = 1,3,5,7…31) 的值:

    25  71  36  78  68  80  5  95  88  56  54  16  1  19  58  92
    
  • 从左到右遍历每一比特,遇到该位为0时一次选取一位。遇到该位为1时向右选取一些比特位一次性进行计算。规则是:选取的比特位数需要小于窗口长度且最左和最右均为1。

    • 举例:79即1001111b,第一次我们选取10011,第二次选取11;
    • 举例:1218即100 1100 0010b,则第一次选取10011,第二、三、四、五次均选取0,第六次选取1,第七次选取0;
  • 选取后进行的操作:若选取的数字转化为十进制为x,选取的数字的比特位数为j。则进行操作:

    for(int i=0;i<j;i++)
    {
    	ans *= ans;
    	ans %= N;
    }
    ans *= pre[x];
    

伪代码:
中国剩余定理加速实现RSA解密_第1张图片

实现

//来自https://github.com/wsxk/hust_crypto_design/blob/main/%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86/ChineseRemainderTheorem.cpp
#include 
#include 
#define window_size 5
//计算a^paraE % n
void expmod(mpz_t a, mpz_t paraE, mpz_t n){
    mpz_t res,tmp;
    mpz_init(res);
    mpz_init(tmp);
    mpz_set_ui(res,1);
    mpz_t pre[1<<window_size];
    for(int i=0;i<(1<<window_size);i++) mpz_init(pre[i]);
    mpz_set_ui(pre[0],1);
    mpz_mod(pre[1],a,n);
    mpz_mul(tmp,pre[1],a);
    mpz_mod(tmp,tmp,n);
    for(int i=3;i<(1<<window_size);i+=2){
        mpz_mul(pre[i],pre[i-2],tmp);
        mpz_mod(pre[i],pre[i],n);
    }
    unsigned long l = paraE->_mp_size*GMP_LIMB_BITS;
    long i=l-1;
    long s;
    long len;
    while (i>=0)
    {
        if(mpz_tstbit(paraE,i)==0)
        {
            mpz_mul(res,res,res);
            mpz_mod(res,res,n);
            i--;
        }
        else
        {
            s = (i + 1 - window_size) >= 0 ? (i + 1 - window_size) : 0;
            while (mpz_tstbit(paraE,s)==0) s++;
            len = i-s+1;
            for(int j=1;j<=len;j++)
            {
                mpz_mul(res,res,res);
                mpz_mod(res,res,n);
            }
            mpz_div_2exp(tmp,paraE,s); //获取向右移s位的结果
            unsigned long long temp = mpz_get_ui(tmp)&((1 << len) - 1); //获取所选取的比特位转换为数字的值
            mpz_mul(res,res,pre[temp]);
            mpz_mod(res,res,n);
            i=s-1;
        }
    }
    mpz_set(a,res);
}

  
int main(){
    int n;
    mpz_t e,p,q,d,inv_p,inv_q,N,phi_N,phi_q,phi_p,dp,dq,c,ans;
    mpz_init(e),mpz_init(p),mpz_init(q),mpz_init(d),mpz_init(c);
    mpz_init(inv_p),mpz_init(inv_q),mpz_init(N),mpz_init(phi_N);
    mpz_init(phi_q),mpz_init(phi_p),mpz_init(dp),mpz_init(dq);
    mpz_init(ans);

    scanf("%d",&n);
    gmp_scanf("%Zd%Zd%Zd",p,q,e);

    mpz_mul(N,p,q);
    mpz_sub_ui(phi_q,q,1);
    mpz_sub_ui(phi_p,p,1);
    
	//求欧拉函数和d
    mpz_mul(phi_N,phi_q,phi_p);
    mpz_invert(d,e,phi_N);
    
    //求dp(d mod p-1)和dq(d mod q-1)
    mpz_mod(dp,d,phi_p);
    mpz_mod(dq,d,phi_q);
    
    //求p逆和q逆
    mpz_invert(inv_p,p,q);
    mpz_invert(inv_q,q,p);
    
    mpz_t c1,c2;
    mpz_init(c1);
    mpz_init(c2);

    while(n--){
        gmp_scanf("%Zd",c);
        //计算c1和c2
        //c1 = c^dp%p c2 = c^dq%p
        mpz_set(c1,c);
        mpz_set(c2,c);
        expmod(c1,dp,p);
        expmod(c2,dq,q);
        
        //最终结果 = c1 * q * inv_q + c2 * p * inv_p
        mpz_mul(c1, c1, q);		
		mpz_mod(c1, c1, N);
		mpz_mul(c1, c1, inv_q);
		mpz_mod(c1, c1, N);

        mpz_mul(c2, c2, p);
		mpz_mod(c2, c2, N);
		mpz_mul(c2, c2, inv_p);
		mpz_mod(c2, c2, N);

		mpz_add(c1, c1, c2);
		mpz_mod(ans, c1, N);

        gmp_printf("%Zd\n",ans);
    }
    return 0;
}

欢迎指正

你可能感兴趣的:(密码学,c++)