作为一种学习经历,我决定在下面的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 *
只是包含len
和sign
字段的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只是在内部使用其中一个。谢谢你看看。