/* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. */ /* * giantExternal.c - convert between giant integer and external representation * * Created Aug. 5 2005 by Doug Mitchell. */ #include #include #include #include /* * Precalculate actual size in bytes needed to serialize a given giant. */ gi_uint16 serializeGiantBytes(const giant g) { gi_size numDigits, numZeros, digitByte; giantDigit digit; gtrimSign(g); numDigits = g->sign; if(numDigits == 0) { return 0; } /* Count the number of leading 0 bytes in the m.s. digit. */ numZeros = 0; digit = g->n[numDigits - 1]; for(digitByte=0; digitByte>= 8; if (byte) { numZeros = 0; } else { numZeros++; } } return (numDigits * GIANT_BYTES_PER_DIGIT) - numZeros; } /* * Serialize, deserialize giants's n[] to/from byte stream. * First byte of byte stream is the m.s. byte of the resulting giant, * regardless of the size of giantDigit. * * No assumption is made about the alignment of cp. * * The numBytes argument indicates the space available on input; * on return it indicates the actual number of bytes written. */ GIReturn serializeGiant( const giant g, gi_uint8 *cp, gi_uint16 *numBytes) /* IN/OUT */ { gi_size digitDex, numDigits, digitByte, totalBytes, bytesLeft; gi_uint8 *currCp; giantDigit digit; GI_CHECK_SP("serializeGiant"); if((g == NULL) || (cp == NULL) || (numBytes == NULL)) { return GR_IllegalArg; } totalBytes = serializeGiantBytes(g); if(totalBytes == 0) { *numBytes = 0; return GR_Success; } numDigits = g->sign; if(totalBytes > *numBytes) { dbgLog("serializeGiant: Insufficient space\n"); return GR_Overflow; } /* * Emit bytes starting at the far end of the outgoing byte * stream, which is the l.s. byte of giant data. In order to prevent * writing out leading zeros, we special case the m.s. digit. */ currCp = cp + totalBytes - 1; for(digitDex=0; digitDexn[digitDex]; for(digitByte=0; digitByte>= 8; } } /* Handle the m.s. digit, by writing out only as many bytes as are left. Since we already wrote out numDigits - 1 digits above the answer is: */ bytesLeft = totalBytes - (numDigits - 1) * GIANT_BYTES_PER_DIGIT; digit = g->n[digitDex]; for(digitByte=0; digitByte>= 8; } *numBytes = totalBytes; return GR_Success; } /* * Initialize a giant with specified data. Does not have to be * aligned to giantDigits (as the output of serializeGiant() always * is). */ GIReturn deserializeGiant( giant g, const gi_uint8 *cp, gi_uint16 numBytes) { gi_size numDigits; giantDigit digit; giantDigit tempDigit; gi_size digitDex; gi_size digitByte; gi_size dex; const gi_uint8 *currCp; GI_CHECK_SP("deserializeGiant"); if(g == NULL) { return GR_IllegalArg; } if(numBytes == 0) { g->sign = 0; return GR_Success; } if(cp == NULL) { return GR_IllegalArg; } /* * Trim off leading zeroes, sometimes placed there during DER * encoding to ensure the number does not appear negative. We * don't support negative numbers in this module... */ while((*cp == 0) && (numBytes != 0)) { cp++; numBytes--; } if(numBytes == 0) { g->sign = 0; return GR_Success; } numDigits = BYTES_TO_GIANT_DIGITS(numBytes); if(numDigits > g->capacity) { return GR_Overflow; } /* * Start at l.s. byte, at the far end of the byte stream. */ digitDex = 0; /* index into g->n[] */ digit = 0; /* accumulator */ digitByte = 0; /* byte index into digit */ currCp = cp + numBytes - 1; for(dex=0; dexn[digitDex++] = digit; /* reset for next digit */ digit = 0; digitByte = 0; } } /* * Infer sign/size from non-zero n[] elements */ g->sign = numDigits; gtrimSign(g); return GR_Success; }