Chapter 8: Input, Output, Assignment, Conversion

Team-Fly

The numerals were now being converted automatically from base 2 to base 10 ... 881, 883, 887, 907 ... each one confirmed as a prime number.

Carl Sagan, Contact

WE BEGIN THIS CHAPTER WITH assignment, the simplest and also the most important function. To be able to assign to a CLINT object a_l the value of another CLINT object b_l, we require a function that copies the digits of b_l to the reserved storage space for a_l, an event that we shall call elementwise assignment. It will not suffice merely to copy the address of the object b_l into the variable a_l, since then both objects would refer to the same location in memory, namely that of b_l, and any change in a_l would be reflected in a change in the object b_l, and conversely. Furthermore, access to the area of memory addressed by a_l could become lost.

We shall return to the problems of elementwise assignment in the second part of this book when we concern ourselves with the implementation of the assignment operator "=" in C++ (see Section 13.3).

The assignment of the value of a CLINT object to another CLINT is effected with the function cpy_l().

start sidebar

Function:

copy a CLINT object as an assignment

Syntax:

void cpy_l (CLINT dest_l, CLINT src_l);

Input:

src_l (assigned value)

Output:

dest_l (destination object)

end sidebar

 void cpy_l (CLINT dest_l, CLINT src_l) {   clint *lastsrc_l = MSDPTR_L (src_l);   *dest_l = *src_l; 

start sidebar

In the next step leading zeros are found and then ignored. At the same time, the number of digits of the target object is adjusted.

end sidebar

   while ((*lastsrc_l == 0) && (*dest_l > 0))     {       --lastsrc_l;       --*dest_l;     } 

start sidebar

Now the relevant digits of the source object are copied into the goal object. Then the function is terminated.

end sidebar

   while (src_l < lastsrc_l)     {       *++dest_l = *++src_l;     } } 

The exchange of the values of two CLINT objects can be accomplished with the help of the macro SWAP_L, the FLINT/C variant of the macro SWAP, which manages in an interesting way to accomplish the exchange of two variables using XOR operations without the requirement of intermediate storage in a temporary variable:

 #define SWAP(a, b) ((a)^=(b), (b)^=(a), (a)^=(b)) #define SWAP_L(a_l, b_l) \     (xor_l((a_l), (b_l), (a_l)), \       xor_l((b_l), (a_l), (b_l)), \       xor_l((a_l), (b_l), (a_l))) 

start sidebar

Function:

swap the values of two CLINT objects

Syntax:

void fswap_l (CLINT a_l, CLINT b_l);

Input:

a_l, b_l (values to be exchanged)

Output:

a_l, b_l

end sidebar

The functions in the FLINT/C library for the input and output of numbers in a form readable by human beings are not among the most exciting functions in this library, yet for many applications they are unavoidable. For practical reasons a form was selected to allow for the input and output by means of character strings, as vectors of type char. For this the two essentially complementary functions str2clint_l() and xclint2str_l() were developed: The first transforms a character string with digits into a CLINT object, and the second, conversely, transforms a CLINT object into a character string. The base of the character string's representation is specified, with representations to bases in the range from 2 to 16 allowed.

The conversion to be carried out by the function str2clint_l() of a representation of type CLINT into a representation in the base specified is accomplished by means of a sequence of multiplications and additions to base B (cf. [Knut], Section 4.4). The function registers any overflow that occurs, the use of invalid bases, and the passing of the null pointer and returns the corresponding error code. Any prefixes indicating the number's representation, "0X," "0x," "0B," or "0b," are ignored.

start sidebar

Function:

conversion of a character string into a CLINT object

Syntax:

int str2clint_l (CLINT n_l, char *str, USHORT b);

Input:

str (pointer to a sequence of char) base

(base of the numerical representation of the character string, 2 base 16)

Output:

n_1 (target CLINT object)

Return:

E_CLINT_OK if all is ok

E_CLINT_BOR if base < 2 or base > 16, or if the number of digits in str is larger than base

E_CLINT_OFL if overflow

E_CLINT_NPT if in str the null pointer was passed

end sidebar

 int str2clint_l (CLINT n_l, char *str, USHORT base) {   clint base_l[10];   USHORT n;   int error = E_CLINT_OK;   if (str == NULL)     {       return E_CLINT_NPT;     }   if (2 > base || base > 16)     {       return E_CLINT_BOR;    /* error: invalid base */     }   u2clint_l (base_l, base);   SETZERO_L (n_l);   if (*str == '0')     {       if ((tolower_l(*(str+1)) == 'x') ||            (tolower_l(*(str+1)) == 'b'))    /* ignore any prefix */          {            ++str;            ++str;          }     }   while (isxdigit ((int)*str) || isspace ((int)*str))     {       if (!isspace ((int)*str))          {            n = (USHORT)tolower_l (*str); 

start sidebar

Many implementations of tolower() from non-ANSI-conforming C libraries return undefined results if a character is not uppercase. The FLINT/C function tolower_l() calls tolower() only for uppercase AZ and otherwise returns the character unchanged.

end sidebar

            switch (n)               {                 case 'a':                 case 'b':                 case 'c':                 case 'd':                 case 'e':                 case 'f':                   n -= (USHORT)('a' -- 10);                   break;                 default:                   n -= (USHORT)'0';               }            if (n >= base)               {                 error = E_CLINT_BOR;                 break;               }            if ((error = mul_l (n_l, base_l, n_l)) != E_CLINT_OK)               {                 break;               }            if ((error = uadd_l (n_l, n, n_l)) != E_CLINT_OK)               {                 break;               }          }       ++str;     }   return error; } 

The function xclint2str_l(), complementary to str2clint_l(), returns a pointer to an internal buffer of storage class static (cf. [Harb], Section 4.3), which contains the calculated numerical representation and its value until xclint2str_l() is called again or the program is ended.

The function xclint2str_l() carries the required conversion of the CLINT representation into the representation to the specified base by means of a sequence of divisions with remainder to the base B.

start sidebar

Function:

Conversion of a CLINT object into a character string

Syntax:

 char * xclint2str_l (CLINT n_l, USHORT base,                int showbase); 

Input:

n_l (CLINT object to be converted)

base (base of the numerical representation of the character string to be specified);

showbase (value 0: The numerical representation has a "0x" in the case base = 16 or "0b" if base = 2. Value = 0: there is no prefix.)

Return:

pointer to the calculated character string if all ok NULL if 2 < b or b > 16

end sidebar

 static char ntable[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; char * xclint2str_l (CLINT n_l, USHORT base, int showbase) {   CLINTD u_l, r_l;   clint base_l[10];   int i = 0;   static char N[CLINTMAXBIT + 3];   if (2U > base || base > 16U)     {       return (char *)NULL;    /* error: invalid base */     }   u2clint_l (base_l, base);   cpy_l (u_l, n_l);   do     {       (void) div_l (u_l, base_l, u_l, r_l);       if (GTZ_L (r_l))          {            N[i++] = (char) ntable[*LSDPTR_L (r_l) & 0xff];          }       else          {            N[i++] = '0';          }     }   while (GTZ_L (u_l));   if (showbase)     {       switch (base)          {            case 2:               N[i++] = 'b';               N[i++] = '0';               break;          case 8:               N[i++] = '0';               break;          case 16:               N[i++] = 'x';               N[i++] = '0';               break;       }     }   N[i] = '0';   return strrev_l (N); } 

For reasons of compatibility with the function clint2str_l() in the first edition of this book, clint2str_l(n_l, base) was defined as a macro that calls the function xclint2str(n_l, base, 0).

Furthermore, macros HEXSTR_L(), DECSTR_L(), OCTSTR_L(), and BINSTR_L() were created, which create, from a passed CLINT object as argument, a character string without prefix with the numerical representation specified by the macro name and thus eliminate the base of the representation as an argument (see Appendix C).

As standard form for the output of CLINT values we have available the macro DISP_L(), which processes a pointer to a character string and a CLINT object as arguments. The character string contains, according to the purpose to which it will be put, information about the following CLINT value to be output, such as "The product of a_l and b_l has the value ... ." The output of the CLINT value is in hexadecimal, that is, to base 16. Additionally, DISP_L() outputs in a new line the number of significant binary digits (that is, without leading zeros) of the indicated CLINT object (cf. Appendix C).

If there are to be conversions between byte vectors and CLINT objects, then the pair of functions byte2clint_l() and clint2byte_l() can be employed (cf. [IEEE], 5.5.1).

It is assumed that the byte vectors embody a numerical representation to base 256 with values increasing from right to left. For the implementation of these functions the reader is referred to the file flint.c. We give here only the function headers.

start sidebar

Function:

conversion of a byte vector into a CLINT object

Syntax:

 int byte2clint_l (CLINT n_l, UCHAR *bytestr, int len); 

Input:

bytestr (pointer to a sequence of UCHAR)

len (length of the byte vector)

Output:

n_l (target CLINT object)

Return:

E_CLINT_OK if all ok

E_CLINT_OFL if overflow

E_CLINT_NPT if in bytestr the null pointer was passed

end sidebar

start sidebar

Function:

conversion of a CLINT object into a byte vector

Syntax:

UCHAR * clint2byte_l (CLINT n_l, int *len);

Input:

n_l (CLINT object to be converted)

Output:

len (length of the generated byte vector)

Return:

pointer to the calculated byte vector NULL, if in len the null pointer was passed

end sidebar

Finally, for the transformation of unsigned values into the CLINT numerical format the two functions u2clint_l() and ul2clint_l() can be used. The function u2clint_l() converts USHORT arguments, and the function ul2clint_l() converts ULONG arguments, into the CLINT numerical format. The function ul2clint_l() will be described in the following as an example.

start sidebar

Function:

conversion of a value of type ULONG into a CLINT object

Syntax:

void ul2clint_l (CLINT num_l, ULONG ul);

Input:

ul (value to be converted)

Output:

num_l (target CLINT object)

end sidebar

 void ul2clint_l (CLINT num_l, ULONG ul) {   *LSDPTR_L (num_l) = (USHORT)(ul & 0xffff);   *(LSDPTR_L (num_l) + 1) = (USHORT)((ul >> 16) & 0xffff);   SETDIGITS_L (num_l, 2);   RMLDZRS_L (num_l); } 

To end this chapter we shall discuss a function that carries out a validity check of a memory object for the CLINT number format. Control functions of this type are called as needed whenever "foreign" values are imported into a system for further processing into a subsystem. Such a subsystem can be, for example, a cryptographic module that before every processing of input data must check whether it is dealing with valid values or arguments. Checking at run time whether the assumptions about the input values of a function have been met is good programming practice, one that helps to avoid undefined situations and that can contribute decisively to the stability of an application. For testing and debugging this usually takes place with assertions, with the help of which run-time conditions can be tested. Assertions are inserted as macros and can be decommissioned for the actual running of the program, usually during compilation via #define NDEBUG. In addition to the assert macro of the C standard library (see [Pla1], Chapter 1) there are a number of further implementations of similar mechanisms that take various actions when the test conditions are violated, such as listing recognized exceptional conditions in a log file, with or without program termination in the event of an error. For extensive information in this area the reader is referred to [Magu], Chapters 2 and 3, as well as [Murp], Chapter 4.

The protection of the functions of a program library like the FLINT/C package against being passed values that lie outside of the domain of definition of the respective parameters can occur within the invoked functions themselves or within the calling functions, where in the latter case the responsibility lies with the programmer who employs the library. For performance considerations, in the development of the FLINT/C functions we did not test every passed CLINT argument for a valid address and possible overflow. The thought of carrying out multiply redundant checks of the numerical format in thousands of modular multiplications of an exponentiation moved the author to offload this control task to the programs that use the FLINT/C functions. An exception is the passing of divisors with the value zero, which is checked as a matter of principle and if it occurs is acknowledged with a suitable error notification, even in all the functions for residue class arithmetic. The code of all the functions was particularly carefully tested to make sure that the FLINT/C library generates only valid formats (cf. Chapter 12).

The function vcheck_l() was created for the analysis of CLINT arguments with regard to the validity of their format. It should help to protect the FLINT/C functions from being passed invalid parameters as CLINT values.

start sidebar

Function:

test for a valid CLINT numerical format

Syntax:

int vcheck_l (CLINT n_l);

Input:

n_l (object to be tested)

Return:

E_VCHECK_OK if format ok

errors and warnings according to Table 8.1

end sidebar

Table 8.1: Diagnostic values of the function vcheck_l()

Return value

Diagnosis

Explanation

E_VCHECK_OK

Format is ok

Info: The number has a valid representation and a value with the range of definition of a CLINT type.

E_VCHECK_LDZ

leading zeros

Warning: The number has leading zeros, but otherwise a valid definition within the range of definition.

E_VCHECK_MEM

memory error

Error: NULL Pointer was passed.

E_VCHECK_OFL

genuine overflow

Error: The passed number is too large; it cannot be represented as a CLINT object.

 int vcheck_l (CLINT n_l) {   unsigned int error = E_VCHECK_OK; 

start sidebar

Check for the null pointer: the ugliest error of them all.

end sidebar

   if (n_l == NULL)     {       error = E_VCHECK_MEM;     }   else     { 

start sidebar

Check for overflow: Does the number have too many digits?

end sidebar

     if (((unsigned int) DIGITS_L (n_l)) > CLINTMAXDIGIT)        {          error = E_VCHECK_OFL;        }     else        { 

start sidebar

Check for leading zeros: These we can live with ;-)

end sidebar

            if ((DIGITS_L (n_l) > 0) && (n_l[DIGITS_L (n_l)] == 0))               {                 error = E_VCHECK_LDZ;               }          }     }   return error; } 

The return values of the function are defined as macros in the file flint.h. An explanation of these values is provided in Table 8.1.

The numeric values of the error codes are smaller than zero, so that a simple comparison with zero suffices to distinguish between errors on the one hand and warnings or the valid case on the other.


Team-Fly


Cryptography in C and C++
Cryptography in C and C++
ISBN: 189311595X
EAN: 2147483647
Year: 2001
Pages: 127

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net