--- pgp/src/mpilib.h 2018/04/24 16:37:53 1.1.1.1 +++ pgp/src/mpilib.h 2018/04/24 16:45:26 1.1.1.9 @@ -1,4 +1,4 @@ -/* C include file for MPI multiprecision integer math routines +/* C include file for MPI multiprecision integer math routines. Boulder Software Engineering 3021 Eleventh Street @@ -6,46 +6,64 @@ (303) 541-0140 (c) Copyright 1986-92 by Philip Zimmermann. All rights reserved. - The author assumes no liability for damages resulting from the use - of this software, even if the damage results from defects in this - software. No warranty is expressed or implied. + The author assumes no liability for damages resulting from the use + of this software, even if the damage results from defects in this + software. No warranty is expressed or implied. These routines implement all of the multiprecision arithmetic necessary - for Rivest-Shamir-Adleman (RSA) public key cryptography, as well as - other number-theoretic algorithms such as ElGamal, Diffie-Hellman, + for Rivest-Shamir-Adleman (RSA) public key cryptography, as well as + other number-theoretic algorithms such as ElGamal, Diffie-Hellman, or Rabin. - Although originally developed in Microsoft C for the IBM PC, this code - contains few machine dependancies. It assumes 2's complement - arithmetic. It can be adapted to 8-bit, 16-bit, or 32-bit machines, + Although originally developed in Microsoft C for the IBM PC, this code + contains few machine dependencies. It assumes 2's complement + arithmetic. It can be adapted to 8-bit, 16-bit, or 32-bit machines, lowbyte-highbyte order or highbyte-lowbyte order. This version has been converted to ANSI C. - Modified 8 Apr 92 - HAJK - Implement new VAX/VMS primitive support. + Modified 8 Apr 92 - HAJK - Implement new VAX/VMS primitive support. + Modified 29 Nov 92 - Thad Smith */ +#include #include "usuals.h" /* typedefs for byte, word16, boolean, etc. */ +#include "platform.h" /* customization for different environments */ - -/* #define PORTABLE */ /* determines if we use C primitives */ -/* #define UNIT8 */ /* use 8-bit units */ -/* #define UNIT16 */ /* use 16-bit units */ -/* #define UNIT32 */ /* use 32-bit units */ -/* #define HIGHFIRST */ /* determines if Motorola or Intel internal format */ - -#ifdef VMS /* VAX/VMS */ -#ifndef PORTABLE -#define UNIT32 /* use 32-bit units */ -#endif /* not PORTABLE */ -#endif /* VMS */ +/* Platform customization: + * A version which runs on almost any computer can be implemented by + * defining PORTABLE and MPORTABLE, preferably as a command line + * parameter. Faster versions can be generated by specifying specific + * parameters, such as size of unit and MULTUNIT, and by supplying some + * of the critical in assembly. See the file platform.h for more + * details on customization. + * + * The symbol HIGHFIRST, designating that integers and longs are stored + * with the most significant bit in the lowest address, should be defined + * on the command line for compiling all files, since it is used by files + * other than the mpilib routines. + */ + +#ifndef ALIGN +#define ALIGN +#endif #ifndef PEASANT /* if not Russian peasant modulo multiply algorithm */ #ifndef MERRITT /* if not Merritt's modmult */ -#define UPTON /* default: use Upton's modmult algorithm */ +#ifndef UPTON /* if not Upton's modmult */ +#ifndef SMITH +#define SMITH /* default: use Smith's modmult algorithm */ +#endif +#endif #endif #endif +#ifdef SMITH +#define UPTON_OR_SMITH /* enable common code */ +#endif +#ifdef UPTON +#define UPTON_OR_SMITH /* enable common code */ +#endif + #ifndef UNIT32 #ifndef UNIT8 #define UNIT16 /* default--use 16-bit units */ @@ -53,7 +71,7 @@ #endif /*** CAUTION: If your machine has an unusual word size that is not a - power of 2 (8, 16, 32, or 64) bits wide, then the macros here that + power of 2 (8, 16, 32, or 64) bits wide, then the macros here that use the symbol "LOG_UNITSIZE" must be changed. ***/ @@ -61,6 +79,7 @@ typedef unsigned char unit; typedef signed char signedunit; #define UNITSIZE 8 /* number of bits in a unit */ +#define LOG_UNITSIZE 3 #define uppermostbit ((unit) 0x80) #define BYTES_PER_UNIT 1 /* number of bytes in a unit */ #define units2bits(n) ((n) << 3) /* fast multiply by UNITSIZE */ @@ -73,6 +92,7 @@ typedef signed char signedunit; typedef word16 unit; typedef short signedunit; #define UNITSIZE 16 /* number of bits in a unit */ +#define LOG_UNITSIZE 4 #define uppermostbit ((unit) 0x8000) #define BYTES_PER_UNIT 2 /* number of bytes in a unit */ #define units2bits(n) ((n) << 4) /* fast multiply by UNITSIZE */ @@ -85,25 +105,27 @@ typedef short signedunit; typedef word32 unit; typedef long signedunit; #define UNITSIZE 32 /* number of bits in a unit */ +#define LOG_UNITSIZE 5 #define uppermostbit ((unit) 0x80000000L) #define BYTES_PER_UNIT 4 /* number of bytes in a unit */ #define units2bits(n) ((n) << 5) /* fast multiply by UNITSIZE */ #define units2bytes(n) ((n) << 2) #define bits2units(n) (((n)+31) >> 5) #define bytes2units(n) (((n)+3) >> 2) -#undef PORTABLE /* can't use our C versions if 32 bits. */ #endif #define power_of_2(b) ((unit) 1 << (b)) /* computes power-of-2 bit masks */ #define bits2bytes(n) (((n)+7) >> 3) /* Some C compilers (like the ADSP2101) will not always collapse constant - expressions at compile time if the expressions contain shift operators. */ + expressions at compile time if the expressions contain shift + operators. */ /* #define uppermostbit power_of_2(UNITSIZE-1) */ /* #define UNITSIZE units2bits(1) */ /* number of bits in a unit */ /* #define bytes2units(n) bits2units((n)<<3) */ /* #define BYTES_PER_UNIT (UNITSIZE >> 3) */ /* LOG_UNITSIZE is the log base 2 of UNITSIZE, ie: 4 for 16-bit units */ -/* #define units2bits(n) ((n) << LOG_UNITSIZE) */ /* fast multiply by UNITSIZE */ +/* #define units2bits(n) ((n) << LOG_UNITSIZE) */ /* fast multiply by + UNITSIZE */ /* #define units2bytes(n) ((n) << (LOG_UNITSIZE-3)) */ /* #define bits2units(n) (((n)+(UNITSIZE-1)) >> LOG_UNITSIZE) */ /* #define bytes2units(n) (((n)+(BYTES_PER_UNIT-1)) >> (LOG_UNITSIZE-3)) */ @@ -115,6 +137,7 @@ typedef unit *unitptr; #ifdef HIGHFIRST /* these definitions assume MSB comes first */ +#define tohigher(n) (-(n)) /* offset towards higher unit */ #define pre_higherunit(r) (--(r)) #define pre_lowerunit(r) (++(r)) #define post_higherunit(r) ((r)--) @@ -126,13 +149,36 @@ typedef unit *unitptr; #define msbptr(r,prec) (r) #define make_msbptr(r,prec) /* (r) = msbptr(r,prec) */ +/* The macro rescale(r,current_precision,new_precision) rescales + a multiprecision integer by adjusting r and its precision to new values. + It can be used to reverse the effects of the normalize + routine given above. See the comments in normalize concerning + Intel vs. Motorola LSB/MSB conventions. + WARNING: You can only safely call rescale on registers that + you have previously normalized with the above normalize routine, + or are known to be big enough for the new precision. You may + specify a new precision that is smaller than the current precision. + You must be careful not to specify a new_precision value that is + too big, or which adjusts the r pointer out of range. +*/ #define rescale(r,currentp,newp) r -= ((newp) - (currentp)) + +/* The macro normalize(r,precision) "normalizes" a multiprecision integer + by adjusting r and precision to new values. For Motorola-style processors + (MSB-first), r is a pointer to the MSB of the register, and must + be adjusted to point to the first nonzero unit. For Intel/VAX-style + (LSB-first) processors, r is a pointer to the LSB of the register, + and must be left unchanged. The precision counter is always adjusted, + regardless of processor type. In the case of precision = 0, + r becomes undefined. +*/ #define normalize(r,prec) \ { prec = significance(r); r += (global_precision-(prec)); } #else /* LOWFIRST byte order */ /* these definitions assume LSB comes first */ +#define tohigher(n) (n) /* offset towards higher unit */ #define pre_higherunit(r) (++(r)) #define pre_lowerunit(r) (--(r)) #define post_higherunit(r) ((r)++) @@ -152,7 +198,8 @@ typedef unit *unitptr; /* Note that the address calculations require that lsbptr, msbptr, make_lsbptr, make_msbptr, mp_tstbit, mp_setbit, mp_clrbit, - and bitptr all have unitptr arguments, not byteptr arguments. */ + and bitptr all have unitptr arguments, not byte pointer arguments. +*/ #define bitptr(r,n) &((r)[bit_index(n)]) #define bitmsk(n) power_of_2((n) & (UNITSIZE-1)) /* bitmsk() assumes UNITSIZE is a power of 2 */ @@ -164,102 +211,67 @@ typedef unit *unitptr; /* #define mp_tstminus(r) ((msunit(r) & uppermostbit)!=0) */ #define mp_tstminus(r) ((signedunit) msunit(r) < 0) -/* MAX_BIT_PRECISION is upper limit that assembly primitives can handle. - It must be less than 32704 bits, or 4088 bytes. It should be an - integer multiple of UNITSIZE*2. -*/ -#define MAX_BIT_PRECISION 1152 -#define MAX_BYTE_PRECISION (MAX_BIT_PRECISION/8) -#define MAX_UNIT_PRECISION (MAX_BIT_PRECISION/UNITSIZE) - - -/*************** multiprecision library primitives ****************/ -#ifdef PORTABLE /* using slow portable C primitives */ + /* set working precision to specified number of bits. */ +#ifdef mp_setp +void mp_setp(short nbits); +#define set_precision(prec) mp_setp(units2bits(global_precision=(prec))) +#else #define set_precision(prec) (global_precision = (prec)) +#endif -#else /* not PORTABLE - not using portable C primitives */ -/* - The following primitives should be coded in assembly. - Functions P_ADDC, P_SUBB, and P_ROTL return a carry flag as their - functional return, and the result of the operation is placed in r1. - These assembly primitives are externally defined, unless PORTABLE - is defined. -*/ - -#ifdef VMS -/* - Define Assembler Prims With Lowercase Names To Prevent GCC hacking - them -*/ -#define P_SETP p_setp -#define P_ADDC p_addc -#define P_SUBB p_subb -#define P_ROTL p_rotl - -#endif /* VMS */ - -void P_SETP(short nbits); - /* sets working precision to specified number of bits. */ - -boolean P_ADDC(unitptr r1, unitptr r2, boolean carry); - /* multiprecision add with carry r2 to r1, result in r1 */ - -boolean P_SUBB(unitptr r1, unitptr r2, boolean borrow); - /* multiprecision subtract with borrow, r2 from r1, result in r1 */ - -boolean P_ROTL(unitptr r1, boolean carry); - /* multiprecision rotate left 1 bit with carry, result in r1. */ - -/* Define C primitive names as the equivalent calls to assembly primitives. */ -#define set_precision(prec) P_SETP(units2bits(global_precision=(prec))) -#define mp_addc P_ADDC -#define mp_subb P_SUBB -#define mp_rotate_left P_ROTL - -#ifdef VMS - -short p_cmp(register unitptr r1,register unitptr r2); - /* Compares registers *r1, *r2, and returns -1, 0, or 1 */ - -#define mp_compare p_cmp - -#endif /* VMS */ - -#endif /* not PORTABLE */ -/************** end of primitives that should be in assembly *************/ +/* We'll pull in the assembler code here if asked to. */ +#ifdef WIN32 +#ifdef USE_WIN32_ASSEMBLER +#include "mpw32asm.h" +#endif /* USE_WIN32_ASSEMBLER */ +#endif /* WIN32 */ #ifdef PEASANT /* Define C names for Russian peasant modmult primitives. */ -#define stage_modulus stage_peasant_modulus -#define mp_modmult peasant_modmult -#define modmult_burn peasant_burn - -#endif /* PEASANT */ +#define stage_modulus stage_peasant_modulus +#define mp_modmult peasant_modmult +#define modmult_burn peasant_burn +#define SLOP_BITS PEASANT_SLOP_BITS +#else /* not PEASANT */ #ifdef MERRITT /* Define C names for Merritt's modmult primitives. */ -#define stage_modulus stage_merritt_modulus -#define mp_modmult merritt_modmult -#define modmult_burn merritt_burn - -#endif /* MERRITT */ +#define stage_modulus stage_merritt_modulus +#define mp_modmult merritt_modmult +#define modmult_burn merritt_burn +#define SLOP_BITS MERRITT_SLOP_BITS +#else /* not PEASANT, MERRITT */ #ifdef UPTON /* Define C names for Upton's modmult primitives. */ -#define stage_modulus stage_upton_modulus -#define mp_modmult upton_modmult -#define modmult_burn upton_burn +#define stage_modulus stage_upton_modulus +#define mp_modmult upton_modmult +#define modmult_burn upton_burn +#define SLOP_BITS UPTON_SLOP_BITS + +#else /* not PEASANT, MERRITT, UPTON */ +#ifdef SMITH +/* Define C names for Smith's modmult primitives. */ +#define stage_modulus stage_smith_modulus +#define mp_modmult smith_modmult +#define modmult_burn smith_burn +#define SLOP_BITS SMITH_SLOP_BITS +#endif /* SMITH */ #endif /* UPTON */ +#endif /* MERRITT */ +#endif /* PEASANT */ #define mp_shift_left(r1) mp_rotate_left(r1,(boolean)0) /* multiprecision shift left 1 bit */ +#if !defined(mp_add) #define mp_add(r1,r2) mp_addc(r1,r2,(boolean)0) /* multiprecision add with no carry */ +#endif #define mp_sub(r1,r2) mp_subb(r1,r2,(boolean)0) /* multiprecision subtract with no borrow */ @@ -289,31 +301,44 @@ short p_cmp(register unitptr r1,register #define countbytes(r) ((countbits(r)+7)>>3) -/* SLOP_BITS is how many "carry bits" to allow for intermediate +/* SLOP_BITS is how many "carry bits" to allow for intermediate calculation results to exceed the size of the modulus. It is used by modexp to give some overflow elbow room for - modmult to use to perform modulo operations with the modulus. - The number of slop bits required is determined by the modmult - algorithm. The Russian peasant modmult algorithm only requires + modmult to use to perform modulo operations with the modulus. + The number of slop bits required is determined by the modmult + algorithm. The Russian peasant modmult algorithm only requires 1 slop bit, for example. Note that if we use an external assembly modmult routine, SLOP_BITS may be meaningless or may be defined in a non-constant manner. */ -#ifdef MERRITT /* use Merritt's modmult algorithm */ -#define SLOP_BITS (UNITSIZE+1) -#define MERRITT_KEY /* cause keygen to generate unnormalized keys */ -#endif /* MERRITT */ -#ifdef PEASANT /* use Russian peasant modmult algorithm */ -#define SLOP_BITS 1 -#endif /* PEASANT */ -#ifdef UPTON /* use Upton's modmult algorithm */ -/* Not clear what SLOP_BITS needs to be */ -#define SLOP_BITS UNITSIZE -#endif /* UPTON */ +#define PEASANT_SLOP_BITS 1 +#define MERRITT_SLOP_BITS UNITSIZE +#define UPTON_SLOP_BITS (UNITSIZE/2) +#ifdef mp_smul /* old version requires MS word = 0 */ +#define SMITH_SLOP_BITS UNITSIZE +#else /* mp_smula or C version of mp_smul */ +#define SMITH_SLOP_BITS 0 +#endif /* mp_smul */ + +#define MIN_KEY_BITS 384 +#define MAX_KEY_BITS 2048 + +/* MAX_BIT_PRECISION is upper limit that assembly primitives can handle. + It must be less than 32704 bits, or 4088 bytes. It should be an + integer multiple of UNITSIZE*2. +*/ +#define MAX_BIT_PRECISION (MAX_KEY_BITS+(2*UNITSIZE)) +#define MAX_BYTE_PRECISION (MAX_BIT_PRECISION/8) +#define MAX_UNIT_PRECISION (MAX_BIT_PRECISION/UNITSIZE) + /* global_precision is the unit precision last set by set_precision */ +#if defined(WIN32) +/* For Win32 we want this to be 32-bit, for compatibility with the assembler code */ +extern unsigned int global_precision; +#else extern short global_precision; - +#endif /* The "bit sniffer" macros all begin sniffing at the MSB. @@ -353,9 +378,6 @@ extern short global_precision; #define stuff_bit(bptr,bitmask) *(bptr) |= bitmask - -#ifdef PORTABLE /* these slow C primitives should be recoded in assembly */ - boolean mp_addc (register unitptr r1,register unitptr r2,register boolean carry); /* multiprecision add with carry r2 to r1, result in r1 */ @@ -367,13 +389,11 @@ boolean mp_subb boolean mp_rotate_left(register unitptr r1,register boolean carry); /* multiprecision rotate left 1 bit with carry, result in r1. */ -#endif /* PORTABLE */ - void mp_shift_right_bits(register unitptr r1,register short bits); /* multiprecision shift right bits, result in r1. */ short mp_compare(register unitptr r1,register unitptr r2); - /* Compares registers *r1, *r2, and returns -1, 0, or 1 */ + /* Compares registers *r1, *r2, and returns -1, 0, or 1 */ boolean mp_inc(register unitptr r); /* Increment multiprecision integer r. */ @@ -384,29 +404,20 @@ boolean mp_dec(register unitptr r); void mp_neg(register unitptr r); /* Compute 2's complement, the arithmetic negative, of r */ -#ifdef VAXC -/* - * A VAX is a CISC machine. Unfortunately C is at to low a level to use - * many of the instruction set enhancements so we define some macros - * here that implement fast moves and fast zero fills with single - * instructions. - */ - -#pragma builtins -#define mp_move( dst, src) _MOVC3( global_precision*4, (char *) src, (char *) dst) -#define unitfill0( r, unitcount) _MOVC5( 0, (char *) 0, 0, unitcount*4, (char *) r) -#define mp_burn(r) _MOVC5(0, (char *) 0, 0, global_precision*4, (char *) r) -#define mp_init0(r) mp_burn(r) /* Just for documentation purposes */ - -#else /* VAXC */ - -void mp_move(register unitptr dst,register unitptr src); +#ifndef mp_move +#define mp_move(d,s) memcpy((void*)(d), (void*)(s), \ + units2bytes(global_precision)) +#endif +#ifndef unitfill0 +#define unitfill0(r,ct) memset((void*)(r), 0, units2bytes(ct)) +#endif -void unitfill0(unitptr r,word16 unitcount); +#ifndef mp_burn #define mp_burn(r) mp_init(r,0) /* for burning the evidence */ #define mp_init0(r) mp_init(r,0) +#endif -#endif /* VAXC */ +#define empty_array(r) unitfill0(r, sizeof(r)/sizeof(r[0])/sizeof(unit)) void mp_init(register unitptr r, word16 value); /* Init multiprecision register r with short value. */ @@ -440,22 +451,33 @@ int mp_mult(register unitptr prod, register unitptr multiplicand,register unitptr multiplier); /* Computes multiprecision prod = multiplicand * multiplier */ -int stage_modulus(unitptr n); +int countbits(unitptr r); + /* Returns number of significant bits in r. */ + +int stage_peasant_modulus(unitptr n); +int stage_merritt_modulus(unitptr n); +int stage_upton_modulus(unitptr n); +int stage_smith_modulus(unitptr n); /* Must pass modulus to stage_modulus before calling modmult. */ -int mp_modmult(register unitptr prod, +int peasant_modmult(register unitptr prod, + unitptr multiplicand,register unitptr multiplier); +int merritt_modmult(register unitptr prod, + unitptr multiplicand,register unitptr multiplier); +int upton_modmult(register unitptr prod, + unitptr multiplicand,register unitptr multiplier); +int smith_modmult(register unitptr prod, unitptr multiplicand,register unitptr multiplier); /* Performs combined multiply/modulo operation, with global modulus */ - -int countbits(unitptr r); - /* Returns number of significant bits in r. */ + + int mp_modexp(register unitptr expout,register unitptr expin, register unitptr exponent,register unitptr modulus); /* Combined exponentiation/modulo algorithm. */ -int rsa_decrypt(unitptr M, unitptr C, - unitptr d, unitptr p, unitptr q, unitptr u); - /* Uses Chinese Remainder Theorem shortcut for RSA decryption. */ +int mp_modexp_crt(unitptr expout, unitptr expin, + unitptr p, unitptr q, unitptr ep, unitptr eq, unitptr u); + /* exponentiation and modulo using Chinese Remainder Theorem */ /****************** end of MPI library ****************************/