scale = 0 /* * bc functions for modular group operations. * Anton Stiglic, 2000, 2001 * send bug reports to: stiglic@cs.mcgill.ca */ /* * modexp ( m, e, n ) returns m^e mod n * Right to left modular exponentiation, as described for example in the * Handbook of Applied Cryptography, algo 14.76, * http://www.cacr.math.uwaterloo.ca/hac/ */ define modexp( m, e, n ) { auto b, a, i, s; a = 1; s = m; while ( e > 0 ) { if ((e % 2) != 0 ) { a = a * s % n; } e /= 2; if ( e > 0 ) { s = s*s % n; } } return ( a ); } /* * mpower( a, b, c ) returns a^b mod c * This was written by Keith Matthews (U. of Queensland) * http://www.maths.uq.edu.au/~krm/MP313/handouts.html */ define mpower( a, b, c ) { auto x, y, z; x = a; y = b; z = 1; while ( y > 0 ) { while ( y%2 == 0) { y /= 2; x = (x*x)%c; } y -= 1; z = (z*x)%c; } return (z); } /* * modinv( a, n ) returns the inverse of a (mod n) or 0 if it doesn't exist */ define modinv( a, n ) { auto ret[]; ret=extended_gcd (a, n); if (ret[0] > 1) { return (0); } if (ret[1] < 0) { return (ret[1] + n); } return (ret[1]); } /* * lcm( a, b ) returns the least common multiple of a and b. */ define lcm( a, b ) { return (a*b/gcd(a,b)); } /* * gcd( a, b) returns the greatest common dividor of a and b. */ define gcd( a, b ) { auto ret[]; ret=extended_gcd(a, b); return (ret[0]); } /* * returns the h such that d = a*h + b*k, for the smallest d > 0. * (see _extended_gcd( a, b ). */ define gcdh( a, b) { auto ret[]; ret=extended_gcd(a, b); if ( a < b ) { return (ret[1]); } else { return (ret[2]); } return (0); } /* * returns the k such that d = a*h + b*k, for the smallest d > 0. * (see extended_gcd( a, b ). */ define gcdk( a, b) { auto ret[]; ret=extended_gcd(a, b); if ( a < b ) { return (ret[2]); } else { return (ret[1]); } return (0); } /* * Internal functions. */ define bits( x ) { auto b; while ( x > 0 ) { x /= 2; b += 1; } return( b ); } /* * extended_gcd( a, b ) computes the smallest d > 0 such that d = a*h + b*k, * it sets the resulting d into ret[0], h and k are stored in ret[1] and ret[2] * respectively (ret[] is assumed to have been declared by the calling function; * if you declared ret[] for some other reason in the scope of the call of this * function, you'll loose the values that where in the array). * * The idea behind the algo is to maintain, after each iteration, the relations, * d = a*x + b*y and d1 = a*x1 + b*y1, * while reducing the value of the d's using the well known fact that * gcd(d, d1) = gcd(d1, d mod d1). */ define extended_gcd ( a, b ) { auto d, d1, d2, q, x, x1, x2, y, y1, y2; /* * we start with d = b = a*0 + b*1 and d1 = a = a*1 + b*0 when * a < b, the "opposite" when a >= b */ if ( a < b ) { d1 = a; d = b; } else { d = a; d1 = b; } x = 1; y = 0; x1 = 0; y1 = 1; while ( d1 > 0 ) { q = d / d1; /* (d2, x2, y2) <- (d, x, y) - q(d1, x1, y1) */ d2 = d - q*d1; x2 = x - q*x1; y2 = y - q*y1; /* (d, x, y) <- (d1, x1, y1) */ d = d1; x = x1; y = y1; /* (d1, x1, y1) <- (d2, x2, y2) */ d1 = d2; x1 = x2; y1 = y2; } ret[0] = d; ret[1] = y; ret[2] = x; return (ret[0]); }