/*无符号低级加法*/18/* low level addition, based on HAC pp.594, Algorithm 14.7 */19int20s_mp_add(mp_int * a, mp_int * b, mp_int * c)21{22 mp_int *x;23int olduse, res, min, max;24/*首先找到两个输入中的最大值*/25/* find sizes, we let |a| <= |b| which means we have to sort */26/* them. "x" will point to the input with the most digits */27/**/28if(a->used > b->used){29 min = b->used;30 max = a->used;31 x = a;32}else{33 min = a->used;34 max = b->used;35 x = b;36}37/*如果c.alloc<max+1,则增加c,使其至少包含max+1位*/38/* init result */39if(c->alloc < max +1){40if((res =mp_grow(c, max +1))!= MP_OKAY){41return res;42}43}4445/* get old used digit count and set new one */46 olduse = c->used;47 c->used = max +1;4849{50register mp_digit u,*tmpa,*tmpb,*tmpc;51registerint i;5253/* alias for digit pointers */5455/* first input */56 tmpa = a->dp;5758/* second input */59 tmpb = b->dp;6061/* destination */62 tmpc = c->dp;6364/* zero the carry */65 u =0;66for(i =0; i < min; i++){67/* Compute the sum at one digit, T[i] = A[i] + B[i] + U */68*tmpc =*tmpa+++*tmpb+++ u;6970/* U = carry bit of T[i] */71 u =*tmpc >>((mp_digit)DIGIT_BIT);7273/* take away carry bit from T[i] */74*tmpc++&= MP_MASK;75}7677/* now copy higher words if any, that is in A+B */78/* if A or B has more digits add those in */79/**/80if(min != max){81for(; i < max; i++){82/* T[i] = X[i] + U */83*tmpc = x->dp[i]+ u;8485/* U = carry bit of T[i] */86 u =*tmpc >>((mp_digit)DIGIT_BIT);8788/* take away carry bit from T[i] */89*tmpc++&= MP_MASK;90}91}9293/* add carry */94*tmpc++= u;9596/* clear digits above oldused */97for(i = c->used; i < olduse; i++){98*tmpc++=0;99}100}101/*压缩c中的多余位*/102mp_clamp(c);103return MP_OKAY;104}
s_mp_add的使用
#include<stdio.h>#include<stdlib.h>#include"utils.h"intmain(){printf("hello libtommath\n");
mp_int a,b,c;mp_init_multi(&a,&b,&c,NULL);mp_read_radix(&a,"a",16);mp_read_radix(&b,"2",16);s_mp_add(&a,&b,&c);printf("a和b相加的结果为:");MP_print(&c);return0;}=============================================:~/workspace/tommath_test$ ./a.out
hello libtommath
a和b相加的结果为: C
4.2.2 低级减法
s_mp_sub的原理
s_mp_sub的实现
/*无符号低级减法*/18/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */19int20s_mp_sub(mp_int * a, mp_int * b, mp_int * c)21{22int olduse, res, min, max;2324/* find sizes */25 min = b->used;26 max = a->used;27/*如果c.alloc<max,则增加c以便至少包含max位*/28/* init result */29if(c->alloc < max){30if((res =mp_grow(c, max))!= MP_OKAY){31return res;32}33}34 olduse = c->used;35 c->used = max;3637{38register mp_digit u,*tmpa,*tmpb,*tmpc;39registerint i;4041/* alias for digit pointers */42 tmpa = a->dp;43 tmpb = b->dp;44 tmpc = c->dp;4546/* set carry to zero */47 u =0;48for(i =0; i < min; i++){49/* T[i] = A[i] - B[i] - U */50*tmpc =*tmpa++-*tmpb++- u;5152/* U = carry bit of T[i]*/53/* Note this saves performing an AND operation since*/54/* if a carry does occur it will propagate all the way to the*/55/* MSB. As a result a single shift is enough to get the carry*/56/**/57 u =*tmpc >>((mp_digit)(CHAR_BIT *sizeof(mp_digit)-1));5859/* Clear carry from T[i] */60*tmpc++&= MP_MASK;61}6263/* now copy higher words if any, e.g. if A has more digits than B */64for(; i < max; i++){65/* T[i] = A[i] - U */66*tmpc =*tmpa++- u;6768/* U = carry bit of T[i] */69 u =*tmpc >>((mp_digit)(CHAR_BIT *sizeof(mp_digit)-1));7071/* Clear carry from T[i] */72*tmpc++&= MP_MASK;73}7475/* clear digits above used (since we may not have grown result above) */76for(i = c->used; i < olduse; i++){77*tmpc++=0;78}79}8081mp_clamp(c);82return MP_OKAY;83}
/*有符号加法*/18/* high level addition (handles signs) */19intmp_add(mp_int * a, mp_int * b, mp_int * c)20{21int sa, sb, res;2223/* get sign of both inputs */24 sa = a->sign;25 sb = b->sign;26/*如果是a和b符号相同的情况*/27/* handle two cases, not four */28if(sa == sb){29/* both positive or both negative */30/* add their magnitudes, copy the sign */31 c->sign = sa;/*c=|a|+|b|*/32 res =s_mp_add(a, b, c);33}else{34/* one positive, the other negative */35/* subtract the one with the greater magnitude from */36/* the one of the lesser magnitude. The result gets */37/* the sign of the one with the greater magnitude. *//*如果是|a|<|b|的情况*/38if(mp_cmp_mag(a, b)== MP_LT){39 c->sign = sb;/*|c|=|b|-|a|*/40 res =s_mp_sub(b, a, c);41}else{/*如果是|a|>|b|的情况*/42 c->sign = sa;/*|c|=|a|-|b|*/43 res =s_mp_sub(a, b, c);44}45}46return res;47}
/*有符号减法运算*/18/* high level subtraction (handles signs) */19int20mp_sub(mp_int * a, mp_int * b, mp_int * c)21{22int sa, sb, res;2324 sa = a->sign;25 sb = b->sign;26/*如果是a和b符号不同的情况*/27if(sa != sb){28/* subtract a negative from a positive, OR */29/* subtract a positive from a negative. */30/* In either case, ADD their magnitudes, */31/* and use the sign of the first number. */32 c->sign = sa;33 res =s_mp_add(a, b, c);/*如果是a和b符号相同的情况*/34}else{35/* subtract a positive from a positive, OR */36/* subtract a negative from a negative. */37/* First, take the difference between their */38/* magnitudes, then... *//*如果是|a|>=|b|的情况*/39if(mp_cmp_mag(a, b)!= MP_LT){40/* Copy the sign from the first */41 c->sign = sa;42/* The first has a larger or equal magnitude */43 res =s_mp_sub(a, b, c);44}else{/*如果是|a|<|b|的情况*/45/* The result has the *opposite* sign from */46/* the first number. */47 c->sign =(sa == MP_ZPOS)? MP_NEG : MP_ZPOS;48/* The second has a larger magnitude */49 res =s_mp_sub(b, a, c);50}51}52return res;53}
mp_sub算法的使用
#include<stdio.h>#include<stdlib.h>#include"utils.h"intmain(){printf("hello libtommath\n");
mp_int a,b,c;mp_init_multi(&a,&b,&c,NULL);mp_read_radix(&a,"a",16);mp_read_radix(&b,"-2",16);mp_sub(&a,&b,&c);printf("a和b相减的结果为:");MP_print(&c);return0;}===================================================:~/workspace/tommath_test$ ./a.out
hello libtommath
a和b相减的结果为: C
4.3 比特和数字移位
4.3.1 乘以2
mp_mul_2的原理
mp_mul_2的实现
18/* b = a*2 */19intmp_mul_2(mp_int * a, mp_int * b)20{21int x, res, oldused;22/*如果b.alloc<a.used+1,则将b增加为包含a.used+1位*/23/* grow to accomodate result */24if(b->alloc < a->used +1){25if((res =mp_grow(b, a->used +1))!= MP_OKAY){26return res;27}28}2930 oldused = b->used;31 b->used = a->used;3233{34register mp_digit r, rr,*tmpa,*tmpb;3536/* alias for source */37 tmpa = a->dp;3839/* alias for dest */40 tmpb = b->dp;4142/* carry */43 r =0;44for(x =0; x < a->used; x++){4546/* get what will be the *next* carry bit from the */47/* MSB of the current digit */48/**/49 rr =*tmpa >>((mp_digit)(DIGIT_BIT -1));5051/* now shift up this digit, add in the carry [from the previous] */52*tmpb++=((*tmpa++<<((mp_digit)1))| r)& MP_MASK;5354/* copy the carry that would be from the source */55/* digit into the next iteration */56/**/57 r = rr;58}5960/* new leading digit? */61if(r !=0){62/* add a MSB which is always 1 at this point */63*tmpb =1;64++(b->used);65}6667/* now zero any excess digits on the destination */68/* that we didn't write to */69/**/70 tmpb = b->dp + b->used;71for(x = b->used; x < oldused; x++){72*tmpb++=0;73}74}75 b->sign = a->sign;76return MP_OKAY;77}
/*除以2运算*/18/* b = a/2 */19intmp_div_2(mp_int * a, mp_int * b)20{21int x, res, oldused;2223/* copy */24if(b->alloc < a->used){25if((res =mp_grow(b, a->used))!= MP_OKAY){26return res;27}28}2930 oldused = b->used;31 b->used = a->used;32{33register mp_digit r, rr,*tmpa,*tmpb;3435/* source alias */36 tmpa = a->dp + b->used -1;3738/* dest alias */39 tmpb = b->dp + b->used -1;4041/* carry */42 r =0;43for(x = b->used -1; x >=0; x--){44/* get the carry for the next iteration */45 rr =*tmpa &1;4647/* shift the current digit, add in carry and store */48*tmpb--=(*tmpa-->>1)|(r <<(DIGIT_BIT -1));4950/* forward carry to next iteration */51 r = rr;52}5354/* zero excess digits */55 tmpb = b->dp + b->used;56for(x = b->used; x < oldused; x++){57*tmpb++=0;58}59}60 b->sign = a->sign;61mp_clamp(b);62return MP_OKAY;63}
18/* shift left a certain amount of digits */19intmp_lshd(mp_int * a,int b)20{21int x, res;2223/* if its less than zero return */24if(b <=0){25return MP_OKAY;26}2728/* grow to fit the new digits */29if(a->alloc < a->used + b){30if((res =mp_grow(a, a->used + b))!= MP_OKAY){31return res;32}33}3435{36register mp_digit *top,*bottom;3738/* increment the used by the shift amount then copy upwards */39 a->used += b;4041/* top */42 top = a->dp + a->used -1;4344/* base */45 bottom = a->dp + a->used -1- b;4647/* much like mp_rshd this is implemented using a sliding window*/48/* except the window goes the otherway around. Copying from*/49/* the bottom to the top. see bn_mp_rshd.c for more info.*/50/**/51for(x = a->used -1; x >= b; x--){52*top--=*bottom--;53}5455/* zero the lower digits */56 top = a->dp;57for(x =0; x < b; x++){58*top++=0;59}60}61return MP_OKAY;62}
18/* shift right a certain amount of digits */19voidmp_rshd(mp_int * a,int b)20{21int x;22/*如果b<=0,则返回*/23/* if b <= 0 then ignore it */24if(b <=0){25return;26}2728/* if b > used then simply zero it and return */29if(a->used <= b){30mp_zero(a);31return;32}3334{35register mp_digit *bottom,*top;3637/* shift the digits down */3839/* bottom */40 bottom = a->dp;4142/* top [offset into digits] */43 top = a->dp + b;4445/* this is implemented as a sliding window where
46 * the window is b-digits long and digits from
47 * the top of the window are copied to the bottom
48 *
49 * e.g.
50
51 b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
52 /\ | ---->
53 \-------------------/ ---->
54 */55for(x =0; x <(a->used - b); x++){56*bottom++=*top++;57}5859/* zero the top digits */60for(; x < a->used; x++){61*bottom++=0;62}63}6465/* remove excess digits */66 a->used -= b;67}
18/* shift left by a certain bit count */19intmp_mul_2d(mp_int * a,int b, mp_int * c)20{21 mp_digit d;22int res;2324/* copy */25if(a != c){26if((res =mp_copy(a, c))!= MP_OKAY){27return res;28}29}3031if(c->alloc <(int)(c->used + b/DIGIT_BIT +1)){32if((res =mp_grow(c, c->used + b / DIGIT_BIT +1))!= MP_OKAY){33return res;34}35}3637/* shift by as many digits in the bit count */38if(b >=(int)DIGIT_BIT){39if((res =mp_lshd(c, b / DIGIT_BIT))!= MP_OKAY){40return res;41}42}4344/* shift any bit count < DIGIT_BIT */45 d =(mp_digit)(b % DIGIT_BIT);46if(d !=0){47register mp_digit *tmpc, shift, mask, r, rr;48registerint x;4950/* bitmask for carries */51 mask =(((mp_digit)1)<< d)-1;5253/* shift for msbs */54 shift = DIGIT_BIT - d;5556/* alias */57 tmpc = c->dp;5859/* carry */60 r =0;61for(x =0; x < c->used; x++){62/* get the higher bits of the current word */63 rr =(*tmpc >> shift)& mask;6465/* shift the current word and OR in the carry */66*tmpc =((*tmpc << d)| r)& MP_MASK;67++tmpc;6869/* set the carry to the carry bits of the current word */70 r = rr;71}7273/* set final carry */74if(r !=0){75 c->dp[(c->used)++]= r;76}77}78mp_clamp(c);79return MP_OKAY;80}
mp_mul_2d的使用
#include<stdio.h>#include<stdlib.h>#include"utils.h"intmain(){printf("hello libtommath\n");
mp_int a,c;mp_init_multi(&a,&c,NULL);int b =2;mp_read_radix(&a,"3",16);mp_mul_2d(&a,b,&c);printf("a*2^b的结果为:");MP_print(&c);return0;}============================================:~/workspace/tommath_test$ ./a.out
hello libtommath
a*2^b的结果为: C
4.5.2 除以2的幂
mp_div_2d的原理
mp_div_2d的实现
18/* shift right by a certain bit count */19/*(store quotient in c, optional remainder in d) */20intmp_div_2d(mp_int * a,int b, mp_int * c, mp_int * d)21{22 mp_digit D, r, rr;23int x, res;24 mp_int t;252627/* if the shift count is <= 0 then we do no work */28if(b <=0){29 res =mp_copy(a, c);30if(d !=NULL){31mp_zero(d);32}33return res;34}3536if((res =mp_init(&t))!= MP_OKAY){37return res;38}3940/* get the remainder */41if(d !=NULL){42if((res =mp_mod_2d(a, b,&t))!= MP_OKAY){43mp_clear(&t);44return res;45}46}4748/* copy */49if((res =mp_copy(a, c))!= MP_OKAY){50mp_clear(&t);51return res;52}5354/* shift by as many digits in the bit count */55if(b >=(int)DIGIT_BIT){56mp_rshd(c, b / DIGIT_BIT);57}5859/* shift any bit count < DIGIT_BIT */60 D =(mp_digit)(b % DIGIT_BIT);61if(D !=0){62register mp_digit *tmpc, mask, shift;6364/* mask */65 mask =(((mp_digit)1)<< D)-1;6667/* shift for lsb */68 shift = DIGIT_BIT - D;6970/* alias */71 tmpc = c->dp +(c->used -1);7273/* carry */74 r =0;75for(x = c->used -1; x >=0; x--){76/* get the lower bits of this word in a temp */77 rr =*tmpc & mask;7879/* shift the current word and */80/*mix in the carry bits from the previous word */81*tmpc =(*tmpc >> D)|(r << shift);82--tmpc;8384/* set the carry to the carry bits of the current word found above */85 r = rr;86}87}88mp_clamp(c);89if(d !=NULL){90mp_exch(&t, d);91}92mp_clear(&t);93return MP_OKAY;94}
18/* calc a value mod 2**b */19int20mp_mod_2d(mp_int * a,int b, mp_int * c)21{22int x, res;2324/* if b is <= 0 then zero the int */25if(b <=0){26mp_zero(c);27return MP_OKAY;28}2930/* if the modulus is larger than the value than return */31if(b >=(int)(a->used * DIGIT_BIT)){32 res =mp_copy(a, c);33return res;34}3536/* copy */37if((res =mp_copy(a, c))!= MP_OKAY){38return res;39}4041/* zero digits above the last digit of the modulus */42for(x =(b / DIGIT_BIT)+((b % DIGIT_BIT)==0?0:1);43 x < c->used; x++){44 c->dp[x]=0;45}46/* clear the digit that is not completely outside/inside the modulus */47 c->dp[b / DIGIT_BIT]&=48(mp_digit)((((mp_digit)1)<<(((mp_digit) b)% DIGIT_BIT))-49((mp_digit)1));50mp_clamp(c);51return MP_OKAY;52}