xref: /plan9/sys/src/libmp/port/mpexp.c (revision dc5a79c1208f0704eeb474acc990728f8b4854f5)
17dd7cddfSDavid du Colombier #include "os.h"
27dd7cddfSDavid du Colombier #include <mp.h>
37dd7cddfSDavid du Colombier #include "dat.h"
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier // res = b**e
67dd7cddfSDavid du Colombier //
77dd7cddfSDavid du Colombier // knuth, vol 2, pp 398-400
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier enum {
107dd7cddfSDavid du Colombier 	Freeb=	0x1,
117dd7cddfSDavid du Colombier 	Freee=	0x2,
127dd7cddfSDavid du Colombier 	Freem=	0x4,
137dd7cddfSDavid du Colombier };
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier //int expdebug;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier void
mpexp(mpint * b,mpint * e,mpint * m,mpint * res)187dd7cddfSDavid du Colombier mpexp(mpint *b, mpint *e, mpint *m, mpint *res)
197dd7cddfSDavid du Colombier {
207dd7cddfSDavid du Colombier 	mpint *t[2];
217dd7cddfSDavid du Colombier 	int tofree;
227dd7cddfSDavid du Colombier 	mpdigit d, bit;
237dd7cddfSDavid du Colombier 	int i, j;
247dd7cddfSDavid du Colombier 
25*dc5a79c1SDavid du Colombier 	i = mpcmp(e,mpzero);
26*dc5a79c1SDavid du Colombier 	if(i==0){
27*dc5a79c1SDavid du Colombier 		mpassign(mpone, res);
28*dc5a79c1SDavid du Colombier 		return;
29*dc5a79c1SDavid du Colombier 	}
30*dc5a79c1SDavid du Colombier 	if(i<0)
31*dc5a79c1SDavid du Colombier 		sysfatal("mpexp: negative exponent");
32*dc5a79c1SDavid du Colombier 
337dd7cddfSDavid du Colombier 	t[0] = mpcopy(b);
347dd7cddfSDavid du Colombier 	t[1] = res;
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier 	tofree = 0;
377dd7cddfSDavid du Colombier 	if(res == b){
387dd7cddfSDavid du Colombier 		b = mpcopy(b);
397dd7cddfSDavid du Colombier 		tofree |= Freeb;
407dd7cddfSDavid du Colombier 	}
417dd7cddfSDavid du Colombier 	if(res == e){
427dd7cddfSDavid du Colombier 		e = mpcopy(e);
437dd7cddfSDavid du Colombier 		tofree |= Freee;
447dd7cddfSDavid du Colombier 	}
457dd7cddfSDavid du Colombier 	if(res == m){
467dd7cddfSDavid du Colombier 		m = mpcopy(m);
477dd7cddfSDavid du Colombier 		tofree |= Freem;
487dd7cddfSDavid du Colombier 	}
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	// skip first bit
517dd7cddfSDavid du Colombier 	i = e->top-1;
527dd7cddfSDavid du Colombier 	d = e->p[i];
537dd7cddfSDavid du Colombier 	for(bit = mpdighi; (bit & d) == 0; bit >>= 1)
547dd7cddfSDavid du Colombier 		;
557dd7cddfSDavid du Colombier 	bit >>= 1;
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier 	j = 0;
587dd7cddfSDavid du Colombier 	for(;;){
597dd7cddfSDavid du Colombier 		for(; bit != 0; bit >>= 1){
607dd7cddfSDavid du Colombier 			mpmul(t[j], t[j], t[j^1]);
617dd7cddfSDavid du Colombier 			if(bit & d)
627dd7cddfSDavid du Colombier 				mpmul(t[j^1], b, t[j]);
637dd7cddfSDavid du Colombier 			else
647dd7cddfSDavid du Colombier 				j ^= 1;
657dd7cddfSDavid du Colombier 			if(m != nil && t[j]->top > m->top){
667dd7cddfSDavid du Colombier 				mpmod(t[j], m, t[j^1]);
677dd7cddfSDavid du Colombier 				j ^= 1;
687dd7cddfSDavid du Colombier 			}
697dd7cddfSDavid du Colombier 		}
707dd7cddfSDavid du Colombier 		if(--i < 0)
717dd7cddfSDavid du Colombier 			break;
727dd7cddfSDavid du Colombier 		bit = mpdighi;
737dd7cddfSDavid du Colombier 		d = e->p[i];
747dd7cddfSDavid du Colombier 	}
757dd7cddfSDavid du Colombier 	if(m != nil){
767dd7cddfSDavid du Colombier 		mpmod(t[j], m, t[j^1]);
777dd7cddfSDavid du Colombier 		j ^= 1;
787dd7cddfSDavid du Colombier 	}
797dd7cddfSDavid du Colombier 	if(t[j] == res){
807dd7cddfSDavid du Colombier 		mpfree(t[j^1]);
817dd7cddfSDavid du Colombier 	} else {
827dd7cddfSDavid du Colombier 		mpassign(t[j], res);
837dd7cddfSDavid du Colombier 		mpfree(t[j]);
847dd7cddfSDavid du Colombier 	}
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier 	if(tofree){
877dd7cddfSDavid du Colombier 		if(tofree & Freeb)
887dd7cddfSDavid du Colombier 			mpfree(b);
897dd7cddfSDavid du Colombier 		if(tofree & Freee)
907dd7cddfSDavid du Colombier 			mpfree(e);
917dd7cddfSDavid du Colombier 		if(tofree & Freem)
927dd7cddfSDavid du Colombier 			mpfree(m);
937dd7cddfSDavid du Colombier 	}
947dd7cddfSDavid du Colombier }
95