rdesktop/crypto/arith.c
Matt Chapman 3adf8de45c Crypto routines.
git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@10 423420c4-83ab-492f-b58f-81f9feb106b5
2000-08-15 10:32:09 +00:00

682 lines
11 KiB
C

/*******************************************************************************
* *
* Copyright (c) Martin Nicolay, 22. Nov. 1988 *
* *
* Wenn diese (oder sinngemaess uebersetzte) Copyright-Angabe enthalten *
* bleibt, darf diese Source fuer jeden nichtkomerziellen Zweck weiter *
* verwendet werden. *
* *
* martin@trillian.megalon.de *
* *
*******************************************************************************/
#include "arith.h"
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!! ACHTUNG !!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Es findet keinerlei Ueberpruefung auf Bereichsueberschreitung
* statt. Alle Werte muessen natuerliche Zahlen aus dem Bereich
* 0 ... (MAXINT+1)^MAXLEN-1 sein.
*
*
* Bei keiner Funktion oder Hilsfunktion werden Annahmen getroffen,
* ueber die Verschiedenheit von Eingabe- & Ausgabe-Werten.
*
*
* Funktionen:
*
* a_add( s1, s2, d )
* NUMBER *s1,*s2,*d;
* *d = *s1 + *s2;
*
* a_assign( *d, *s )
* NUMBER *d,*s;
* *d = *s;
*
* int a_cmp( c1, c2 )
* NUMBER *c1,*c2;
* 1 : falls *c1 > *c2
* 0 : falls *c1 == *c2
* -1 : falls *c1 < *c2
*
* a_div( d1, d2, q, r )
* NUMBER *d1,*d2,*q,*r;
* *q = *d1 / *d2 Rest *r;
*
* a_div2( n )
* NUMBER *n;
* *n /= 2;
*
* a_ggt( a, b, f )
* NUMBER *a,*b,*f;
* *f = ( *a, *b );
*
* a_imult( n, m, d )
* NUMBER *n;
* INT m;
* NUMBER *d;
* *d = *n * m
*
* a_mult( m1, m2, d )
* NUMBER *m1,*m2,*d;
* *d = *m1 * *m2;
*
* a_sub( s1, s2, d )
* NUMBER *s1,*s2,*d;
* *d = *s1 - *s2;
*
* Modulare Funktionen
* m_init( n, o )
* NUMBER *n,*o;
* Initialsierung der Modularen Funktionen
* o != 0 : *o = alter Wert
*
* m_add( s1, s2, d )
* NUMBER *s1, *s2, *d;
* *d = *s1 + *s2;
*
* m_mult( m1, m2, d )
* NUMBER *m1,*m2,*d;
*
* m_exp( x, n, z )
* NUMBER *x,*n,*z;
* *z = *x exp *n;
*
*
* Hilfs-Funktionen:
*
* int n_bits( n, b )
* NUMBER *n;
* int b;
* return( unterste b Bits der Dualdarstellung von n)
*
* n_div( d1, z2, q, r )
* NUMBER *d1,z2[MAXBIT],*q,*r;
* *q = *d1 / z2[0] Rest *r;
* z2[i] = z2[0] * 2^i, i=0..MAXBIT-1
*
* int n_cmp( i1, i2, l )
* INT i1[l], i2[l];
* 1 : falls i1 > i2
* 0 : falls i1 == i2
* -1 : falls i1 < i2
*
* int n_mult( n, m, d, l)
* INT n[l], m, d[];
* d = m * n;
* return( sizeof(d) ); d.h. 'l' oder 'l+1'
*
* int n_sub( p1, p2, p3, l, lo )
* INT p1[l], p2[lo], p3[];
* p3 = p1 - p2;
* return( sizeof(p3) ); d.h. '<= min(l,lo)'
*
* int n_bitlen( n )
* NUMBER *n;
* return( sizeof(n) in bits )
*
*/
/*
* Konstante 1, 2
*/
NUMBER a_one = {
1,
{ (INT)1, },
};
NUMBER a_two = {
#if MAXINT == 1
2,
{ 0, (INT)1, },
#else
1,
{ (INT)2, },
#endif
};
/*
* Vergleiche zwei INT arrays der Laenge l
*/
int n_cmp( i1, i2, l )
INT *i1,*i2;
{
i1 += (l-1); /* Pointer ans Ende */
i2 += (l-1);
for (;l--;)
if ( *i1-- != *i2-- )
return( i1[1] > i2[1] ? 1 : -1 );
return(0);
}
/*
* Vergleiche zwei NUMBER
*/
int a_cmp( c1, c2 )
NUMBER *c1,*c2;
{
int l;
/* bei verschiedener Laenge klar*/
if ( (l=c1->n_len) != c2->n_len)
return( l - c2->n_len);
/* vergleiche als arrays */
return( n_cmp( c1->n_part, c2->n_part, l) );
}
/*
* Zuweisung einer NUMBER (d = s)
*/
void a_assign( d, s )
NUMBER *d,*s;
{
int l;
if (s == d) /* nichts zu kopieren */
return;
if ((l=s->n_len))
memcpy( d->n_part, s->n_part, sizeof(INT)*l);
d->n_len = l;
}
/*
* Addiere zwei NUMBER (d = s1 + s2)
*/
void a_add( s1, s2, d )
NUMBER *s1,*s2,*d;
{
int l,lo,ld,same;
register LONG sum;
register INT *p1,*p2,*p3;
register INT b;
/* setze s1 auch die groessere Zahl */
l = s1->n_len;
if ( (l=s1->n_len) < s2->n_len ) {
NUMBER *tmp = s1;
s1 = s2;
s2 = tmp;
l = s1->n_len;
}
ld = l;
lo = s2->n_len;
p1 = s1->n_part;
p2 = s2->n_part;
p3 = d->n_part;
same = (s1 == d);
sum = 0;
while (l --) {
if (lo) { /* es ist noch was von s2 da */
lo--;
b = *p2++;
}
else
b = 0; /* ansonten 0 nehmen */
sum += (LONG)*p1++ + (LONG)b;
*p3++ = TOINT(sum);
if (sum > (LONG)MAXINT) { /* carry merken */
sum = 1;
}
else
sum = 0;
if (!lo && same && !sum) /* nichts mehr zu tuen */
break;
}
if (sum) { /* letztes carry beruecksichtigen */
ld++;
*p3 = sum;
}
d->n_len = ld; /* Laenge setzen */
}
/*
* Subtrahiere zwei INT arrays. return( Laenge Ergebniss )
* l == Laenge p1
* lo== Laenge p3
*/
int n_sub( p1, p2, p3, l, lo )
INT *p1,*p2,*p3;
int l,lo;
{
int ld,lc,same;
int over = 0;
register LONG dif;
LONG a,b;
same = (p1 == p3); /* frueher Abbruch moeglich */
for (lc=1, ld=0; l--; lc++) {
a = (LONG)*p1++;
if (lo) { /* ist noch was von p2 da ? */
lo--;
b = (LONG)*p2++;
}
else
b=0; /* ansonten 0 nehmen */
if (over) /* frueherer Overflow */
b++;
if ( b > a ) { /* jetzt Overflow ? */
over = 1;
dif = (MAXINT +1) + a;
}
else {
over = 0;
dif = a;
}
dif -= b;
*p3++ = (INT)dif;
if (dif) /* Teil != 0 : Laenge neu */
ld = lc;
if (!lo && same && !over) { /* nichts mehr zu tuen */
if (l > 0) /* Laenge korrigieren */
ld = lc + l;
break;
}
}
return( ld );
}
/*
* Subtrahiere zwei NUMBER (d= s1 - s2)
*/
void a_sub( s1, s2, d )
NUMBER *s1,*s2,*d;
{
d->n_len = n_sub( s1->n_part, s2->n_part, d->n_part
,s1->n_len, s2->n_len );
}
/*
* Mulitipliziere INT array der Laenge l mit einer INT (d = n * m)
* return neue Laenge
*/
int n_mult( n, m, d, l)
register INT *n;
register INT m;
INT *d;
{
int i;
register LONG mul;
for (i=l,mul=0; i; i--) {
mul += (LONG)m * (LONG)*n++;
*d++ = TOINT(mul);
mul = DIVMAX1( mul );
}
if (mul) { /* carry ? */
l++;
*d = mul;
}
return( l );
}
/*
* Mulitipliziere eine NUMBER mit einer INT (d = n * m)
*/
void a_imult( n, m, d )
NUMBER *n;
INT m;
NUMBER *d;
{
if (m == 0)
d->n_len=0;
else if (m == 1)
a_assign( d, n );
else
d->n_len = n_mult( n->n_part, m, d->n_part, n->n_len );
}
/*
* Multipliziere zwei NUMBER (d = m1 * m2)
*/
void a_mult( m1, m2, d )
NUMBER *m1,*m2,*d;
{
static INT id[ MAXLEN ]; /* Zwischenspeicher */
register INT *vp; /* Pointer darin */
register LONG sum; /* Summe fuer jede Stelle */
register LONG tp1; /* Zwischenspeicher fuer m1 */
register INT *p2;
INT *p1;
int l1,l2,ld,lc,l,i,j;
l1 = m1->n_len;
l2 = m2->n_len;
l = l1 + l2;
if (l >= MAXLEN)
abort();
for (i=l, vp=id; i--;)
*vp++ = 0;
/* ohne Uebertrag in Zwischenspeicher multiplizieren */
for ( p1 = m1->n_part, i=0; i < l1 ; i++, p1++ ) {
tp1 = (LONG)*p1;
vp = &id[i];
sum = 0;
for ( p2 = m2->n_part, j = l2; j--;) {
sum += (LONG)*vp + (tp1 * (LONG)*p2++);
*vp++ = TOINT( sum );
sum = DIVMAX1(sum);
}
*vp++ += (INT)sum;
}
/* jetzt alle Uebertraege beruecksichtigen */
ld = 0;
for (lc=0, vp=id, p1=d->n_part; lc++ < l;) {
if (( *p1++ = *vp++ ))
ld = lc;
}
d->n_len = ld;
}
/*
* Dividiere Zwei NUMBER mit Rest (q= d1 / z2[0] Rest r)
* z2[i] = z2[0] * 2^i, i=0..MAXBIT-1
* r = 0 : kein Rest
* q = 0 : kein Quotient
*/
void n_div( d1, z2, q, r )
NUMBER *d1,*z2,*q,*r;
{
static NUMBER dummy_rest; /* Dummy Variable, falls r = 0 */
static NUMBER dummy_quot; /* Dummy Variable, falla q = 0 */
INT *i1,*i1e,*i3;
int l2,ld,l,lq;
#if MAXINT != 1
INT z;
int pw,l2t;
#endif
if (!z2->n_len)
abort();
if (!r)
r = &dummy_rest;
if (!q)
q = &dummy_quot;
a_assign( r, d1 ); /* Kopie von d1 in den Rest */
l2= z2->n_len; /* Laenge von z2[0] */
l = r->n_len - l2; /* Laenge des noch ''rechts'' liegenden
Stuecks von d1 */
lq= l +1; /* Laenge des Quotienten */
i3= q->n_part + l;
i1= r->n_part + l;
ld = l2; /* aktuelle Laenge des ''Vergleichsstuecks''
von d1 */
i1e= i1 + (ld-1);
for (; l >= 0; ld++, i1--, i1e--, l--, i3--) {
*i3 = 0;
if (ld == l2 && ! *i1e) {
ld--;
continue;
}
if ( ld > l2 || (ld == l2 && n_cmp( i1, z2->n_part, l2) >= 0 ) ) {
#if MAXINT != 1
/* nach 2er-Potenzen zerlegen */
for (pw=MAXBIT-1, z=(INT)HIGHBIT; pw >= 0; pw--, z /= 2) {
if ( ld > (l2t= z2[pw].n_len)
|| (ld == l2t
&& n_cmp( i1, z2[pw].n_part, ld) >= 0) ) {
ld = n_sub( i1, z2[pw].n_part, i1, ld, l2t );
(*i3) += z;
}
}
#else
/* bei MAXINT == 1 alles viel einfacher */
ld = n_sub( i1, z2->n_part, i1, ld, l2 );
(*i3) ++;
#endif
}
}
/* Korrektur, falls l von Anfang an Negativ war */
l ++;
lq -= l;
ld += l;
if (lq>0 && !q->n_part[lq -1]) /* evtl. Laenge korrigieren */
lq--;
q->n_len = lq;
r->n_len = ld -1;
}
/*
* Dividiere Zwei NUMBER mit Rest (q= d1 / z2[0] Rest r)
* z2[i] = z2[0] * 2^i, i=0..MAXBIT-1
* r = 0 : kein Rest
* q = 0 : kein Quotient
*/
void a_div( d1, d2, q, r )
NUMBER *d1,*d2,*q,*r;
{
#if MAXINT != 1
NUMBER z2[MAXBIT];
INT z;
int i;
a_assign( &z2[0], d2 );
for (i=1,z=2; i < MAXBIT; i++, z *= 2)
a_imult( d2, z, &z2[i] );
d2 = z2;
#endif
n_div( d1, d2, q, r );
}
/*
* Dividiere eine NUMBER durch 2
*/
void a_div2( n )
NUMBER *n;
{
#if MAXBIT == LOWBITS
register INT *p;
int i;
#if MAXINT != 1
register INT h;
register int c;
c=0;
i= n->n_len;
p= &n->n_part[i-1];
for (; i--;) {
if (c) {
c = (h= *p) & 1;
h /= 2;
h |= HIGHBIT;
}
else {
c = (h= *p) & 1;
h /= 2;
}
*p-- = h;
}
if ( (i= n->n_len) && n->n_part[i-1] == 0 )
n->n_len = i-1;
#else /* MAXBIT != 1 */
p = n->n_part;
i = n->n_len;
if (i) {
n->n_len = i-1;
for (; --i ; p++)
p[0] = p[1];
}
#endif /* MAXBIT != 1 */
#else /* MAXBIT == LOWBITS */
a_div( n, &a_two, n, NUM0P );
#endif /* MAXBIT == LOWBITS */
}
/*
* MODULO-FUNKTIONEN
*/
static NUMBER mod_z2[ MAXBIT ];
/*
* Init
*/
void m_init( n, o )
NUMBER *n,*o;
{
INT z;
int i;
if (o)
a_assign( o, &mod_z2[0] );
if (! a_cmp( n, &mod_z2[0] ) )
return;
for (i=0,z=1; i < MAXBIT; i++, z *= 2)
a_imult( n, z, &mod_z2[i] );
}
void m_add( s1, s2, d )
NUMBER *s1, *s2, *d;
{
a_add( s1, s2, d );
if (a_cmp( d, mod_z2 ) >= 0)
a_sub( d, mod_z2, d );
}
void m_mult( m1, m2, d )
NUMBER *m1,*m2,*d;
{
a_mult( m1, m2, d );
n_div( d, mod_z2, NUM0P, d );
}
/*
* Restklassen Exponent
*/
void m_exp( x, n, z )
NUMBER *x,*n,*z;
{
NUMBER xt,nt;
a_assign( &nt, n );
a_assign( &xt, x );
a_assign( z, &a_one );
while (nt.n_len) {
while ( ! (nt.n_part[0] & 1) ) {
m_mult( &xt, &xt, &xt );
a_div2( &nt );
}
m_mult( &xt, z, z );
a_sub( &nt, &a_one, &nt );
}
}
/*
* GGT
*/
void a_ggt( a, b, f )
NUMBER *a,*b,*f;
{
NUMBER t[2];
int at,bt, tmp;
a_assign( &t[0], a ); at= 0;
a_assign( &t[1], b ); bt= 1;
if ( a_cmp( &t[at], &t[bt] ) < 0 ) {
tmp= at; at= bt; bt= tmp;
}
/* euklidischer Algorithmus */
while ( t[bt].n_len ) {
a_div( &t[at], &t[bt], NUM0P, &t[at] );
tmp= at; at= bt; bt= tmp;
}
a_assign( f, &t[at] );
}
/*
* die untersten b bits der Dualdarstellung von n
* die bits muessen in ein int passen
*/
int n_bits(n,b)
NUMBER *n;
{
INT *p;
int l;
unsigned r;
int m = (1<<b) -1;
if ( n->n_len == 0)
return(0);
if (LOWBITS >= b)
return( n->n_part[0] & m );
#if LOWBITS != 0
l = (b-1) / LOWBITS;
#else
l = n->n_len -1;
#endif
for (p= &n->n_part[l],r=0; l-- >= 0 && b > 0; b-= LOWBITS, p--) {
r = MULMAX1( r );
r += (unsigned)*p;
}
return( r & m );
}
/*
* Anzahl der bits von n bei Dualdarstellung
*/
int n_bitlen( n )
NUMBER *n;
{
NUMBER b;
int i;
a_assign( &b, &a_one );
for (i=0; a_cmp( &b, n ) <= 0; a_mult( &b, &a_two, &b ), i++)
;
return(i);
}