为什么我的C bigint modexp这么慢,或者,为什么它在python中如此之快?

时间:2016-01-21 00:21:05

标签: python c performance

作为一种学习经历,我决定在下面的C.代码中编写我自己的bigint例程来获取modexp,但总结一下:它与蒙哥马利乘法重复平方。它需要永远才能运行。在我的拥有1GB内存的虚拟机上,任何大于128位素数模块的程序都会导致程序自行终止,较小的程序会花费相当多的时间。同时,在python中,我做了

def modexp ( g, u, p ):
   s = 1
   while u != 0:
      if u & 1:
         s = (s * g)%p
      u >>= 1
      g = (g * g)%p;
   return s
p = 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff
g = 0x02
a = int(urandom(1000).encode('hex'),base=16) % p
modexp(g,a,p)

就像 instant 一样。 python是否只是为了处理bigint而预先计算了大量的东西,或者是否有一些非常深刻的东西,或者它是最可能的结果,也就是说,我只是不知道我在做什么? / p>

这是一些相关的C代码,不是我要求任何人仔细阅读,但也可以包含它......

Bigints存储在typedef struct string中,char *只是包含lensign字段的string __modExpOdd(string a, string e, string n){//Assumes the modulus is odd. Repeated squaring with Mongtomery multiplication. string r = charToS(0x01); int rpow=0; int ebits = countSignificantBits(e); while(__bigIntComp(r,n)==-1){ r = stringLeftShift(r,1); rpow++; } string nprime = extendedEuclidean(r,n,charToS(0x01))[1]; nprime.sign = 1; string abar = bigIntDivide(bigIntMultiply(a,r),n)[1]; string xbar = bigIntDivide(r,n)[1]; for(int i = ebits-1; i>=0; i--){ xbar = __monPro(xbar, xbar, n, nprime, rpow); if(bigIntParity(stringRightShift(e,i))){ xbar = __monPro(abar, xbar, n, nprime, rpow); } } return __monPro(xbar, charToS(0x01), n, nprime, rpow); } 的包装器。

string *extendedEuclidean(string A, string B, string C){
//returns x, y, with 0 <= x < B such that Ax + By = C
    string S,s,T,t,R,r,q,temp;

    S=charToS(0x00);
    s=charToS(0x01);
    T=charToS(0x01);
    t=charToS(0x00);
    R=bigIntCopy(B);
    r=bigIntCopy(A);
    int revflag = 0;
    if(bigIntComp(A,B)==-1){// need to have A>B for this to work.
        temp = R;
        R = r;
        r = temp;
        revflag = 1;
    }

    while(bigIntComp(R,charToS(0x00))!=0){
        q = bigIntDivide(r,R)[0];
        memcpy(&temp, &R, sizeof(string)); R = bigIntSubtract(r, bigIntMultiply(q, R)); memcpy(&r, &temp, sizeof(string));
        memcpy(&temp, &S, sizeof(string)); S = bigIntSubtract(s, bigIntMultiply(q, S)); memcpy(&s, &temp, sizeof(string));
        memcpy(&temp, &T, sizeof(string)); T = bigIntSubtract(t, bigIntMultiply(q, T)); memcpy(&t, &temp, sizeof(string));
    }
    //at this point, s*A + t*B = r = gcd(A,B), and T,S are quotients of A,B by the gcd.
    string *qr = bigIntDivide(C,r);
    string ratio = bigIntCopy(qr[0]);
    if(bigIntComp(qr[1],charToS(0x00))!=0) return NULL;
    if(revflag==1){
        temp = s;
        s = t;
        t = temp;
    }

    //normalise s, t so that 0 <= s < B
    if(s.sign==-1){
        qr = bigIntDivide(bigIntAbs(s),bigIntAbs(B));
        string q = (bigIntComp(qr[1],charToS(0x00))==0) ? qr[0] : bigIntIncr(qr[0]);
        s = bigIntAdd(s,bigIntMultiply(q,bigIntAbs(B)));
        t = bigIntSubtract(t, bigIntMultiply(q,bigIntAbs(A)));
    }
    //multiply to get the correct coefficients
    s = bigIntMultiply(s,ratio);
    t = bigIntMultiply(t,ratio);
    string *ret = calloc(2,sizeof(string));
    ret[0] = s;
    ret[1] = t;
    return ret;
}

调试告诉我,最糟糕的瓶颈是扩展欧几里德算法主循环中的除法步骤:

string *__bigIntDivide(string a, string b){ //assumes a, b positive
    string *qr = calloc(2, sizeof(string));
    if(__bigIntComp(b,charToS(0x00))==0){
        return NULL;
    }
    if(__bigIntComp(a,b)==-1){
        qr[0] = charToS(0x00);
        qr[1] = bigIntCopy(b);
        return qr;
    }
    if(__bigIntComp(a,b)==0){
        qr[0] = charToS(0x01);
        qr[1] = charToS(0x00);
        return qr;
    }
    int pow = ispowerof2(b);
    if(pow!=-1){
        qr[0] = stringRightShift(a,pow);
        qr[1] = getSignificantBits(a,pow);
        qr[0].sign=1;
        qr[1].sign=1;
        return qr;
    }
    //long division, in base-256
    string divisor = charToS(a.c[0]);
    string quotient = NULLSTRING;
    int i=1;
    do{

        while(__bigIntComp(divisor,b)==-1 && i<a.len){ 
            divisor = stringCat(divisor, charToS(a.c[i]));
            i++;
        }
        if(i == a.len && __bigIntComp(divisor, b) == -1){
            break;
        }
        qr = __findQuotient(divisor, b, charToS(0x00), charToS(0xFF));
        quotient = stringCat(quotient, qr[0]);
        divisor = qr[1];
    }while(i<a.len);
    qr[0] = bigIntCopy(quotient);
    qr[1] = bigIntCopy(divisor);
    return qr;
}

string *__findQuotient(string divisor, string dividend, string minq, string maxq){ //an O(log n) division routine, finds q by a binary search instead of linear
    string q = stringRightShift(bigIntAdd(minq,maxq),1);
    string diff = stringRightShift(bigIntSubtract(maxq,minq),1);
    string p = bigIntMultiply(dividend, q);
    string *qr=calloc(2,sizeof(string));

    while( __bigIntComp(diff, charToS(0x00)) == 1){
        fflush(stdout);
        if(__bigIntComp(divisor, p) == 1){ // if divisor > dividend *q, q is too small.
            q = bigIntAdd(q, diff);
        }
        if(__bigIntComp(divisor, p) == -1){ // if divisor < dividend * q, q is too big.
            q = bigIntSubtract(q, diff);
        }
        if(__bigIntComp(divisor, p)==0){
            qr[0] = q;
            qr[1] = charToS(0x00);
            return qr;
        }
        p = bigIntMultiply(dividend, q);
        diff = stringRightShift(diff,1);
    }
    while(__bigIntComp(divisor, p)==1){ // if a > b*q, q is too small, so increment it. Afterwards, it will be 1 too big.
        q = bigIntIncr(q);
        p = bigIntAdd(p, dividend);
    }
    while(__bigIntComp(divisor, p) == -1){ // while a < b*q, decrement q
        q = bigIntDecr(q);
        p = bigIntSubtract(p,dividend);
    }
    qr[0] = q;
    qr[1] = bigIntSubtract(divisor, p);
    return qr;
}

你可能会好奇地看到分割例程,这只是一个很长的分工:

string __monPro(string abar, string bbar, string n, string nprime, int rpow){
    string t = bigIntMultiply(abar, bbar);
    string m = getSignificantBits(bigIntMultiply(t,nprime),rpow);
    string u = stringRightShift(bigIntAdd(t,bigIntMultiply(m,n)),rpow);
    if(bigIntComp(u,n)>=0) return bigIntSubtract(u,n);
    return u;
} 

蒙哥马利的产品功能,直接来自最初描述的纸张:

def example(x, y, z=None):
    if z is None:
        return x + y
    else:
        return x + y + z

所以我只是好奇它是否都是在python中预先计算的,或者我是否应该寻找内存泄漏?我没有使用任何C bigint库测试它,因为我一直很懒,而且因为我认为python只是在内部使用其中一个。谢谢你看看。

0 个答案:

没有答案