xref: /inferno-os/libmp/port/mpexp.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include "os.h"
2*37da2899SCharles.Forsyth #include <mp.h>
3*37da2899SCharles.Forsyth #include "dat.h"
4*37da2899SCharles.Forsyth 
5*37da2899SCharles.Forsyth // res = b**e
6*37da2899SCharles.Forsyth //
7*37da2899SCharles.Forsyth // knuth, vol 2, pp 398-400
8*37da2899SCharles.Forsyth 
9*37da2899SCharles.Forsyth enum {
10*37da2899SCharles.Forsyth 	Freeb=	0x1,
11*37da2899SCharles.Forsyth 	Freee=	0x2,
12*37da2899SCharles.Forsyth 	Freem=	0x4,
13*37da2899SCharles.Forsyth };
14*37da2899SCharles.Forsyth 
15*37da2899SCharles.Forsyth //int expdebug;
16*37da2899SCharles.Forsyth 
17*37da2899SCharles.Forsyth void
mpexp(mpint * b,mpint * e,mpint * m,mpint * res)18*37da2899SCharles.Forsyth mpexp(mpint *b, mpint *e, mpint *m, mpint *res)
19*37da2899SCharles.Forsyth {
20*37da2899SCharles.Forsyth 	mpint *t[2];
21*37da2899SCharles.Forsyth 	int tofree;
22*37da2899SCharles.Forsyth 	mpdigit d, bit;
23*37da2899SCharles.Forsyth 	int i, j;
24*37da2899SCharles.Forsyth 
25*37da2899SCharles.Forsyth 	i = mpcmp(e,mpzero);
26*37da2899SCharles.Forsyth 	if(i==0){
27*37da2899SCharles.Forsyth 		mpassign(mpone, res);
28*37da2899SCharles.Forsyth 		return;
29*37da2899SCharles.Forsyth 	}
30*37da2899SCharles.Forsyth 	if(i<0)
31*37da2899SCharles.Forsyth 		sysfatal("mpexp: negative exponent");
32*37da2899SCharles.Forsyth 
33*37da2899SCharles.Forsyth 	t[0] = mpcopy(b);
34*37da2899SCharles.Forsyth 	t[1] = res;
35*37da2899SCharles.Forsyth 
36*37da2899SCharles.Forsyth 	tofree = 0;
37*37da2899SCharles.Forsyth 	if(res == b){
38*37da2899SCharles.Forsyth 		b = mpcopy(b);
39*37da2899SCharles.Forsyth 		tofree |= Freeb;
40*37da2899SCharles.Forsyth 	}
41*37da2899SCharles.Forsyth 	if(res == e){
42*37da2899SCharles.Forsyth 		e = mpcopy(e);
43*37da2899SCharles.Forsyth 		tofree |= Freee;
44*37da2899SCharles.Forsyth 	}
45*37da2899SCharles.Forsyth 	if(res == m){
46*37da2899SCharles.Forsyth 		m = mpcopy(m);
47*37da2899SCharles.Forsyth 		tofree |= Freem;
48*37da2899SCharles.Forsyth 	}
49*37da2899SCharles.Forsyth 
50*37da2899SCharles.Forsyth 	// skip first bit
51*37da2899SCharles.Forsyth 	i = e->top-1;
52*37da2899SCharles.Forsyth 	d = e->p[i];
53*37da2899SCharles.Forsyth 	for(bit = mpdighi; (bit & d) == 0; bit >>= 1)
54*37da2899SCharles.Forsyth 		;
55*37da2899SCharles.Forsyth 	bit >>= 1;
56*37da2899SCharles.Forsyth 
57*37da2899SCharles.Forsyth 	j = 0;
58*37da2899SCharles.Forsyth 	for(;;){
59*37da2899SCharles.Forsyth 		for(; bit != 0; bit >>= 1){
60*37da2899SCharles.Forsyth 			mpmul(t[j], t[j], t[j^1]);
61*37da2899SCharles.Forsyth 			if(bit & d)
62*37da2899SCharles.Forsyth 				mpmul(t[j^1], b, t[j]);
63*37da2899SCharles.Forsyth 			else
64*37da2899SCharles.Forsyth 				j ^= 1;
65*37da2899SCharles.Forsyth 			if(m != nil && t[j]->top > m->top){
66*37da2899SCharles.Forsyth 				mpmod(t[j], m, t[j^1]);
67*37da2899SCharles.Forsyth 				j ^= 1;
68*37da2899SCharles.Forsyth 			}
69*37da2899SCharles.Forsyth 		}
70*37da2899SCharles.Forsyth 		if(--i < 0)
71*37da2899SCharles.Forsyth 			break;
72*37da2899SCharles.Forsyth 		bit = mpdighi;
73*37da2899SCharles.Forsyth 		d = e->p[i];
74*37da2899SCharles.Forsyth 	}
75*37da2899SCharles.Forsyth 	if(m != nil){
76*37da2899SCharles.Forsyth 		mpmod(t[j], m, t[j^1]);
77*37da2899SCharles.Forsyth 		j ^= 1;
78*37da2899SCharles.Forsyth 	}
79*37da2899SCharles.Forsyth 	if(t[j] == res){
80*37da2899SCharles.Forsyth 		mpfree(t[j^1]);
81*37da2899SCharles.Forsyth 	} else {
82*37da2899SCharles.Forsyth 		mpassign(t[j], res);
83*37da2899SCharles.Forsyth 		mpfree(t[j]);
84*37da2899SCharles.Forsyth 	}
85*37da2899SCharles.Forsyth 
86*37da2899SCharles.Forsyth 	if(tofree){
87*37da2899SCharles.Forsyth 		if(tofree & Freeb)
88*37da2899SCharles.Forsyth 			mpfree(b);
89*37da2899SCharles.Forsyth 		if(tofree & Freee)
90*37da2899SCharles.Forsyth 			mpfree(e);
91*37da2899SCharles.Forsyth 		if(tofree & Freem)
92*37da2899SCharles.Forsyth 			mpfree(m);
93*37da2899SCharles.Forsyth 	}
94*37da2899SCharles.Forsyth }
95