/* crypto/bn/bn_knuth.c */ #include #include "cryptlib.h" #include "bn.h" /* This is just a test implementation, it has not been modified for * speed and it still has memory leaks. */ int BN_mask_bits(BIGNUM *a,int n); #undef DEBUG #define MAIN /* r must be different to a and b * Toom-Cook multiplication algorithm, taken from * The Art Of Computer Programming, Volume 2, Donald Knuth */ #define CODE1 ((BIGNUM *)0x01) #define CODE2 ((BIGNUM *)0x02) #define CODE3 ((BIGNUM *)0x03) #define MAXK (30+1) #define C3 3 #define C4 4 #define C5 5 #define C6 6 #define C7 7 #define C8 8 #define C9 9 #define C10 10 #define DONE 11 int new_total=0; int Free_total=0; int max=0,max_total=0; BIGNUM *LBN_new(void ); BIGNUM *LBN_dup(BIGNUM *a); void LBN_free(BIGNUM *a); int BN_mul_knuth(w, a, b) BIGNUM *w; BIGNUM *a; BIGNUM *b; { int ret=1; int i,j,n,an,bn,y,z; BIGNUM *U[MAXK],*V[MAXK],*T[MAXK]; BIGNUM *C[(MAXK*2*3)]; BIGNUM *W[(MAXK*2)],*t1,*t2,*t3,*t4; int Utos,Vtos,Ctos,Wtos,Ttos; unsigned int k,Q,R; unsigned int q[MAXK]; unsigned int r[MAXK]; int state; /* C1 */ Utos=Vtos=Ctos=Wtos=Ttos=0; k=1; q[0]=q[1]=64; r[0]=r[1]=4; Q=6; R=2; if (!bn_expand(w,BN_BITS2*2)) goto err; an=BN_num_bits(a); bn=BN_num_bits(b); n=(an > bn)?an:bn; while ((q[k-1]+q[k]) < n) { k++; Q+=R; i=R+1; if ((i*i) <= Q) R=i; q[k]=(1<top == 0) || (t1->top == 0)) w->top=0; else BN_mul(w,t1,t2); LBN_free(t1); /* FREE */ LBN_free(t2); /* FREE */ state=C10; } else { lr=r[k]; lq=q[k]; lp=q[k-1]+q[k]; state=C4; } break; case C4: for (z=0; z<2; z++) /* do for u and v */ { /* break the item at C[Ctos-1] * into lr+1 parts of lq bits each * for j=0; j<=2r; j++ */ t1=C[--Ctos]; /* pop off u */ #ifdef DEBUG printf("Ctos=%d poped %d\n",Ctos,1); #endif if ((t2=LBN_dup(t1)) == NULL) goto err; BN_mask_bits(t2,lq); T[Ttos++]=t2; #ifdef DEBUG printf("C4 r=0 bits=%d\n",BN_num_bits(t2)); #endif for (i=1; i<=lr; i++) { if (!BN_rshift(t1,t1,lq)) goto err; if ((t2=LBN_dup(t1)) == NULL) goto err; BN_mask_bits(t2,lq); T[Ttos++]=t2; #ifdef DEBUG printf("C4 r=%d bits=%d\n",i, BN_num_bits(t2)); #endif } LBN_free(t1); if ((t2=LBN_new()) == NULL) goto err; if ((t3=LBN_new()) == NULL) goto err; for (j=0; j<=2*lr; j++) { if ((t1=LBN_new()) == NULL) goto err; if (!BN_set_word(t3,j)) goto err; for (i=lr; i>=0; i--) { if (!BN_mul(t2,t1,t3)) goto err; if (!BN_add(t1,t2,T[i])) goto err; } /* t1 is U(j) */ if (z == 0) U[Utos++]=t1; else V[Vtos++]=t1; } LBN_free(t2); LBN_free(t3); while (Ttos) LBN_free(T[--Ttos]); } #ifdef DEBUG for (i=0; i0; i--) { C[Ctos++]=V[i]; C[Ctos++]=U[i]; C[Ctos++]=CODE3; } C[Ctos++]=V[0]; C[Ctos++]=U[0]; #ifdef DEBUG printf("Ctos=%d pushed %d\n",Ctos,2*lr*3+3); #endif Vtos=Utos=0; state=C3; break; case C6: if ((t1=LBN_dup(w)) == NULL) goto err; W[Wtos++]=t1; #ifdef DEBUG printf("put %d bit number onto w\n",BN_num_bits(t1)); #endif state=C3; break; case C7: lr=r[k]; lq=q[k]; lp=q[k]+q[k-1]; z=Wtos-2*lr-1; for (j=1; j<=2*lr; j++) { for (i=2*lr; i>=j; i--) { if (!BN_sub(W[z+i],W[z+i],W[z+i-1])) goto err; BN_div_word(W[z+i],j); } } state=C8; break; case C8: y=2*lr-1; if ((t1=LBN_new()) == NULL) goto err; if ((t3=LBN_new()) == NULL) goto err; for (j=y; j>0; j--) { if (!BN_set_word(t3,j)) goto err; for (i=j; i<=y; i++) { if (!BN_mul(t1,W[z+i+1],t3)) goto err; if (!BN_sub(W[z+i],W[z+i],t1)) goto err; } } LBN_free(t1); LBN_free(t3); state=C9; break; case C9: BN_zero(w); #ifdef DEBUG printf("lq=%d\n",lq); #endif for (i=lr*2; i>=0; i--) { BN_lshift(w,w,lq); BN_add(w,w,W[z+i]); } for (i=0; i<=lr*2; i++) LBN_free(W[--Wtos]); state=C10; break; case C10: k++; t1=C[--Ctos]; #ifdef DEBUG printf("Ctos=%d poped %d\n",Ctos,1); printf("code= CODE%d\n",t1); #endif if (t1 == CODE3) state=C6; else if (t1 == CODE2) { if ((t2=LBN_dup(w)) == NULL) goto err; W[Wtos++]=t2; state=C7; } else if (t1 == CODE1) { state=DONE; } else { printf("BAD ERROR\n"); goto err; } break; default: printf("bad state\n"); goto err; break; } if (state == DONE) break; } ret=1; err: if (ret == 0) printf("ERROR\n"); return(ret); } #ifdef MAIN main() { BIGNUM *a,*b,*r; int i; if ((a=LBN_new()) == NULL) goto err; if ((b=LBN_new()) == NULL) goto err; if ((r=LBN_new()) == NULL) goto err; if (!BN_rand(a,1024*2,0,0)) goto err; if (!BN_rand(b,1024*2,0,0)) goto err; for (i=0; i<10; i++) { if (!BN_mul_knuth(r,a,b)) goto err; /**/ /*if (!BN_mul(r,a,b)) goto err; /**/ } BN_print(stdout,a); printf(" * "); BN_print(stdout,b); printf(" =\n"); BN_print(stdout,r); printf("\n"); printf("BN_new() =%d\nBN_free()=%d max=%d\n",new_total,Free_total,max); exit(0); err: ERR_load_crypto_strings(); ERR_print_errors(stderr); exit(1); } #endif int BN_mask_bits(a,n) BIGNUM *a; int n; { int b,w; w=n/BN_BITS2; b=n%BN_BITS2; if (w >= a->top) return(0); if (b == 0) a->top=w; else { a->top=w+1; a->d[w]&= ~(BN_MASK2< max) max=max_total; return(BN_dup(a)); } BIGNUM *LBN_new() { new_total++; max_total++; if (max_total > max) max=max_total; return(BN_new()); } void LBN_free(a) BIGNUM *a; { max_total--; if (max_total > max) max=max_total; Free_total++; BN_free(a); }