mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
	
	
		
			379 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
		
		
			
		
	
	
			379 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
|  | /* crypto/bn/bn_knuth.c */ | ||
|  | 
 | ||
|  | #include <stdio.h>
 | ||
|  | #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<<Q); | ||
|  | 		r[k]=(1<<R); | ||
|  | 		} | ||
|  | #ifdef DEBUG
 | ||
|  | 	printf("k   ="); | ||
|  | 	for (i=0; i<=k; i++) printf("%7d",i); | ||
|  | 	printf("\nq[k]="); | ||
|  | 	for (i=0; i<=k; i++) printf("%7d",q[i]); | ||
|  | 	printf("\nr[k]="); | ||
|  | 	for (i=0; i<=k; i++) printf("%7d",r[i]); | ||
|  | 	printf("\n"); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	/* C2 */ | ||
|  | 	C[Ctos++]=CODE1; | ||
|  | 	if ((t1=LBN_dup(a)) == NULL) goto err; | ||
|  | 	C[Ctos++]=t1; | ||
|  | 	if ((t1=LBN_dup(b)) == NULL) goto err; | ||
|  | 	C[Ctos++]=t1; | ||
|  | 
 | ||
|  | 	state=C3; | ||
|  | 	for (;;) | ||
|  | 		{ | ||
|  | #ifdef DEBUG
 | ||
|  | 		printf("state=C%d, Ctos=%d Wtos=%d\n",state,Ctos,Wtos); | ||
|  | #endif
 | ||
|  | 		switch (state) | ||
|  | 			{ | ||
|  | 			int lr,lq,lp; | ||
|  | 		case C3: | ||
|  | 			k--; | ||
|  | 			if (k == 0) | ||
|  | 				{ | ||
|  | 				t1=C[--Ctos]; | ||
|  | 				t2=C[--Ctos]; | ||
|  | #ifdef DEBUG
 | ||
|  | 				printf("Ctos=%d poped %d\n",Ctos,2); | ||
|  | #endif
 | ||
|  | 				if ((t2->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; i<Utos; i++) | ||
|  | 				printf("U[%2d]=%4d bits\n",i,BN_num_bits(U[i])); | ||
|  | 			for (i=0; i<Vtos; i++) | ||
|  | 				printf("V[%2d]=%4d bits\n",i,BN_num_bits(V[i])); | ||
|  | #endif
 | ||
|  | 			/* C5 */ | ||
|  | #ifdef DEBUG
 | ||
|  | 			printf("PUSH CODE2 and %d CODE3 onto stack\n",2*lr); | ||
|  | #endif
 | ||
|  | 			C[Ctos++]=CODE2; | ||
|  | 			for (i=2*lr; i>0; 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<<b); | ||
|  | 		} | ||
|  | 	return(1); | ||
|  | 	} | ||
|  | 
 | ||
|  | BIGNUM *LBN_dup(a) | ||
|  | BIGNUM *a; | ||
|  | 	{ | ||
|  | 	new_total++; | ||
|  | 	max_total++; | ||
|  | 	if (max_total > 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); | ||
|  | 	} |