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);
|
|
}
|