text: /*
   * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License").
   * You may not use this file except in compliance with the License.
   * A copy of the License is located at
   *
   * http://aws.amazon.com/apache2.0
   *
   * or in the "license" file accompanying this file. This file is distributed
   * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
   * express or implied. See the License for the specific language governing
   * permissions and limitations under the License.
   * The license is detailed in the file LICENSE.md, and applies to this file.
   *
   * Written by Nir Drucker and Shay Gueron
   * AWS Cryptographic Algorithms Group.
   * (ndrucker@amazon.com, gueron@amazon.com)
   *
   * Based on the original Rainbow code from
   * https://csrc.nist.gov/CSRC/media/Projects/Post-Quantum-Cryptography/documents/round-2/submissions/Rainbow-Round2.zip
   */
  
  #pragma once
  
  EXTERNC_BEGIN
  
  #include "utils_hash.h"
  
  #ifdef USE_ORIG_RNG
  #    include "rng.h"
  #    define CTR_DRBG_ENTROPY_LEN (48)
  
  typedef AES256_CTR_DRBG_struct prng_t;
  
  #else
  #    include "ctr_drbg/ctr_drbg.h"
  
  typedef CTR_DRBG_STATE prng_t;
  #endif
  
  _INLINE_
  int prng_set(OUT prng_t *prng,
               IN const uint8_t *prng_seed,
               IN const uint64_t prng_seedlen)
  {
      uint8_t      seed[CTR_DRBG_ENTROPY_LEN];
      const size_t rem = CTR_DRBG_ENTROPY_LEN - prng_seedlen;
  
      if(prng_seedlen >= CTR_DRBG_ENTROPY_LEN) {
          memcpy(seed, prng_seed, CTR_DRBG_ENTROPY_LEN);
      } else {
          memcpy(seed, prng_seed, prng_seedlen);
          hash_msg(seed + prng_seedlen, rem, prng_seed, prng_seedlen);
      }
  
  #ifdef USE_ORIG_RNG
      randombytes_init_with_state(prng, seed);
  #else
      CTR_DRBG_init(prng, seed, NULL, 0);
  #endif
  
      return SUCCESS;
  }
  
  #ifdef USE_ORIG_RNG
  
  _INLINE_
  uint32_t prng_gen(IN OUT prng_t *prng, OUT uint8_t *out, IN const uint64_t outlen)
  {
      randombytes_with_state(prng, out, outlen);
      return outlen;
  }
  
  #else
  
  _INLINE_
  uint32_t prng_gen(IN OUT prng_t *prng, OUT uint8_t *out, IN const uint64_t outlen)
  {
      const size_t max_len  = CTR_DRBG_MAX_GENERATE_LENGTH;
      size_t       curr_out = outlen;
  
      int ctr;
      for(ctr = 0; curr_out > max_len; ctr++) {
          GUARD(CTR_DRBG_generate(prng, &out[ctr * max_len], max_len, NULL, 0));
          curr_out -= max_len;
      }
      GUARD(CTR_DRBG_generate(prng, &out[ctr * max_len], curr_out, NULL, 0));
  
      return outlen;
  }
  
  #endif
  
  _INLINE_
  void prng_clear(OUT prng_t *prng)
  {
  #ifdef USE_ORIG_RNG
      // Because prng is unsed
      (void)(prng);
      return;
  #else
      CTR_DRBG_clear(prng);
  #endif
  }
  
  EXTERNC_END
  