/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
   unpublished work protected as such under copyright law.  This work
   contains proprietary, confidential, and trade secret information of
   RSA Data Security, Inc.  Use, disclosure or reproduction without the
   express written authorization of RSA Data Security, Inc. is
   prohibited.
 */

#include "port_before.h"
#include "global.h"
#include "algae.h"
#include "digrand.h"
#include "port_after.h"

/* Calling routine must initialize the digest algorithm and set
     digestRandom->vTable.
   digestLen is the length of the output of the digest algorithm (i.e. 16).
   state must point to an unsigned char * array of 3 * digestLen.
 */
void A_DigestRandomInit (digestRandom, digestLen, state)
A_DigestRandom *digestRandom;
unsigned int digestLen;
unsigned char *state;
{
  digestRandom->_state = state;
  digestRandom->_output = state + digestLen;
  digestRandom->_digest = digestRandom->_output + digestLen;

  digestRandom->_outputAvailable = 0;
  digestRandom->_digestLen = digestLen;

  T_memset ((POINTER)digestRandom->_state, 0, digestLen);
}

void A_DigestRandomUpdate (digestRandom, input, inputLen)
A_DigestRandom *digestRandom;
unsigned char *input;
unsigned int inputLen;
{
  unsigned int i, j, x;
  
  (*digestRandom->vTable->DigestUpdate) (digestRandom, input, inputLen);
  (*digestRandom->vTable->DigestFinal) (digestRandom, digestRandom->_digest);

  /* add digest to state */
  x = 0;
  for (i = 0; i < digestRandom->_digestLen; i++) {
    j = digestRandom->_digestLen-1-i;
    x += digestRandom->_state[j] + digestRandom->_digest[j];
    digestRandom->_state[j] = (unsigned char)x;
    x >>= 8;
  }
}

void A_DigestRandomGenerateBytes (digestRandom, output, outputLen)
A_DigestRandom *digestRandom;
unsigned char *output;
unsigned int outputLen;
{
  unsigned int available, i;
  
  available = digestRandom->_outputAvailable;

  while (outputLen > available) {
    T_memcpy
      ((POINTER)output,
       (POINTER)&digestRandom->_output[digestRandom->_digestLen-available],
       available);
    output += available;
    outputLen -= available;

    /* generate new output */
    (*digestRandom->vTable->DigestUpdate)
       (digestRandom, digestRandom->_state, digestRandom->_digestLen);
    (*digestRandom->vTable->DigestFinal) (digestRandom, digestRandom->_output);
    available = digestRandom->_digestLen;

    /* increment state */
    for (i = 0; i < digestRandom->_digestLen; i++)
      if (digestRandom->_state[digestRandom->_digestLen-1-i]++)
        break;
  }

  T_memcpy 
    ((POINTER)output,
     (POINTER)&digestRandom->_output[digestRandom->_digestLen-available],
     outputLen);
  digestRandom->_outputAvailable = available - outputLen;
}

